// Forward-only URP PBR shader with hardware tessellation + height-map displacement and an occlusion // map, built for the PictureFrameBuilder picture surface (works on any mesh with sane UVs). // // Deferred+ compatible via the ComplexLit pattern (same as PlayerCamoLit): "UniversalMaterialType" = // "ComplexLit" stencils these pixels out of the deferred lighting and URP shades them in the // UniversalForwardOnly pass instead - the only way a custom vertex pipeline (tessellation) can run // on the deferred path. ALL depth-relevant passes (ShadowCaster / DepthOnly / DepthNormalsOnly) run // the same hull/domain displacement so shadows, SSAO and depth match the displaced surface. // // Displacement = (height - 0.5) * _Displacement * _TessellationStrength along the vertex normal; // _Displacement is the authored amplitude in meters, _TessellationStrength is the runtime knob the // PictureFrameBuilder drives per frame (like _BumpScale / _OcclusionStrength). Shader "Chameleon/PictureTessellationLit" { Properties { _BaseMap("Albedo", 2D) = "white" {} _BaseColor("Color", Color) = (1, 1, 1, 1) _Smoothness("Smoothness", Range(0.0, 1.0)) = 0.5 _Metallic("Metallic", Range(0.0, 1.0)) = 0.0 [Normal] _BumpMap("Normal Map", 2D) = "bump" {} _BumpScale("Normal Strength", Range(-3.0, 3.0)) = 1.0 _HeightMap("Height Map", 2D) = "gray" {} _Displacement("Displacement (m)", Range(0.0, 0.2)) = 0.02 _TessellationStrength("Tessellation Strength", Range(-10.0, 10.0)) = 1.0 _TessellationFactor("Tessellation Factor", Range(1.0, 32.0)) = 8.0 _OcclusionMap("Occlusion Map", 2D) = "white" {} _OcclusionStrength("Occlusion Strength", Range(0.0, 3.0)) = 1.0 _OcclusionContrast("Occlusion Contrast", Range(-1.0, 3.0)) = 0.0 _Brightness("Brightness", Range(0.0, 3.0)) = 1.0 } SubShader { Tags { "RenderType" = "Opaque" "RenderPipeline" = "UniversalPipeline" "UniversalMaterialType" = "ComplexLit" "Queue" = "Geometry" } LOD 300 HLSLINCLUDE #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" TEXTURE2D(_HeightMap); SAMPLER(sampler_HeightMap); CBUFFER_START(UnityPerMaterial) float4 _BaseMap_ST; half4 _BaseColor; half _Smoothness; half _Metallic; half _BumpScale; half _Displacement; half _TessellationStrength; half _TessellationFactor; half _OcclusionStrength; half _OcclusionContrast; half _Brightness; CBUFFER_END struct Attributes { float4 positionOS : POSITION; float3 normalOS : NORMAL; float4 tangentOS : TANGENT; float2 uv : TEXCOORD0; float2 staticLightmapUV : TEXCOORD1; float2 dynamicLightmapUV : TEXCOORD2; }; // Hull/domain control point: everything stays in object space until the domain stage. struct ControlPoint { float4 positionOS : INTERNALTESSPOS; float3 normalOS : NORMAL; float4 tangentOS : TANGENT; float2 uv : TEXCOORD0; float2 staticLightmapUV : TEXCOORD1; float2 dynamicLightmapUV : TEXCOORD2; }; struct TessFactors { float edge[3] : SV_TessFactor; float inside : SV_InsideTessFactor; }; ControlPoint TessVertex(Attributes input) { ControlPoint p; p.positionOS = input.positionOS; p.normalOS = input.normalOS; p.tangentOS = input.tangentOS; p.uv = input.uv; p.staticLightmapUV = input.staticLightmapUV; p.dynamicLightmapUV = input.dynamicLightmapUV; return p; } TessFactors PatchConstants(InputPatch patch) { TessFactors f; // No displacement -> no reason to subdivide (keeps the wireframe a plain grid). half factor = (_TessellationStrength == 0.0h || _Displacement == 0.0h) ? 1.0h : _TessellationFactor; f.edge[0] = factor; f.edge[1] = factor; f.edge[2] = factor; f.inside = factor; return f; } [domain("tri")] [outputcontrolpoints(3)] [outputtopology("triangle_cw")] [partitioning("fractional_odd")] [patchconstantfunc("PatchConstants")] ControlPoint TessHull(InputPatch patch, uint id : SV_OutputControlPointID) { return patch[id]; } #define TESS_INTERPOLATE(field) (patch[0].field * bary.x + patch[1].field * bary.y + patch[2].field * bary.z) // Barycentric interpolation + height displacement along the vertex normal; each pass turns // the resulting object-space vertex into its own varyings in its domain function. Attributes TessInterpolate(OutputPatch patch, float3 bary) { Attributes v; v.positionOS = TESS_INTERPOLATE(positionOS); v.normalOS = normalize(TESS_INTERPOLATE(normalOS)); v.tangentOS = TESS_INTERPOLATE(tangentOS); v.uv = TESS_INTERPOLATE(uv); v.staticLightmapUV = TESS_INTERPOLATE(staticLightmapUV); v.dynamicLightmapUV = TESS_INTERPOLATE(dynamicLightmapUV); float height = SAMPLE_TEXTURE2D_LOD(_HeightMap, sampler_HeightMap, TRANSFORM_TEX(v.uv, _BaseMap), 0).r; v.positionOS.xyz += v.normalOS * ((height - 0.5) * _Displacement * _TessellationStrength); return v; } ENDHLSL Pass { Name "ForwardLit" Tags { "LightMode" = "UniversalForwardOnly" } ZWrite On Cull Back HLSLPROGRAM #pragma target 4.6 #pragma vertex TessVertex #pragma hull TessHull #pragma domain ForwardDomain #pragma fragment ForwardFragment // Keyword set mirrored from URP Lit.shader's ForwardLit pass (Universal Pipeline + // Unity defined keywords) so every lighting feature the standard Lit supports works // here too: lightmaps, shadowmask/mixed lighting, APV probe volumes, decals (DBuffer), // vertex additional lights, rendering-layer output, reflection probe rotation. #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 _ EVALUATE_SH_MIXED EVALUATE_SH_VERTEX #pragma multi_compile_fragment _ _ADDITIONAL_LIGHT_SHADOWS #pragma multi_compile_fragment _ _REFLECTION_PROBE_BLENDING #pragma multi_compile_fragment _ _REFLECTION_PROBE_BOX_PROJECTION #pragma multi_compile_fragment _ _REFLECTION_PROBE_ATLAS #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 _ _SCREEN_SPACE_IRRADIANCE #pragma multi_compile_fragment _ _DBUFFER_MRT1 _DBUFFER_MRT2 _DBUFFER_MRT3 #pragma multi_compile_fragment _ _LIGHT_COOKIES #pragma multi_compile _ _LIGHT_LAYERS #pragma multi_compile _ _CLUSTER_LIGHT_LOOP #include_with_pragmas "Packages/com.unity.render-pipelines.universal/ShaderLibrary/RenderingLayers.hlsl" #pragma multi_compile _ LIGHTMAP_SHADOW_MIXING #pragma multi_compile _ SHADOWS_SHADOWMASK #pragma multi_compile _ DIRLIGHTMAP_COMBINED #pragma multi_compile _ LIGHTMAP_ON #pragma multi_compile_fragment _ LIGHTMAP_BICUBIC_SAMPLING #pragma multi_compile_fragment _ REFLECTION_PROBE_ROTATION #pragma multi_compile _ DYNAMICLIGHTMAP_ON #pragma multi_compile _ USE_LEGACY_LIGHTMAPS #include_with_pragmas "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Fog.hlsl" #include_with_pragmas "Packages/com.unity.render-pipelines.universal/ShaderLibrary/ProbeVolumeVariants.hlsl" #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl" #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DBuffer.hlsl" TEXTURE2D(_BaseMap); SAMPLER(sampler_BaseMap); TEXTURE2D(_BumpMap); SAMPLER(sampler_BumpMap); TEXTURE2D(_OcclusionMap); SAMPLER(sampler_OcclusionMap); struct Varyings { float4 positionCS : SV_POSITION; float2 uv : TEXCOORD0; float3 positionWS : TEXCOORD1; float3 normalWS : TEXCOORD2; float4 tangentWS : TEXCOORD3; // w = bitangent sign #ifdef _ADDITIONAL_LIGHTS_VERTEX half4 fogFactorAndVertexLight : TEXCOORD4; // x: fog, yzw: vertex light #else half fogFactor : TEXCOORD4; #endif DECLARE_LIGHTMAP_OR_SH(staticLightmapUV, vertexSH, 5); #ifdef DYNAMICLIGHTMAP_ON float2 dynamicLightmapUV : TEXCOORD6; #endif #ifdef USE_APV_PROBE_OCCLUSION float4 probeOcclusion : TEXCOORD7; #endif }; [domain("tri")] Varyings ForwardDomain(TessFactors factors, OutputPatch patch, float3 bary : SV_DomainLocation) { Attributes v = TessInterpolate(patch, bary); VertexPositionInputs pos = GetVertexPositionInputs(v.positionOS.xyz); VertexNormalInputs nrm = GetVertexNormalInputs(v.normalOS, v.tangentOS); Varyings o = (Varyings)0; o.positionCS = pos.positionCS; o.positionWS = pos.positionWS; o.normalWS = nrm.normalWS; o.tangentWS = float4(nrm.tangentWS, v.tangentOS.w * GetOddNegativeScale()); o.uv = TRANSFORM_TEX(v.uv, _BaseMap); half fogFactor = 0; #if !defined(_FOG_FRAGMENT) fogFactor = ComputeFogFactor(pos.positionCS.z); #endif #ifdef _ADDITIONAL_LIGHTS_VERTEX o.fogFactorAndVertexLight = half4(fogFactor, VertexLighting(pos.positionWS, nrm.normalWS)); #else o.fogFactor = fogFactor; #endif OUTPUT_LIGHTMAP_UV(v.staticLightmapUV, unity_LightmapST, o.staticLightmapUV); #ifdef DYNAMICLIGHTMAP_ON o.dynamicLightmapUV = v.dynamicLightmapUV * unity_DynamicLightmapST.xy + unity_DynamicLightmapST.zw; #endif OUTPUT_SH4(pos.positionWS, o.normalWS, GetWorldSpaceNormalizeViewDir(pos.positionWS), o.vertexSH, o.probeOcclusion); return o; } void ForwardFragment( Varyings input , out half4 outColor : SV_Target0 #ifdef _WRITE_RENDERING_LAYERS , out uint outRenderingLayers : SV_Target1 #endif ) { half4 albedo = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, input.uv) * _BaseColor; // Height-weighted brightness: raised areas get the full multiplier, deep areas stay // untouched (height 0.5 = mid-gray default when no map is bound -> half effect). half heightBr = SAMPLE_TEXTURE2D(_HeightMap, sampler_HeightMap, input.uv).r; albedo.rgb *= lerp(1.0h, _Brightness, heightBr); half3 normalTS = UnpackNormalScale(SAMPLE_TEXTURE2D(_BumpMap, sampler_BumpMap, input.uv), _BumpScale); half occ = SAMPLE_TEXTURE2D(_OcclusionMap, sampler_OcclusionMap, input.uv).g; // Contrast around mid-gray: 0 = as sampled, -1 = flat (no occlusion detail), 3 = 4x. occ = saturate((occ - 0.5h) * (1.0h + _OcclusionContrast) + 0.5h); float sgn = input.tangentWS.w; float3 bitangentWS = sgn * cross(input.normalWS, input.tangentWS.xyz); half3x3 tbn = half3x3(input.tangentWS.xyz, bitangentWS, input.normalWS); InputData inputData = (InputData)0; inputData.positionWS = input.positionWS; inputData.positionCS = input.positionCS; inputData.normalWS = NormalizeNormalPerPixel(TransformTangentToWorld(normalTS, tbn)); inputData.viewDirectionWS = GetWorldSpaceNormalizeViewDir(input.positionWS); inputData.normalizedScreenSpaceUV = GetNormalizedScreenSpaceUV(input.positionCS); #if defined(_MAIN_LIGHT_SHADOWS_SCREEN) inputData.shadowCoord = float4(inputData.normalizedScreenSpaceUV, 0, 1); #else inputData.shadowCoord = TransformWorldToShadowCoord(input.positionWS); #endif #ifdef _ADDITIONAL_LIGHTS_VERTEX inputData.fogCoord = InitializeInputDataFog(float4(input.positionWS, 1.0), input.fogFactorAndVertexLight.x); inputData.vertexLighting = input.fogFactorAndVertexLight.yzw; #else inputData.fogCoord = InitializeInputDataFog(float4(input.positionWS, 1.0), input.fogFactor); #endif // Baked GI exactly like LitForwardPass.InitializeBakedGIData: lightmaps (static/ // dynamic), APV probe volumes, screen-space irradiance, shadowmask - else SH. #if defined(_SCREEN_SPACE_IRRADIANCE) inputData.bakedGI = SAMPLE_GI(_ScreenSpaceIrradiance, input.positionCS.xy); #elif defined(DYNAMICLIGHTMAP_ON) inputData.bakedGI = SAMPLE_GI(input.staticLightmapUV, input.dynamicLightmapUV, input.vertexSH, inputData.normalWS); inputData.shadowMask = SAMPLE_SHADOWMASK(input.staticLightmapUV); #elif !defined(LIGHTMAP_ON) && (defined(PROBE_VOLUMES_L1) || defined(PROBE_VOLUMES_L2)) inputData.bakedGI = SAMPLE_GI(input.vertexSH, GetAbsolutePositionWS(inputData.positionWS), inputData.normalWS, inputData.viewDirectionWS, input.positionCS.xy, input.probeOcclusion, inputData.shadowMask); #else inputData.bakedGI = SAMPLE_GI(input.staticLightmapUV, input.vertexSH, inputData.normalWS); inputData.shadowMask = SAMPLE_SHADOWMASK(input.staticLightmapUV); #endif SurfaceData surfaceData = (SurfaceData)0; surfaceData.albedo = albedo.rgb; surfaceData.alpha = 1; surfaceData.metallic = _Metallic; surfaceData.smoothness = _Smoothness; surfaceData.normalTS = normalTS; // Strength > 1 keeps darkening past the authored map (saturate stops negatives). surfaceData.occlusion = saturate(LerpWhiteTo(occ, _OcclusionStrength)); #if defined(_DBUFFER) ApplyDecalToSurfaceData(input.positionCS, surfaceData, inputData); #endif half4 color = UniversalFragmentPBR(inputData, surfaceData); color.rgb = MixFog(color.rgb, inputData.fogCoord); outColor = color; #ifdef _WRITE_RENDERING_LAYERS outRenderingLayers = EncodeMeshRenderingLayer(); #endif } ENDHLSL } Pass { Name "ShadowCaster" Tags { "LightMode" = "ShadowCaster" } ZWrite On ZTest LEqual ColorMask 0 Cull Back HLSLPROGRAM #pragma target 4.6 #pragma vertex TessVertex #pragma hull TessHull #pragma domain ShadowDomain #pragma fragment ShadowFragment // NOT multi_compile_vertex: the keyword is consumed in the DOMAIN stage here. #pragma multi_compile _ _CASTING_PUNCTUAL_LIGHT_SHADOW #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl" float3 _LightDirection; float3 _LightPosition; struct ShadowVaryings { float4 positionCS : SV_POSITION; }; [domain("tri")] ShadowVaryings ShadowDomain(TessFactors factors, OutputPatch patch, float3 bary : SV_DomainLocation) { Attributes v = TessInterpolate(patch, bary); float3 positionWS = TransformObjectToWorld(v.positionOS.xyz); float3 normalWS = TransformObjectToWorldNormal(v.normalOS); #if defined(_CASTING_PUNCTUAL_LIGHT_SHADOW) float3 lightDirectionWS = normalize(_LightPosition - positionWS); #else float3 lightDirectionWS = _LightDirection; #endif float4 positionCS = TransformWorldToHClip(ApplyShadowBias(positionWS, normalWS, lightDirectionWS)); #if UNITY_REVERSED_Z positionCS.z = min(positionCS.z, UNITY_NEAR_CLIP_VALUE); #else positionCS.z = max(positionCS.z, UNITY_NEAR_CLIP_VALUE); #endif ShadowVaryings o; o.positionCS = positionCS; return o; } half4 ShadowFragment() : SV_Target { return 0; } ENDHLSL } Pass { Name "DepthOnly" Tags { "LightMode" = "DepthOnly" } ZWrite On ColorMask R Cull Back HLSLPROGRAM #pragma target 4.6 #pragma vertex TessVertex #pragma hull TessHull #pragma domain DepthDomain #pragma fragment DepthFragment struct DepthVaryings { float4 positionCS : SV_POSITION; }; [domain("tri")] DepthVaryings DepthDomain(TessFactors factors, OutputPatch patch, float3 bary : SV_DomainLocation) { Attributes v = TessInterpolate(patch, bary); DepthVaryings o; o.positionCS = TransformObjectToHClip(v.positionOS.xyz); return o; } half DepthFragment(DepthVaryings input) : SV_Target { return input.positionCS.z; } ENDHLSL } Pass { // Deferred+'s normals prepass draws ONLY this tag (the forward path draws both), see the // PlayerCamoLit fix - geometric (displaced) normal is enough for SSAO/HTrace. Name "DepthNormalsOnly" Tags { "LightMode" = "DepthNormalsOnly" } ZWrite On Cull Back HLSLPROGRAM #pragma target 4.6 #pragma vertex TessVertex #pragma hull TessHull #pragma domain DepthNormalsDomain #pragma fragment DepthNormalsFragment // Same as URP Lit's DepthNormals pass: decals need the rendering-layers target. #include_with_pragmas "Packages/com.unity.render-pipelines.universal/ShaderLibrary/RenderingLayers.hlsl" struct DepthNormalsVaryings { float4 positionCS : SV_POSITION; float3 normalWS : TEXCOORD0; }; [domain("tri")] DepthNormalsVaryings DepthNormalsDomain(TessFactors factors, OutputPatch patch, float3 bary : SV_DomainLocation) { Attributes v = TessInterpolate(patch, bary); DepthNormalsVaryings o; o.positionCS = TransformObjectToHClip(v.positionOS.xyz); o.normalWS = TransformObjectToWorldNormal(v.normalOS); return o; } void DepthNormalsFragment( DepthNormalsVaryings input , out half4 outNormalWS : SV_Target0 #ifdef _WRITE_RENDERING_LAYERS , out uint outRenderingLayers : SV_Target1 #endif ) { outNormalWS = half4(NormalizeNormalPerPixel(input.normalWS), 0); #ifdef _WRITE_RENDERING_LAYERS outRenderingLayers = EncodeMeshRenderingLayer(); #endif } ENDHLSL } Pass { // The project renders forward(+); the ONLY consumer of this pass is HTrace WSGI, which // renders its thin GBuffer through the "UniversalGBuffer" tag and composites its traced // irradiance from GBuffer0.rgb (albedo) / GBuffer1.a (occlusion) AFTER post-processing. // Without it these pixels keep stale GBuffer data and get wrong injected GI (the cyan // sky tint) - same failure class as the HeroCutout/PlayerCamo GBuffer fixes. Albedo is // graded exactly like the forward pass (brightness/occlusion/contrast) so the injected // indirect light matches the visible picture. Name "GBuffer" Tags { "LightMode" = "UniversalGBuffer" } ZWrite On ZTest LEqual Cull Back HLSLPROGRAM #pragma target 4.6 #pragma exclude_renderers gles3 glcore #pragma vertex TessVertex #pragma hull TessHull #pragma domain GBufferDomain #pragma fragment GBufferFragment #pragma multi_compile _ _MAIN_LIGHT_SHADOWS _MAIN_LIGHT_SHADOWS_CASCADE _MAIN_LIGHT_SHADOWS_SCREEN #pragma multi_compile_fragment _ _REFLECTION_PROBE_BLENDING #pragma multi_compile_fragment _ _REFLECTION_PROBE_BOX_PROJECTION #pragma multi_compile_fragment _ _SHADOWS_SOFT _SHADOWS_SOFT_LOW _SHADOWS_SOFT_MEDIUM _SHADOWS_SOFT_HIGH #pragma multi_compile_fragment _ _DBUFFER_MRT1 _DBUFFER_MRT2 _DBUFFER_MRT3 #pragma multi_compile_fragment _ _RENDER_PASS_ENABLED #pragma multi_compile _ _CLUSTER_LIGHT_LOOP #pragma multi_compile _ EVALUATE_SH_MIXED EVALUATE_SH_VERTEX #include_with_pragmas "Packages/com.unity.render-pipelines.universal/ShaderLibrary/RenderingLayers.hlsl" #pragma multi_compile _ LIGHTMAP_SHADOW_MIXING #pragma multi_compile _ SHADOWS_SHADOWMASK #pragma multi_compile _ DIRLIGHTMAP_COMBINED #pragma multi_compile _ LIGHTMAP_ON #pragma multi_compile_fragment _ LIGHTMAP_BICUBIC_SAMPLING #pragma multi_compile_fragment _ REFLECTION_PROBE_ROTATION #pragma multi_compile _ DYNAMICLIGHTMAP_ON #pragma multi_compile _ USE_LEGACY_LIGHTMAPS #pragma multi_compile_fragment _ _GBUFFER_NORMALS_OCT #pragma multi_compile_fragment _ _SCREEN_SPACE_IRRADIANCE #include_with_pragmas "Packages/com.unity.render-pipelines.universal/ShaderLibrary/ProbeVolumeVariants.hlsl" #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl" #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/GBufferOutput.hlsl" #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DBuffer.hlsl" TEXTURE2D(_BaseMap); SAMPLER(sampler_BaseMap); TEXTURE2D(_BumpMap); SAMPLER(sampler_BumpMap); TEXTURE2D(_OcclusionMap); SAMPLER(sampler_OcclusionMap); struct GBufferVaryings { float4 positionCS : SV_POSITION; float2 uv : TEXCOORD0; float3 positionWS : TEXCOORD1; float3 normalWS : TEXCOORD2; float4 tangentWS : TEXCOORD3; // w = bitangent sign DECLARE_LIGHTMAP_OR_SH(staticLightmapUV, vertexSH, 4); #ifdef DYNAMICLIGHTMAP_ON float2 dynamicLightmapUV : TEXCOORD5; #endif #ifdef USE_APV_PROBE_OCCLUSION float4 probeOcclusion : TEXCOORD6; #endif }; [domain("tri")] GBufferVaryings GBufferDomain(TessFactors factors, OutputPatch patch, float3 bary : SV_DomainLocation) { Attributes v = TessInterpolate(patch, bary); VertexPositionInputs pos = GetVertexPositionInputs(v.positionOS.xyz); VertexNormalInputs nrm = GetVertexNormalInputs(v.normalOS, v.tangentOS); GBufferVaryings o = (GBufferVaryings)0; o.positionCS = pos.positionCS; o.positionWS = pos.positionWS; o.normalWS = nrm.normalWS; o.tangentWS = float4(nrm.tangentWS, v.tangentOS.w * GetOddNegativeScale()); o.uv = TRANSFORM_TEX(v.uv, _BaseMap); OUTPUT_LIGHTMAP_UV(v.staticLightmapUV, unity_LightmapST, o.staticLightmapUV); #ifdef DYNAMICLIGHTMAP_ON o.dynamicLightmapUV = v.dynamicLightmapUV * unity_DynamicLightmapST.xy + unity_DynamicLightmapST.zw; #endif OUTPUT_SH4(pos.positionWS, o.normalWS, GetWorldSpaceNormalizeViewDir(pos.positionWS), o.vertexSH, o.probeOcclusion); return o; } GBufferFragOutput GBufferFragment(GBufferVaryings input) { // Surface build mirrors ForwardFragment 1:1 (graded albedo, contrast'd occlusion). half4 albedo = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, input.uv) * _BaseColor; half heightBr = SAMPLE_TEXTURE2D(_HeightMap, sampler_HeightMap, input.uv).r; albedo.rgb *= lerp(1.0h, _Brightness, heightBr); half3 normalTS = UnpackNormalScale(SAMPLE_TEXTURE2D(_BumpMap, sampler_BumpMap, input.uv), _BumpScale); half occ = SAMPLE_TEXTURE2D(_OcclusionMap, sampler_OcclusionMap, input.uv).g; occ = saturate((occ - 0.5h) * (1.0h + _OcclusionContrast) + 0.5h); half occlusion = saturate(LerpWhiteTo(occ, _OcclusionStrength)); float sgn = input.tangentWS.w; float3 bitangentWS = sgn * cross(input.normalWS, input.tangentWS.xyz); half3x3 tbn = half3x3(input.tangentWS.xyz, bitangentWS, input.normalWS); InputData inputData = (InputData)0; inputData.positionWS = input.positionWS; inputData.positionCS = input.positionCS; inputData.normalWS = NormalizeNormalPerPixel(TransformTangentToWorld(normalTS, tbn)); inputData.viewDirectionWS = GetWorldSpaceNormalizeViewDir(input.positionWS); inputData.normalizedScreenSpaceUV = GetNormalizedScreenSpaceUV(input.positionCS); #if defined(_MAIN_LIGHT_SHADOWS_SCREEN) inputData.shadowCoord = float4(inputData.normalizedScreenSpaceUV, 0, 1); #else inputData.shadowCoord = TransformWorldToShadowCoord(input.positionWS); #endif #if defined(_SCREEN_SPACE_IRRADIANCE) inputData.bakedGI = SAMPLE_GI(_ScreenSpaceIrradiance, input.positionCS.xy); #elif defined(DYNAMICLIGHTMAP_ON) inputData.bakedGI = SAMPLE_GI(input.staticLightmapUV, input.dynamicLightmapUV, input.vertexSH, inputData.normalWS); inputData.shadowMask = SAMPLE_SHADOWMASK(input.staticLightmapUV); #elif !defined(LIGHTMAP_ON) && (defined(PROBE_VOLUMES_L1) || defined(PROBE_VOLUMES_L2)) inputData.bakedGI = SAMPLE_GI(input.vertexSH, GetAbsolutePositionWS(inputData.positionWS), inputData.normalWS, inputData.viewDirectionWS, input.positionCS.xy, input.probeOcclusion, inputData.shadowMask); #else inputData.bakedGI = SAMPLE_GI(input.staticLightmapUV, input.vertexSH, inputData.normalWS); inputData.shadowMask = SAMPLE_SHADOWMASK(input.staticLightmapUV); #endif SurfaceData surfaceData = (SurfaceData)0; surfaceData.albedo = saturate(albedo.rgb); // GBuffer0 is UNORM; HTrace multiplies GI by it surfaceData.alpha = 1; surfaceData.metallic = _Metallic; surfaceData.smoothness = _Smoothness; surfaceData.normalTS = normalTS; surfaceData.occlusion = occlusion; #if defined(_DBUFFER) ApplyDecalToSurfaceData(input.positionCS, surfaceData, inputData); #endif BRDFData brdfData; InitializeBRDFData(surfaceData.albedo, surfaceData.metallic, surfaceData.specular, surfaceData.smoothness, surfaceData.alpha, brdfData); Light mainLight = GetMainLight(inputData.shadowCoord, inputData.positionWS, inputData.shadowMask); MixRealtimeAndBakedGI(mainLight, inputData.normalWS, inputData.bakedGI, inputData.shadowMask); half3 color = GlobalIllumination(brdfData, (BRDFData)0, 0, inputData.bakedGI, surfaceData.occlusion, inputData.positionWS, inputData.normalWS, inputData.viewDirectionWS, inputData.normalizedScreenSpaceUV); return PackGBuffersBRDFData(brdfData, inputData, surfaceData.smoothness, color, surfaceData.occlusion); } ENDHLSL } } FallBack "Universal Render Pipeline/Lit" }