首页 > 其他分享 >Unity URP Houdini 风格化云

Unity URP Houdini 风格化云

时间:2024-03-09 17:22:17浏览次数:30  
标签:Depth lerp half float depth Unity URP 风格化 float2

目录

前言

云的实现一般有三种思路:Volume体积云、billboard公告牌、Particle粒子,对于风格化来说体渲染的实现过于真实(但光遇的风格化云貌似是使用体渲染实现的,后面有空会考虑尝试还原还原),而Particle消耗太大了!因此本文将着重展现如何使用公告牌技术实现一个不错的风格化云效果

Youtube上有位大佬讲解了如何使用houdini和ue快速实现一个吉卜力风的卡通云,虽然效果还是ok,但个人认为,这种方法容易露馅。不过,这其中的制作云的思路可以参考,无需再用PS来频繁上色。本篇将在此基础上,添加实现其他的功能(主要思路来自Tyler Smith

Render Type

  • 这里采用半透明效果

  • 实现

    Tags 
    { 
        "RenderPipeline" = "UniversalRenderPipeline"
        "RenderType"="Transparent"
        "Queue" = "Transparent"
        "IgnoreProjector" = "True"
    }
    
    Tags
    {
    	"LightMode" = "UniversalForward"
    }
    Blend [_BlendSrc] [_BlendDst]
    BlendOp [_BlendOp]
    ZWrite [_ZWriteMode]
    

不透明度

  • 因为云是一种半透明物体,不能简单地使用diffuse Texture的A通道(为了方便调节美术效果,需要控制它的opacity),所以我用到了DepthFade(弱化半透明物体和不透明物体间相交时产生的硬线)

  • 实现

    • DepthFade

      // UE中的实现
      float DepthFade(in half opacity = 1, in float sceneDepth = 1, in float pixelDepth = 1, in half depthFade = 100)
      {
          half depthDiff = sceneDepth - pixelDepth;
      
          return opacity * saturate(depthDiff / depthFade);
      }
      
    • Scene Depth 和 Pixel Depth

      struct Depth
      {
          float raw;
          float linear01;
          float eye;
      };
      
      // 获取深度图,并提取深度
      Depth SampleDepth(float4 positionSS)
      {
          float4 positionSSNor = float4(positionSS.xyz / positionSS.w, positionSS.w);
      
          Depth depth = (Depth)0;
      
          depth.raw = SampleSceneDepth(positionSSNor.xy);
          depth.eye = LinearEyeDepth(depth.raw, _ZBufferParams);
          depth.linear01 = Linear01Depth(depth.raw, _ZBufferParams);
      
          return depth;
      }
      
      float GetRawDepth(Depth depth)
      {
          return depth.raw;
      }
      
      float GetLinear01Depth(Depth depth)
      {
          return depth.linear01;
      }
      
      float GetEyeDepth(Depth depth)
      {
          return depth.eye;
      }
      
      // positionSS为未进行透视除法的屏幕空间
      float GetPixelDepth(float4 positionSS)
      {
          return positionSS.w;
      }
      
      // 计算得出片元的opacity
      // 这里的albedo是基于POM采样MainTex得到的
      half GetSurfaceOpacity(float4 alebdo, float2 uv, float4 positionSS)
      {
          half surfaceOpacity = SAMPLE_TEXTURE2D(_AlbedoTex, sampler_AlbedoTex, uv).a;
          
          // 计算scene depth 和 pixel depth
          Depth depth = SampleDepth(positionSS);
          float sceneEyeDepth = GetEyeDepth(depth);
          float pixelDepth = GetPixelDepth(positionSS);
      
          // 计算opacity
          float opacity = 1.f;
          _OpacityContrast = max(0.0001f, _OpacityContrast);
          opacity = pow(surfaceOpacity, _OpacityContrast);
          opacity *= pow(alebdo.a, _OpacityContrast);
      
          return DepthFade(sceneEyeDepth, pixelDepth, opacity, _FadeDistance);
      }
      
      // 后续在片元shader对opacity进行clip即可
      
  • 效果
    现在可以通过调节Diffuse Opacity Contrast 和 Depth Fade Distance来控制云的不透明度

自发光

  • 为了控制云的颜色,需要对云上色,分别是红绿蓝三种颜色,这三种颜色控制云的三个区域,随后采样在shader中提取对应通道进行lerp

  • 纹理

    • R通道:基色

    • G通道:水平lerp

    • B通道:边缘

  • 实现

    half3 GetSurfaceEmission(float2 uv)
    {
        half3 o = half3(0, 0, 0);
    
        half3 emissiveColor = SAMPLE_TEXTURE2D(_EmissionTex, sampler_EmissionTex, uv);
        _BaseContrast = max(0.0001f, _BaseContrast);
        _HorizionContrast = max(0.0001f, _HorizionContrast);
        _RimContrast = max(0.0001f, _RimContrast);
        _RimPower = max(0.0001f, _RimPower);
        
        half RChannel = emissiveColor.r;
        RChannel = pow(RChannel, _BaseContrast);
        half GChannel = emissiveColor.g;
        GChannel = pow(GChannel, _HorizionContrast);
        half BChannel = emissiveColor.b;
        BChannel = pow(BChannel, _RimContrast);
    
        o = lerp(_OverlayTint1, _OverlayTint2, RChannel);
        o = lerp(o, _HorizionTint, GChannel);
        o = lerp(o, _RimTint * _RimPower, BChannel);
    
        return o;
    }
    
  • 效果

Parallax Occlusion Mapping

  • 目前实现的云已经有一定的体积感,但为了更好的视觉效果,这里还添加了Parallax Occlusion Mapping视差贴图

  • 实现

    float2 ParallaxOcclusionMapping(Texture2D heightTex, sampler sampler_heightTex, float2 uv, float4 positionCS, half3 viewDirTSNor, half heightRatio, half minLayer, half maxLayer)
    {
        float numLayers = lerp(maxLayer, minLayer, abs(dot(half3(0.h, 0.h, 1.h), viewDirTSNor)));
        float layerHeight = 1.f / numLayers;  // 每层高度
        float currentLayerHeight = 0.f;
    
        // shift of texture coordinates for each layer
        float2 uvDelta = heightRatio * viewDirTSNor.xy / viewDirTSNor.z / numLayers;
        float2 currentUV = uv;
    
        float currentHeightTexValue = GetHeight(currentUV, heightTex, sampler_heightTex);
        while(currentLayerHeight < currentHeightTexValue)
        {
            currentUV -= uvDelta;   // shift of texture coordinates
            currentLayerHeight += layerHeight;  // to next layer
            currentHeightTexValue = GetHeight(currentUV, heightTex, sampler_heightTex); // new height
        }
    
        // last uv
        float2 lastUV = currentUV + uvDelta;
    
        // heights for lerp
        float nextHeight    = currentHeightTexValue - currentLayerHeight;
        float lastHeight    = GetHeight(lastUV, heightTex, sampler_heightTex) - currentLayerHeight + layerHeight;
        
        // proportions for lerp
        float weight = nextHeight / (nextHeight - lastHeight);
    
        // lerp uv
        float2 result = lastUV * weight + currentUV * (1.f-weight);
    
        // lerp depth values
        float parallaxHeight = currentLayerHeight + lastHeight * weight + nextHeight * (1.0 - weight);
    
        return result;
    }
    

动画

  • 最后,为云加上动画,这里使用flowmap,和一个Noise 对floawmap进行扰动

  • 纹理

    • Flowmap

    • Noise

  • 实现

    void CalcFlow(inout float2 uv3, float2 uv4)
    {
        float2 flowValue = SAMPLE_TEXTURE2D(_FlowTex, sampler_FlowTex, uv3).rg;
    
        float2 flowNoisePanner = panner(uv4, _NoisePannerTime * _Time.y, _PannerSpeed);
        float flowNoiseValue = SAMPLE_TEXTURE2D(_FlowNoiseTex, sampler_FlowNoiseTex, flowNoisePanner).r;
        flowNoiseValue *= _FlowPower;
    
        float2 baseUV = lerp(uv3, flowValue, flowNoiseValue);
    
        uv3 = panner(baseUV, _BasePannerTime * _Time.y, _PannerSpeed);
    }
    
  • 效果

reference

吉卜力风的卡通云

Tyler Smith

GLSL 中的视差遮蔽映射

标签:Depth,lerp,half,float,depth,Unity,URP,风格化,float2
From: https://www.cnblogs.com/chenglixue/p/18063002

相关文章

  • Unity3D 多线程定时器的原理与实现详解
    Unity3D提供了丰富的功能和工具,让开发者可以轻松地创建各种类型的游戏。其中,定时器是一个非常重要的功能,在游戏开发中经常会被使用到。Unity3D中并没有提供原生的多线程定时器功能,但我们可以通过一些技巧和方法来实现一个多线程定时器。对啦!这里有个游戏开发交流小组里面聚集了......
  • Unity3D 多人战场Animation优化详解
    在多人战场游戏中,动画的优化是非常重要的,因为动画是游戏中的核心元素之一,直接影响玩家的游戏体验。对啦!这里有个游戏开发交流小组里面聚集了一帮热爱学习游戏的零基础小白,也有一些正在从事游戏开发的技术大佬,欢迎你来交流学习。在本文中,我们将详细介绍如何在Unity3D中优化多人战......
  • [Unity/Gamma校正]通俗解释Gamma空间
    经常接触纹理制作或是shader编写应该多多少少都听说过Gamma校正Gamma校正本身很好理解,\(Gamma\=\Linear^{2.2}\)通过\(pow2.2\)这条曲线,将线性的颜色值映射到非线性 耳熟能详的案例是中灰值 人眼对灰度的感知不是线性的,如果线性地显示深度会觉得中灰偏亮这是因为人......
  • burpsuit app 抓包 安卓7.0以上证书制作
    burpsuitapp抓包以及安卓7.0以上证书制作前言:今天在使用某校园跑脚本时需要上传token,只能抓包获取,但发现安卓7.0以上的证书不能直接导入,故记录一下制作以及导入方式。首先我们要从burpsuite的客户端或者官方网页获得证书,将证书放在kali中或其他带有openssl的linux系统中,对其......
  • Unity3D 渲染队列 ZTest与ZWrite详解
    在Unity3D中,渲染队列(RenderingQueue)是一个非常重要的概念,它决定了游戏中各个物体的渲染顺序和优先级。而在渲染队列中,ZTest和ZWrite又是两个关键的参数,它们决定了物体在渲染的过程中如何处理深度测试和深度写入。本文将详细介绍Unity3D中的渲染队列、ZTest和ZWrite的概念,并给出相......
  • Unity3D 立方体纹理与自制天空盒详解
    在Unity3D中,立方体纹理和自制天空盒是常见的技术,它们可以帮助开发者创建出更加真实和引人入胜的游戏场景。本文将详细介绍Unity3D中立方体纹理和自制天空盒的实现方法,希望能帮助读者更好地理解和运用这些技术。对啦!这里有个游戏开发交流小组里面聚集了一帮热爱学习游戏的零基础小......
  • Unity3D 多人战场Animation优化详解
    在多人战场游戏中,动画的优化是非常重要的,因为动画是游戏中的核心元素之一,直接影响玩家的游戏体验。对啦!这里有个游戏开发交流小组里面聚集了一帮热爱学习游戏的零基础小白,也有一些正在从事游戏开发的技术大佬,欢迎你来交流学习。在本文中,我们将详细介绍如何在Unity3D中优化多人战......
  • iOS使用Unity容器动态加载3D模型
    项目背景我们的APP是一个数字藏品平台,里面的很多藏品需要展示3D模型,3D模型里面可能会包含场景,动画,交互。而对应3D场景来说,考虑到要同时支持iOS端,安卓端,Unity是个天然的优秀方案。对于Unity容器来说,需要满足如下的功能:1.在APP启动时,需要满足动态下载最新的模型文件。2.在点击藏......
  • BurpSuite使用教程
    BurpSuite使用教程BurpSuite是基于java环境运行,所以要安装java环境启动BurpSuite方式第一种:双击BurpSuite.jar,点击run进行进入第二种:命令启动或者创建一个.bat文件(批处理文件),写入命令,双击启动(该命令与第一种run旁边的命令一致)java-noverify-javaagent:burploader.jar-jar......
  • 基于unity和c#的障碍跑酷游戏的二次开发
    一、设计背景近年来,虚拟现实技术取得了突飞猛进的发展,为游戏行业带来了新的机遇。通过将跑酷游戏与虚拟现实技术相结合,可以为玩家提供更加真实、沉浸式的游戏体验,让玩家仿佛置身于现实世界中的跑酷场景中。现代游戏越来越注重玩家之间的互动和竞技。跑酷游戏可以设置多人在线模......