Explorar el Código

Add legacy PBR

Sebastien Vandenberghe hace 8 años
padre
commit
886fd3a698

+ 4 - 2
Tools/DevLoader/BabylonLoader.js

@@ -155,9 +155,11 @@ var BABYLONDEVTOOLS;
                     var endDirectoryIndex = shaderFile.lastIndexOf('/');
                     shaderFile = shaderFile.substring(0, endDirectoryIndex + 1);
                     shaderFile += library.output.replace('.js', '.js.fx');
-                    file = file.replace('../', '');
-                    file = babylonJSPath + '/' + file;
                     this.loadScript(shaderFile);
+                    if (library.shadersIncludeFiles) {
+                        var includeShaderFile = shaderFile.replace('.js.fx', '.js.include.fx');
+                        this.loadScript(includeShaderFile);
+                    }
                 }
             }
             else if (min) {

+ 18 - 0
Tools/Gulp/config.json

@@ -1065,6 +1065,24 @@
                     "../../materialsLibrary/src/cell/cell.fragment.fx"
                 ],
                 "output": "babylon.cellMaterial.js"
+            },
+            {
+                "files": [
+                    "../../materialsLibrary/src/legacyPBR/babylon.legacyPBRMaterial.ts"
+                ],
+                "shaderFiles": [
+                    "../../materialsLibrary/src/legacyPBR/legacyPbr.vertex.fx",
+                    "../../materialsLibrary/src/legacyPBR/legacyPbr.fragment.fx"
+                ],
+                "shadersIncludeFiles": [
+                    "../../materialsLibrary/src/legacyPBR/legacyPbrFragmentDeclaration.fx",
+                    "../../materialsLibrary/src/legacyPBR/legacyPbrFunctions.fx",
+                    "../../materialsLibrary/src/legacyPBR/legacyPbrLightFunctions.fx",
+                    "../../materialsLibrary/src/legacyPBR/legacyPbrLightFunctionsCall.fx",
+                    "../../materialsLibrary/src/legacyPBR/legacyPbrUboDeclaration.fx",
+                    "../../materialsLibrary/src/legacyPBR/legacyPbrVertexDeclaration.fx"
+                ],
+                "output": "babylon.legacyPbrMaterial.js"
             }
         ],
         "build": {

+ 8 - 3
Tools/Gulp/gulpfile.js

@@ -116,7 +116,7 @@ function shadersName(filename) {
 }
 
 function includeShadersName(filename) {
-    return filename.replace('.fx', '');
+    return path.basename(filename).replace('.fx', '');
 }
 
 /*
@@ -255,6 +255,11 @@ var buildExternalLibrary = function (library, settings, watch) {
         .pipe(sourcemaps.init())
         .pipe(typescript(externalTsConfig));
 
+    var includeShader = gulp.src(library.shadersIncludeFiles || [], { base: settings.build.srcOutputDirectory })
+        .pipe(uncommentShader())
+        .pipe(appendSrcToVariable("BABYLON.Effect.IncludesShadersStore", includeShadersName, library.output + '.include.fx'))
+        .pipe(gulp.dest(settings.build.srcOutputDirectory));
+
     var shader = gulp.src(library.shaderFiles || [], { base: settings.build.srcOutputDirectory })
         .pipe(uncommentShader())
         .pipe(appendSrcToVariable("BABYLON.Effect.ShadersStore", shadersName, library.output + '.fx'))
@@ -275,10 +280,10 @@ var buildExternalLibrary = function (library, settings, watch) {
         .pipe(gulp.dest(outputDirectory));
 
     if (watch) {
-        return merge2([shader, dev, css]);
+        return merge2([shader, includeShader, dev, css]);
     }
     else {
-        var code = merge2([tsProcess.js, shader])
+        var code = merge2([tsProcess.js, shader, includeShader])
             .pipe(concat(library.output))
             .pipe(gulp.dest(outputDirectory))
             .pipe(cleants())

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 3342 - 3342
dist/preview release/babylon.d.ts


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 27 - 27
dist/preview release/babylon.js


+ 8 - 1
dist/preview release/babylon.max.js

@@ -7614,7 +7614,7 @@ var BABYLON;
         });
         Object.defineProperty(Engine, "Version", {
             get: function () {
-                return "3.0-alpha";
+                return "3.0-beta";
             },
             enumerable: true,
             configurable: true
@@ -23464,6 +23464,13 @@ var BABYLON;
             if (!parsedMaterial.customType) {
                 return BABYLON.StandardMaterial.Parse(parsedMaterial, scene, rootUrl);
             }
+            if (parsedMaterial.customType === "BABYLON.PBRMaterial" && !parsedMaterial.overloadedAlbedo) {
+                parsedMaterial.customType === "BABYLON.legacyPBRMaterial";
+                if (!BABYLON.legacyPBRMaterial) {
+                    BABYLON.Tools.Error("Your scene is trying to load a legacy version of the PBRMaterial, please, include it from the materials library.");
+                    return;
+                }
+            }
             var materialType = BABYLON.Tools.Instantiate(parsedMaterial.customType);
             return materialType.Parse(parsedMaterial, scene, rootUrl);
             ;

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 3342 - 3342
dist/preview release/babylon.module.d.ts


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 27 - 27
dist/preview release/babylon.worker.js


+ 337 - 0
dist/preview release/materialsLibrary/babylon.legacyPbrMaterial.d.ts

@@ -0,0 +1,337 @@
+/// <reference path="../../../dist/preview release/babylon.d.ts" />
+declare module BABYLON {
+    /**
+     * The Physically based material of BJS.
+     *
+     * This offers the main features of a standard PBR material.
+     * For more information, please refer to the documentation :
+     * http://doc.babylonjs.com/extensions/Physically_Based_Rendering
+     */
+    class LegacyPBRMaterial extends BABYLON.Material {
+        /**
+         * Intensity of the direct lights e.g. the four lights available in your scene.
+         * This impacts both the direct diffuse and specular highlights.
+         */
+        directIntensity: number;
+        /**
+         * Intensity of the emissive part of the material.
+         * This helps controlling the emissive effect without modifying the emissive color.
+         */
+        emissiveIntensity: number;
+        /**
+         * Intensity of the environment e.g. how much the environment will light the object
+         * either through harmonics for rough material or through the refelction for shiny ones.
+         */
+        environmentIntensity: number;
+        /**
+         * This is a special control allowing the reduction of the specular highlights coming from the
+         * four lights of the scene. Those highlights may not be needed in full environment lighting.
+         */
+        specularIntensity: number;
+        private _lightingInfos;
+        /**
+         * Debug Control allowing disabling the bump map on this material.
+         */
+        disableBumpMap: boolean;
+        /**
+         * Debug Control helping enforcing or dropping the darkness of shadows.
+         * 1.0 means the shadows have their normal darkness, 0.0 means the shadows are not visible.
+         */
+        overloadedShadowIntensity: number;
+        /**
+         * Debug Control helping dropping the shading effect coming from the diffuse lighting.
+         * 1.0 means the shade have their normal impact, 0.0 means no shading at all.
+         */
+        overloadedShadeIntensity: number;
+        private _overloadedShadowInfos;
+        /**
+         * The camera exposure used on this material.
+         * This property is here and not in the camera to allow controlling exposure without full screen post process.
+         * This corresponds to a photographic exposure.
+         */
+        cameraExposure: number;
+        /**
+         * The camera contrast used on this material.
+         * This property is here and not in the camera to allow controlling contrast without full screen post process.
+         */
+        cameraContrast: number;
+        /**
+         * Color Grading 2D Lookup Texture.
+         * This allows special effects like sepia, black and white to sixties rendering style.
+         */
+        cameraColorGradingTexture: BaseTexture;
+        /**
+         * The color grading curves provide additional color adjustmnent that is applied after any color grading transform (3D LUT).
+         * They allow basic adjustment of saturation and small exposure adjustments, along with color filter tinting to provide white balance adjustment or more stylistic effects.
+         * These are similar to controls found in many professional imaging or colorist software. The global controls are applied to the entire image. For advanced tuning, extra controls are provided to adjust the shadow, midtone and highlight areas of the image;
+         * corresponding to low luminance, medium luminance, and high luminance areas respectively.
+         */
+        cameraColorCurves: ColorCurves;
+        private _cameraInfos;
+        private _microsurfaceTextureLods;
+        /**
+         * Debug Control allowing to overload the ambient color.
+         * This as to be use with the overloadedAmbientIntensity parameter.
+         */
+        overloadedAmbient: Color3;
+        /**
+         * Debug Control indicating how much the overloaded ambient color is used against the default one.
+         */
+        overloadedAmbientIntensity: number;
+        /**
+         * Debug Control allowing to overload the albedo color.
+         * This as to be use with the overloadedAlbedoIntensity parameter.
+         */
+        overloadedAlbedo: Color3;
+        /**
+         * Debug Control indicating how much the overloaded albedo color is used against the default one.
+         */
+        overloadedAlbedoIntensity: number;
+        /**
+         * Debug Control allowing to overload the reflectivity color.
+         * This as to be use with the overloadedReflectivityIntensity parameter.
+         */
+        overloadedReflectivity: Color3;
+        /**
+         * Debug Control indicating how much the overloaded reflectivity color is used against the default one.
+         */
+        overloadedReflectivityIntensity: number;
+        /**
+         * Debug Control allowing to overload the emissive color.
+         * This as to be use with the overloadedEmissiveIntensity parameter.
+         */
+        overloadedEmissive: Color3;
+        /**
+         * Debug Control indicating how much the overloaded emissive color is used against the default one.
+         */
+        overloadedEmissiveIntensity: number;
+        private _overloadedIntensity;
+        /**
+         * Debug Control allowing to overload the reflection color.
+         * This as to be use with the overloadedReflectionIntensity parameter.
+         */
+        overloadedReflection: Color3;
+        /**
+         * Debug Control indicating how much the overloaded reflection color is used against the default one.
+         */
+        overloadedReflectionIntensity: number;
+        /**
+         * Debug Control allowing to overload the microsurface.
+         * This as to be use with the overloadedMicroSurfaceIntensity parameter.
+         */
+        overloadedMicroSurface: number;
+        /**
+         * Debug Control indicating how much the overloaded microsurface is used against the default one.
+         */
+        overloadedMicroSurfaceIntensity: number;
+        private _overloadedMicroSurface;
+        /**
+         * AKA Diffuse Texture in standard nomenclature.
+         */
+        albedoTexture: BaseTexture;
+        /**
+         * AKA Occlusion Texture in other nomenclature.
+         */
+        ambientTexture: BaseTexture;
+        /**
+         * AKA Occlusion Texture Intensity in other nomenclature.
+         */
+        ambientTextureStrength: number;
+        opacityTexture: BaseTexture;
+        reflectionTexture: BaseTexture;
+        emissiveTexture: BaseTexture;
+        /**
+         * AKA Specular texture in other nomenclature.
+         */
+        reflectivityTexture: BaseTexture;
+        /**
+         * Used to switch from specular/glossiness to metallic/roughness workflow.
+         */
+        metallicTexture: BaseTexture;
+        /**
+         * Specifies the metallic scalar of the metallic/roughness workflow.
+         * Can also be used to scale the metalness values of the metallic texture.
+         */
+        metallic: number;
+        /**
+         * Specifies the roughness scalar of the metallic/roughness workflow.
+         * Can also be used to scale the roughness values of the metallic texture.
+         */
+        roughness: number;
+        /**
+         * Used to enable roughness/glossiness fetch from a separate chanel depending on the current mode.
+         * Gray Scale represents roughness in metallic mode and glossiness in specular mode.
+         */
+        microSurfaceTexture: BaseTexture;
+        bumpTexture: BaseTexture;
+        lightmapTexture: BaseTexture;
+        refractionTexture: BaseTexture;
+        ambientColor: Color3;
+        /**
+         * AKA Diffuse Color in other nomenclature.
+         */
+        albedoColor: Color3;
+        /**
+         * AKA Specular Color in other nomenclature.
+         */
+        reflectivityColor: Color3;
+        reflectionColor: Color3;
+        emissiveColor: Color3;
+        /**
+         * AKA Glossiness in other nomenclature.
+         */
+        microSurface: number;
+        /**
+         * source material index of refraction (IOR)' / 'destination material IOR.
+         */
+        indexOfRefraction: number;
+        /**
+         * Controls if refraction needs to be inverted on Y. This could be usefull for procedural texture.
+         */
+        invertRefractionY: boolean;
+        opacityFresnelParameters: FresnelParameters;
+        emissiveFresnelParameters: FresnelParameters;
+        /**
+         * This parameters will make the material used its opacity to control how much it is refracting aginst not.
+         * Materials half opaque for instance using refraction could benefit from this control.
+         */
+        linkRefractionWithTransparency: boolean;
+        /**
+         * The emissive and albedo are linked to never be more than one (Energy conservation).
+         */
+        linkEmissiveWithAlbedo: boolean;
+        useLightmapAsShadowmap: boolean;
+        /**
+         * In this mode, the emissive informtaion will always be added to the lighting once.
+         * A light for instance can be thought as emissive.
+         */
+        useEmissiveAsIllumination: boolean;
+        /**
+         * Secifies that the alpha is coming form the albedo channel alpha channel.
+         */
+        useAlphaFromAlbedoTexture: boolean;
+        /**
+         * Specifies that the material will keeps the specular highlights over a transparent surface (only the most limunous ones).
+         * A car glass is a good exemple of that. When sun reflects on it you can not see what is behind.
+         */
+        useSpecularOverAlpha: boolean;
+        /**
+         * Specifies if the reflectivity texture contains the glossiness information in its alpha channel.
+         */
+        useMicroSurfaceFromReflectivityMapAlpha: boolean;
+        /**
+         * Specifies if the metallic texture contains the roughness information in its alpha channel.
+         */
+        useRoughnessFromMetallicTextureAlpha: boolean;
+        /**
+         * Specifies if the metallic texture contains the roughness information in its green channel.
+         */
+        useRoughnessFromMetallicTextureGreen: boolean;
+        /**
+         * Specifies if the metallic texture contains the metallness information in its blue channel.
+         */
+        useMetallnessFromMetallicTextureBlue: boolean;
+        /**
+         * Specifies if the metallic texture contains the ambient occlusion information in its red channel.
+         */
+        useAmbientOcclusionFromMetallicTextureRed: boolean;
+        /**
+         * Specifies if the ambient texture contains the ambient occlusion information in its red channel only.
+         */
+        useAmbientInGrayScale: boolean;
+        /**
+         * In case the reflectivity map does not contain the microsurface information in its alpha channel,
+         * The material will try to infer what glossiness each pixel should be.
+         */
+        useAutoMicroSurfaceFromReflectivityMap: boolean;
+        /**
+         * Allows to work with scalar in linear mode. This is definitely a matter of preferences and tools used during
+         * the creation of the material.
+         */
+        useScalarInLinearSpace: boolean;
+        /**
+         * BJS is using an harcoded light falloff based on a manually sets up range.
+         * In PBR, one way to represents the fallof is to use the inverse squared root algorythm.
+         * This parameter can help you switch back to the BJS mode in order to create scenes using both materials.
+         */
+        usePhysicalLightFalloff: boolean;
+        /**
+         * Specifies that the material will keeps the reflection highlights over a transparent surface (only the most limunous ones).
+         * A car glass is a good exemple of that. When the street lights reflects on it you can not see what is behind.
+         */
+        useRadianceOverAlpha: boolean;
+        /**
+         * Allows using the bump map in parallax mode.
+         */
+        useParallax: boolean;
+        /**
+         * Allows using the bump map in parallax occlusion mode.
+         */
+        useParallaxOcclusion: boolean;
+        /**
+         * Controls the scale bias of the parallax mode.
+         */
+        parallaxScaleBias: number;
+        /**
+         * If sets to true, disables all the lights affecting the material.
+         */
+        disableLighting: boolean;
+        /**
+         * Number of Simultaneous lights allowed on the material.
+         */
+        maxSimultaneousLights: number;
+        /**
+         * If sets to true, x component of normal map value will invert (x = 1.0 - x).
+         */
+        invertNormalMapX: boolean;
+        /**
+         * If sets to true, y component of normal map value will invert (y = 1.0 - y).
+         */
+        invertNormalMapY: boolean;
+        /**
+         * If sets to true and backfaceCulling is false, normals will be flipped on the backside.
+         */
+        twoSidedLighting: boolean;
+        private _renderTargets;
+        private _worldViewProjectionMatrix;
+        private _globalAmbientColor;
+        private _tempColor;
+        private _renderId;
+        private _defines;
+        private _cachedDefines;
+        private _useLogarithmicDepth;
+        /**
+         * Instantiates a new PBRMaterial instance.
+         *
+         * @param name The material name
+         * @param scene The scene the material will be use in.
+         */
+        constructor(name: string, scene: Scene);
+        getClassName(): string;
+        useLogarithmicDepth: boolean;
+        needAlphaBlending(): boolean;
+        needAlphaTesting(): boolean;
+        private _shouldUseAlphaFromAlbedoTexture();
+        getAlphaTestTexture(): BaseTexture;
+        private _checkCache(scene, mesh?, useInstances?);
+        private convertColorToLinearSpaceToRef(color, ref);
+        private static convertColorToLinearSpaceToRef(color, ref, useScalarInLinear);
+        private static _scaledAlbedo;
+        private static _scaledReflectivity;
+        private static _scaledEmissive;
+        private static _scaledReflection;
+        static BindLights(scene: Scene, mesh: AbstractMesh, effect: Effect, defines: MaterialDefines, useScalarInLinearSpace: boolean, maxSimultaneousLights: number, usePhysicalLightFalloff: boolean): void;
+        isReady(mesh?: AbstractMesh, useInstances?: boolean): boolean;
+        buildUniformLayout(): void;
+        unbind(): void;
+        bindOnlyWorldMatrix(world: Matrix): void;
+        private _myScene;
+        private _myShadowGenerator;
+        bind(world: Matrix, mesh?: Mesh): void;
+        getAnimatables(): IAnimatable[];
+        dispose(forceDisposeEffect?: boolean, forceDisposeTextures?: boolean): void;
+        clone(name: string): LegacyPBRMaterial;
+        serialize(): any;
+        static Parse(source: any, scene: Scene, rootUrl: string): LegacyPBRMaterial;
+    }
+}

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1515 - 0
dist/preview release/materialsLibrary/babylon.legacyPbrMaterial.js


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 3 - 0
dist/preview release/materialsLibrary/babylon.legacyPbrMaterial.min.js


+ 10 - 4
materialsLibrary/index.html

@@ -48,7 +48,8 @@
 	<script src="test/addgradient.js"></script>
 	<script src="test/addsky.js"></script>
 	<script src="test/addgrid.js"></script>
-    <script src="test/addpbr.js"></script>
+	<script src="test/addpbr.js"></script>
+	<script src="test/addlegacypbr.js"></script>
 	<script src="test/addCell.js"></script>
 	
 	<script>
@@ -195,12 +196,14 @@
 				var terrain = prepareTerrain();
 
 				var pbr = preparePBR();
+
+				var legacypbr = prepareLegacyPBR();
 				
 				var triPlanar = prepareTriPlanar();
 				
 				var sky = prepareSky();
-                
-                var grid = prepareGrid();
+
+				var grid = prepareGrid();
 
 				var shadowOnly = new BABYLON.ShadowOnlyMaterial();
 
@@ -211,7 +214,7 @@
 				sphere.material = std;				
 				sphere.receiveShadows = true;
 
-				gui.add(options, 'material', ['standard', 'simple', 'water', 'fire', 'lava', 'normal', 'terrain', 'pbr', 'fur', 'triPlanar', 'gradient', 'sky', 'grid', 'shadowOnly', 'cell']).onFinishChange(function () {
+				gui.add(options, 'material', ['standard', 'simple', 'water', 'fire', 'lava', 'normal', 'terrain', 'pbr', 'legacyPbr', 'fur', 'triPlanar', 'gradient', 'sky', 'grid', 'shadowOnly', 'cell']).onFinishChange(function () {
 					water.enableRenderTargets(false);
 					skybox.material = skyboxMaterial;
 					currentMesh.isVisible = true;
@@ -244,6 +247,9 @@
 						case "pbr":
 							currentMaterial = pbr;
 							break;
+						case "legacyPbr":
+							currentMaterial = legacypbr;
+							break;
 						case "fur":
 							currentMaterial = fur.material;
 							fur.configureFur(currentMesh);

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1701 - 0
materialsLibrary/src/legacyPBR/babylon.legacyPBRMaterial.ts


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 6 - 0
materialsLibrary/src/legacyPBR/babylon.legacyPbrMaterial.js.include.fx


+ 692 - 0
materialsLibrary/src/legacyPBR/legacyPbr.fragment.fx

@@ -0,0 +1,692 @@
+#if defined(BUMP)|| !defined(NORMAL)
+#extension GL_OES_standard_derivatives : enable
+#endif
+
+#ifdef LODBASEDMICROSFURACE
+#extension GL_EXT_shader_texture_lod : enable
+#endif
+
+#ifdef LOGARITHMICDEPTH
+#extension GL_EXT_frag_depth : enable
+#endif
+
+precision highp float;
+
+#include<__decl__legacyPbrFragment>
+
+uniform vec3 vEyePosition;
+uniform vec3 vAmbientColor;
+uniform vec4 vCameraInfos;
+
+// Input
+varying vec3 vPositionW;
+
+#ifdef NORMAL
+varying vec3 vNormalW;
+#endif
+
+#ifdef VERTEXCOLOR
+varying vec4 vColor;
+#endif
+
+// Lights
+#include<__decl__lightFragment>[0..maxSimultaneousLights]
+
+// Samplers
+#ifdef ALBEDO
+varying vec2 vAlbedoUV;
+uniform sampler2D albedoSampler;
+#endif
+
+#ifdef AMBIENT
+varying vec2 vAmbientUV;
+uniform sampler2D ambientSampler;
+#endif
+
+#ifdef OPACITY	
+varying vec2 vOpacityUV;
+uniform sampler2D opacitySampler;
+#endif
+
+#ifdef EMISSIVE
+varying vec2 vEmissiveUV;
+uniform sampler2D emissiveSampler;
+#endif
+
+#ifdef LIGHTMAP
+varying vec2 vLightmapUV;
+uniform sampler2D lightmapSampler;
+#endif
+
+#if defined(REFLECTIVITY) || defined(METALLICWORKFLOW) 
+varying vec2 vReflectivityUV;
+uniform sampler2D reflectivitySampler;
+#endif
+
+#ifdef MICROSURFACEMAP
+varying vec2 vMicroSurfaceSamplerUV;
+uniform sampler2D microSurfaceSampler;
+#endif
+
+// Fresnel
+#include<fresnelFunction>
+
+// Refraction
+#ifdef REFRACTION
+
+
+#ifdef REFRACTIONMAP_3D
+uniform samplerCube refractionCubeSampler;
+#else
+uniform sampler2D refraction2DSampler;
+#endif
+#endif
+
+// Reflection
+#ifdef REFLECTION
+
+#ifdef REFLECTIONMAP_3D
+uniform samplerCube reflectionCubeSampler;
+#else
+uniform sampler2D reflection2DSampler;
+#endif
+
+#ifdef REFLECTIONMAP_SKYBOX
+varying vec3 vPositionUVW;
+#else
+#if defined(REFLECTIONMAP_EQUIRECTANGULAR_FIXED) || defined(REFLECTIONMAP_MIRROREDEQUIRECTANGULAR_FIXED)
+varying vec3 vDirectionW;
+#endif
+
+#endif
+
+#include<reflectionFunction>
+
+#endif
+
+#ifdef CAMERACOLORGRADING
+	#include<colorGradingDefinition>
+#endif
+
+#ifdef CAMERACOLORCURVES
+	#include<colorCurvesDefinition>
+#endif
+
+// PBR
+#include<shadowsFragmentFunctions>
+#include<legacyPbrFunctions>
+
+#ifdef CAMERACOLORGRADING
+	#include<colorGrading>
+#endif
+
+#ifdef CAMERACOLORCURVES
+	#include<colorCurves>
+#endif
+
+#include<harmonicsFunctions>
+#include<legacyPbrLightFunctions>
+
+#include<helperFunctions>
+#include<bumpFragmentFunctions>
+#include<clipPlaneFragmentDeclaration>
+#include<logDepthDeclaration>
+
+// Fog
+#include<fogFragmentDeclaration>
+
+void main(void) {
+#include<clipPlaneFragment>
+
+	vec3 viewDirectionW = normalize(vEyePosition - vPositionW);
+
+	// Bump
+#ifdef NORMAL
+	vec3 normalW = normalize(vNormalW);
+#else
+	vec3 normalW = normalize(cross(dFdx(vPositionW), dFdy(vPositionW)));
+#endif
+
+#include<bumpFragment>
+
+#ifdef TWOSIDEDLIGHTING
+	normalW = gl_FrontFacing ? normalW : -normalW;
+#endif
+
+	// Albedo
+	vec4 surfaceAlbedo = vec4(1., 1., 1., 1.);
+	vec3 surfaceAlbedoContribution = vAlbedoColor.rgb;
+
+	// Alpha
+	float alpha = vAlbedoColor.a;
+
+#ifdef ALBEDO
+	surfaceAlbedo = texture2D(albedoSampler, vAlbedoUV + uvOffset);
+	surfaceAlbedo = vec4(toLinearSpace(surfaceAlbedo.rgb), surfaceAlbedo.a);
+
+	#ifndef LINKREFRACTIONTOTRANSPARENCY
+		#ifdef ALPHATEST
+			if (surfaceAlbedo.a < 0.4)
+				discard;
+		#endif
+	#endif
+
+	#ifdef ALPHAFROMALBEDO
+		alpha *= surfaceAlbedo.a;
+	#endif
+
+	surfaceAlbedo.rgb *= vAlbedoInfos.y;
+#else
+	// No Albedo texture.
+	surfaceAlbedo.rgb = surfaceAlbedoContribution;
+	surfaceAlbedoContribution = vec3(1., 1., 1.);
+#endif
+
+#ifdef VERTEXCOLOR
+	surfaceAlbedo.rgb *= vColor.rgb;
+#endif
+
+#ifdef OVERLOADEDVALUES
+	surfaceAlbedo.rgb = mix(surfaceAlbedo.rgb, vOverloadedAlbedo, vOverloadedIntensity.y);
+#endif
+
+	// Ambient color
+	vec3 ambientOcclusionColor = vec3(1., 1., 1.);
+
+#ifdef AMBIENT
+	vec3 ambientOcclusionColorMap = texture2D(ambientSampler, vAmbientUV + uvOffset).rgb * vAmbientInfos.y;
+	#ifdef AMBIENTINGRAYSCALE			
+		ambientOcclusionColorMap = vec3(ambientOcclusionColorMap.r, ambientOcclusionColorMap.r, ambientOcclusionColorMap.r);
+	#endif
+	ambientOcclusionColor = mix(ambientOcclusionColor, ambientOcclusionColorMap, vAmbientInfos.z);
+
+	#ifdef OVERLOADEDVALUES
+		ambientOcclusionColor.rgb = mix(ambientOcclusionColor.rgb, vOverloadedAmbient, vOverloadedIntensity.x);
+	#endif
+#endif
+
+	// Reflectivity map
+	float microSurface = vReflectivityColor.a;
+	vec3 surfaceReflectivityColor = vReflectivityColor.rgb;
+
+#ifdef REFLECTIVITY
+	vec4 surfaceReflectivityColorMap = texture2D(reflectivitySampler, vReflectivityUV + uvOffset);
+	surfaceReflectivityColor = surfaceReflectivityColorMap.rgb;
+	surfaceReflectivityColor = toLinearSpace(surfaceReflectivityColor);
+	surfaceReflectivityColor *= vReflectivityInfos.y;
+
+	#ifdef OVERLOADEDVALUES
+		surfaceReflectivityColor = mix(surfaceReflectivityColor, vOverloadedReflectivity, vOverloadedIntensity.z);
+	#endif
+
+	#ifdef MICROSURFACEFROMREFLECTIVITYMAP
+		microSurface = surfaceReflectivityColorMap.a * vReflectivityInfos.z;
+	#else
+		#ifdef MICROSURFACEAUTOMATIC
+			microSurface = computeDefaultMicroSurface(microSurface, surfaceReflectivityColor);
+		#endif
+	#endif
+#else
+	#ifdef OVERLOADEDVALUES
+		surfaceReflectivityColor = mix(surfaceReflectivityColor, vOverloadedReflectivity, vOverloadedIntensity.z);
+	#endif
+#endif
+
+#ifdef METALLICWORKFLOW
+	vec2 metallicRoughness = surfaceReflectivityColor.rg;
+
+	#ifdef METALLICMAP
+		vec4 surfaceMetallicColorMap = texture2D(reflectivitySampler, vReflectivityUV + uvOffset);
+
+		#ifdef AOSTOREINMETALMAPRED			
+			vec3 aoStoreInMetalMap = vec3(surfaceMetallicColorMap.r, surfaceMetallicColorMap.r, surfaceMetallicColorMap.r);
+			ambientOcclusionColor = mix(ambientOcclusionColor, aoStoreInMetalMap, vReflectivityInfos.z);
+		#endif
+
+		#ifdef METALLNESSSTOREINMETALMAPBLUE
+			metallicRoughness.r *= surfaceMetallicColorMap.b;
+		#else
+			metallicRoughness.r *= surfaceMetallicColorMap.r;
+		#endif
+
+		#ifdef ROUGHNESSSTOREINMETALMAPALPHA
+			metallicRoughness.g *= surfaceMetallicColorMap.a;
+		#else
+			#ifdef ROUGHNESSSTOREINMETALMAPGREEN
+				metallicRoughness.g *= surfaceMetallicColorMap.g;
+			#endif
+		#endif
+	#endif
+
+	#ifdef MICROSURFACEMAP
+		vec4 microSurfaceTexel = texture2D(microSurfaceSampler, vMicroSurfaceSamplerUV + uvOffset) * vMicroSurfaceSamplerInfos.y;
+		metallicRoughness.g *= microSurfaceTexel.r;
+	#endif
+
+	// Compute microsurface form roughness.
+	microSurface = 1.0 - metallicRoughness.g;
+
+	// Diffuse is used as the base of the reflectivity.
+	vec3 baseColor = surfaceAlbedo.rgb;
+
+	// Default specular reflectance at normal incidence.
+	// 4% corresponds to index of refraction (IOR) of 1.50, approximately equal to glass.
+	const vec3 DefaultSpecularReflectanceDielectric = vec3(0.04, 0.04, 0.04);
+
+	// Compute the converted diffuse.
+	surfaceAlbedo.rgb = mix(baseColor.rgb * (1.0 - DefaultSpecularReflectanceDielectric.r), vec3(0., 0., 0.), metallicRoughness.r);
+
+	// Compute the converted reflectivity.
+	surfaceReflectivityColor = mix(DefaultSpecularReflectanceDielectric, baseColor, metallicRoughness.r);
+
+	#ifdef OVERLOADEDVALUES
+		surfaceReflectivityColor = mix(surfaceReflectivityColor, vOverloadedReflectivity, vOverloadedIntensity.z);
+	#endif
+#else
+	#ifdef MICROSURFACEMAP
+		vec4 microSurfaceTexel = texture2D(microSurfaceSampler, vMicroSurfaceSamplerUV + uvOffset) * vMicroSurfaceSamplerInfos.y;
+		microSurface = microSurfaceTexel.r;
+	#endif
+#endif
+
+#ifdef OVERLOADEDVALUES
+	microSurface = mix(microSurface, vOverloadedMicroSurface.x, vOverloadedMicroSurface.y);
+#endif
+
+	// Compute N dot V.
+	float NdotV = max(0.00000000001, dot(normalW, viewDirectionW));
+
+	// Adapt microSurface.
+	microSurface = clamp(microSurface, 0., 1.) * 0.98;
+
+	// Compute roughness.
+	float roughness = clamp(1. - microSurface, 0.000001, 1.0);
+
+	// Lighting
+	vec3 lightDiffuseContribution = vec3(0., 0., 0.);
+
+#ifdef OVERLOADEDSHADOWVALUES
+	vec3 shadowedOnlyLightDiffuseContribution = vec3(1., 1., 1.);
+#endif
+
+#ifdef SPECULARTERM
+	vec3 lightSpecularContribution = vec3(0., 0., 0.);
+#endif
+	
+	float notShadowLevel = 1.; // 1 - shadowLevel
+
+	#ifdef LIGHTMAP
+  		vec3 lightmapColor = texture2D(lightmapSampler, vLightmapUV + uvOffset).rgb * vLightmapInfos.y;
+  	#endif
+
+	float NdotL = -1.;
+	lightingInfo info;
+
+	// Compute reflectance.
+	float reflectance = max(max(surfaceReflectivityColor.r, surfaceReflectivityColor.g), surfaceReflectivityColor.b);
+
+	// For typical incident reflectance range (between 4% to 100%) set the grazing reflectance to 100% for typical fresnel effect.
+    // For very low reflectance range on highly diffuse objects (below 4%), incrementally reduce grazing reflecance to 0%.
+    float reflectance90 = clamp(reflectance * 25.0, 0.0, 1.0);
+	vec3 specularEnvironmentR0 = surfaceReflectivityColor.rgb;
+	vec3 specularEnvironmentR90 = vec3(1.0, 1.0, 1.0) * reflectance90;
+
+#include<legacyPbrLightFunctionsCall>[0..maxSimultaneousLights]
+
+#ifdef SPECULARTERM
+	lightSpecularContribution *= vLightingIntensity.w;
+#endif
+
+#ifdef OPACITY
+	vec4 opacityMap = texture2D(opacitySampler, vOpacityUV + uvOffset);
+
+	#ifdef OPACITYRGB
+		opacityMap.rgb = opacityMap.rgb * vec3(0.3, 0.59, 0.11);
+		alpha *= (opacityMap.x + opacityMap.y + opacityMap.z)* vOpacityInfos.y;
+	#else
+		alpha *= opacityMap.a * vOpacityInfos.y;
+	#endif
+#endif
+
+#ifdef VERTEXALPHA
+	alpha *= vColor.a;
+#endif
+
+#ifdef OPACITYFRESNEL
+	float opacityFresnelTerm = computeFresnelTerm(viewDirectionW, normalW, opacityParts.z, opacityParts.w);
+
+	alpha += opacityParts.x * (1.0 - opacityFresnelTerm) + opacityFresnelTerm * opacityParts.y;
+#endif
+
+	// Refraction
+	vec3 surfaceRefractionColor = vec3(0., 0., 0.);
+
+	// Go mat -> blurry reflexion according to microSurface
+#ifdef LODBASEDMICROSFURACE
+	float alphaG = convertRoughnessToAverageSlope(roughness);
+#endif
+
+#ifdef REFRACTION
+	vec3 refractionVector = refract(-viewDirectionW, normalW, vRefractionInfos.y);
+
+	#ifdef LODBASEDMICROSFURACE
+		#ifdef USEPMREMREFRACTION
+			float lodRefraction = getMipMapIndexFromAverageSlopeWithPMREM(vMicrosurfaceTextureLods.y, alphaG);
+		#else
+			float lodRefraction = getMipMapIndexFromAverageSlope(vMicrosurfaceTextureLods.y, alphaG);
+		#endif
+	#else
+		float biasRefraction = (vMicrosurfaceTextureLods.y + 2.) * (1.0 - microSurface);
+	#endif
+
+	#ifdef REFRACTIONMAP_3D
+		refractionVector.y = refractionVector.y * vRefractionInfos.w;
+
+		if (dot(refractionVector, viewDirectionW) < 1.0)
+		{
+		#ifdef LODBASEDMICROSFURACE
+			#ifdef USEPMREMREFRACTION
+					// Empiric Threshold
+					if ((vMicrosurfaceTextureLods.y - lodRefraction) > 4.0)
+					{
+						// Bend to not reach edges.
+						float scaleRefraction = 1. - exp2(lodRefraction) / exp2(vMicrosurfaceTextureLods.y); // CubemapSize is the size of the base mipmap
+						float maxRefraction = max(max(abs(refractionVector.x), abs(refractionVector.y)), abs(refractionVector.z));
+						if (abs(refractionVector.x) != maxRefraction) refractionVector.x *= scaleRefraction;
+						if (abs(refractionVector.y) != maxRefraction) refractionVector.y *= scaleRefraction;
+						if (abs(refractionVector.z) != maxRefraction) refractionVector.z *= scaleRefraction;
+					}
+			#endif
+
+				surfaceRefractionColor = textureCubeLodEXT(refractionCubeSampler, refractionVector, lodRefraction).rgb * vRefractionInfos.x;
+		#else
+				surfaceRefractionColor = textureCube(refractionCubeSampler, refractionVector, biasRefraction).rgb * vRefractionInfos.x;
+		#endif
+		}
+
+		#ifndef REFRACTIONMAPINLINEARSPACE
+			surfaceRefractionColor = toLinearSpace(surfaceRefractionColor.rgb);
+		#endif
+	#else
+		vec3 vRefractionUVW = vec3(refractionMatrix * (view * vec4(vPositionW + refractionVector * vRefractionInfos.z, 1.0)));
+
+		vec2 refractionCoords = vRefractionUVW.xy / vRefractionUVW.z;
+
+		refractionCoords.y = 1.0 - refractionCoords.y;
+
+		#ifdef LODBASEDMICROSFURACE
+			surfaceRefractionColor = texture2DLodEXT(refraction2DSampler, refractionCoords, lodRefraction).rgb * vRefractionInfos.x;
+		#else
+			surfaceRefractionColor = texture2D(refraction2DSampler, refractionCoords, biasRefraction).rgb * vRefractionInfos.x;
+		#endif    
+
+		surfaceRefractionColor = toLinearSpace(surfaceRefractionColor.rgb);
+	#endif
+#endif
+
+	// Reflection
+	vec3 environmentRadiance = vReflectionColor.rgb;
+	vec3 environmentIrradiance = vReflectionColor.rgb;
+
+#ifdef REFLECTION
+	vec3 vReflectionUVW = computeReflectionCoords(vec4(vPositionW, 1.0), normalW);
+
+	#ifdef LODBASEDMICROSFURACE
+		#ifdef USEPMREMREFLECTION
+			float lodReflection = getMipMapIndexFromAverageSlopeWithPMREM(vMicrosurfaceTextureLods.x, alphaG);
+		#else
+			float lodReflection = getMipMapIndexFromAverageSlope(vMicrosurfaceTextureLods.x, alphaG);
+		#endif
+	#else
+		float biasReflection = (vMicrosurfaceTextureLods.x + 2.) * (1.0 - microSurface);
+	#endif
+
+	#ifdef REFLECTIONMAP_3D
+
+		#ifdef LODBASEDMICROSFURACE
+			#ifdef USEPMREMREFLECTION
+				// Empiric Threshold
+				if ((vMicrosurfaceTextureLods.y - lodReflection) > 4.0)
+				{
+					// Bend to not reach edges.
+					float scaleReflection = 1. - exp2(lodReflection) / exp2(vMicrosurfaceTextureLods.x); // CubemapSize is the size of the base mipmap
+					float maxReflection = max(max(abs(vReflectionUVW.x), abs(vReflectionUVW.y)), abs(vReflectionUVW.z));
+					if (abs(vReflectionUVW.x) != maxReflection) vReflectionUVW.x *= scaleReflection;
+					if (abs(vReflectionUVW.y) != maxReflection) vReflectionUVW.y *= scaleReflection;
+					if (abs(vReflectionUVW.z) != maxReflection) vReflectionUVW.z *= scaleReflection;
+				}
+			#endif
+
+			environmentRadiance = textureCubeLodEXT(reflectionCubeSampler, vReflectionUVW, lodReflection).rgb * vReflectionInfos.x;
+		#else
+			environmentRadiance = textureCube(reflectionCubeSampler, vReflectionUVW, biasReflection).rgb * vReflectionInfos.x;
+		#endif
+
+		#ifdef USESPHERICALFROMREFLECTIONMAP
+			#ifndef REFLECTIONMAP_SKYBOX
+				vec3 normalEnvironmentSpace = (reflectionMatrix * vec4(normalW, 1)).xyz;
+				environmentIrradiance = EnvironmentIrradiance(normalEnvironmentSpace);
+			#endif
+		#else
+			environmentRadiance = toLinearSpace(environmentRadiance.rgb);
+
+			environmentIrradiance = textureCube(reflectionCubeSampler, normalW, 20.).rgb * vReflectionInfos.x;
+			environmentIrradiance = toLinearSpace(environmentIrradiance.rgb);
+			environmentIrradiance *= 0.2; // Hack in case of no hdr cube map use for environment.
+		#endif
+	#else
+		vec2 coords = vReflectionUVW.xy;
+
+		#ifdef REFLECTIONMAP_PROJECTION
+			coords /= vReflectionUVW.z;
+		#endif
+
+		coords.y = 1.0 - coords.y;
+		#ifdef LODBASEDMICROSFURACE
+			environmentRadiance = texture2DLodEXT(reflection2DSampler, coords, lodReflection).rgb * vReflectionInfos.x;
+		#else
+			environmentRadiance = texture2D(reflection2DSampler, coords, biasReflection).rgb * vReflectionInfos.x;
+		#endif
+
+		environmentRadiance = toLinearSpace(environmentRadiance.rgb);
+
+		environmentIrradiance = texture2D(reflection2DSampler, coords, 20.).rgb * vReflectionInfos.x;
+		environmentIrradiance = toLinearSpace(environmentIrradiance.rgb);
+	#endif
+#endif
+
+#ifdef OVERLOADEDVALUES
+	environmentIrradiance = mix(environmentIrradiance, vOverloadedReflection, vOverloadedMicroSurface.z);
+	environmentRadiance = mix(environmentRadiance, vOverloadedReflection, vOverloadedMicroSurface.z);
+#endif
+
+	environmentRadiance *= vLightingIntensity.z;
+	environmentIrradiance *= vLightingIntensity.z;
+
+	// Specular Environment Fresnel.
+	vec3 specularEnvironmentReflectance = FresnelSchlickEnvironmentGGX(clamp(NdotV, 0., 1.), specularEnvironmentR0, specularEnvironmentR90, sqrt(microSurface));
+
+	// Compute refractance
+	vec3 refractance = vec3(0.0, 0.0, 0.0);
+
+#ifdef REFRACTION
+	vec3 transmission = vec3(1.0, 1.0, 1.0);
+	#ifdef LINKREFRACTIONTOTRANSPARENCY
+		// Transmission based on alpha.
+		transmission *= (1.0 - alpha);
+
+		// Tint the material with albedo.
+		// TODO. PBR Tinting.
+		vec3 mixedAlbedo = surfaceAlbedoContribution.rgb * surfaceAlbedo.rgb;
+		float maxChannel = max(max(mixedAlbedo.r, mixedAlbedo.g), mixedAlbedo.b);
+		vec3 tint = clamp(maxChannel * mixedAlbedo, 0.0, 1.0);
+
+		// Decrease Albedo Contribution
+		surfaceAlbedoContribution *= alpha;
+
+		// Decrease irradiance Contribution
+		environmentIrradiance *= alpha;
+
+		// Tint reflectance
+		surfaceRefractionColor *= tint;
+
+		// Put alpha back to 1;
+		alpha = 1.0;
+	#endif
+
+	// Add Multiple internal bounces.
+	vec3 bounceSpecularEnvironmentReflectance = (2.0 * specularEnvironmentReflectance) / (1.0 + specularEnvironmentReflectance);
+	specularEnvironmentReflectance = mix(bounceSpecularEnvironmentReflectance, specularEnvironmentReflectance, alpha);
+
+	// In theory T = 1 - R.
+	transmission *= 1.0 - specularEnvironmentReflectance;
+
+	// Should baked in diffuse.
+	refractance = surfaceRefractionColor * transmission;
+#endif
+
+	// Apply Energy Conservation taking in account the environment level only if the environment is present.
+	surfaceAlbedo.rgb = (1. - reflectance) * surfaceAlbedo.rgb;
+
+	refractance *= vLightingIntensity.z;
+	environmentRadiance *= specularEnvironmentReflectance;
+
+	// Emissive
+	vec3 surfaceEmissiveColor = vEmissiveColor;
+#ifdef EMISSIVE
+	vec3 emissiveColorTex = texture2D(emissiveSampler, vEmissiveUV + uvOffset).rgb;
+	surfaceEmissiveColor = toLinearSpace(emissiveColorTex.rgb) * surfaceEmissiveColor * vEmissiveInfos.y;
+#endif
+
+#ifdef OVERLOADEDVALUES
+	surfaceEmissiveColor = mix(surfaceEmissiveColor, vOverloadedEmissive, vOverloadedIntensity.w);
+#endif
+
+#ifdef EMISSIVEFRESNEL
+	float emissiveFresnelTerm = computeFresnelTerm(viewDirectionW, normalW, emissiveRightColor.a, emissiveLeftColor.a);
+
+	surfaceEmissiveColor *= emissiveLeftColor.rgb * (1.0 - emissiveFresnelTerm) + emissiveFresnelTerm * emissiveRightColor.rgb;
+#endif
+
+	// Composition
+#ifdef EMISSIVEASILLUMINATION
+	vec3 finalDiffuse = lightDiffuseContribution * surfaceAlbedoContribution;
+
+	#ifdef OVERLOADEDSHADOWVALUES
+		shadowedOnlyLightDiffuseContribution = shadowedOnlyLightDiffuseContribution * surfaceAlbedoContribution;
+	#endif
+#else
+	#ifdef LINKEMISSIVEWITHALBEDO
+		vec3 finalDiffuse = (lightDiffuseContribution + surfaceEmissiveColor) * surfaceAlbedoContribution;
+
+		#ifdef OVERLOADEDSHADOWVALUES
+			shadowedOnlyLightDiffuseContribution = (shadowedOnlyLightDiffuseContribution + surfaceEmissiveColor) * surfaceAlbedoContribution;
+		#endif
+	#else
+		vec3 finalDiffuse = lightDiffuseContribution * surfaceAlbedoContribution + surfaceEmissiveColor;
+
+		#ifdef OVERLOADEDSHADOWVALUES
+			shadowedOnlyLightDiffuseContribution = shadowedOnlyLightDiffuseContribution * surfaceAlbedoContribution + surfaceEmissiveColor;
+		#endif
+	#endif
+#endif
+
+finalDiffuse.rgb += vAmbientColor;
+finalDiffuse *= surfaceAlbedo.rgb;
+finalDiffuse = max(finalDiffuse, 0.0);
+
+#ifdef OVERLOADEDSHADOWVALUES
+	shadowedOnlyLightDiffuseContribution += vAmbientColor;
+	shadowedOnlyLightDiffuseContribution *= surfaceAlbedo.rgb;
+	shadowedOnlyLightDiffuseContribution = max(shadowedOnlyLightDiffuseContribution, 0.0);
+	finalDiffuse = mix(finalDiffuse, shadowedOnlyLightDiffuseContribution, (1.0 - vOverloadedShadowIntensity.y));
+#endif
+
+finalDiffuse = (finalDiffuse * vLightingIntensity.x + surfaceAlbedo.rgb * environmentIrradiance) * ambientOcclusionColor;
+
+#ifdef SPECULARTERM
+	vec3 finalSpecular = lightSpecularContribution * surfaceReflectivityColor;
+	#ifdef SPECULAROVERALPHA
+		alpha = clamp(alpha + getLuminance(finalSpecular), 0., 1.);
+	#endif
+#else
+	vec3 finalSpecular = vec3(0.0);
+#endif
+
+#ifdef RADIANCEOVERALPHA
+	alpha = clamp(alpha + getLuminance(environmentRadiance), 0., 1.);
+#endif
+
+// Composition
+// Reflection already includes the environment intensity.
+vec4 finalColor = vec4(finalDiffuse + finalSpecular * vLightingIntensity.x + environmentRadiance + refractance, alpha);
+
+#ifdef EMISSIVEASILLUMINATION
+	finalColor.rgb += (surfaceEmissiveColor * vLightingIntensity.y);
+#endif
+
+#ifdef LIGHTMAP
+    #ifndef LIGHTMAPEXCLUDED
+        #ifdef USELIGHTMAPASSHADOWMAP
+            finalColor.rgb *= lightmapColor;
+        #else
+            finalColor.rgb += lightmapColor;
+        #endif
+    #endif
+#endif
+
+	finalColor = max(finalColor, 0.0);
+
+#ifdef CAMERATONEMAP
+	finalColor.rgb = toneMaps(finalColor.rgb);
+#endif
+
+	finalColor.rgb = toGammaSpace(finalColor.rgb);
+
+#include<logDepthFragment>
+#include<fogFragment>(color, finalColor)
+
+#ifdef CAMERACONTRAST
+	finalColor = contrasts(finalColor);
+#endif
+
+	finalColor.rgb = clamp(finalColor.rgb, 0., 1.);
+
+#ifdef CAMERACOLORGRADING
+	finalColor = colorGrades(finalColor);
+#endif
+
+#ifdef CAMERACOLORCURVES
+	finalColor.rgb = applyColorCurves(finalColor.rgb);
+#endif
+
+	// Normal Display.
+	// gl_FragColor = vec4(normalW * 0.5 + 0.5, 1.0);
+
+	// Ambient reflection color.
+	// gl_FragColor = vec4(ambientReflectionColor, 1.0);
+
+	// Reflection color.
+	// gl_FragColor = vec4(reflectionColor, 1.0);
+
+	// Base color.
+	// gl_FragColor = vec4(surfaceAlbedo.rgb, 1.0);
+
+	// Specular color.
+	// gl_FragColor = vec4(surfaceReflectivityColor.rgb, 1.0);
+
+	// MicroSurface color.
+	// gl_FragColor = vec4(microSurface, microSurface, microSurface, 1.0);
+
+	// Specular Map
+	// gl_FragColor = vec4(reflectivityMapColor.rgb, 1.0);
+
+	// Refractance
+	// gl_FragColor = vec4(refractance.rgb, 1.0);
+
+	//// Emissive Color
+	//vec2 test = vEmissiveUV * 0.5 + 0.5;
+	//gl_FragColor = vec4(test.x, test.y, 1.0, 1.0);
+
+	gl_FragColor = finalColor;
+}

+ 239 - 0
materialsLibrary/src/legacyPBR/legacyPbr.vertex.fx

@@ -0,0 +1,239 @@
+precision highp float;
+
+#include<__decl__legacyPbrVertex>
+
+// Attributes
+attribute vec3 position;
+#ifdef NORMAL
+attribute vec3 normal;
+#endif
+#ifdef TANGENT
+attribute vec4 tangent;
+#endif
+#ifdef UV1
+attribute vec2 uv;
+#endif
+#ifdef UV2
+attribute vec2 uv2;
+#endif
+#ifdef VERTEXCOLOR
+attribute vec4 color;
+#endif
+
+#include<bonesDeclaration>
+
+// Uniforms
+#include<instancesDeclaration>
+
+#ifdef ALBEDO
+varying vec2 vAlbedoUV;
+#endif
+
+#ifdef AMBIENT
+varying vec2 vAmbientUV;
+#endif
+
+#ifdef OPACITY
+varying vec2 vOpacityUV;
+#endif
+
+#ifdef EMISSIVE
+varying vec2 vEmissiveUV;
+#endif
+
+#ifdef LIGHTMAP
+varying vec2 vLightmapUV;
+#endif
+
+#if defined(REFLECTIVITY) || defined(METALLICWORKFLOW) 
+varying vec2 vReflectivityUV;
+#endif
+
+#ifdef MICROSURFACEMAP
+varying vec2 vMicroSurfaceSamplerUV;
+#endif
+
+#ifdef BUMP
+varying vec2 vBumpUV;
+#endif
+
+// Output
+varying vec3 vPositionW;
+#ifdef NORMAL
+varying vec3 vNormalW;
+#endif
+
+#ifdef VERTEXCOLOR
+varying vec4 vColor;
+#endif
+
+#include<bumpVertexDeclaration>
+#include<clipPlaneVertexDeclaration>
+#include<fogVertexDeclaration>
+#include<shadowsVertexDeclaration>[0..maxSimultaneousLights]
+
+#include<morphTargetsVertexGlobalDeclaration>
+#include<morphTargetsVertexDeclaration>[0..maxSimultaneousMorphTargets]
+
+#ifdef REFLECTIONMAP_SKYBOX
+varying vec3 vPositionUVW;
+#endif
+
+#if defined(REFLECTIONMAP_EQUIRECTANGULAR_FIXED) || defined(REFLECTIONMAP_MIRROREDEQUIRECTANGULAR_FIXED)
+varying vec3 vDirectionW;
+#endif
+
+#include<logDepthDeclaration>
+
+void main(void) {
+	vec3 positionUpdated = position;
+#ifdef NORMAL
+	vec3 normalUpdated = normal;
+#endif
+#ifdef TANGENT
+    vec4 tangentUpdated = tangent;
+#endif
+
+#include<morphTargetsVertex>[0..maxSimultaneousMorphTargets]
+
+#ifdef REFLECTIONMAP_SKYBOX
+    vPositionUVW = positionUpdated;
+#endif 
+
+#include<instancesVertex>
+#include<bonesVertex>
+
+    gl_Position = viewProjection * finalWorld * vec4(positionUpdated, 1.0);
+
+    vec4 worldPos = finalWorld * vec4(positionUpdated, 1.0);
+    vPositionW = vec3(worldPos);
+
+#ifdef NORMAL
+    vNormalW = normalize(vec3(finalWorld * vec4(normalUpdated, 0.0)));
+#endif
+
+#if defined(REFLECTIONMAP_EQUIRECTANGULAR_FIXED) || defined(REFLECTIONMAP_MIRROREDEQUIRECTANGULAR_FIXED)
+    vDirectionW = normalize(vec3(finalWorld * vec4(positionUpdated, 0.0)));
+#endif
+
+    // Texture coordinates
+#ifndef UV1
+    vec2 uv = vec2(0., 0.);
+#endif
+#ifndef UV2
+    vec2 uv2 = vec2(0., 0.);
+#endif
+
+#ifdef ALBEDO
+    if (vAlbedoInfos.x == 0.)
+    {
+        vAlbedoUV = vec2(albedoMatrix * vec4(uv, 1.0, 0.0));
+    }
+    else
+    {
+        vAlbedoUV = vec2(albedoMatrix * vec4(uv2, 1.0, 0.0));
+    }
+#endif
+
+#ifdef AMBIENT
+    if (vAmbientInfos.x == 0.)
+    {
+        vAmbientUV = vec2(ambientMatrix * vec4(uv, 1.0, 0.0));
+    }
+    else
+    {
+        vAmbientUV = vec2(ambientMatrix * vec4(uv2, 1.0, 0.0));
+    }
+#endif
+
+#ifdef OPACITY
+    if (vOpacityInfos.x == 0.)
+    {
+        vOpacityUV = vec2(opacityMatrix * vec4(uv, 1.0, 0.0));
+    }
+    else
+    {
+        vOpacityUV = vec2(opacityMatrix * vec4(uv2, 1.0, 0.0));
+    }
+#endif
+
+#ifdef EMISSIVE
+    if (vEmissiveInfos.x == 0.)
+    {
+        vEmissiveUV = vec2(emissiveMatrix * vec4(uv, 1.0, 0.0));
+    }
+    else
+    {
+        vEmissiveUV = vec2(emissiveMatrix * vec4(uv2, 1.0, 0.0));
+    }
+#endif
+
+#ifdef LIGHTMAP
+    if (vLightmapInfos.x == 0.)
+    {
+        vLightmapUV = vec2(lightmapMatrix * vec4(uv, 1.0, 0.0));
+    }
+    else
+    {
+        vLightmapUV = vec2(lightmapMatrix * vec4(uv2, 1.0, 0.0));
+    }
+#endif
+
+#if defined(REFLECTIVITY) || defined(METALLICWORKFLOW) 
+    if (vReflectivityInfos.x == 0.)
+    {
+        vReflectivityUV = vec2(reflectivityMatrix * vec4(uv, 1.0, 0.0));
+    }
+    else
+    {
+        vReflectivityUV = vec2(reflectivityMatrix * vec4(uv2, 1.0, 0.0));
+    }
+#endif
+
+#ifdef MICROSURFACEMAP
+    if (vMicroSurfaceSamplerInfos.x == 0.)
+    {
+        vMicroSurfaceSamplerUV = vec2(microSurfaceSamplerMatrix * vec4(uv, 1.0, 0.0));
+    }
+    else
+    {
+        vMicroSurfaceSamplerUV = vec2(microSurfaceSamplerMatrix * vec4(uv2, 1.0, 0.0));
+    }
+#endif
+
+#ifdef BUMP
+    if (vBumpInfos.x == 0.)
+    {
+        vBumpUV = vec2(bumpMatrix * vec4(uv, 1.0, 0.0));
+    }
+    else
+    {
+        vBumpUV = vec2(bumpMatrix * vec4(uv2, 1.0, 0.0));
+    }
+#endif
+
+    // TBN
+#include<bumpVertex>
+
+    // Clip plane
+#include<clipPlaneVertex>
+
+    // Fog
+#include<fogVertex>
+
+    // Shadows
+#include<shadowsVertex>[0..maxSimultaneousLights]
+
+    // Vertex color
+#ifdef VERTEXCOLOR
+    vColor = color;
+#endif
+
+    // Point size
+#ifdef POINTSIZE
+    gl_PointSize = pointSize;
+#endif
+
+    // Log. depth
+#include<logDepthVertex>
+}

+ 96 - 0
materialsLibrary/src/legacyPBR/legacyPbrFragmentDeclaration.fx

@@ -0,0 +1,96 @@
+uniform vec3 vReflectionColor;
+uniform vec4 vAlbedoColor;
+
+// CUSTOM CONTROLS
+uniform vec4 vLightingIntensity;
+
+#ifdef OVERLOADEDVALUES
+uniform vec4 vOverloadedIntensity;
+uniform vec3 vOverloadedAmbient;
+uniform vec3 vOverloadedAlbedo;
+uniform vec3 vOverloadedReflectivity;
+uniform vec3 vOverloadedEmissive;
+uniform vec3 vOverloadedReflection;
+uniform vec3 vOverloadedMicroSurface;
+#endif
+
+#ifdef OVERLOADEDSHADOWVALUES
+uniform vec4 vOverloadedShadowIntensity;
+#endif
+
+#if defined(REFLECTION) || defined(REFRACTION)
+uniform vec2 vMicrosurfaceTextureLods;
+#endif
+
+uniform vec4 vReflectivityColor;
+uniform vec3 vEmissiveColor;
+
+// Samplers
+#ifdef ALBEDO
+uniform vec2 vAlbedoInfos;
+#endif
+
+#ifdef AMBIENT
+uniform vec3 vAmbientInfos;
+#endif
+
+#ifdef BUMP
+uniform vec3 vBumpInfos;
+#endif
+
+#ifdef OPACITY	
+uniform vec2 vOpacityInfos;
+#endif
+
+#ifdef EMISSIVE
+uniform vec2 vEmissiveInfos;
+#endif
+
+#ifdef LIGHTMAP
+uniform vec2 vLightmapInfos;
+#endif
+
+#if defined(REFLECTIVITY) || defined(METALLICWORKFLOW) 
+uniform vec3 vReflectivityInfos;
+#endif
+
+#ifdef MICROSURFACEMAP
+uniform vec2 vMicroSurfaceSamplerInfos;
+#endif
+
+#ifdef OPACITYFRESNEL
+uniform vec4 opacityParts;
+#endif
+
+#ifdef EMISSIVEFRESNEL
+uniform vec4 emissiveLeftColor;
+uniform vec4 emissiveRightColor;
+#endif
+
+// Refraction Reflection
+#if defined(REFLECTIONMAP_SPHERICAL) || defined(REFLECTIONMAP_PROJECTION) || defined(REFRACTION)
+uniform mat4 view;
+#endif
+
+// Refraction
+#ifdef REFRACTION
+uniform vec4 vRefractionInfos;
+
+#ifdef REFRACTIONMAP_3D
+#else
+uniform mat4 refractionMatrix;
+#endif
+#endif
+
+// Reflection
+#ifdef REFLECTION
+uniform vec2 vReflectionInfos;
+
+#ifdef REFLECTIONMAP_SKYBOX
+#else
+
+#if defined(REFLECTIONMAP_PLANAR) || defined(REFLECTIONMAP_CUBIC) || defined(REFLECTIONMAP_PROJECTION)
+uniform mat4 reflectionMatrix;
+#endif
+#endif
+#endif

+ 190 - 0
materialsLibrary/src/legacyPBR/legacyPbrFunctions.fx

@@ -0,0 +1,190 @@
+// Constants
+#define RECIPROCAL_PI2 0.15915494
+#define FRESNEL_MAXIMUM_ON_ROUGH 0.25
+
+// PBR CUSTOM CONSTANTS
+const float kPi = 3.1415926535897932384626433832795;
+const float kRougnhessToAlphaScale = 0.1;
+const float kRougnhessToAlphaOffset = 0.29248125;
+
+float Square(float value)
+{
+    return value * value;
+}
+
+float getLuminance(vec3 color)
+{
+    return clamp(dot(color, vec3(0.2126, 0.7152, 0.0722)), 0., 1.);
+}
+
+float convertRoughnessToAverageSlope(float roughness)
+{
+    // Calculate AlphaG as square of roughness; add epsilon to avoid numerical issues
+    const float kMinimumVariance = 0.0005;
+    float alphaG = Square(roughness) + kMinimumVariance;
+    return alphaG;
+}
+
+// Based on Beckamm roughness to Blinn exponent + http://casual-effects.blogspot.ca/2011/08/plausible-environment-lighting-in-two.html 
+float getMipMapIndexFromAverageSlope(float maxMipLevel, float alpha)
+{
+    // do not take in account lower mips hence -1... and wait from proper preprocess.
+    // formula comes from approximation of the mathematical solution.
+    //float mip = maxMipLevel + kRougnhessToAlphaOffset + 0.5 * log2(alpha);
+    
+    // In the mean time 
+    // Always [0..1] goes from max mip to min mip in a log2 way.  
+    // Change 5 to nummip below.
+    // http://www.wolframalpha.com/input/?i=x+in+0..1+plot+(+5+%2B+0.3+%2B+0.1+*+5+*+log2(+(1+-+x)+*+(1+-+x)+%2B+0.0005))
+    float mip = kRougnhessToAlphaOffset + maxMipLevel + (maxMipLevel * kRougnhessToAlphaScale * log2(alpha));
+    
+    return clamp(mip, 0., maxMipLevel);
+}
+
+float getMipMapIndexFromAverageSlopeWithPMREM(float maxMipLevel, float alphaG)
+{
+    float specularPower = clamp(2. / alphaG - 2., 0.000001, 2048.);
+    
+    // Based on CubeMapGen for cosine power with 2048 spec default and 0.25 dropoff 
+    return clamp(- 0.5 * log2(specularPower) + 5.5, 0., maxMipLevel);
+}
+
+// From Microfacet Models for Refraction through Rough Surfaces, Walter et al. 2007
+float smithVisibilityG1_TrowbridgeReitzGGX(float dot, float alphaG)
+{
+    float tanSquared = (1.0 - dot * dot) / (dot * dot);
+    return 2.0 / (1.0 + sqrt(1.0 + alphaG * alphaG * tanSquared));
+}
+
+float smithVisibilityG_TrowbridgeReitzGGX_Walter(float NdotL, float NdotV, float alphaG)
+{
+    return smithVisibilityG1_TrowbridgeReitzGGX(NdotL, alphaG) * smithVisibilityG1_TrowbridgeReitzGGX(NdotV, alphaG);
+}
+
+// Trowbridge-Reitz (GGX)
+// Generalised Trowbridge-Reitz with gamma power=2.0
+float normalDistributionFunction_TrowbridgeReitzGGX(float NdotH, float alphaG)
+{
+    // Note: alphaG is average slope (gradient) of the normals in slope-space.
+    // It is also the (trigonometric) tangent of the median distribution value, i.e. 50% of normals have
+    // a tangent (gradient) closer to the macrosurface than this slope.
+    float a2 = Square(alphaG);
+    float d = NdotH * NdotH * (a2 - 1.0) + 1.0;
+    return a2 / (kPi * d * d);
+}
+
+vec3 fresnelSchlickGGX(float VdotH, vec3 reflectance0, vec3 reflectance90)
+{
+    return reflectance0 + (reflectance90 - reflectance0) * pow(clamp(1.0 - VdotH, 0., 1.), 5.0);
+}
+
+vec3 FresnelSchlickEnvironmentGGX(float VdotN, vec3 reflectance0, vec3 reflectance90, float smoothness)
+{
+    // Schlick fresnel approximation, extended with basic smoothness term so that rough surfaces do not approach reflectance90 at grazing angle
+    float weight = mix(FRESNEL_MAXIMUM_ON_ROUGH, 1.0, smoothness);
+    return reflectance0 + weight * (reflectance90 - reflectance0) * pow(clamp(1.0 - VdotN, 0., 1.), 5.0);
+}
+
+// Cook Torance Specular computation.
+vec3 computeSpecularTerm(float NdotH, float NdotL, float NdotV, float VdotH, float roughness, vec3 specularColor, vec3 reflectance90)
+{
+    float alphaG = convertRoughnessToAverageSlope(roughness);
+    float distribution = normalDistributionFunction_TrowbridgeReitzGGX(NdotH, alphaG);
+    float visibility = smithVisibilityG_TrowbridgeReitzGGX_Walter(NdotL, NdotV, alphaG);
+    visibility /= (4.0 * NdotL * NdotV); // Cook Torance Denominator  integated in viibility to avoid issues when visibility function changes.
+
+    vec3 fresnel = fresnelSchlickGGX(VdotH, specularColor, reflectance90);
+
+    float specTerm = max(0., visibility * distribution) * NdotL;
+    return fresnel * specTerm * kPi; // TODO: audit pi constants
+}
+
+float computeDiffuseTerm(float NdotL, float NdotV, float VdotH, float roughness)
+{
+    // Diffuse fresnel falloff as per Disney principled BRDF, and in the spirit of
+    // of general coupled diffuse/specular models e.g. Ashikhmin Shirley.
+    float diffuseFresnelNV = pow(clamp(1.0 - NdotL, 0.000001, 1.), 5.0);
+    float diffuseFresnelNL = pow(clamp(1.0 - NdotV, 0.000001, 1.), 5.0);
+    float diffuseFresnel90 = 0.5 + 2.0 * VdotH * VdotH * roughness;
+    float diffuseFresnelTerm =
+        (1.0 + (diffuseFresnel90 - 1.0) * diffuseFresnelNL) *
+        (1.0 + (diffuseFresnel90 - 1.0) * diffuseFresnelNV);
+
+
+    return diffuseFresnelTerm * NdotL;
+    // PI Test
+    // diffuseFresnelTerm /= kPi;
+}
+
+float adjustRoughnessFromLightProperties(float roughness, float lightRadius, float lightDistance)
+{
+    #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)
+{
+    float kReflectivityNoAlphaWorkflow_SmoothnessMax = 0.95;
+
+    float reflectivityLuminance = getLuminance(reflectivityColor);
+    float reflectivityLuma = sqrt(reflectivityLuminance);
+    microSurface = reflectivityLuma * kReflectivityNoAlphaWorkflow_SmoothnessMax;
+
+    return microSurface;
+}
+
+vec3 toLinearSpace(vec3 color)
+{
+    return vec3(pow(color.r, 2.2), pow(color.g, 2.2), pow(color.b, 2.2));
+}
+
+vec3 toGammaSpace(vec3 color)
+{
+    return vec3(pow(color.r, 1.0 / 2.2), pow(color.g, 1.0 / 2.2), pow(color.b, 1.0 / 2.2));
+}
+
+#ifdef CAMERATONEMAP
+    vec3 toneMaps(vec3 color)
+    {
+        color = max(color, 0.0);
+
+        // TONE MAPPING / EXPOSURE
+        color.rgb = color.rgb * vCameraInfos.x;
+
+        float tuning = 1.5; // TODO: sync up so e.g. 18% greys are matched to exposure appropriately
+        // PI Test
+        // tuning *=  kPi;
+        vec3 tonemapped = 1.0 - exp2(-color.rgb * tuning); // simple local photographic tonemapper
+        color.rgb = mix(color.rgb, tonemapped, 1.0);
+        return color;
+    }
+#endif
+
+#ifdef CAMERACONTRAST
+    vec4 contrasts(vec4 color)
+    {
+        color = clamp(color, 0.0, 1.0);
+
+        vec3 resultHighContrast = color.rgb * color.rgb * (3.0 - 2.0 * color.rgb);
+        float contrast = vCameraInfos.y;
+        if (contrast < 1.0)
+        {
+            // Decrease contrast: interpolate towards zero-contrast image (flat grey)
+            color.rgb = mix(vec3(0.5, 0.5, 0.5), color.rgb, contrast);
+        }
+        else
+        {
+            // Increase contrast: apply simple shoulder-toe high contrast curve
+            color.rgb = mix(color.rgb, resultHighContrast, contrast - 1.0);
+        }
+
+        return color;
+    }
+#endif

+ 157 - 0
materialsLibrary/src/legacyPBR/legacyPbrLightFunctions.fx

@@ -0,0 +1,157 @@
+// Light Computing
+struct lightingInfo
+{
+    vec3 diffuse;
+    #ifdef SPECULARTERM
+        vec3 specular;
+    #endif
+};
+
+float computeDistanceLightFalloff(vec3 lightOffset, float lightDistanceSquared, float range)
+{   
+    #ifdef USEPHYSICALLIGHTFALLOFF
+        float lightDistanceFalloff = 1.0 / ((lightDistanceSquared + 0.0001));
+    #else
+        float lightDistanceFalloff = max(0., 1.0 - length(lightOffset) / range);
+    #endif
+    
+    return lightDistanceFalloff;
+}
+
+float computeDirectionalLightFalloff(vec3 lightDirection, vec3 directionToLightCenterW, float lightAngle, float exponent)
+{
+    float falloff = 0.0;
+    
+    #ifdef USEPHYSICALLIGHTFALLOFF
+        float cosHalfAngle = cos(lightAngle * 0.5);
+        const float kMinusLog2ConeAngleIntensityRatio = 6.64385618977; // -log2(0.01)
+
+        // Calculate a Spherical Gaussian (von Mises-Fisher distribution, not angle-based Gaussian) such that the peak is in the light direction,
+        // and the value at the nominal cone angle is 1% of the peak. Because we want the distribution to decay from unity (100%)
+        // at the peak direction (dot product = 1) down to 1% at the nominal cone cutoff (dot product = cosAngle) 
+        // the falloff rate expressed in terms of the base-two dot product is therefore -log2(ConeAngleIntensityRatio) / (1.0 - cosAngle).
+        // Note that the distribution is unnormalised in that peak density is unity, rather than the total energy is unity.
+        float concentrationKappa = kMinusLog2ConeAngleIntensityRatio / (1.0 - cosHalfAngle);
+    
+        // Evaluate spherical gaussian for light directional falloff for spot light type (note: spot directional falloff; 
+        // not directional light type)
+        vec4 lightDirectionSpreadSG = vec4(-lightDirection * concentrationKappa, -concentrationKappa);
+        falloff = exp2(dot(vec4(directionToLightCenterW, 1.0), lightDirectionSpreadSG));
+    #else
+        float cosAngle = max(0.000000000000001, dot(-lightDirection, directionToLightCenterW));
+        if (cosAngle >= lightAngle)
+        {
+            falloff = max(0., pow(cosAngle, exponent));
+        }
+    #endif
+    
+    return falloff;
+}
+
+lightingInfo computeLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec3 diffuseColor, vec3 specularColor, float rangeRadius, float roughness, float NdotV, vec3 reflectance90, out float NdotL) {
+    lightingInfo result;
+
+    vec3 lightDirection;
+    float attenuation = 1.0;
+    float lightDistance;
+    
+    // Point
+    if (lightData.w == 0.)
+    {
+        vec3 lightOffset = lightData.xyz - vPositionW;
+        float lightDistanceSquared = dot(lightOffset, lightOffset);
+        attenuation = computeDistanceLightFalloff(lightOffset, lightDistanceSquared, rangeRadius);
+        
+        lightDistance = sqrt(lightDistanceSquared);
+        lightDirection = normalize(lightOffset);
+    }
+    // Directional
+    else
+    {
+        lightDistance = length(-lightData.xyz);
+        lightDirection = normalize(-lightData.xyz);
+    }
+    
+    // Roughness
+    roughness = adjustRoughnessFromLightProperties(roughness, rangeRadius, lightDistance);
+    
+    // diffuse
+    vec3 H = normalize(viewDirectionW + lightDirection);
+    NdotL = max(0.00000000001, dot(vNormal, lightDirection));
+    float VdotH = clamp(0.00000000001, 1.0, dot(viewDirectionW, H));
+
+    float diffuseTerm = computeDiffuseTerm(NdotL, NdotV, VdotH, roughness);
+    result.diffuse = diffuseTerm * diffuseColor * attenuation;
+
+    #ifdef SPECULARTERM
+        // Specular
+        float NdotH = max(0.00000000001, dot(vNormal, H));
+
+        vec3 specTerm = computeSpecularTerm(NdotH, NdotL, NdotV, VdotH, roughness, specularColor, reflectance90);
+        result.specular = specTerm * attenuation;
+    #endif
+
+    return result;
+}
+
+lightingInfo computeSpotLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec4 lightDirection, vec3 diffuseColor, vec3 specularColor, float rangeRadius, float roughness, float NdotV, vec3 reflectance90, out float NdotL) {
+    lightingInfo result;
+
+    vec3 lightOffset = lightData.xyz - vPositionW;
+    vec3 directionToLightCenterW = normalize(lightOffset);
+
+    // Distance falloff.
+    float lightDistanceSquared = dot(lightOffset, lightOffset);
+    float attenuation = computeDistanceLightFalloff(lightOffset, lightDistanceSquared, rangeRadius);
+    
+    // Directional falloff.
+    float directionalAttenuation = computeDirectionalLightFalloff(lightDirection.xyz, directionToLightCenterW, lightDirection.w, lightData.w);
+    attenuation *= directionalAttenuation;
+    
+    // Roughness.
+    float lightDistance = sqrt(lightDistanceSquared);
+    roughness = adjustRoughnessFromLightProperties(roughness, rangeRadius, lightDistance);
+    
+    // Diffuse
+    vec3 H = normalize(viewDirectionW + directionToLightCenterW);
+    NdotL = max(0.00000000001, dot(vNormal, directionToLightCenterW));
+    float VdotH = clamp(dot(viewDirectionW, H), 0.00000000001, 1.0);
+
+    float diffuseTerm = computeDiffuseTerm(NdotL, NdotV, VdotH, roughness);
+    result.diffuse = diffuseTerm * diffuseColor * attenuation;
+
+    #ifdef SPECULARTERM
+        // Specular
+        float NdotH = max(0.00000000001, dot(vNormal, H));
+
+        vec3 specTerm = computeSpecularTerm(NdotH, NdotL, NdotV, VdotH, roughness, specularColor, reflectance90);
+        result.specular = specTerm  * attenuation;
+    #endif
+
+    return result;
+}
+
+lightingInfo computeHemisphericLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec3 diffuseColor, vec3 specularColor, vec3 groundColor, float roughness, float NdotV, vec3 reflectance90, out float NdotL) {
+    lightingInfo result;
+
+    // Roughness
+    // Do not touch roughness on hemispheric.
+
+    // Diffuse
+    NdotL = dot(vNormal, lightData.xyz) * 0.5 + 0.5;
+    result.diffuse = mix(groundColor, diffuseColor, NdotL);
+
+    #ifdef SPECULARTERM
+        // Specular
+        vec3 lightVectorW = normalize(lightData.xyz);
+        vec3 H = normalize(viewDirectionW + lightVectorW);
+        float NdotH = max(0.00000000001, dot(vNormal, H));
+        NdotL = max(0.00000000001, NdotL);
+        float VdotH = clamp(0.00000000001, 1.0, dot(viewDirectionW, H));
+
+        vec3 specTerm = computeSpecularTerm(NdotH, NdotL, NdotV, VdotH, roughness, specularColor, reflectance90);
+        result.specular = specTerm;
+    #endif
+
+    return result;
+}

+ 65 - 0
materialsLibrary/src/legacyPBR/legacyPbrLightFunctionsCall.fx

@@ -0,0 +1,65 @@
+#ifdef LIGHT{X}
+    #if defined(LIGHTMAP) && defined(LIGHTMAPEXCLUDED{X}) && defined(LIGHTMAPNOSPECULAR{X})
+        //No light calculation
+    #else
+        #ifdef SPOTLIGHT{X}
+            info = computeSpotLighting(viewDirectionW, normalW, light{X}.vLightData, light{X}.vLightDirection, light{X}.vLightDiffuse.rgb, light{X}.vLightSpecular, light{X}.vLightDiffuse.a, roughness, NdotV, specularEnvironmentR90, NdotL);
+        #endif
+        #ifdef HEMILIGHT{X}
+            info = computeHemisphericLighting(viewDirectionW, normalW, light{X}.vLightData, light{X}.vLightDiffuse.rgb, light{X}.vLightSpecular, light{X}.vLightGround, roughness, NdotV, specularEnvironmentR90, NdotL);
+        #endif
+        #if defined(POINTLIGHT{X}) || defined(DIRLIGHT{X})
+            info = computeLighting(viewDirectionW, normalW, light{X}.vLightData, light{X}.vLightDiffuse.rgb, light{X}.vLightSpecular, light{X}.vLightDiffuse.a, roughness, NdotV, specularEnvironmentR90, NdotL);
+        #endif
+    #endif
+    
+    #ifdef SHADOW{X}
+        #ifdef SHADOWESM{X}
+			#if defined(POINTLIGHT{X})
+				notShadowLevel = computeShadowWithESMCube(light{X}.vLightData.xyz, shadowSampler{X}, light{X}.shadowsInfo.x, light{X}.shadowsInfo.z);
+			#else
+				notShadowLevel = computeShadowWithESM(light{X}.vPositionFromLight, shadowSampler{X}, light{X}.shadowsInfo.x, light{X}.shadowsInfo.z);
+			#endif
+        #else
+            #ifdef SHADOWPCF{X}
+                #if defined(POINTLIGHT{X})
+                    notShadowLevel = computeShadowWithPCFCube(light{X}.vLightData.xyz, shadowSampler{X}, light{X}.shadowsInfo.y, light{X}.shadowsInfo.x);
+                #else
+                    notShadowLevel = computeShadowWithPCF(vPositionFromLight{X}, shadowSampler{X}, light{X}.shadowsInfo.y, light{X}.shadowsInfo.x);
+                #endif
+            #else
+                #if defined(POINTLIGHT{X})
+                    notShadowLevel = computeShadowCube(light{X}.vLightData.xyz, shadowSampler{X}, light{X}.shadowsInfo.x);
+                #else
+                    notShadowLevel = computeShadow(vPositionFromLight{X}, shadowSampler{X}, light{X}.shadowsInfo.x);
+                #endif
+            #endif
+        #endif
+    #else
+        notShadowLevel = 1.;
+    #endif
+    
+    #if defined(LIGHTMAP) && defined(LIGHTMAPEXCLUDED{X})
+	    lightDiffuseContribution += lightmapColor * notShadowLevel;
+	    
+        #ifdef SPECULARTERM
+            #ifndef LIGHTMAPNOSPECULAR{X}
+                lightSpecularContribution += info.specular * notShadowLevel * lightmapColor;
+            #endif
+        #endif
+    #else
+        lightDiffuseContribution += info.diffuse * notShadowLevel;
+        
+        #ifdef OVERLOADEDSHADOWVALUES
+            if (NdotL < 0.000000000011)
+            {
+                notShadowLevel = 1.;
+            }
+            shadowedOnlyLightDiffuseContribution *= notShadowLevel;
+        #endif
+
+        #ifdef SPECULARTERM
+            lightSpecularContribution += info.specular * notShadowLevel;
+        #endif
+    #endif
+#endif

+ 52 - 0
materialsLibrary/src/legacyPBR/legacyPbrUboDeclaration.fx

@@ -0,0 +1,52 @@
+layout(std140, column_major) uniform;
+
+uniform Material
+{
+	uniform vec2 vAlbedoInfos;
+	uniform vec3 vAmbientInfos;
+	uniform vec2 vOpacityInfos;
+	uniform vec2 vEmissiveInfos;
+	uniform vec2 vLightmapInfos;
+	uniform vec3 vReflectivityInfos;
+	uniform vec2 vMicroSurfaceSamplerInfos;
+	uniform vec4 vRefractionInfos;
+	uniform vec2 vReflectionInfos;
+	uniform vec3 vBumpInfos;
+	uniform mat4 albedoMatrix;
+	uniform mat4 ambientMatrix;
+	uniform mat4 opacityMatrix;
+	uniform mat4 emissiveMatrix;
+	uniform mat4 lightmapMatrix;
+	uniform mat4 reflectivityMatrix;
+	uniform mat4 microSurfaceSamplerMatrix;
+	uniform mat4 bumpMatrix;
+	uniform mat4 refractionMatrix;
+	uniform mat4 reflectionMatrix;
+
+	uniform vec3 vReflectionColor;
+	uniform vec4 vAlbedoColor;
+	uniform vec4 vLightingIntensity;
+
+	uniform vec2 vMicrosurfaceTextureLods;
+	uniform vec4 vReflectivityColor;
+	uniform vec3 vEmissiveColor;
+	uniform vec4 opacityParts;
+	uniform vec4 emissiveLeftColor;
+	uniform vec4 emissiveRightColor;
+
+	uniform vec4 vOverloadedIntensity;
+	uniform vec3 vOverloadedAmbient;
+	uniform vec3 vOverloadedAlbedo;
+	uniform vec3 vOverloadedReflectivity;
+	uniform vec3 vOverloadedEmissive;
+	uniform vec3 vOverloadedReflection;
+	uniform vec3 vOverloadedMicroSurface;
+	uniform vec4 vOverloadedShadowIntensity;
+
+	uniform float pointSize;
+};
+
+uniform Scene {
+	mat4 viewProjection;
+	mat4 view;
+};

+ 46 - 0
materialsLibrary/src/legacyPBR/legacyPbrVertexDeclaration.fx

@@ -0,0 +1,46 @@
+uniform mat4 view;
+uniform mat4 viewProjection;
+
+#ifdef ALBEDO
+uniform mat4 albedoMatrix;
+uniform vec2 vAlbedoInfos;
+#endif
+
+#ifdef AMBIENT
+uniform mat4 ambientMatrix;
+uniform vec3 vAmbientInfos;
+#endif
+
+#ifdef OPACITY
+uniform mat4 opacityMatrix;
+uniform vec2 vOpacityInfos;
+#endif
+
+#ifdef EMISSIVE
+uniform vec2 vEmissiveInfos;
+uniform mat4 emissiveMatrix;
+#endif
+
+#ifdef LIGHTMAP
+uniform vec2 vLightmapInfos;
+uniform mat4 lightmapMatrix;
+#endif
+
+#if defined(REFLECTIVITY) || defined(METALLICWORKFLOW) 
+uniform vec3 vReflectivityInfos;
+uniform mat4 reflectivityMatrix;
+#endif
+
+#ifdef MICROSURFACEMAP
+uniform vec2 vMicroSurfaceSamplerInfos;
+uniform mat4 microSurfaceSamplerMatrix;
+#endif
+
+#ifdef BUMP
+uniform vec3 vBumpInfos;
+uniform mat4 bumpMatrix;
+#endif
+
+#ifdef POINTSIZE
+uniform float pointSize;
+#endif

+ 238 - 0
materialsLibrary/test/addlegacypbr.js

@@ -0,0 +1,238 @@
+window.prepareLegacyPBR = function() {
+	var pbr = new BABYLON.LegacyPBRMaterial("legacyPbr", scene);
+
+	pbr.albedoTexture = new BABYLON.Texture("../assets/textures/amiga.jpg", scene);
+	pbr.albedoTexture.uScale = 5;
+	pbr.albedoTexture.vScale = 5;
+    
+    var hdrTexture = new BABYLON.HDRCubeTexture("../assets/textures/hdr/environment.hdr", scene, 512);
+
+    var colorGradingTexture = new BABYLON.ColorGradingTexture("../assets/textures/ColorGrading.3DL", scene);
+    
+    // Uncomment for PMREM Generation
+    // var hdrTexture = new BABYLON.HDRCubeTexture("textures/hdr/environment.hdr", scene, 128, false, true, false, true);
+    pbr.reflectionTexture = hdrTexture;
+    pbr.refractionTexture = hdrTexture;
+    pbr.linkRefractionWithTransparency = true;
+    pbr.indexOfRefraction = 0.52;
+    
+	pbr.reflectivityColor = new BABYLON.Color3(0.3, 0.3, 0.3);
+	pbr.microSurface = 0.9;
+    
+    // Skybox
+    var hdrSkybox = BABYLON.Mesh.CreateBox("hdrSkyBox", 1000.0, scene);
+    var hdrSkyboxMaterial = new BABYLON.PBRMaterial("skyBox", scene);
+    hdrSkyboxMaterial.backFaceCulling = false;
+    hdrSkyboxMaterial.reflectionTexture = hdrTexture.clone();
+    hdrSkyboxMaterial.reflectionTexture.coordinatesMode = BABYLON.Texture.SKYBOX_MODE;
+    hdrSkyboxMaterial.microSurface = 1;
+    hdrSkyboxMaterial.specularColor = new BABYLON.Color3(1, 1, 1);
+    hdrSkyboxMaterial.disableLighting = true;
+    hdrSkyboxMaterial.cameraExposure = 0.6;
+    hdrSkyboxMaterial.cameraContrast = 1.6;
+    hdrSkyboxMaterial.directIntensity = 0;
+    hdrSkybox.material = hdrSkyboxMaterial;
+    hdrSkybox.infiniteDistance = true;
+    hdrSkybox.setEnabled(false);
+    
+	registerButtonUI("legacyPbr", "Default", function() {
+		setRangeValues({
+		  "directIntensity": 1,
+		  "emissiveIntensity": 1,
+		  "environmentIntensity": 1,
+		  "specularIntensity": 1,
+		  "ShadowIntensity": 1,
+		  "ShadeIntensity": 1,
+		  "cameraExposure": 1,
+		  "cameraContrast": 1,
+		  "microSurface": 0.9,
+		  "reflectivityColorR": 0.3,
+		  "reflectivityColorG": 0.3,
+		  "reflectivityColorB": 0.3,
+		  "albedoColorR": 1,
+		  "albedoColorG": 1,
+		  "albedoColorB": 1,
+		  "albedoColorLevel": 0
+		});
+	});
+    registerButtonUI("legacyPbr", "Env Irradiance", function() {
+		setRangeValues({
+		  "directIntensity": 0,
+		  "emissiveIntensity": 1,
+		  "environmentIntensity": 1,
+		  "specularIntensity": 1,
+		  "ShadowIntensity": 1,
+		  "ShadeIntensity": 1,
+		  "cameraExposure": 1,
+		  "cameraContrast": 1,
+		  "microSurface": 0,
+		  "reflectivityColorR": 0,
+		  "reflectivityColorG": 0,
+		  "reflectivityColorB": 0,
+		  "albedoColorR": 1,
+		  "albedoColorG": 1,
+		  "albedoColorB": 1,
+		  "albedoColorLevel": 1
+		});
+        
+        hdrSkybox.setEnabled(true);
+	});
+	registerButtonUI("legacyPbr", "Rough Gold", function() {
+		setRangeValues({
+		  "directIntensity": 1.3439461727881254,
+		  "emissiveIntensity": 1,
+		  "environmentIntensity": 0.3685013699580344,
+		  "specularIntensity": 1,
+		  "ShadowIntensity": 1,
+		  "ShadeIntensity": 1,
+		  "cameraExposure": 0.7153261887420668,
+		  "cameraContrast": 1.6474178892241538,
+		  "microSurface": 0.42269274789303946,
+		  "reflectivityColorR": 1,
+		  "reflectivityColorG": 0.8453854957860789,
+		  "reflectivityColorB": 0.5093989525890475,
+		  "albedoColorR": 0,
+		  "albedoColorG": 0,
+		  "albedoColorB": 0,
+		  "albedoColorLevel": 1
+		});
+	});
+	registerButtonUI("legacyPbr", "Plastic", function() {
+		setRangeValues({
+		  "directIntensity": 0.9971213540040931,
+		  "emissiveIntensity": 1,
+		  "environmentIntensity": 0.3685013699580344,
+		  "specularIntensity": 1,
+		  "ShadowIntensity": 0.975444802830091,
+		  "ShadeIntensity": 0.8020323934380749,
+		  "cameraExposure": 0.7586792910900708,
+		  "cameraContrast": 1.5823882357021477,
+		  "microSurface": 0.8562237713730799,
+		  "reflectivityColorR": 0.05,
+		  "reflectivityColorG": 0.05,
+		  "reflectivityColorB": 0.05,
+		  "albedoColorR": 0.20592723615301922,
+		  "albedoColorG": 0.942929976069088,
+		  "albedoColorB": 1,
+		  "albedoColorLevel": 1
+		});
+	});
+	
+    registerRangeUI("legacyPbr", "indiceOfRefraction", 0, 2, function(value) {
+		pbr.indexOfRefraction = value;
+	}, function() {
+		return pbr.indexOfRefraction;
+	});
+    
+    registerRangeUI("legacyPbr", "alpha", 0, 1, function(value) {
+		pbr.alpha = value;
+	}, function() {
+		return pbr.alpha;
+	});
+    
+    registerRangeUI("legacyPbr", "directIntensity", 0, 2, function(value) {
+		pbr.directIntensity = value;
+	}, function() {
+		return pbr.directIntensity;
+	});
+    
+	registerRangeUI("legacyPbr", "emissiveIntensity", 0, 2, function(value) {
+		pbr.emissiveIntensity = value;
+	}, function() {
+		return pbr.emissiveIntensity;
+	});
+	
+	registerRangeUI("legacyPbr", "environmentIntensity", 0, 2, function(value) {
+		pbr.environmentIntensity = value;
+	}, function() {
+		return pbr.environmentIntensity;
+	});
+
+	registerRangeUI("legacyPbr", "specularIntensity", 0, 2, function(value) {
+		pbr.specularIntensity = value;
+	}, function() {
+		return pbr.specularIntensity;
+	});
+	
+	registerRangeUI("legacyPbr", "ShadowIntensity", 0, 2, function(value) {
+		pbr.overloadedShadowIntensity = value;
+	}, function() {
+		return pbr.overloadedShadowIntensity;
+	});
+	
+	registerRangeUI("legacyPbr", "ShadeIntensity", 0, 2, function(value) {
+		pbr.overloadedShadeIntensity = value;
+	}, function() {
+		return pbr.overloadedShadeIntensity;
+	});
+	
+	registerRangeUI("legacyPbr", "cameraExposure", 0, 2, function(value) {
+		pbr.cameraExposure = value;
+	}, function() {
+		return pbr.cameraExposure;
+	});
+
+	registerRangeUI("legacyPbr", "cameraContrast", 0, 2, function(value) {
+		pbr.cameraContrast = value;
+	}, function() {
+		return pbr.cameraContrast;
+	});
+	
+	registerRangeUI("legacyPbr", "microSurface", 0, 1, function(value) {
+		pbr.microSurface = value;
+	}, function() {
+		return pbr.microSurface;
+	});
+
+	registerRangeUI("legacyPbr", "reflectivityColorR", 0, 1, function(value) {
+		pbr.reflectivityColor.r = value;
+	}, function() {
+		return pbr.reflectivityColor.r;
+	});
+
+	registerRangeUI("legacyPbr", "reflectivityColorG", 0, 1, function(value) {
+		pbr.reflectivityColor.g = value;
+	}, function() {
+		return pbr.reflectivityColor.g;
+	});
+
+	registerRangeUI("legacyPbr", "reflectivityColorB", 0, 1, function(value) {
+		pbr.reflectivityColor.b = value;
+	}, function() {
+		return pbr.reflectivityColor.b;
+	});
+
+	registerRangeUI("legacyPbr", "albedoColorR", 0, 1, function(value) {
+		pbr.overloadedAlbedo.r = value;
+	}, function() {
+		return pbr.overloadedAlbedo.r;
+	});
+
+	registerRangeUI("legacyPbr", "albedoColorG", 0, 1, function(value) {
+		pbr.overloadedAlbedo.g = value;
+	}, function() {
+		return pbr.overloadedAlbedo.g;
+	});
+
+	registerRangeUI("legacyPbr", "albedoColorB", 0, 1, function(value) {
+		pbr.overloadedAlbedo.b = value;
+	}, function() {
+		return pbr.overloadedAlbedo.b;
+	});
+
+	registerRangeUI("legacyPbr", "albedoColorLevel", 0, 1, function(value) {
+		pbr.overloadedAlbedoIntensity = value;
+	}, function() {
+		return pbr.overloadedAlbedoIntensity;
+	});
+    
+    registerButtonUI("legacyPbr", "Toggle Skybox", function() {
+        hdrSkybox.setEnabled(!hdrSkybox.isEnabled());
+	});
+
+    registerButtonUI("legacyPbr", "Color Grading", function() {
+        pbr.cameraColorGradingTexture = pbr.cameraColorGradingTexture ? null : colorGradingTexture; 
+	});
+
+	return pbr;
+}

+ 8 - 0
src/Materials/babylon.material.ts

@@ -586,6 +586,14 @@
                 return StandardMaterial.Parse(parsedMaterial, scene, rootUrl);
             }
 
+            if (parsedMaterial.customType === "BABYLON.PBRMaterial" && !parsedMaterial.overloadedAlbedo) {
+                parsedMaterial.customType === "BABYLON.legacyPBRMaterial";
+                if (!(<any>BABYLON).legacyPBRMaterial) {
+                    BABYLON.Tools.Error("Your scene is trying to load a legacy version of the PBRMaterial, please, include it from the materials library.");
+                    return;
+                }
+            }
+
             var materialType = Tools.Instantiate(parsedMaterial.customType);
             return materialType.Parse(parsedMaterial, scene, rootUrl);;
         }