Terrain material with texture array?

Hi everyone,

Is there an example of a modified terrain material that uses texture arrays to bypass the texture count limit (which is limited to 12 textures)?

Thanks in advance

didnt @yaRnMcDonuts had one here?

Im using Texture Array for terrain textures like:

frag:

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

if you want read:

tempAlbedo.rgb = texture2DArray(m_PhongTextures, vec3(coord##index, texIndex) ).rgb;\

j3md:

        TextureArray PhongTextures
        TextureArray NormalmapTextures -LINEAR
        TextureArray ParallaxmapTextures -LINEAR
        TextureArray RoughnessmapTextures -LINEAR

java:

import com.jme3.texture.TextureArray;

using:

        List<Image> phongTextureList = new ArrayList<>();

        // some code to fill, remember about below(tho im not sure if needed here):
        phong.setWrap(Texture.WrapMode.Repeat);


        TextureArray phongTextures = new TextureArray(phongTextureList);
        phongTextures.setWrap(Texture.WrapMode.Repeat);
        phongTextures.setMinFilter(Texture.MinFilter.Trilinear);

        // some material init code / etc

        mat.setTexture("PhongTextures", phongTextures);
2 Likes

Thank you so much, @oxplay2

Don’t know. I think he is using PBR material. In my case, I am using Phong material.

Do you pass alpha map textures also in the texture arrays?

Edit:
If possible, I would appreciate it if you can post the whole frag shader and j3md file (for the Phong material), please?

I am a shader nooob! :sweat_smile:

1 Like

oh, it would be too much now to just pull phong only, i will just show you all .frag file and .j3md file

#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_Metallic_0;
uniform float m_Metallic_1;
uniform float m_Metallic_2;
uniform float m_Metallic_3;

uniform float m_Parallax_0;
uniform float m_Parallax_1;
uniform float m_Parallax_2;
uniform float m_Parallax_3;

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

#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 ALPHAMAP
  uniform sampler2D m_AlphaMap;
#endif

#ifdef PARALLAXMAP_0
  uniform float m_ParallaxHeight_0;
  uniform float m_ParallaxHeightFix_0;
  uniform float m_ParallaxAOColorFactor_0;
#endif
#ifdef PARALLAXMAP_1
  uniform float m_ParallaxHeight_1;
  uniform float m_ParallaxHeightFix_1;
  uniform float m_ParallaxAOColorFactor_1;
#endif
#ifdef PARALLAXMAP_2
  uniform float m_ParallaxHeight_2;
  uniform float m_ParallaxHeightFix_2;
  uniform float m_ParallaxAOColorFactor_2;
#endif
#ifdef PARALLAXMAP_3
  uniform float m_ParallaxHeight_3;
  uniform float m_ParallaxHeightFix_3;
  uniform float m_ParallaxAOColorFactor_3;
#endif


uniform sampler2D m_NoiseMap_1;
uniform sampler2D m_NoiseMap_2;

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

varying float camDist;
varying float height;

vec2 coord;
vec4 albedo = vec4(0.0,0.0,0.0,1.0);
vec4 tempAlbedo = vec4(0.0,0.0,0.0,1.0);
vec4 tempNormal;
vec4 tempRoughness;
vec3 normal = vec3(0.0,1.0,0.0);
vec3 newNormal;
vec3 parallax;
vec2 newTexCoord;
vec3 viewDir;
mat3 tbnMat;
vec3 norm;
float Metallic = 0.0;
float Roughness = 0.5;
float currentBlendValue = 0.01;
float blendPercent = 1.0;
float parallaxAverageDepth = 0.0;
float parallaxAverageAOColorFactor = 0.0;
float clampedMoistureDepth = 0.0;
float moistureRoughness = 0.0;
vec4 alphaBlend;
float normalBasedMoisureIntensity = 0.0;
float noise = 0.0;
float noise2 = 0.0;
float noise3 = 0.0;
float noise4 = 0.0;

/////////////////////////////////////////
//TANGENTS
///////////////////////////////////////
/*
vec3 Texture_sampleTSpaceNormal(in sampler2D itx,in vec2 uv){ 
        vec4 normalHeight = Texture_sample(itx, uv); 

        #ifdef OPENGL_NORMALMAP
            vec3 normal = normalize((normalHeight.xyz * vec3(2.,-2.,2.) - vec3(1.,-1.,1.)));
        #else
            vec3 normal = normalize((normalHeight.xyz * vec3(2.,2.,2.) - vec3(1.,1.,1.)));
        #endif

        normal.z = sqrt(1-clamp(dot(normal.xy, normal.xy),0.,1.)); // Reconstruct Z
        return normal;
    }

    vec3 Triplanar_sampleWorldNormal(in sampler2D tx,in sampler2D txTop,in float scale){
        vec3 normalX=Texture_sampleTSpaceNormal(tx,(TriplanarData.worldPos.zy+TriplanarData.zyOffset)*scale);
        vec3 normalY=Texture_sampleTSpaceNormal(txTop,(TriplanarData.worldPos.xz+TriplanarData.xzOffset)*scale); //tx?
        vec3 normalZ=Texture_sampleTSpaceNormal(tx,(TriplanarData.worldPos.xy+TriplanarData.xyOffset)*scale);

    vec3 s=sign(TriplanarData.surfaceWorldNormal);

    vec3 T=vec3(0,0,1);
    vec3 N=vec3(1,0,0)*s;
    vec3 B=cross(T,N);

    mat3 tbnMat= mat3(T,B,N );
    normalX=tbnMat*normalX;

    T=vec3(0,0,1);
    N=vec3(0,1,0)*s;
    B=cross(T,N);
    tbnMat=mat3(T,B,N );
    normalY=tbnMat*normalY;

    T=vec3(0,1,0);
    N=vec3(0,0,1)*s;
    B=cross(T,N);
    tbnMat= mat3(T,B,N );
    normalZ=tbnMat*normalZ;   
    
    vec3 blending=abs(TriplanarData.surfaceNormal);
    blending=normalize(max(blending, 0.00001)); 
    float b=(blending.x+blending.y+blending.z);
    blending/=vec3(b);    
    
    return (normalX * (blending.x)) + (normalY *(blending.y)) + (normalZ * (blending.z));
}
*/
///////////////////////////////////////////
//TANGENTS CALCULATING
mat3 cotangent_frame(vec3 N, vec3 p, vec2 uv){
    // get edge vectors of the pixel triangle
    vec3 dp1 = dFdx( p );
    vec3 dp2 = dFdy( p );
    vec2 duv1 = dFdx( uv );
    vec2 duv2 = dFdy( uv );
     
    // solve the linear system
    vec3 dp2perp = cross( dp2, N );
    vec3 dp1perp = cross( N, dp1 );
    vec3 T = dp2perp * duv1.x + dp1perp * duv2.x;
    vec3 B = dp2perp * duv1.y + dp1perp * duv2.y;
     
    // construct a scale-invariant frame 
    float invmax = 1.0/sqrt( max( dot(T,T), dot(B,B) ) );
    return mat3( T * invmax, B * invmax, N );
}
 
mat3 calcTBN(vec3 N, vec3 V, vec2 texcoord ){
    mat3 TBN = cotangent_frame( N, -V, texcoord );
    return TBN;
}
////////////////////////////////////

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

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

#define BLEND(index, ab, texIndex)\
    tempAlbedo.rgb = texture2DArray(m_PhongTextures, vec3(coord##index, texIndex) ).rgb;\
    tempRoughness.rgb = texture2DArray(m_RoughnessmapTextures, vec3(coord##index, texIndex) ).rgb;\
    albedo.rgb = mix( albedo.rgb, tempAlbedo.rgb, blendPercent);\
    normal.rgb = mix(normal.xyz, wNormal.xyz, blendPercent);\
    clampedMoistureDepth = PARALLAX_MOISTURE_DEPTH_INTENSITY##index * lastParallaxDepth + PARALLAX_MOISTURE_DEPTH_FIX##index;\
    moistureRoughness = mix(moistureRoughness, clampedMoistureDepth, blendPercent);\
    Metallic = mix(Metallic, m_Metallic##index, blendPercent);\
    Roughness = mix(Roughness, m_Roughness##index * tempRoughness.r, blendPercent);

#define BLEND_NORMAL(index, ab, texIndex)\
    newNormal = texture2DArray(m_NormalmapTextures, vec3(coord##index, texIndex) ).rgb;\
    normal = mix(normal, newNormal, blendPercent);\

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

void calculateParallax(inout vec2 parallaxTexCoord, in float initialParallaxHeight, in float parallaxHeight, in float parallaxAOColorFactor, in float intensity, in int texIndex) {

    #ifdef PARALLAX_LOD_DISTANCE
    if(camDist < PARALLAX_LOD_DISTANCE && blendPercent > 0.2){
    #else
    if(blendPercent > 0.2){
    #endif
        mat3 invTBN=transpose(tbnMat); 
        vec3 TanPos = invTBN*wPosition;
        vec3 TanCamPos = invTBN*g_CameraPosition;        
        vec3 TanViewDir=normalize(TanCamPos-TanPos);
        Parallax_initFor(TanViewDir,parallaxHeight);
        Parallax_TextureArray_displaceCoords(parallaxTexCoord, m_ParallaxmapTextures, initialParallaxHeight, texIndex);
    }
    parallaxAverageDepth += lastParallaxDepth * blendPercent;
    parallaxAverageDepth = clamp(parallaxAverageDepth, 0.0, 1.0);
    parallaxAverageAOColorFactor += clamp(parallaxAOColorFactor, 0.0, 1.0) * blendPercent;
}

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

    normalBasedMoisureIntensity = normalize(wNormal).y;
    normalBasedMoisureIntensity = clamp(pow(normalBasedMoisureIntensity, 8), 0.0, 1.0);

    vec3 wvPosition=(vec4(inPosition,1)*g_WorldViewMatrix).xyz;
    #ifdef SLOT_0   
        DEFINE_COORD(_0)
        CALCULATE_BLEND_PERCENT(alphaBlend.r)
        #if defined(PARALLAXMAPPING) && defined (PARALLAXMAP_0)
            PARALLAX_BLEND(_0, alphaBlend.r, 0)
        #endif
        BLEND(_0,  alphaBlend.r, 0)
        #ifdef NORMALMAP_0
            BLEND_NORMAL(_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
        BLEND(_1,  alphaBlend.g, 1)
        #ifdef NORMALMAP_1
            BLEND_NORMAL(_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
        BLEND(_2,  alphaBlend.b, 2)
        #ifdef NORMALMAP_2
            BLEND_NORMAL(_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
        BLEND(_3,  alphaBlend.a, 3)
        #ifdef NORMALMAP_3
            BLEND_NORMAL(_3,  alphaBlend.a, 3)
        #endif
    #endif
    #if defined(PARALLAXMAPPING)

    moistureRoughness *= clamp(0.5 + noise, 0.0, 1.0);
    moistureRoughness *= normalBasedMoisureIntensity;

    float moisureIntensity = POST_RAIN_MOISTURE;
    Roughness -= moistureRoughness * clamp(moisureIntensity, 0.0, 1.0);
    Metallic += moistureRoughness * clamp(moisureIntensity, 0.0, 1.0);
    
    if(Roughness < 0.5){
        Roughness -= (0.5 - Roughness) * 1;
        Metallic += (0.5 - Roughness) * 1;
    }

    #endif
    return albedo;
}

#ifdef PROBE_COLOR
    uniform vec4 m_ProbeColor;
#endif

void main(){

    noise = texture2D(m_NoiseMap_1, texCoord*20).r;
    noise2 = texture2D(m_NoiseMap_2, texCoord*20).r;
    noise3 = texture2D(m_NoiseMap_1, texCoord*30).r;
    noise4 = texture2D(m_NoiseMap_2, texCoord*30).r;
    

    viewDir = normalize(g_CameraPosition - wPosition);

    vec3 norm = normalize(wNormal);
    normal = norm;

    
    /////////////////////////////////////////
    //TANGENTS
    ///////////////////////////////////////
    tbnMat = calcTBN(normal, viewDir, texCoord);

    /////////////////////////////////////////
    //fix for geforce card (wireframe mode)
    if(isnan(tbnMat[0].x)){
        // domyslny tangent
        vec3 T=vec3(0,0,1);
        vec3 N=vec3(0,1,0);
        vec3 B=cross(T,N);
        tbnMat=mat3(T,B,N);
    }
    /////////////////////////////////////////
    
    newTexCoord=texCoord;
    alphaBlend = texture2D( m_AlphaMap, newTexCoord.xy );
    //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

    Metallic = clamp(Metallic, 0.0, 1.0);
    Roughness = clamp(Roughness, 0.0, 1.0);

    //roughnessing vars
    Roughness *= 0.9 + noise3 * 0.1;
    Metallic *= 0.8 + noise4 * 0.2;

    // for high roughness, make normal up direction so it will be flat
    normal = mix(vec3(0.0,1.0,0.0), normal, clamp(Roughness, 0.0, 1.0));
    normal = normalize(normal);

     #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;
    }
    
    //////////////////////////////////////////////////
    //normal.y *= 20;
    //normal = normalize(normal);
    //////////////////////////////////////////////////

    vec3 metalnessNormal = normal;
    metalnessNormal.y *= 2;
    metalnessNormal = normalize(metalnessNormal);

    #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, metalnessNormal, metalnessNormal, Roughness, diffuseColor, specularColor, ndotv, ao, g_LightProbeData, g_ShCoeffs, g_PrefEnvMap, color1);
        #if NB_PROBES >= 2
            float ndf2 = renderProbe(viewDir, wPosition, metalnessNormal, metalnessNormal, Roughness, diffuseColor, specularColor, ndotv, ao, g_LightProbeData2, g_ShCoeffs2, g_PrefEnvMap2, color2);
        #endif
        #if NB_PROBES == 3
            float ndf3 = renderProbe(viewDir, wPosition, metalnessNormal, metalnessNormal, 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

    //noise = texture2D(m_NoiseMap_2, texCoord).r;
    //parallaxAverageAOColorFactor *= noise;

   //gl_FragColor.rbg = mix(gl_FragColor.rbg,vec3(0,0,0),parallaxAverageDepth/2);
    gl_FragColor.rbg = mix(gl_FragColor.rbg*parallaxAverageAOColorFactor,gl_FragColor.rbg,clamp((1.-parallaxAverageDepth)*1.2,0.0,1.0));
    gl_FragColor.a = 1.0;
    //ponizej robi ze tam gdzie niema alphy - tekstury, tam jest czarne
    //gl_FragColor.rbg = mix(vec3(0.0,0.0,0.0), gl_FragColor.rbg,clamp(1000.0*(alphaBlend.r + alphaBlend.g + alphaBlend.b + alphaBlend.a),0.0,1.0));

    
    //gl_FragColor.rgb = vec3(parallaxAverageDepth, parallaxAverageDepth, parallaxAverageDepth);
    
    //gl_FragColor.rgb = vec3(Metallic, Metallic, Metallic);
    //gl_FragColor.rgb = vec3(Roughness, Roughness, Roughness);
    
    //gl_FragColor.rgb = vec3(noise, noise, noise);
    
    
    //gl_FragColor.a = 1.0;
    
    //gl_FragColor.rgb = vec3(height/50,0,0);
    //gl_FragColor.rgb = vec3(height/20,1 - height/20,0);
    
    //gl_FragColor.r *= normalize(wNormal).y;
    //gl_FragColor.b *= normalize(wNormal).y;
    //gl_FragColor.rgb = vec3(normalBasedMoisureIntensity, 1.0 - normalBasedMoisureIntensity, 0.0);

    //gl_FragColor.rgb *= normalize(normal);
    //int texIndex = 0;
    //vec4 baseColorMapValue = texture2DArray(m_PhongTextures, vec3(texCoord, texIndex) ).rgba;

    //gl_FragColor = (baseColorMapValue * );
}

j3md:

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
        Float PostRainMoisture : 0.5

        // 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 Metallic_0 : 0.0
        Float Metallic_1 : 0.0
        Float Metallic_2 : 0.0
        Float Metallic_3 : 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
        TextureArray RoughnessmapTextures -LINEAR

        Texture2D NoiseMap_1
        Texture2D NoiseMap_2

        // Texture map #0
        Float Slot_0_scale
        Float ParallaxHeight_0
        Float ParallaxHeightFix_0
        Float ParallaxAOColorFactor_0 : 0.3
        Float ParallaxRainMoistureDepthFix_0 : 0
        Float ParallaxRainMoistureDepthIntensity_0 : 1
        Float ParallaxRainMoistureDepthWater_0 : 1
        Boolean UseSlot_0
        Boolean UseNormalMap_0
        Boolean UseParallaxMap_0

        // Texture map #1
        Float Slot_1_scale
        Float ParallaxHeight_1
        Float ParallaxHeightFix_1
        Float ParallaxAOColorFactor_1 : 0.3
        Float ParallaxRainMoistureDepthFix_1 : 0
        Float ParallaxRainMoistureDepthIntensity_1 : 1
        Float ParallaxRainMoistureDepthWater_1 : 1
        Boolean UseSlot_1
        Boolean UseNormalMap_1
        Boolean UseParallaxMap_1

        // Texture map #2
        Float Slot_2_scale
        Float ParallaxHeight_2
        Float ParallaxHeightFix_2
        Float ParallaxAOColorFactor_2 : 0.3
        Float ParallaxRainMoistureDepthFix_2 : 0
        Float ParallaxRainMoistureDepthIntensity_2 : 1
        Float ParallaxRainMoistureDepthWater_2 : 1
        Boolean UseSlot_2
        Boolean UseNormalMap_2
        Boolean UseParallaxMap_2

        // Texture map #3
        Float Slot_3_scale
        Float ParallaxHeight_3
        Float ParallaxHeightFix_3
        Float ParallaxAOColorFactor_3 : 0.3
        Float ParallaxRainMoistureDepthFix_3 : 0
        Float ParallaxRainMoistureDepthIntensity_3 : 1
        Float ParallaxRainMoistureDepthWater_3 : 1
        Boolean UseSlot_3
        Boolean UseNormalMap_3
        Boolean UseParallaxMap_3

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

        // Texture that specifies alpha values
        Texture2D AlphaMap -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 GLSL330:   MatDefs/RTerrain/RTerrain.vert
        FragmentShader GLSL330: MatDefs/RTerrain/RTerrain.frag

        WorldParameters {
            WorldViewProjectionMatrix
            CameraPosition
            WorldMatrix
            WorldNormalMatrix
            ViewProjectionMatrix
            ViewMatrix
            Time
        }

        Defines {
            POST_RAIN_MOISTURE : PostRainMoisture;
            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
            NORMALMAP_0 : UseNormalMap_0
            NORMALMAP_1 : UseNormalMap_1
            NORMALMAP_2 : UseNormalMap_2
            NORMALMAP_3 : UseNormalMap_3
            SPECULARMAP : SpecularMap
            ALPHAMAP : AlphaMap
            PARALLAXMAP_0 : UseParallaxMap_0
            PARALLAXMAP_1 : UseParallaxMap_1
            PARALLAXMAP_2 : UseParallaxMap_2
            PARALLAXMAP_3 : UseParallaxMap_3
            PARALLAX_MOISTURE_DEPTH_FIX_0 : ParallaxRainMoistureDepthFix_0
            PARALLAX_MOISTURE_DEPTH_FIX_1 : ParallaxRainMoistureDepthFix_1
            PARALLAX_MOISTURE_DEPTH_FIX_2 : ParallaxRainMoistureDepthFix_2
            PARALLAX_MOISTURE_DEPTH_FIX_3 : ParallaxRainMoistureDepthFix_3
            PARALLAX_MOISTURE_DEPTH_INTENSITY_0 : ParallaxRainMoistureDepthIntensity_0
            PARALLAX_MOISTURE_DEPTH_INTENSITY_1 : ParallaxRainMoistureDepthIntensity_1
            PARALLAX_MOISTURE_DEPTH_INTENSITY_2 : ParallaxRainMoistureDepthIntensity_2
            PARALLAX_MOISTURE_DEPTH_INTENSITY_3 : ParallaxRainMoistureDepthIntensity_3
            PARALLAX_MOISTURE_DEPTH_WATER_0 : ParallaxRainMoistureDepthWater_0
            PARALLAX_MOISTURE_DEPTH_WATER_1 : ParallaxRainMoistureDepthWater_1
            PARALLAX_MOISTURE_DEPTH_WATER_2 : ParallaxRainMoistureDepthWater_2
            PARALLAX_MOISTURE_DEPTH_WATER_3 : ParallaxRainMoistureDepthWater_3
            NOISEMAP_1 : NoiseMap_1
            NOISEMAP_2 : NoiseMap_2
        }
    }
    
}

.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;   
varying float height;   

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);
    height = wPosition.y;
}

remove not needed code or ust from default terrain shader to replace my crazy code there :wink:

note, my terrain material do not support triplannar as i remember.

Alphamap i probably had still just sampler, but you can use sampler2DArray to have multiple alphamaps, tho it will require much more blending there. (so i probably due to optimize/fps issues just have one)

1 Like

Thanks

1 Like

FYI, Ryan’s PBR terrain shaders have been integrated in the Engine. The advanced version uses texture arrays:

4 Likes

Looking at those codes and the code provided by @oxplay2, I got a grasp of how to use texture array.

Thanks, everyone for the help. :slightly_smiling_face:

2 Likes

You may also be interested in considering using this new loop functionality that’s been added to the master branch. ( I have not used these new for loops yet myself, but I do plan to refractor my terrain shaders with these for loops in the future )

When I wrote my shader using texture arrays, this PR didn’t exist, so that’s why every JME terrain shader has redundant code for texture slots 1-12 instead of using recursion. But now I think for loops should be possible in jme shaders, so that’s something to consider if you’re feeling more adventurous and are using master branch.

3 Likes

good one, i forgot about it!

2 Likes

Thanks, will take a look at it.

Does a single instance of texture array still limited to 16 textures (on GPU) or there is no such limit?

You can put every texture into one massive array if you want I think, but I just split them up into more than one texture array for organizational purpose.

So if there is a limit to the number of textures you can have in each texture array, I expect it is quite high, or at least high enough I haven’t hit it.

So you are still limited to 16 texture params, but one or more of these params can be a texture array param which can contain as many textures as you want in each array.

2 Likes

im not sure about limit, but thing is that each texture need to be same size (i mean in TextureArray)

2 Likes

Yeah the “must be same size and format” error can be finicky to troubleshoot (especially if your textures come from different sources) because it not only is talking about the size and .jpg and .png format, but also the bit depth and color space of the texture.

3 Likes