Selaa lähdekoodia

Add photometric scale and light intensity mode

Sebastien Vandenberghe 8 vuotta sitten
vanhempi
commit
1c7a8c7091

+ 35 - 0
materialsLibrary/index.html

@@ -334,6 +334,41 @@
                     pointLight.intensity = options.lightIntensity;
                     spotLight.intensity = options.lightIntensity;
                 });
+
+				f1.add(options, 'lightIntensityMode', ['automatic', 'luminousPower', 'luminousIntensity', 'illuminance', 'luminance']).onFinishChange(function() {
+					switch (options.lightIntensityMode) {
+						case "automatic":
+							hemisphericLight.intensityMode = BABYLON.Light.INTENSITYMODE_AUTOMATIC;
+							directionalLight.intensityMode = BABYLON.Light.INTENSITYMODE_AUTOMATIC;
+							pointLight.intensityMode = BABYLON.Light.INTENSITYMODE_AUTOMATIC;
+							spotLight.intensityMode = BABYLON.Light.INTENSITYMODE_AUTOMATIC;
+							break;
+						case "luminousPower":
+							hemisphericLight.intensityMode = BABYLON.Light.INTENSITYMODE_LUMINOUSPOWER;
+							directionalLight.intensityMode = BABYLON.Light.INTENSITYMODE_LUMINOUSPOWER;
+							pointLight.intensityMode = BABYLON.Light.INTENSITYMODE_LUMINOUSPOWER;
+							spotLight.intensityMode = BABYLON.Light.INTENSITYMODE_LUMINOUSPOWER;
+							break;
+						case "luminousIntensity":
+							hemisphericLight.intensityMode = BABYLON.Light.INTENSITYMODE_LUMINOUSINTENSITY;
+							directionalLight.intensityMode = BABYLON.Light.INTENSITYMODE_LUMINOUSINTENSITY;
+							pointLight.intensityMode = BABYLON.Light.INTENSITYMODE_LUMINOUSINTENSITY;
+							spotLight.intensityMode = BABYLON.Light.INTENSITYMODE_LUMINOUSINTENSITY;
+							break;
+						case "illuminance":
+							hemisphericLight.intensityMode = BABYLON.Light.INTENSITYMODE_ILLUMINANCE;
+							directionalLight.intensityMode = BABYLON.Light.INTENSITYMODE_ILLUMINANCE;
+							pointLight.intensityMode = BABYLON.Light.INTENSITYMODE_ILLUMINANCE;
+							spotLight.intensityMode = BABYLON.Light.INTENSITYMODE_ILLUMINANCE;
+							break;
+						case "luminance":
+							hemisphericLight.intensityMode = BABYLON.Light.INTENSITYMODE_LUMINANCE;
+							directionalLight.intensityMode = BABYLON.Light.INTENSITYMODE_LUMINANCE;
+							pointLight.intensityMode = BABYLON.Light.INTENSITYMODE_LUMINANCE;
+							spotLight.intensityMode = BABYLON.Light.INTENSITYMODE_LUMINANCE;
+							break;
+					}
+                });
                 
                 f1.add(options, 'lightRange').onChange(function() {
                     hemisphericLight.range = options.lightRange;

+ 1 - 0
materialsLibrary/test/index.js

@@ -11,6 +11,7 @@ var options = {
 	fog: false,
 	skybox: false,
     lightIntensity: 1.0,
+	lightIntensityMode: 0,
     lightRange: 1000,
     lightRadius: 0.0000001
 }

+ 156 - 5
src/Lights/babylon.light.ts

@@ -58,6 +58,84 @@
             return Light._LIGHTMAP_SHADOWSONLY;
         }
 
+        // Intensity Mode Consts
+        private static _INTENSITYMODE_AUTOMATIC = 0;
+        private static _INTENSITYMODE_LUMINOUSPOWER = 1;
+        private static _INTENSITYMODE_LUMINOUSINTENSITY = 2;
+        private static _INTENSITYMODE_ILLUMINANCE = 3;
+        private static _INTENSITYMODE_LUMINANCE = 4;
+
+        /**
+         * Each light type uses the default quantity according to its type:
+         *      point/spot lights use luminous intensity
+         *      directional lights use illuminance
+         */
+        public static get INTENSITYMODE_AUTOMATIC(): number {
+            return Light._INTENSITYMODE_AUTOMATIC;
+        }
+
+        /**
+         * lumen (lm)
+         */
+        public static get INTENSITYMODE_LUMINOUSPOWER(): number {
+            return Light._INTENSITYMODE_LUMINOUSPOWER;
+        }
+
+        /**
+         * candela (lm/sr)
+         */
+        public static get INTENSITYMODE_LUMINOUSINTENSITY(): number {
+            return Light._INTENSITYMODE_LUMINOUSINTENSITY;
+        }
+
+        /**
+         * lux (lm/m^2)
+         */
+        public static get INTENSITYMODE_ILLUMINANCE(): number {
+            return Light._INTENSITYMODE_ILLUMINANCE;
+        }
+
+        /**
+         * nit (cd/m^2)
+         */
+        public static get INTENSITYMODE_LUMINANCE(): number {
+            return Light._INTENSITYMODE_LUMINANCE;
+        }
+
+        // Light types ids const.
+        private static _LIGHTTYPEID_POINTLIGHT = 0;
+        private static _LIGHTTYPEID_DIRECTIONALLIGHT = 1;
+        private static _LIGHTTYPEID_SPOTLIGHT = 2;
+        private static _LIGHTTYPEID_HEMISPHERICLIGHT = 3;
+
+        /**
+         * Light type const id of the point light.
+         */
+        public static get LIGHTTYPEID_POINTLIGHT(): number {
+            return Light._LIGHTTYPEID_POINTLIGHT;
+        }
+
+        /**
+         * Light type const id of the directional light.
+         */
+        public static get LIGHTTYPEID_DIRECTIONALLIGHT(): number {
+            return Light._LIGHTTYPEID_DIRECTIONALLIGHT;
+        }
+
+        /**
+         * Light type const id of the spot light.
+         */
+        public static get LIGHTTYPEID_SPOTLIGHT(): number {
+            return Light._LIGHTTYPEID_SPOTLIGHT;
+        }
+
+        /**
+         * Light type const id of the hemispheric light.
+         */
+        public static get LIGHTTYPEID_HEMISPHERICLIGHT(): number {
+            return Light._LIGHTTYPEID_HEMISPHERICLIGHT;
+        }
+
         @serializeAsColor3()
         public diffuse = new Color3(1.0, 1.0, 1.0);
 
@@ -70,6 +148,16 @@
         @serialize()
         public range = Number.MAX_VALUE;
 
+        /**
+         * Defines the photometric scale used to interpret intensity.
+         * This is only relevant with PBR Materials where the light intensity can be defined in a physical way.
+         */
+        @serialize()
+        public intensityMode: number = Light.INTENSITYMODE_AUTOMATIC;
+
+        @serialize()
+        public radius = 0.00001;
+
         private _includedOnlyMeshes: AbstractMesh[];
         public get includedOnlyMeshes(): AbstractMesh[] {
             return this._includedOnlyMeshes;
@@ -124,11 +212,7 @@
             
             this._lightmapMode = value;
             this._markMeshesAsLightDirty();
-        }    
-
-        // PBR Properties.
-        @serialize()
-        public radius = 0.00001;
+        }
 
         public _shadowGenerator: IShadowGenerator;
         private _parentedWorldMatrix: Matrix;
@@ -296,6 +380,73 @@
         }
 
         /**
+         * Returns the intensity scaled by the Photometric Scale according to the light type and intensity mode.
+         */
+        public getScaledIntensity() {
+            let photometricScale = this.getPhotometricScale();
+            return photometricScale * this.intensity;
+        }
+
+        /**
+         * Returns the Photometric Scale according to the light type and intensity mode.
+         */
+        public getPhotometricScale() {
+            let photometricScale = 0.0;
+            let lightTypeID = this.getTypeID();
+
+            //get photometric mode
+            let photometricMode = this.intensityMode;
+            if (photometricMode === Light.INTENSITYMODE_AUTOMATIC) {
+                if (lightTypeID === Light.LIGHTTYPEID_DIRECTIONALLIGHT) {
+                    photometricMode = Light.INTENSITYMODE_ILLUMINANCE;
+                } else {
+                    photometricMode = Light.INTENSITYMODE_LUMINOUSINTENSITY;
+                }
+            }
+
+            //compute photometric scale
+            switch (lightTypeID) {
+                case Light.LIGHTTYPEID_POINTLIGHT:
+                case Light.LIGHTTYPEID_SPOTLIGHT:
+                    switch (photometricMode) {
+                        case Light.INTENSITYMODE_LUMINOUSPOWER:
+                            photometricScale = 1.0 / (4.0 * Math.PI);
+                            break;
+                        case Light.INTENSITYMODE_LUMINOUSINTENSITY:
+                            photometricScale = 1.0;
+                            break;
+                        case Light.INTENSITYMODE_LUMINANCE:
+                            photometricScale = this.radius * this.radius;
+                            break;
+                    }
+                    break;
+
+                case Light.LIGHTTYPEID_DIRECTIONALLIGHT:
+                    switch (photometricMode) {
+                        case Light.INTENSITYMODE_ILLUMINANCE:
+                            photometricScale = 1.0;
+                            break;
+                        case Light.INTENSITYMODE_LUMINANCE:
+                            // When radius (and therefore solid angle) is non-zero a directional lights brightness can be specified via central (peak) luminance.
+                            // For a directional light the 'radius' defines the angular radius (in radians) rather than world-space radius (e.g. in metres).
+                            let apexAngleRadians = this.radius;
+                            // Impose a minimum light angular size to avoid the light becoming an infinitely small angular light source (i.e. a dirac delta function).
+                            apexAngleRadians = Math.max(apexAngleRadians, 0.001);
+                            let solidAngle = 2.0 * Math.PI * (1.0 - Math.cos(apexAngleRadians));
+                            photometricScale = solidAngle;
+                            break;
+                    }
+                    break;
+
+                case Light.LIGHTTYPEID_HEMISPHERICLIGHT:
+                    // No fall off in hemisperic light.
+                    photometricScale = 1.0;
+                    break;
+            }
+            return photometricScale;
+        }
+
+        /**
          * Returns a new Light object, named "name", from the current one.  
          */
         public clone(name: string): Light {

+ 1 - 1
src/Lights/babylon.spotLight.ts

@@ -155,7 +155,7 @@
                     this.position.y,
                     this.position.z,
                     this.exponent,
-                    lightIndex);                    
+                    lightIndex);
 
                 normalizeDirection = Vector3.Normalize(this.direction);
             }

+ 4 - 3
src/Materials/PBR/babylon.pbrBaseMaterial.ts

@@ -492,7 +492,8 @@
             var lightIndex = 0;
             var depthValuesAlreadySet = false;
             for (var light of mesh._lightSources) {
-                var useUbo = light._uniformBuffer.useUbo;
+                let useUbo = light._uniformBuffer.useUbo;
+                let scaledIntensity = light.getScaledIntensity();
 
                 light._uniformBuffer.bindToEffect(effect, "Light" + lightIndex);
                 MaterialHelper.BindLightProperties(light, effect, lightIndex);
@@ -500,13 +501,13 @@
                 // GAMMA CORRECTION.
                 this.convertColorToLinearSpaceToRef(light.diffuse, PBRMaterial._scaledAlbedo, useScalarInLinearSpace);
 
-                PBRMaterial._scaledAlbedo.scaleToRef(light.intensity, PBRMaterial._scaledAlbedo);
+                PBRMaterial._scaledAlbedo.scaleToRef(scaledIntensity, PBRMaterial._scaledAlbedo);
                 light._uniformBuffer.updateColor4(useUbo ? "vLightDiffuse" : "vLightDiffuse" + lightIndex, PBRMaterial._scaledAlbedo, usePhysicalLightFalloff ? light.radius : light.range);
 
                 if (defines["SPECULARTERM"]) {
                     this.convertColorToLinearSpaceToRef(light.specular, PBRMaterial._scaledReflectivity, useScalarInLinearSpace);
 
-                    PBRMaterial._scaledReflectivity.scaleToRef(light.intensity, PBRMaterial._scaledReflectivity);
+                    PBRMaterial._scaledReflectivity.scaleToRef(scaledIntensity, PBRMaterial._scaledReflectivity);
                     light._uniformBuffer.updateColor3(useUbo ? "vLightSpecular" : "vLightSpecular" + lightIndex, PBRMaterial._scaledReflectivity);
                 }