@@ -169,6 +169,25 @@ float2 CalculateTerrainParallaxOffset(float4 layerBlends, float2 texCoord, float
169169 return heightBiasOffset + (maxParallaxOffset * (1.0f - saturate (refinedHeight)));
170170}
171171
172+ // Terrain-specific self-shadow using blended heightmaps
173+ float TraceTerrainSelfShadow (float4 layerBlends, float2 texCoords, float3 tanLightDir, float edgeWeight, float hScale)
174+ {
175+ float2 inXY = (tanLightDir.xy * hScale * edgeWeight) / max (tanLightDir.z, 0.01f );
176+
177+ float sh0 = 1.0f - BlendTerrainHeight (layerBlends, texCoords);
178+
179+ float shA = (1.0f - BlendTerrainHeight (layerBlends, texCoords + inXY * 0.88 ) - sh0 - 0.88 ) * 1 ;
180+ float sh9 = (1.0f - BlendTerrainHeight (layerBlends, texCoords + inXY * 0.77 ) - sh0 - 0.77 ) * 2 ;
181+ float sh8 = (1.0f - BlendTerrainHeight (layerBlends, texCoords + inXY * 0.66 ) - sh0 - 0.66 ) * 4 ;
182+ float sh7 = (1.0f - BlendTerrainHeight (layerBlends, texCoords + inXY * 0.55 ) - sh0 - 0.55 ) * 6 ;
183+ float sh6 = (1.0f - BlendTerrainHeight (layerBlends, texCoords + inXY * 0.44 ) - sh0 - 0.44 ) * 8 ;
184+ float sh5 = (1.0f - BlendTerrainHeight (layerBlends, texCoords + inXY * 0.33 ) - sh0 - 0.33 ) * 10 ;
185+ float sh4 = (1.0f - BlendTerrainHeight (layerBlends, texCoords + inXY * 0.22 ) - sh0 - 0.22 ) * 12 ;
186+
187+ float finalHeight = max (max (max (max (max (max (shA, sh9), sh8), sh7), sh6), sh5), sh4);
188+ return saturate (finalHeight);
189+ }
190+
172191float4 main (VS_OUTPUT input) : SV_TARGET
173192{
174193 float4 vc0 = input.Colour0;
@@ -192,7 +211,8 @@ float4 main(VS_OUTPUT input) : SV_TARGET
192211 layerBlends.z = vc1.g * (1.0f - vc1.b);
193212 layerBlends.w = vc1.g * vc1.b;
194213
195- // Calculate single parallax offset using blended heights (GTA V approach)
214+ // Calculate single parallax offset using blended heights
215+ float parallaxSelfShadow = 1.0 ;
196216 if (EnableHeightMap && RenderMode == 0 )
197217 {
198218 float3 viewDir = -normalize (input.CamRelPos); // Negate to get direction FROM surface TO camera
@@ -209,6 +229,17 @@ float4 main(VS_OUTPUT input) : SV_TARGET
209229 sc2 += parallaxOffset;
210230 sc3 += parallaxOffset;
211231 sc4 += parallaxOffset;
232+
233+ // Parallax self-shadow, transform light dir to tangent space and trace blended heights
234+ float3 tanLightDir;
235+ tanLightDir.x = dot (tang, GlobalLights.LightDir.xyz);
236+ tanLightDir.y = dot (bitang, GlobalLights.LightDir.xyz);
237+ tanLightDir.z = dot (norm, GlobalLights.LightDir.xyz);
238+ float2 blendedScaleBias = GetBlendedScaleBias (layerBlends);
239+ float blendedHScale = blendedScaleBias.x * POM_HEIGHT_SCALE;
240+ float edgeWeight = 1.0f - saturate (input.EdgeWeight.x);
241+ float shadowAmount = TraceTerrainSelfShadow (layerBlends, sc0, tanLightDir, edgeWeight, blendedHScale);
242+ parallaxSelfShadow = 1.0 - shadowAmount * PARALLAX_SELF_SHADOW_AMOUNT;
212243 }
213244
214245 float4 bc0 = float4 (0.5 , 0.5 , 0.5 , 1 );
@@ -392,7 +423,7 @@ float4 main(VS_OUTPUT input) : SV_TARGET
392423
393424 float3 spec = 0 ;
394425
395- tv.rgb = FullLighting (tv.rgb, spec, norm, vc0, GlobalLights, EnableShadows, input.Shadows.x, input.LightShadow);
426+ tv.rgb = FullLighting (tv.rgb, spec, norm, vc0, GlobalLights, EnableShadows, input.Shadows.x, input.LightShadow, parallaxSelfShadow );
396427
397428
398429 return float4 (tv.rgb, saturate (tv.a));
0 commit comments