zoukankan      html  css  js  c++  java
  • Unity Shader 噪声消融特效

    噪声是个很神奇的东西,以前接触的时候就是在自动生成地图上,因为噪声本来就近自然所以,很多特效也是基于噪声的。

    前几篇文章介绍了纹理和光照,这回其实也就是用这么多。就是光照加一个噪声的法线纹理。

    你可能就玩过一款游戏,剑灵,游戏中怪物死亡的时候会有一种消融的效果。让我们来看一看是怎么实现的。

    下面三个图片分别是BurnAmount = 0、BurnAmount = 0.25、BurnAmount = 0.5时的效果。

      

    这里我们用两个Pass来处理这个效果

    • 第一个Pass:渲染模型的正常颜色和消融的混合颜色
    • 第二个Pass:处理消融的阴影,如不特殊处理则影子不会有消融效果。

    下面给出代码(有必要的注释)

      1 Shader "Shader/Shader"
      2 {
      3     Properties
      4     {
      5         _MainTex ("Main Tex", 2D) = "white" {}
      6         // 法线贴图
      7         _BumpMap ("Bump Map", 2D) = "bump" {}
      8         // 噪声贴图
      9         _BurnMap ("Burn Map", 2D) = "white" {}
     10         // 控制消融程度
     11         _BurnAmount ("Burn Amount", Range(0, 1)) = 0
     12         // 控制模型烧焦效果的线宽
     13         _LineWidth ("Burn Line Width", Range(0.0, 0.2)) = 0.1
     14         // 烧焦边缘的颜色
     15         _BurnColor ("Burn Color", Color) = (1, 0, 0, 1)
     16     }
     17     SubShader
     18     {
     19         Tags { "RenderType"="Opaque" "Queue"="Geometry" }
     20 
     21         Pass
     22         {
     23             Tags { "LightMode"="ForwardBase" }
     24             
     25             // 所有面都不被剔除,因为消融的时候应该可以看到物体的内部。
     26             Cull Off
     27 
     28             CGPROGRAM
     29             #pragma vertex vert
     30             #pragma fragment frag
     31             // 为得到正确的光照设置的编译指令
     32             #pragma multi_compile_fwdbase
     33 
     34             #include "Lighting.cginc"
     35             #include "AutoLight.cginc"
     36 
     37             sampler2D _MainTex;
     38             sampler2D _BumpMap;
     39             sampler2D _BurnMap;
     40             float4 _MainTex_ST;
     41             float4 _BumpMap_ST;
     42             float4 _BurnMap_ST;
     43             fixed _BurnAmount;
     44             fixed _LineWidth;
     45             fixed4 _BurnColor;
     46 
     47             struct a2v
     48             {
     49                 float4 vertex : POSITION;
     50                 float3 normal : NORMAL;
     51                 float2 texcoord : TEXCOORD0;
     52                 fixed4 tangent : TANGENT;
     53             };
     54 
     55             struct v2f
     56             {
     57                 float4 pos : SV_POSITION;
     58                 float2 uvMainTex : TEXCOORD0;
     59                 float2 uvBumpMap : TEXCOORD1;
     60                 float2 uvBurnMap : TEXCOORD2;
     61                 // 切线视图的光照方向
     62                 float3 lightDir : TEXCOORD3;
     63                 float3 worldPos : TEXCOORD4;
     64                 // Shader 阴影宏:用于对阴影纹理采样的坐标
     65                 // 参数:一个可用的差值寄存器的索引值,用世界的顶点坐标。即5(从0开始)
     66                 SHADOW_COORDS(5)
     67             };
     68 
     69             v2f vert(a2v v)
     70             {
     71                 v2f o;
     72 
     73                 o.pos = UnityObjectToClipPos(v.vertex);
     74 
     75                 o.uvMainTex = TRANSFORM_TEX(v.texcoord, _MainTex);
     76                 o.uvBumpMap = TRANSFORM_TEX(v.texcoord, _BumpMap);
     77                 o.uvBurnMap = TRANSFORM_TEX(v.texcoord, _BurnMap);
     78 
     79                 TANGENT_SPACE_ROTATION;
     80                 o.lightDir = mul(rotation, ObjSpaceLightDir(v.vertex));
     81                 o.worldPos = UnityObjectToWorldDir(v.vertex);
     82 
     83                 // 阴影宏:在顶点着色器中计算上一步中声明的阴影纹理坐标
     84                 TRANSFER_SHADOW(o);
     85 
     86                 return o;
     87             }
     88 
     89             fixed4 frag(v2f i) : SV_Target
     90             {
     91                 // 取噪声贴图进行采样
     92                 fixed3 burn = tex2D(_BurnMap, i.uvBurnMap);
     93                 // 用于剔除像素点,if (采样结果-消融程度阀值 > 0) 存留 or 丢弃
     94                 clip(burn.r - _BurnAmount);
     95 
     96                 fixed3 albedo = tex2D(_MainTex, i.uvMainTex).rgb;
     97 
     98                 fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
     99 
    100                 fixed3 tangentLightDir = normalize(i.lightDir);
    101                 fixed3 tangentNormal = UnpackNormal(tex2D(_BumpMap, i.uvBumpMap));
    102                 fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(tangentLightDir, tangentNormal));
    103 
    104                 // 阴影宏:计算阴影值,最后与漫反射的颜色叠加
    105                 UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);
    106 
    107                 // smoothsetp(e1,e2,x)平滑过度函数
    108                 // 原理:if (x < e1) 结果 = 0
    109                 // if (x > e2) 结果 = 1
    110                 // if (e1 < x < e2) 结果 = 3 * pow(x, 2) - 2 * pow(x, 3)
    111                 // t = 0时,该像素为正常的模型颜色
    112                 // t = 1时,该像素位于消融的边界处
    113                 fixed t = 1 - smoothstep(0.0, _LineWidth, burn.r - _BurnAmount);
    114 
    115                 // 最终颜色,在消融和正常中差值,系数为t
    116                 fixed3 finalColor = lerp(ambient + diffuse * atten, _BurnColor, t);
    117 
    118                 return fixed4(finalColor, 1);
    119             }
    120             ENDCG
    121         }
    122 
    123         // 此Pass是处理阴影的,我们需要按照正常的Pass的处理来剔除片元或进行顶点动画。以便阴影可以和物体正常渲染的结果相匹配。
    124         Pass
    125         {
    126             // 光照模式定义为阴影
    127             Tags { "LightMode"="ShadowCaster" }
    128 
    129             CGPROGRAM
    130             #pragma vertex vert
    131             #pragma fragment frag
    132             // 处理阴影的编译指令
    133             #pragma multi_compile_shadowcaster
    134             
    135             #include "UnityCG.cginc"
    136 
    137             fixed _BurnAmount;
    138             sampler2D _BurnMap;
    139             float4 _BurnMap_ST;
    140 
    141             struct a2v
    142             {
    143                 float4 vertex : POSITION;
    144                 float2 texcoord : TEXCOORD0;
    145                 float3 normal : NORMAL;
    146                 float4 tangent: TANGENT;
    147             };
    148 
    149             struct v2f
    150             {
    151                 // 定义阴影投射需要定义的变量
    152                 V2F_SHADOW_CASTER;
    153                 float2 uvBurnMap : TEXCOORD0;
    154             };
    155             
    156             v2f vert (a2v v)
    157             {
    158                 v2f o;
    159 
    160                 // 填充V2F_SHADOW_CASTER定义的变量
    161                 TRANSFER_SHADOW_CASTER_NORMALOFFSET(o)
    162                 o.uvBurnMap = TRANSFORM_TEX(v.texcoord, _BurnMap);
    163 
    164                 return o;
    165             }
    166             
    167             fixed4 frag (v2f i) : SV_Target
    168             {
    169                 fixed3 burn = tex2D(_BurnMap, i.uvBurnMap);
    170                 
    171                 clip(burn - _BurnAmount);
    172 
    173                 // 让Unity完成阴影投射
    174                 SHADOW_CASTER_FRAGMENT(i)
    175             }
    176             ENDCG
    177         }
    178     }
    179 }

    本文引自Unity Shader 入门精要

  • 相关阅读:
    java
    java
    java
    java
    java
    java
    java
    java
    sed命令的用法
    linux系统产生随机数的6种方法
  • 原文地址:https://www.cnblogs.com/SHOR/p/8044437.html
Copyright © 2011-2022 走看看