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 入门精要

  • 相关阅读:
    949. Largest Time for Given Digits
    450. Delete Node in a BST
    983. Minimum Cost For Tickets
    16. 3Sum Closest java solutions
    73. Set Matrix Zeroes java solutions
    347. Top K Frequent Elements java solutions
    215. Kth Largest Element in an Array java solutions
    75. Sort Colors java solutions
    38. Count and Say java solutions
    371. Sum of Two Integers java solutions
  • 原文地址:https://www.cnblogs.com/SHOR/p/8044437.html
Copyright © 2011-2022 走看看