瀏覽代碼

Move transparencyMode and alpha related functions to base Material

Popov72 5 年之前
父節點
當前提交
02ea71b146
共有 4 個文件被更改,包括 127 次插入67 次删除
  1. 5 53
      src/Materials/PBR/pbrBaseMaterial.ts
  2. 92 10
      src/Materials/material.ts
  3. 18 3
      src/Materials/standardMaterial.ts
  4. 12 1
      src/Shaders/default.fragment.fx

+ 5 - 53
src/Materials/PBR/pbrBaseMaterial.ts

@@ -269,23 +269,23 @@ export abstract class PBRBaseMaterial extends PushMaterial {
     /**
      * PBRMaterialTransparencyMode: No transparency mode, Alpha channel is not use.
      */
-    public static readonly PBRMATERIAL_OPAQUE = 0;
+    public static readonly PBRMATERIAL_OPAQUE = Material.MATERIAL_OPAQUE;
 
     /**
      * PBRMaterialTransparencyMode: Alpha Test mode, pixel are discarded below a certain threshold defined by the alpha cutoff value.
      */
-    public static readonly PBRMATERIAL_ALPHATEST = 1;
+    public static readonly PBRMATERIAL_ALPHATEST = Material.MATERIAL_ALPHATEST;
 
     /**
      * PBRMaterialTransparencyMode: Pixels are blended (according to the alpha mode) with the already drawn pixels in the current frame buffer.
      */
-    public static readonly PBRMATERIAL_ALPHABLEND = 2;
+    public static readonly PBRMATERIAL_ALPHABLEND = Material.MATERIAL_ALPHABLEND;
 
     /**
      * PBRMaterialTransparencyMode: Pixels are blended (according to the alpha mode) with the already drawn pixels in the current frame buffer.
      * They are also discarded below the alpha cutoff threshold to improve performances.
      */
-    public static readonly PBRMATERIAL_ALPHATESTANDBLEND = 3;
+    public static readonly PBRMATERIAL_ALPHATESTANDBLEND = Material.MATERIAL_ALPHATESTANDBLEND;
 
     /**
      * Defines the default value of how much AO map is occluding the analytical lights
@@ -608,11 +608,6 @@ export abstract class PBRBaseMaterial extends PushMaterial {
     protected _useLinearAlphaFresnel = false;
 
     /**
-     * The transparency mode of the material.
-     */
-    protected _transparencyMode: Nullable<number> = null;
-
-    /**
      * Specifies the environment BRDF texture used to comput the scale and offset roughness values
      * from cos thetav and roughness:
      * http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf
@@ -818,40 +813,9 @@ export abstract class PBRBaseMaterial extends PushMaterial {
     }
 
     /**
-     * Gets the current transparency mode.
-     */
-    @serialize()
-    public get transparencyMode(): Nullable<number> {
-        return this._transparencyMode;
-    }
-
-    /**
-     * Sets the transparency mode of the material.
-     *
-     * | Value | Type                                | Description |
-     * | ----- | ----------------------------------- | ----------- |
-     * | 0     | OPAQUE                              |             |
-     * | 1     | ALPHATEST                           |             |
-     * | 2     | ALPHABLEND                          |             |
-     * | 3     | ALPHATESTANDBLEND                   |             |
-     *
-     */
-    public set transparencyMode(value: Nullable<number>) {
-        if (this._transparencyMode === value) {
-            return;
-        }
-
-        this._transparencyMode = value;
-
-        this._forceAlphaTest = (value === PBRBaseMaterial.PBRMATERIAL_ALPHATESTANDBLEND);
-
-        this._markAllSubMeshesAsTexturesAndMiscDirty();
-    }
-
-    /**
      * Returns true if alpha blending should be disabled.
      */
-    private get _disableAlphaBlending(): boolean {
+    protected get _disableAlphaBlending(): boolean {
         return (this.subSurface.disableAlphaBlending ||
             this._transparencyMode === PBRBaseMaterial.PBRMATERIAL_OPAQUE ||
             this._transparencyMode === PBRBaseMaterial.PBRMATERIAL_ALPHATEST);
@@ -869,18 +833,6 @@ export abstract class PBRBaseMaterial extends PushMaterial {
     }
 
     /**
-     * Specifies if the mesh will require alpha blending.
-     * @param mesh - BJS mesh.
-     */
-    public needAlphaBlendingForMesh(mesh: AbstractMesh): boolean {
-        if (this._disableAlphaBlending && mesh.visibility >= 1.0) {
-            return false;
-        }
-
-        return super.needAlphaBlendingForMesh(mesh);
-    }
-
-    /**
      * Specifies whether or not this material should be rendered in alpha test mode.
      */
     public needAlphaTesting(): boolean {

+ 92 - 10
src/Materials/material.ts

@@ -123,6 +123,27 @@ export class Material implements IAnimatable {
     public static readonly AllDirtyFlag = Constants.MATERIAL_AllDirtyFlag;
 
     /**
+     * MaterialTransparencyMode: No transparency mode, Alpha channel is not use.
+     */
+    public static readonly MATERIAL_OPAQUE = 0;
+
+    /**
+     * MaterialTransparencyMode: Alpha Test mode, pixel are discarded below a certain threshold defined by the alpha cutoff value.
+     */
+    public static readonly MATERIAL_ALPHATEST = 1;
+
+    /**
+     * MaterialTransparencyMode: Pixels are blended (according to the alpha mode) with the already drawn pixels in the current frame buffer.
+     */
+    public static readonly MATERIAL_ALPHABLEND = 2;
+
+    /**
+     * MaterialTransparencyMode: Pixels are blended (according to the alpha mode) with the already drawn pixels in the current frame buffer.
+     * They are also discarded below the alpha cutoff threshold to improve performances.
+     */
+    public static readonly MATERIAL_ALPHATESTANDBLEND = 3;
+
+    /**
      * The ID of the material
      */
     @serialize()
@@ -668,10 +689,63 @@ export class Material implements IAnimatable {
     }
 
     /**
-     * Specifies if the material will require alpha blending
+     * 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.
+     */
+    protected _transparencyMode: Nullable<number> = null;
+
+    /**
+     * Gets the current transparency mode.
+     */
+    @serialize()
+    public get transparencyMode(): Nullable<number> {
+        return this._transparencyMode;
+    }
+
+    /**
+     * Sets the transparency mode of the material.
+     *
+     * | Value | Type                                | Description |
+     * | ----- | ----------------------------------- | ----------- |
+     * | 0     | OPAQUE                              |             |
+     * | 1     | ALPHATEST                           |             |
+     * | 2     | ALPHABLEND                          |             |
+     * | 3     | ALPHATESTANDBLEND                   |             |
+     *
+     */
+    public set transparencyMode(value: Nullable<number>) {
+        if (this._transparencyMode === value) {
+            return;
+        }
+
+        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);
+    }
+
+    /**
+     * 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;
+        }
+
         return (this.alpha < 1.0);
     }
 
@@ -681,18 +755,34 @@ export class Material implements IAnimatable {
      * @returns a boolean specifying if alpha blending is needed for the mesh
      */
     public needAlphaBlendingForMesh(mesh: AbstractMesh): boolean {
+        if (this._disableAlphaBlending && mesh.visibility >= 1.0) {
+            return false;
+        }
+
         return this.needAlphaBlending() || (mesh.visibility < 1.0) || mesh.hasVertexAlpha;
     }
 
     /**
-     * Specifies if this material should be rendered in alpha test mode
+     * 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;
+        }
+
         return false;
     }
 
     /**
+     * Specifies if material alpha testing should be turned on for the mesh
+     * @param mesh defines the mesh to check
+     */
+    protected _shouldTurnAlphaTestOn(mesh: AbstractMesh): boolean {
+        return (!this.needAlphaBlendingForMesh(mesh) && this.needAlphaTesting());
+    }
+
+    /**
      * Gets the texture used for the alpha test
      * @returns the texture to use for alpha testing
      */
@@ -794,14 +884,6 @@ export class Material implements IAnimatable {
     }
 
     /**
-     * Specifies if material alpha testing should be turned on for the mesh
-     * @param mesh defines the mesh to check
-     */
-    protected _shouldTurnAlphaTestOn(mesh: AbstractMesh): boolean {
-        return (!this.needAlphaBlendingForMesh(mesh) && this.needAlphaTesting());
-    }
-
-    /**
      * Processes to execute after binding the material to a mesh
      * @param mesh defines the rendered mesh
      */

+ 18 - 3
src/Materials/standardMaterial.ts

@@ -15,6 +15,7 @@ import { Mesh } from "../Meshes/mesh";
 import { ImageProcessingConfiguration, IImageProcessingConfigurationDefines } from "./imageProcessingConfiguration";
 import { ColorCurves } from "./colorCurves";
 import { FresnelParameters } from "./fresnelParameters";
+import { Material } from "../Materials/material";
 import { MaterialDefines } from "../Materials/materialDefines";
 import { PushMaterial } from "./pushMaterial";
 import { MaterialHelper } from "./materialHelper";
@@ -114,6 +115,8 @@ export class StandardMaterialDefines extends MaterialDefines implements IImagePr
     public NUM_MORPH_INFLUENCERS = 0;
     public NONUNIFORMSCALING = false; // https://playground.babylonjs.com#V6DWIH
     public PREMULTIPLYALPHA = false; // https://playground.babylonjs.com#LNVJJ7
+    public ALPHATEST_AFTERALLALPHACOMPUTATIONS = false;
+    public ALPHABLEND = true;
 
     public IMAGEPROCESSING = false;
     public VIGNETTE = false;
@@ -744,6 +747,10 @@ export class StandardMaterial extends PushMaterial {
      * @returns a boolean specifying if alpha blending is needed
      */
     public needAlphaBlending(): boolean {
+        if (this._disableAlphaBlending) {
+            return false;
+        }
+
         return (this.alpha < 1.0) || (this._opacityTexture != null) || this._shouldUseAlphaFromDiffuseTexture() || this._opacityFresnelParameters && this._opacityFresnelParameters.isEnabled;
     }
 
@@ -752,11 +759,15 @@ export class StandardMaterial extends PushMaterial {
      * @returns a boolean specifying if an alpha test is needed.
      */
     public needAlphaTesting(): boolean {
-        return this._diffuseTexture != null && this._diffuseTexture.hasAlpha;
+        if (this._forceAlphaTest) {
+            return true;
+        }
+
+        return this._diffuseTexture != null && this._diffuseTexture.hasAlpha && (this._transparencyMode == null || this._transparencyMode === Material.MATERIAL_ALPHATEST);
     }
 
     protected _shouldUseAlphaFromDiffuseTexture(): boolean {
-        return this._diffuseTexture != null && this._diffuseTexture.hasAlpha && this._useAlphaFromDiffuseTexture;
+        return this._diffuseTexture != null && this._diffuseTexture.hasAlpha && this._useAlphaFromDiffuseTexture && this._transparencyMode !== Material.MATERIAL_OPAQUE;
     }
 
     /**
@@ -971,6 +982,10 @@ export class StandardMaterial extends PushMaterial {
             defines.SPECULAROVERALPHA = this._useSpecularOverAlpha;
 
             defines.PREMULTIPLYALPHA = (this.alphaMode === Constants.ALPHA_PREMULTIPLIED || this.alphaMode === Constants.ALPHA_PREMULTIPLIED_PORTERDUFF);
+
+            defines.ALPHATEST_AFTERALLALPHACOMPUTATIONS = this.transparencyMode !== null;
+
+            defines.ALPHABLEND = this.transparencyMode === null || this.needAlphaBlendingForMesh(mesh); // check on null for backward compatibility
         }
 
         if (defines._areImageProcessingDirty && this._imageProcessingConfiguration) {
@@ -1012,7 +1027,7 @@ export class StandardMaterial extends PushMaterial {
         }
 
         // Misc.
-        MaterialHelper.PrepareDefinesForMisc(mesh, scene, this._useLogarithmicDepth, this.pointsCloud, this.fogEnabled, this._shouldTurnAlphaTestOn(mesh), defines);
+        MaterialHelper.PrepareDefinesForMisc(mesh, scene, this._useLogarithmicDepth, this.pointsCloud, this.fogEnabled, this._shouldTurnAlphaTestOn(mesh) || this._forceAlphaTest, defines);
 
         // Attribs
         MaterialHelper.PrepareDefinesForAttributes(mesh, defines, true, true, true);

+ 12 - 1
src/Shaders/default.fragment.fx

@@ -195,7 +195,7 @@ void main(void) {
 #ifdef DIFFUSE
 	baseColor = texture2D(diffuseSampler, vDiffuseUV + uvOffset);
 
-	#ifdef ALPHATEST
+	#if defined(ALPHATEST) && !defined(ALPHATEST_AFTERALLALPHACOMPUTATIONS)
 		if (baseColor.a < alphaCutOff)
 			discard;
 	#endif
@@ -363,6 +363,17 @@ vec3 reflectionColor = vec3(0., 0., 0.);
 	alpha += opacityParts.x * (1.0 - opacityFresnelTerm) + opacityFresnelTerm * opacityParts.y;
 #endif
 
+#ifdef ALPHATEST
+    #ifdef ALPHATEST_AFTERALLALPHACOMPUTATIONS
+        if (alpha < alphaCutOff)
+            discard;
+    #endif
+    #ifndef ALPHABLEND
+        // Prevent to blend with the canvas.
+        alpha = 1.0;
+    #endif
+#endif
+
 	// Emissive
 	vec3 emissiveColor = vEmissiveColor;
 #ifdef EMISSIVE