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;
}