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

j3md:

// NOTE: Doesn't support OpenGL1
MaterialDef PBR Terrain {

    MaterialParameters {
        Float NormalType : -1.0
        Vector4 ProbeColor

        // Use alpha channel of normal texture for parallax mapping;
        Boolean parallaxMapping

        Float ParallaxLODDistance : 20 

        // The emissive color of the object
        Color Emissive        
        // the emissive power
        Float EmissivePower : 3.5      
        // the emissive intensity
        Float EmissiveIntensity : 2.3

        // Specular/gloss map
        Texture2D MetallicMap -LINEAR

        // Set to Use Lightmap
        Texture2D LightMap

        Float Roughness_0 : 0.0
        Float Roughness_1 : 0.0
        Float Roughness_2 : 0.0
        Float Roughness_3 : 0.0
        Float Roughness_4 : 0.0
        Float Roughness_5 : 0.0
        Float Roughness_6 : 0.0
        Float Roughness_7 : 0.0
        Float Roughness_8 : 0.0
        Float Roughness_9 : 0.0
        Float Roughness_10 : 0.0
        Float Roughness_11 : 0.0

        Float Metallic_0 : 0.0
        Float Metallic_1 : 0.0
        Float Metallic_2 : 0.0
        Float Metallic_3 : 0.0
        Float Metallic_4 : 0.0
        Float Metallic_5 : 0.0
        Float Metallic_6 : 0.0
        Float Metallic_7 : 0.0
        Float Metallic_8 : 0.0
        Float Metallic_9 : 0.0
        Float Metallic_10 : 0.0
        Float Metallic_11 : 0.0

        // use tri-planar mapping
        Boolean useTriPlanarMapping

        // Use ward specular instead of phong
        Boolean WardIso

        // Albedo color
        Color Albedo

        TextureArray PhongTextures
        TextureArray NormalmapTextures -LINEAR
        TextureArray ParallaxmapTextures -LINEAR

        // Texture map #0
        Float Slot_0_scale
        Float ParallaxHeight_0
        Boolean UseSlot_0
        Boolean UseNormalMap_0
        Boolean UseParallaxMap_0

        // Texture map #1
        Float Slot_1_scale
        Float ParallaxHeight_1
        Boolean UseSlot_1
        Boolean UseNormalMap_1
        Boolean UseParallaxMap_1

        // Texture map #2
        Float Slot_2_scale
        Float ParallaxHeight_2
        Boolean UseSlot_2
        Boolean UseNormalMap_2
        Boolean UseParallaxMap_2

        // Texture map #3
        Float Slot_3_scale
        Float ParallaxHeight_3
        Boolean UseSlot_3
        Boolean UseNormalMap_3
        Boolean UseParallaxMap_3

        // Texture map #4
        Float Slot_4_scale
        Float ParallaxHeight_4
        Boolean UseSlot_4
        Boolean UseNormalMap_4
        Boolean UseParallaxMap_4

        // Texture map #5
        Float Slot_5_scale
        Float ParallaxHeight_5
        Boolean UseSlot_5
        Boolean UseNormalMap_5
        Boolean UseParallaxMap_5

        // Texture map #6
        Float Slot_6_scale
        Float ParallaxHeight_6
        Boolean UseSlot_6
        Boolean UseNormalMap_6
        Boolean UseParallaxMap_6

        // Texture map #7
        Float Slot_7_scale
        Float ParallaxHeight_7
        Boolean UseSlot_7
        Boolean UseNormalMap_7
        Boolean UseParallaxMap_7

        // Texture map #8
        Float Slot_8_scale
        Float ParallaxHeight_8
        Boolean UseSlot_8
        Boolean UseNormalMap_8
        Boolean UseParallaxMap_8

        // Texture map #9
        Float Slot_9_scale
        Float ParallaxHeight_9
        Boolean UseSlot_9
        Boolean UseNormalMap_9
        Boolean UseParallaxMap_9

        // Texture map #10
        Float Slot_10_scale
        Float ParallaxHeight_10
        Boolean UseSlot_10
        Boolean UseNormalMap_10
        Boolean UseParallaxMap_10

        // Texture map #11
        Float Slot_11_scale
        Float ParallaxHeight_11
        Boolean UseSlot_11
        Boolean UseNormalMap_11
        Boolean UseParallaxMap_11

        // Texture that specifies alpha values
        Texture2D AlphaMap -LINEAR
        Texture2D AlphaMap_1 -LINEAR
        Texture2D AlphaMap_2 -LINEAR

        // For Spec gloss pipeline
        Boolean UseSpecGloss
        Texture2D SpecularMap
        Texture2D GlossinessMap
        Texture2D SpecularGlossinessMap
        Color Specular : 1.0 1.0 1.0 1.0
        Float Glossiness : 1.0

        Vector4 ProbeData

        // Prefiltered Env Map for indirect specular lighting
        TextureCubeMap PrefEnvMap -LINEAR
        
        // Irradiance map for indirect diffuse lighting
        TextureCubeMap IrradianceMap -LINEAR

        //integrate BRDF map for indirect Lighting
        Texture2D IntegrateBRDF -LINEAR

        // Parallax/height map
        Texture2D ParallaxMap -LINEAR

        //Set to true is parallax map is stored in the alpha channel of the normal map
        Boolean PackedNormalParallax   

        // Set to Use Lightmap
        Texture2D LightMap

        // Set to use TexCoord2 for the lightmap sampling
        Boolean SeparateTexCoord
        // the light map is a gray scale ao map, on ly the r channel will be read.
        Boolean LightMapAsAOMap

        //shadows
        Int FilterMode
        Boolean HardwareShadows

        Texture2D ShadowMap0
        Texture2D ShadowMap1
        Texture2D ShadowMap2
        Texture2D ShadowMap3
        //pointLights
        Texture2D ShadowMap4
        Texture2D ShadowMap5
        
        Float ShadowIntensity
        Vector4 Splits
        Vector2 FadeInfo

        Matrix4 LightViewProjectionMatrix0
        Matrix4 LightViewProjectionMatrix1
        Matrix4 LightViewProjectionMatrix2
        Matrix4 LightViewProjectionMatrix3
        //pointLight
        Matrix4 LightViewProjectionMatrix4
        Matrix4 LightViewProjectionMatrix5   
        Vector3 LightPos
        Vector3 LightDir

        Float PCFEdge
        Float ShadowMapSize

        // For hardware skinning
        Int NumberOfBones
        Matrix4Array BoneMatrices
                
        //For instancing
        Boolean UseInstancing

        //For Vertex Color
        Boolean UseVertexColor

        Boolean BackfaceShadows : false
    }

    Technique {

        LightMode SinglePassAndImageBased

        VertexShader GLSL150:   MatDefs/PBRTerrainV2/terrainPBRShaderV2.vert
        FragmentShader GLSL150: MatDefs/PBRTerrainV2/terrainPBRShaderV2.frag

        WorldParameters {
            WorldViewProjectionMatrix
            CameraPosition
            WorldMatrix
            WorldNormalMatrix
            ViewProjectionMatrix
            ViewMatrix
            Time
        }

        Defines {
            PARALLAX_LOD_DISTANCE : ParallaxLODDistance
            PARALLAXMAPPING : parallaxMapping
            EMISSIVEMAP : EmissiveMap
            SPECGLOSSPIPELINE : SpecularMap
            PROBE_COLOR : ProbeColor
            NORMAL_TYPE: NormalType
            TRI_PLANAR_MAPPING : useTriPlanarMapping
            SLOT_0 : UseSlot_0
            SLOT_1 : UseSlot_1
            SLOT_2 : UseSlot_2
            SLOT_3 : UseSlot_3
            SLOT_4 : UseSlot_4
            SLOT_5 : UseSlot_5
            SLOT_6 : UseSlot_6
            SLOT_7 : UseSlot_7
            SLOT_8 : UseSlot_8
            SLOT_9 : UseSlot_9
            SLOT_10 : UseSlot_10
            SLOT_11 : UseSlot_11
            NORMALMAP_0 : UseNormalMap_0
            NORMALMAP_1 : UseNormalMap_1
            NORMALMAP_2 : UseNormalMap_2
            NORMALMAP_3 : UseNormalMap_3
            NORMALMAP_4 : UseNormalMap_4
            NORMALMAP_5 : UseNormalMap_5
            NORMALMAP_6 : UseNormalMap_6
            NORMALMAP_7 : UseNormalMap_7
            NORMALMAP_8 : UseNormalMap_8
            NORMALMAP_9 : UseNormalMap_9
            NORMALMAP_10 : UseNormalMap_10
            NORMALMAP_11 : UseNormalMap_11
            SPECULARMAP : SpecularMap
            ALPHAMAP : AlphaMap
            ALPHAMAP_1 : AlphaMap_1
            ALPHAMAP_2 : AlphaMap_2
            PARALLAXMAP_0 : UseParallaxMap_0
            PARALLAXMAP_1 : UseParallaxMap_1
            PARALLAXMAP_2 : UseParallaxMap_2
            PARALLAXMAP_3 : UseParallaxMap_3
            PARALLAXMAP_4 : UseParallaxMap_4
            PARALLAXMAP_5 : UseParallaxMap_5
            PARALLAXMAP_6 : UseParallaxMap_6
            PARALLAXMAP_7 : UseParallaxMap_7
            PARALLAXMAP_8 : UseParallaxMap_8
            PARALLAXMAP_9 : UseParallaxMap_9
            PARALLAXMAP_10 : UseParallaxMap_10
            PARALLAXMAP_11 : UseParallaxMap_11
        }
    }
    
}

vert:

#import "MatDefs/ShaderLib/GLSLCompat.glsllib"
#import "MatDefs/ShaderLib/Instancing.glsllib"

attribute vec3 inPosition;
attribute vec3 inNormal;
attribute vec2 inTexCoord;
uniform vec3 g_CameraPosition;

uniform vec4 g_AmbientLightColor; //passed to .frag for scaling light probe brightness in 3.3 compatible version of this shader.

varying vec2 texCoord;
varying vec3 wPosition;
varying vec3 wNormal;

#ifdef TRI_PLANAR_MAPPING
  varying vec4 wVertex;
#endif


#if defined(NORMALMAP_0) || defined(NORMALMAP_1) || defined(NORMALMAP_2) || defined(NORMALMAP_3) || defined(NORMALMAP_4) || defined(PLAGUEDNORMALMAP)
    attribute vec4 inTangent;
    varying vec4 wTangent;
#endif

varying float camDist;   

void main(){
    vec4 modelSpacePos = vec4(inPosition, 1.0);

    gl_Position = TransformWorldViewProjection(modelSpacePos);

    texCoord = inTexCoord;

    wPosition = TransformWorld(modelSpacePos).xyz;
    wNormal  = normalize(TransformWorldNormal(inNormal));
   #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)
        wTangent = vec4(TransformWorldNormal(inTangent.xyz),inTangent.w);
    #endif

    #ifdef TRI_PLANAR_MAPPING
       wVertex = vec4(inPosition,0.0);
       wNormal = inNormal;
    #endif

    camDist = distance(g_CameraPosition.xyz, wPosition.xyz);
}

edit:
oh and i forgot:

riccardo OcclusionParallax.glsllib was updated too, i forgot to send.

here it is:

/**
*   Occlusion Parallax Mapping
*   The implementation is based on this: https://learnopengl.com/Advanced-Lighting/Parallax-Mapping
*
*       - Riccardo Balbo
*/

#ifndef _OCCLUSION_PARALLAX_
    #define _OCCLUSION_PARALLAX_
     
    #ifndef Texture_sample
        #define Texture_sample texture
    #endif

    // #define HEIGHT_MAP R_COMPONENT
    // #define DEPTH_MAP R_COMPONENT
    
    #define R_COMPONENT 0
    #define G_COMPONENT 1
    #define B_COMPONENT 2    
    #define A_COMPONENT 3

    #if !defined(HEIGHT_MAP) && !defined(DEPTH_MAP)
        #define HEIGHT_MAP R_COMPONENT
    #endif
    
    #ifdef DEPTH_MAP
        #define HEIGHT_MAP DEPTH_MAP
    #endif

     struct _ParallaxData{
        vec2 deltaTexCoords;
        float layerDepth;
    } ParallaxData;

    
    void Parallax_initFor(in vec3 viewDir,in float heightScale){
        const float minLayers = 8.;
        const float maxLayers = 64.;

        float numLayers = mix(maxLayers, minLayers, abs(dot(vec3(0.0, 0.0, 1.0), viewDir))); 

        vec2 P = viewDir.xy / viewDir.z * heightScale;

        ParallaxData.layerDepth = 1.0 / numLayers;
        ParallaxData.deltaTexCoords = P / numLayers;
    }

    float _Parallax_selectDepth(in vec4 d){
        float depth;
        
        #if HEIGHT_MAP==R_COMPONENT
            depth=d.r;
        #elif HEIGHT_MAP==G_COMPONENT
            depth=d.g;
        #elif HEIGHT_MAP==B_COMPONENT
            depth=d.b;
        #else 
            depth=d.a;            
        #endif

        #ifndef DEPTH_MAP
            depth=1.-depth;
        #endif

        return depth;
    }

    float _Parallax_sampleDepth(in sampler2D depthMap,in vec2 uv){
        vec4 d=Texture_sample(depthMap,uv);
        return _Parallax_selectDepth(d);
    }

    void Parallax_displaceCoords(inout vec2 texCoords,in sampler2D depthMap){
        vec2 currentTexCoords = texCoords;
        float currentDepthMapValue = (_Parallax_sampleDepth(depthMap, currentTexCoords));
        float currentLayerDepth = 0.0;

        while(currentLayerDepth < currentDepthMapValue){
            currentTexCoords -= ParallaxData.deltaTexCoords;
            currentDepthMapValue = (_Parallax_sampleDepth(depthMap, currentTexCoords));
            currentLayerDepth += ParallaxData.layerDepth;
        }

        vec2 prevTexCoords = currentTexCoords + ParallaxData.deltaTexCoords;
        float afterDepth = currentDepthMapValue - currentLayerDepth;
        float beforeDepth = (_Parallax_sampleDepth(depthMap, prevTexCoords)) - currentLayerDepth + ParallaxData.layerDepth;

        float weight = afterDepth / (afterDepth - beforeDepth);
        texCoords = prevTexCoords * weight + currentTexCoords * (1.0 - weight);
    }

    float _Parallax_TextureArray_sampleDepth(in sampler2DArray depthMap,in vec2 uv,in int index){
        vec4 d= texture2DArray(depthMap, vec3(uv, index) );
        return _Parallax_selectDepth(d);
    }

    void Parallax_TextureArray_displaceCoords(inout vec2 texCoords,in sampler2DArray depthMap,in int index){
        vec2 currentTexCoords = texCoords;
        float currentDepthMapValue = (_Parallax_TextureArray_sampleDepth(depthMap, currentTexCoords, index));
        float currentLayerDepth = 0.0;

        while(currentLayerDepth < currentDepthMapValue){
            currentTexCoords -= ParallaxData.deltaTexCoords;
            currentDepthMapValue = (_Parallax_TextureArray_sampleDepth(depthMap, currentTexCoords, index));
            currentLayerDepth += ParallaxData.layerDepth;
        }

        vec2 prevTexCoords = currentTexCoords + ParallaxData.deltaTexCoords;
        float afterDepth = currentDepthMapValue - currentLayerDepth;
        float beforeDepth = (_Parallax_TextureArray_sampleDepth(depthMap, prevTexCoords, index)) - currentLayerDepth + ParallaxData.layerDepth;

        float weight = afterDepth / (afterDepth - beforeDepth);
        texCoords = prevTexCoords * weight + currentTexCoords * (1.0 - weight);
    }
#endif
2 Likes