Unity URP Shader之标准的BlinnPhong光照模型
BlinnPhong光照,这是shader中最基础,最经典的光照模型,具体计算方法如下:
1. 漫反射
half3 diffuseCol = NdotL * lightCol * baseCol * shadowAttenuation * distanceAttenuation;
2. 镜面反射
half halfDir = normalize(viewDir + lightDir);
half NdotH = saturate(dot(worldNormal, halfDir));
half3 specularCol = pow(NdotH, gloss) * lightCol * baseCol * shadowAttenuation * distanceAttenuation;
shader如下:
1 Shader "MyURP/Kerry/URPBlinnPhong" 2 { 3 Properties 4 { 5 _BaseMap("Base Map", 2D) = "white" {} 6 _NormalMap("Normal Map", 2D) = "bump" {} 7 _SpecGloss("Specular Gloss", Range(1, 20)) = 8 8 } 9 10 SubShader 11 { 12 Tags 13 { 14 "RenderType" = "Opaque" 15 "RenderPipeline" = "UniversalPipeline" 16 } 17 18 Pass 19 { 20 Tags 21 { 22 "LightMode" = "UniversalForward" 23 } 24 25 HLSLPROGRAM 26 27 // Universal Pipeline keywords 28 #pragma multi_compile _ _MAIN_LIGHT_SHADOWS 29 #pragma multi_compile _ _ADDITIONAL_LIGHTS 30 #pragma multi_compile_fragment _ _ADDITIONAL_LIGHT_SHADOWS 31 32 #pragma vertex vert 33 #pragma fragment frag 34 #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" 35 #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl" 36 37 TEXTURE2D(_BaseMap); SAMPLER(sampler_BaseMap); 38 TEXTURE2D(_NormalMap); SAMPLER(sampler_NormalMap); 39 float _SpecGloss; 40 41 struct appdata 42 { 43 float4 vertex : POSITION; 44 float2 uv : TEXCOORD0; 45 float4 normal : NORMAL; 46 float4 tangent : TANGENT; 47 }; 48 49 struct v2f 50 { 51 float4 pos : SV_POSITION; 52 float2 uv : TEXCOORD0; 53 float3 worldNormal : TEXCOORD1; 54 float3 worldTangent : TEXCOORD2; 55 float3 worldBinormal : TEXCOORD3; 56 float3 worldPos : TEXCOORD4; 57 float4 shadowCoord : TEXCOORD5; 58 }; 59 60 v2f vert(appdata v) 61 { 62 v2f o; 63 o.pos = mul(UNITY_MATRIX_MVP, v.vertex); 64 o.uv = v.uv; 65 o.worldNormal = normalize(mul(v.normal, unity_WorldToObject).xyz); 66 o.worldTangent = normalize(mul(unity_ObjectToWorld, v.tangent).xyz); 67 o.worldBinormal = normalize(cross(o.worldNormal, o.worldTangent) * v.tangent.w); 68 o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz; 69 o.shadowCoord = TransformWorldToShadowCoord(o.worldPos); 70 return o; 71 } 72 73 half4 frag(v2f i) : SV_TARGET 74 { 75 // get info 76 float3 worldNormal = normalize(i.worldNormal); 77 float3 worldTangent = normalize(i.worldTangent); 78 float3 worldBinormal = normalize(i.worldBinormal); 79 float3 worldPos = i.worldPos; 80 81 // sample texture 82 half4 baseMap = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, i.uv); 83 half4 normalMap = SAMPLE_TEXTURE2D(_NormalMap, sampler_NormalMap, i.uv); 84 half3 normalData = UnpackNormal(normalMap); 85 86 // 法线 87 float3x3 matrixTNB = float3x3(worldTangent, worldBinormal, worldNormal); 88 float3 normal = mul(normalData, matrixTNB); 89 90 // 主光源光照计算 91 float4 shadowCoord = i.shadowCoord; 92 float3 worldView = GetWorldSpaceNormalizeViewDir(worldPos); 93 half3 finalLightCol = half3(0, 0, 0); 94 { 95 Light mainLight = GetMainLight(shadowCoord); 96 // diffuse 97 float NdotL = dot(normal, mainLight.direction); 98 NdotL = saturate(NdotL * 0.5 + 0.5); 99 half3 diffuse = baseMap.rgb * mainLight.color * NdotL 100 * mainLight.shadowAttenuation * mainLight.distanceAttenuation; 101 102 // specular 103 float3 halfVL = normalize(mainLight.direction + worldView); 104 float NdotH = saturate(dot(normal, halfVL)); 105 half3 specular = baseMap.rgb * mainLight.color * pow(NdotH, _SpecGloss) 106 * mainLight.shadowAttenuation * mainLight.distanceAttenuation; 107 108 finalLightCol = diffuse + specular; 109 } 110 111 // 其它光源光照计算 112 #if defined(_ADDITIONAL_LIGHTS) 113 uint addLightCount = GetAdditionalLightsCount(); 114 for(uint lightIndex = 0;lightIndex < addLightCount;++lightIndex) 115 { 116 Light addLight = GetAdditionalLight(lightIndex, worldPos, shadowCoord); 117 118 // diffuse 119 float NdotL = dot(normal, addLight.direction); 120 NdotL = saturate(NdotL * 0.5 + 0.5); 121 half3 diffuse = baseMap.rgb * addLight.color * NdotL 122 * addLight.shadowAttenuation * addLight.distanceAttenuation; 123 124 // specular 125 float3 halfVL = normalize(addLight.direction + worldView); 126 float NdotH = saturate(dot(normal, halfVL)); 127 half3 specular = baseMap.rgb * addLight.color * pow(NdotH, _SpecGloss) 128 * addLight.shadowAttenuation * addLight.distanceAttenuation; 129 130 finalLightCol += (diffuse + specular); 131 } 132 #endif 133 134 half4 col = half4(finalLightCol, 1); 135 return col; 136 } 137 138 ENDHLSL 139 } 140 141 Pass 142 { 143 Name "ShadowCaster" 144 Tags{"LightMode" = "ShadowCaster"} 145 146 ZWrite On 147 ZTest LEqual 148 ColorMask 0 149 Cull[_Cull] 150 151 HLSLPROGRAM 152 #pragma exclude_renderers gles gles3 glcore 153 #pragma target 4.5 154 155 // ------------------------------------- 156 // Material Keywords 157 #pragma shader_feature_local_fragment _ALPHATEST_ON 158 #pragma shader_feature_local_fragment _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A 159 160 //-------------------------------------- 161 // GPU Instancing 162 #pragma multi_compile_instancing 163 #pragma multi_compile _ DOTS_INSTANCING_ON 164 165 // ------------------------------------- 166 // Universal Pipeline keywords 167 168 // This is used during shadow map generation to differentiate between directional and punctual light shadows, as they use different formulas to apply Normal Bias 169 #pragma multi_compile_vertex _ _CASTING_PUNCTUAL_LIGHT_SHADOW 170 171 #pragma vertex ShadowPassVertex 172 #pragma fragment ShadowPassFragment 173 174 #include "Packages/com.unity.render-pipelines.universal/Shaders/LitInput.hlsl" 175 #include "Packages/com.unity.render-pipelines.universal/Shaders/ShadowCasterPass.hlsl" 176 ENDHLSL 177 } 178 } 179 180 FallBack "Hidden/Universal Render Pipeline/FallbackError" 181 }
效果如下: