Shader "NLD_URP/Scene/NLD_Scene_Terrain" { Properties { _MinShadowStrength("Min Shadow Strength", Range(0,1)) = 0.4 [HideInInspector] [ToggleUI] _EnableHeightBlend("EnableHeightBlend", Float) = 0.0 _HeightTransition("Height Transition", Range(0, 1.0)) = 0.0 // Layer count is passed down to guide height-blend enable/disable, due // to the fact that heigh-based blend will be broken with multipass. [HideInInspector] [PerRendererData] _NumLayersCount ("Total Layer Count", Float) = 1.0 // set by terrain engine [HideInInspector] _Control("Control (RGBA)", 2D) = "red" {} [HideInInspector] _Splat3("Layer 3 (A)", 2D) = "grey" {} [HideInInspector] _Splat2("Layer 2 (B)", 2D) = "grey" {} [HideInInspector] _Splat1("Layer 1 (G)", 2D) = "grey" {} [HideInInspector] _Splat0("Layer 0 (R)", 2D) = "grey" {} // used in fallback on old cards & base map [HideInInspector] _MainTex("BaseMap (RGB)", 2D) = "grey" {} [HideInInspector] _BaseColor("Main Color", Color) = (1,1,1,1) [HideInInspector] _TerrainHolesTexture("Holes Map (RGB)", 2D) = "white" {} [ToggleUI] _EnableInstancedPerPixelNormal("Enable Instanced per-pixel normal", Float) = 1.0 } HLSLINCLUDE #pragma multi_compile_fragment __ _ALPHATEST_ON ENDHLSL SubShader { Tags { "Queue" = "Geometry-100" "RenderType" = "Opaque" "RenderPipeline" = "UniversalPipeline" "UniversalMaterialType" = "Lit" "IgnoreProjector" = "False" "TerrainCompatible" = "True"} Pass { Name "ForwardLit" Tags { "LightMode" = "UniversalForward" } HLSLPROGRAM #pragma target 3.0 #pragma vertex SplatmapVert #pragma fragment SplatmapFragment2 #define _METALLICSPECGLOSSMAP 1 #define _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A 1 // ------------------------------------- // Universal Pipeline keywords #pragma multi_compile _ _MAIN_LIGHT_SHADOWS _MAIN_LIGHT_SHADOWS_CASCADE _MAIN_LIGHT_SHADOWS_SCREEN #pragma multi_compile _ _ADDITIONAL_LIGHTS_VERTEX _ADDITIONAL_LIGHTS #pragma multi_compile _ LIGHTMAP_SHADOW_MIXING #pragma multi_compile _ SHADOWS_SHADOWMASK #pragma multi_compile _ _LIGHT_LAYERS #pragma multi_compile _ _FORWARD_PLUS #pragma multi_compile _ EVALUATE_SH_MIXED EVALUATE_SH_VERTEX #pragma multi_compile_fragment _ _ADDITIONAL_LIGHT_SHADOWS #pragma multi_compile_fragment _ _REFLECTION_PROBE_BLENDING #pragma multi_compile_fragment _ _SHADOWS_SOFT _SHADOWS_SOFT_LOW _SHADOWS_SOFT_MEDIUM _SHADOWS_SOFT_HIGH #pragma multi_compile_fragment _ _SCREEN_SPACE_OCCLUSION #pragma multi_compile_fragment _ _DBUFFER_MRT1 _DBUFFER_MRT2 _DBUFFER_MRT3 #pragma multi_compile_fragment _ _LIGHT_COOKIES #pragma multi_compile_fragment _ _SHADOWS_SOFT_LOW _SHADOWS_SOFT_MEDIUM _SHADOWS_SOFT_HIGH #include_with_pragmas "Packages/com.unity.render-pipelines.core/ShaderLibrary/FoveatedRenderingKeywords.hlsl" #include_with_pragmas "Packages/com.unity.render-pipelines.universal/ShaderLibrary/RenderingLayers.hlsl" // ------------------------------------- // Unity defined keywords #pragma multi_compile _ DIRLIGHTMAP_COMBINED #pragma multi_compile _ LIGHTMAP_ON #pragma multi_compile _ DYNAMICLIGHTMAP_ON #pragma multi_compile_fog #pragma multi_compile_fragment _ DEBUG_DISPLAY #pragma multi_compile_instancing #pragma instancing_options assumeuniformscaling nomatrices nolightprobe nolightmap #pragma shader_feature_local_fragment _TERRAIN_BLEND_HEIGHT #pragma shader_feature_local _NORMALMAP #pragma shader_feature_local_fragment _MASKMAP // Sample normal in pixel shader when doing instancing #pragma shader_feature_local _TERRAIN_INSTANCED_PERPIXEL_NORMAL #include "Packages/com.unity.render-pipelines.universal/Shaders/Terrain/TerrainLitInput.hlsl" #include "Packages/com.unity.render-pipelines.universal/Shaders/Terrain/TerrainLitPasses.hlsl" float _MinShadowStrength; half3 LightingPhysicallyBased2(BRDFData brdfData, BRDFData brdfDataClearCoat, half3 lightColor, half3 lightDirectionWS, half lightAttenuation, half3 normalWS, half3 viewDirectionWS, half clearCoatMask, bool specularHighlightsOff) { lightAttenuation = max(lightAttenuation, _MinShadowStrength); half3 radiance = lightColor * lightAttenuation; half3 brdf = brdfData.diffuse; return brdf * radiance; } half3 LightingPhysicallyBased2(BRDFData brdfData, BRDFData brdfDataClearCoat, Light light, half3 normalWS, half3 viewDirectionWS, half clearCoatMask, bool specularHighlightsOff) { return LightingPhysicallyBased2(brdfData, brdfDataClearCoat, light.color, light.direction, light.distanceAttenuation * light.shadowAttenuation, normalWS, viewDirectionWS, clearCoatMask, specularHighlightsOff); } //////////////////////////////////////////////////////////////////////////////// /// PBR lighting... //////////////////////////////////////////////////////////////////////////////// half4 UniversalFragmentPBR2(InputData inputData, SurfaceData surfaceData) { #if defined(_SPECULARHIGHLIGHTS_OFF) bool specularHighlightsOff = true; #else bool specularHighlightsOff = false; #endif BRDFData brdfData; // NOTE: can modify "surfaceData"... InitializeBRDFData(surfaceData, brdfData); #if defined(DEBUG_DISPLAY) half4 debugColor; if (CanDebugOverrideOutputColor(inputData, surfaceData, brdfData, debugColor)) { return debugColor; } #endif // Clear-coat calculation... BRDFData brdfDataClearCoat = CreateClearCoatBRDFData(surfaceData, brdfData); half4 shadowMask = CalculateShadowMask(inputData); AmbientOcclusionFactor aoFactor = CreateAmbientOcclusionFactor(inputData, surfaceData); uint meshRenderingLayers = GetMeshRenderingLayer(); Light mainLight = GetMainLight(inputData, shadowMask, aoFactor); // NOTE: We don't apply AO to the GI here because it's done in the lighting calculation below... MixRealtimeAndBakedGI(mainLight, inputData.normalWS, inputData.bakedGI); LightingData lightingData = CreateLightingData(inputData, surfaceData); lightingData.giColor = GlobalIllumination(brdfData, brdfDataClearCoat, surfaceData.clearCoatMask, inputData.bakedGI, aoFactor.indirectAmbientOcclusion, inputData.positionWS, inputData.normalWS, inputData.viewDirectionWS, inputData.normalizedScreenSpaceUV); #ifdef _LIGHT_LAYERS if (IsMatchingLightLayer(mainLight.layerMask, meshRenderingLayers)) #endif { lightingData.mainLightColor = LightingPhysicallyBased2(brdfData, brdfDataClearCoat, mainLight, inputData.normalWS, inputData.viewDirectionWS, surfaceData.clearCoatMask, specularHighlightsOff); } // return half4(brdfData.albedo * mainLight.shadowAttenuation, 1); #if defined(_ADDITIONAL_LIGHTS) uint pixelLightCount = GetAdditionalLightsCount(); #if USE_FORWARD_PLUS for (uint lightIndex = 0; lightIndex < min(URP_FP_DIRECTIONAL_LIGHTS_COUNT, MAX_VISIBLE_LIGHTS); lightIndex++) { FORWARD_PLUS_SUBTRACTIVE_LIGHT_CHECK Light light = GetAdditionalLight(lightIndex, inputData, shadowMask, aoFactor); #ifdef _LIGHT_LAYERS if (IsMatchingLightLayer(light.layerMask, meshRenderingLayers)) #endif { lightingData.additionalLightsColor += LightingPhysicallyBased(brdfData, brdfDataClearCoat, light, inputData.normalWS, inputData.viewDirectionWS, surfaceData.clearCoatMask, specularHighlightsOff); } } #endif LIGHT_LOOP_BEGIN(pixelLightCount) Light light = GetAdditionalLight(lightIndex, inputData, shadowMask, aoFactor); #ifdef _LIGHT_LAYERS if (IsMatchingLightLayer(light.layerMask, meshRenderingLayers)) #endif { lightingData.additionalLightsColor += LightingPhysicallyBased(brdfData, brdfDataClearCoat, light, inputData.normalWS, inputData.viewDirectionWS, surfaceData.clearCoatMask, specularHighlightsOff); } LIGHT_LOOP_END #endif #if defined(_ADDITIONAL_LIGHTS_VERTEX) lightingData.vertexLightingColor += inputData.vertexLighting * brdfData.diffuse; #endif #if REAL_IS_HALF // Clamp any half.inf+ to HALF_MAX return min(CalculateFinalColor(lightingData, surfaceData.alpha), HALF_MAX); #else return CalculateFinalColor(lightingData, surfaceData.alpha); #endif } // Deprecated: Use the version which takes "SurfaceData" instead of passing all of these arguments... half4 UniversalFragmentPBR2(InputData inputData, half3 albedo, half metallic, half3 specular, half smoothness, half occlusion, half3 emission, half alpha) { SurfaceData surfaceData; surfaceData.albedo = albedo; surfaceData.specular = specular; surfaceData.metallic = metallic; surfaceData.smoothness = smoothness; surfaceData.normalTS = half3(0, 0, 1); surfaceData.emission = emission; surfaceData.occlusion = occlusion; surfaceData.alpha = alpha; surfaceData.clearCoatMask = 0; surfaceData.clearCoatSmoothness = 1; return UniversalFragmentPBR2(inputData, surfaceData); } // Used in Standard Terrain shader #ifdef TERRAIN_GBUFFER FragmentOutput SplatmapFragment(Varyings IN) #else void SplatmapFragment2( Varyings IN , out half4 outColor : SV_Target0 #ifdef _WRITE_RENDERING_LAYERS , out float4 outRenderingLayers : SV_Target1 #endif ) #endif { UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(IN); #ifdef _ALPHATEST_ON ClipHoles(IN.uvMainAndLM.xy); #endif half3 normalTS = half3(0.0h, 0.0h, 1.0h); #ifdef TERRAIN_SPLAT_BASEPASS half3 albedo = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, IN.uvMainAndLM.xy).rgb; half smoothness = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, IN.uvMainAndLM.xy).a; half metallic = SAMPLE_TEXTURE2D(_MetallicTex, sampler_MetallicTex, IN.uvMainAndLM.xy).r; half alpha = 1; half occlusion = 1; #else half4 hasMask = half4(_LayerHasMask0, _LayerHasMask1, _LayerHasMask2, _LayerHasMask3); half4 masks[4]; ComputeMasks(masks, hasMask, IN); float2 splatUV = (IN.uvMainAndLM.xy * (_Control_TexelSize.zw - 1.0f) + 0.5f) * _Control_TexelSize.xy; half4 splatControl = SAMPLE_TEXTURE2D(_Control, sampler_Control, splatUV); half alpha = dot(splatControl, 1.0h); #ifdef _TERRAIN_BLEND_HEIGHT // disable Height Based blend when there are more than 4 layers (multi-pass breaks the normalization) if (_NumLayersCount <= 4) HeightBasedSplatModify(splatControl, masks); #endif half weight; half4 mixedDiffuse; half4 defaultSmoothness; SplatmapMix(IN.uvMainAndLM, IN.uvSplat01, IN.uvSplat23, splatControl, weight, mixedDiffuse, defaultSmoothness, normalTS); half3 albedo = mixedDiffuse.rgb; half4 defaultMetallic = half4(_Metallic0, _Metallic1, _Metallic2, _Metallic3); half4 defaultOcclusion = half4(_MaskMapRemapScale0.g, _MaskMapRemapScale1.g, _MaskMapRemapScale2.g, _MaskMapRemapScale3.g) + half4(_MaskMapRemapOffset0.g, _MaskMapRemapOffset1.g, _MaskMapRemapOffset2.g, _MaskMapRemapOffset3.g); half4 maskSmoothness = half4(masks[0].a, masks[1].a, masks[2].a, masks[3].a); defaultSmoothness = lerp(defaultSmoothness, maskSmoothness, hasMask); half smoothness = dot(splatControl, defaultSmoothness); half4 maskMetallic = half4(masks[0].r, masks[1].r, masks[2].r, masks[3].r); defaultMetallic = lerp(defaultMetallic, maskMetallic, hasMask); half metallic = dot(splatControl, defaultMetallic); half4 maskOcclusion = half4(masks[0].g, masks[1].g, masks[2].g, masks[3].g); defaultOcclusion = lerp(defaultOcclusion, maskOcclusion, hasMask); half occlusion = dot(splatControl, defaultOcclusion); #endif InputData inputData; InitializeInputData(IN, normalTS, inputData); SETUP_DEBUG_TEXTURE_DATA(inputData, IN.uvMainAndLM.xy, _BaseMap); #if defined(_DBUFFER) half3 specular = half3(0.0h, 0.0h, 0.0h); ApplyDecal(IN.clipPos, albedo, specular, inputData.normalWS, metallic, occlusion, smoothness); #endif #ifdef TERRAIN_GBUFFER BRDFData brdfData; InitializeBRDFData(albedo, metallic, /* specular */ half3(0.0h, 0.0h, 0.0h), smoothness, alpha, brdfData); // Baked lighting. half4 color; Light mainLight = GetMainLight(inputData.shadowCoord, inputData.positionWS, inputData.shadowMask); MixRealtimeAndBakedGI(mainLight, inputData.normalWS, inputData.bakedGI, inputData.shadowMask); color.rgb = GlobalIllumination(brdfData, inputData.bakedGI, occlusion, inputData.positionWS, inputData.normalWS, inputData.viewDirectionWS); color.a = alpha; SplatmapFinalColor(color, inputData.fogCoord); // Dynamic lighting: emulate SplatmapFinalColor() by scaling gbuffer material properties. This will not give the same results // as forward renderer because we apply blending pre-lighting instead of post-lighting. // Blending of smoothness and normals is also not correct but close enough? brdfData.albedo.rgb *= alpha; brdfData.diffuse.rgb *= alpha; brdfData.specular.rgb *= alpha; brdfData.reflectivity *= alpha; inputData.normalWS = inputData.normalWS * alpha; smoothness *= alpha; return BRDFDataToGbuffer(brdfData, inputData, smoothness, color.rgb, occlusion); #else half4 color = UniversalFragmentPBR2(inputData, albedo, metallic, /* specular */ half3(0.0h, 0.0h, 0.0h), smoothness, occlusion, /* emission */ half3(0, 0, 0), alpha); SplatmapFinalColor(color, inputData.fogCoord); outColor = half4(color.rgb, 1.0h); #ifdef _WRITE_RENDERING_LAYERS uint renderingLayers = GetMeshRenderingLayer(); outRenderingLayers = float4(EncodeMeshRenderingLayer(renderingLayers), 0, 0, 0); #endif #endif } ENDHLSL } Pass { Name "ShadowCaster" Tags{"LightMode" = "ShadowCaster"} ZWrite On ColorMask 0 HLSLPROGRAM #pragma target 2.0 #pragma vertex ShadowPassVertex #pragma fragment ShadowPassFragment #pragma multi_compile_instancing #pragma instancing_options assumeuniformscaling nomatrices nolightprobe nolightmap // ------------------------------------- // Universal Pipeline keywords // This is used during shadow map generation to differentiate between directional and punctual light shadows, as they use different formulas to apply Normal Bias #pragma multi_compile_vertex _ _CASTING_PUNCTUAL_LIGHT_SHADOW #include "Packages/com.unity.render-pipelines.universal/Shaders/Terrain/TerrainLitInput.hlsl" #include "Packages/com.unity.render-pipelines.universal/Shaders/Terrain/TerrainLitPasses.hlsl" ENDHLSL } Pass { Name "SceneSelectionPass" Tags { "LightMode" = "SceneSelectionPass" } HLSLPROGRAM #pragma target 2.0 #pragma vertex DepthOnlyVertex #pragma fragment DepthOnlyFragment #pragma multi_compile_instancing #pragma instancing_options assumeuniformscaling nomatrices nolightprobe nolightmap #define SCENESELECTIONPASS #include "Packages/com.unity.render-pipelines.universal/Shaders/Terrain/TerrainLitInput.hlsl" #include "Packages/com.unity.render-pipelines.universal/Shaders/Terrain/TerrainLitPasses.hlsl" ENDHLSL } // This pass it not used during regular rendering, only for lightmap baking. Pass { Name "Meta" Tags{"LightMode" = "Meta"} Cull Off HLSLPROGRAM #pragma vertex TerrainVertexMeta #pragma fragment TerrainFragmentMeta #pragma multi_compile_instancing #pragma instancing_options assumeuniformscaling nomatrices nolightprobe nolightmap #pragma shader_feature EDITOR_VISUALIZATION #define _METALLICSPECGLOSSMAP 1 #define _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A 1 #include "Packages/com.unity.render-pipelines.universal/Shaders/Terrain/TerrainLitInput.hlsl" #include "Packages/com.unity.render-pipelines.universal/Shaders/Terrain/TerrainLitMetaPass.hlsl" ENDHLSL } UsePass "Hidden/Nature/Terrain/Utilities/PICKING" } // Dependency "AddPassShader" = "Hidden/Universal Render Pipeline/Terrain/Lit (Add Pass)" // Dependency "BaseMapShader" = "Hidden/Universal Render Pipeline/Terrain/Lit (Base Pass)" Dependency "BaseMapGenShader" = "Hidden/Universal Render Pipeline/Terrain/Lit (Basemap Gen)" CustomEditor "UnityEditor.Rendering.Universal.TerrainLitShaderGUI" Fallback "Hidden/Universal Render Pipeline/FallbackError" }