Parallax Occlusion Mapping for jme

TERRAIN UPDATE

  • since now it require “LWJGL_OPENGL3”:

     settings.setRenderer(AppSettings.LWJGL_OPENGL3);
    
  • added TextureArray (thanks @jayfella for help) - now can use all 12 textures with albedo/normal/parallax textures each. also thanks for @RiccardoBlb

  • changed blending to be based on percentage blending, not mask intensity based.

usage example:

/////////////////////////////////////////////////////
        mat_terrain = new Material(assetManager, "MatDefs/PBRTerrainV2/terrainPBRShaderV2.j3md");
        mat_terrain.setFloat("ParallaxLODDistance", 30f);
        /////////////////////////////////////////////////////
        mat_terrain.setTexture("AlphaMap", assetManager.loadTexture("Textures/Terrain/splat/startAlphamap2.png"));
        mat_terrain.setTexture("AlphaMap_1", assetManager.loadTexture("Textures/Terrain/splat/startAlphamap3.png"));
        mat_terrain.setTexture("AlphaMap_2", assetManager.loadTexture("Textures/Terrain/splat/startAlphamap4.png"));
        /////////////////////////////////////////////////////
        List<Image> phongTextureList = new ArrayList<>();
        List<Image> normalmapTextureList = new ArrayList<>();
        List<Image> parallaxmapTextureList = new ArrayList<>();
        /////////////////////////////////////////////////////
        int i = 0;
        for (Iterator<TerrainManager.TerrainMaterial> iterator = materials.iterator(); iterator.hasNext();) {
            TerrainManager.TerrainMaterial terrMat = iterator.next();
            mat_terrain.setBoolean("UseSlot_"+i, true);
            Texture phong = assetManager.loadTexture(terrMat.baseColorMap);
            phong.setWrap(Texture.WrapMode.Repeat);
            //phong.setWidth(124);
            //phong.setHeight(124);
            phongTextureList.add(phong.getImage());
            mat_terrain.setFloat("Slot_"+i+"_scale", terrMat.scale);
            mat_terrain.setFloat("Metallic_"+i, terrMat.metallic);
            mat_terrain.setFloat("Roughness_"+i, terrMat.roughness);
            if(!terrMat.normalMap.isEmpty()){
                mat_terrain.setBoolean("UseNormalMap_"+i, true);
                Texture normal = assetManager.loadTexture(terrMat.normalMap);
                normal.setWrap(Texture.WrapMode.Repeat);
                //normal.setWidth(124);
                //normal.setHeight(124);
                normalmapTextureList.add(normal.getImage());
            }
            mat_terrain.setBoolean("parallaxMapping", terrMat.useOcclusionParallax);
            if(terrMat.useOcclusionParallax && !terrMat.parallaxMap.isEmpty()){
                mat_terrain.setBoolean("UseParallaxMap_"+i, true);
                Texture parallax = assetManager.loadTexture(terrMat.parallaxMap);
                parallax.setWrap(Texture.WrapMode.Repeat);
                //parallax.setWidth(124);
                //parallax.setHeight(124);
                parallaxmapTextureList.add(parallax.getImage());
                mat_terrain.setFloat("ParallaxHeight_"+i, terrMat.parallaxHeight);
            }
            i++;
        }
        /////////////////////////////////////////////////////
        TextureArray phongTextures = new TextureArray(phongTextureList);
        phongTextures.setWrap(Texture.WrapMode.Repeat);
        phongTextures.setMinFilter(Texture.MinFilter.Trilinear);
        mat_terrain.setTexture("PhongTextures", phongTextures);
        /////////////////////////////////////////////////////
        TextureArray normalmapTextures = new TextureArray(normalmapTextureList);
        normalmapTextures.setWrap(Texture.WrapMode.Repeat);
        normalmapTextures.setMinFilter(Texture.MinFilter.Trilinear);
        mat_terrain.setTexture("NormalmapTextures", normalmapTextures);
        /////////////////////////////////////////////////////
        TextureArray parallaxmapTextures = new TextureArray(parallaxmapTextureList);
        parallaxmapTextures.setWrap(Texture.WrapMode.Repeat);
        parallaxmapTextures.setMinFilter(Texture.MinFilter.Trilinear);
        mat_terrain.setTexture("ParallaxmapTextures", parallaxmapTextures);
        /////////////////////////////////////////////////////

frag shader:

#extension GL_EXT_texture_array : enable
#import "MatDefs/ShaderLib/GLSLCompat.glsllib"
#import "MatDefs/ShaderLib/PBR.glsllib"
#import "MatDefs/ShaderLib/Parallax.glsllib"
#import "MatDefs/ShaderLib/Lighting.glsllib"

uniform vec4 g_LightData[NB_LIGHTS];

uniform vec4 g_AmbientLightColor;

varying vec3 wPosition;

uniform float g_Time;

// Configure height channel
#ifdef NORMALMAP_PARALLAX
  #define HEIGHT_MAP A_COMPONENT
#else
  #define HEIGHT_MAP R_COMPONENT
#endif
#import "MatDefs/ShaderLib/OcclusionParallax.glsllib"

#if NB_PROBES >= 1
  uniform samplerCube g_PrefEnvMap;
  uniform vec3 g_ShCoeffs[9];
  uniform mat4 g_LightProbeData;
#endif
#if NB_PROBES >= 2
  uniform samplerCube g_PrefEnvMap2;
  uniform vec3 g_ShCoeffs2[9];
  uniform mat4 g_LightProbeData2;
#endif
#if NB_PROBES == 3
  uniform samplerCube g_PrefEnvMap3;
  uniform vec3 g_ShCoeffs3[9];
  uniform mat4 g_LightProbeData3;
#endif

#ifdef EMISSIVE
    uniform vec4 m_Emissive;
#endif
#ifdef EMISSIVEMAP
    uniform sampler2D m_EmissiveMap;
#endif
#if defined(EMISSIVE) || defined(EMISSIVEMAP)
    uniform float m_EmissivePower;
    uniform float m_EmissiveIntensity;
#endif 

#ifdef SPECGLOSSPIPELINE
  uniform sampler2D m_SpecularMap;
  uniform sampler2D m_GlossMap;
#endif

#ifdef LIGHTMAP
  uniform sampler2D m_LightMap;
#endif

varying vec3 vNormal;

#if defined(NORMALMAP_0) || defined(NORMALMAP_1) || defined(NORMALMAP_2) || defined(NORMALMAP_3) || defined(NORMALMAP_4) || defined(NORMALMAP_5) || defined(NORMALMAP_6) || defined(NORMALMAP_7) || defined(PLAGUEDNORMALMAP)
    varying vec4 wTangent;
#endif

varying vec2 texCoord;
uniform vec3 inPosition;
uniform mat4 g_WorldViewMatrix;
uniform vec3 g_CameraPosition;

varying vec3 vPosition;
varying vec3 vnPosition;
varying vec3 vViewDir;
varying vec4 vLightDir;
varying vec4 vnLightDir;
varying vec3 lightVec;

uniform float m_Roughness_0;
uniform float m_Roughness_1;
uniform float m_Roughness_2;
uniform float m_Roughness_3;
uniform float m_Roughness_4;
uniform float m_Roughness_5;
uniform float m_Roughness_6;
uniform float m_Roughness_7;
uniform float m_Roughness_8;
uniform float m_Roughness_9;
uniform float m_Roughness_10;
uniform float m_Roughness_11;

uniform float m_Metallic_0;
uniform float m_Metallic_1;
uniform float m_Metallic_2;
uniform float m_Metallic_3;
uniform float m_Metallic_4;
uniform float m_Metallic_5;
uniform float m_Metallic_6;
uniform float m_Metallic_7;
uniform float m_Metallic_8;
uniform float m_Metallic_9;
uniform float m_Metallic_10;
uniform float m_Metallic_11;

uniform float m_Parallax_0;
uniform float m_Parallax_1;
uniform float m_Parallax_2;
uniform float m_Parallax_3;
uniform float m_Parallax_4;
uniform float m_Parallax_5;
uniform float m_Parallax_6;
uniform float m_Parallax_7;
uniform float m_Parallax_8;
uniform float m_Parallax_9;
uniform float m_Parallax_10;
uniform float m_Parallax_11;

#ifdef PARALLAX_LOD_DISTANCE
    uniform float m_ParallaxLODDistance;
#endif

uniform sampler2DArray m_PhongTextures;
uniform sampler2DArray m_NormalmapTextures;
uniform sampler2DArray m_ParallaxmapTextures;

#ifdef SLOT_0
  uniform float m_Slot_0_scale;
#endif
#ifdef SLOT_1
  uniform float m_Slot_1_scale;
#endif
#ifdef SLOT_2
  uniform float m_Slot_2_scale;
#endif
#ifdef SLOT_3
  uniform float m_Slot_3_scale;
#endif
#ifdef SLOT_4
  uniform float m_Slot_4_scale;
#endif
#ifdef SLOT_5
  uniform float m_Slot_5_scale;
#endif
#ifdef SLOT_6
  uniform float m_Slot_6_scale;
#endif
#ifdef SLOT_7
  uniform float m_Slot_7_scale;
#endif
#ifdef SLOT_8
  uniform float m_Slot_8_scale;
#endif
#ifdef SLOT_9
  uniform float m_Slot_9_scale;
#endif
#ifdef SLOT_10
  uniform float m_Slot_10_scale;
#endif
#ifdef SLOT_11
  uniform float m_Slot_11_scale;
#endif

#ifdef ALPHAMAP
  uniform sampler2D m_AlphaMap;
#endif
#ifdef ALPHAMAP_1
  uniform sampler2D m_AlphaMap_1;
#endif
#ifdef ALPHAMAP_2
  uniform sampler2D m_AlphaMap_2;
#endif

#ifdef PARALLAXMAP_0
  uniform float m_ParallaxHeight_0;
#endif
#ifdef PARALLAXMAP_1
  uniform float m_ParallaxHeight_1;
#endif
#ifdef PARALLAXMAP_2
  uniform float m_ParallaxHeight_2;
#endif
#ifdef PARALLAXMAP_3
  uniform float m_ParallaxHeight_3;
#endif
#ifdef PARALLAXMAP_4
  uniform float m_ParallaxHeight_4;
#endif
#ifdef PARALLAXMAP_5
  uniform float m_ParallaxHeight_5;
#endif
#ifdef PARALLAXMAP_6
  uniform float m_ParallaxHeight_6;
#endif
#ifdef PARALLAXMAP_7
  uniform float m_ParallaxHeight_7;
#endif
#ifdef PARALLAXMAP_8
  uniform float m_ParallaxHeight_8;
#endif
#ifdef PARALLAXMAP_9
  uniform float m_ParallaxHeight_9;
#endif
#ifdef PARALLAXMAP_10
  uniform float m_ParallaxHeight_10;
#endif
#ifdef PARALLAXMAP_11
  uniform float m_ParallaxHeight_11;
#endif

vec4 emissive;
  varying vec3 wNormal;
//ifdef TRI_PLANAR_MAPPING
  varying vec4 wVertex;
//#endif

varying float camDist;

vec2 coord;
vec4 albedo;
vec4 tempAlbedo, tempNormal;
vec3 normal = vec3(0.5,0.5,1);
vec3 newNormal;
vec3 parallax;
vec2 newTexCoord;
vec3 viewDir;
mat3 tbnMat;
vec3 norm;
float Metallic;
float Roughness;
float currentBlendValue = 0.01;
float blendPercent = 1;

#define DEFINE_COORD(index) vec2 coord##index = newTexCoord * m_Slot##index##_scale;

#define CALCULATE_BLEND_PERCENT(ab)\
    currentBlendValue += ab;\
    blendPercent = (0.000001+ab)/(currentBlendValue+0.000001);

#define BLEND(index, ab, texIndex)\
    tempAlbedo.rgb = texture2DArray(m_PhongTextures, vec3(coord##index, texIndex) ).rgb;\
    albedo.rgb = mix( albedo.rgb, tempAlbedo.rgb, blendPercent);\
    normal.rgb = mix(normal.xyz, wNormal.xyz, blendPercent);\
    Metallic = mix(Metallic, m_Metallic##index, blendPercent);\
    Roughness = mix(Roughness, m_Roughness##index, blendPercent);

#define BLEND_NORMAL(index, ab, texIndex)\
    tempAlbedo.rgb = texture2DArray(m_PhongTextures, vec3(coord##index, texIndex) ).rgb;\
    albedo.rgb = mix( albedo.rgb, tempAlbedo.rgb, blendPercent);\
    Metallic = mix(Metallic, m_Metallic##index, blendPercent);\
    Roughness = mix(Roughness, m_Roughness##index, blendPercent);\
    newNormal = texture2DArray(m_NormalmapTextures, vec3(coord##index, texIndex) ).rgb;\
    normal = mix(normal, newNormal, blendPercent);

#define PARALLAX_BLEND(index, ab, texIndex)\
    calculateParallax(coord##index, m_ParallaxHeight##index, ab, texIndex);

void calculateParallax(inout vec2 parallaxTexCoord, in float parallaxHeight, in float intensity, in int texIndex) {
    #ifdef PARALLAX_LOD_DISTANCE  
        if(camDist < m_ParallaxLODDistance && blendPercent > 0.2){
            vec3 vViewDir =  viewDir * tbnMat;
            Parallax_initFor(vViewDir,parallaxHeight);
            Parallax_TextureArray_displaceCoords(parallaxTexCoord,m_ParallaxmapTextures, texIndex);
        }
    #else
        if(blendPercent > 0.2){
            vec3 vViewDir =  viewDir * tbnMat;
            Parallax_initFor(vViewDir,parallaxHeight);
            Parallax_TextureArray_displaceCoords(parallaxTexCoord,m_ParallaxmapTextures, texIndex);
        }
    #endif
}

vec4 calculateAlbedoBlend(in vec2 newTexCoord) {
    vec4 alphaBlend = texture2D( m_AlphaMap, newTexCoord.xy );
    vec4 albedo = vec4(1.0);
    Roughness = 1;
    Metallic = 0;
    
    vec3 blending = abs( wNormal );
    blending = (blending -0.2) * 0.7;
    blending = normalize(max(blending, 0.00001));      // Force weights to sum to 1.0 (very important!)
    float b = (blending.x + blending.y + blending.z);
    blending /= vec3(b, b, b);

    vec3 wvPosition=(vec4(inPosition,1)*g_WorldViewMatrix).xyz;
    #ifdef ALPHAMAP_1
      vec4 alphaBlend1   = texture2D( m_AlphaMap_1, newTexCoord.xy );
    #endif
    #ifdef ALPHAMAP_2
      vec4 alphaBlend2   = texture2D( m_AlphaMap_2, newTexCoord.xy );
    #endif
    #ifdef SLOT_0   
        DEFINE_COORD(_0)
        CALCULATE_BLEND_PERCENT(alphaBlend.r)
        #if defined(PARALLAXMAPPING) && defined (PARALLAXMAP_0)
            PARALLAX_BLEND(_0, alphaBlend.r, 0)
        #endif
        #ifdef NORMALMAP_0
            BLEND_NORMAL(_0,  alphaBlend.r, 0)
        #else
            BLEND(_0,  alphaBlend.r, 0)
        #endif
    #endif
    #ifdef SLOT_1
        DEFINE_COORD(_1)
        CALCULATE_BLEND_PERCENT(alphaBlend.g)
        #if defined(PARALLAXMAPPING) && defined (PARALLAXMAP_1)
            PARALLAX_BLEND(_1, alphaBlend.g, 1)
        #endif
        #ifdef NORMALMAP_1
            BLEND_NORMAL(_1,  alphaBlend.g, 1)
        #else
            BLEND(_1,  alphaBlend.g, 1)
        #endif
    #endif
    #ifdef SLOT_2
        DEFINE_COORD(_2)
        CALCULATE_BLEND_PERCENT(alphaBlend.b)
        #if defined(PARALLAXMAPPING) && defined (PARALLAXMAP_2)
            PARALLAX_BLEND(_2, alphaBlend.b, 2)
        #endif
        #ifdef NORMALMAP_2
            BLEND_NORMAL(_2,  alphaBlend.b, 2)
        #else
            BLEND(_2,  alphaBlend.b, 2)
        #endif
    #endif
    #ifdef SLOT_3
        DEFINE_COORD(_3)
        CALCULATE_BLEND_PERCENT(alphaBlend.a)
        #if defined(PARALLAXMAPPING) && defined (PARALLAXMAP_3)
            PARALLAX_BLEND(_3, alphaBlend.a, 3)
        #endif
        #ifdef NORMALMAP_3
            BLEND_NORMAL(_3,  alphaBlend.a, 3)
        #else
            BLEND(_3,  alphaBlend.a, 3)
        #endif
    #endif

    #ifdef ALPHAMAP_1
        #ifdef SLOT_4
            DEFINE_COORD(_4)
            CALCULATE_BLEND_PERCENT(alphaBlend1.r)
            #if defined(PARALLAXMAPPING) && defined (PARALLAXMAP_4)
                PARALLAX_BLEND(_4,  alphaBlend1.r, 4)
            #endif
            #ifdef NORMALMAP_4
                BLEND_NORMAL(_4,  alphaBlend1.r, 4)
            #else
                BLEND(_4,  alphaBlend1.r, 4)
            #endif
        #endif
        #ifdef SLOT_5
            DEFINE_COORD(_5)
            CALCULATE_BLEND_PERCENT(alphaBlend1.g)
            #if defined(PARALLAXMAPPING) && defined (PARALLAXMAP_5)
                PARALLAX_BLEND(_5,  alphaBlend1.g, 5)
            #endif
            #ifdef NORMALMAP_5
                BLEND_NORMAL(_5,  alphaBlend1.g, 5)
            #else
                BLEND(_5,  alphaBlend1.g, 5)
            #endif
        #endif
        #ifdef SLOT_6
            DEFINE_COORD(_6)
            CALCULATE_BLEND_PERCENT(alphaBlend1.b)
            #if defined(PARALLAXMAPPING) && defined (PARALLAXMAP_6)
                PARALLAX_BLEND(_6,  alphaBlend1.b, 6)
            #endif
            #ifdef NORMALMAP_6
                BLEND_NORMAL(_6,  alphaBlend1.b, 6)
            #else
                BLEND(_6,  alphaBlend1.b, 6)
            #endif
        #endif
        #ifdef SLOT_7
            DEFINE_COORD(_7)
            CALCULATE_BLEND_PERCENT(alphaBlend1.a)
            #if defined(PARALLAXMAPPING) && defined (PARALLAXMAP_7)
                PARALLAX_BLEND(_7,  alphaBlend1.a, 7)
            #endif
            #ifdef NORMALMAP_7
                BLEND_NORMAL(_7,  alphaBlend1.a, 7)
            #else
                BLEND(_7,  alphaBlend1.a, 7)
            #endif
        #endif
    #endif
    
    #ifdef ALPHAMAP_2
        #ifdef SLOT_8
            DEFINE_COORD(_8)
            CALCULATE_BLEND_PERCENT(alphaBlend2.r)
            #if defined(PARALLAXMAPPING) && defined (PARALLAXMAP_8)
                PARALLAX_BLEND(_8,  alphaBlend2.r, 8)
            #endif
            #ifdef NORMALMAP_8
                BLEND_NORMAL(_8,  alphaBlend2.r, 8)
            #else
                BLEND(_8,  alphaBlend2.r, 8)
            #endif
        #endif
        #ifdef SLOT_9
            DEFINE_COORD(_9)
            CALCULATE_BLEND_PERCENT(alphaBlend2.g)
            #if defined(PARALLAXMAPPING) && defined (PARALLAXMAP_9)
                PARALLAX_BLEND(_9,  alphaBlend2.g, 9)
            #endif
            #ifdef NORMALMAP_9
                BLEND_NORMAL(_9,  alphaBlend2.g, 9)
            #else
                BLEND(_9,  alphaBlend2.g, 9)
            #endif
        #endif
        #ifdef SLOT_10
            DEFINE_COORD(_10)
            CALCULATE_BLEND_PERCENT(alphaBlend2.b)
            #if defined(PARALLAXMAPPING) && defined (PARALLAXMAP_10)
                PARALLAX_BLEND(_10,  alphaBlend2.b, 10)
            #endif
            #ifdef NORMALMAP_10
                BLEND_NORMAL(_10,  alphaBlend2.b, 10)
            #else
                BLEND(_10,  alphaBlend2.b, 10)
            #endif
        #endif
        #ifdef SLOT_11
            DEFINE_COORD(_11)
            CALCULATE_BLEND_PERCENT(alphaBlend2.a)
            #if defined(PARALLAXMAPPING) && defined (PARALLAXMAP_11)
                PARALLAX_BLEND(_11,  alphaBlend2.a, 11)
            #endif
            #ifdef NORMALMAP_11
                BLEND_NORMAL(_11,  alphaBlend2.a, 11)
            #else
                BLEND(_11,  alphaBlend2.a, 11)
            #endif
        #endif                   
    #endif

    return albedo;
}

#ifdef PROBE_COLOR
    uniform vec4 m_ProbeColor;
#endif

void main(){
    viewDir = normalize(g_CameraPosition - wPosition);
    
    vec3 norm = normalize(wNormal);
    normal = norm;
    //norm = vec3(0.5, 0.5, 1.0);
    #if defined(NORMALMAP_0) || defined(PARALLAXMAP) || defined(PLAGUEDNORMALMAP)
        vec3 tan = normalize(wTangent.xyz);
        //tbnMat = mat3(tan, wTangent.w * cross( (wNormal), (tan)), norm);
        tbnMat = mat3(tan, wTangent.w * cross( (norm), (tan)), norm);
    #endif
    
    newTexCoord=texCoord;

    //always calculated since the
    vec3 blending;
    #ifdef SLOT_0
      #ifdef ALPHAMAP
        albedo = calculateAlbedoBlend(newTexCoord);
      #else
        DEFINE_COORD(_0)
        albedo = texture2DArray(m_PhongTextures, vec3(coord##index, 0) );
      #endif
    #endif

    if(albedo.a <= 0.1){
        albedo.r = 1.0;
        discard;
    }

    //---------------------
    // normal calculations
    //---------------------
    #if defined(NORMALMAP_0) || defined(NORMALMAP_1) || defined(NORMALMAP_2) || defined(NORMALMAP_3) || defined(NORMALMAP_4) || defined(NORMALMAP_5) || defined(NORMALMAP_6) || defined(NORMALMAP_7) || defined(NORMALMAP_8) || defined(NORMALMAP_9) || defined(NORMALMAP_10) || defined(NORMALMAP_11)
       #ifdef TRI_PLANAR_MAPPING
     //    normal = calculateNormalTriPlanar(wNormal, wVertex, texCoord);
       #else
     //    normal = calculateNormal(texCoord);
       #endif
       normal += norm * 0.9;
       normal = normalize(normal * vec3(2.0) - vec3(1.0));
       normal.z /= 100;
       normal = normalize(normal);
    #else
       normal = normalize(norm * vec3(2.0) - vec3(1.0));
       normal = wNormal;
    #endif

 //   normal = normalize(normal * vec3(2.0) - vec3(1.0));

     #ifdef SPECGLOSSPIPELINE
        #ifdef USE_PACKED_SG
            vec4 specularColor = texture2D(m_SpecularGlossinessMap, newTexCoord);
            float glossiness = specularColor.a * m_Glossiness;
            specularColor *= m_Specular;
        #else
            #ifdef SPECULARMAP
                vec4 specularColor = texture2D(m_SpecularMap, newTexCoord);
            #else
                vec4 specularColor = vec4(1.0);
            #endif
            #ifdef GLOSSINESSMAP
                float glossiness = texture2D(m_GlossinessMap, newTexCoord).r * m_Glossiness;
            #else
                float glossiness = m_Glossiness;
            #endif
            specularColor *= m_Specular;
        #endif
        vec4 diffuseColor = albedo;// * (1.0 - max(max(specularColor.r, specularColor.g), specularColor.b));
        Roughness = 1.0 - glossiness;
        vec3 fZero = specularColor.xyz;
    #else
        float specular = 0.5;
        float nonMetalSpec = 0.08 * specular;
        vec4 specularColor = (nonMetalSpec - nonMetalSpec * Metallic) + albedo * Metallic;
        vec4 diffuseColor = albedo - albedo * Metallic;
        vec3 fZero = vec3(specular);
    #endif

    gl_FragColor.rgb = vec3(0.0);
    vec3 ao = vec3(1.0);

    float ndotv = max( dot( normal, viewDir ),0.0);
    for( int i = 0;i < NB_LIGHTS; i+=3){
        vec4 lightColor = g_LightData[i];
        vec4 lightData1 = g_LightData[i+1];                
        vec4 lightDir;
        vec3 lightVec;            
        lightComputeDir(wPosition, lightColor.w, lightData1, lightDir, lightVec);

        float fallOff = 1.0;
        #if __VERSION__ >= 110
            // allow use of control flow
        if(lightColor.w > 1.0){
        #endif
            fallOff =  computeSpotFalloff(g_LightData[i+2], lightVec);
        #if __VERSION__ >= 110
        }
        #endif
        //point light attenuation
        fallOff *= lightDir.w;

        lightDir.xyz = normalize(lightDir.xyz);            
        vec3 directDiffuse;
        vec3 directSpecular;
        
        float hdotv = PBR_ComputeDirectLight(normal, lightDir.xyz, viewDir,
                            lightColor.rgb, fZero, Roughness, ndotv,
                            directDiffuse,  directSpecular);

        vec3 directLighting = diffuseColor.rgb *directDiffuse + directSpecular;
        gl_FragColor.rgb += directLighting * fallOff;
    }

    #if NB_PROBES >= 1
        vec3 color1 = vec3(0.0);
        vec3 color2 = vec3(0.0);
        vec3 color3 = vec3(0.0);
        float weight1 = 1.0;
        float weight2 = 0.0;
        float weight3 = 0.0;

        float ndf = renderProbe(viewDir, wPosition, normal, norm, Roughness, diffuseColor, specularColor, ndotv, ao, g_LightProbeData, g_ShCoeffs, g_PrefEnvMap, color1);
        #if NB_PROBES >= 2
            float ndf2 = renderProbe(viewDir, wPosition, normal, norm, Roughness, diffuseColor, specularColor, ndotv, ao, g_LightProbeData2, g_ShCoeffs2, g_PrefEnvMap2, color2);
        #endif
        #if NB_PROBES == 3
            float ndf3 = renderProbe(viewDir, wPosition, normal, norm, Roughness, diffuseColor, specularColor, ndotv, ao, g_LightProbeData3, g_ShCoeffs3, g_PrefEnvMap3, color3);
        #endif

         #if NB_PROBES >= 2
            float invNdf =  max(1.0 - ndf,0.0);
            float invNdf2 =  max(1.0 - ndf2,0.0);
            float sumNdf = ndf + ndf2;
            float sumInvNdf = invNdf + invNdf2;
            #if NB_PROBES == 3
                float invNdf3 = max(1.0 - ndf3,0.0);
                sumNdf += ndf3;
                sumInvNdf += invNdf3;
                weight3 =  ((1.0 - (ndf3 / sumNdf)) / (NB_PROBES - 1)) *  (invNdf3 / sumInvNdf);
            #endif

            weight1 = ((1.0 - (ndf / sumNdf)) / (NB_PROBES - 1)) *  (invNdf / sumInvNdf);
            weight2 = ((1.0 - (ndf2 / sumNdf)) / (NB_PROBES - 1)) *  (invNdf2 / sumInvNdf);

            float weightSum = weight1 + weight2 + weight3;

            weight1 /= weightSum;
            weight2 /= weightSum;
            weight3 /= weightSum;
        #endif
        
        #if USE_AMBIENT_LIGHT
            color1.rgb *= g_AmbientLightColor.rgb;
            color2.rgb *= g_AmbientLightColor.rgb;
            color3.rgb *= g_AmbientLightColor.rgb;
        #endif
        
        gl_FragColor.rgb += color1 * clamp(weight1,0.0,1.0) + color2 * clamp(weight2,0.0,1.0) + color3 * clamp(weight3,0.0,1.0);
    #endif
 
    #if defined(EMISSIVE) || defined (EMISSIVEMAP)
        #ifdef EMISSIVEMAP
            emissive = texture2D(m_EmissiveMap, newTexCoord);
        #else
            emissive = m_Emissive;
        #endif
        gl_FragColor += emissive * pow(emissive.a, m_EmissivePower) * m_EmissiveIntensity;
    #endif

    gl_FragColor.a = 1.0;
}
3 Likes