Visitar URL original
fix(core): draw the shadow map without per-layer polygon offset (#10892) · visgl/deck.gl@2b94af2 · GitHub
Skip to content

Commit 2b94af2

Browse files
charlieforward9claude
authored andcommitted
fix(core): draw the shadow map without per-layer polygon offset (#10892)
Layer._drawLayer applies `getPolygonOffset` (default [0, -layerIndex * 100]) in every pass. The shadow map stores gl_FragCoord.z, which includes the offset, so the k-th layer drawn in the shadow pass stored a depth k * 100 * 2^-16 closer to the light. From the third layer on, layers fell partly or fully into their own shadow. ShadowPass now sets depthBias: 0 so the shadow map is drawn without the offset. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit 324350c)
1 parent 4504464 commit 2b94af2

4 files changed

Lines changed: 83 additions & 1 deletion

File tree

‎modules/core/src/passes/shadow-pass.ts‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,10 @@ export default class ShadowPass extends LayersPass {
8282
...layer.props.parameters,
8383
blend: false,
8484
depthWriteEnabled: true,
85-
depthCompare: 'less-equal'
85+
depthCompare: 'less-equal',
86+
// The shadow map stores gl_FragCoord.z, which includes the per-layer polygon offset
87+
// (`getPolygonOffset`). Draw without it so layers do not shadow themselves.
88+
depthBias: 0
8689
};
8790
}
8891

‎test/modules/core/passes/shadow-pass.spec.ts‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,3 +110,18 @@ webglTest('ShadowPass#render disables lighting', () => {
110110
shadowPass.delete();
111111
layerManager.finalize();
112112
});
113+
114+
test('ShadowPass#getLayerParameters', () => {
115+
const layer = new PolygonLayer({
116+
data: FIXTURES.polygons.slice(0, 3),
117+
getPolygon: f => f,
118+
parameters: {depthBias: 10}
119+
});
120+
121+
const shadowPass = new ShadowPass(device, {pixelRatio: 1.0});
122+
const parameters = shadowPass.getLayerParameters(layer, 3, null);
123+
124+
expect(parameters.depthBias, `ShadowPass draws without polygon offset`).toBe(0);
125+
expect(parameters.blend, `ShadowPass disables blending`).toBe(false);
126+
shadowPass.delete();
127+
});
5.9 KB
Loading

‎test/render/test-cases/effects.spec.ts‎

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,27 @@ const MASK_POLYGON = [
4040
[-122.48, 37.75]
4141
];
4242

43+
// Coplanar ground tiles, one layer each. Tiles with a higher layer index must not shadow themselves.
44+
const SHADOW_TILE_SIZE = 0.0008;
45+
const shadowTileLayers = Array.from({length: 8}, (_, i) => {
46+
const x = -122.4 + ((i % 4) - 1.5) * SHADOW_TILE_SIZE;
47+
const y = 37.74 + (0.5 - Math.floor(i / 4)) * SHADOW_TILE_SIZE;
48+
const r = SHADOW_TILE_SIZE / 2;
49+
return new SolidPolygonLayer({
50+
id: `shadow-tile-${i}`,
51+
data: [
52+
[
53+
[x - r, y - r],
54+
[x + r, y - r],
55+
[x + r, y + r],
56+
[x - r, y + r]
57+
]
58+
],
59+
getPolygon: f => f,
60+
getFillColor: [200, 200, 200]
61+
});
62+
});
63+
4364
const testCases = [
4465
{
4566
name: 'shadow-effect',
@@ -140,6 +161,49 @@ const testCases = [
140161
],
141162
goldenImage: './test/render/golden-images/shadow-effect-simple-mesh.png'
142163
},
164+
{
165+
name: 'shadow-effect-layer-index',
166+
effects: [
167+
new LightingEffect({
168+
ambientLight: new AmbientLight({
169+
color: [255, 255, 255],
170+
intensity: 1.0
171+
}),
172+
dirLight: new DirectionalLight({
173+
color: [255, 255, 255],
174+
intensity: 1.0,
175+
direction: [1, -0.5, -1],
176+
_shadow: true
177+
})
178+
})
179+
],
180+
viewState: {
181+
latitude: 37.74,
182+
longitude: -122.4,
183+
zoom: 17,
184+
pitch: 45,
185+
bearing: 0
186+
},
187+
layers: [
188+
...shadowTileLayers,
189+
new SolidPolygonLayer({
190+
id: 'shadow-box',
191+
data: [
192+
[
193+
[-122.4003, 37.7397],
194+
[-122.3997, 37.7397],
195+
[-122.3997, 37.7403],
196+
[-122.4003, 37.7403]
197+
]
198+
],
199+
extruded: true,
200+
getPolygon: f => f,
201+
getElevation: 40,
202+
getFillColor: [230, 80, 60]
203+
})
204+
],
205+
goldenImage: './test/render/golden-images/shadow-effect-layer-index.png'
206+
},
143207
...[true, false].map(maskInverted => ({
144208
name: `mask-effect${maskInverted ? '-inverted' : ''}`,
145209
viewState: {

0 commit comments

Comments
 (0)