浏览代码

Add PBR Includes

Sébastien Vandenberghe 9 年之前
父节点
当前提交
17edd528ca

+ 5 - 1
materialsLibrary/config.json

@@ -12,7 +12,11 @@
     {
       "file": "materials/pbr/babylon.pbrMaterial.ts",
       "referenceFiles": [
-        "materials/pbr/includes/helperFunctions.fx"  
+        "materials/pbr/includes/pbrFunctions.fx",
+        "materials/pbr/includes/harmonicsFunctions.fx",
+        "materials/pbr/includes/pbrLightFunctions.fx",
+        "materials/pbr/includes/pbrLightFunctionsCall.fx",
+        "materials/pbr/includes/pbrShadowFunctions.fx"  
       ],
       "shaderFiles": [
         "materials/pbr/pbr.vertex.fx",

文件差异内容过多而无法显示
+ 7 - 3
materialsLibrary/dist/babylon.pbrMaterial.js


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


+ 31 - 0
materialsLibrary/materials/pbr/includes/harmonicsFunctions.fx

@@ -0,0 +1,31 @@
+#ifdef USESPHERICALFROMREFLECTIONMAP
+    uniform vec3 vSphericalX;
+    uniform vec3 vSphericalY;
+    uniform vec3 vSphericalZ;
+    uniform vec3 vSphericalXX;
+    uniform vec3 vSphericalYY;
+    uniform vec3 vSphericalZZ;
+    uniform vec3 vSphericalXY;
+    uniform vec3 vSphericalYZ;
+    uniform vec3 vSphericalZX;
+
+    vec3 EnvironmentIrradiance(vec3 normal)
+    {
+        // Note: 'normal' is assumed to be normalised (or near normalised)
+        // This isn't as critical as it is with other calculations (e.g. specular highlight), but the result will be incorrect nonetheless.
+
+        // TODO: switch to optimal implementation
+        vec3 result =
+            vSphericalX * normal.x +
+            vSphericalY * normal.y +
+            vSphericalZ * normal.z +
+            vSphericalXX * normal.x * normal.x +
+            vSphericalYY * normal.y * normal.y +
+            vSphericalZZ * normal.z * normal.z +
+            vSphericalYZ * normal.y * normal.z +
+            vSphericalZX * normal.z * normal.x +
+            vSphericalXY * normal.x * normal.y;
+
+        return result.rgb;
+    }
+#endif

+ 0 - 18
materialsLibrary/materials/pbr/includes/helperFunctions.fx

@@ -1,18 +0,0 @@
-// PBR HELPER METHODS
-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;
-}

+ 197 - 0
materialsLibrary/materials/pbr/includes/pbrFunctions.fx

@@ -0,0 +1,197 @@
+// 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)
+{
+    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, vec3(1., 1., 1.));
+
+    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)
+{
+    // At small angle this approximation works. 
+    float lightRoughness = lightRadius / lightDistance;
+    // Distribution can sum.
+    float totalRoughness = clamp(lightRoughness + roughness, 0., 1.);
+    return totalRoughness;
+}
+
+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));
+}
+
+float computeLightFalloff(vec3 lightOffset, float lightDistanceSquared, float range)
+{
+    #ifdef USEPHYSICALLIGHTFALLOFF
+        float lightDistanceFalloff = 1.0 / ((lightDistanceSquared + 0.0001));
+        return lightDistanceFalloff;
+    #else
+        float lightFalloff = max(0., 1.0 - length(lightOffset) / range);
+        return lightFalloff;
+    #endif
+}
+
+#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

+ 130 - 0
materialsLibrary/materials/pbr/includes/pbrLightFunctions.fx

@@ -0,0 +1,130 @@
+// Light Computing
+struct lightingInfo
+{
+    vec3 diffuse;
+    #ifdef SPECULARTERM
+        vec3 specular;
+    #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 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 = computeLightFalloff(lightOffset, lightDistanceSquared, range);
+        
+        lightDistance = sqrt(lightDistanceSquared);
+        lightDirection = normalize(lightOffset);
+    }
+    // Directional
+    else
+    {
+        lightDistance = length(-lightData.xyz);
+        lightDirection = normalize(-lightData.xyz);
+    }
+    
+    // Roughness
+    roughness = adjustRoughnessFromLightProperties(roughness, lightRadius, 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);
+        result.specular = specTerm * attenuation;
+    #endif
+
+    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 result;
+
+    vec3 lightOffset = lightData.xyz - vPositionW;
+    vec3 lightVectorW = normalize(lightOffset);
+
+    // diffuse
+    float cosAngle = max(0.000000000000001, dot(-lightDirection.xyz, lightVectorW));
+    
+    if (cosAngle >= lightDirection.w)
+    {
+        cosAngle = max(0., pow(cosAngle, lightData.w));
+        
+        // Inverse squared falloff.
+        float lightDistanceSquared = dot(lightOffset, lightOffset);
+        float attenuation = computeLightFalloff(lightOffset, lightDistanceSquared, range);
+        
+        // Directional falloff.
+        attenuation *= cosAngle;
+        
+        // Roughness.
+        float lightDistance = sqrt(lightDistanceSquared);
+        roughness = adjustRoughnessFromLightProperties(roughness, lightRadius, lightDistance);
+        
+        // Diffuse
+        vec3 H = normalize(viewDirectionW - lightDirection.xyz);
+        NdotL = max(0.00000000001, dot(vNormal, -lightDirection.xyz));
+        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);
+            result.specular = specTerm  * attenuation;
+        #endif
+
+        return result;
+    }
+
+    result.diffuse = vec3(0.);
+    #ifdef SPECULARTERM
+        result.specular = vec3(0.);
+    #endif
+
+    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 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);
+        result.specular = specTerm;
+    #endif
+
+    return result;
+}

+ 50 - 0
materialsLibrary/materials/pbr/includes/pbrLightFunctionsCall.fx

@@ -0,0 +1,50 @@
+#ifdef LIGHT{X}
+    #ifndef SPECULARTERM
+        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);
+    #endif
+    #ifdef HEMILIGHT{X}
+        info = computeHemisphericLighting(viewDirectionW, normalW, vLightData{X}, vLightDiffuse{X}.rgb, vLightSpecular{X}, vLightGround{X}, roughness, NdotV, vLightRadiuses[{X}], 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);
+    #endif
+    
+    #ifdef SHADOW{X}
+        #ifdef SHADOWVSM{X}
+            notShadowLevel = computeShadowWithVSM(vPositionFromLight{X}, shadowSampler{X}, shadowsInfo{X}.z, shadowsInfo{X}.x);
+        #else
+            #ifdef SHADOWPCF{X}
+                #if defined(POINTLIGHT{X})
+                    notShadowLevel = computeShadowWithPCFCube(vLightData{X}.xyz, shadowSampler{X}, shadowsInfo{X}.y, shadowsInfo{X}.z, shadowsInfo{X}.x);
+                #else
+                    notShadowLevel = computeShadowWithPCF(vPositionFromLight{X}, shadowSampler{X}, shadowsInfo{X}.y, shadowsInfo{X}.z, shadowsInfo{X}.x);
+                #endif
+            #else
+                #if defined(POINTLIGHT{X})
+                    notShadowLevel = computeShadowCube(vLightData{X}.xyz, shadowSampler{X}, shadowsInfo{X}.x, shadowsInfo{X}.z);
+                #else
+                    notShadowLevel = computeShadow(vPositionFromLight{X}, shadowSampler{X}, shadowsInfo{X}.x, shadowsInfo{X}.z);
+                #endif
+            #endif
+        #endif
+    #else
+        notShadowLevel = 1.;
+    #endif
+    
+    lightDiffuseContribution += info.diffuse * notShadowLevel;
+    
+    #ifdef OVERLOADEDSHADOWVALUES
+        if (NdotL < 0.000000000011)
+        {
+            notShadowLevel = 1.;
+        }
+        shadowedOnlyLightDiffuseContribution *= notShadowLevel;
+    #endif
+
+    #ifdef SPECULARTERM
+        lightSpecularContribution += info.specular * notShadowLevel;
+    #endif
+#endif

+ 171 - 0
materialsLibrary/materials/pbr/includes/pbrShadowFunctions.fx

@@ -0,0 +1,171 @@
+// Shadows
+#ifdef SHADOWS
+
+    float unpack(vec4 color)
+    {
+        const vec4 bit_shift = vec4(1.0 / (255.0 * 255.0 * 255.0), 1.0 / (255.0 * 255.0), 1.0 / 255.0, 1.0);
+        return dot(color, bit_shift);
+    }
+
+    #if defined(POINTLIGHT0) || defined(POINTLIGHT1) || defined(POINTLIGHT2) || defined(POINTLIGHT3)
+        uniform vec2 depthValues;
+
+        float computeShadowCube(vec3 lightPosition, samplerCube shadowSampler, float darkness, float bias)
+        {
+            vec3 directionToLight = vPositionW - lightPosition;
+            float depth = length(directionToLight);
+            depth = clamp(depth, 0., 1.0);
+
+            directionToLight = normalize(directionToLight);
+            directionToLight.y = - directionToLight.y;
+
+            float shadow = unpack(textureCube(shadowSampler, directionToLight)) + bias;
+
+            if (depth > shadow)
+            {
+                #ifdef OVERLOADEDSHADOWVALUES
+                    return mix(1.0, darkness, vOverloadedShadowIntensity.x);
+                #else
+                    return darkness;
+                #endif
+            }
+            return 1.0;
+        }
+
+        float computeShadowWithPCFCube(vec3 lightPosition, samplerCube shadowSampler, float mapSize, float bias, float darkness)
+        {
+            vec3 directionToLight = vPositionW - lightPosition;
+            float depth = length(directionToLight);
+
+            depth = (depth - depthValues.x) / (depthValues.y - depthValues.x);
+            depth = clamp(depth, 0., 1.0);
+
+            directionToLight = normalize(directionToLight);
+            directionToLight.y = -directionToLight.y;
+
+            float visibility = 1.;
+
+            vec3 poissonDisk[4];
+            poissonDisk[0] = vec3(-1.0, 1.0, -1.0);
+            poissonDisk[1] = vec3(1.0, -1.0, -1.0);
+            poissonDisk[2] = vec3(-1.0, -1.0, -1.0);
+            poissonDisk[3] = vec3(1.0, -1.0, 1.0);
+
+            // Poisson Sampling
+            float biasedDepth = depth - bias;
+
+            if (unpack(textureCube(shadowSampler, directionToLight + poissonDisk[0] * mapSize)) < biasedDepth) visibility -= 0.25;
+            if (unpack(textureCube(shadowSampler, directionToLight + poissonDisk[1] * mapSize)) < biasedDepth) visibility -= 0.25;
+            if (unpack(textureCube(shadowSampler, directionToLight + poissonDisk[2] * mapSize)) < biasedDepth) visibility -= 0.25;
+            if (unpack(textureCube(shadowSampler, directionToLight + poissonDisk[3] * mapSize)) < biasedDepth) visibility -= 0.25;
+
+            #ifdef OVERLOADEDSHADOWVALUES
+                return  min(1.0, mix(1.0, visibility + darkness, vOverloadedShadowIntensity.x));
+            #else
+                return  min(1.0, visibility + darkness);
+            #endif
+        }
+    #endif
+
+    #if defined(SPOTLIGHT0) || defined(SPOTLIGHT1) || defined(SPOTLIGHT2) || defined(SPOTLIGHT3) ||  defined(DIRLIGHT0) || defined(DIRLIGHT1) || defined(DIRLIGHT2) || defined(DIRLIGHT3)
+        float computeShadow(vec4 vPositionFromLight, sampler2D shadowSampler, float darkness, float bias)
+        {
+            vec3 depth = vPositionFromLight.xyz / vPositionFromLight.w;
+            depth = 0.5 * depth + vec3(0.5);
+            vec2 uv = depth.xy;
+
+            if (uv.x < 0. || uv.x > 1.0 || uv.y < 0. || uv.y > 1.0)
+            {
+                return 1.0;
+            }
+
+            float shadow = unpack(texture2D(shadowSampler, uv)) + bias;
+
+            if (depth.z > shadow)
+            {
+                #ifdef OVERLOADEDSHADOWVALUES
+                    return mix(1.0, darkness, vOverloadedShadowIntensity.x);
+                #else
+                    return darkness;
+                #endif
+            }
+            return 1.;
+        }
+
+        float computeShadowWithPCF(vec4 vPositionFromLight, sampler2D shadowSampler, float mapSize, float bias, float darkness)
+        {
+            vec3 depth = vPositionFromLight.xyz / vPositionFromLight.w;
+            depth = 0.5 * depth + vec3(0.5);
+            vec2 uv = depth.xy;
+
+            if (uv.x < 0. || uv.x > 1.0 || uv.y < 0. || uv.y > 1.0)
+            {
+                return 1.0;
+            }
+
+            float visibility = 1.;
+
+            vec2 poissonDisk[4];
+            poissonDisk[0] = vec2(-0.94201624, -0.39906216);
+            poissonDisk[1] = vec2(0.94558609, -0.76890725);
+            poissonDisk[2] = vec2(-0.094184101, -0.92938870);
+            poissonDisk[3] = vec2(0.34495938, 0.29387760);
+
+            // Poisson Sampling
+            float biasedDepth = depth.z - bias;
+
+            if (unpack(texture2D(shadowSampler, uv + poissonDisk[0] * mapSize)) < biasedDepth) visibility -= 0.25;
+            if (unpack(texture2D(shadowSampler, uv + poissonDisk[1] * mapSize)) < biasedDepth) visibility -= 0.25;
+            if (unpack(texture2D(shadowSampler, uv + poissonDisk[2] * mapSize)) < biasedDepth) visibility -= 0.25;
+            if (unpack(texture2D(shadowSampler, uv + poissonDisk[3] * mapSize)) < biasedDepth) visibility -= 0.25;
+
+            #ifdef OVERLOADEDSHADOWVALUES
+                return  min(1.0, mix(1.0, visibility + darkness, vOverloadedShadowIntensity.x));
+            #else
+                return  min(1.0, visibility + darkness);
+            #endif
+        }
+
+        // Thanks to http://devmaster.net/
+        float unpackHalf(vec2 color)
+        {
+            return color.x + (color.y / 255.0);
+        }
+
+        float linstep(float low, float high, float v) {
+            return clamp((v - low) / (high - low), 0.0, 1.0);
+        }
+
+        float ChebychevInequality(vec2 moments, float compare, float bias)
+        {
+            float p = smoothstep(compare - bias, compare, moments.x);
+            float variance = max(moments.y - moments.x * moments.x, 0.02);
+            float d = compare - moments.x;
+            float p_max = linstep(0.2, 1.0, variance / (variance + d * d));
+
+            return clamp(max(p, p_max), 0.0, 1.0);
+        }
+
+        float computeShadowWithVSM(vec4 vPositionFromLight, sampler2D shadowSampler, float bias, float darkness)
+        {
+            vec3 depth = vPositionFromLight.xyz / vPositionFromLight.w;
+            depth = 0.5 * depth + vec3(0.5);
+            vec2 uv = depth.xy;
+
+            if (uv.x < 0. || uv.x > 1.0 || uv.y < 0. || uv.y > 1.0 || depth.z >= 1.0)
+            {
+                return 1.0;
+            }
+
+            vec4 texel = texture2D(shadowSampler, uv);
+
+            vec2 moments = vec2(unpackHalf(texel.xy), unpackHalf(texel.zw));
+            #ifdef OVERLOADEDSHADOWVALUES
+                return min(1.0, mix(1.0, 1.0 - ChebychevInequality(moments, depth.z, bias) + darkness, vOverloadedShadowIntensity.x));
+            #else
+                return min(1.0, 1.0 - ChebychevInequality(moments, depth.z, bias) + darkness);
+            #endif
+        }
+    #endif
+
+#endif

+ 9 - 420
materialsLibrary/materials/pbr/legacypbr.fragment.fx

@@ -28,185 +28,6 @@ uniform vec3 vOverloadedMicroSurface;
 uniform vec4 vOverloadedShadowIntensity;
 #endif
 
-// PBR CUSTOM CONSTANTS
-const float kPi = 3.1415926535897932384626433832795;
-const float kRougnhessToAlphaScale = 0.1;
-const float kRougnhessToAlphaOffset = 0.29248125;
-
-#include<helperFunctions>
-
-// 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)
-{
-    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, vec3(1., 1., 1.));
-
-    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)
-{
-    // At small angle this approximation works. 
-    float lightRoughness = lightRadius / lightDistance;
-    // Distribution can sum.
-    float totalRoughness = clamp(lightRoughness + roughness, 0., 1.);
-    return totalRoughness;
-}
-
-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));
-}
-
-float computeLightFalloff(vec3 lightOffset, float lightDistanceSquared, float range)
-{
-    #ifdef USEPHYSICALLIGHTFALLOFF
-        float lightDistanceFalloff = 1.0 / ((lightDistanceSquared + 0.0001));
-        return lightDistanceFalloff;
-    #else
-        float lightFalloff = max(0., 1.0 - length(lightOffset) / range);
-        return lightFalloff;
-    #endif
-}
-
-#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
-// END PBR HELPER METHODS
-
 uniform vec4 vReflectivityColor;
 uniform vec3 vEmissiveColor;
 
@@ -266,136 +87,10 @@ uniform sampler2D reflectivitySampler;
 
 #include<clipPlaneFragmentDeclaration>
 
-// Light Computing
-struct lightingInfo
-{
-    vec3 diffuse;
-#ifdef SPECULARTERM
-    vec3 specular;
-#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 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 = computeLightFalloff(lightOffset, lightDistanceSquared, range);
-        
-        lightDistance = sqrt(lightDistanceSquared);
-        lightDirection = normalize(lightOffset);
-    }
-    // Directional
-    else
-    {
-        lightDistance = length(-lightData.xyz);
-        lightDirection = normalize(-lightData.xyz);
-    }
-    
-    // Roughness
-    roughness = adjustRoughnessFromLightProperties(roughness, lightRadius, 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);
-    result.specular = specTerm * attenuation;
-#endif
-
-    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 result;
-
-    vec3 lightOffset = lightData.xyz - vPositionW;
-    vec3 lightVectorW = normalize(lightOffset);
-
-    // diffuse
-    float cosAngle = max(0.000000000000001, dot(-lightDirection.xyz, lightVectorW));
-    
-    if (cosAngle >= lightDirection.w)
-    {
-        cosAngle = max(0., pow(cosAngle, lightData.w));
-        
-        // Inverse squared falloff.
-        float lightDistanceSquared = dot(lightOffset, lightOffset);
-        float attenuation = computeLightFalloff(lightOffset, lightDistanceSquared, range);
-        
-        // Directional falloff.
-        attenuation *= cosAngle;
-        
-        // Roughness.
-        float lightDistance = sqrt(lightDistanceSquared);
-        roughness = adjustRoughnessFromLightProperties(roughness, lightRadius, lightDistance);
-        
-        // Diffuse
-        vec3 H = normalize(viewDirectionW - lightDirection.xyz);
-        NdotL = max(0.00000000001, dot(vNormal, -lightDirection.xyz));
-        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);
-        result.specular = specTerm  * attenuation;
-#endif
-
-        return result;
-    }
-
-    result.diffuse = vec3(0.);
-#ifdef SPECULARTERM
-    result.specular = vec3(0.);
-#endif
-
-    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 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);
-    result.specular = specTerm;
-#endif
-
-    return result;
-}
+// PBR
+#include<pbrFunctions>
+#include<harmonicsFunctions>
+#include<pbrLightFunctions>
 
 void main(void) {
 #include<clipPlaneFragment>
@@ -506,118 +201,12 @@ void main(void) {
 #endif
     float notShadowLevel = 1.; // 1 - shadowLevel
     float NdotL = -1.;
+    lightingInfo info;
 
-#ifdef LIGHT0
-#ifndef SPECULARTERM
-    vec3 vLightSpecular0 = vec3(0.0);
-#endif
-#ifdef SPOTLIGHT0
-    lightingInfo info = computeSpotLighting(viewDirectionW, normalW, vLightData0, vLightDirection0, vLightDiffuse0.rgb, vLightSpecular0, vLightDiffuse0.a, roughness, NdotV, vLightRadiuses[0], NdotL);
-#endif
-#ifdef HEMILIGHT0
-    lightingInfo info = computeHemisphericLighting(viewDirectionW, normalW, vLightData0, vLightDiffuse0.rgb, vLightSpecular0, vLightGround0, roughness, NdotV, vLightRadiuses[0], NdotL);
-#endif
-#if defined(POINTLIGHT0) || defined(DIRLIGHT0)
-    lightingInfo info = computeLighting(viewDirectionW, normalW, vLightData0, vLightDiffuse0.rgb, vLightSpecular0, vLightDiffuse0.a, roughness, NdotV, vLightRadiuses[0], NdotL);
-#endif
-    notShadowLevel = 1.;
-    lightDiffuseContribution += info.diffuse * notShadowLevel;
-#ifdef OVERLOADEDSHADOWVALUES
-    if (NdotL < 0.000000000011)
-    {
-        notShadowLevel = 1.;
-    }
-    shadowedOnlyLightDiffuseContribution *= notShadowLevel;
-#endif
-#ifdef SPECULARTERM
-    lightSpecularContribution += info.specular * notShadowLevel;
-#endif
-#endif
-
-#ifdef LIGHT1
-#ifndef SPECULARTERM
-    vec3 vLightSpecular1 = vec3(0.0);
-#endif
-#ifdef SPOTLIGHT1
-    info = computeSpotLighting(viewDirectionW, normalW, vLightData1, vLightDirection1, vLightDiffuse1.rgb, vLightSpecular1, vLightDiffuse1.a, roughness, NdotV, vLightRadiuses[1], NdotL);
-#endif
-#ifdef HEMILIGHT1
-    info = computeHemisphericLighting(viewDirectionW, normalW, vLightData1, vLightDiffuse1.rgb, vLightSpecular1, vLightGround1, roughness, NdotV, vLightRadiuses[1], NdotL);
-#endif
-#if defined(POINTLIGHT1) || defined(DIRLIGHT1)
-    info = computeLighting(viewDirectionW, normalW, vLightData1, vLightDiffuse1.rgb, vLightSpecular1, vLightDiffuse1.a, roughness, NdotV, vLightRadiuses[1], NdotL);
-#endif
-    notShadowLevel = 1.;
-    lightDiffuseContribution += info.diffuse * notShadowLevel;
-#ifdef OVERLOADEDSHADOWVALUES
-    if (NdotL < 0.000000000011)
-    {
-        notShadowLevel = 1.;
-    }
-    shadowedOnlyLightDiffuseContribution *= notShadowLevel;
-#endif
-
-#ifdef SPECULARTERM
-    lightSpecularContribution += info.specular * notShadowLevel;
-#endif
-#endif
-
-#ifdef LIGHT2
-#ifndef SPECULARTERM
-    vec3 vLightSpecular2 = vec3(0.0);
-#endif
-#ifdef SPOTLIGHT2
-    info = computeSpotLighting(viewDirectionW, normalW, vLightData2, vLightDirection2, vLightDiffuse2.rgb, vLightSpecular2, vLightDiffuse2.a, roughness, NdotV, vLightRadiuses[2], NdotL);
-#endif
-#ifdef HEMILIGHT2
-    info = computeHemisphericLighting(viewDirectionW, normalW, vLightData2, vLightDiffuse2.rgb, vLightSpecular2, vLightGround2, roughness, NdotV, vLightRadiuses[2], NdotL);
-#endif
-#if defined(POINTLIGHT2) || defined(DIRLIGHT2)
-    info = computeLighting(viewDirectionW, normalW, vLightData2, vLightDiffuse2.rgb, vLightSpecular2, vLightDiffuse2.a, roughness, NdotV, vLightRadiuses[2], NdotL);
-#endif
-    notShadowLevel = 1.;
-    lightDiffuseContribution += info.diffuse * notShadowLevel;
-#ifdef OVERLOADEDSHADOWVALUES
-    if (NdotL < 0.000000000011)
-    {
-        notShadowLevel = 1.;
-    }
-    shadowedOnlyLightDiffuseContribution *= notShadowLevel;
-#endif
-
-#ifdef SPECULARTERM
-    lightSpecularContribution += info.specular * notShadowLevel;
-#endif
-#endif
-
-#ifdef LIGHT3
-#ifndef SPECULARTERM
-    vec3 vLightSpecular3 = vec3(0.0);
-#endif
-#ifdef SPOTLIGHT3
-    info = computeSpotLighting(viewDirectionW, normalW, vLightData3, vLightDirection3, vLightDiffuse3.rgb, vLightSpecular3, vLightDiffuse3.a, roughness, NdotV, vLightRadiuses[3], NdotL);
-#endif
-#ifdef HEMILIGHT3
-    info = computeHemisphericLighting(viewDirectionW, normalW, vLightData3, vLightDiffuse3.rgb, vLightSpecular3, vLightGround3, roughness, NdotV, vLightRadiuses[3], NdotL);
-#endif
-#if defined(POINTLIGHT3) || defined(DIRLIGHT3)
-    info = computeLighting(viewDirectionW, normalW, vLightData3, vLightDiffuse3.rgb, vLightSpecular3, vLightDiffuse3.a, roughness, NdotV, vLightRadiuses[3], NdotL);
-#endif
-
-    notShadowLevel = 1.;
-    lightDiffuseContribution += info.diffuse * notShadowLevel;
-#ifdef OVERLOADEDSHADOWVALUES
-    if (NdotL < 0.000000000011)
-    {
-        notShadowLevel = 1.;
-    }
-    shadowedOnlyLightDiffuseContribution *= notShadowLevel;
-#endif
-
-#ifdef SPECULARTERM
-    lightSpecularContribution += info.specular * notShadowLevel;
-#endif
-#endif
+#include<pbrLightFunctionsCall>[0]
+#include<pbrLightFunctionsCall>[1]
+#include<pbrLightFunctionsCall>[2]
+#include<pbrLightFunctionsCall>[3]
 
 #ifdef SPECULARTERM
     lightSpecularContribution *= vLightingIntensity.w;

+ 12 - 713
materialsLibrary/materials/pbr/pbr.fragment.fx

@@ -12,10 +12,6 @@
 
 precision highp float;
 
-// Constants
-#define RECIPROCAL_PI2 0.15915494
-#define FRESNEL_MAXIMUM_ON_ROUGH 0.25
-
 uniform vec3 vEyePosition;
 uniform vec3 vAmbientColor;
 uniform vec3 vReflectionColor;
@@ -40,223 +36,12 @@ uniform vec4 vCameraInfos;
     uniform vec4 vOverloadedShadowIntensity;
 #endif
 
-#ifdef USESPHERICALFROMREFLECTIONMAP
-    uniform vec3 vSphericalX;
-    uniform vec3 vSphericalY;
-    uniform vec3 vSphericalZ;
-    uniform vec3 vSphericalXX;
-    uniform vec3 vSphericalYY;
-    uniform vec3 vSphericalZZ;
-    uniform vec3 vSphericalXY;
-    uniform vec3 vSphericalYZ;
-    uniform vec3 vSphericalZX;
-
-    vec3 EnvironmentIrradiance(vec3 normal)
-    {
-        // Note: 'normal' is assumed to be normalised (or near normalised)
-        // This isn't as critical as it is with other calculations (e.g. specular highlight), but the result will be incorrect nonetheless.
-
-        // TODO: switch to optimal implementation
-        vec3 result =
-            vSphericalX * normal.x +
-            vSphericalY * normal.y +
-            vSphericalZ * normal.z +
-            vSphericalXX * normal.x * normal.x +
-            vSphericalYY * normal.y * normal.y +
-            vSphericalZZ * normal.z * normal.z +
-            vSphericalYZ * normal.y * normal.z +
-            vSphericalZX * normal.z * normal.x +
-            vSphericalXY * normal.x * normal.y;
-
-        return result.rgb;
-    }
-#endif
-
 #if defined(REFLECTION) || defined(REFRACTION)
     uniform vec2 vMicrosurfaceTextureLods;
 #endif
 
-// PBR CUSTOM CONSTANTS
-const float kPi = 3.1415926535897932384626433832795;
-const float kRougnhessToAlphaScale = 0.1;
-const float kRougnhessToAlphaOffset = 0.29248125;
-
-#include<helperFunctions>
-
-// 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)
-{
-    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, vec3(1., 1., 1.));
-
-    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)
-{
-    // At small angle this approximation works. 
-    float lightRoughness = lightRadius / lightDistance;
-    // Distribution can sum.
-    float totalRoughness = clamp(lightRoughness + roughness, 0., 1.);
-    return totalRoughness;
-}
-
-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));
-}
-
-float computeLightFalloff(vec3 lightOffset, float lightDistanceSquared, float range)
-{
-    #ifdef USEPHYSICALLIGHTFALLOFF
-        float lightDistanceFalloff = 1.0 / ((lightDistanceSquared + 0.0001));
-        return lightDistanceFalloff;
-    #else
-        float lightFalloff = max(0., 1.0 - length(lightOffset) / range);
-        return lightFalloff;
-    #endif
-}
-
-#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
-// END PBR HELPER METHODS
-
-    uniform vec4 vReflectivityColor;
-    uniform vec3 vEmissiveColor;
+uniform vec4 vReflectivityColor;
+uniform vec3 vEmissiveColor;
 
 // Input
 varying vec3 vPositionW;
@@ -367,177 +152,11 @@ varying vec3 vPositionUVW;
 
 #endif
 
-// Shadows
-#ifdef SHADOWS
-
-float unpack(vec4 color)
-{
-    const vec4 bit_shift = vec4(1.0 / (255.0 * 255.0 * 255.0), 1.0 / (255.0 * 255.0), 1.0 / 255.0, 1.0);
-    return dot(color, bit_shift);
-}
-
-#if defined(POINTLIGHT0) || defined(POINTLIGHT1) || defined(POINTLIGHT2) || defined(POINTLIGHT3)
-uniform vec2 depthValues;
-
-float computeShadowCube(vec3 lightPosition, samplerCube shadowSampler, float darkness, float bias)
-{
-	vec3 directionToLight = vPositionW - lightPosition;
-	float depth = length(directionToLight);
-	depth = clamp(depth, 0., 1.0);
-
-	directionToLight = normalize(directionToLight);
-	directionToLight.y = - directionToLight.y;
-
-	float shadow = unpack(textureCube(shadowSampler, directionToLight)) + bias;
-
-    if (depth > shadow)
-    {
-#ifdef OVERLOADEDSHADOWVALUES
-        return mix(1.0, darkness, vOverloadedShadowIntensity.x);
-#else
-        return darkness;
-#endif
-    }
-    return 1.0;
-}
-
-float computeShadowWithPCFCube(vec3 lightPosition, samplerCube shadowSampler, float mapSize, float bias, float darkness)
-{
-    vec3 directionToLight = vPositionW - lightPosition;
-    float depth = length(directionToLight);
-
-    depth = (depth - depthValues.x) / (depthValues.y - depthValues.x);
-    depth = clamp(depth, 0., 1.0);
-
-    directionToLight = normalize(directionToLight);
-    directionToLight.y = -directionToLight.y;
-
-    float visibility = 1.;
-
-    vec3 poissonDisk[4];
-    poissonDisk[0] = vec3(-1.0, 1.0, -1.0);
-    poissonDisk[1] = vec3(1.0, -1.0, -1.0);
-    poissonDisk[2] = vec3(-1.0, -1.0, -1.0);
-    poissonDisk[3] = vec3(1.0, -1.0, 1.0);
-
-    // Poisson Sampling
-    float biasedDepth = depth - bias;
-
-    if (unpack(textureCube(shadowSampler, directionToLight + poissonDisk[0] * mapSize)) < biasedDepth) visibility -= 0.25;
-    if (unpack(textureCube(shadowSampler, directionToLight + poissonDisk[1] * mapSize)) < biasedDepth) visibility -= 0.25;
-    if (unpack(textureCube(shadowSampler, directionToLight + poissonDisk[2] * mapSize)) < biasedDepth) visibility -= 0.25;
-    if (unpack(textureCube(shadowSampler, directionToLight + poissonDisk[3] * mapSize)) < biasedDepth) visibility -= 0.25;
-
-#ifdef OVERLOADEDSHADOWVALUES
-    return  min(1.0, mix(1.0, visibility + darkness, vOverloadedShadowIntensity.x));
-#else
-    return  min(1.0, visibility + darkness);
-#endif
-}
-#endif
-
-#if defined(SPOTLIGHT0) || defined(SPOTLIGHT1) || defined(SPOTLIGHT2) || defined(SPOTLIGHT3) ||  defined(DIRLIGHT0) || defined(DIRLIGHT1) || defined(DIRLIGHT2) || defined(DIRLIGHT3)
-float computeShadow(vec4 vPositionFromLight, sampler2D shadowSampler, float darkness, float bias)
-{
-    vec3 depth = vPositionFromLight.xyz / vPositionFromLight.w;
-    depth = 0.5 * depth + vec3(0.5);
-    vec2 uv = depth.xy;
-
-    if (uv.x < 0. || uv.x > 1.0 || uv.y < 0. || uv.y > 1.0)
-    {
-        return 1.0;
-    }
-
-    float shadow = unpack(texture2D(shadowSampler, uv)) + bias;
-
-    if (depth.z > shadow)
-    {
-#ifdef OVERLOADEDSHADOWVALUES
-        return mix(1.0, darkness, vOverloadedShadowIntensity.x);
-#else
-        return darkness;
-#endif
-    }
-    return 1.;
-}
-
-float computeShadowWithPCF(vec4 vPositionFromLight, sampler2D shadowSampler, float mapSize, float bias, float darkness)
-{
-    vec3 depth = vPositionFromLight.xyz / vPositionFromLight.w;
-    depth = 0.5 * depth + vec3(0.5);
-    vec2 uv = depth.xy;
-
-    if (uv.x < 0. || uv.x > 1.0 || uv.y < 0. || uv.y > 1.0)
-    {
-        return 1.0;
-    }
-
-    float visibility = 1.;
-
-    vec2 poissonDisk[4];
-    poissonDisk[0] = vec2(-0.94201624, -0.39906216);
-    poissonDisk[1] = vec2(0.94558609, -0.76890725);
-    poissonDisk[2] = vec2(-0.094184101, -0.92938870);
-    poissonDisk[3] = vec2(0.34495938, 0.29387760);
-
-    // Poisson Sampling
-    float biasedDepth = depth.z - bias;
-
-    if (unpack(texture2D(shadowSampler, uv + poissonDisk[0] * mapSize)) < biasedDepth) visibility -= 0.25;
-    if (unpack(texture2D(shadowSampler, uv + poissonDisk[1] * mapSize)) < biasedDepth) visibility -= 0.25;
-    if (unpack(texture2D(shadowSampler, uv + poissonDisk[2] * mapSize)) < biasedDepth) visibility -= 0.25;
-    if (unpack(texture2D(shadowSampler, uv + poissonDisk[3] * mapSize)) < biasedDepth) visibility -= 0.25;
-
-#ifdef OVERLOADEDSHADOWVALUES
-    return  min(1.0, mix(1.0, visibility + darkness, vOverloadedShadowIntensity.x));
-#else
-    return  min(1.0, visibility + darkness);
-#endif
-}
-
-// Thanks to http://devmaster.net/
-float unpackHalf(vec2 color)
-{
-    return color.x + (color.y / 255.0);
-}
-
-float linstep(float low, float high, float v) {
-    return clamp((v - low) / (high - low), 0.0, 1.0);
-}
-
-float ChebychevInequality(vec2 moments, float compare, float bias)
-{
-    float p = smoothstep(compare - bias, compare, moments.x);
-    float variance = max(moments.y - moments.x * moments.x, 0.02);
-    float d = compare - moments.x;
-    float p_max = linstep(0.2, 1.0, variance / (variance + d * d));
-
-    return clamp(max(p, p_max), 0.0, 1.0);
-}
-
-float computeShadowWithVSM(vec4 vPositionFromLight, sampler2D shadowSampler, float bias, float darkness)
-{
-    vec3 depth = vPositionFromLight.xyz / vPositionFromLight.w;
-    depth = 0.5 * depth + vec3(0.5);
-    vec2 uv = depth.xy;
-
-    if (uv.x < 0. || uv.x > 1.0 || uv.y < 0. || uv.y > 1.0 || depth.z >= 1.0)
-    {
-        return 1.0;
-    }
-
-    vec4 texel = texture2D(shadowSampler, uv);
-
-    vec2 moments = vec2(unpackHalf(texel.xy), unpackHalf(texel.zw));
-#ifdef OVERLOADEDSHADOWVALUES
-    return min(1.0, mix(1.0, 1.0 - ChebychevInequality(moments, depth.z, bias) + darkness, vOverloadedShadowIntensity.x));
-#else
-    return min(1.0, 1.0 - ChebychevInequality(moments, depth.z, bias) + darkness);
-#endif
-}
-#endif
-
-#endif
+// PBR
+#include<pbrShadowFunctions>
+#include<pbrFunctions>
+#include<harmonicsFunctions>
+#include<pbrLightFunctions>
 
 #include<bumpFragmentFunctions>
 #include<clipPlaneFragmentDeclaration>
@@ -546,137 +165,6 @@ float computeShadowWithVSM(vec4 vPositionFromLight, sampler2D shadowSampler, flo
 // Fog
 #include<fogFragmentDeclaration>
 
-// Light Computing
-struct lightingInfo
-{
-    vec3 diffuse;
-#ifdef SPECULARTERM
-    vec3 specular;
-#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 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 = computeLightFalloff(lightOffset, lightDistanceSquared, range);
-        
-        lightDistance = sqrt(lightDistanceSquared);
-        lightDirection = normalize(lightOffset);
-    }
-    // Directional
-    else
-    {
-        lightDistance = length(-lightData.xyz);
-        lightDirection = normalize(-lightData.xyz);
-    }
-    
-    // Roughness
-    roughness = adjustRoughnessFromLightProperties(roughness, lightRadius, 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);
-    result.specular = specTerm * attenuation;
-#endif
-
-    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 result;
-
-    vec3 lightOffset = lightData.xyz - vPositionW;
-    vec3 lightVectorW = normalize(lightOffset);
-
-    // diffuse
-    float cosAngle = max(0.000000000000001, dot(-lightDirection.xyz, lightVectorW));
-    
-    if (cosAngle >= lightDirection.w)
-    {
-        cosAngle = max(0., pow(cosAngle, lightData.w));
-        
-        // Inverse squared falloff.
-        float lightDistanceSquared = dot(lightOffset, lightOffset);
-        float attenuation = computeLightFalloff(lightOffset, lightDistanceSquared, range);
-        
-        // Directional falloff.
-        attenuation *= cosAngle;
-        
-        // Roughness.
-        float lightDistance = sqrt(lightDistanceSquared);
-        roughness = adjustRoughnessFromLightProperties(roughness, lightRadius, lightDistance);
-        
-        // Diffuse
-        vec3 H = normalize(viewDirectionW - lightDirection.xyz);
-        NdotL = max(0.00000000001, dot(vNormal, -lightDirection.xyz));
-        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);
-        result.specular = specTerm  * attenuation;
-#endif
-
-        return result;
-    }
-
-    result.diffuse = vec3(0.);
-#ifdef SPECULARTERM
-    result.specular = vec3(0.);
-#endif
-
-    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 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);
-    result.specular = specTerm;
-#endif
-
-    return result;
-}
-
 void main(void) {
 #include<clipPlaneFragment>
 
@@ -790,201 +278,12 @@ void main(void) {
 #endif
     float notShadowLevel = 1.; // 1 - shadowLevel
     float NdotL = -1.;
+    lightingInfo info;
 
-#ifdef LIGHT0
-#ifndef SPECULARTERM
-    vec3 vLightSpecular0 = vec3(0.0);
-#endif
-#ifdef SPOTLIGHT0
-    lightingInfo info = computeSpotLighting(viewDirectionW, normalW, vLightData0, vLightDirection0, vLightDiffuse0.rgb, vLightSpecular0, vLightDiffuse0.a, roughness, NdotV, vLightRadiuses[0], NdotL);
-#endif
-#ifdef HEMILIGHT0
-    lightingInfo info = computeHemisphericLighting(viewDirectionW, normalW, vLightData0, vLightDiffuse0.rgb, vLightSpecular0, vLightGround0, roughness, NdotV, vLightRadiuses[0], NdotL);
-#endif
-#if defined(POINTLIGHT0) || defined(DIRLIGHT0)
-    lightingInfo info = computeLighting(viewDirectionW, normalW, vLightData0, vLightDiffuse0.rgb, vLightSpecular0, vLightDiffuse0.a, roughness, NdotV, vLightRadiuses[0], NdotL);
-#endif
-#ifdef SHADOW0
-#ifdef SHADOWVSM0
-    notShadowLevel = computeShadowWithVSM(vPositionFromLight0, shadowSampler0, shadowsInfo0.z, shadowsInfo0.x);
-#else
-#ifdef SHADOWPCF0
-#if defined(POINTLIGHT0)
-    notShadowLevel = computeShadowWithPCFCube(vLightData0.xyz, shadowSampler0, shadowsInfo0.y, shadowsInfo0.z, shadowsInfo0.x);
-#else
-    notShadowLevel = computeShadowWithPCF(vPositionFromLight0, shadowSampler0, shadowsInfo0.y, shadowsInfo0.z, shadowsInfo0.x);
-#endif
-#else
-#if defined(POINTLIGHT0)
-    notShadowLevel = computeShadowCube(vLightData0.xyz, shadowSampler0, shadowsInfo0.x, shadowsInfo0.z);
-#else
-    notShadowLevel = computeShadow(vPositionFromLight0, shadowSampler0, shadowsInfo0.x, shadowsInfo0.z);
-#endif
-#endif
-#endif
-#else
-    notShadowLevel = 1.;
-#endif
-    lightDiffuseContribution += info.diffuse * notShadowLevel;
-#ifdef OVERLOADEDSHADOWVALUES
-    if (NdotL < 0.000000000011)
-    {
-        notShadowLevel = 1.;
-    }
-    shadowedOnlyLightDiffuseContribution *= notShadowLevel;
-#endif
-
-#ifdef SPECULARTERM
-    lightSpecularContribution += info.specular * notShadowLevel;
-#endif
-#endif
-
-#ifdef LIGHT1
-#ifndef SPECULARTERM
-    vec3 vLightSpecular1 = vec3(0.0);
-#endif
-#ifdef SPOTLIGHT1
-    info = computeSpotLighting(viewDirectionW, normalW, vLightData1, vLightDirection1, vLightDiffuse1.rgb, vLightSpecular1, vLightDiffuse1.a, roughness, NdotV, vLightRadiuses[1], NdotL);
-#endif
-#ifdef HEMILIGHT1
-    info = computeHemisphericLighting(viewDirectionW, normalW, vLightData1, vLightDiffuse1.rgb, vLightSpecular1, vLightGround1, roughness, NdotV, vLightRadiuses[1], NdotL);
-#endif
-#if defined(POINTLIGHT1) || defined(DIRLIGHT1)
-    info = computeLighting(viewDirectionW, normalW, vLightData1, vLightDiffuse1.rgb, vLightSpecular1, vLightDiffuse1.a, roughness, NdotV, vLightRadiuses[1], NdotL);
-#endif
-#ifdef SHADOW1
-#ifdef SHADOWVSM1
-    notShadowLevel = computeShadowWithVSM(vPositionFromLight1, shadowSampler1, shadowsInfo1.z, shadowsInfo1.x);
-#else
-#ifdef SHADOWPCF1
-#if defined(POINTLIGHT1)
-    notShadowLevel = computeShadowWithPCFCube(vLightData1.xyz, shadowSampler1, shadowsInfo1.y, shadowsInfo1.z, shadowsInfo1.x);
-#else
-    notShadowLevel = computeShadowWithPCF(vPositionFromLight1, shadowSampler1, shadowsInfo1.y, shadowsInfo1.z, shadowsInfo1.x);
-#endif
-#else
-#if defined(POINTLIGHT1)
-    notShadowLevel = computeShadowCube(vLightData1.xyz, shadowSampler1, shadowsInfo1.x, shadowsInfo1.z);
-#else
-    notShadowLevel = computeShadow(vPositionFromLight1, shadowSampler1, shadowsInfo1.x, shadowsInfo1.z);
-#endif
-#endif
-#endif
-#else
-    notShadowLevel = 1.;
-#endif
-
-    lightDiffuseContribution += info.diffuse * notShadowLevel;
-#ifdef OVERLOADEDSHADOWVALUES
-    if (NdotL < 0.000000000011)
-    {
-        notShadowLevel = 1.;
-    }
-    shadowedOnlyLightDiffuseContribution *= notShadowLevel;
-#endif
-
-#ifdef SPECULARTERM
-    lightSpecularContribution += info.specular * notShadowLevel;
-#endif
-#endif
-
-#ifdef LIGHT2
-#ifndef SPECULARTERM
-    vec3 vLightSpecular2 = vec3(0.0);
-#endif
-#ifdef SPOTLIGHT2
-    info = computeSpotLighting(viewDirectionW, normalW, vLightData2, vLightDirection2, vLightDiffuse2.rgb, vLightSpecular2, vLightDiffuse2.a, roughness, NdotV, vLightRadiuses[2], NdotL);
-#endif
-#ifdef HEMILIGHT2
-    info = computeHemisphericLighting(viewDirectionW, normalW, vLightData2, vLightDiffuse2.rgb, vLightSpecular2, vLightGround2, roughness, NdotV, vLightRadiuses[2], NdotL);
-#endif
-#if defined(POINTLIGHT2) || defined(DIRLIGHT2)
-    info = computeLighting(viewDirectionW, normalW, vLightData2, vLightDiffuse2.rgb, vLightSpecular2, vLightDiffuse2.a, roughness, NdotV, vLightRadiuses[2], NdotL);
-#endif
-#ifdef SHADOW2
-#ifdef SHADOWVSM2
-    notShadowLevel = computeShadowWithVSM(vPositionFromLight2, shadowSampler2, shadowsInfo2.z, shadowsInfo2.x);
-#else
-#ifdef SHADOWPCF2
-#if defined(POINTLIGHT2)
-    notShadowLevel = computeShadowWithPCFCube(vLightData2.xyz, shadowSampler2, shadowsInfo2.y, shadowsInfo2.z, shadowsInfo2.x);
-#else
-    notShadowLevel = computeShadowWithPCF(vPositionFromLight2, shadowSampler2, shadowsInfo2.y, shadowsInfo2.z, shadowsInfo2.x);
-#endif
-#else
-#if defined(POINTLIGHT2)
-    notShadowLevel = computeShadowCube(vLightData2.xyz, shadowSampler2, shadowsInfo2.x, shadowsInfo2.z);
-#else
-    notShadowLevel = computeShadow(vPositionFromLight2, shadowSampler2, shadowsInfo2.x, shadowsInfo2.z);
-#endif
-#endif	
-#endif	
-#else
-    notShadowLevel = 1.;
-#endif
-
-    lightDiffuseContribution += info.diffuse * notShadowLevel;
-#ifdef OVERLOADEDSHADOWVALUES
-    if (NdotL < 0.000000000011)
-    {
-        notShadowLevel = 1.;
-    }
-    shadowedOnlyLightDiffuseContribution *= notShadowLevel;
-#endif
-
-#ifdef SPECULARTERM
-    lightSpecularContribution += info.specular * notShadowLevel;
-#endif
-#endif
-
-#ifdef LIGHT3
-#ifndef SPECULARTERM
-    vec3 vLightSpecular3 = vec3(0.0);
-#endif
-#ifdef SPOTLIGHT3
-    info = computeSpotLighting(viewDirectionW, normalW, vLightData3, vLightDirection3, vLightDiffuse3.rgb, vLightSpecular3, vLightDiffuse3.a, roughness, NdotV, vLightRadiuses[3], NdotL);
-#endif
-#ifdef HEMILIGHT3
-    info = computeHemisphericLighting(viewDirectionW, normalW, vLightData3, vLightDiffuse3.rgb, vLightSpecular3, vLightGround3, roughness, NdotV, vLightRadiuses[3], NdotL);
-#endif
-#if defined(POINTLIGHT3) || defined(DIRLIGHT3)
-    info = computeLighting(viewDirectionW, normalW, vLightData3, vLightDiffuse3.rgb, vLightSpecular3, vLightDiffuse3.a, roughness, NdotV, vLightRadiuses[3], NdotL);
-#endif
-#ifdef SHADOW3
-#ifdef SHADOWVSM3
-    notShadowLevel = computeShadowWithVSM(vPositionFromLight3, shadowSampler3, shadowsInfo3.z, shadowsInfo3.x);
-#else
-#ifdef SHADOWPCF3
-#if defined(POINTLIGHT3)
-    notShadowLevel = computeShadowWithPCFCube(vLightData3.xyz, shadowSampler3, shadowsInfo3.y, shadowsInfo3.z, shadowsInfo3.x);
-#else
-    notShadowLevel = computeShadowWithPCF(vPositionFromLight3, shadowSampler3, shadowsInfo3.y, shadowsInfo3.z, shadowsInfo3.x);
-#endif
-#else
-#if defined(POINTLIGHT3)
-    notShadowLevel = computeShadowCube(vLightData3.xyz, shadowSampler3, shadowsInfo3.x, shadowsInfo3.z);
-#else
-    notShadowLevel = computeShadow(vPositionFromLight3, shadowSampler3, shadowsInfo3.x, shadowsInfo3.z);
-#endif
-#endif	
-#endif	
-#else
-    notShadowLevel = 1.;
-#endif
-
-    lightDiffuseContribution += info.diffuse * notShadowLevel;
-#ifdef OVERLOADEDSHADOWVALUES
-    if (NdotL < 0.000000000011)
-    {
-        notShadowLevel = 1.;
-    }
-    shadowedOnlyLightDiffuseContribution *= notShadowLevel;
-#endif
-
-#ifdef SPECULARTERM
-    lightSpecularContribution += info.specular * notShadowLevel;
-#endif
-#endif
+#include<pbrLightFunctionsCall>[0]
+#include<pbrLightFunctionsCall>[1]
+#include<pbrLightFunctionsCall>[2]
+#include<pbrLightFunctionsCall>[3]
 
 #ifdef SPECULARTERM
     lightSpecularContribution *= vLightingIntensity.w;