自言自语
消融效果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 几个东西绕来绕去嵌套进行 确实把我这个笨脑子给绕晕了。 好歹是给理出来了。。。 难啊 又睡这么晚。。。只能吃点保肝药了。。