赞
踩
效果图:
代码:
- Shader "CustomShader/Texture/RampShader"
- {
- Properties
- {
- _RampTex ("Texture", 2D) = "white" {}
- _Color ("Color Tint", Color) = (1, 1, 1, 1)
- _Specular ("Specular", Color) = (1, 1, 1, 1)
- _Gloss ("Gloss", Range(8.0, 256)) = 20
- }
- SubShader
- {
- Pass
- {
- Tags {"LightMode" = "ForwardBase"}
-
- CGPROGRAM
- #pragma vertex vert
- #pragma fragment frag
-
- #include "Lighting.cginc"
-
- sampler2D _RampTex; //渐变纹理
- float4 _RampTex_ST; //纹理属性变量
- fixed4 _Color;
- fixed4 _Specular;
- float _Gloss;
-
- struct appdata
- {
- float4 vertex : POSITION;
- float2 uv : TEXCOORD0;
- float3 normal : NORMAL;
- };
-
- struct v2f
- {
- float2 uv : TEXCOORD0;
- float4 vertex : SV_POSITION;
- float3 worldPos : TEXCOORD1;
- float3 worldNormal : TEXCOORD2;
- };
-
- v2f vert (appdata v)
- {
- v2f o;
- o.vertex = UnityObjectToClipPos(v.vertex);
- //内置宏TRANSFORM_TEX计算经过平铺和偏移后的纹理坐标
- o.uv = TRANSFORM_TEX(v.uv, _RampTex);
- o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
- o.worldNormal = UnityObjectToWorldNormal(v.normal);
-
- return o;
- }
-
- fixed4 frag (v2f i) : SV_Target
- {
- fixed3 worldNormal = normalize(i.worldNormal);
- fixed3 lightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
- fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
-
- fixed halfLambert = dot(worldNormal, lightDir) * 0.5 + 0.5;
- fixed3 color = tex2D(_RampTex, fixed2(halfLambert, halfLambert)).rgb * _Color.rgb;
-
- fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
-
- fixed3 diffuse = _LightColor0.rgb * color;
-
- fixed3 halfDir = normalize(viewDir + lightDir);
- fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(worldNormal, halfDir)), _Gloss);
-
- return fixed4(ambient + diffuse + specular, 1.0);
- }
- ENDCG
- }
- }
-
- FallBack "Specular"
- }
在片段着色器中使用半兰伯特光照模型:
- fixed halfLambert = dot(worldNormal, lightDir) * 0.5 + 0.5;
- fixed3 color = tex2D(_RampTex, fixed2(halfLambert, halfLambert)).rgb * _Color.rgb;
在上面的代码中,通过对法线方向和光照方向的点积做一次0.5倍的缩放以及一个0.5大小的偏移来计算半兰伯特部分halfLambert。这样,我们得到的halfLambert 的范围被映射到了[0,1]之间。之后,我们使用halfLambert 来构建一个纹理坐标,并用这个纹理坐标对渐变纹理_RampTex进行采样。由于_RampTex实际就是一个一维纹理(它在纵轴方向上颜色不变),因此纹理坐标的u和v方向我们都使用了halfLambert。 然后,把从渐变纹理采样得到的颜色和材质颜色Color相乘,得到最终的漫反射颜色。剩下的代码就是计算高光反射和环境光,并把它们的结果进行相加。
fixed2(halfLambert, halfLambert) 这句其实我们只关心其x坐标,y坐标没意义。那么halfLambert为什么可以与纹理坐标联系起来呢,我们从漫反射的公式中看出,法线与光照方向的夹角决定了光照系数,夹角越小,光照系数越大,漫反射越强,反之,系数越小,漫反射越弱,那么我们用渐变纹理的x轴表示其系数变化,x轴也就是系数越小,就采样越黑的颜色,表示漫反射越弱,系数越大也就是x越大,就采样越白的颜色,表示漫反射越强,所以我们的渐变纹理是从左到右从黑到白,就是这个原理。
————————————————
版权声明:本文为CSDN博主「Aimar_Johnny」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/lzhq1982/article/details/77659332
需要注意的是,我们需要把渐变纹理的Wrap Mode 设为Clamp模式,以防止对纹理进行采样时由于浮点数精度而造成的问题。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。