Skip to content

Commit 617c456

Browse files
committed
add shadowing to parallax geometry
1 parent 3315a75 commit 617c456

File tree

6 files changed

+77
-6
lines changed

6 files changed

+77
-6
lines changed

CodeWalker.Shaders/BasicPS.hlsl

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,27 @@ float4 main(VS_OUTPUT input) : SV_TARGET
55
{
66
// Calculate parallax offset if height mapping is enabled
77
float2 parallaxTexOffset = float2(0, 0);
8+
float parallaxSelfShadow = 1.0;
89
if (EnableHeightMap && RenderMode == 0)
910
{
1011
float3 viewDir = -normalize(input.CamRelPos); // Negate to get direction FROM surface TO camera
12+
float3 norm0 = normalize(input.Normal);
13+
float3 tang0 = normalize(input.Tangent.xyz);
14+
float3 bitang0 = normalize(input.Bitangent.xyz);
1115
parallaxTexOffset = ParallaxOffset(
1216
Heightmap, TextureSS, input.Texcoord0,
13-
viewDir, normalize(input.Normal),
14-
normalize(input.Tangent.xyz), normalize(input.Bitangent.xyz),
17+
viewDir, norm0, tang0, bitang0,
1518
heightScale, heightBias);
19+
20+
// Parallax self-shadow, transform light dir to tangent space and trace
21+
float3 tanLightDir;
22+
tanLightDir.x = dot(tang0, GlobalLights.LightDir.xyz);
23+
tanLightDir.y = dot(bitang0, GlobalLights.LightDir.xyz);
24+
tanLightDir.z = dot(norm0, GlobalLights.LightDir.xyz);
25+
float shadowAmount = TraceSelfShadow(Heightmap, TextureSS,
26+
input.Texcoord0 + parallaxTexOffset,
27+
tanLightDir, 1.0, heightScale);
28+
parallaxSelfShadow = 1.0 - shadowAmount * PARALLAX_SELF_SHADOW_AMOUNT;
1629
}
1730

1831
// Apply parallax offset to base texture coordinates
@@ -176,7 +189,7 @@ float4 main(VS_OUTPUT input) : SV_TARGET
176189

177190
float4 fc = c;
178191

179-
c.rgb = FullLighting(c.rgb, spec, norm, input.Colour0, GlobalLights, EnableShadows, input.Shadows.x, input.LightShadow);
192+
c.rgb = FullLighting(c.rgb, spec, norm, input.Colour0, GlobalLights, EnableShadows, input.Shadows.x, input.LightShadow, parallaxSelfShadow);
180193

181194

182195
if (IsEmissive==1)

CodeWalker.Shaders/Common.hlsli

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,30 @@ float TraceHeight(Texture2D<float4> heightMapSampler, SamplerState samplerState,
215215
return clamp(finalHeight, 0.0, 1.0f);
216216
}
217217

218+
// Parallax self-shadow: traces through heightmap in light direction to find occlusion
219+
// Returns shadow factor (0 = fully lit, 1 = fully in shadow)
220+
float TraceSelfShadow(Texture2D<float4> heightMapSampler, SamplerState samplerState, float2 texCoords, float3 tanLightDir, float edgeWeight, float hScale)
221+
{
222+
float2 inXY = (tanLightDir.xy * hScale * edgeWeight) / max(tanLightDir.z, 0.01f);
223+
224+
// Sample base height at current (displaced) position
225+
float sh0 = heightMapSampler.SampleLevel(samplerState, texCoords, 0).r;
226+
227+
// Trace 7 samples along light direction with increasing weight for closer occlusion
228+
float shA = (heightMapSampler.SampleLevel(samplerState, texCoords + inXY * 0.88, 0).r - sh0 - 0.88) * 1;
229+
float sh9 = (heightMapSampler.SampleLevel(samplerState, texCoords + inXY * 0.77, 0).r - sh0 - 0.77) * 2;
230+
float sh8 = (heightMapSampler.SampleLevel(samplerState, texCoords + inXY * 0.66, 0).r - sh0 - 0.66) * 4;
231+
float sh7 = (heightMapSampler.SampleLevel(samplerState, texCoords + inXY * 0.55, 0).r - sh0 - 0.55) * 6;
232+
float sh6 = (heightMapSampler.SampleLevel(samplerState, texCoords + inXY * 0.44, 0).r - sh0 - 0.44) * 8;
233+
float sh5 = (heightMapSampler.SampleLevel(samplerState, texCoords + inXY * 0.33, 0).r - sh0 - 0.33) * 10;
234+
float sh4 = (heightMapSampler.SampleLevel(samplerState, texCoords + inXY * 0.22, 0).r - sh0 - 0.22) * 12;
235+
236+
float finalHeight = max(max(max(max(max(max(shA, sh9), sh8), sh7), sh6), sh5), sh4);
237+
return saturate(finalHeight);
238+
}
239+
240+
#define PARALLAX_SELF_SHADOW_AMOUNT 0.95f
241+
218242
// Calculate parallax texture coordinate offset
219243
float2 ParallaxOffset(Texture2D<float4> heightMapSampler, SamplerState samplerState, float2 texCoords,
220244
float3 viewDir, float3 normal, float3 tangent, float3 bitangent,

CodeWalker.Shaders/Shadowmap.hlsli

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ float ShadowAmount(float4 shadowcoord, float shadowdepth)//, inout float4 colour
225225

226226

227227

228-
float3 FullLighting(float3 diff, float3 spec, float3 norm, float4 vc0, uniform ShaderGlobalLightParams globalLights, uint enableShadows, float shadowdepth, float4 shadowcoord)
228+
float3 FullLighting(float3 diff, float3 spec, float3 norm, float4 vc0, uniform ShaderGlobalLightParams globalLights, uint enableShadows, float shadowdepth, float4 shadowcoord, float selfShadow = 1.0)
229229
{
230230
float lf = saturate(dot(norm, globalLights.LightDir.xyz));
231231

@@ -241,6 +241,9 @@ float3 FullLighting(float3 diff, float3 spec, float3 norm, float4 vc0, uniform S
241241
}
242242
}
243243

244+
// Apply parallax self-shadow to cascade shadow
245+
shadowlit *= selfShadow;
246+
244247
lf *= shadowlit;
245248

246249
float3 speclit = spec*shadowlit;

CodeWalker.Shaders/TerrainPS.hlsl

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
172191
float4 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));

Shaders/BasicPS.cso

1.48 KB
Binary file not shown.

Shaders/TerrainPS.cso

3.99 KB
Binary file not shown.

0 commit comments

Comments
 (0)