消散效果shader实践含clip阴影pass——UnityShader学习笔记

自言自语

消融效果shader学习练习笔记 没啥可说得了 写完看不见模型了 ORZ

然后晚上回来把绕不明白的几个函数给绕明白了。。。再加上阴影相关的几个宏 单独列个PASS 保持消散时的阴影一致 这几个宏得记一下 我这里默写下

CGPROGRAM块中 还要额外添加一段声明

#pragma multi_compile_shadowcaster

V2F 结构体中 V2F_SHADOW_CASTER;
顶点着色器中 TRANSFER_SHADOW_CASTER_NORMALOFFSET(o)
片元着色其中 SHADOW_CASETER_FRAGMENT(i)

一、效果部分

在这里插入图片描述

二、Shader部分

Shader "TNShaderPractise/ShaderPractise_Dissolve_40"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _NormalMap("法线贴图",2D)="bump"{}
        _DissolveMap("噪声贴图",2D)="white"{}
        _DissolveValue("溶解大小",Range(0,2))=0.2
        _LineWidth("边缘宽度",Range(0,0.7))=0.1
        [HDR]_LineColor01("边缘颜色1",Color)=(1,1,1,1)
        [HDR]_LineColor02("边缘颜色2",Color)=(1,1,1,1)
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" "Queue"="Transparent" }
        Pass
        {
		//第一次写完模型不见了,也没报错,最后查了半天才发现 把 "ForwardBase" 拼错了..... 因此标记下  提醒自己
            Tags{"LightMode"="ForwardBase"}

			Cull Off

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile_fwdbase
            #include "Lighting.cginc"
            #include "UnityCG.cginc"
            #include "AutoLight.cginc"

            struct a2v
            {
                float4 vertex : POSITION;
				//因为不需要其他空间下的转换 因此只在切线空间下进行法线计算就可以  不需要TBN转换矩阵,因此利用 TANGENT_SPACE_ROTATION宏来帮我们完成光源的空间转换即可
                float4 tangent : TANGENT;
                float3 normal : NORMAL;
                float4 texcoord : TEXCOORD0;
            };

            struct v2f
            {
                float4 uv : TEXCOORD1;
                float4 worldPos : TEXCOORD2;
                float4 pos : SV_POSITION;
                float3 tangentLightDir : TEXCOORD4;
                SHADOW_COORDS(3)
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            sampler2D _NormalMap;
            sampler2D _DissolveMap;
            float4 _DissolveMap_ST;
            float _DissolveValue;
            float _LineWidth;
            fixed4 _LineColor01;
            fixed4 _LineColor02;


            v2f vert (a2v v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.uv.xy = v.texcoord;
                o.uv.zw =TRANSFORM_TEX(v.texcoord,_DissolveMap);

                TANGENT_SPACE_ROTATION;
                o.tangentLightDir = mul(rotation,ObjSpaceLightDir(v.vertex)).xyz;

                o.worldPos = mul(unity_ObjectToWorld,v.vertex);

                TRANSFER_SHADOW(o);

                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 col = tex2D(_MainTex, i.uv.xy);
                fixed4 dissolve = tex2D(_DissolveMap,i.uv.zw);
				//做一个减法 得到透明度测试下 要被剔除的部分
                float dissovleArea = dissolve.b -_DissolveValue;
			   //clip函数将小于0的像素直接不显示
                clip(dissovleArea);

                fixed3 lightDir = normalize(i.tangentLightDir);
				//切线空间下 UnpackNormal正好解压出来是 切线空间下 因此不必再构造TBN矩阵去转换到世界空间啦 当然也可以转换  代码量就多了点
                fixed3 normal = UnpackNormal(tex2D(_NormalMap,i.uv.xy));

				//传统的漫反射计算
                half nl = saturate(dot(normal,lightDir));

                fixed4 ambCol = half4(UNITY_LIGHTMODEL_AMBIENT.xyz,1)*col;

                fixed4 diff = _LightColor0*col*nl;


				//smoothstep函数平滑取得一个和边缘宽度相关的值 这个值其实就是边界范围。

				//**************************************************************************************
				//返回值										条件																			 *
				//		0							x < a < b 或 x > a > b															     *
				//		1							x < b < a 或 x > b > a															     *
				//某个值	                   根据x在域 [a, b] (或者[b, a])中的位置, 返回某个在 [0, 1] 内的值   *
				//**************************************************************************************

				//因为_LineWidth>=0	使我们设定好的一个限制, 则 根据smoothstep函数的意义,我们可以判断 当dissovleArea<0进行透明度测试镂空后,dissovleArea(x)<0(b)<_LineWidth(a)  则dissWidth返回值为1
				//否则dissovleArea不小于0 则像素不会被剔除, 则  dissovleArea(x)>_LineWidth(a) >0(b)  则dissWidth返回值为0 其余是平滑的某个 _LineWidth和0 之间的一个值  则这个值就是一个宽度的范围	   
                float dissWidth = smoothstep (_LineWidth,0,dissovleArea);
				//将溶解边缘部分在宽度范围内进行两个颜色插值,得到一个效果	  宽度范围越接近0 也就是dissWidth越接近0 说明当前像素点越接近于模型内部,因此给_LineColor01 效果红色表示烧的暗沉了 相反则表示烧的最旺最亮的颜色
				//稍微有点绕,所以特别详细并且啰嗦的注释说明下,免得下次看见了又傻逼了..
                fixed4 dissCol = lerp(_LineColor01,_LineColor02,dissWidth);
				//这一步可有可无,只是增加一些饱和度和亮度.
                dissCol = pow(dissCol,5);
				//上阴影
                UNITY_LIGHT_ATTENUATION(atten,i,i.worldPos);

				//最后在用刚才得到的插值参考值 混合边缘颜色和 实际透明度剔除后的漫反射效果.	step这里是保证消散参数为0, 就没有任何消散颜色干扰
                fixed4 finalCol = lerp(diff*atten+ambCol,dissCol,dissWidth*step(0.0001,_DissolveValue));
			   //输出结果
                return finalCol;
            }


            ENDCG
        }

		//第二个pass是为了给透明度裁剪后,正确显示投影的而用的 如果是粒子特效的话 则不需要这个pass
		Pass
		{
		//起个名字以后调用?好像不行 因为参数不通用,, 哈哈
			  NAME "SHADOWCASTERCUSTOM"

			  Tags{"LightMode"="ShadowCaster"}

			  CGPROGRAM
			  #pragma vertex vert
			  #pragma fragment frag

			  //这两句得加上 不然后边的shadow相关宏用不了
			  #pragma multi_compile_shadowcaster
			  #include "UnityCG.cginc"

			  	 //相应用到的属性别忘了声明
				sampler2D _DissolveMap;
				float4 _DissolveMap_ST;
				float _DissolveValue;

			  struct v2f 
			  {
			  //第一句 输出结构体中声明好 第一个宏  V2F_SHADOW_CASTER; 占用的是 TEXCOORD0 的存储空间	   需要分号 “;”
				V2F_SHADOW_CASTER;
				float2 uv : TEXCOORD1;
			  };

			  v2f vert(appdata_base v)
			  {
				v2f o;
				//第二句 顶点着色器中  声明好第二个调用方法  TRANSFER_SHADOW_CASETR_NORMALOFFSET(o)  不需要分号 “;”
				TRANSFER_SHADOW_CASTER_NORMALOFFSET(o)
				 o.uv = TRANSFORM_TEX(v.texcoord,_DissolveMap);
				 return o;
			  }

			  fixed4 frag(v2f i):SV_Target
			  {
				fixed4 dissolve = tex2D(_DissolveMap,i.uv);
				clip(dissolve.b-_DissolveValue);
				//第三句 最后片元着色器中完成阴影相关计算的宏的方法调用  SHADOW_CASETER_FRAGMENT(i)  也不需要分好 ";"
				SHADOW_CASTER_FRAGMENT(i)
			  }
			  ENDCG
		}
    }
	FallBack "Diffuse"
}



总结

smoothstep lerp 几个东西绕来绕去嵌套进行 确实把我这个笨脑子给绕晕了。 好歹是给理出来了。。。 难啊 又睡这么晚。。。只能吃点保肝药了。。

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值