Skip to content

Commit da46f5f

Browse files
authored
fix shadow mapping on models larger than 1x1 by scaling projection bounds rather than camera scale (#5168)
1 parent 7fa5398 commit da46f5f

1 file changed

Lines changed: 28 additions & 8 deletions

File tree

  • packages/model-viewer/src/three-components

packages/model-viewer/src/three-components/Shadow.ts

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ export class Shadow extends Object3D {
104104
// like MeshDepthMaterial, but goes from black to transparent
105105
this.depthMaterial.onBeforeCompile = function(shader) {
106106
shader.fragmentShader = shader.fragmentShader.replace(
107-
'gl_FragColor = vec4( vec3( 1.0 - fragCoordZ ), opacity );',
107+
/gl_FragColor\s*=\s*vec4\(\s*vec3\(\s*1\.0\s*-\s*fragCoordZ\s*\),\s*opacity\s*\);/,
108108
'gl_FragColor = vec4( vec3( 0.0 ), ( 1.0 - fragCoordZ ) * opacity );');
109109
};
110110
// Render both sides, back sides face the light source and
@@ -232,10 +232,18 @@ export class Shadow extends Object3D {
232232
}
233233

234234
// These pads account for the softening radius around the shadow.
235-
this.camera.scale.set(
236-
size.x * (1 + TAP_WIDTH / baseWidth),
237-
size.z * (1 + TAP_WIDTH / baseHeight),
238-
1);
235+
const frustumWidth = size.x * (1 + TAP_WIDTH / baseWidth);
236+
const frustumHeight = size.z * (1 + TAP_WIDTH / baseHeight);
237+
238+
this.camera.left = -frustumWidth / 2;
239+
this.camera.right = frustumWidth / 2;
240+
this.camera.bottom = -frustumHeight / 2;
241+
this.camera.top = frustumHeight / 2;
242+
this.camera.scale.set(1, 1, 1);
243+
244+
this.floor.scale.set(frustumWidth, frustumHeight, 1);
245+
this.blurPlane.scale.set(frustumWidth, frustumHeight, 1);
246+
239247
this.needsUpdate = true;
240248
}
241249

@@ -280,9 +288,6 @@ export class Shadow extends Object3D {
280288
// force the depthMaterial to everything
281289
scene.overrideMaterial = this.depthMaterial;
282290

283-
// set renderer clear alpha
284-
const initialClearAlpha = renderer.getClearAlpha();
285-
renderer.setClearAlpha(0);
286291
this.floor.visible = false;
287292

288293
// disable XR for offscreen rendering
@@ -292,8 +297,23 @@ export class Shadow extends Object3D {
292297
// render to the render target to get the depths
293298
const oldRenderTarget = renderer.getRenderTarget();
294299
renderer.setRenderTarget(this.renderTarget);
300+
301+
const initialClearAlpha = renderer.getClearAlpha();
302+
renderer.setClearAlpha(0);
303+
const state = (renderer as any).state;
304+
if (state != null) {
305+
state.buffers.color.setMask(true);
306+
state.buffers.depth.setMask(true);
307+
}
308+
renderer.clear();
309+
310+
const initialAutoClear = renderer.autoClear;
311+
renderer.autoClear = false;
312+
295313
renderer.render(scene, this.camera);
296314

315+
renderer.autoClear = initialAutoClear;
316+
297317
// and reset the override material
298318
scene.overrideMaterial = null;
299319
this.floor.visible = true;

0 commit comments

Comments
 (0)