429 lines
20 KiB
Plaintext
429 lines
20 KiB
Plaintext
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"
|
|
}
|