Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix bug in ShadowOnlyMaterial with CSM and autoCalcDepthBounds = true #8142

Merged
merged 1 commit into from May 12, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions dist/preview release/what's new.md
Expand Up @@ -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

Expand Down
36 changes: 34 additions & 2 deletions materialsLibrary/src/shadowOnly/shadowOnlyMaterial.ts
Expand Up @@ -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;
Expand All @@ -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);
Expand All @@ -49,7 +51,7 @@ export class ShadowOnlyMaterial extends PushMaterial {
public shadowColor = Color3.Black();

public needAlphaBlending(): boolean {
return true;
return this._needAlphaBlending;
}

public needAlphaTesting(): boolean {
Expand All @@ -68,6 +70,15 @@ export class ShadowOnlyMaterial extends PushMaterial {
this._activeLight = light;
}

private _getFirstShadowLightForMesh(mesh: AbstractMesh): Nullable<IShadowLight> {
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) {
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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());
}

Expand Down