浏览代码

HighlightsPostProcess done + step 1 of imageProcessingPostProcess

David Catuhe 8 年之前
父节点
当前提交
7a93a135ae

+ 6 - 2
Tools/Gulp/config.json

@@ -575,7 +575,9 @@
                 "../../src/PostProcess/babylon.volumetricLightScatteringPostProcess.js",
                 "../../src/PostProcess/babylon.colorCorrectionPostProcess.js",
                 "../../src/PostProcess/babylon.tonemapPostProcess.js",
-                "../../src/PostProcess/babylon.displayPassPostProcess.js"                                
+                "../../src/PostProcess/babylon.displayPassPostProcess.js",                                
+                "../../src/PostProcess/babylon.highlightsPostProcess.js",
+                "../../src/PostProcess/babylon.imageProcessingPostProcess.js"
             ],
             "dependUpon" : [
                 "postProcesses"
@@ -592,7 +594,9 @@
                 "volumetricLightScatteringPass.fragment",
                 "colorCorrection.fragment",
                 "tonemap.fragment",
-                "displayPass.fragment"
+                "displayPass.fragment",
+                "highlights.fragment",
+                "imageProcessing.fragment"
             ],
             "shaderIncludes": [
                 "kernelBlurFragment",

文件差异内容过多而无法显示
+ 4019 - 3967
dist/preview release/babylon.d.ts


文件差异内容过多而无法显示
+ 17 - 17
dist/preview release/babylon.js


文件差异内容过多而无法显示
+ 42 - 5
dist/preview release/babylon.max.js


文件差异内容过多而无法显示
+ 4019 - 3967
dist/preview release/babylon.module.d.ts


文件差异内容过多而无法显示
+ 17 - 17
dist/preview release/babylon.worker.js


+ 11 - 0
dist/preview release/gui/babylon.gui.d.ts

@@ -347,6 +347,17 @@ declare module BABYLON.GUI {
 }
 
 
+declare var DOMImage: new (width?: number, height?: number) => HTMLImageElement;
+declare module BABYLON.GUI {
+    class Slider extends Control {
+        name: string;
+        private _barHeight;
+        constructor(name?: string);
+        _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
+    }
+}
+
+
 declare module BABYLON.GUI {
     class TextBlock extends Control {
         name: string;

+ 48 - 0
dist/preview release/gui/babylon.gui.js

@@ -1958,6 +1958,54 @@ var __extends = (this && this.__extends) || (function () {
         d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
     };
 })();
+var DOMImage = Image;
+var BABYLON;
+(function (BABYLON) {
+    var GUI;
+    (function (GUI) {
+        var Slider = (function (_super) {
+            __extends(Slider, _super);
+            function Slider(name) {
+                var _this = _super.call(this, name) || this;
+                _this.name = name;
+                _this._barHeight = new GUI.ValueAndUnit(0.5, GUI.ValueAndUnit.UNITMODE_PERCENTAGE, false);
+                return _this;
+            }
+            Slider.prototype._draw = function (parentMeasure, context) {
+                context.save();
+                this._applyStates(context);
+                if (this._processMeasures(parentMeasure, context)) {
+                    // Main bar
+                    var effectiveBarHeight = 0;
+                    if (this._barHeight.isPixel) {
+                        effectiveBarHeight = Math.min(this._barHeight.getValue(this._host), this._currentMeasure.height);
+                    }
+                    else {
+                        effectiveBarHeight = this._currentMeasure.height * this._barHeight.getValue(this._host);
+                    }
+                    context.fillRect(this._currentMeasure.left, this._currentMeasure.top + (this._currentMeasure.height - effectiveBarHeight) / 2, this._currentMeasure.width, effectiveBarHeight);
+                }
+                context.restore();
+            };
+            return Slider;
+        }(GUI.Control));
+        GUI.Slider = Slider;
+    })(GUI = BABYLON.GUI || (BABYLON.GUI = {}));
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=slider.js.map
+
+/// <reference path="../../../dist/preview release/babylon.d.ts"/>
+var __extends = (this && this.__extends) || (function () {
+    var extendStatics = Object.setPrototypeOf ||
+        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+    return function (d, b) {
+        extendStatics(d, b);
+        function __() { this.constructor = d; }
+        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+    };
+})();
 var BABYLON;
 (function (BABYLON) {
     var GUI;

文件差异内容过多而无法显示
+ 2 - 2
dist/preview release/gui/babylon.gui.min.js


+ 3 - 1
dist/preview release/what's new.md

@@ -22,8 +22,10 @@
  - New build system based on workloads. [More info here](http://doc.babylonjs.com/generals/how_to_start#custom-builds) ([deltakosh](https://github.com/deltakosh))
  - New `Cell Shading` material added into `Materials Library` [Demo](http://www.babylonjs.com/Demos/CellShading/) ([Julien Moreau-Mathis](https://github.com/julien-moreau))
  - New kernel based blur. [Demo](https://www.babylonjs-playground.com/#FBH4J7#1) ([deltakosh](https://github.com/deltakosh))
- 
+ - New highlights postprocess ([deltakosh](https://github.com/deltakosh))
+
 ### Updates
+ - PostProcess can now use alpha blending and share outputs ([deltakosh](https://github.com/deltakosh))
 - Added `ArcRotateCamera.panningInertia` to decouple inertia from panning inertia ([deltakosh](https://github.com/deltakosh))
 - Added `FIXED_EQUIRECTANGULAR_MIRRORED_MODE` mode for reflection texture. [Demo here](http://www.babylonjs-playground.com/#11GAIH#22) ([deltakosh](https://github.com/deltakosh))
 - Introduced `boundingBox.centerWorld` and `boundingBox.extendSizeWorld` ([deltakosh](https://github.com/deltakosh))

+ 7 - 0
src/PostProcess/babylon.highlightsPostProcess.ts

@@ -0,0 +1,7 @@
+module BABYLON {
+    export class HighlightsPostProcess extends PostProcess {
+        constructor(name: string, options: number | PostProcessOptions, camera: Camera, samplingMode?: number, engine?: Engine, reusable?: boolean, textureType: number = Engine.TEXTURETYPE_UNSIGNED_INT) {
+            super(name, "highlights", null, null, options, camera, samplingMode, engine, reusable, null, textureType);
+        }
+    }
+} 

+ 87 - 0
src/PostProcess/babylon.imageProcessingPostProcess.ts

@@ -0,0 +1,87 @@
+module BABYLON {
+    export class ImageProcessingPostProcess extends PostProcess {
+		public colorGradingTexture: BaseTexture;
+		public colorGradingWeight: number = 1.0;
+		public colorCurves = new ColorCurves();
+
+		public vignetteStretch: number;
+		public vignetteCentreX: number;
+		public vignetteCentreY: number;
+		public vignetteWeight: number;
+		public vignetteColor: BABYLON.Color4 = new BABYLON.Color4(0, 0, 0, 0);
+		public vignetteBlendMode = ImageProcessingPostProcess.VIGNETTEMODE_MULTIPLY;
+
+		public cameraContrast: number;
+		public cameraExposureValue: number;
+		public cameraToneMappingEnabled: boolean;
+
+        constructor(name: string, options: number | PostProcessOptions, camera?: Camera, samplingMode?: number, engine?: Engine, reusable?: boolean) {
+            super(name, "imageProcessing", [
+                                            'contrast',
+                                            'vignetteSettings1',
+                                            'vignetteSettings2',
+                                            'vignetteSettings3',
+                                            'cameraExposureLinear',
+                                            'toneMappingEnabled',
+                                            'vCameraColorCurveNegative',
+                                            'vCameraColorCurveNeutral',
+                                            'vCameraColorCurvePositive',
+                                            'hasTextureColorTransform',
+                                            'colorTransformSettings'                    
+                                            ], ["txColorTransform"], options, camera, samplingMode, engine, reusable);
+
+            this.onApply = (effect: Effect) => {
+                let aspectRatio = this.width / this.height;
+                
+                // Color 
+                ColorCurves.Bind(this.colorCurves, effect);
+
+                // Vignette
+                let vignetteScaleY = 0;// TODO Math.tan(imageProcessing._scene.activeCamera.fov * 0.5);
+                let vignetteScaleX = vignetteScaleY * aspectRatio;
+
+                let vignetteScaleGeometricMean = Math.sqrt(vignetteScaleX * vignetteScaleY);
+                vignetteScaleX = Tools.Mix(vignetteScaleX, vignetteScaleGeometricMean, this.vignetteStretch);
+                vignetteScaleY = Tools.Mix(vignetteScaleY, vignetteScaleGeometricMean, this.vignetteStretch);
+
+                effect.setFloat4('vignetteSettings1', vignetteScaleX, vignetteScaleY, -vignetteScaleX * this.vignetteCentreX, -vignetteScaleY * this.vignetteCentreY);
+
+                let vignettePower = -2.0 * this.vignetteWeight;
+                effect.setFloat4('vignetteSettings2', this.vignetteColor.r, this.vignetteColor.g, this.vignetteColor.b, vignettePower);
+
+                effect.setFloat4('vignetteSettings3', 0, 0, 0, this.vignetteBlendMode);
+
+                // Contrast and tonemapping
+                effect.setFloat('contrast', this.cameraContrast);
+
+                effect.setFloat('cameraExposureLinear', Math.pow(2.0, - this.cameraExposureValue) * Math.PI);
+                effect.setFloat('toneMappingEnabled', this.cameraToneMappingEnabled ? 1.0 : 0.0);                
+                
+                // Color transform settings
+                let hasColorGradingTexture = (this.colorGradingTexture != null) && this.colorGradingTexture.isReady();
+                effect.setBool('hasTextureColorTransform', hasColorGradingTexture);
+                //effect.setTexture('txColorTransform', hasColorGradingTexture ? this.colorGradingTexture : emptyTexture);
+                let textureSize = hasColorGradingTexture ? this.colorGradingTexture.getSize().height : 1.0;
+
+                effect.setFloat4("colorTransformSettings",
+                    (textureSize - 1) / textureSize, // textureScale
+                    0.5 / textureSize, // textureOffset
+                    textureSize, // textureSize
+                    hasColorGradingTexture ? this.colorGradingWeight : 0.0 // weight
+                );                
+            };
+        }
+
+        // Statics
+        private static _VIGNETTEMODE_MULTIPLY = 1;
+        private static _VIGNETTEMODE_OPAQUE = 2;
+
+        public static get VIGNETTEMODE_MULTIPLY(): number {
+            return ImageProcessingPostProcess._VIGNETTEMODE_MULTIPLY;
+        }
+
+        public static get VIGNETTEMODE_OPAQUE(): number {
+            return ImageProcessingPostProcess._VIGNETTEMODE_OPAQUE;
+        }
+    }
+}

+ 1 - 1
src/PostProcess/babylon.passPostProcess.ts

@@ -1,5 +1,5 @@
 module BABYLON {
-    export class PassPostProcess extends PostProcess {
+    export class PassPostProcess extends PostProcess {    
         constructor(name: string, options: number | PostProcessOptions, camera: Camera, samplingMode?: number, engine?: Engine, reusable?: boolean, textureType: number = Engine.TEXTURETYPE_UNSIGNED_INT) {
             super(name, "pass", null, null, options, camera, samplingMode, engine, reusable, null, textureType);
         }

+ 91 - 55
src/PostProcess/babylon.postProcess.ts

@@ -7,6 +7,9 @@
         public height = -1;
         public renderTargetSamplingMode: number;
         public clearColor: Color4;
+        public autoClear = true;
+        public alphaMode = Engine.ALPHA_DISABLE;
+        public alphaConstants: Color4;        
 
         /*
             Enable Pixel Perfect mode where texture is not scaled to be power of 2.
@@ -31,7 +34,8 @@
         private _parameters: string[];
         private _scaleRatio = new Vector2(1, 1);
         protected _indexParameters: any;
-
+        private _shareOutputWithPostProcess: PostProcess;
+        
         // Events
 
         /**
@@ -104,6 +108,10 @@
             this._onAfterRenderObserver = this.onAfterRenderObservable.add(callback);
         }
 
+        public get outputTexture(): WebGLTexture {
+            return this._textures.data[this._currentRenderTextureInd];
+        }      
+
         constructor(public name: string, fragmentUrl: string, parameters: string[], samplers: string[], options: number | PostProcessOptions, camera: Camera, samplingMode: number = Texture.NEAREST_SAMPLINGMODE, engine?: Engine, reusable?: boolean, defines?: string, textureType: number = Engine.TEXTURETYPE_UNSIGNED_INT, vertexUrl: string = "postprocess", indexParameters?: any, blockCompilation = false) {
             if (camera != null) {
                 this._camera = camera;
@@ -134,11 +142,19 @@
             if (!blockCompilation) {
                 this.updateEffect(defines);
             }
-        }
+        }    
 
         public getEngine(): Engine {
             return this._engine;
         }        
+
+        public shareOutputWith(postProcess: PostProcess): PostProcess {
+            this._disposeTextures();
+
+            this._shareOutputWithPostProcess = postProcess;
+
+            return this;
+        }
         
         public updateEffect(defines?: string, uniforms?: string[], samplers?: string[], indexParameters?: any) {
             this._effect = this._engine.createEffect({ vertex: this._vertexUrl, fragment: this._fragmentUrl },
@@ -163,82 +179,94 @@
         }
 
         public activate(camera: Camera, sourceTexture?: WebGLTexture): void {
-            camera = camera || this._camera;
+            if (!this._shareOutputWithPostProcess) {
+                camera = camera || this._camera;
 
-            var scene = camera.getScene();
-            var maxSize = camera.getEngine().getCaps().maxTextureSize;
+                var scene = camera.getScene();
+                var maxSize = camera.getEngine().getCaps().maxTextureSize;
 
-            var requiredWidth = ((sourceTexture ? sourceTexture._width : this._engine.getRenderingCanvas().width) * <number>this._options) | 0;
-            var requiredHeight = ((sourceTexture ? sourceTexture._height : this._engine.getRenderingCanvas().height) * <number>this._options) | 0;
+                var requiredWidth = ((sourceTexture ? sourceTexture._width : this._engine.getRenderingCanvas().width) * <number>this._options) | 0;
+                var requiredHeight = ((sourceTexture ? sourceTexture._height : this._engine.getRenderingCanvas().height) * <number>this._options) | 0;
 
-            var desiredWidth = (<PostProcessOptions>this._options).width || requiredWidth;
-            var desiredHeight = (<PostProcessOptions>this._options).height || requiredHeight;
+                var desiredWidth = (<PostProcessOptions>this._options).width || requiredWidth;
+                var desiredHeight = (<PostProcessOptions>this._options).height || requiredHeight;
 
-            if (this.renderTargetSamplingMode !== Texture.NEAREST_SAMPLINGMODE) {
-                if (!(<PostProcessOptions>this._options).width) {
-                    desiredWidth = Tools.GetExponentOfTwo(desiredWidth, maxSize);
-                }
+                if (this.renderTargetSamplingMode !== Texture.NEAREST_SAMPLINGMODE) {
+                    if (!(<PostProcessOptions>this._options).width) {
+                        desiredWidth = Tools.GetExponentOfTwo(desiredWidth, maxSize);
+                    }
 
-                if (!(<PostProcessOptions>this._options).height) {
-                    desiredHeight = Tools.GetExponentOfTwo(desiredHeight, maxSize);
+                    if (!(<PostProcessOptions>this._options).height) {
+                        desiredHeight = Tools.GetExponentOfTwo(desiredHeight, maxSize);
+                    }
                 }
-            }
 
-            if (this.width !== desiredWidth || this.height !== desiredHeight) {
-                if (this._textures.length > 0) {
-                    for (var i = 0; i < this._textures.length; i++) {
-                        this._engine._releaseTexture(this._textures.data[i]);
-                    }
-                    this._textures.reset();
-                }         
-                this.width = desiredWidth;
-                this.height = desiredHeight;
-
-                let textureSize = { width: this.width, height: this.height };
-                let textureOptions = { 
-                    generateMipMaps: false, 
-                    generateDepthBuffer: camera._postProcesses.indexOf(this) === 0, 
-                    generateStencilBuffer: camera._postProcesses.indexOf(this) === 0 && this._engine.isStencilEnable,
-                    samplingMode: this.renderTargetSamplingMode, 
-                    type: this._textureType 
-                };
-
-                this._textures.push(this._engine.createRenderTargetTexture(textureSize, textureOptions));
-
-                if (this._reusable) {
+                if (this.width !== desiredWidth || this.height !== desiredHeight) {
+                    if (this._textures.length > 0) {
+                        for (var i = 0; i < this._textures.length; i++) {
+                            this._engine._releaseTexture(this._textures.data[i]);
+                        }
+                        this._textures.reset();
+                    }         
+                    this.width = desiredWidth;
+                    this.height = desiredHeight;
+
+                    let textureSize = { width: this.width, height: this.height };
+                    let textureOptions = { 
+                        generateMipMaps: false, 
+                        generateDepthBuffer: camera._postProcesses.indexOf(this) === 0, 
+                        generateStencilBuffer: camera._postProcesses.indexOf(this) === 0 && this._engine.isStencilEnable,
+                        samplingMode: this.renderTargetSamplingMode, 
+                        type: this._textureType 
+                    };
+
                     this._textures.push(this._engine.createRenderTargetTexture(textureSize, textureOptions));
+
+                    if (this._reusable) {
+                        this._textures.push(this._engine.createRenderTargetTexture(textureSize, textureOptions));
+                    }
+
+                    this.onSizeChangedObservable.notifyObservers(this);
                 }
 
-                this.onSizeChangedObservable.notifyObservers(this);
+                this._textures.forEach(texture => {
+                    if (texture.samples !== this.samples) {
+                        this._engine.updateRenderTargetTextureSampleCount(texture, this.samples);
+                    }
+                });
             }
 
-            this._textures.forEach(texture => {
-                if (texture.samples !== this.samples) {
-                    this._engine.updateRenderTargetTextureSampleCount(texture, this.samples);
-                }
-            });
+            var target = this._shareOutputWithPostProcess ? this._shareOutputWithPostProcess.outputTexture : this.outputTexture;
 
             if (this.enablePixelPerfectMode) {
                 this._scaleRatio.copyFromFloats(requiredWidth / desiredWidth, requiredHeight / desiredHeight);
-                this._engine.bindFramebuffer(this._textures.data[this._currentRenderTextureInd], 0, requiredWidth, requiredHeight);
+                this._engine.bindFramebuffer(target, 0, requiredWidth, requiredHeight);
             }
             else {
                 this._scaleRatio.copyFromFloats(1, 1);
-                this._engine.bindFramebuffer(this._textures.data[this._currentRenderTextureInd]);
+                this._engine.bindFramebuffer(target);
             }
 
             this.onActivateObservable.notifyObservers(camera);
 
             // Clear
-            if (this.clearColor) {
-                this._engine.clear(this.clearColor, true, true, true);
-            } else {
-                this._engine.clear(scene.clearColor, scene.autoClear || scene.forceWireframe, true, true);
+            if (this.autoClear && this.alphaMode === Engine.ALPHA_DISABLE) {
+                if (this.clearColor) {
+                    this._engine.clear(this.clearColor, true, true, true);
+                } else {
+                    this._engine.clear(scene.clearColor, scene.autoClear || scene.forceWireframe, true, true);
+                }
             }
 
             if (this._reusable) {
                 this._currentRenderTextureInd = (this._currentRenderTextureInd + 1) % 2;
             }
+
+            // Alpha
+            this._engine.setAlphaMode(this.alphaMode);
+            if (this.alphaConstants) {
+                this.getEngine().setAlphaConstants(this.alphaConstants.r, this.alphaConstants.g, this.alphaConstants.b, this.alphaConstants.a);
+            }
         }
 
         public get isSupported(): boolean {
@@ -253,12 +281,12 @@
             // States
             this._engine.enableEffect(this._effect);
             this._engine.setState(false);
-            this._engine.setAlphaMode(Engine.ALPHA_DISABLE);
             this._engine.setDepthBuffer(false);
             this._engine.setDepthWrite(false);
 
-            // Texture
-            this._effect._bindTexture("textureSampler", this._textures.data[this._currentRenderTextureInd]);
+            // Texture            
+            var source = this._shareOutputWithPostProcess ? this._shareOutputWithPostProcess.outputTexture : this.outputTexture;
+            this._effect._bindTexture("textureSampler", source);
 
             // Parameters
             this._effect.setVector2("scale", this._scaleRatio);
@@ -267,8 +295,10 @@
             return this._effect;
         }
 
-        public dispose(camera?: Camera): void {
-            camera = camera || this._camera;            
+        private _disposeTextures() {
+            if (this._shareOutputWithPostProcess) {
+                return;
+            }
 
             if (this._textures.length > 0) {
                 for (var i = 0; i < this._textures.length; i++) {
@@ -276,6 +306,12 @@
                 }
             }
             this._textures.dispose();
+        }
+
+        public dispose(camera?: Camera): void {
+            camera = camera || this._camera;            
+
+            this._disposeTextures();
 
             if (!camera) {
                 return;

+ 2 - 1
src/PostProcess/babylon.postProcessManager.ts

@@ -122,9 +122,10 @@
                 }
             }
 
-            // Restore depth buffer
+            // Restore states
             engine.setDepthBuffer(true);
             engine.setDepthWrite(true);
+            engine.setAlphaMode(Engine.ALPHA_DISABLE);
         }
 
         public dispose(): void {

+ 17 - 0
src/Shaders/highlights.fragment.fx

@@ -0,0 +1,17 @@
+// Samplers
+varying vec2 vUV;
+uniform sampler2D textureSampler;
+
+const vec3 RGBLuminanceCoefficients = vec3(0.2126, 0.7152, 0.0722);
+
+void main(void) 
+{
+	vec4 tex = texture2D(textureSampler, vUV);
+	vec3 c = tex.rgb;
+	float luma = dot(c.rgb, RGBLuminanceCoefficients);
+	
+	// to artificially desaturate/whiteout: c = mix(c, vec3(luma), luma * luma * luma * 0.1)
+	// brighter = higher luma = lower exponent = more diffuse glow
+	
+	gl_FragColor = vec4(pow(c, vec3(25.0 - luma * 15.0)), tex.a);	
+}

+ 125 - 0
src/Shaders/imageProcessing.fragment.fx

@@ -0,0 +1,125 @@
+// Samplers
+varying vec2 vUV;
+uniform sampler2D textureSampler;
+
+const float GammaEncodePowerApprox = 1.0 / 2.2;
+const vec3 RGBLuminanceCoefficients = vec3(0.2126, 0.7152, 0.0722);
+
+uniform float contrast;
+uniform vec4 vignetteSettings1;
+uniform vec4 vignetteSettings2;
+uniform vec4 vignetteSettings3;
+uniform float cameraExposureLinear;
+uniform float toneMappingEnabled;
+uniform vec4 vCameraColorCurveNegative;
+uniform vec4 vCameraColorCurveNeutral;
+uniform vec4 vCameraColorCurvePositive;
+uniform bool hasTextureColorTransform;
+uniform sampler2D txColorTransform;
+uniform vec4 colorTransformSettings;
+
+#define VignetteBlendModeMultiply 0.0
+#define VignetteBlendModeOpaque 1.0
+
+vec3 applyEaseInOut(vec3 x){
+	return x * x * (3.0 - 2.0 * x);
+}
+
+/** 
+ * Polyfill for SAMPLE_TEXTURE_3D, which is unsupported in WebGL.
+ * colorTransformSettings.y = textureOffset (0.5 / textureSize).
+ * colorTransformSettings.z = textureSize.
+ */
+vec3 sampleTexture3D(sampler2D colorTransform, vec3 color)
+{
+	float sliceSize = 2.0 * colorTransformSettings.y; // Size of 1 slice relative to the texture, for example 1/8
+
+	float sliceContinuous = (color.y - colorTransformSettings.y) * colorTransformSettings.z;
+	float sliceInteger = floor(sliceContinuous);
+
+	// Note: this is mathematically equivalent to fract(sliceContinuous); but we use explicit subtract
+	// rather than separate fract() for correct results near slice boundaries (matching sliceInteger choice)
+	float sliceFraction = sliceContinuous - sliceInteger;
+
+	vec2 sliceUV = color.xz;
+	
+	sliceUV.x *= sliceSize;
+	sliceUV.x += sliceInteger * sliceSize;
+
+	vec4 slice0Color = texture2D(colorTransform, sliceUV);
+
+	sliceUV.x += sliceSize;
+	vec4 slice1Color = texture2D(colorTransform, sliceUV);
+
+	vec3 result = mix(slice0Color.rgb, slice1Color.rgb, sliceFraction);
+	color.rgb = result.bgr;
+
+	return color;
+}
+
+vec4 applyImageProcessing(vec4 result, vec2 viewportXY){
+
+	result.rgb *= cameraExposureLinear;
+
+	//vignette
+	vec3 vignetteXY1 = vec3(viewportXY * vignetteSettings1.xy + vignetteSettings1.zw, 1.0);
+	float vignetteTerm = dot(vignetteXY1, vignetteXY1);
+	float vignette = pow(vignetteTerm, vignetteSettings2.w);
+
+	// Interpolate between the artist 'color' and white based on the physical transmission value 'vignette'.
+	vec3 vignetteColor = vignetteSettings2.rgb;
+
+	float vignetteBlendMode = vignetteSettings3.w;
+
+	if (vignetteBlendMode == VignetteBlendModeMultiply) {
+		vec3 vignetteColorMultiplier = mix(vignetteColor, vec3(1, 1, 1), vignette);
+		result.rgb *= vignetteColorMultiplier;
+	}
+
+	if (vignetteBlendMode == VignetteBlendModeOpaque) {
+		result.rgb = mix(vignetteColor, result.rgb, vignette);
+	}
+	
+	float tonemappingCalibration = 1.590579;
+	vec3 tonemapped = 1.0 - exp2(-tonemappingCalibration * result.rgb);
+
+	result.rgb = mix(result.rgb, tonemapped, toneMappingEnabled);
+	result.rgb = pow(result.rgb, vec3(GammaEncodePowerApprox));
+	result.rgb = clamp(result.rgb, 0.0, 1.0);
+
+	vec3 resultHighContrast = applyEaseInOut(result.rgb);
+
+	if (contrast < 1.0) {
+		result.rgb = mix(vec3(0.5, 0.5, 0.5), result.rgb, contrast);
+	} else {
+		result.rgb = mix(result.rgb, resultHighContrast, contrast - 1.0);
+	}
+
+	// Apply Color Transform
+	if (hasTextureColorTransform) {
+		vec3 colorTransformInput = result.rgb * colorTransformSettings.xxx + colorTransformSettings.yyy;
+		vec3 colorTransformOutput = sampleTexture3D(txColorTransform, colorTransformInput).rgb;
+
+		result.rgb = mix(result.rgb, colorTransformOutput, colorTransformSettings.www);
+	}
+
+	// Apply Color Curves
+	float luma = dot(result.rgb, RGBLuminanceCoefficients);
+	vec2 curveMix = clamp(vec2(luma * 3.0 - 1.5, luma * -3.0 + 1.5), vec2(0.0), vec2(1.0));
+	vec4 colorCurve = vCameraColorCurveNeutral + curveMix.x * vCameraColorCurvePositive - curveMix.y * vCameraColorCurveNegative;
+
+	result.rgb *= colorCurve.rgb;
+	result.rgb = mix(vec3(luma), result.rgb, colorCurve.a);
+
+	return result;
+}
+
+void main(void) 
+{
+	vec4 result = texture2D(textureSampler, vUV);
+
+	vec2 viewportXY = texelCoord * 2.0 - 1.0;
+	result = applyImageProcessing(result, viewportXY);
+
+	gl_FragColor = result;
+}

+ 58 - 0
src/States/babylon.alphaCullingState.ts

@@ -2,8 +2,12 @@
     export class _AlphaState {
         private _isAlphaBlendDirty = false;
         private _isBlendFunctionParametersDirty = false;
+        private _isBlendEquationParametersDirty = false;
+        private _isBlendConstantsDirty = false;
         private _alphaBlend = false;
         private _blendFunctionParameters = new Array<number>(4);
+        private _blendEquationParameters = new Array<number>(2);
+        private _blendConstants = new Array<number>(4);
 
         /**
          * Initializes the state.
@@ -29,6 +33,24 @@
             this._isAlphaBlendDirty = true;
         }
 
+        public setAlphaBlendConstants(r: number, g: number, b: number, a: number): void {
+            if (
+                this._blendConstants[0] === r &&
+                this._blendConstants[1] === g &&
+                this._blendConstants[2] === b &&
+                this._blendConstants[3] === a
+            ) {
+                return;
+            }
+
+            this._blendConstants[0] = r;
+            this._blendConstants[1] = g;
+            this._blendConstants[2] = b;
+            this._blendConstants[3] = a;
+
+            this._isBlendConstantsDirty = true;
+        }        
+
         public setAlphaBlendFunctionParameters(value0: number, value1: number, value2: number, value3: number): void {
             if (
                 this._blendFunctionParameters[0] === value0 &&
@@ -47,6 +69,20 @@
             this._isBlendFunctionParametersDirty = true;
         }
 
+        public setAlphaEquationParameters(rgb: number, alpha): void {
+            if (
+                this._blendEquationParameters[0] === rgb &&
+                this._blendEquationParameters[1] === alpha
+            ) {
+                return;
+            }
+
+            this._blendEquationParameters[0] = rgb;
+            this._blendEquationParameters[1] = alpha;
+
+            this._isBlendEquationParametersDirty = true;
+        }        
+
         public reset() {
             this._alphaBlend = false;
             this._blendFunctionParameters[0] = null;
@@ -54,8 +90,18 @@
             this._blendFunctionParameters[2] = null;
             this._blendFunctionParameters[3] = null;
 
+            this._blendEquationParameters[0] = null;
+            this._blendEquationParameters[1] = null; 
+
+            this._blendConstants[0] = null;
+            this._blendConstants[1] = null;
+            this._blendConstants[2] = null;
+            this._blendConstants[3] = null;                       
+
             this._isAlphaBlendDirty = true;
             this._isBlendFunctionParametersDirty = false;
+            this._isBlendEquationParametersDirty = false;
+            this._isBlendConstantsDirty = false;
         }
 
         public apply(gl: WebGLRenderingContext) {
@@ -80,6 +126,18 @@
                 gl.blendFuncSeparate(this._blendFunctionParameters[0], this._blendFunctionParameters[1], this._blendFunctionParameters[2], this._blendFunctionParameters[3]);
                 this._isBlendFunctionParametersDirty = false;
             }
+
+            // Alpha equation
+            if (this._isBlendEquationParametersDirty) {
+                gl.blendEquationSeparate(this._isBlendEquationParametersDirty[0], this._isBlendEquationParametersDirty[1]);
+                this._isBlendEquationParametersDirty = false;
+            }        
+
+            // Constants
+            if (this._isBlendConstantsDirty) {
+                gl.blendColor(this._blendConstants[0], this._blendConstants[1], this._blendConstants[2], this._blendConstants[3]);
+                this._isBlendConstantsDirty = false;
+            }                    
         }
     }
 }

文件差异内容过多而无法显示
+ 11 - 0
src/Tools/babylon.tools.ts


+ 13 - 0
src/babylon.engine.ts

@@ -246,6 +246,7 @@
         private static _ALPHA_ONEONE = 6;
         private static _ALPHA_PREMULTIPLIED = 7;
         private static _ALPHA_PREMULTIPLIED_PORTERDUFF = 8;
+        private static _ALPHA_INTERPOLATE = 9;
 
         private static _DELAYLOADSTATE_NONE = 0;
         private static _DELAYLOADSTATE_LOADED = 1;
@@ -381,6 +382,10 @@
             return Engine._ALPHA_PREMULTIPLIED_PORTERDUFF;
         }
 
+        public static get ALPHA_INTERPOLATE(): number {
+            return Engine._ALPHA_INTERPOLATE;
+        }        
+
         public static get DELAYLOADSTATE_NONE(): number {
             return Engine._DELAYLOADSTATE_NONE;
         }
@@ -2159,6 +2164,10 @@
             this._gl.colorMask(enable, enable, enable, enable);
         }
 
+        public setAlphaConstants(r: number, g: number, b: number, a: number) {
+            this._alphaState.setAlphaBlendConstants(r, g, b, a);
+        }
+
         public setAlphaMode(mode: number, noDepthWriteChange: boolean = false): void {
             if (this._alphaMode === mode) {
                 return;
@@ -2200,6 +2209,10 @@
                     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 Engine.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;                    
             }
             if (!noDepthWriteChange) {
                 this.setDepthWrite(mode === Engine.ALPHA_DISABLE);