Преглед изворни кода

Merge pull request #7274 from sebavan/master

Thin Engine Refinment
David Catuhe пре 5 година
родитељ
комит
f989c3b71f

+ 162 - 0
src/Engines/Extensions/engine.alpha.ts

@@ -0,0 +1,162 @@
+import { ThinEngine } from "../../Engines/thinEngine";
+import { Constants } from '../constants';
+
+declare module "../../Engines/thinEngine" {
+    export interface ThinEngine {
+        /**
+         * Sets alpha constants used by some alpha blending modes
+         * @param r defines the red component
+         * @param g defines the green component
+         * @param b defines the blue component
+         * @param a defines the alpha component
+         */
+        setAlphaConstants(r: number, g: number, b: number, a: number): void;
+
+        /**
+         * Sets the current alpha mode
+         * @param mode defines the mode to use (one of the Engine.ALPHA_XXX)
+         * @param noDepthWriteChange defines if depth writing state should remains unchanged (false by default)
+         * @see http://doc.babylonjs.com/resources/transparency_and_how_meshes_are_rendered
+         */
+        setAlphaMode(mode: number, noDepthWriteChange?: boolean): void;
+
+        /**
+         * Gets the current alpha mode
+         * @see http://doc.babylonjs.com/resources/transparency_and_how_meshes_are_rendered
+         * @returns the current alpha mode
+         */
+        getAlphaMode(): number;
+
+        /**
+         * Sets the current alpha equation
+         * @param equation defines the equation to use (one of the Engine.ALPHA_EQUATION_XXX)
+         */
+        setAlphaEquation(equation: number): void;
+
+        /**
+         * Gets the current alpha equation.
+         * @returns the current alpha equation
+         */
+        getAlphaEquation(): number;
+    }
+}
+
+ThinEngine.prototype.setAlphaConstants = function(r: number, g: number, b: number, a: number) {
+    this._alphaState.setAlphaBlendConstants(r, g, b, a);
+};
+
+ThinEngine.prototype.setAlphaMode = function(mode: number, noDepthWriteChange: boolean = false): void {
+    if (this._alphaMode === mode) {
+        return;
+    }
+
+    switch (mode) {
+        case Constants.ALPHA_DISABLE:
+            this._alphaState.alphaBlend = false;
+            break;
+        case Constants.ALPHA_PREMULTIPLIED:
+            this._alphaState.setAlphaBlendFunctionParameters(this._gl.ONE, this._gl.ONE_MINUS_SRC_ALPHA, this._gl.ONE, this._gl.ONE);
+            this._alphaState.alphaBlend = true;
+            break;
+        case Constants.ALPHA_PREMULTIPLIED_PORTERDUFF:
+            this._alphaState.setAlphaBlendFunctionParameters(this._gl.ONE, this._gl.ONE_MINUS_SRC_ALPHA, this._gl.ONE, this._gl.ONE_MINUS_SRC_ALPHA);
+            this._alphaState.alphaBlend = true;
+            break;
+        case Constants.ALPHA_COMBINE:
+            this._alphaState.setAlphaBlendFunctionParameters(this._gl.SRC_ALPHA, this._gl.ONE_MINUS_SRC_ALPHA, this._gl.ONE, this._gl.ONE);
+            this._alphaState.alphaBlend = true;
+            break;
+        case Constants.ALPHA_ONEONE:
+            this._alphaState.setAlphaBlendFunctionParameters(this._gl.ONE, this._gl.ONE, this._gl.ZERO, this._gl.ONE);
+            this._alphaState.alphaBlend = true;
+            break;
+        case Constants.ALPHA_ADD:
+            this._alphaState.setAlphaBlendFunctionParameters(this._gl.SRC_ALPHA, this._gl.ONE, this._gl.ZERO, this._gl.ONE);
+            this._alphaState.alphaBlend = true;
+            break;
+        case Constants.ALPHA_SUBTRACT:
+            this._alphaState.setAlphaBlendFunctionParameters(this._gl.ZERO, this._gl.ONE_MINUS_SRC_COLOR, this._gl.ONE, this._gl.ONE);
+            this._alphaState.alphaBlend = true;
+            break;
+        case Constants.ALPHA_MULTIPLY:
+            this._alphaState.setAlphaBlendFunctionParameters(this._gl.DST_COLOR, this._gl.ZERO, this._gl.ONE, this._gl.ONE);
+            this._alphaState.alphaBlend = true;
+            break;
+        case Constants.ALPHA_MAXIMIZED:
+            this._alphaState.setAlphaBlendFunctionParameters(this._gl.SRC_ALPHA, this._gl.ONE_MINUS_SRC_COLOR, this._gl.ONE, this._gl.ONE);
+            this._alphaState.alphaBlend = true;
+            break;
+        case Constants.ALPHA_INTERPOLATE:
+            this._alphaState.setAlphaBlendFunctionParameters(this._gl.CONSTANT_COLOR, this._gl.ONE_MINUS_CONSTANT_COLOR, this._gl.CONSTANT_ALPHA, this._gl.ONE_MINUS_CONSTANT_ALPHA);
+            this._alphaState.alphaBlend = true;
+            break;
+        case Constants.ALPHA_SCREENMODE:
+            this._alphaState.setAlphaBlendFunctionParameters(this._gl.ONE, this._gl.ONE_MINUS_SRC_COLOR, this._gl.ONE, this._gl.ONE_MINUS_SRC_ALPHA);
+            this._alphaState.alphaBlend = true;
+            break;
+        case Constants.ALPHA_ONEONE_ONEONE:
+            this._alphaState.setAlphaBlendFunctionParameters(this._gl.ONE, this._gl.ONE, this._gl.ONE, this._gl.ONE);
+            this._alphaState.alphaBlend = true;
+            break;
+        case Constants.ALPHA_ALPHATOCOLOR:
+            this._alphaState.setAlphaBlendFunctionParameters(this._gl.DST_ALPHA, this._gl.ONE, this._gl.ZERO, this._gl.ZERO);
+            this._alphaState.alphaBlend = true;
+            break;
+        case Constants.ALPHA_REVERSEONEMINUS:
+            this._alphaState.setAlphaBlendFunctionParameters(this._gl.ONE_MINUS_DST_COLOR, this._gl.ONE_MINUS_SRC_COLOR, this._gl.ONE_MINUS_DST_ALPHA, this._gl.ONE_MINUS_SRC_ALPHA);
+            this._alphaState.alphaBlend = true;
+            break;
+        case Constants.ALPHA_SRC_DSTONEMINUSSRCALPHA:
+            this._alphaState.setAlphaBlendFunctionParameters(this._gl.ONE, this._gl.ONE_MINUS_SRC_ALPHA, this._gl.ONE, this._gl.ONE_MINUS_SRC_ALPHA);
+            this._alphaState.alphaBlend = true;
+            break;
+        case Constants.ALPHA_ONEONE_ONEZERO:
+            this._alphaState.setAlphaBlendFunctionParameters(this._gl.ONE, this._gl.ONE, this._gl.ONE, this._gl.ZERO);
+            this._alphaState.alphaBlend = true;
+            break;
+        case Constants.ALPHA_EXCLUSION:
+            this._alphaState.setAlphaBlendFunctionParameters(this._gl.ONE_MINUS_DST_COLOR, this._gl.ONE_MINUS_SRC_COLOR, this._gl.ZERO, this._gl.ONE);
+            this._alphaState.alphaBlend = true;
+            break;
+    }
+    if (!noDepthWriteChange) {
+        this.depthCullingState.depthMask = (mode === Constants.ALPHA_DISABLE);
+    }
+    this._alphaMode = mode;
+};
+
+ThinEngine.prototype.getAlphaMode = function(): number {
+    return this._alphaMode;
+};
+
+ThinEngine.prototype.setAlphaEquation = function(equation: number): void {
+    if (this._alphaEquation === equation) {
+        return;
+    }
+
+    switch (equation) {
+        case Constants.ALPHA_EQUATION_ADD:
+            this._alphaState.setAlphaEquationParameters(this._gl.FUNC_ADD, this._gl.FUNC_ADD);
+            break;
+        case Constants.ALPHA_EQUATION_SUBSTRACT:
+            this._alphaState.setAlphaEquationParameters(this._gl.FUNC_SUBTRACT, this._gl.FUNC_SUBTRACT);
+            break;
+        case Constants.ALPHA_EQUATION_REVERSE_SUBTRACT:
+            this._alphaState.setAlphaEquationParameters(this._gl.FUNC_REVERSE_SUBTRACT, this._gl.FUNC_REVERSE_SUBTRACT);
+            break;
+        case Constants.ALPHA_EQUATION_MAX:
+            this._alphaState.setAlphaEquationParameters(this._gl.MAX, this._gl.MAX);
+            break;
+        case Constants.ALPHA_EQUATION_MIN:
+            this._alphaState.setAlphaEquationParameters(this._gl.MIN, this._gl.MIN);
+            break;
+        case Constants.ALPHA_EQUATION_DARKEN:
+            this._alphaState.setAlphaEquationParameters(this._gl.MIN, this._gl.FUNC_ADD);
+            break;
+    }
+    this._alphaEquation = equation;
+};
+
+ThinEngine.prototype.getAlphaEquation = function() {
+    return this._alphaEquation;
+};

+ 2 - 2
src/Engines/Extensions/engine.renderTarget.ts

@@ -34,8 +34,8 @@ ThinEngine.prototype.createRenderTargetTexture = function(this: ThinEngine, size
 
 
     if (options !== undefined && typeof options === "object") {
     if (options !== undefined && typeof options === "object") {
         fullOptions.generateMipMaps = options.generateMipMaps;
         fullOptions.generateMipMaps = options.generateMipMaps;
-        fullOptions.generateDepthBuffer = options.generateDepthBuffer === undefined ? true : options.generateDepthBuffer;
-        fullOptions.generateStencilBuffer = fullOptions.generateDepthBuffer && options.generateStencilBuffer;
+        fullOptions.generateDepthBuffer = !!options.generateDepthBuffer;
+        fullOptions.generateStencilBuffer = !!options.generateStencilBuffer;
         fullOptions.type = options.type === undefined ? Constants.TEXTURETYPE_UNSIGNED_INT : options.type;
         fullOptions.type = options.type === undefined ? Constants.TEXTURETYPE_UNSIGNED_INT : options.type;
         fullOptions.samplingMode = options.samplingMode === undefined ? Constants.TEXTURE_TRILINEAR_SAMPLINGMODE : options.samplingMode;
         fullOptions.samplingMode = options.samplingMode === undefined ? Constants.TEXTURE_TRILINEAR_SAMPLINGMODE : options.samplingMode;
         fullOptions.format = options.format === undefined ? Constants.TEXTUREFORMAT_RGBA : options.format;
         fullOptions.format = options.format === undefined ? Constants.TEXTUREFORMAT_RGBA : options.format;

+ 1 - 0
src/Engines/Extensions/index.ts

@@ -1,3 +1,4 @@
+export * from "./engine.alpha";
 export * from "./engine.occlusionQuery";
 export * from "./engine.occlusionQuery";
 export * from "./engine.transformFeedback";
 export * from "./engine.transformFeedback";
 export * from "./engine.multiview";
 export * from "./engine.multiview";

+ 20 - 15
src/Engines/constants.ts

@@ -2,56 +2,61 @@
 export class Constants {
 export class Constants {
     /** Defines that alpha blending is disabled */
     /** Defines that alpha blending is disabled */
     public static readonly ALPHA_DISABLE = 0;
     public static readonly ALPHA_DISABLE = 0;
-    /** Defines that alpha blending to SRC ALPHA * SRC + DEST */
+    /** Defines that alpha blending is SRC ALPHA * SRC + DEST */
     public static readonly ALPHA_ADD = 1;
     public static readonly ALPHA_ADD = 1;
-    /** Defines that alpha blending to SRC ALPHA * SRC + (1 - SRC ALPHA) * DEST */
+    /** Defines that alpha blending is SRC ALPHA * SRC + (1 - SRC ALPHA) * DEST */
     public static readonly ALPHA_COMBINE = 2;
     public static readonly ALPHA_COMBINE = 2;
-    /** Defines that alpha blending to DEST - SRC * DEST */
+    /** Defines that alpha blending is DEST - SRC * DEST */
     public static readonly ALPHA_SUBTRACT = 3;
     public static readonly ALPHA_SUBTRACT = 3;
-    /** Defines that alpha blending to SRC * DEST */
+    /** Defines that alpha blending is SRC * DEST */
     public static readonly ALPHA_MULTIPLY = 4;
     public static readonly ALPHA_MULTIPLY = 4;
-    /** Defines that alpha blending to SRC ALPHA * SRC + (1 - SRC) * DEST */
+    /** Defines that alpha blending is SRC ALPHA * SRC + (1 - SRC) * DEST */
     public static readonly ALPHA_MAXIMIZED = 5;
     public static readonly ALPHA_MAXIMIZED = 5;
-    /** Defines that alpha blending to SRC + DEST */
+    /** Defines that alpha blending is SRC + DEST */
     public static readonly ALPHA_ONEONE = 6;
     public static readonly ALPHA_ONEONE = 6;
-    /** Defines that alpha blending to SRC + (1 - SRC ALPHA) * DEST */
+    /** Defines that alpha blending is SRC + (1 - SRC ALPHA) * DEST */
     public static readonly ALPHA_PREMULTIPLIED = 7;
     public static readonly ALPHA_PREMULTIPLIED = 7;
     /**
     /**
-     * Defines that alpha blending to SRC + (1 - SRC ALPHA) * DEST
+     * Defines that alpha blending is SRC + (1 - SRC ALPHA) * DEST
      * Alpha will be set to (1 - SRC ALPHA) * DEST ALPHA
      * Alpha will be set to (1 - SRC ALPHA) * DEST ALPHA
      */
      */
     public static readonly ALPHA_PREMULTIPLIED_PORTERDUFF = 8;
     public static readonly ALPHA_PREMULTIPLIED_PORTERDUFF = 8;
-    /** Defines that alpha blending to CST * SRC + (1 - CST) * DEST */
+    /** Defines that alpha blending is CST * SRC + (1 - CST) * DEST */
     public static readonly ALPHA_INTERPOLATE = 9;
     public static readonly ALPHA_INTERPOLATE = 9;
     /**
     /**
-     * Defines that alpha blending to SRC + (1 - SRC) * DEST
+     * Defines that alpha blending is SRC + (1 - SRC) * DEST
      * Alpha will be set to SRC ALPHA + (1 - SRC ALPHA) * DEST ALPHA
      * Alpha will be set to SRC ALPHA + (1 - SRC ALPHA) * DEST ALPHA
      */
      */
     public static readonly ALPHA_SCREENMODE = 10;
     public static readonly ALPHA_SCREENMODE = 10;
     /**
     /**
-     * Defines that alpha blending to SRC + DST
+     * Defines that alpha blending is SRC + DST
      * Alpha will be set to SRC ALPHA + DST ALPHA
      * Alpha will be set to SRC ALPHA + DST ALPHA
      */
      */
     public static readonly ALPHA_ONEONE_ONEONE = 11;
     public static readonly ALPHA_ONEONE_ONEONE = 11;
     /**
     /**
-     * Defines that alpha blending to SRC * DST ALPHA + DST
+     * Defines that alpha blending is SRC * DST ALPHA + DST
      * Alpha will be set to 0
      * Alpha will be set to 0
      */
      */
     public static readonly ALPHA_ALPHATOCOLOR = 12;
     public static readonly ALPHA_ALPHATOCOLOR = 12;
     /**
     /**
-     * Defines that alpha blending to SRC * (1 - DST) + DST * (1 - SRC)
+     * Defines that alpha blending is SRC * (1 - DST) + DST * (1 - SRC)
      */
      */
     public static readonly ALPHA_REVERSEONEMINUS = 13;
     public static readonly ALPHA_REVERSEONEMINUS = 13;
     /**
     /**
-     * Defines that alpha blending to SRC + DST * (1 - SRC ALPHA)
+     * Defines that alpha blending is SRC + DST * (1 - SRC ALPHA)
      * Alpha will be set to SRC ALPHA + DST ALPHA * (1 - SRC ALPHA)
      * Alpha will be set to SRC ALPHA + DST ALPHA * (1 - SRC ALPHA)
      */
      */
     public static readonly ALPHA_SRC_DSTONEMINUSSRCALPHA = 14;
     public static readonly ALPHA_SRC_DSTONEMINUSSRCALPHA = 14;
     /**
     /**
-     * Defines that alpha blending to SRC + DST
+     * Defines that alpha blending is SRC + DST
      * Alpha will be set to SRC ALPHA
      * Alpha will be set to SRC ALPHA
      */
      */
     public static readonly ALPHA_ONEONE_ONEZERO = 15;
     public static readonly ALPHA_ONEONE_ONEZERO = 15;
+    /**
+     * Defines that alpha blending is SRC * (1 - DST) + DST * (1 - SRC)
+     * Alpha will be set to DST ALPHA
+     */
+    public static readonly ALPHA_EXCLUSION = 16;
 
 
     /** Defines that alpha blending equation a SUM */
     /** Defines that alpha blending equation a SUM */
     public static readonly ALPHA_EQUATION_ADD = 0;
     public static readonly ALPHA_EQUATION_ADD = 0;

+ 2 - 164
src/Engines/engine.ts

@@ -22,6 +22,8 @@ import { PerfCounter } from '../Misc/perfCounter';
 import { WebGLDataBuffer } from '../Meshes/WebGL/webGLDataBuffer';
 import { WebGLDataBuffer } from '../Meshes/WebGL/webGLDataBuffer';
 import { Logger } from '../Misc/logger';
 import { Logger } from '../Misc/logger';
 
 
+import "./Extensions/engine.alpha";
+
 declare type Material = import("../Materials/material").Material;
 declare type Material = import("../Materials/material").Material;
 declare type PostProcess = import("../PostProcesses/postProcess").PostProcess;
 declare type PostProcess = import("../PostProcesses/postProcess").PostProcess;
 
 
@@ -419,11 +421,6 @@ export class Engine extends ThinEngine {
     private _dummyFramebuffer: WebGLFramebuffer;
     private _dummyFramebuffer: WebGLFramebuffer;
     private _rescalePostProcess: PostProcess;
     private _rescalePostProcess: PostProcess;
 
 
-    /** @hidden */
-    protected _alphaMode = Constants.ALPHA_ADD;
-    /** @hidden */
-    protected _alphaEquation = Constants.ALPHA_DISABLE;
-
     // Deterministic lockstepMaxSteps
     // Deterministic lockstepMaxSteps
     private _deterministicLockstep: boolean = false;
     private _deterministicLockstep: boolean = false;
     private _lockstepMaxSteps: number = 4;
     private _lockstepMaxSteps: number = 4;
@@ -753,165 +750,6 @@ export class Engine extends ThinEngine {
     }
     }
 
 
     /**
     /**
-     * Enable or disable color writing
-     * @param enable defines the state to set
-     */
-    public setColorWrite(enable: boolean): void {
-        this._gl.colorMask(enable, enable, enable, enable);
-        this._colorWrite = enable;
-    }
-
-    /**
-     * Gets a boolean indicating if color writing is enabled
-     * @returns the current color writing state
-     */
-    public getColorWrite(): boolean {
-        return this._colorWrite;
-    }
-
-    /**
-     * Sets alpha constants used by some alpha blending modes
-     * @param r defines the red component
-     * @param g defines the green component
-     * @param b defines the blue component
-     * @param a defines the alpha component
-     */
-    public setAlphaConstants(r: number, g: number, b: number, a: number) {
-        this._alphaState.setAlphaBlendConstants(r, g, b, a);
-    }
-
-    /**
-     * Sets the current alpha mode
-     * @param mode defines the mode to use (one of the Engine.ALPHA_XXX)
-     * @param noDepthWriteChange defines if depth writing state should remains unchanged (false by default)
-     * @see http://doc.babylonjs.com/resources/transparency_and_how_meshes_are_rendered
-     */
-    public setAlphaMode(mode: number, noDepthWriteChange: boolean = false): void {
-        if (this._alphaMode === mode) {
-            return;
-        }
-
-        switch (mode) {
-            case Constants.ALPHA_DISABLE:
-                this._alphaState.alphaBlend = false;
-                break;
-            case Constants.ALPHA_PREMULTIPLIED:
-                this._alphaState.setAlphaBlendFunctionParameters(this._gl.ONE, this._gl.ONE_MINUS_SRC_ALPHA, this._gl.ONE, this._gl.ONE);
-                this._alphaState.alphaBlend = true;
-                break;
-            case Constants.ALPHA_PREMULTIPLIED_PORTERDUFF:
-                this._alphaState.setAlphaBlendFunctionParameters(this._gl.ONE, this._gl.ONE_MINUS_SRC_ALPHA, this._gl.ONE, this._gl.ONE_MINUS_SRC_ALPHA);
-                this._alphaState.alphaBlend = true;
-                break;
-            case Constants.ALPHA_COMBINE:
-                this._alphaState.setAlphaBlendFunctionParameters(this._gl.SRC_ALPHA, this._gl.ONE_MINUS_SRC_ALPHA, this._gl.ONE, this._gl.ONE);
-                this._alphaState.alphaBlend = true;
-                break;
-            case Constants.ALPHA_ONEONE:
-                this._alphaState.setAlphaBlendFunctionParameters(this._gl.ONE, this._gl.ONE, this._gl.ZERO, this._gl.ONE);
-                this._alphaState.alphaBlend = true;
-                break;
-            case Constants.ALPHA_ADD:
-                this._alphaState.setAlphaBlendFunctionParameters(this._gl.SRC_ALPHA, this._gl.ONE, this._gl.ZERO, this._gl.ONE);
-                this._alphaState.alphaBlend = true;
-                break;
-            case Constants.ALPHA_SUBTRACT:
-                this._alphaState.setAlphaBlendFunctionParameters(this._gl.ZERO, this._gl.ONE_MINUS_SRC_COLOR, this._gl.ONE, this._gl.ONE);
-                this._alphaState.alphaBlend = true;
-                break;
-            case Constants.ALPHA_MULTIPLY:
-                this._alphaState.setAlphaBlendFunctionParameters(this._gl.DST_COLOR, this._gl.ZERO, this._gl.ONE, this._gl.ONE);
-                this._alphaState.alphaBlend = true;
-                break;
-            case Constants.ALPHA_MAXIMIZED:
-                this._alphaState.setAlphaBlendFunctionParameters(this._gl.SRC_ALPHA, this._gl.ONE_MINUS_SRC_COLOR, this._gl.ONE, this._gl.ONE);
-                this._alphaState.alphaBlend = true;
-                break;
-            case Constants.ALPHA_INTERPOLATE:
-                this._alphaState.setAlphaBlendFunctionParameters(this._gl.CONSTANT_COLOR, this._gl.ONE_MINUS_CONSTANT_COLOR, this._gl.CONSTANT_ALPHA, this._gl.ONE_MINUS_CONSTANT_ALPHA);
-                this._alphaState.alphaBlend = true;
-                break;
-            case Constants.ALPHA_SCREENMODE:
-                this._alphaState.setAlphaBlendFunctionParameters(this._gl.ONE, this._gl.ONE_MINUS_SRC_COLOR, this._gl.ONE, this._gl.ONE_MINUS_SRC_ALPHA);
-                this._alphaState.alphaBlend = true;
-                break;
-            case Constants.ALPHA_ONEONE_ONEONE:
-                this._alphaState.setAlphaBlendFunctionParameters(this._gl.ONE, this._gl.ONE, this._gl.ONE, this._gl.ONE);
-                this._alphaState.alphaBlend = true;
-                break;
-            case Constants.ALPHA_ALPHATOCOLOR:
-                this._alphaState.setAlphaBlendFunctionParameters(this._gl.DST_ALPHA, this._gl.ONE, this._gl.ZERO, this._gl.ZERO);
-                this._alphaState.alphaBlend = true;
-                break;
-            case Constants.ALPHA_REVERSEONEMINUS:
-                this._alphaState.setAlphaBlendFunctionParameters(this._gl.ONE_MINUS_DST_COLOR, this._gl.ONE_MINUS_SRC_COLOR, this._gl.ONE_MINUS_DST_ALPHA, this._gl.ONE_MINUS_SRC_ALPHA);
-                this._alphaState.alphaBlend = true;
-                break;
-            case Constants.ALPHA_SRC_DSTONEMINUSSRCALPHA:
-                this._alphaState.setAlphaBlendFunctionParameters(this._gl.ONE, this._gl.ONE_MINUS_SRC_ALPHA, this._gl.ONE, this._gl.ONE_MINUS_SRC_ALPHA);
-                this._alphaState.alphaBlend = true;
-                break;
-            case Constants.ALPHA_ONEONE_ONEZERO:
-                this._alphaState.setAlphaBlendFunctionParameters(this._gl.ONE, this._gl.ONE, this._gl.ONE, this._gl.ZERO);
-                this._alphaState.alphaBlend = true;
-                break;
-        }
-        if (!noDepthWriteChange) {
-            this.setDepthWrite(mode === Constants.ALPHA_DISABLE);
-        }
-        this._alphaMode = mode;
-    }
-
-    /**
-     * Gets the current alpha mode
-     * @see http://doc.babylonjs.com/resources/transparency_and_how_meshes_are_rendered
-     * @returns the current alpha mode
-     */
-    public getAlphaMode(): number {
-        return this._alphaMode;
-    }
-
-    /**
-     * Sets the current alpha equation
-     * @param equation defines the equation to use (one of the Engine.ALPHA_EQUATION_XXX)
-     */
-    public setAlphaEquation(equation: number): void {
-        if (this._alphaEquation === equation) {
-            return;
-        }
-
-        switch (equation) {
-            case Constants.ALPHA_EQUATION_ADD:
-                this._alphaState.setAlphaEquationParameters(this._gl.FUNC_ADD, this._gl.FUNC_ADD);
-                break;
-            case Constants.ALPHA_EQUATION_SUBSTRACT:
-                this._alphaState.setAlphaEquationParameters(this._gl.FUNC_SUBTRACT, this._gl.FUNC_SUBTRACT);
-                break;
-            case Constants.ALPHA_EQUATION_REVERSE_SUBTRACT:
-                this._alphaState.setAlphaEquationParameters(this._gl.FUNC_REVERSE_SUBTRACT, this._gl.FUNC_REVERSE_SUBTRACT);
-                break;
-            case Constants.ALPHA_EQUATION_MAX:
-                this._alphaState.setAlphaEquationParameters(this._gl.MAX, this._gl.MAX);
-                break;
-            case Constants.ALPHA_EQUATION_MIN:
-                this._alphaState.setAlphaEquationParameters(this._gl.MIN, this._gl.MIN);
-                break;
-            case Constants.ALPHA_EQUATION_DARKEN:
-                this._alphaState.setAlphaEquationParameters(this._gl.MIN, this._gl.FUNC_ADD);
-                break;
-        }
-        this._alphaEquation = equation;
-    }
-
-    /**
-     * Gets the current alpha equation.
-     * @returns the current alpha equation
-     */
-    public getAlphaEquation(): number {
-        return this._alphaEquation;
-    }
-
-    /**
      * Gets a boolean indicating if stencil buffer is enabled
      * Gets a boolean indicating if stencil buffer is enabled
      * @returns the current stencil buffer state
      * @returns the current stencil buffer state
      */
      */

+ 18 - 10
src/Engines/instancingAttributeInfo.ts

@@ -3,9 +3,16 @@
  */
  */
 export interface InstancingAttributeInfo {
 export interface InstancingAttributeInfo {
     /**
     /**
+     * Name of the GLSL attribute
+     * if attribute index is not specified, this is used to retrieve the index from the effect
+     */
+    attributeName: string;
+
+    /**
      * Index/offset of the attribute in the vertex shader
      * Index/offset of the attribute in the vertex shader
+     * if not specified, this will be computes from the name.
      */
      */
-    index: number;
+    index?: number;
 
 
     /**
     /**
      * size of the attribute, 1, 2, 3 or 4
      * size of the attribute, 1, 2, 3 or 4
@@ -13,23 +20,24 @@ export interface InstancingAttributeInfo {
     attributeSize: number;
     attributeSize: number;
 
 
     /**
     /**
-     * type of the attribute, gl.BYTE, gl.UNSIGNED_BYTE, gl.SHORT, gl.UNSIGNED_SHORT, gl.FIXED, gl.FLOAT.
-     * default is FLOAT
+     * Offset of the data in the Vertex Buffer acting as the instancing buffer
      */
      */
-    attributeType: number;
+    offset: number;
 
 
     /**
     /**
-     * normalization of fixed-point data. behavior unclear, use FALSE, default is FALSE
+     * Modifies the rate at which generic vertex attributes advance when rendering multiple instances
+     * default to 1
      */
      */
-    normalized: boolean;
+    divisor?: number;
 
 
     /**
     /**
-     * Offset of the data in the Vertex Buffer acting as the instancing buffer
+     * type of the attribute, gl.BYTE, gl.UNSIGNED_BYTE, gl.SHORT, gl.UNSIGNED_SHORT, gl.FIXED, gl.FLOAT.
+     * default is FLOAT
      */
      */
-    offset: number;
+    attributeType?: number;
 
 
     /**
     /**
-     * Name of the GLSL attribute, for debugging purpose only
+     * normalization of fixed-point data. behavior unclear, use FALSE, default is FALSE
      */
      */
-    attributeName: string;
+    normalized?: boolean;
 }
 }

+ 142 - 50
src/Engines/thinEngine.ts

@@ -283,7 +283,6 @@ export class ThinEngine {
     /** @hidden */
     /** @hidden */
     public _caps: EngineCapabilities;
     public _caps: EngineCapabilities;
     private _isStencilEnable: boolean;
     private _isStencilEnable: boolean;
-    protected _colorWrite = true;
 
 
     private _glVersion: string;
     private _glVersion: string;
     private _glRenderer: string;
     private _glRenderer: string;
@@ -330,11 +329,19 @@ export class ThinEngine {
 
 
     // States
     // States
     /** @hidden */
     /** @hidden */
+    protected _colorWrite = true;
+    /** @hidden */
+    protected _colorWriteChanged = true;
+    /** @hidden */
     protected _depthCullingState = new DepthCullingState();
     protected _depthCullingState = new DepthCullingState();
     /** @hidden */
     /** @hidden */
     protected _stencilState = new StencilState();
     protected _stencilState = new StencilState();
     /** @hidden */
     /** @hidden */
-    protected _alphaState = new AlphaState();
+    public _alphaState = new AlphaState();
+    /** @hidden */
+    public _alphaMode = Constants.ALPHA_ADD;
+    /** @hidden */
+    public _alphaEquation = Constants.ALPHA_DISABLE;
 
 
     // Cache
     // Cache
     /** @hidden */
     /** @hidden */
@@ -1792,24 +1799,7 @@ export class ThinEngine {
         }
         }
 
 
         if ((<any>offsetLocations[0]).index !== undefined) {
         if ((<any>offsetLocations[0]).index !== undefined) {
-            let stride = 0;
-            for (let i = 0; i < offsetLocations.length; i++) {
-                let ai = <InstancingAttributeInfo>offsetLocations[i];
-                stride += ai.attributeSize * 4;
-            }
-            for (let i = 0; i < offsetLocations.length; i++) {
-                let ai = <InstancingAttributeInfo>offsetLocations[i];
-
-                if (!this._vertexAttribArraysEnabled[ai.index]) {
-                    this._gl.enableVertexAttribArray(ai.index);
-                    this._vertexAttribArraysEnabled[ai.index] = true;
-                }
-
-                this._vertexAttribPointer(instancesBuffer, ai.index, ai.attributeSize, ai.attributeType || this._gl.FLOAT, ai.normalized || false, stride, ai.offset);
-                this._gl.vertexAttribDivisor(ai.index, 1);
-                this._currentInstanceLocations.push(ai.index);
-                this._currentInstanceBuffers.push(instancesBuffer);
-            }
+            this.bindInstancesBuffer(instancesBuffer, offsetLocations as any, true);
         } else {
         } else {
             for (let index = 0; index < 4; index++) {
             for (let index = 0; index < 4; index++) {
                 let offsetLocation = <number>offsetLocations[index];
                 let offsetLocation = <number>offsetLocations[index];
@@ -1828,12 +1818,82 @@ export class ThinEngine {
     }
     }
 
 
     /**
     /**
-     * Apply all cached states (depth, culling, stencil and alpha)
+     * Bind the content of a webGL buffer used with instanciation
+     * @param instancesBuffer defines the webGL buffer to bind
+     * @param attributesInfo defines the offsets or attributes information used to determine where data must be stored in the buffer
+     * @param computeStride defines Wether to compute the strides from the info or use the default 0
      */
      */
-    public applyStates() {
-        this._depthCullingState.apply(this._gl);
-        this._stencilState.apply(this._gl);
-        this._alphaState.apply(this._gl);
+    public bindInstancesBuffer(instancesBuffer: DataBuffer, attributesInfo: InstancingAttributeInfo[], computeStride = true): void {
+        this.bindArrayBuffer(instancesBuffer);
+
+        let stride = 0;
+        if (computeStride) {
+            for (let i = 0; i < attributesInfo.length; i++) {
+                let ai = attributesInfo[i];
+                stride += ai.attributeSize * 4;
+            }
+        }
+
+        for (let i = 0; i < attributesInfo.length; i++) {
+            let ai = attributesInfo[i];
+            if (ai.index === undefined) {
+                ai.index = this._currentEffect!.getAttributeLocationByName(ai.attributeName);
+            }
+
+            if (!this._vertexAttribArraysEnabled[ai.index]) {
+                this._gl.enableVertexAttribArray(ai.index);
+                this._vertexAttribArraysEnabled[ai.index] = true;
+            }
+
+            this._vertexAttribPointer(instancesBuffer, ai.index, ai.attributeSize, ai.attributeType || this._gl.FLOAT, ai.normalized || false, stride, ai.offset);
+            this._gl.vertexAttribDivisor(ai.index, ai.divisor === undefined ? 1 : ai.divisor);
+            this._currentInstanceLocations.push(ai.index);
+            this._currentInstanceBuffers.push(instancesBuffer);
+        }
+    }
+
+    /**
+     * Disable the instance attribute corresponding to the name in parameter
+     * @param name defines the name of the attribute to disable
+     */
+    public disableInstanceAttributeByName(name: string) {
+        if (!this._currentEffect) {
+            return;
+        }
+
+        const attributeLocation = this._currentEffect.getAttributeLocationByName(name);
+        this.disableInstanceAttribute(attributeLocation);
+    }
+
+    /**
+     * Disable the instance attribute corresponding to the location in parameter
+     * @param attributeLocation defines the attribute location of the attribute to disable
+     */
+    public disableInstanceAttribute(attributeLocation: number) {
+        let shouldClean = false;
+        let index: number;
+        while ((index = this._currentInstanceLocations.indexOf(attributeLocation)) !== -1) {
+            this._currentInstanceLocations.splice(index, 1);
+            this._currentInstanceBuffers.splice(index, 1);
+
+            shouldClean = true;
+            index = this._currentInstanceLocations.indexOf(attributeLocation);
+        }
+
+        if (shouldClean) {
+            this._gl.vertexAttribDivisor(attributeLocation, 0);
+            this.disableAttributeByIndex(attributeLocation);
+        }
+    }
+
+    /**
+     * Disable the attribute corresponding to the location in parameter
+     * @param attributeLocation defines the attribute location of the attribute to disable
+     */
+    public disableAttributeByIndex(attributeLocation: number) {
+        this._gl.disableVertexAttribArray(attributeLocation);
+        this._vertexAttribArraysEnabled[attributeLocation] = false;
+        this._currentBufferPointers[attributeLocation].active = false;
     }
     }
 
 
     /**
     /**
@@ -2473,6 +2533,40 @@ export class ThinEngine {
     // States
     // States
 
 
     /**
     /**
+     * Apply all cached states (depth, culling, stencil and alpha)
+     */
+    public applyStates() {
+        this._depthCullingState.apply(this._gl);
+        this._stencilState.apply(this._gl);
+        this._alphaState.apply(this._gl);
+
+        if (this._colorWriteChanged) {
+            this._colorWriteChanged = false;
+            const enable = this._colorWrite;
+            this._gl.colorMask(enable, enable, enable, enable);
+        }
+    }
+
+    /**
+     * Enable or disable color writing
+     * @param enable defines the state to set
+     */
+    public setColorWrite(enable: boolean): void {
+        if (enable !== this._colorWrite) {
+            this._colorWriteChanged = true;
+            this._colorWrite = enable;
+        }
+    }
+
+    /**
+     * Gets a boolean indicating if color writing is enabled
+     * @returns the current color writing state
+     */
+    public getColorWrite(): boolean {
+        return this._colorWrite;
+    }
+
+    /**
      * Gets the depth culling state manager
      * Gets the depth culling state manager
      */
      */
     public get depthCullingState(): DepthCullingState {
     public get depthCullingState(): DepthCullingState {
@@ -2526,6 +2620,8 @@ export class ThinEngine {
             this._depthCullingState.reset();
             this._depthCullingState.reset();
             this._depthCullingState.depthFunc = this._gl.LEQUAL;
             this._depthCullingState.depthFunc = this._gl.LEQUAL;
             this._alphaState.reset();
             this._alphaState.reset();
+            this._colorWrite = true;
+            this._colorWriteChanged = true;
 
 
             this._unpackFlipYCached = null;
             this._unpackFlipYCached = null;
 
 
@@ -3123,35 +3219,35 @@ export class ThinEngine {
 
 
     /** @hidden */
     /** @hidden */
     public _setupFramebufferDepthAttachments(generateStencilBuffer: boolean, generateDepthBuffer: boolean, width: number, height: number, samples = 1): Nullable<WebGLRenderbuffer> {
     public _setupFramebufferDepthAttachments(generateStencilBuffer: boolean, generateDepthBuffer: boolean, width: number, height: number, samples = 1): Nullable<WebGLRenderbuffer> {
-        var depthStencilBuffer: Nullable<WebGLRenderbuffer> = null;
         var gl = this._gl;
         var gl = this._gl;
 
 
         // Create the depth/stencil buffer
         // Create the depth/stencil buffer
+        if (generateStencilBuffer && generateDepthBuffer) {
+            return this._getDepthStencilBuffer(width, height, samples, gl.DEPTH_STENCIL, gl.DEPTH24_STENCIL8, gl.DEPTH_STENCIL_ATTACHMENT);
+        }
+        if (generateDepthBuffer) {
+            return this._getDepthStencilBuffer(width, height, samples, gl.DEPTH_COMPONENT16, gl.DEPTH_COMPONENT16, gl.DEPTH_ATTACHMENT);
+        }
         if (generateStencilBuffer) {
         if (generateStencilBuffer) {
-            depthStencilBuffer = gl.createRenderbuffer();
-            gl.bindRenderbuffer(gl.RENDERBUFFER, depthStencilBuffer);
+            return this._getDepthStencilBuffer(width, height, samples, gl.STENCIL_INDEX8, gl.STENCIL_INDEX8, gl.STENCIL_ATTACHMENT);
+        }
 
 
-            if (samples > 1) {
-                gl.renderbufferStorageMultisample(gl.RENDERBUFFER, samples, gl.DEPTH24_STENCIL8, width, height);
-            } else {
-                gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, width, height);
-            }
+        return null;
+    }
 
 
-            gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, depthStencilBuffer);
-        }
-        else if (generateDepthBuffer) {
-            depthStencilBuffer = gl.createRenderbuffer();
-            gl.bindRenderbuffer(gl.RENDERBUFFER, depthStencilBuffer);
+    private _getDepthStencilBuffer = (width: number, height: number, samples: number, internalFormat: number, msInternalFormat: number, attachment: number) => {
+        var gl = this._gl;
+        const depthStencilBuffer = gl.createRenderbuffer();
 
 
-            if (samples > 1) {
-                gl.renderbufferStorageMultisample(gl.RENDERBUFFER, samples, gl.DEPTH_COMPONENT16, width, height);
-            } else {
-                gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, width, height);
-            }
+        gl.bindRenderbuffer(gl.RENDERBUFFER, depthStencilBuffer);
 
 
-            gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, depthStencilBuffer);
+        if (samples > 1) {
+            gl.renderbufferStorageMultisample(gl.RENDERBUFFER, samples, msInternalFormat, width, height);
+        } else {
+            gl.renderbufferStorage(gl.RENDERBUFFER, internalFormat, width, height);
         }
         }
 
 
+        gl.framebufferRenderbuffer(gl.FRAMEBUFFER, attachment, gl.RENDERBUFFER, depthStencilBuffer);
         return depthStencilBuffer;
         return depthStencilBuffer;
     }
     }
 
 
@@ -3548,9 +3644,7 @@ export class ThinEngine {
             this._mustWipeVertexAttributes = false;
             this._mustWipeVertexAttributes = false;
 
 
             for (var i = 0; i < this._caps.maxVertexAttribs; i++) {
             for (var i = 0; i < this._caps.maxVertexAttribs; i++) {
-                this._gl.disableVertexAttribArray(i);
-                this._vertexAttribArraysEnabled[i] = false;
-                this._currentBufferPointers[i].active = false;
+                this.disableAttributeByIndex(i);
             }
             }
             return;
             return;
         }
         }
@@ -3560,9 +3654,7 @@ export class ThinEngine {
                 continue;
                 continue;
             }
             }
 
 
-            this._gl.disableVertexAttribArray(i);
-            this._vertexAttribArraysEnabled[i] = false;
-            this._currentBufferPointers[i].active = false;
+            this.disableAttributeByIndex(i);
         }
         }
     }
     }
 
 

+ 10 - 3
src/Materials/effect.ts

@@ -137,6 +137,7 @@ export class Effect implements IDisposable {
     private _allFallbacksProcessed = false;
     private _allFallbacksProcessed = false;
     private _attributesNames: string[];
     private _attributesNames: string[];
     private _attributes: number[];
     private _attributes: number[];
+    private _attributeLocationByName: { [name: string] : number };
     private _uniforms: { [key: string]: Nullable<WebGLUniformLocation> } = {};
     private _uniforms: { [key: string]: Nullable<WebGLUniformLocation> } = {};
     /**
     /**
      * Key for the effect.
      * Key for the effect.
@@ -210,6 +211,8 @@ export class Effect implements IDisposable {
             this._fallbacks = fallbacks;
             this._fallbacks = fallbacks;
         }
         }
 
 
+        this._attributeLocationByName = { };
+
         this.uniqueId = Effect._uniqueIdSeed++;
         this.uniqueId = Effect._uniqueIdSeed++;
 
 
         var vertexSource: any;
         var vertexSource: any;
@@ -349,9 +352,7 @@ export class Effect implements IDisposable {
      * @returns the attribute location.
      * @returns the attribute location.
      */
      */
     public getAttributeLocationByName(name: string): number {
     public getAttributeLocationByName(name: string): number {
-        var index = this._attributesNames.indexOf(name);
-
-        return this._attributes[index];
+        return this._attributeLocationByName[name];
     }
     }
 
 
     /**
     /**
@@ -555,6 +556,12 @@ export class Effect implements IDisposable {
                 });
                 });
 
 
                 this._attributes = engine.getAttributes(this._pipelineContext!, attributesNames);
                 this._attributes = engine.getAttributes(this._pipelineContext!, attributesNames);
+                if (attributesNames) {
+                    for (let i = 0; i < attributesNames.length; i++) {
+                        const name = attributesNames[i];
+                        this._attributeLocationByName[name] = this._attributes[i];
+                    }
+                }
 
 
                 var index: number;
                 var index: number;
                 for (index = 0; index < this._samplerList.length; index++) {
                 for (index = 0; index < this._samplerList.length; index++) {

+ 2 - 1
tests/validation/config.json

@@ -4,7 +4,8 @@
         {
         {
             "title": "Node material #1",
             "title": "Node material #1",
             "playgroundId": "#QJ71C6#0",
             "playgroundId": "#QJ71C6#0",
-            "referenceImage": "node-material1.png"
+            "referenceImage": "node-material1.png",
+            "renderCount": 20
         },     
         },     
         {
         {
             "title": "Node material #2",
             "title": "Node material #2",