From 4623c25cb2bf2e8391615d877215793b2dfe9eb7 Mon Sep 17 00:00:00 2001 From: Popov72 Date: Mon, 11 May 2020 20:27:31 +0200 Subject: [PATCH] Fix bug with CSM and autoCalcDepthBounds = true --- dist/preview release/what's new.md | 1 + .../src/shadowOnly/shadowOnlyMaterial.ts | 36 +++++++++++++++++-- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/dist/preview release/what's new.md b/dist/preview release/what's new.md index 580467a9548..843d15375f7 100644 --- a/dist/preview release/what's new.md +++ b/dist/preview release/what's new.md @@ -191,6 +191,7 @@ - Make sure bone matrices are up to date when calling `TransformNode.attachToBone` ([Popov72](https://github.com/Popov72)) - Fix display problem with transparent objects and SSAO2 pipeline (bug in the `GeometryBufferRenderer`) ([Popov72](https://github.com/Popov72)) - Fixed `Sound` not accepting a `TransformNode` as a source for spatial sound ([Poolminer](https://github.com/Poolminer)) +- Fix bug when using `ShadowOnlyMaterial` with Cascaded Shadow Map and `autoCalcDepthBounds` is `true` ([Popov72](https://github.com/Popov72)) ## Breaking changes diff --git a/materialsLibrary/src/shadowOnly/shadowOnlyMaterial.ts b/materialsLibrary/src/shadowOnly/shadowOnlyMaterial.ts index f8406f3f9f1..31977f4bb82 100644 --- a/materialsLibrary/src/shadowOnly/shadowOnlyMaterial.ts +++ b/materialsLibrary/src/shadowOnly/shadowOnlyMaterial.ts @@ -18,6 +18,7 @@ import { _TypeStore } from 'babylonjs/Misc/typeStore'; import "./shadowOnly.fragment"; import "./shadowOnly.vertex"; import { EffectFallbacks } from 'babylonjs/Materials/effectFallbacks'; +import { CascadedShadowGenerator } from 'babylonjs/Lights/Shadows/cascadedShadowGenerator'; class ShadowOnlyMaterialDefines extends MaterialDefines { public CLIPPLANE = false; @@ -41,6 +42,7 @@ class ShadowOnlyMaterialDefines extends MaterialDefines { export class ShadowOnlyMaterial extends PushMaterial { private _activeLight: IShadowLight; + private _needAlphaBlending = true; constructor(name: string, scene: Scene) { super(name, scene); @@ -49,7 +51,7 @@ export class ShadowOnlyMaterial extends PushMaterial { public shadowColor = Color3.Black(); public needAlphaBlending(): boolean { - return true; + return this._needAlphaBlending; } public needAlphaTesting(): boolean { @@ -68,6 +70,15 @@ export class ShadowOnlyMaterial extends PushMaterial { this._activeLight = light; } + private _getFirstShadowLightForMesh(mesh: AbstractMesh): Nullable { + for (var light of mesh.lightSources) { + if (light.shadowEnabled) { + return light as IShadowLight; + } + } + return null; + } + // Methods public isReadyForSubMesh(mesh: AbstractMesh, subMesh: SubMesh, useInstances?: boolean): boolean { if (this.isFrozen) { @@ -114,6 +125,16 @@ export class ShadowOnlyMaterial extends PushMaterial { defines._needNormals = MaterialHelper.PrepareDefinesForLights(scene, mesh, defines, false, 1); + const shadowGenerator = this._getFirstShadowLightForMesh(mesh)?.getShadowGenerator(); + + this._needAlphaBlending = true; + + if (shadowGenerator && (shadowGenerator as any).getClassName && (shadowGenerator as any).getClassName() === 'CascadedShadowGenerator') { + const csg = shadowGenerator as CascadedShadowGenerator; + + this._needAlphaBlending = !csg.autoCalcDepthBounds; + } + // Attribs MaterialHelper.PrepareDefinesForAttributes(mesh, defines, false, true); @@ -226,10 +247,21 @@ export class ShadowOnlyMaterial extends PushMaterial { // Lights if (scene.lightsEnabled) { MaterialHelper.BindLights(scene, mesh, this._activeEffect, defines, 1); + + const light = this._getFirstShadowLightForMesh(mesh); + + if (light) { + // Make sure the uniforms for this light will be rebound for other materials using this light when rendering the current frame. + // Indeed, there is an optimization in Light that binds the light uniforms only once per frame for a given light (if using ubo). + // Doing this way assumes that all uses of this light are the same, meaning all parameters passed to Light._bindLlight + // are the same, notably useSpecular. However, isReadyForSubMesh (see above) is passing false for this parameter, which may not be + // the value the other materials may pass. + light._renderId = -1; + } } // View - if (scene.fogEnabled && mesh.applyFog && scene.fogMode !== Scene.FOGMODE_NONE) { + if (scene.fogEnabled && mesh.applyFog && scene.fogMode !== Scene.FOGMODE_NONE || defines["SHADOWCSM0"]) { this._activeEffect.setMatrix("view", scene.getViewMatrix()); }