Skip to content

Commit

Permalink
Better alpha handling
Browse files Browse the repository at this point in the history
  • Loading branch information
bghgary committed Sep 13, 2024
1 parent 9e3589d commit 89fab21
Show file tree
Hide file tree
Showing 24 changed files with 79 additions and 131 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -902,7 +902,7 @@ export class BackgroundMaterial extends PushMaterial {
}

// Misc.
PrepareDefinesForMisc(mesh, scene, this._useLogarithmicDepth, this.pointsCloud, this.fogEnabled, this._shouldTurnAlphaTestOn(mesh), defines);
PrepareDefinesForMisc(mesh, scene, this._useLogarithmicDepth, this.pointsCloud, this.fogEnabled, this.needAlphaTestingForMesh(mesh), defines);

// Values that need to be evaluated on every frame
PrepareDefinesForFrameBoundValues(scene, engine, this, defines, useInstances, null, subMesh.getRenderingMesh().hasThinInstances);
Expand Down
59 changes: 18 additions & 41 deletions packages/dev/core/src/Materials/PBR/pbrBaseMaterial.ts
Original file line number Diff line number Diff line change
Expand Up @@ -721,12 +721,6 @@ export abstract class PBRBaseMaterial extends PushMaterial {
*/
public _alphaCutOff = 0.4;

/**
* Enforces alpha test in opaque or blend mode in order to improve the performances of some situations.
* @internal
*/
public override _forceAlphaTest = false;

/**
* A fresnel is applied to the alpha of the model to ensure grazing angles edges are not alpha tested.
* And/Or occlude the blended part. (alpha is converted to gamma to compute the fresnel)
Expand Down Expand Up @@ -1008,55 +1002,38 @@ export abstract class PBRBaseMaterial extends PushMaterial {
return "PBRBaseMaterial";
}

/**
* Returns true if alpha blending should be disabled.
*/
protected override get _disableAlphaBlending(): boolean {
return (
this._transparencyMode === PBRBaseMaterial.PBRMATERIAL_OPAQUE ||
this._transparencyMode === PBRBaseMaterial.PBRMATERIAL_ALPHATEST ||
this.subSurface?.disableAlphaBlending
);
protected _shouldUseAlphaFromAlbedoTexture(): boolean {
return this._albedoTexture != null && this._albedoTexture.hasAlpha && this._useAlphaFromAlbedoTexture && this._transparencyMode !== PBRBaseMaterial.PBRMATERIAL_OPAQUE;
}

/**
* @returns whether or not this material should be rendered in alpha blend mode.
*/
protected override _hasAlpha(mesh: AbstractMesh): boolean {
return super._hasAlpha(mesh) || this._shouldUseAlphaFromAlbedoTexture() || this._opacityTexture != null;
}

/** @override */
public override needAlphaBlending(): boolean {
if (this._disableAlphaBlending) {
if (this._hasTransparencyMode) {
return this._transparencyModeIsBlend;
}

if (this.subSurface?.disableAlphaBlending) {
return false;
}

return this.alpha < 1.0 || this._opacityTexture != null || this._shouldUseAlphaFromAlbedoTexture();
return super.needAlphaBlending();
}

/**
* @returns whether or not this material should be rendered in alpha test mode.
*/
/** @override */
public override needAlphaTesting(): boolean {
if (this._forceAlphaTest) {
return true;
if (this._hasTransparencyMode) {
return this._transparencyModeIsTest;
}

if (this.subSurface?.disableAlphaBlending) {
return false;
}

return this._hasAlphaChannel() && (this._transparencyMode == null || this._transparencyMode === PBRBaseMaterial.PBRMATERIAL_ALPHATEST);
}

/**
* @returns whether or not the alpha value of the albedo texture should be used for alpha blending.
*/
protected _shouldUseAlphaFromAlbedoTexture(): boolean {
return this._albedoTexture != null && this._albedoTexture.hasAlpha && this._useAlphaFromAlbedoTexture && this._transparencyMode !== PBRBaseMaterial.PBRMATERIAL_OPAQUE;
}

/**
* @returns whether or not there is a usable alpha channel for transparency.
*/
protected _hasAlphaChannel(): boolean {
return (this._albedoTexture != null && this._albedoTexture.hasAlpha) || this._opacityTexture != null;
return super.needAlphaTesting();
}

/**
Expand Down Expand Up @@ -1897,7 +1874,7 @@ export abstract class PBRBaseMaterial extends PushMaterial {
this._useLogarithmicDepth,
this.pointsCloud,
this.fogEnabled,
this._shouldTurnAlphaTestOn(mesh) || this._forceAlphaTest,
this.needAlphaTestingForMesh(mesh),
defines,
this._applyDecalMapAfterDetailMap
);
Expand Down
61 changes: 31 additions & 30 deletions packages/dev/core/src/Materials/material.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1058,11 +1058,6 @@ export class Material implements IAnimatable, IClipPlanesHolder {
return this.sideOrientation !== null ? this.sideOrientation : mesh.sideOrientation;
}

/**
* Enforces alpha test in opaque or blend mode in order to improve the performances of some situations.
*/
protected _forceAlphaTest = false;

/**
* The transparency mode of the material.
*/
Expand Down Expand Up @@ -1094,25 +1089,32 @@ export class Material implements IAnimatable, IClipPlanesHolder {

this._transparencyMode = value;

this._forceAlphaTest = value === Material.MATERIAL_ALPHATESTANDBLEND;

this._markAllSubMeshesAsTexturesAndMiscDirty();
}

/**
* Returns true if alpha blending should be disabled.
*/
protected get _disableAlphaBlending(): boolean {
return this._transparencyMode === Material.MATERIAL_OPAQUE || this._transparencyMode === Material.MATERIAL_ALPHATEST;
protected get _hasTransparencyMode(): boolean {
return this._transparencyMode != null;
}

protected get _transparencyModeIsBlend(): boolean {
return this._transparencyMode === Material.MATERIAL_ALPHABLEND || this._transparencyMode === Material.MATERIAL_ALPHATESTANDBLEND;
}

protected get _transparencyModeIsTest(): boolean {
return this._transparencyMode === Material.MATERIAL_ALPHATEST || this._transparencyMode === Material.MATERIAL_ALPHATESTANDBLEND;
}

protected _hasAlpha(mesh: AbstractMesh): boolean {
return this.alpha < 1.0 || mesh.hasVertexAlpha;
}

/**
* Specifies whether or not this material should be rendered in alpha blend mode.
* @returns a boolean specifying if alpha blending is needed
*/
public needAlphaBlending(): boolean {
if (this._disableAlphaBlending) {
return false;
if (this._hasTransparencyMode) {
return this._transparencyModeIsBlend;
}

return this.alpha < 1.0;
Expand All @@ -1124,24 +1126,24 @@ export class Material implements IAnimatable, IClipPlanesHolder {
* @returns a boolean specifying if alpha blending is needed for the mesh
*/
public needAlphaBlendingForMesh(mesh: AbstractMesh): boolean {
if (mesh.visibility < 1.0) {
return true;
if (this._hasTransparencyMode) {
return this._transparencyModeIsBlend;
}

if (this._disableAlphaBlending) {
return false;
if (this.needAlphaBlending()) {
return true;
}

return mesh.hasVertexAlpha || this.needAlphaBlending();
return this._hasAlpha(mesh) || mesh.visibility < 1.0;
}

/**
* Specifies whether or not this material should be rendered in alpha test mode.
* @returns a boolean specifying if an alpha test is needed.
*/
public needAlphaTesting(): boolean {
if (this._forceAlphaTest) {
return true;
if (this._hasTransparencyMode) {
return this._transparencyModeIsTest;
}

return false;
Expand All @@ -1153,16 +1155,15 @@ export class Material implements IAnimatable, IClipPlanesHolder {
* @returns a boolean specifying if an alpha test is needed.
*/
public needAlphaTestingForMesh(mesh: AbstractMesh): boolean {
return mesh.hasVertexAlpha || this.needAlphaTesting();
}
if (this._hasTransparencyMode) {
return this._transparencyModeIsTest;
}

/**
* Specifies if material alpha testing should be turned on for the mesh
* @param mesh defines the mesh to check
* @returns a boolean specifying if alpha testing should be turned on for the mesh
*/
protected _shouldTurnAlphaTestOn(mesh: AbstractMesh): boolean {
return !this.needAlphaBlendingForMesh(mesh) && this.needAlphaTestingForMesh(mesh);
if (this.needAlphaTesting()) {
return true;
}

return this._hasAlpha(mesh);
}

/**
Expand Down
2 changes: 1 addition & 1 deletion packages/dev/core/src/Materials/shaderMaterial.ts
Original file line number Diff line number Diff line change
Expand Up @@ -847,7 +847,7 @@ export class ShaderMaterial extends PushMaterial {
}

// Alpha test
if (mesh && this._shouldTurnAlphaTestOn(mesh)) {
if (mesh && this.needAlphaTestingForMesh(mesh)) {
defines.push("#define ALPHATEST");
}

Expand Down
48 changes: 9 additions & 39 deletions packages/dev/core/src/Materials/standardMaterial.ts
Original file line number Diff line number Diff line change
Expand Up @@ -871,47 +871,17 @@ export class StandardMaterial extends PushMaterial {
return "StandardMaterial";
}

/**
* Specifies if the material will require alpha blending
* @returns a boolean specifying if alpha blending is needed
*/
public override needAlphaBlending(): boolean {
if (this._disableAlphaBlending) {
return false;
}

return (
this.alpha < 1.0 ||
this._opacityTexture != null ||
this._shouldUseAlphaFromDiffuseTexture() ||
(this._opacityFresnelParameters && this._opacityFresnelParameters.isEnabled)
);
}

/**
* Specifies if this material should be rendered in alpha test mode
* @returns a boolean specifying if an alpha test is needed.
*/
public override needAlphaTesting(): boolean {
if (this._forceAlphaTest) {
return true;
}

return this._hasAlphaChannel() && (this._transparencyMode == null || this._transparencyMode === Material.MATERIAL_ALPHATEST);
}

/**
* @returns whether or not the alpha value of the diffuse texture should be used for alpha blending.
*/
protected _shouldUseAlphaFromDiffuseTexture(): boolean {
return this._diffuseTexture != null && this._diffuseTexture.hasAlpha && this._useAlphaFromDiffuseTexture && this._transparencyMode !== Material.MATERIAL_OPAQUE;
}

/**
* @returns whether or not there is a usable alpha channel for transparency.
*/
protected _hasAlphaChannel(): boolean {
return (this._diffuseTexture != null && this._diffuseTexture.hasAlpha) || this._opacityTexture != null;
protected override _hasAlpha(mesh: AbstractMesh): boolean {
return super._hasAlpha(mesh) || this._shouldUseAlphaFromDiffuseTexture() || this._opacityTexture != null;
}

/** @override */
public override needAlphaBlending(): boolean {
return super.needAlphaBlending() || this._opacityFresnelParameters?.isEnabled;
}

/**
Expand Down Expand Up @@ -1224,7 +1194,7 @@ export class StandardMaterial extends PushMaterial {
this._useLogarithmicDepth,
this.pointsCloud,
this.fogEnabled,
this._shouldTurnAlphaTestOn(mesh) || this._forceAlphaTest,
this.needAlphaTestingForMesh(mesh),
defines,
this._applyDecalMapAfterDetailMap
);
Expand Down Expand Up @@ -1686,7 +1656,7 @@ export class StandardMaterial extends PushMaterial {
BindTextureMatrix(this._opacityTexture, ubo, "opacity");
}

if (this._hasAlphaChannel()) {
if (this._hasAlpha(mesh)) {
ubo.updateFloat("alphaCutOff", this.alphaCutOff);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ albedoOpacityOutParams albedoOpacityBlock(
#if !defined(SS_LINKREFRACTIONTOTRANSPARENCY) && !defined(ALPHAFRESNEL)
#ifdef ALPHATEST
#if DEBUGMODE != 88
if (alpha < ALPHATESTVALUE)
if (alpha + 0.0000001 < ALPHATESTVALUE)
discard;
#endif

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
outParams.alpha = getReflectanceFromAnalyticalBRDFLookup_Jones(saturate(dot(viewDirectionW, normalForward)), vec3(opacity0), vec3(opacity90), sqrt(microSurface)).x;

#ifdef ALPHATEST
if (outParams.alpha < ALPHATESTVALUE)
if (outParams.alpha + 0.0000001 < ALPHATESTVALUE)
discard;

#ifndef ALPHABLEND
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ vec4 finalColor = glowColor;
#endif

#ifdef ALPHATEST
if (finalColor.a < ALPHATESTVALUE)
if (finalColor.a + 0.0000001 < ALPHATESTVALUE)
discard;
#endif

Expand Down
2 changes: 1 addition & 1 deletion packages/dev/core/src/Shaders/shadowMap.fragment.fx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ void main(void)
#endif

#ifdef ALPHATESTVALUE
if (alphaFromAlphaTexture < ALPHATESTVALUE)
if (alphaFromAlphaTexture + 0.0000001 < ALPHATESTVALUE)
discard;
#endif
#endif
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ fn albedoOpacityBlock(
#if !defined(SS_LINKREFRACTIONTOTRANSPARENCY) && !defined(ALPHAFRESNEL)
#ifdef ALPHATEST
#if DEBUGMODE != 88
if (alpha < ALPHATESTVALUE) {
if (alpha + 0.0000001 < ALPHATESTVALUE) {
discard;
}
#endif
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
outParams.alpha = getReflectanceFromAnalyticalBRDFLookup_Jones(saturate(dot(viewDirectionW, normalForward)), vec3f(opacity0), vec3f(opacity90), sqrt(microSurface)).x;

#ifdef ALPHATEST
if (outParams.alpha < ALPHATESTVALUE) {
if (outParams.alpha + 0.0000001 < ALPHATESTVALUE) {
discard;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ var finalColor: vec4f = uniforms.glowColor;
#endif

#ifdef ALPHATEST
if (finalColor.a < ALPHATESTVALUE)
if (finalColor.a + 0.0000001 < ALPHATESTVALUE)
discard;
#endif

Expand Down
2 changes: 1 addition & 1 deletion packages/dev/core/src/ShadersWGSL/shadowMap.fragment.fx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ fn main(input: FragmentInputs) -> FragmentOutputs {
#endif

#ifdef ALPHATESTVALUE
if (alphaFromAlphaTexture < ALPHATESTVALUE) {
if (alphaFromAlphaTexture + 0.0000001 < ALPHATESTVALUE) {
discard;
}
#endif
Expand Down
2 changes: 1 addition & 1 deletion packages/dev/materials/src/cell/cellMaterial.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ export class CellMaterial extends PushMaterial {
defines.CELLBASIC = !this.computeHighLevel;

// Misc.
PrepareDefinesForMisc(mesh, scene, this._useLogarithmicDepth, this.pointsCloud, this.fogEnabled, this._shouldTurnAlphaTestOn(mesh), defines);
PrepareDefinesForMisc(mesh, scene, this._useLogarithmicDepth, this.pointsCloud, this.fogEnabled, this.needAlphaTestingForMesh(mesh), defines);

// Lights
defines._needNormals = PrepareDefinesForLights(scene, mesh, defines, false, this._maxSimultaneousLights, this._disableLighting);
Expand Down
2 changes: 1 addition & 1 deletion packages/dev/materials/src/fur/furMaterial.ts
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ export class FurMaterial extends PushMaterial {
}

// Misc.
PrepareDefinesForMisc(mesh, scene, this._useLogarithmicDepth, this.pointsCloud, this.fogEnabled, this._shouldTurnAlphaTestOn(mesh), defines);
PrepareDefinesForMisc(mesh, scene, this._useLogarithmicDepth, this.pointsCloud, this.fogEnabled, this.needAlphaTestingForMesh(mesh), defines);

// Lights
defines._needNormals = PrepareDefinesForLights(scene, mesh, defines, false, this._maxSimultaneousLights, this._disableLighting);
Expand Down
2 changes: 1 addition & 1 deletion packages/dev/materials/src/gradient/gradientMaterial.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ export class GradientMaterial extends PushMaterial {

PrepareDefinesForFrameBoundValues(scene, engine, this, defines, useInstances ? true : false);

PrepareDefinesForMisc(mesh, scene, this._useLogarithmicDepth, this.pointsCloud, this.fogEnabled, this._shouldTurnAlphaTestOn(mesh), defines);
PrepareDefinesForMisc(mesh, scene, this._useLogarithmicDepth, this.pointsCloud, this.fogEnabled, this.needAlphaTestingForMesh(mesh), defines);

defines._needNormals = PrepareDefinesForLights(scene, mesh, defines, false, this._maxSimultaneousLights, this._disableLighting);

Expand Down
Loading

0 comments on commit 89fab21

Please sign in to comment.