Skip to content

Commit

Permalink
Better alpha handling
Browse files Browse the repository at this point in the history
  • Loading branch information
bghgary committed Nov 4, 2024
1 parent 4704059 commit add318a
Show file tree
Hide file tree
Showing 23 changed files with 87 additions and 130 deletions.
4 changes: 2 additions & 2 deletions packages/dev/core/src/Layers/effectLayer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -595,7 +595,7 @@ export abstract class EffectLayer {

// Diffuse
if (material) {
const needAlphaTest = material.needAlphaTesting();
const needAlphaTest = material.needAlphaTestingForMesh(mesh);

const diffuseTexture = material.getAlphaTestTexture();
const needAlphaBlendFromDiffuse =
Expand Down Expand Up @@ -986,7 +986,7 @@ export abstract class EffectLayer {
}

if (!renderingMaterial) {
const needAlphaTest = material.needAlphaTesting();
const needAlphaTest = material.needAlphaTestingForMesh(effectiveMesh);

const diffuseTexture = material.getAlphaTestTexture();
const needAlphaBlendFromDiffuse =
Expand Down
2 changes: 1 addition & 1 deletion packages/dev/core/src/Lights/Shadows/shadowGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1564,7 +1564,7 @@ export class ShadowGenerator implements IShadowGenerator {
}

// Alpha test
const needAlphaTesting = material.needAlphaTesting();
const needAlphaTesting = material.needAlphaTestingForMesh(mesh);

if (needAlphaTesting || material.needAlphaBlending()) {
if (this.useOpacityTextureForTransparentShadow) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -889,7 +889,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 @@ -725,12 +725,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 @@ -1001,55 +995,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 @@ -1894,7 +1871,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
60 changes: 35 additions & 25 deletions packages/dev/core/src/Materials/material.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1081,11 +1081,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 @@ -1117,25 +1112,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 @@ -1147,36 +1149,44 @@ 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;
}

/**
* Specifies if material alpha testing should be turned on for the mesh
* Specifies whether or not this material should be rendered in alpha test mode when used with the given mesh.
* @param mesh defines the mesh to check
* @returns a boolean specifying if alpha testing should be turned on for the mesh
* @returns a boolean specifying if an alpha test is needed.
*/
protected _shouldTurnAlphaTestOn(mesh: AbstractMesh): boolean {
return !this.needAlphaBlendingForMesh(mesh) && this.needAlphaTesting();
public needAlphaTestingForMesh(mesh: AbstractMesh): boolean {
if (this._hasTransparencyMode) {
return this._transparencyModeIsTest;
}

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 @@ -855,7 +855,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 @@ -866,47 +866,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 @@ -1221,7 +1191,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 @@ -1687,7 +1657,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 @@ -213,7 +213,7 @@ export class VolumetricLightScatteringPostProcess extends PostProcess {

// Alpha test
if (material) {
if (material.needAlphaTesting()) {
if (material.needAlphaTestingForMesh(mesh)) {
defines.push("#define ALPHATEST");
}

Expand Down Expand Up @@ -463,7 +463,7 @@ export class VolumetricLightScatteringPostProcess extends PostProcess {
effect.setMatrix("viewProjection", scene.getTransformMatrix());

// Alpha test
if (material.needAlphaTesting()) {
if (material.needAlphaTestingForMesh(effectiveMesh)) {
const alphaTexture = material.getAlphaTestTexture();

if (alphaTexture) {
Expand Down
4 changes: 2 additions & 2 deletions packages/dev/core/src/Rendering/depthRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ export class DepthRenderer {

if (!renderingMaterial) {
// Alpha test
if (material.needAlphaTesting()) {
if (material.needAlphaTestingForMesh(effectiveMesh)) {
const alphaTexture = material.getAlphaTestTexture();

if (alphaTexture) {
Expand Down Expand Up @@ -404,7 +404,7 @@ export class DepthRenderer {
const attribs = [VertexBuffer.PositionKind];

// Alpha test
if (material.needAlphaTesting() && material.getAlphaTestTexture()) {
if (material.needAlphaTestingForMesh(mesh) && material.getAlphaTestTexture()) {
defines.push("#define ALPHATEST");
if (mesh.isVerticesDataPresent(VertexBuffer.UVKind)) {
attribs.push(VertexBuffer.UVKind);
Expand Down
4 changes: 2 additions & 2 deletions packages/dev/core/src/Rendering/geometryBufferRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -524,7 +524,7 @@ export class GeometryBufferRenderer {
if (material) {
let needUv = false;
// Alpha test
if (material.needAlphaTesting() && material.getAlphaTestTexture()) {
if (material.needAlphaTestingForMesh(mesh) && material.getAlphaTestTexture()) {
defines.push("#define ALPHATEST");
defines.push(`#define ALPHATEST_UV${material.getAlphaTestTexture().coordinatesIndex + 1}`);
needUv = true;
Expand Down Expand Up @@ -1045,7 +1045,7 @@ export class GeometryBufferRenderer {
material._preBind(drawWrapper, sideOrientation);

// Alpha test
if (material.needAlphaTesting()) {
if (material.needAlphaTestingForMesh(effectiveMesh)) {
const alphaTexture = material.getAlphaTestTexture();
if (alphaTexture) {
effect.setTexture("diffuseSampler", alphaTexture);
Expand Down
4 changes: 2 additions & 2 deletions packages/dev/core/src/Rendering/outlineRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ export class OutlineRenderer implements ISceneComponent {
}

// Alpha test
if (material && material.needAlphaTesting()) {
if (material && material.needAlphaTestingForMesh(effectiveMesh)) {
const alphaTexture = material.getAlphaTestTexture();
if (alphaTexture) {
effect.setTexture("diffuseSampler", alphaTexture);
Expand Down Expand Up @@ -288,7 +288,7 @@ export class OutlineRenderer implements ISceneComponent {
const scene = mesh.getScene();

// Alpha test
if (material.needAlphaTesting()) {
if (material.needAlphaTestingForMesh(mesh)) {
defines.push("#define ALPHATEST");
if (mesh.isVerticesDataPresent(VertexBuffer.UVKind)) {
attribs.push(VertexBuffer.UVKind);
Expand Down
Loading

0 comments on commit add318a

Please sign in to comment.