1. 程式人生 > >Unity3D 自定義光照模型實現

Unity3D 自定義光照模型實現

// Use BlinnPhong Shader "U1/Obj/U1ObjNoAmbient" { Properties{ _Color("Diffuse Material Color", Color) = (1,1,1,1) _SpecColor("Specular Material Color", Color) = (1,1,1,1) _MainTex("Base (RGB) Gloss (A)", 2D) = "white" {} _BumpMap("Normalmap", 2D) = "bump" {} // 材料鏡面光澤度 _EmissionMap("Emission", 2D) = "black" {} } SubShader{ Pass{ Tags{ "LightMode" = "ForwardBase" } // pass for ambient light and first light source CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" uniform float4 _LightColor0; // color of light source (from "Lighting.cginc") // User-specified properties uniform float4 _Color; uniform float4 _SpecColor; sampler2D _MainTex; sampler2D _BumpMap; sampler2D _EmissionMap; struct vertexInput { float4 vertex : POSITION; float2 uv : TEXCOORD0; //float3 normal : NORMAL; }; struct vertexOutput { float4 pos : SV_POSITION; float2 uv : TEXCOORD0; float3 lightDir : TEXCOORD1;//未規範化的 float3 viewDir : TEXCOORD2; }; vertexOutput vert(vertexInput input) { vertexOutput output; output.pos = mul(UNITY_MATRIX_MVP, input.vertex); output.uv = input.uv; float4 vertexWorldPos = mul(_Object2World, input.vertex); if (0.0 == _WorldSpaceLightPos0.w) // directional light? { output.lightDir = _WorldSpaceLightPos0.xyz; } else { output.lightDir = _WorldSpaceLightPos0 - vertexWorldPos; } #if !defined(GSE_SHADER_LOW) output.viewDir = normalize(_WorldSpaceCameraPos - vertexWorldPos); #else output.viewDir = float3(0, 0, 0); #endif return output; } float4 frag(vertexOutput input) : COLOR { float4 resColor = tex2D(_MainTex, input.uv); resColor = resColor * _Color; float4 bumTex = tex2D(_BumpMap, input.uv); float3 normalObjectDir = UnpackNormal(bumTex); // the same as mul(transpose(_World2Object), float4(input.normal, 0.0)) but fast. float3 normalDir = normalize(mul(normalObjectDir, _World2Object).xyz); float attenuation; if (0.0 == _WorldSpaceLightPos0.w) // directional light? { attenuation = 1.0; // no attenuation } else // point or spot light { float distance = length(input.lightDir); attenuation = 1.0 / distance; // linear attenuation } // 移除全域性環境光影響 /*float3 ambientLighting = UNITY_LIGHTMODEL_AMBIENT.rgb * _Color.rgb;*/ float3 lightDir = normalize(input.lightDir); float3 diffuseReflection = attenuation * _LightColor0.rgb * resColor.rgb * max(0.0, dot(normalDir, lightDir)); resColor.rgb += diffuseReflection.rgb; #if !defined(GSE_SHADER_LOW) float4 emissionTex = tex2D(_EmissionMap, input.uv); half shininess = 1 - emissionTex.r; if (dot(normalDir, lightDir) > 0.0) // light source on the wrong side? { float3 h = normalize(lightDir + input.viewDir); float nh = max(0.0, dot(normalDir, h)); float spec = min(pow(nh, shininess*128.0), (1 - shininess)*1.2); // max = 1.0 to avoid flick effect when object is small //c.rgb *= 1 + s.Emission.r; // emission, no need to calculate here resColor.rgb += attenuation * _LightColor0.rgb * _SpecColor.rgb * spec; // specular } #endif return resColor;//ambientLighting + } ENDCG } Pass{ Tags{ "LightMode" = "ForwardAdd" } // pass for additional light sources Blend One One // additive blending CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" uniform float4 _LightColor0; // color of light source (from "Lighting.cginc") // User-specified properties uniform float4 _Color; uniform float4 _SpecColor; sampler2D _BumpMap; sampler2D _EmissionMap; struct vertexInput { float4 vertex : POSITION; float2 uv : TEXCOORD0; //float3 normal : NORMAL; }; struct vertexOutput { float4 pos : SV_POSITION; float2 uv : TEXCOORD0; float3 lightDir : TEXCOORD1; float3 viewDir : TEXCOORD2; }; vertexOutput vert(vertexInput input) { vertexOutput output; output.pos = mul(UNITY_MATRIX_MVP, input.vertex); output.uv = input.uv; float4 vertexWorldPos = mul(_Object2World, input.vertex); if (0.0 == _WorldSpaceLightPos0.w) // directional light? { output.lightDir = _WorldSpaceLightPos0.xyz; } else { output.lightDir = _WorldSpaceLightPos0 - vertexWorldPos; } #if !defined(GSE_SHADER_LOW) output.viewDir = normalize(_WorldSpaceCameraPos - vertexWorldPos); #else output.viewDir = float3(0, 0, 0); #endif return output; } float4 frag(vertexOutput input) : COLOR { float4 bumTex = tex2D(_BumpMap, input.uv); float3 normalObjectDir = UnpackNormal(bumTex); // the same as mul(transpose(_World2Object), float4(input.normal, 0.0)) but fast. //float3 normalDir = normalize(mul(normalObjectDir, _World2Object).xyz); float3 normalDir = normalize(mul(normalObjectDir, _World2Object).xyz); float3 lightDirection; float attenuation; if (0.0 == _WorldSpaceLightPos0.w) // directional light? { attenuation = 1.0; // no attenuation } else // point or spot light { float distance = length(input.lightDir); attenuation = 1.0 / distance; // linear attenuation } float3 lightDir = normalize(input.lightDir); float3 resColor = attenuation * _LightColor0.rgb * _Color.rgb * max(0.0, dot(normalDir, lightDir)); #if !defined(GSE_SHADER_LOW) float4 emissionTex = tex2D(_EmissionMap, input.uv); half shininess = 1 - emissionTex.r; if (dot(normalDir, lightDir) > 0.0) // light source on the wrong side? { float3 h = normalize(lightDir + input.viewDir); float nh = max(0.0, dot(normalDir, h)); float spec = min(pow(nh, shininess*128.0), (1 - shininess)*1.2); // max = 1.0 to avoid flick effect when object is small //c.rgb *= 1 + s.Emission.r; // emission, no need to calculate here resColor.rgb += attenuation * _LightColor0.rgb * _SpecColor.rgb * spec; // specular } #endif return float4(resColor, 1.0); // no ambient lighting in this pass } ENDCG } } FallBack "Mobile/VertexLit" } 參考: