Просмотр исходного кода

ColorGrading and Infinite Lights

Sébastien Vandenberghe 9 лет назад
Родитель
Сommit
e1eb0e2134

+ 36 - 24
src/Materials/Textures/babylon.colorGradingTexture.ts

@@ -48,6 +48,8 @@ module BABYLON {
             this.url = url;
             this.hasAlpha = false;
             this.isCube = false;
+            this.wrapU = Texture.CLAMP_ADDRESSMODE;
+            this.wrapV = Texture.CLAMP_ADDRESSMODE;
             
             this._texture = this._getFromCache(url, true);
 
@@ -75,16 +77,17 @@ module BABYLON {
 
             var mipLevels = 0;
             var floatArrayView: Float32Array = null;
-            var texture = this.getScene().getEngine().createRawTexture(null, 1, 1, BABYLON.Engine.TEXTUREFORMAT_RGB, false, false, Texture.NEAREST_SAMPLINGMODE);
+            var texture = this.getScene().getEngine().createRawTexture(null, 1, 1, BABYLON.Engine.TEXTUREFORMAT_RGB, false, false, Texture.BILINEAR_SAMPLINGMODE);
             this._texture = texture;
             
             var callback = (text: string) => {
-                var buffer: ArrayBuffer;
                 var data: Uint8Array;
+                var tempData: Float32Array;
                 
                 var line: string;
                 var lines = text.split('\n');
-                var size = 0, pixelIndex = 0;
+                var size = 0, pixelIndexW = 0, pixelIndexH = 0, pixelIndexSlice = 0;
+                var maxColor = 0;
                 
                 for (let i = 0; i < lines.length; i++) {
                     line = lines[i];
@@ -99,37 +102,46 @@ module BABYLON {
                     if (size === 0) {
                         // Number of space + one
                         size = words.length;
-                        buffer = new ArrayBuffer(size * size * size * 3); // volume texture of side size and rgb 8
-                        data = new Uint8Array(buffer);
+                        data = new Uint8Array(size * size * size * 3); // volume texture of side size and rgb 8
+                        tempData = new Float32Array(size * size * size * 3);
                         continue;
                     }
                     
                     if (size != 0)
                     {
-                        var r = parseInt(words[0]);
-                        var g = parseInt(words[1]);
-                        var b = parseInt(words[2]);
+                        var r = Math.max(parseInt(words[0]), 0);
+                        var g = Math.max(parseInt(words[1]), 0);
+                        var b = Math.max(parseInt(words[2]), 0);
                         
-                        r = Math.round(Math.max(Math.min(255, r), 0));
-                        g = Math.round(Math.max(Math.min(255, g), 0));
-                        b = Math.round(Math.max(Math.min(255, b), 0));
-
-                        // Transpose ordering from RGB to BGR (naming here might also be transposed).
-                        var indexR = pixelIndex % size;
-                        var indexG = (pixelIndex / size) % size;
-                        var indexB = (pixelIndex / size) / size;
-
-                        var pixelStorageIndex = indexR * (size * size * 3) + indexG * size * 3 + indexB * 3;
-                        data[pixelStorageIndex + 0] = r;//255;//r;
-                        data[pixelStorageIndex + 1] = g;//0;//g;
-                        data[pixelStorageIndex + 2] = b;//255;//b;
-
-                        pixelIndex++;
+                        maxColor = Math.max(r, maxColor);
+                        maxColor = Math.max(g, maxColor);
+                        maxColor = Math.max(b, maxColor);
+                        
+                        var pixelStorageIndex = (pixelIndexW + pixelIndexSlice * size + pixelIndexH * size * size) * 3;
+                        
+                        tempData[pixelStorageIndex + 0] = r;
+                        tempData[pixelStorageIndex + 1] = g;
+                        tempData[pixelStorageIndex + 2] = b;
+                        
+                        pixelIndexSlice++;
+                        if (pixelIndexSlice % size == 0) {
+                            pixelIndexH++;
+                            pixelIndexSlice = 0;
+                            if (pixelIndexH % size == 0) {
+                                pixelIndexW++;
+                                pixelIndexH = 0;
+                            }
+                        }
                     }
                 }
+            
+                for (let i = 0; i < tempData.length; i++) {
+                    var value = tempData[i];
+                    data[i] = (value / maxColor * 255);
+                }
                 
-                this.getScene().getEngine().updateRawTexture(texture, data, BABYLON.Engine.TEXTUREFORMAT_RGB, false);
                 this.getScene().getEngine().updateTextureSize(texture, size * size, size);
+                this.getScene().getEngine().updateRawTexture(texture, data, BABYLON.Engine.TEXTUREFORMAT_RGB, false);
             }
 
             Tools.LoadFile(this.url, callback);

+ 57 - 64
src/Materials/babylon.pbrMaterial.ts

@@ -1,6 +1,4 @@
 module BABYLON {
-    var maxSimultaneousLights = 4;
-
     class PBRMaterialDefines extends MaterialDefines {
         public ALBEDO = false;
         public AMBIENT = false;
@@ -18,40 +16,7 @@
         public ALPHAFROMALBEDO = false;
         public POINTSIZE = false;
         public FOG = false;
-        public LIGHT0 = false;
-        public LIGHT1 = false;
-        public LIGHT2 = false;
-        public LIGHT3 = false;
-        public SPOTLIGHT0 = false;
-        public SPOTLIGHT1 = false;
-        public SPOTLIGHT2 = false;
-        public SPOTLIGHT3 = false;
-        public HEMILIGHT0 = false;
-        public HEMILIGHT1 = false;
-        public HEMILIGHT2 = false;
-        public HEMILIGHT3 = false;
-        public POINTLIGHT0 = false;
-        public POINTLIGHT1 = false;
-        public POINTLIGHT2 = false;
-        public POINTLIGHT3 = false;
-        public DIRLIGHT0 = false;
-        public DIRLIGHT1 = false;
-        public DIRLIGHT2 = false;
-        public DIRLIGHT3 = false;
         public SPECULARTERM = false;
-        public SHADOW0 = false;
-        public SHADOW1 = false;
-        public SHADOW2 = false;
-        public SHADOW3 = false;
-        public SHADOWS = false;
-        public SHADOWVSM0 = false;
-        public SHADOWVSM1 = false;
-        public SHADOWVSM2 = false;
-        public SHADOWVSM3 = false;
-        public SHADOWPCF0 = false;
-        public SHADOWPCF1 = false;
-        public SHADOWPCF2 = false;
-        public SHADOWPCF3 = false;
         public OPACITYFRESNEL = false;
         public EMISSIVEFRESNEL = false;
         public FRESNEL = false;
@@ -97,7 +62,7 @@
 
         constructor() {
             super();
-            this._keys = Object.keys(this);
+            this.rebuild();
         }
     }
 
@@ -184,6 +149,9 @@
         @serializeAsTexture()
         public cameraColorGradingTexture: BaseTexture = null;
 
+        private _cameraColorGradingScaleOffset: Vector4 = new Vector4(1.0, 1.0, 0.0, 0.0);
+        private _cameraColorGradingInfos: Vector4 = new Vector4(1.0, 1.0, 0.0, 0.0);
+         
         private _cameraInfos: Vector4 = new Vector4(1.0, 1.0, 0.0, 0.0);
 
         private _microsurfaceTextureLods: Vector2 = new Vector2(0.0, 0.0);
@@ -440,10 +408,19 @@
          */
         @serialize()
         public parallaxScaleBias = 0.05;
-
+        
+        /**
+         * If sets to true, disables all the lights affecting the material.
+         */
         @serialize()
         public disableLighting = false;
 
+        /**
+         * Number of Simultaneous lights allowed on the material.
+         */
+        @serialize()
+        public maxSimultaneousLights = 4;  
+
         private _renderTargets = new SmartArray<RenderTargetTexture>(16);
         private _worldViewProjectionMatrix = Matrix.Zero();
         private _globalAmbientColor = new Color3(0, 0, 0);
@@ -546,9 +523,8 @@
         private static _scaledReflectivity = new Color3();
         private static _scaledEmissive = new Color3();
         private static _scaledReflection = new Color3();
-        private static _lightRadiuses = [1, 1, 1, 1];
 
-        public static BindLights(scene: Scene, mesh: AbstractMesh, effect: Effect, defines: MaterialDefines, useScalarInLinearSpace: boolean) {
+        public static BindLights(scene: Scene, mesh: AbstractMesh, effect: Effect, defines: MaterialDefines, useScalarInLinearSpace: boolean, maxSimultaneousLights: number, usePhysicalLightFalloff: boolean) {
             var lightIndex = 0;
             var depthValuesAlreadySet = false;
             for (var index = 0; index < scene.lights.length; index++) {
@@ -562,15 +538,13 @@
                     continue;
                 }
 
-                this._lightRadiuses[lightIndex] = light.radius;
-
                 MaterialHelper.BindLightProperties(light, effect, lightIndex);
 
                 // GAMMA CORRECTION.
                 this.convertColorToLinearSpaceToRef(light.diffuse, PBRMaterial._scaledAlbedo, useScalarInLinearSpace);
 
                 PBRMaterial._scaledAlbedo.scaleToRef(light.intensity, PBRMaterial._scaledAlbedo);
-                effect.setColor4("vLightDiffuse" + lightIndex, PBRMaterial._scaledAlbedo, light.range);
+                effect.setColor4("vLightDiffuse" + lightIndex, PBRMaterial._scaledAlbedo, usePhysicalLightFalloff ? light.radius : light.range);
 
                 if (defines["SPECULARTERM"]) {
                     this.convertColorToLinearSpaceToRef(light.specular, PBRMaterial._scaledReflectivity, useScalarInLinearSpace);
@@ -589,11 +563,6 @@
                 if (lightIndex === maxSimultaneousLights)
                     break;
             }
-
-            effect.setFloat4("vLightRadiuses", this._lightRadiuses[0],
-                this._lightRadiuses[1],
-                this._lightRadiuses[2],
-                this._lightRadiuses[3]);
         }
 
         public isReady(mesh?: AbstractMesh, useInstances?: boolean): boolean {
@@ -842,7 +811,7 @@
             }
 
             if (scene.lightsEnabled && !this.disableLighting) {
-                needNormals = MaterialHelper.PrepareDefinesForLights(scene, mesh, this._defines) || needNormals;
+                needNormals = MaterialHelper.PrepareDefinesForLights(scene, mesh, this._defines, this.maxSimultaneousLights) || needNormals;
             }
 
             if (StandardMaterial.FresnelEnabled) {
@@ -954,7 +923,7 @@
                     fallbacks.addFallback(0, "LOGARITHMICDEPTH");
                 }
 
-                MaterialHelper.HandleFallbacksForShadows(this._defines, fallbacks);
+                MaterialHelper.HandleFallbacksForShadows(this._defines, fallbacks, this.maxSimultaneousLights);
 
                 if (this._defines.SPECULARTERM) {
                     fallbacks.addFallback(0, "SPECULARTERM");
@@ -1004,31 +973,32 @@
                     shaderName = "legacypbr";
                 }
                 var join = this._defines.toString();
-                this._effect = scene.getEngine().createEffect(shaderName,
-                    attribs,
-                    ["world", "view", "viewProjection", "vEyePosition", "vLightsType", "vAmbientColor", "vAlbedoColor", "vReflectivityColor", "vEmissiveColor", "vReflectionColor",
-                        "vLightData0", "vLightDiffuse0", "vLightSpecular0", "vLightDirection0", "vLightGround0", "lightMatrix0",
-                        "vLightData1", "vLightDiffuse1", "vLightSpecular1", "vLightDirection1", "vLightGround1", "lightMatrix1",
-                        "vLightData2", "vLightDiffuse2", "vLightSpecular2", "vLightDirection2", "vLightGround2", "lightMatrix2",
-                        "vLightData3", "vLightDiffuse3", "vLightSpecular3", "vLightDirection3", "vLightGround3", "lightMatrix3",
+                
+                var uniforms = ["world", "view", "viewProjection", "vEyePosition", "vLightsType", "vAmbientColor", "vAlbedoColor", "vReflectivityColor", "vEmissiveColor", "vReflectionColor",
                         "vFogInfos", "vFogColor", "pointSize",
                         "vAlbedoInfos", "vAmbientInfos", "vOpacityInfos", "vReflectionInfos", "vEmissiveInfos", "vReflectivityInfos", "vBumpInfos", "vLightmapInfos", "vRefractionInfos",
                         "mBones",
                         "vClipPlane", "albedoMatrix", "ambientMatrix", "opacityMatrix", "reflectionMatrix", "emissiveMatrix", "reflectivityMatrix", "bumpMatrix", "lightmapMatrix", "refractionMatrix",
-                        "shadowsInfo0", "shadowsInfo1", "shadowsInfo2", "shadowsInfo3", "depthValues",
+                        "depthValues",
                         "opacityParts", "emissiveLeftColor", "emissiveRightColor",
-                        "vLightingIntensity", "vOverloadedShadowIntensity", "vOverloadedIntensity", "vCameraInfos", "vOverloadedAlbedo", "vOverloadedReflection", "vOverloadedReflectivity", "vOverloadedEmissive", "vOverloadedMicroSurface",
+                        "vLightingIntensity", "vOverloadedShadowIntensity", "vOverloadedIntensity", "vOverloadedAlbedo", "vOverloadedReflection", "vOverloadedReflectivity", "vOverloadedEmissive", "vOverloadedMicroSurface",
                         "logarithmicDepthConstant",
                         "vSphericalX", "vSphericalY", "vSphericalZ",
                         "vSphericalXX", "vSphericalYY", "vSphericalZZ",
                         "vSphericalXY", "vSphericalYZ", "vSphericalZX",
-                        "vMicrosurfaceTextureLods", "vLightRadiuses"
-                    ],
+                        "vMicrosurfaceTextureLods",
+                        "vCameraInfos", "vCameraColorGradingInfos", "vCameraColorGradingScaleOffset"
+                    ];
+                
+                MaterialHelper.PrepareUniformsListForList(uniforms, this._defines, this.maxSimultaneousLights); 
+                
+                this._effect = scene.getEngine().createEffect(shaderName,
+                    attribs, uniforms,
                     ["albedoSampler", "ambientSampler", "opacitySampler", "reflectionCubeSampler", "reflection2DSampler", "emissiveSampler", "reflectivitySampler", "bumpSampler", "lightmapSampler", "refractionCubeSampler", "refraction2DSampler",
                         "shadowSampler0", "shadowSampler1", "shadowSampler2", "shadowSampler3",
                         "cameraColorGrading2DSampler"
                     ],
-                    join, fallbacks, this.onCompiled, this.onError);
+                    join, fallbacks, this.onCompiled, this.onError, {maxSimultaneousLights: this.maxSimultaneousLights});
             }
             if (!this._effect.isReady()) {
                 return false;
@@ -1208,8 +1178,31 @@
                     
                     if (this.cameraColorGradingTexture) {
                         this._effect.setTexture("cameraColorGrading2DSampler", this.cameraColorGradingTexture);
-                        this._cameraInfos.z = this.cameraColorGradingTexture.level;
-                        this._cameraInfos.w = this.cameraColorGradingTexture.getSize().height;
+                        
+                        this._cameraColorGradingInfos.x = this.cameraColorGradingTexture.level;                     // Texture Level
+                        this._cameraColorGradingInfos.y = this.cameraColorGradingTexture.getSize().height;          // Texture Size example with 8
+                        this._cameraColorGradingInfos.z = this._cameraColorGradingInfos.y - 1.0;                    // SizeMinusOne 8 - 1
+                        this._cameraColorGradingInfos.w = 1 / this._cameraColorGradingInfos.y;                      // Space of 1 slice 1 / 8
+                        
+                        this._effect.setFloat4("vCameraColorGradingInfos", 
+                            this._cameraColorGradingInfos.x,
+                            this._cameraColorGradingInfos.y,
+                            this._cameraColorGradingInfos.z,
+                            this._cameraColorGradingInfos.w);
+                        
+                        var slicePixelSizeU = this._cameraColorGradingInfos.w / this._cameraColorGradingInfos.y;    // Space of 1 pixel in U direction, e.g. 1/64
+                        var slicePixelSizeV = 1.0 / this._cameraColorGradingInfos.y;							    // Space of 1 pixel in V direction, e.g. 1/8
+                        this._cameraColorGradingScaleOffset.x = this._cameraColorGradingInfos.z * slicePixelSizeU;  // Extent of lookup range in U for a single slice so that range corresponds to (size-1) texels, for example 7/64
+                        this._cameraColorGradingScaleOffset.y = this._cameraColorGradingInfos.z / 
+                            this._cameraColorGradingInfos.y;							                            // Extent of lookup range in V for a single slice so that range corresponds to (size-1) texels, for example 7/8
+                        this._cameraColorGradingScaleOffset.z = 0.5 * slicePixelSizeU;						        // Offset of lookup range in U to align sample position with texel centre, for example 0.5/64 
+                        this._cameraColorGradingScaleOffset.w = 0.5 * slicePixelSizeV;						        // Offset of lookup range in V to align sample position with texel centre, for example 0.5/8
+                        
+                        this._effect.setFloat4("vCameraColorGradingScaleOffset", 
+                            this._cameraColorGradingScaleOffset.x,
+                            this._cameraColorGradingScaleOffset.y,
+                            this._cameraColorGradingScaleOffset.z,
+                            this._cameraColorGradingScaleOffset.w);
                     }
                 }
 
@@ -1247,7 +1240,7 @@
 
                 // Lights
                 if (this._myScene.lightsEnabled && !this.disableLighting) {
-                    PBRMaterial.BindLights(this._myScene, mesh, this._effect, this._defines, this.useScalarInLinearSpace);
+                    PBRMaterial.BindLights(this._myScene, mesh, this._effect, this._defines, this.useScalarInLinearSpace, this.maxSimultaneousLights, this.usePhysicalLightFalloff);
                 }
 
                 // View

+ 32 - 21
src/Shaders/ShadersInclude/pbrFunctions.fx

@@ -118,11 +118,15 @@ float computeDiffuseTerm(float NdotL, float NdotV, float VdotH, float roughness)
 
 float adjustRoughnessFromLightProperties(float roughness, float lightRadius, float lightDistance)
 {
-    // At small angle this approximation works. 
-    float lightRoughness = lightRadius / lightDistance;
-    // Distribution can sum.
-    float totalRoughness = clamp(lightRoughness + roughness, 0., 1.);
-    return totalRoughness;
+    #ifdef USEPHYSICALLIGHTFALLOFF
+        // At small angle this approximation works. 
+        float lightRoughness = lightRadius / lightDistance;
+        // Distribution can sum.
+        float totalRoughness = clamp(lightRoughness + roughness, 0., 1.);
+        return totalRoughness;
+    #else
+        return roughness;
+    #endif
 }
 
 float computeDefaultMicroSurface(float microSurface, vec3 reflectivityColor)
@@ -197,23 +201,30 @@ float computeLightFalloff(vec3 lightOffset, float lightDistanceSquared, float ra
 #endif
 
 #ifdef CAMERACOLORGRADING
-    vec4 colorGrades(vec4 color, sampler2D lut, float level, float lutSize)
+    vec4 colorGrades(vec4 color, sampler2D texture, vec4 vCameraColorGradingInfos, vec4 vCameraColorGradingScaleOffset) 
     {
-        color = clamp(color, 0.0, 1.0);
-        vec2 uv = color.rg;
-        
-        float blueIndex = color.b / lutSize;
-        float fl = floor(blueIndex);
-        float fr = fract(blueIndex);
-        
-        uv.x += fl;
-        vec3 colorTransformInputLowerBound = texture2D(lut, uv).rgb;
-        uv.x += (1.0 / lutSize);
-        vec3 colorTransformInputUpperBound = texture2D(lut, uv).rgb;
-        
-        vec3 result = mix(colorTransformInputLowerBound, colorTransformInputUpperBound, fr);
-        
-        color.rgb = mix(color.rgb, result, level);
+        // Dynamic runtime calculations (dependent on input color)
+        float sliceContinuous = color.z * vCameraColorGradingInfos.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; 
+
+        // Calculate UV offset from slice origin (top-left)
+        vec2 sliceUV = color.xy * vCameraColorGradingScaleOffset.xy + vCameraColorGradingScaleOffset.zw;
+
+        // Calculate UV positions into overall texture for neighbouring slices 
+        // (to emulate trilinear filtering on missing 3D hardware texture support)
+        sliceUV.x += sliceInteger * vCameraColorGradingInfos.w;
+        vec4 slice0Color = texture2D(texture, sliceUV);
+
+        sliceUV.x += vCameraColorGradingInfos.w;
+        vec4 slice1Color = texture2D(texture, sliceUV);
+
+        vec3 result = mix(slice0Color.rgb, slice1Color.rgb, sliceFraction);
+        color.rgb = mix(color.rgb, result, vCameraColorGradingInfos.x);
+
         return color;
     }
 #endif

+ 7 - 7
src/Shaders/ShadersInclude/pbrLightFunctions.fx

@@ -7,7 +7,7 @@ struct lightingInfo
     #endif
 };
 
-lightingInfo computeLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec3 diffuseColor, vec3 specularColor, float range, float roughness, float NdotV, float lightRadius, out float NdotL) {
+lightingInfo computeLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec3 diffuseColor, vec3 specularColor, float rangeRadius, float roughness, float NdotV, out float NdotL) {
     lightingInfo result;
 
     vec3 lightDirection;
@@ -19,7 +19,7 @@ lightingInfo computeLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData,
     {
         vec3 lightOffset = lightData.xyz - vPositionW;
         float lightDistanceSquared = dot(lightOffset, lightOffset);
-        attenuation = computeLightFalloff(lightOffset, lightDistanceSquared, range);
+        attenuation = computeLightFalloff(lightOffset, lightDistanceSquared, rangeRadius);
         
         lightDistance = sqrt(lightDistanceSquared);
         lightDirection = normalize(lightOffset);
@@ -32,7 +32,7 @@ lightingInfo computeLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData,
     }
     
     // Roughness
-    roughness = adjustRoughnessFromLightProperties(roughness, lightRadius, lightDistance);
+    roughness = adjustRoughnessFromLightProperties(roughness, rangeRadius, lightDistance);
     
     // diffuse
     vec3 H = normalize(viewDirectionW + lightDirection);
@@ -53,7 +53,7 @@ lightingInfo computeLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData,
     return result;
 }
 
-lightingInfo computeSpotLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec4 lightDirection, vec3 diffuseColor, vec3 specularColor, float range, float roughness, float NdotV, float lightRadius, out float NdotL) {
+lightingInfo computeSpotLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec4 lightDirection, vec3 diffuseColor, vec3 specularColor, float rangeRadius, float roughness, float NdotV, out float NdotL) {
     lightingInfo result;
 
     vec3 lightOffset = lightData.xyz - vPositionW;
@@ -68,14 +68,14 @@ lightingInfo computeSpotLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightDa
         
         // Inverse squared falloff.
         float lightDistanceSquared = dot(lightOffset, lightOffset);
-        float attenuation = computeLightFalloff(lightOffset, lightDistanceSquared, range);
+        float attenuation = computeLightFalloff(lightOffset, lightDistanceSquared, rangeRadius);
         
         // Directional falloff.
         attenuation *= cosAngle;
         
         // Roughness.
         float lightDistance = sqrt(lightDistanceSquared);
-        roughness = adjustRoughnessFromLightProperties(roughness, lightRadius, lightDistance);
+        roughness = adjustRoughnessFromLightProperties(roughness, rangeRadius, lightDistance);
         
         // Diffuse
         vec3 H = normalize(viewDirectionW - lightDirection.xyz);
@@ -104,7 +104,7 @@ lightingInfo computeSpotLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightDa
     return result;
 }
 
-lightingInfo computeHemisphericLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec3 diffuseColor, vec3 specularColor, vec3 groundColor, float roughness, float NdotV, float lightRadius, out float NdotL) {
+lightingInfo computeHemisphericLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec3 diffuseColor, vec3 specularColor, vec3 groundColor, float roughness, float NdotV, out float NdotL) {
     lightingInfo result;
 
     // Roughness

+ 3 - 3
src/Shaders/ShadersInclude/pbrLightFunctionsCall.fx

@@ -3,13 +3,13 @@
         vec3 vLightSpecular{X} = vec3(0.0);
     #endif
     #ifdef SPOTLIGHT{X}
-        info = computeSpotLighting(viewDirectionW, normalW, vLightData{X}, vLightDirection{X}, vLightDiffuse{X}.rgb, vLightSpecular{X}, vLightDiffuse{X}.a, roughness, NdotV, vLightRadiuses[{X}], NdotL);
+        info = computeSpotLighting(viewDirectionW, normalW, vLightData{X}, vLightDirection{X}, vLightDiffuse{X}.rgb, vLightSpecular{X}, vLightDiffuse{X}.a, roughness, NdotV, NdotL);
     #endif
     #ifdef HEMILIGHT{X}
-        info = computeHemisphericLighting(viewDirectionW, normalW, vLightData{X}, vLightDiffuse{X}.rgb, vLightSpecular{X}, vLightGround{X}, roughness, NdotV, vLightRadiuses[{X}], NdotL);
+        info = computeHemisphericLighting(viewDirectionW, normalW, vLightData{X}, vLightDiffuse{X}.rgb, vLightSpecular{X}, vLightGround{X}, roughness, NdotV, NdotL);
     #endif
     #if defined(POINTLIGHT{X}) || defined(DIRLIGHT{X})
-        info = computeLighting(viewDirectionW, normalW, vLightData{X}, vLightDiffuse{X}.rgb, vLightSpecular{X}, vLightDiffuse{X}.a, roughness, NdotV, vLightRadiuses[{X}], NdotL);
+        info = computeLighting(viewDirectionW, normalW, vLightData{X}, vLightDiffuse{X}.rgb, vLightSpecular{X}, vLightDiffuse{X}.a, roughness, NdotV, NdotL);
     #endif
     
     #ifdef SHADOW{X}

+ 14 - 3
src/Shaders/legacypbr.fragment.fx

@@ -8,7 +8,6 @@ uniform vec3 vEyePosition;
 uniform vec3 vAmbientColor;
 uniform vec4 vAlbedoColor;
 uniform vec3 vReflectionColor;
-uniform vec4 vLightRadiuses;
 
 // CUSTOM CONTROLS
 uniform vec4 vLightingIntensity;
@@ -43,7 +42,7 @@ varying vec4 vColor;
 #endif
 
 // Lights
-#include<lightFragmentDeclaration>[0..3]
+#include<lightFragmentDeclaration>[0..maxSimultaneousLights]
 
 // Samplers
 #ifdef ALBEDO
@@ -84,6 +83,12 @@ uniform sampler2D reflectivitySampler;
 
 #include<clipPlaneFragmentDeclaration>
 
+#ifdef CAMERACOLORGRADING
+    uniform sampler2D cameraColorGrading2DSampler;
+    uniform vec4 vCameraColorGradingInfos;
+    uniform vec4 vCameraColorGradingScaleOffset;
+#endif
+
 // PBR
 #include<pbrFunctions>
 #include<harmonicsFunctions>
@@ -200,7 +205,7 @@ void main(void) {
     float NdotL = -1.;
     lightingInfo info;
 
-#include<pbrLightFunctionsCall>[0..3]
+#include<pbrLightFunctionsCall>[0..maxSimultaneousLights]
 
 #ifdef SPECULARTERM
     lightSpecularContribution *= vLightingIntensity.w;
@@ -316,5 +321,11 @@ vec3 surfaceEmissiveColor = vEmissiveColor;
     finalColor = contrasts(finalColor);
 #endif
 
+    finalColor.rgb = clamp(finalColor.rgb, 0., 1.);
+    
+#ifdef CAMERACOLORGRADING
+    finalColor = colorGrades(finalColor, cameraColorGrading2DSampler, vCameraColorGradingInfos, vCameraColorGradingScaleOffset);
+#endif
+
     gl_FragColor = finalColor;
 }

+ 8 - 5
src/Shaders/pbr.fragment.fx

@@ -16,7 +16,6 @@ uniform vec3 vEyePosition;
 uniform vec3 vAmbientColor;
 uniform vec3 vReflectionColor;
 uniform vec4 vAlbedoColor;
-uniform vec4 vLightRadiuses;
 
 // CUSTOM CONTROLS
 uniform vec4 vLightingIntensity;
@@ -55,7 +54,7 @@ varying vec4 vColor;
 #endif
 
 // Lights
-#include<lightFragmentDeclaration>[0..3]
+#include<lightFragmentDeclaration>[0..maxSimultaneousLights]
 
 // Samplers
 #ifdef ALBEDO
@@ -151,6 +150,8 @@ uniform vec4 emissiveRightColor;
 
 #ifdef CAMERACOLORGRADING
     uniform sampler2D cameraColorGrading2DSampler;
+    uniform vec4 vCameraColorGradingInfos;
+    uniform vec4 vCameraColorGradingScaleOffset;
 #endif
 
 // PBR
@@ -281,7 +282,7 @@ void main(void) {
     float NdotL = -1.;
     lightingInfo info;
 
-#include<pbrLightFunctionsCall>[0..3]
+#include<pbrLightFunctionsCall>[0..maxSimultaneousLights]
 
 #ifdef SPECULARTERM
     lightSpecularContribution *= vLightingIntensity.w;
@@ -594,9 +595,11 @@ vec3 surfaceEmissiveColor = vEmissiveColor;
 #ifdef CAMERACONTRAST
     finalColor = contrasts(finalColor);
 #endif
-
+    
+    finalColor.rgb = clamp(finalColor.rgb, 0., 1.);
+    
 #ifdef CAMERACOLORGRADING
-    finalColor = colorGrades(finalColor, cameraColorGrading2DSampler, vCameraInfos.z, vCameraInfos.w);
+    finalColor = colorGrades(finalColor, cameraColorGrading2DSampler, vCameraColorGradingInfos, vCameraColorGradingScaleOffset);
 #endif
 
     // Normal Display.

+ 7 - 0
src/babylon.engine.ts

@@ -1535,6 +1535,10 @@
             var internalFormat = this._getInternalFormat(format);
             this._gl.bindTexture(this._gl.TEXTURE_2D, texture);
             this._gl.pixelStorei(this._gl.UNPACK_FLIP_Y_WEBGL, invertY === undefined ? 1 : (invertY ? 1 : 0));
+            
+            if (texture._width % 4 !== 0) {
+                this._gl.pixelStorei(this._gl.UNPACK_ALIGNMENT, 1);
+            } 
 
             if (compression) {
                 this._gl.compressedTexImage2D(this._gl.TEXTURE_2D, 0, this.getCaps().s3tc[compression], texture._width, texture._height, 0, data);
@@ -1915,6 +1919,9 @@
         public updateTextureSize(texture: WebGLTexture, width: number, height: number) {
             texture._width = width;
             texture._height = height;
+            texture._size = width * height;
+            texture._baseWidth = width;
+            texture._baseHeight = height;
         }
 
         public createRawCubeTexture(url: string, scene: Scene, size: number, format: number, type: number, noMipmap: boolean,