基本光照模型简单实现
Lambert光照模型,根据光照向量与顶点法线的夹角来确定光照强度:
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)' Shader "James/Lambert" { Properties { _MainTex("MainTex", 2D) = "white" {} } SubShader { Pass { Tags { "LightMode" = "ForwardBase" } CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" fixed4 _LightColor0; sampler2D _MainTex; float4 _MainTex_ST; struct v2f { float4 pos : SV_POSITION; float2 uv : TEXCOORD0; float3 lightDir : TEXCOORD1; float3 normal : TEXCOORD2; }; v2f vert(appdata_full v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.texcoord, _MainTex); // 从顶点位置到Light的局部向量 o.lightDir = ObjSpaceLightDir(v.vertex); o.normal = v.normal; return o; } float4 frag(v2f i) : COLOR { i.lightDir = normalize(i.lightDir); i.normal = normalize(i.normal); // 纹理采样 float4 c = tex2D(_MainTex, i.uv); // 光强度,法向和光照方向的cos值 float diffuse = max(0, dot(i.normal, i.lightDir)); // 纹理色 * 光源色 * 强度参数 c = c * _LightColor0 * diffuse; return c; } ENDCG } } FallBack "Diffuse" }
Phong光照模型,根据光照向量的反射向量与视线的夹角来计算镜面高光的强度,另外再加上漫射光的成分:
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)' Shader "James/Phong" { Properties { _MainTex("MainTex", 2D) = "white" {} _Gloss("Gloss", Float) = 1 _Shininess("Shininess", Float) = 10 _SpecColor("Specular Color", Color) = (1,1,1,1) } SubShader { Pass { Tags { "LightMode" = "ForwardBase" } CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" fixed4 _LightColor0; sampler2D _MainTex; float4 _MainTex_ST; float _Gloss; float _Shininess; fixed4 _SpecColor; struct v2f { float4 pos : SV_POSITION; float2 uv : TEXCOORD0; float3 normal : TEXCOORD1; float3 lightDir : TEXCOORD2; // 光照方向 float3 reflectLightDir : TEXCOORD3; // 光照反射方向 float3 viewDir : TEXCOORD4; // 视线方向 }; v2f vert(appdata_full v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.texcoord, _MainTex); o.normal = v.normal; // 从顶点位置到light的局部向量 o.lightDir = ObjSpaceLightDir(v.vertex); // 反射向量,注意需要使用-o.lightDir o.reflectLightDir = reflect(-o.lightDir, v.normal); // 视线,顶点到camera的局部变量 o.viewDir = ObjSpaceViewDir(v.vertex); return o; } float4 frag(v2f i) : COLOR { i.lightDir = normalize(i.lightDir); i.normal = normalize(i.normal); i.reflectLightDir = normalize(i.reflectLightDir); i.viewDir = normalize(i.viewDir); // 纹理采样 float4 c = tex2D(_MainTex, i.uv); // 漫射光强度 float diffuse = max(0, dot(i.normal, i.lightDir)); // 镜面光强度 float specular = max(0, dot(i.reflectLightDir, i.viewDir)); specular = pow(specular, _Shininess) * _Gloss; // 纹理色 * 光源色 * 强度参数 c = (c * diffuse + _SpecColor * specular) * _LightColor0; return c; } ENDCG } } FallBack "Diffuse" }
BlinnPhong光照模型,根据光照向量和视线的半角向量,与顶点法线的夹角来计算镜面高光的强度,另外再加上漫射光的成分:
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)' Shader "James/BlinnPhong" { Properties { _MainTex("MainTex", 2D) = "white" {} _Gloss("Gloss", Float) = 5 _Shininess("Shininess", Float) = 10 _SpecColor("Specular Color", Color) = (1,1,1,1) } SubShader { Pass { Tags { "LightMode" = "ForwardBase" } CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" fixed4 _LightColor0; sampler2D _MainTex; float4 _MainTex_ST; float _Gloss; float _Shininess; fixed4 _SpecColor; struct v2f { float4 pos : SV_POSITION; float2 uv : TEXCOORD0; float3 normal : TEXCOORD1; float3 lightDir : TEXCOORD2; // 光照方向 float3 viewDir : TEXCOORD3; // 视线方向 }; v2f vert(appdata_full v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.texcoord, _MainTex); o.normal = v.normal; // 顶点->light的局部向量 o.lightDir = ObjSpaceLightDir(v.vertex); // 顶点->camera的局部向量 float3 viewDir = ObjSpaceViewDir(v.vertex); // 视线,顶点到camera的局部变量 o.viewDir = ObjSpaceViewDir(v.vertex); return o; } float4 frag(v2f i) : COLOR { i.lightDir = normalize(i.lightDir); i.normal = normalize(i.normal); i.viewDir = normalize(i.viewDir); // 半角向量,光照方向和视线的中间值 float3 halfDir = (i.lightDir + i.viewDir) * 0.5; halfDir = normalize(halfDir); // 纹理采样 float4 c = tex2D(_MainTex, i.uv); // 漫射光强度 float diffuse = max(0, dot(i.normal, i.lightDir)); // 镜面光强度 float specular = max(0, dot(i.normal, halfDir)); specular = pow(specular, _Shininess) * _Gloss; // 纹理色 * 光源色 * 强度参数 c = (c * diffuse + _SpecColor * specular) * _LightColor0; return c; } ENDCG } } FallBack "Diffuse" }
BinnPhong比Phong少计算一次反射向量,会更简洁和高效。
带光源衰减的计算方式:
Shader "James/Direct2" { Properties { _Color("Color",Color) = (1,1,1,1) _SpecularColor("Specular",Color) = (1,1,1,1) _Gloss("Gloss",Range(8.0,256)) = 20 } SubShader { Pass { Tags{"LightMode" = "ForwardBase"} CGPROGRAM #pragma multi_compile_fwdbase #pragma vertex vert #pragma fragment frag #include "Lighting.cginc" #include "AutoLight.cginc" //计算阴影所用的宏包含在AutoLight.cginc文件中 fixed4 _Color; fixed4 _SpecularColor; float _Gloss; struct a2v { float4 vertex:POSITION; float3 normal:NORMAL; }; struct v2f { float4 pos:SV_POSITION; float3 worldPos:TEXCOORD0; float3 worldNormal:TEXCOORD1; SHADOW_COORDS(2) //该宏的作用是声明一个用于对阴影纹理采样的坐标 //这个宏的参数是下一个可用的插值寄存器的索引值,上述中为2 }; v2f vert(a2v v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.worldPos = mul(unity_ObjectToWorld,v.vertex).xyz; o.worldNormal = UnityObjectToWorldNormal(v.normal); TRANSFER_SHADOW(o); //该宏用于计算上一步声明的阴影纹理采样坐标 return o; } fixed4 frag(v2f i) :SV_Target { float3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos)); float3 worldNormal = normalize(i.worldNormal); float3 worldViewDir = normalize(UnityWorldSpaceViewDir(i.worldPos)); fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz; fixed3 diffuse = _LightColor0.rgb*_Color.rgb*max(0,dot(worldLightDir,worldNormal)); fixed3 halfDir = normalize(worldLightDir + worldViewDir); fixed3 specularColor = _LightColor0.rgb*_SpecularColor.rgb*pow(saturate(dot(halfDir,worldNormal)),_Gloss); fixed shadow = SHADOW_ATTENUATION(i); //片元着色器中计算阴影值 fixed atten = 1.0; return fixed4(ambient + (diffuse + specularColor)*atten*shadow,1.0); } ENDCG } Pass { Tags{"LightMode" = "ForwardAdd"} Blend One One CGPROGRAM #pragma multi_compile_fwdadd #pragma vertex vert #pragma fragment frag #include "Lighting.cginc" #include "AutoLight.cginc" fixed4 _Color; fixed4 _SpecularColor; float _Gloss; struct a2v { float4 vertex:POSITION; float3 normal:NORMAL; }; struct v2f { float4 pos:SV_POSITION; float3 worldPos:TEXCOORD0; float3 worldNormal:TEXCOORD1; }; v2f vert(a2v v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.worldPos = mul(unity_ObjectToWorld,v.vertex).xyz; o.worldNormal = UnityObjectToWorldNormal(v.normal); return o; } fixed4 frag(v2f i) :SV_Target { #ifdef USING_DIRECTIONAL_LIGHT fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz); fixed atten = 1.0; #else fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz - i.worldPos.xyz); float3 lightCoord = mul(unity_WorldToLight,float4(i.worldPos,1.0)).xyz; fixed atten = tex2D(_LightTexture0,dot(lightCoord,lightCoord).rr).UNITY_ATTEN_CHANNEL; #endif float3 worldNormal = normalize(i.worldNormal); float3 worldViewDir = normalize(UnityWorldSpaceViewDir(i.worldPos)); fixed3 diffuse = _LightColor0.rgb*_Color.rgb*max(0,dot(worldLightDir,worldNormal)); fixed3 halfDir = normalize(worldLightDir + worldViewDir); fixed3 specularColor = _LightColor0.rgb*_SpecularColor.rgb*pow(saturate(dot(halfDir,worldNormal)),_Gloss); return fixed4((diffuse + specularColor)*atten,1.0); } ENDCG } } FallBack "Specular" }
参考:https://blog.csdn.net/u013477973/article/details/80639969