2
0
Эх сурвалжийг харах

Merge pull request #2353 from jMonkeyEngine/yaRnMcDonuts-patch-4

Per-Layer TriPlanar and Refactoring for PBR Terrain Shaders
Ryan McDonough 7 сар өмнө
parent
commit
7e2f336b45

+ 103 - 630
jme3-terrain/src/main/resources/Common/MatDefs/Terrain/AdvancedPBRTerrain.frag

@@ -1,669 +1,142 @@
 #extension GL_EXT_texture_array : enable
 #import "Common/ShaderLib/GLSLCompat.glsllib"
-#import "Common/ShaderLib/PBR.glsllib"
-#import "Common/ShaderLib/Lighting.glsllib"
-#import "Common/MatDefs/Terrain/AfflictionLib.glsllib"
 
-varying vec3 wPosition;
-varying vec3 vNormal;
-varying vec2 texCoord;
-uniform vec3 g_CameraPosition;
-varying vec3 vPosition;
-varying vec3 vnPosition;
-varying vec3 vViewDir;
-varying vec4 vLightDir;
-varying vec4 vnLightDir;
-varying vec3 lightVec;
-varying vec3 inNormal;
-varying vec3 wNormal;
+#define ENABLE_PBRLightingUtils_getWorldPosition 1
+#define ENABLE_PBRLightingUtils_getLocalPosition 1
+#define ENABLE_PBRLightingUtils_getWorldNormal 1
+#define ENABLE_PBRLightingUtils_getTexCoord 1
+#define ENABLE_PBRLightingUtils_computeDirectLightContribution 1
+#define ENABLE_PBRLightingUtils_computeProbesContribution 1
 
-// Specular-AA
-#ifdef SPECULAR_AA_SCREEN_SPACE_VARIANCE
-  uniform float m_SpecularAASigma;
-#endif
-#ifdef SPECULAR_AA_THRESHOLD
-  uniform float m_SpecularAAKappa;
-#endif
+#define ENABLE_PBRTerrainUtils_readPBRTerrainLayers 1
 
-#ifdef DEBUG_VALUES_MODE
-    uniform int m_DebugValuesMode;
+#import "Common/ShaderLib/module/pbrlighting/PBRLightingUtils.glsllib"
+#import "Common/MatDefs/ShaderLib/PBRTerrainUtils.glsllib"
+#ifdef AFFLICTIONTEXTURE
+    #import "Common/MatDefs/ShaderLib/AfflictionLib.glsllib"
 #endif
 
+//declare PBR Lighting vars
 uniform vec4 g_LightData[NB_LIGHTS];
-uniform vec4 g_AmbientLightColor;
-
-#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 TRI_PLANAR_MAPPING
-  varying vec4 wVertex; 
-#endif
-
-//texture arrays:
-uniform sampler2DArray m_AlbedoTextureArray;
-uniform sampler2DArray m_NormalParallaxTextureArray;
-uniform sampler2DArray m_MetallicRoughnessAoEiTextureArray;
-
-//texture-slot params for 12 unique texture slots (0-11) where the integer value points to the desired texture's index in the corresponding texture array:
-#for i=0..12 ( $0 )
-    uniform int m_AfflictionMode_$i;
-    uniform float m_Roughness_$i;
-    uniform float m_Metallic_$i;
-    uniform float m_AlbedoMap_$i_scale;
-    uniform vec4 m_EmissiveColor_$i;
-    
-    #ifdef ALBEDOMAP_$i
-        uniform int m_AlbedoMap_$i;
-    #endif        
-    #ifdef NORMALMAP_$i
-        uniform int m_NormalMap_$i;
-    #endif    
-    #ifdef METALLICROUGHNESSMAP_$i
-        uniform int m_MetallicRoughnessMap_$i;
-    #endif
-#endfor 
-
-//3 alpha maps :
-#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
+uniform vec3 g_CameraPosition;
 
-#ifdef DISCARD_ALPHA
-    uniform float m_AlphaDiscardThreshold;
+#ifdef DEBUG_VALUES_MODE
+    uniform int m_DebugValuesMode;
 #endif
 
-//fog vars for basic fog :
 #ifdef USE_FOG
-#import "Common/ShaderLib/MaterialFog.glsllib"
-    uniform vec4 m_FogColor;
-    float fogDistance;
-
-    uniform vec2 m_LinearFog;
+    #import "Common/ShaderLib/MaterialFog.glsllib"
 #endif
-#ifdef FOG_EXP
-    uniform float m_ExpFog;
-#endif
-#ifdef FOG_EXPSQ
-    uniform  float m_ExpSqFog;
-#endif
-
-//sun intensity is a secondary AO value that can be painted per-vertex in the red channel of the 
-// vertex colors, or it can be set as a static value for an entire material with the StaticSunIntensity float param 
-#if defined(USE_VERTEX_COLORS_AS_SUN_INTENSITY) 
-    varying vec4 vertColors; 
-#endif
-
-#ifdef STATIC_SUN_INTENSITY
-    uniform float m_StaticSunIntensity;
-#endif
-//sun intensity AO value is only applied to the directional light, not to point lights, so it is important to track if the 
-//sun is more/less bright than the brightest point light for each fragment to determine how the light probe's ambient light should be scaled later on in light calculation code
-float brightestPointLight = 0.0;
-
-//optional affliction paramaters that use the AfflictionAlphaMap's green channel for splatting m_SplatAlbedoMap and the red channel for splatting desaturation  :
-#ifdef AFFLICTIONTEXTURE 
-    uniform sampler2D m_AfflictionAlphaMap;
-#endif
-#ifdef USE_SPLAT_NOISE
-     uniform float m_SplatNoiseVar;
-#endif
-//only defined for non-terrain geoemtries and terrains that are not positioned nor sized in correlation to the 2d array of AfflictionAlphaMaps used for splatting accross large tile based scenes in a grid
-#ifdef TILELOCATION
-    uniform float m_TileWidth;
-    uniform vec3 m_TileLocation;
-#endif
-#ifdef AFFLICTIONALBEDOMAP
-    uniform sampler2D m_SplatAlbedoMap;
-#endif
-#ifdef AFFLICTIONNORMALMAP
-    uniform sampler2D m_SplatNormalMap;
-#endif
-#ifdef AFFLICTIONROUGHNESSMETALLICMAP
-    uniform sampler2D m_SplatRoughnessMetallicMap;
-#endif
-#ifdef AFFLICTIONEMISSIVEMAP
-    uniform sampler2D m_SplatEmissiveMap;
-#endif
-
-uniform int m_AfflictionSplatScale;
-uniform float m_AfflictionRoughnessValue;
-uniform float m_AfflictionMetallicValue;
-uniform float m_AfflictionEmissiveValue;
-uniform vec4 m_AfflictionEmissiveColor;
-
-vec4 afflictionVector;
-float noiseHash;
-float livelinessValue;
-float afflictionValue;
-int afflictionMode = 1;
-
-//general temp vars :
-vec4 tempAlbedo, tempNormal, tempEmissiveColor;
-float tempParallax, tempMetallic, tempRoughness, tempAo, tempEmissiveIntensity;
 
-vec3 viewDir;
-vec2 coord;
-vec4 albedo = vec4(1.0);
-vec3 normal = vec3(0.5,0.5,1);
-vec3 norm;
-float Metallic;
-float Roughness;
-float packedAoValue = 1.0;
-vec4 emissive;
-float emissiveIntensity = 1.0;
-float indoorSunLightExposure = 1.0;
- 
-vec4 packedMetallicRoughnessAoEiVec;
-vec4 packedNormalParallaxVec;  
-
-
-void main(){    
-    
-    #ifdef USE_FOG
-        fogDistance = distance(g_CameraPosition, wPosition.xyz);
-    #endif
+void main(){       
+    vec3 wpos = PBRLightingUtils_getWorldPosition();
+    vec3 worldViewDir = normalize(g_CameraPosition - wpos);
     
-    float indoorSunLightExposure = 1.0;
+    // Create a blank PBRSurface.
+    PBRSurface surface = PBRLightingUtils_createPBRSurface(worldViewDir);
     
-    viewDir = normalize(g_CameraPosition - wPosition);
+    //pre-calculate necessary values for tri-planar blending
+    TriPlanarUtils_calculateBlending(surface.geometryNormal);
 
-    norm  = normalize(wNormal);
-    normal = norm;
-
-
-    afflictionVector = vec4(1.0, 0.0, 1.0, 0.0); //r channel is sturation, g channel is affliction splat texture intensity, b and a unused (might use b channel for wetness eventually)
-    
+    //reads terrain alphaMaps
+    PBRTerrainUtils_readAlphaMaps();   
+   
+    //CUSTOM LIB EXAMPLE:
     #ifdef AFFLICTIONTEXTURE
-    
-        #ifdef TILELOCATION 
-        //subterrains that are not centred in tile or equal to tile width in total size need to have m_TileWidth pre-set. (tileWidth is the x,z dimesnions that the AfflictionAlphaMap represents)..
-            vec2 tileCoords;
-            float xPos, zPos;
-
-            vec3 locInTile = (wPosition - m_TileLocation);
-
-             locInTile += vec3(m_TileWidth/2, 0, m_TileWidth/2);
-
-             xPos = (locInTile.x / m_TileWidth);
-             zPos = 1 - (locInTile.z / m_TileWidth);
-
-            tileCoords = vec2(xPos, zPos);
+        AfflictionLib_readAfflictionVector();
+    #endif
 
-            afflictionVector = texture2D(m_AfflictionAlphaMap, tileCoords).rgba;
+    // read and blend up to 12 texture layers
+    #for i=0..12 (#ifdef ALBEDOMAP_$i $0 #endif)
+    
+        PBRTerrainTextureLayer terrainTextureLayer_$i = PBRTerrainUtils_createAdvancedPBRTerrainLayer($i);
         
+        #ifdef USE_FIRST_LAYER_AS_TRANSPARENCY
+            if($i == 0){
+                if(terrainTextureLayer_$i.blendValue > 0.01f){ 
+                    discard;
+                }     
+            }    
+        #endif 
         
-     
-        #else
-           // ..othrewise when terrain size matches tileWidth, the terrain's texCoords can be used for simple texel fetching of the AfflictionAlphaMap
-            afflictionVector = texture2D(m_AfflictionAlphaMap, texCoord.xy).rgba;
-        #endif
-    #endif
-
-    livelinessValue = afflictionVector.r;
-    afflictionValue = afflictionVector.g;
-
-
-    #ifdef ALBEDOMAP_0
-        #ifdef ALPHAMAP           
-
-            vec4 alphaBlend;
-            vec4 alphaBlend_0, alphaBlend_1, alphaBlend_2;
-            int texChannelForAlphaBlending;
-
-            alphaBlend_0 = texture2D( m_AlphaMap, texCoord.xy );
-
-            #ifdef ALPHAMAP_1
-                alphaBlend_1 = texture2D( m_AlphaMap_1, texCoord.xy );
+        terrainTextureLayer_$i.emission = m_EmissiveColor_$i;
+        
+        #if defined(TRI_PLANAR_MAPPING) || defined(TRI_PLANAR_MAPPING_$i)
+          //triplanar:
+            
+            PBRTerrainUtils_readTriPlanarAlbedoTexArray(ALBEDOMAP_$i, m_AlbedoMap_$i_scale, m_AlbedoTextureArray, terrainTextureLayer_$i);        
+            #ifdef NORMALMAP_$i
+                PBRTerrainUtils_readTriPlanarNormalTexArray(NORMALMAP_$i, m_AlbedoMap_$i_scale, m_NormalParallaxTextureArray, terrainTextureLayer_$i);
             #endif
-            #ifdef ALPHAMAP_2
-                alphaBlend_2 = texture2D( m_AlphaMap_2, texCoord.xy );
+            #ifdef METALLICROUGHNESSMAP_$i
+                PBRTerrainUtils_readTriPlanarMetallicRoughnessAoEiTexArray(METALLICROUGHNESSMAP_$i, m_AlbedoMap_$i_scale, m_MetallicRoughnessAoEiTextureArray, terrainTextureLayer_$i);
             #endif
-
-            vec2 texSlotCoords;   
-
-            float finalAlphaBlendForLayer = 1.0;
-
-            vec3 blending = abs( norm );
-            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);
-
-            #for i=0..12 (#ifdef ALBEDOMAP_$i $0 #endif)
-
-                //assign texture slot's blending from index's correct alpha map
-                if($i <= 3){
-                    alphaBlend = alphaBlend_0;       
-                }else if($i <= 7){
-                    alphaBlend = alphaBlend_1;
-                }else if($i <= 11){
-                    alphaBlend = alphaBlend_2;
-                }
-
-                texChannelForAlphaBlending = int(mod(float($i), 4.0)); //pick the correct channel (r g b or a) based on the layer's index
-                switch(texChannelForAlphaBlending) {
-                    case 0:
-                        finalAlphaBlendForLayer = alphaBlend.r;
-                        break;
-                    case 1:
-                        finalAlphaBlendForLayer = alphaBlend.g;
-                        break;
-                    case 2:
-                        finalAlphaBlendForLayer = alphaBlend.b;
-                        break;
-                    case 3:
-                        finalAlphaBlendForLayer = alphaBlend.a;
-                        break;            
-                }
-
-                afflictionMode = m_AfflictionMode_$i;            
-                tempEmissiveColor = m_EmissiveColor_$i;
-
-                #ifdef TRI_PLANAR_MAPPING   
-            //tri planar
-                    tempAlbedo = getTriPlanarBlendFromTexArray(wVertex, blending, m_AlbedoMap_$i, m_AlbedoMap_$i_scale, m_AlbedoTextureArray);
-
-                    #ifdef NORMALMAP_$i
-                        packedNormalParallaxVec.rgba = getTriPlanarBlendFromTexArray(wVertex, blending, m_NormalMap_$i, m_AlbedoMap_$i_scale, m_NormalParallaxTextureArray).rgba;
-                        tempNormal.xyz = calculateTangentsAndApplyToNormals(packedNormalParallaxVec.xyz, wNormal);// this gets rid of the need for pre-generating tangents for TerrainPatches, since doing so doesn't seem to work (tbnMat is always blank for terrains even with tangents pre-generated, not sure why...)
-                        tempParallax = packedNormalParallaxVec.w;
-
-                        #ifdef PARALLAXHEIGHT_0    
-                            //wip
-                        #endif
-                    #else
-                        tempNormal.rgb = wNormal.rgb;
-                    #endif
-                    #ifdef METALLICROUGHNESSMAP_$i
-                        packedMetallicRoughnessAoEiVec = getTriPlanarBlendFromTexArray(wVertex, blending, m_MetallicRoughnessMap_$i, m_AlbedoMap_$i_scale, m_MetallicRoughnessAoEiTextureArray).rgba;
-                        tempRoughness = packedMetallicRoughnessAoEiVec.g * m_Roughness_$i;
-                        tempMetallic = packedMetallicRoughnessAoEiVec.b * m_Metallic_$i;
-                        tempAo = packedMetallicRoughnessAoEiVec.r;
-                        tempEmissiveIntensity = packedMetallicRoughnessAoEiVec.a;        
-                    #endif
-                #else    
-
-             // non triplanar
-                    texSlotCoords = texCoord * m_AlbedoMap_$i_scale;
-
-                    tempAlbedo =  texture2DArray(m_AlbedoTextureArray, vec3(texSlotCoords, m_AlbedoMap_$i));
-
-                    #ifdef NORMALMAP_$i
-                        packedNormalParallaxVec = texture2DArray(m_NormalParallaxTextureArray, vec3(texSlotCoords,  m_NormalMap_$i));
-                        tempNormal.xyz = calculateTangentsAndApplyToNormals(packedNormalParallaxVec.xyz, wNormal);
-                        tempParallax = packedNormalParallaxVec.w;
-
-                        #ifdef PARALLAXHEIGHT_0  
-                            //eventually add parallax code here if a PARALLAXHEIGHT_$i float is defined. but this shader is at the define limit currently, 
-                           // so to do that will require removing defines around scale to use that for enabling parallax  per layer instead, since there's no reason for define around basic float scale anyways
-                        #endif
-                    #else
-                        tempNormal.rgb = wNormal.rgb;
-                    #endif
-
-                    #ifdef METALLICROUGHNESSMAP_$i
-                        packedMetallicRoughnessAoEiVec = texture2DArray(m_MetallicRoughnessAoEiTextureArray, vec3(texSlotCoords, m_MetallicRoughnessMap_$i));
-                        tempRoughness = packedMetallicRoughnessAoEiVec.g * m_Roughness_$i;
-                        tempMetallic = packedMetallicRoughnessAoEiVec.b * m_Metallic_$i;
-                        tempAo = packedMetallicRoughnessAoEiVec.r;
-                        tempEmissiveIntensity = packedMetallicRoughnessAoEiVec.a;        
-                    #endif
-                #endif        
-
-
-                //blend to float values if no texture value for mrao map exists
-                #if !defined(METALLICROUGHNESSMAP_$i)
-                    tempRoughness =  m_Roughness_$i;
-                    tempMetallic =  m_Metallic_$i;
-                    tempAo = 1.0;
-                #endif
-
-              //note: most of these functions can be found in AfflictionLib.glslib
-                tempAlbedo.rgb = alterLiveliness(tempAlbedo.rgb, livelinessValue, afflictionMode); //changes saturation of albedo for this layer; does nothing if not using AfflictionAlphaMap for affliction splatting        
-
-                tempEmissiveColor *= tempEmissiveIntensity;
-
-             //mix values from this index layer to final output values based on finalAlphaBlendForLayer 
-                albedo.rgb = mix(albedo.rgb, tempAlbedo.rgb , finalAlphaBlendForLayer);        
-                normal.rgb = mix(normal.rgb, tempNormal.rgb, finalAlphaBlendForLayer);        
-                Metallic = mix(Metallic, tempMetallic, finalAlphaBlendForLayer);
-                Roughness = mix(Roughness, tempRoughness, finalAlphaBlendForLayer);
-                packedAoValue = mix(packedAoValue, tempAo, finalAlphaBlendForLayer);
-                emissiveIntensity = mix(emissiveIntensity, tempEmissiveIntensity, finalAlphaBlendForLayer);
-                emissive = mix(emissive, tempEmissiveColor, finalAlphaBlendForLayer);
-
-            #endfor         
-        #else
-            albedo = texture2D(m_AlbedoMap_0, texCoord);
+        #else 
+          //non tri-planar:
+        
+            PBRTerrainUtils_readAlbedoTexArray(ALBEDOMAP_$i, m_AlbedoMap_$i_scale, m_AlbedoTextureArray, terrainTextureLayer_$i);        
+            #ifdef NORMALMAP_$i
+                PBRTerrainUtils_readNormalTexArray(NORMALMAP_$i, m_AlbedoMap_$i_scale, m_NormalParallaxTextureArray, terrainTextureLayer_$i);
+            #endif
+            #ifdef METALLICROUGHNESSMAP_$i
+                PBRTerrainUtils_readMetallicRoughnessAoEiTexArray(METALLICROUGHNESSMAP_$i, m_AlbedoMap_$i_scale, m_MetallicRoughnessAoEiTextureArray, terrainTextureLayer_$i);
+            #endif       
+        #endif    
+        
+        //CUSTOM LIB EXAMPLE: uses a custom alpha map to desaturate albedo color for a color-removal effect
+        #ifdef AFFLICTIONTEXTURE
+            afflictionMode = m_AfflictionMode_$i;     
+            terrainTextureLayer_$i.albedo.rgb = alterLiveliness(terrainTextureLayer_$i.albedo.rgb, livelinessValue, afflictionMode); //changes saturation of albedo for this layer; does nothing if not using AfflictionAlphaMap for affliction splatting     
         #endif
-    #endif
 
-    float alpha = albedo.a;
+        //blends this layer
+        PBRTerrainUtils_blendPBRTerrainLayer(surface, terrainTextureLayer_$i);
+    #endfor                     
+    
     #ifdef DISCARD_ALPHA
-        if(alpha < m_AlphaDiscardThreshold){
+        if(surface.alpha < m_AlphaDiscardThreshold){
             discard;
         }
-    #endif       
-
-    //APPLY AFFLICTIONN TO THE PIXEL
-    #ifdef AFFLICTIONTEXTURE
-        vec4 afflictionAlbedo;    
-
-
-        float newAfflictionScale = m_AfflictionSplatScale; 
-        vec2 newScaledCoords;
-
-
-        #ifdef AFFLICTIONALBEDOMAP
-            #ifdef TRI_PLANAR_MAPPING
-                newAfflictionScale = newAfflictionScale / 256;
-                afflictionAlbedo = getTriPlanarBlend(wVertex, blending, m_SplatAlbedoMap , newAfflictionScale);
-            #else
-                newScaledCoords = mod(wPosition.xz / m_AfflictionSplatScale, 0.985);
-                afflictionAlbedo = texture2D(m_SplatAlbedoMap , newScaledCoords);
-            #endif
-
-        #else
-            afflictionAlbedo = vec4(1.0, 1.0, 1.0, 1.0);
-        #endif
-
-        vec3 afflictionNormal;
-        #ifdef AFFLICTIONNORMALMAP
-            #ifdef TRI_PLANAR_MAPPING
-
-                afflictionNormal = getTriPlanarBlend(wVertex, blending, m_SplatNormalMap , newAfflictionScale).rgb;
-
-            #else
-                afflictionNormal = texture2D(m_SplatNormalMap , newScaledCoords).rgb;
-            #endif
-
-        #else
-            afflictionNormal = norm; 
-
-        #endif
-        float afflictionMetallic = m_AfflictionMetallicValue;
-        float afflictionRoughness = m_AfflictionRoughnessValue;
-        float afflictionAo = 1.0;
-
-
-        vec4 afflictionEmissive = m_AfflictionEmissiveColor;
-        float afflictionEmissiveIntensity = m_AfflictionEmissiveValue;
-
-        #ifdef AFFLICTIONROUGHNESSMETALLICMAP    
-            vec4 metallicRoughnessAoEiVec;
-            #ifdef TRI_PLANAR_MAPPING
-                metallicRoughnessAoEiVec = texture2D(m_SplatRoughnessMetallicMap, newScaledCoords);
-            #else
-                metallicRoughnessAoEiVec = getTriPlanarBlend(wVertex, blending, m_SplatRoughnessMetallicMap, newAfflictionScale);
-            #endif
+    #endif   
 
-            afflictionRoughness *= metallicRoughnessAoEiVec.g;
-            afflictionMetallic *= metallicRoughnessAoEiVec.b;
-            afflictionAo = metallicRoughnessAoEiVec.r;
-            afflictionEmissiveIntensity *= metallicRoughnessAoEiVec.a; //important not to leave this channel all black by accident when creating the mraoei map if using affliction emissiveness    
+    PBRLightingUtils_readSunLightExposureParams(surface);
 
-        #endif
-
-        #ifdef AFFLICTIONEMISSIVEMAP
-            vec4 emissiveMapColor;
-            #ifdef TRI_PLANAR_MAPPING
-                emissiveMapColor = texture2D(m_SplatEmissiveMap, newScaledCoords);
-            #else
-                emissiveMapColor = getTriPlanarBlend(wVertex, blending, m_SplatEmissiveMap, newAfflictionScale);
-            #endif
-            afflictionEmissive *= emissiveMapColor;
-        #endif
-
-        float adjustedAfflictionValue = afflictionValue;
-        #ifdef USE_SPLAT_NOISE
-            noiseHash = getStaticNoiseVar0(wPosition, afflictionValue * m_SplatNoiseVar); //VERY IMPORTANT to replace this with a noiseMap texture, as calculating noise per pixel in-shader like this does lower framerate a lot
-
-            adjustedAfflictionValue = getAdjustedAfflictionVar(afflictionValue);
-            if(afflictionValue >= 0.99){
-                adjustedAfflictionValue = afflictionValue;
-            }
-        #else
-            noiseHash = 1.0;
-        #endif           
-
-        Roughness = alterAfflictionRoughness(adjustedAfflictionValue, Roughness, afflictionRoughness, noiseHash);
-        Metallic = alterAfflictionMetallic(adjustedAfflictionValue, Metallic,  afflictionMetallic, noiseHash);
-        albedo = alterAfflictionColor(adjustedAfflictionValue, albedo, afflictionAlbedo, noiseHash );
-        normal = alterAfflictionNormalsForTerrain(adjustedAfflictionValue, normal, afflictionNormal, noiseHash , wNormal);
-        emissive = alterAfflictionGlow(adjustedAfflictionValue, emissive, afflictionEmissive, noiseHash);
-        emissiveIntensity = alterAfflictionEmissiveIntensity(adjustedAfflictionValue, emissiveIntensity, afflictionEmissiveIntensity, noiseHash);
-        emissiveIntensity *= afflictionEmissive.a;
-        //affliction ao value blended below after specular calculation
-        
-    #endif
-
-    // spec gloss pipeline code would go here if supported, but likely will not be for terrain shaders as defines are limited and heavily used
-
-    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);
-
-    gl_FragColor.rgb = vec3(0.0);
- 
-//simple ao calculation, no support for lightmaps like stock pbr shader.. (probably could add lightmap support with another texture array, but
-//                                                                         that would add another texture read per slot and require removing 12 other defines to make room...)
-    vec3 ao = vec3(packedAoValue);
-    
+    //CUSTOM LIB EXAMPLE: uses a custom alpha map and noise to blend an extra splat layer overtop of all other layers
     #ifdef AFFLICTIONTEXTURE
-        ao = alterAfflictionAo(afflictionValue, ao, vec3(afflictionAo), noiseHash); // alter the AO map for affliction values
+        AfflictionLib_blendSplatLayers(surface);
     #endif
-    ao.rgb = ao.rrr;
-    specularColor.rgb *= ao;
- 
- 
-  
-    #ifdef STATIC_SUN_INTENSITY
-        indoorSunLightExposure = m_StaticSunIntensity; //single float value to indicate percentage of
-                           //sunlight hitting the model (only works for small models or models with 100% consistent sunlighting accross every pixel)
-    #endif
-    #ifdef USE_VERTEX_COLORS_AS_SUN_INTENSITY
-        indoorSunLightExposure = vertColors.r * indoorSunLightExposure;      //use R channel of vertexColors for..       
-    #endif 
-                                                               // similar purpose as above...
-                                                             //but uses r channel vert colors like an AO map specifically
-                                                                 //for sunlight (solution for scaling lighting for indoor
-                                                                  // and shadey/dimly lit models, especially big ones with)
-    brightestPointLight = 0.0;
-    
-     
-    float ndotv = max( dot( normal, viewDir ),0.0);
-    #ifdef SPECULAR_AA
-        float sigma = 1.0;
-        float kappa = 0.18;
-        #ifdef SPECULAR_AA_SCREEN_SPACE_VARIANCE
-            sigma = m_SpecularAASigma;
-        #endif
-        #ifdef SPECULAR_AA_THRESHOLD
-            kappa = m_SpecularAAKappa;
-        #endif
-    #endif
-    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;
-        
-        #ifdef SPECULAR_AA
-            float hdotv = PBR_ComputeDirectLightWithSpecularAA(
-                                normal, lightDir.xyz, viewDir,
-                                lightColor.rgb, fZero, Roughness, sigma, kappa, ndotv,
-                                directDiffuse,  directSpecular);
-        #else
-            float hdotv = PBR_ComputeDirectLight(
-                                normal, lightDir.xyz, viewDir,
-                                lightColor.rgb, fZero, Roughness, ndotv,
-                                directDiffuse,  directSpecular);
-        #endif
-
-        vec3 directLighting = diffuseColor.rgb *directDiffuse + directSpecular;
-            
-        #if defined(USE_VERTEX_COLORS_AS_SUN_INTENSITY) || defined(STATIC_SUN_INTENSITY)
-           if(fallOff == 1.0){
-                directLighting.rgb *= indoorSunLightExposure;// ... *^. to scale down how intense just the sun is (ambient and direct light are 1.0 fallOff)
-                
-            }
-            else{
-                    brightestPointLight = max(fallOff, brightestPointLight);
-          
-           }
-
-       #endif        
-        
-        gl_FragColor.rgb += directLighting * fallOff;             
-    }
-        
-    float minVertLighting;
-    #ifdef BRIGHTEN_INDOOR_SHADOWS
-        minVertLighting = 0.0833; //brighten shadows so that caves which are naturally covered from the DL shadows are not way too dark compared to when shadows are off (mostly only necessary for naturally dark scenes, or dark areas when using the sun intensity code above)
-    #else
-        minVertLighting = 0.0533;
-    
-    #endif
-    
-    indoorSunLightExposure = max(indoorSunLightExposure, brightestPointLight);   
-    indoorSunLightExposure = max(indoorSunLightExposure, minVertLighting);       //scale the indoorSunLightExposure back up to account for the brightest point light nearby before scaling light probes by this value below   
-    
-    #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
-
-        #ifdef USE_AMBIENT_LIGHT
-            color1.rgb *= g_AmbientLightColor.rgb;
-            color2.rgb *= g_AmbientLightColor.rgb;
-            color3.rgb *= g_AmbientLightColor.rgb;
-        #endif
-        
-// multiply probes by the indoorSunLightExposure, as determined by pixel's  sunlightExposure and adjusted for 
-// nearby point/spot lights ( will be multiplied by 1.0 and left unchanged if you are not defining any of the sunlight exposure variables for dimming indoors areas)
-        color1.rgb *= indoorSunLightExposure;
-        color2.rgb *= indoorSunLightExposure;
-        color3.rgb *= indoorSunLightExposure;
-        
-        
-        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
+   //Calculate necessary variables in pbr surface prior to applying lighting. Ensure all texture/param reading and blending occurrs prior to this being called!
+    PBRLightingUtils_calculatePreLightingValues(surface);
     
-    if(emissive.a > 0){    
-        emissive = emissive * pow(emissive.a * 5, emissiveIntensity) * emissiveIntensity * 20 * emissive.a;    
-    }
-  //  emissive = emissive * pow(emissiveIntensity * 2.3, emissive.a);
-
-    gl_FragColor += emissive;
-   
-     // add fog after the lighting because shadows will cause the fog to darken
-    // which just results in the geometry looking like it's changed color
+    // Calculate direct lights
+    for(int i = 0;i < NB_LIGHTS; i+=3){
+        vec4 lightData0 = g_LightData[i];
+        vec4 lightData1 = g_LightData[i+1];
+        vec4 lightData2 = g_LightData[i+2];    
+        PBRLightingUtils_computeDirectLightContribution(
+          lightData0, lightData1, lightData2, 
+          surface
+        );
+    }    
+
+    // Calculate env probes
+    PBRLightingUtils_computeProbesContribution(surface);
+
+    // Put it all together
+    gl_FragColor.rgb = vec3(0.0);
+    gl_FragColor.rgb += surface.bakedLightContribution;
+    gl_FragColor.rgb += surface.directLightContribution;
+    gl_FragColor.rgb += surface.envLightContribution;
+    gl_FragColor.rgb += surface.emission;
+    gl_FragColor.a = surface.alpha;      
+  
     #ifdef USE_FOG
-        #ifdef FOG_LINEAR
-            gl_FragColor = getFogLinear(gl_FragColor, m_FogColor, m_LinearFog.x, m_LinearFog.y, fogDistance);
-        #endif
-        #ifdef FOG_EXP
-            gl_FragColor = getFogExp(gl_FragColor, m_FogColor, m_ExpFog, fogDistance);
-        #endif
-        #ifdef FOG_EXPSQ
-            gl_FragColor = getFogExpSquare(gl_FragColor, m_FogColor, m_ExpSqFog, fogDistance);
-        #endif
-    #endif 
+        gl_FragColor = MaterialFog_calculateFogColor(vec4(gl_FragColor));
+    #endif
     
-    //outputs the final value of the selected layer as a color for debug purposes. 
+   //outputs the final value of the selected layer as a color for debug purposes. 
     #ifdef DEBUG_VALUES_MODE
-        if(m_DebugValuesMode == 0){
-            gl_FragColor.rgb = vec3(albedo);
-        }
-        else if(m_DebugValuesMode == 1){
-            gl_FragColor.rgb = vec3(normal);
-        }
-        else if(m_DebugValuesMode == 2){
-            gl_FragColor.rgb = vec3(Roughness);
-        }
-        else if(m_DebugValuesMode == 3){
-            gl_FragColor.rgb = vec3(Metallic);
-        }
-        else if(m_DebugValuesMode == 4){
-            gl_FragColor.rgb = ao.rgb;
-        }
-        else if(m_DebugValuesMode == 5){
-            gl_FragColor.rgb = vec3(emissive.rgb);     
-        }        
+        gl_FragColor = PBRLightingUtils_getColorOutputForDebugMode(m_DebugValuesMode, vec4(gl_FragColor.rgba), surface);
     #endif
-    
-    gl_FragColor.a = albedo.a;
-
 }

+ 69 - 36
jme3-terrain/src/main/resources/Common/MatDefs/Terrain/AdvancedPBRTerrain.j3md

@@ -1,22 +1,27 @@
-// NOTE: Doesn't support OpenGL1
-MaterialDef Advanced PBR Terrain {
+MaterialDef AdvancedPBRTerrain {
 
     MaterialParameters {
         Int BoundDrawBuffer
 
-    
+        Texture2D SunLightExposureMap
         Boolean UseVertexColorsAsSunIntensity //set true to make the vertex color's R channel how exposed a vertex is to the sun
         Float StaticSunIntensity              //used for setting the sun exposure value for a whole material
                                              //these are usually generated at run time or setup in a level editor per-geometry, so that models indoors can have the DirectionalLight dimmed accordingly.
 
         Boolean BrightenIndoorShadows  //set true if shadows are enabled and indoor areas without full sun exposure are too dark compared to when shadows are turned off in settings
 
+        Boolean UseFirstLayerAsTransparency
   
         TextureArray AlbedoTextureArray
         TextureArray NormalParallaxTextureArray -LINEAR
         TextureArray MetallicRoughnessAoEiTextureArray -LINEAR
 
-
+       // Specular-AA
+        Boolean UseSpecularAA : true
+        // screen space variance,Use the slider to set the strength of the geometric specular anti-aliasing effect between 0 and 1. Higher values produce a blurrier result with less aliasing.
+        Float SpecularAASigma
+        // clamping threshold,Use the slider to set a maximum value for the offset that HDRP subtracts from the smoothness value to reduce artifacts.
+        Float SpecularAAKappa
 
         Int AfflictionSplatScale : 8
         Float AfflictionRoughnessValue : 1.0
@@ -27,13 +32,6 @@ MaterialDef Advanced PBR Terrain {
      // affliction texture splatting & desaturation functionality
         Boolean UseTriplanarAfflictionMapping
 
-        // Specular-AA
-        Boolean UseSpecularAA : true
-        // screen space variance,Use the slider to set the strength of the geometric specular anti-aliasing effect between 0 and 1. Higher values produce a blurrier result with less aliasing.
-        Float SpecularAASigma
-        // clamping threshold,Use the slider to set a maximum value for the offset that HDRP subtracts from the smoothness value to reduce artifacts.
-        Float SpecularAAKappa
-
         Texture2D AfflictionAlphaMap
 
         Texture2D SplatAlbedoMap  -LINEAR
@@ -125,6 +123,19 @@ MaterialDef Advanced PBR Terrain {
         Float AlbedoMap_10_scale : 1
         Float AlbedoMap_11_scale : 1
 
+        Boolean UseTriPlanarMapping_0
+        Boolean UseTriPlanarMapping_1
+        Boolean UseTriPlanarMapping_2
+        Boolean UseTriPlanarMapping_3
+        Boolean UseTriPlanarMapping_4
+        Boolean UseTriPlanarMapping_5
+        Boolean UseTriPlanarMapping_6
+        Boolean UseTriPlanarMapping_7
+        Boolean UseTriPlanarMapping_8
+        Boolean UseTriPlanarMapping_9
+        Boolean UseTriPlanarMapping_10
+        Boolean UseTriPlanarMapping_11
+
 
         Int NormalMap_0
         Int NormalMap_1
@@ -169,17 +180,21 @@ MaterialDef Advanced PBR Terrain {
 
 
 
-        // debug the final value of the selected layer as a color output            
-        Int DebugValuesMode
+        //used in order to convert world coords to tex coords so afflictionTexture accurately represents the world in cases where terrain is not scaled at a 1,1,1 value
+        Float TileWidth : 0
+        Vector3 TileLocation
 
+ // debug the final value of the selected layer as a color output            
+        Int DebugValuesMode
             // Layers:
-            //   0 - albedo (un-shaded)
+            //   0 - albedo (unshaded)
             //   1 - normals
             //   2 - roughness
             //   3 - metallic
             //   4 - ao
-            //   5  - emissive
-
+            //   5 - emissive
+            //   6 - exposure
+            //   7 - alpha
 
         // use tri-planar mapping
         Boolean useTriPlanarMapping
@@ -279,6 +294,27 @@ MaterialDef Advanced PBR Terrain {
 
         Defines {
             BOUND_DRAW_BUFFER: BoundDrawBuffer
+
+            USE_FOG : UseFog
+            FOG_LINEAR : LinearFog
+            FOG_EXP : ExpFog
+            FOG_EXPSQ : ExpSqFog
+
+            EXPOSUREMAP : SunLightExposureMap
+            USE_VERTEX_COLORS_AS_SUN_EXPOSURE : UseVertexColorsAsSunIntensity
+            STATIC_SUN_EXPOSURE : StaticSunIntensity
+            BRIGHTEN_INDOOR_SHADOWS : BrightenIndoorShadows
+
+            USE_FIRST_LAYER_AS_TRANSPARENCY : UseFirstLayerAsTransparency
+
+            SPECULAR_AA : UseSpecularAA
+            SPECULAR_AA_SCREEN_SPACE_VARIANCE : SpecularAASigma
+            SPECULAR_AA_THRESHOLD : SpecularAAKappa
+
+            DISCARD_ALPHA : AlphaDiscardThreshold
+
+            TILELOCATION : TileLocation
+            AFFLICTIONTEXTURE : AfflictionAlphaMap
                 
             AFFLICTIONTEXTURE : AfflictionAlphaMap
             AFFLICTIONALBEDOMAP: SplatAlbedoMap 
@@ -287,23 +323,12 @@ MaterialDef Advanced PBR Terrain {
             AFFLICTIONEMISSIVEMAP : SplatEmissiveMap
             USE_SPLAT_NOISE : SplatNoiseVar
 
-            SPECULAR_AA : UseSpecularAA
-            SPECULAR_AA_SCREEN_SPACE_VARIANCE : SpecularAASigma
-            SPECULAR_AA_THRESHOLD : SpecularAAKappa
-
             TRI_PLANAR_MAPPING : useTriPlanarMapping
 
-            DISCARD_ALPHA : AlphaDiscardThreshold
-
             ALPHAMAP : AlphaMap
             ALPHAMAP_1 : AlphaMap_1
             ALPHAMAP_2 : AlphaMap_2
 
-            USE_FOG : UseFog
-            FOG_LINEAR : LinearFog
-            FOG_EXP : ExpFog
-            FOG_EXPSQ : ExpSqFog
-
             ALBEDOMAP_0 : AlbedoMap_0
             ALBEDOMAP_1 : AlbedoMap_1
             ALBEDOMAP_2 : AlbedoMap_2
@@ -343,9 +368,20 @@ MaterialDef Advanced PBR Terrain {
             METALLICROUGHNESSMAP_10 : MetallicRoughnessMap_10
             METALLICROUGHNESSMAP_11 : MetallicRoughnessMap_11
 
-            DEBUG_VALUES_MODE : DebugValuesMode
-
+            TRI_PLANAR_MAPPING_0 : UseTriPlanarMapping_0
+            TRI_PLANAR_MAPPING_1 : UseTriPlanarMapping_1
+            TRI_PLANAR_MAPPING_2 : UseTriPlanarMapping_2
+            TRI_PLANAR_MAPPING_3 : UseTriPlanarMapping_3
+            TRI_PLANAR_MAPPING_4 : UseTriPlanarMapping_4
+            TRI_PLANAR_MAPPING_5 : UseTriPlanarMapping_5
+            TRI_PLANAR_MAPPING_6 : UseTriPlanarMapping_6
+            TRI_PLANAR_MAPPING_7 : UseTriPlanarMapping_7
+            TRI_PLANAR_MAPPING_8 : UseTriPlanarMapping_8
+            TRI_PLANAR_MAPPING_9 : UseTriPlanarMapping_9
+            TRI_PLANAR_MAPPING_10 : UseTriPlanarMapping_10
+            TRI_PLANAR_MAPPING_11 : UseTriPlanarMapping_11
 
+            DEBUG_VALUES_MODE : DebugValuesMode
 
         }
     }
@@ -353,8 +389,8 @@ MaterialDef Advanced PBR Terrain {
 
     Technique PreShadow {
 
-        VertexShader   GLSL300 GLSL150 GLSL100:   Common/MatDefs/Shadow/PreShadow.vert
-        FragmentShader GLSL300 GLSL150 GLSL100: Common/MatDefs/Shadow/PreShadow.frag
+        VertexShader GLSL300 GLSL150 GLSL100 :   Common/MatDefs/Shadow/PreShadow.vert
+        FragmentShader GLSL300 GLSL150 GLSL100 : Common/MatDefs/Shadow/PreShadow.frag
 
         WorldParameters {
             WorldViewProjectionMatrix
@@ -382,8 +418,8 @@ MaterialDef Advanced PBR Terrain {
 
 
     Technique PostShadow{
-        VertexShader    GLSL300 GLSL150 GLSL100:   Common/MatDefs/Shadow/PostShadow.vert
-        FragmentShader  GLSL300 GLSL150 GLSL100: Common/MatDefs/Shadow/PostShadow.frag
+        VertexShader GLSL300 GLSL150 GLSL100:   Common/MatDefs/Shadow/PostShadow.vert
+        FragmentShader GLSL300 GLSL150 GLSL100: Common/MatDefs/Shadow/PostShadow.frag
 
         WorldParameters {
             WorldViewProjectionMatrix
@@ -413,7 +449,4 @@ MaterialDef Advanced PBR Terrain {
             PolyOffset -0.1 0  
         }
     }
-    
-
-    
 }

+ 0 - 343
jme3-terrain/src/main/resources/Common/MatDefs/Terrain/AfflictionLib.glsllib

@@ -1,343 +0,0 @@
-#import "Common/ShaderLib/NoiseLib.glsllib"
-
-//code for tri-planar mapping on any afflicted shaders
-vec4 getTriPlanarBlend(in vec4 coords, in vec3 blending, in sampler2D map, in float scale) {
-      vec4 col1 = texture2D( map, coords.yz * scale);
-      vec4 col2 = texture2D( map, coords.xz * scale);
-      vec4 col3 = texture2D( map, coords.xy * scale); 
-      // blend the results of the 3 planar projections.
-      vec4 tex = col1 * blending.x + col2 * blending.y + col3 * blending.z;
-      
-      return tex;
-}
-
-vec4 getTriPlanarBlendFromTexArray(in vec4 coords, in vec3 blending, in int idInTexArray, in float scale, in sampler2DArray texArray) {
-      vec4 col1 = texture2DArray( texArray, vec3((coords.yz * scale), idInTexArray ) );
-      vec4 col2 = texture2DArray( texArray, vec3((coords.xz * scale), idInTexArray ) );
-      vec4 col3 = texture2DArray( texArray, vec3((coords.xy * scale), idInTexArray ) );
-      // blend the results of the 3 planar projections.
-      vec4 tex = col1 * blending.x + col2 * blending.y + col3 * blending.z;
-      
-      return tex;
-}
-
-
-//used for mixing normal map normals with the world normals. texture slots without a normal map use wNormal as their blending value instead
-vec3 calculateTangentsAndApplyToNormals(in vec3 normalIn, in vec3 worldNorm){
-    
-    
-    vec3 returnNorm = normalize((normalIn.xyz * vec3(2.0) - vec3(1.0)));
-     
-    
-        vec3 baseNorm = worldNorm.rgb + vec3(0, 0, 1);
-        returnNorm *= vec3(-1, -1, 1);
-        returnNorm = baseNorm.rgb*dot(baseNorm.rgb, returnNorm.rgb)/baseNorm.z - returnNorm.rgb;
-
-        returnNorm = normalize(returnNorm);
-        
-
-        return returnNorm;
-}
-
-
-vec4 desaturate(vec4 albedo, float deathVar){
-        
-    vec3 gray = vec3(dot(vec3(0.2126,0.7152,0.0722), albedo.rgb));
-    albedo = vec4(mix(albedo.rgb, gray, deathVar), 0.0);
-
-    return albedo;
-}
-
-//methods for terrains
-    vec3 alterLiveliness(vec3 color, float liveVal, int mode){
-
-            float deathVar = (1.0 - (liveVal));
-
-//0 means dont scale to be desaturated (bricks, stones, etc)
-            if(mode > 0){ //1 means almost fully desaturated.. 1 is less alive, and 2 is slightly less, etc etc
-                deathVar -= mode * 0.033;
-
-                deathVar = max(0.0, deathVar);
-                deathVar = min(0.99, deathVar);
-
-                float hueVar = (deathVar) * 0.34;
-                color.r += color.r*hueVar * 1.8;
-                color.g -= color.g*hueVar;
-                color.b -= color.b*hueVar*5.0 ;
-
-
-                color = desaturate(vec4(color, 1.0), deathVar).rgb;
-                
-            }
-
-          
-   
-        return color;
-        
-    }
-
-
-    vec3 alterLiveliness(vec3 color, float livelinessValue){
-    //change hue
-
-        float deathVar = (1.0 - (livelinessValue));
-
-        float hueVar = (deathVar) * 0.34;
-        color.r += color.r*hueVar * 1.8;
-        color.g -= color.g*hueVar;
-        color.b -= color.b*hueVar*5.0 ;
-
-
-       color = desaturate(vec4(color, 1.0), deathVar).rgb;
-
-
-        return color;
-    }
-
-
-//methods for death and afflictionness applied to all other types of affliction shaders
-
-
-vec4 alterBarkLiveliness(vec4 albedo, float livelinessValue){
-    float deathVar = 1.0 - livelinessValue;
-
-    float hueVar = (deathVar) * 0.97;
-    albedo.r += albedo.r*hueVar * 0.21;
-    albedo.g += albedo.g*hueVar*0.84;
-    albedo.b -= albedo.b*hueVar*1.9;
-
-    albedo *= 0.1 + (0.9 * livelinessValue);
-
-    return albedo;
-}
-
-vec4 alterPlantLiveliness(vec4 albedo, float livelinessValue){
-    float deathVar = 1.0 - livelinessValue;
-
-    float hueVar = (deathVar) * 0.77;
-    albedo.r += albedo.r*hueVar * 1.8;
-    albedo.g -= albedo.g*hueVar;
-    albedo.b -= albedo.b*hueVar*5.0 ;
-
-    return albedo;
-}
-
-vec4 alterStoneLiveliness(vec4 albedo, float livelinessValue){
-    livelinessValue = 0.56 + (0.44 * livelinessValue); //stone and rock has an 80% minimum, and scales up from there
-
-    float deathVar = 1.0 - livelinessValue;
-    
-
-    float hueVar = (deathVar);
-    albedo.r += albedo.r*hueVar * 1.2;
-    albedo.g += albedo.g*hueVar;
-    albedo.b -= albedo.b*hueVar*3.14 ;
-
-    albedo = desaturate(albedo, deathVar * 1.7);
-
-    
-
-    return albedo;
-}
-
-
-
-//AFFLICTION METHODS
-
-//adjusts the affliction value for the best visual representation (since 0.0 - 1.0 is not as visually linear as it is numerically)
-float getAdjustedAfflictionVar(float afflictionVar){
-
-    float adjustedVar = afflictionVar;
-        if(afflictionVar > 0.02){
-            adjustedVar = mix(0.02, 0.53, afflictionVar);
-        }
-        else{
-            adjustedVar = 0;
-        }
-   
-    return adjustedVar;
-}
-
-float getAfflictionEdgeTaper(float noiseVar, float afflictionVar){
-
-    float amt = noiseVar - (0.4 * afflictionVar) - .04;
-
-    if(amt <= 0.05){
-        amt = 0.05;
-    }
-    
-
-    return amt;
-}
-
-vec4 alterAfflictionColor(float afflictionVar, vec4 albedo, vec4 afflictionAlbedo, float noiseVar){    
-
-         
-    float edgeTaper = getAfflictionEdgeTaper(noiseVar, afflictionVar);  
-
-    if(afflictionVar >= noiseVar){
-        float albedoOpacity = min((afflictionVar * 0.2) + 0.8 , 1.0);
-        albedo.rgba = mix(albedo.rgba, afflictionAlbedo.rgba, albedoOpacity);
-    }
-    else if(afflictionVar > edgeTaper){
-        float edgeDiff = noiseVar - afflictionVar;
-        edgeDiff = edgeDiff / afflictionVar;
-
-
-        albedo.rgba = mix(afflictionAlbedo.rgba, albedo.rgba, edgeDiff);
-    }
-   else{
-        
-        albedo.rgba = mix(albedo.rgba, afflictionAlbedo.rgba, afflictionVar);
-    }
-    
-
-    return albedo;
-}
-vec4 alterAfflictionGlow(float afflictionVar, vec4 emissive, vec4 afflictionGlowColor, float noiseVar){    
-    
-     
-    emissive = mix(emissive, afflictionGlowColor, afflictionVar);
-
-    return emissive;
-}
-
-float alterAfflictionEmissiveIntensity(float afflictionVar, float emissiveIntensity, float afflictionEmissiveIntensity, float noiseVar){
-   
-   
-   emissiveIntensity = mix(emissiveIntensity, afflictionEmissiveIntensity, afflictionVar);
-
-    return emissiveIntensity;
-}
-
-vec3 alterAfflictionNormals(float afflictionVar, vec3 normal, vec3 afflictionNormal, float noiseVar){
-
-    vec3 originalNorm = normal;
-    
-    float edgeTaper = getAfflictionEdgeTaper(noiseVar, afflictionVar);      
-
-    if(afflictionVar >= noiseVar){
-        normal = afflictionNormal;
-    }
-    else if(afflictionVar > edgeTaper){
-        float edgeDiff = noiseVar - afflictionVar;
-        edgeDiff = edgeDiff / afflictionVar;
-         normal = mix(afflictionNormal, normal, edgeDiff);
-    }
-    else{
-        normal = mix(normal, afflictionNormal,  afflictionVar);
-    }
-
-    
-    return normalize(normal);
-}
-
-vec3 alterAfflictionNormalsForTerrain(float afflictionVar, vec3 normal, vec3 afflictionNormal, float noiseVar, vec3 worldNorm){
-     
-
-    float edgeTaper = getAfflictionEdgeTaper(noiseVar, afflictionVar);  
-    
-    
-    vec3 blendedNormal = normal;
-    
-    float blendValue = afflictionVar;
-    
-    if(afflictionVar >= noiseVar){
-        blendValue = 1.0;
-    }
-    else if(afflictionVar > edgeTaper){
-        float edgeDiff = noiseVar - afflictionVar;
-        edgeDiff = edgeDiff / afflictionVar;
-        
-        blendValue = edgeDiff;
-        
-    }
-     else{
-         float blendAmt = noiseVar * afflictionVar;
-         blendAmt = max(0.0, blendAmt);
-         blendAmt = min(1.0, blendAmt);
-         
-         blendValue = blendAmt;
-         
-    }
-
-    
-    afflictionNormal = calculateTangentsAndApplyToNormals(afflictionNormal, worldNorm);
-    blendedNormal = mix(normal, afflictionNormal, blendValue);
-
-    return blendedNormal;
-}
-
-vec3 alterAfflictionAo(float afflictionVar, vec3 ao, vec3 afflictionAo, float noiseVar){
-
-
-     
-
-    float edgeTaper = getAfflictionEdgeTaper(noiseVar, afflictionVar);  
-
-    if(afflictionVar >= noiseVar){
-        ao = afflictionAo;
-    }
-    else if(afflictionVar > edgeTaper){
-        float edgeDiff = noiseVar - afflictionVar;
-        edgeDiff = edgeDiff / afflictionVar;
-
-         ao = mix(afflictionAo, ao, edgeDiff);
-    }
-    else{
-        ao = mix(ao, afflictionAo, afflictionVar);
-   }
-    
-    return ao;
-}
-
-float alterAfflictionRoughness(float afflictionVar, float originalRoughness, float afflictionRoughness, float noiseVar){
-
-
-    float edgeTaper = getAfflictionEdgeTaper(noiseVar, afflictionVar);  
-    if(afflictionVar >= noiseVar){
-        originalRoughness = afflictionRoughness;
-    }
-    else if(afflictionVar > edgeTaper){
-        float edgeDiff = noiseVar - afflictionVar;
-        edgeDiff = edgeDiff / afflictionVar;
-
-         originalRoughness = mix(afflictionRoughness, originalRoughness, edgeDiff);
-    }
-
-    
-    originalRoughness = min(originalRoughness, 1.0);
-
-
-    return originalRoughness;
-}
-
-float alterAfflictionMetallic(float afflictionVar, float originalMetallic, float afflictionMetallic, float noiseVar){
-
-
-     
-
-
-       float edgeTaper = getAfflictionEdgeTaper(noiseVar, afflictionVar);  
-    if(afflictionVar >= noiseVar){
-        originalMetallic = afflictionMetallic;
-    }
-    else if(afflictionVar > edgeTaper){
-        float edgeDiff = noiseVar - afflictionVar;
-        edgeDiff = edgeDiff / afflictionVar;
-
-         originalMetallic = mix(afflictionMetallic, originalMetallic, edgeDiff);
-    }
-
-    
-    originalMetallic = min(originalMetallic, 1.0);
-    return originalMetallic;
-}
-
-
-
-
-
-
-
-

+ 462 - 0
jme3-terrain/src/main/resources/Common/MatDefs/Terrain/Modular/AfflictionLib.glsllib

@@ -0,0 +1,462 @@
+#ifndef __AFFLICTION_LIB__
+    #define __AFFLICTION_LIB__
+    
+    #import "Common/ShaderLib/NoiseLib.glsllib"
+    #import "Common/ShaderLib/TangentUtils.glsllib"
+
+    #import "Common/ShaderLib/TriPlanarUtils.glsllib"
+
+    #ifdef AFFLICTIONTEXTURE
+        uniform sampler2D m_AfflictionAlphaMap;
+    #endif
+    #ifdef AFFLICTIONALBEDOMAP
+        uniform sampler2D m_SplatAlbedoMap;
+    #endif
+    #ifdef AFFLICTIONNORMALMAP
+        uniform sampler2D m_SplatNormalMap;
+    #endif
+    #ifdef AFFLICTIONROUGHNESSMETALLICMAP
+        uniform sampler2D m_SplatRoughnessMetallicMap;
+    #endif
+    #ifdef AFFLICTIONEMISSIVEMAP
+        uniform sampler2D m_SplatEmissiveMap;
+    #endif
+    #ifdef USE_SPLAT_NOISE
+         uniform float m_SplatNoiseVar;
+    #endif
+    
+    #ifdef TILELOCATION
+       uniform float m_TileWidth;
+       uniform vec3 m_TileLocation;
+   #endif
+
+    uniform int m_AfflictionSplatScale;
+    uniform float m_AfflictionRoughnessValue;
+    uniform float m_AfflictionMetallicValue;
+    uniform float m_AfflictionEmissiveValue;
+    uniform vec4 m_AfflictionEmissiveColor;
+
+    vec4 afflictionVector;
+    float noiseHash;
+    float livelinessValue;
+    float afflictionValue;
+    int afflictionMode = 1;
+
+    vec4 desaturate(vec4 albedo, float deathVar){
+        vec3 gray = vec3(dot(vec3(0.2126,0.7152,0.0722), albedo.rgb));
+        albedo = vec4(mix(albedo.rgb, gray, deathVar), 0.0);
+
+        return albedo;
+    }
+    vec3 alterLiveliness(vec3 color, float liveVal, int mode){
+
+        float deathVar = (1.0 - (liveVal));
+
+    //0 means dont scale to be desaturated (bricks, stones, etc)
+        if(mode > 0){ //1 means almost fully desaturated.. 1 is less alive, and 2 is slightly less, etc etc
+            deathVar -= mode * 0.033;
+
+            deathVar = max(0.0, deathVar);
+            deathVar = min(0.99, deathVar);
+
+            float hueVar = (deathVar) * 0.34;
+            color.r += color.r*hueVar * 1.8;
+            color.g -= color.g*hueVar;
+            color.b -= color.b*hueVar * 5.0 ;
+
+            color = desaturate(vec4(color, 1.0), deathVar).rgb;
+
+        }
+
+        return color;
+
+    }
+
+
+    vec3 alterLiveliness(vec3 color, float livelinessValue){
+
+        float deathVar = (1.0 - (livelinessValue));
+
+        float hueVar = (deathVar) * 0.34;
+        color.r += color.r*hueVar * 1.8;
+        color.g -= color.g*hueVar;
+        color.b -= color.b*hueVar*5.0 ;
+
+        color = desaturate(vec4(color, 1.0), deathVar).rgb;
+
+        return color;
+    }
+
+
+    //methods for death and afflictionness applied to all other types of affliction shaders
+
+
+    vec4 alterBarkLiveliness(vec4 albedo, float livelinessValue){
+        float deathVar = 1.0 - livelinessValue;
+
+        float hueVar = (deathVar) * 0.97;
+        albedo.r += albedo.r*hueVar * 0.21;
+        albedo.g += albedo.g*hueVar*0.84;
+        albedo.b -= albedo.b*hueVar*1.9;
+
+        albedo *= 0.1 + (0.9 * livelinessValue);
+
+        return albedo;
+    }
+
+    vec4 alterPlantLiveliness(vec4 albedo, float livelinessValue){
+        float deathVar = 1.0 - livelinessValue;
+
+        float hueVar = (deathVar) * 0.77;
+        albedo.r += albedo.r*hueVar * 1.8;
+        albedo.g -= albedo.g*hueVar;
+        albedo.b -= albedo.b*hueVar*5.0 ;
+
+        return albedo;
+    }
+
+    vec4 alterStoneLiveliness(vec4 albedo, float livelinessValue){
+        livelinessValue = 0.56 + (0.44 * livelinessValue); //stone and rock has an 80% minimum, and scales up from there
+
+        float deathVar = 1.0 - livelinessValue;
+
+        float hueVar = (deathVar);
+        albedo.r += albedo.r*hueVar * 1.2;
+        albedo.g += albedo.g*hueVar;
+        albedo.b -= albedo.b*hueVar*3.14 ;
+
+        albedo = desaturate(albedo, deathVar * 1.7);
+
+        return albedo;
+    }
+
+    vec3 desaturateVec(vec3 albedo, float deathVar){
+        vec3 gray = vec3(dot(vec3(0.2126,0.7152,0.0722), albedo.rgb));
+        albedo = mix(albedo, gray, deathVar);
+
+        return albedo;
+    }
+    vec3 alterStoneLivelinessVar(vec3 albedo, float livelinessValue){
+        livelinessValue = 0.56 + (0.44 * livelinessValue); //stone and rock has an 80% minimum, and scales up from there
+
+        float deathVar = 1.0 - livelinessValue;
+
+        float hueVar = (deathVar);
+        albedo.r += albedo.r*hueVar * 1.2;
+        albedo.g += albedo.g*hueVar;
+        albedo.b -= albedo.b*hueVar*3.14 ;
+
+        albedo = desaturateVec(albedo, deathVar * 1.7);
+
+        return albedo;
+    }
+
+    //AFFLICTION METHODS
+
+    //adjusts the affliction value for the best visual representation (since 0.0 - 1.0 is not as visually linear as it is numerically)
+    float getAdjustedAfflictionVar(float afflictionVar){
+        float adjustedVar = afflictionVar;
+            if(afflictionVar > 0.02){
+                adjustedVar = mix(0.02, 0.53, afflictionVar);
+            }
+            else{
+                adjustedVar = 0;
+            }
+
+        return adjustedVar;
+    }
+
+    float getAfflictionEdgeTaper(float noiseVar, float afflictionVar){
+        float amt = noiseVar - (0.4 * afflictionVar) - .04;
+
+        if(amt <= 0.05){
+            amt = 0.05;
+        }
+        return amt;
+    }
+
+    vec4 alterAfflictionColor(float afflictionVar, vec4 albedo, vec4 afflictionAlbedo, float noiseVar){    
+        float originalAlpha = albedo.a;     
+
+        float edgeTaper = getAfflictionEdgeTaper(noiseVar, afflictionVar);  
+
+        if(afflictionVar >= noiseVar){
+            float albedoOpacity = min((afflictionVar * 0.2) + 0.8 , 1.0);
+            albedo.rgba = mix(albedo.rgba, afflictionAlbedo.rgba, albedoOpacity);
+        }
+        else if(afflictionVar > edgeTaper){
+            float edgeDiff = noiseVar - afflictionVar;
+            edgeDiff = edgeDiff / afflictionVar;
+
+            albedo.rgba = mix(afflictionAlbedo.rgba, albedo.rgba, edgeDiff);
+        }
+       else{
+            albedo.rgba = mix(albedo.rgba, afflictionAlbedo.rgba, afflictionVar);
+        }
+
+        albedo.a = albedo.a * originalAlpha; //ensures alpha blending is always done based on original texture so
+                                             //avoid artifacts on edge of transparent leaves and similar materials
+
+        return albedo;
+    }
+    vec4 alterAfflictionGlow(float afflictionVar, vec4 emissive, vec4 afflictionGlowColor, float noiseVar){   
+        emissive = mix(emissive, afflictionGlowColor, afflictionVar);
+
+        return emissive;
+    }
+
+    float alterAfflictionEmissiveIntensity(float afflictionVar, float emissiveIntensity, float afflictionEmissiveIntensity, float noiseVar){
+       emissiveIntensity = mix(emissiveIntensity, afflictionEmissiveIntensity, afflictionVar);
+
+        return emissiveIntensity;
+    }
+
+    vec3 alterAfflictionNormals(float afflictionVar, vec3 normal, vec3 afflictionNormal, float noiseVar){
+        vec3 originalNorm = normal;
+
+        float edgeTaper = getAfflictionEdgeTaper(noiseVar, afflictionVar);      
+
+        if(afflictionVar >= noiseVar){
+            normal = afflictionNormal;
+        }
+        else if(afflictionVar > edgeTaper){
+            float edgeDiff = noiseVar - afflictionVar;
+            edgeDiff = edgeDiff / afflictionVar;
+            normal = mix(afflictionNormal, normal, edgeDiff);
+        }
+        else{
+            normal = mix(normal, afflictionNormal,  afflictionVar);
+        }
+
+
+        return normalize(normal);
+    }
+
+    vec3 alterAfflictionNormalsForTerrain(float afflictionVar, vec3 normal, vec3 afflictionNormal, float noiseVar, vec3 worldNorm){
+        float edgeTaper = getAfflictionEdgeTaper(noiseVar, afflictionVar);  
+        vec3 blendedNormal = normal;
+
+        float blendValue = afflictionVar;
+
+        if(afflictionVar >= noiseVar){
+            blendValue = 1.0;
+        }
+        else if(afflictionVar > edgeTaper){
+            float edgeDiff = noiseVar - afflictionVar;
+            edgeDiff = edgeDiff / afflictionVar;
+
+            blendValue = edgeDiff;
+
+        }
+         else{
+             float blendAmt = noiseVar * afflictionVar;
+             blendAmt = max(0.0, blendAmt);
+             blendAmt = min(1.0, blendAmt);
+
+             blendValue = blendAmt;
+        }
+
+        afflictionNormal = calculateTangentsAndApplyToNormals(afflictionNormal, worldNorm);
+        blendedNormal = mix(normal, afflictionNormal, blendValue);
+
+        return blendedNormal;
+    }
+
+    vec3 alterAfflictionAo(float afflictionVar, vec3 ao, vec3 afflictionAo, float noiseVar){
+
+        float edgeTaper = getAfflictionEdgeTaper(noiseVar, afflictionVar);  
+
+        if(afflictionVar >= noiseVar){
+            ao = afflictionAo;
+        }
+        else if(afflictionVar > edgeTaper){
+            float edgeDiff = noiseVar - afflictionVar;
+            edgeDiff = edgeDiff / afflictionVar;
+
+             ao = mix(afflictionAo, ao, edgeDiff);
+        }
+        else{
+            ao = mix(ao, afflictionAo, afflictionVar);
+       }
+
+        return ao;
+    }
+
+    float alterAfflictionRoughness(float afflictionVar, float originalRoughness, float afflictionRoughness, float noiseVar){
+        float edgeTaper = getAfflictionEdgeTaper(noiseVar, afflictionVar);  
+        if(afflictionVar >= noiseVar){
+            originalRoughness = afflictionRoughness;
+        }
+        else if(afflictionVar > edgeTaper){
+            float edgeDiff = noiseVar - afflictionVar;
+            edgeDiff = edgeDiff / afflictionVar;
+
+             originalRoughness = mix(afflictionRoughness, originalRoughness, edgeDiff);
+        }
+
+
+        originalRoughness = min(originalRoughness, 1.0);
+
+
+        return originalRoughness;
+    }
+
+    float alterAfflictionMetallic(float afflictionVar, float originalMetallic, float afflictionMetallic, float noiseVar){
+        float edgeTaper = getAfflictionEdgeTaper(noiseVar, afflictionVar);  
+        if(afflictionVar >= noiseVar){
+            originalMetallic = afflictionMetallic;
+        }
+        else if(afflictionVar > edgeTaper){
+            float edgeDiff = noiseVar - afflictionVar;
+            edgeDiff = edgeDiff / afflictionVar;
+
+             originalMetallic = mix(afflictionMetallic, originalMetallic, edgeDiff);
+        }
+
+
+        originalMetallic = min(originalMetallic, 1.0);
+        return originalMetallic;
+    }
+
+    #ifndef __SURFACE_MODULE__
+        #import "Common/ShaderLib/module/PBRSurface.glsl"
+    #endif
+    
+    void AfflictionLib_readAfflictionVector(){
+         #ifdef AFFLICTIONTEXTURE
+        
+            afflictionVector = vec4(1.0, 0.0, 1.0, 0.0); //r channel is saturation, g channel is affliction splat texture intensity, b and a unused (might use b channel for wetness eventually)    
+        
+            #ifdef TILELOCATION 
+            //subterrains that are not centred in tile or equal to tile width in total size need to have m_TileWidth pre-set. (tileWidth is the x,z dimesnions that the AfflictionAlphaMap represents)..
+                vec2 tileCoords;
+                float xPos, zPos;
+
+                vec3 locInTile = (wPosition - m_TileLocation);
+
+                 locInTile += vec3(m_TileWidth/2, 0, m_TileWidth/2);
+
+                 xPos = (locInTile.x / m_TileWidth);
+                 zPos = 1 - (locInTile.z / m_TileWidth);
+
+                tileCoords = vec2(xPos, zPos);
+
+                afflictionVector = texture2D(m_AfflictionAlphaMap, tileCoords).rgba;
+                
+            #else
+               // ..othrewise when terrain size matches tileWidth, the terrain's texCoords can be used for simple texel fetching of the AfflictionAlphaMap
+                afflictionVector = texture2D(m_AfflictionAlphaMap, texCoord.xy).rgba;
+            #endif
+
+            livelinessValue = afflictionVector.r;
+            afflictionValue = afflictionVector.g;
+        #endif
+        
+    }
+
+    void AfflictionLib_blendSplatLayers(inout PBRSurface surface){
+        
+        TriPlanarUtils_calculateBlending(surface.geometryNormal);
+
+        #ifdef AFFLICTIONTEXTURE     
+            vec4 afflictionAlbedo;    
+            
+            float newAfflictionScale = m_AfflictionSplatScale; 
+            vec2 newScaledCoords;
+            
+            #ifdef AFFLICTIONALBEDOMAP
+                #ifdef TRI_PLANAR_MAPPING
+                    newAfflictionScale = newAfflictionScale / 256;
+                    afflictionAlbedo = getTriPlanarBlend(lPosition, m_SplatAlbedoMap , newAfflictionScale);
+                #else
+                    newScaledCoords = mod(wPosition.xz / m_AfflictionSplatScale, 0.985);
+                    afflictionAlbedo = texture2D(m_SplatAlbedoMap , newScaledCoords);
+                #endif
+
+            #else
+                afflictionAlbedo = vec4(1.0, 1.0, 1.0, 1.0);
+            #endif
+
+            vec3 afflictionNormal;
+            #ifdef AFFLICTIONNORMALMAP
+                #ifdef TRI_PLANAR_MAPPING
+
+                    afflictionNormal = getTriPlanarBlend(lPosition, m_SplatNormalMap , newAfflictionScale).rgb;
+
+                #else
+                    afflictionNormal = texture2D(m_SplatNormalMap , newScaledCoords).rgb;
+                #endif
+                afflictionNormal = normalize((afflictionNormal * vec3(2.0,2.0, 2.0) - vec3(1.0, 1.0, 1.0)));
+                
+                if(surface.hasTangents == true){                    
+                    afflictionNormal = normalize(surface.tbnMat * afflictionNormal);
+                }
+            #else
+                afflictionNormal = surface.geometryNormal; 
+
+            #endif
+            float afflictionMetallic = m_AfflictionMetallicValue;
+            float afflictionRoughness = m_AfflictionRoughnessValue;
+            float afflictionAo = 1.0;
+
+            vec4 afflictionEmissive = m_AfflictionEmissiveColor;
+            float afflictionEmissiveIntensity = m_AfflictionEmissiveValue;
+
+            #ifdef AFFLICTIONROUGHNESSMETALLICMAP    
+                vec4 metallicRoughnessAoEiVec;
+                #ifdef TRI_PLANAR_MAPPING
+                    metallicRoughnessAoEiVec = texture2D(m_SplatRoughnessMetallicMap, newScaledCoords);
+                #else
+                    metallicRoughnessAoEiVec = getTriPlanarBlend(lPosition, m_SplatRoughnessMetallicMap, newAfflictionScale);
+                #endif
+
+                afflictionRoughness *= metallicRoughnessAoEiVec.g;
+                afflictionMetallic *= metallicRoughnessAoEiVec.b;
+                afflictionAo = metallicRoughnessAoEiVec.r;
+                afflictionEmissiveIntensity *= metallicRoughnessAoEiVec.a; //important not to leave this channel all black by accident when creating the mraoei map if using affliction emissiveness    
+
+            #endif
+
+            #ifdef AFFLICTIONEMISSIVEMAP
+                vec4 emissiveMapColor;
+                #ifdef TRI_PLANAR_MAPPING
+                    emissiveMapColor = texture2D(m_SplatEmissiveMap, newScaledCoords);
+                #else
+                    emissiveMapColor = getTriPlanarBlend(lPosition, m_SplatEmissiveMap, newAfflictionScale);
+                #endif
+                afflictionEmissive *= emissiveMapColor;
+            #endif
+
+            float adjustedAfflictionValue = afflictionValue;
+            #ifdef USE_SPLAT_NOISE
+                noiseHash = getStaticNoiseVar0(wPosition, afflictionValue * m_SplatNoiseVar); //VERY IMPORTANT to replace this with a noiseMap texture, as calculating noise per pixel in-shader like this does lower framerate a lot
+
+                adjustedAfflictionValue = getAdjustedAfflictionVar(afflictionValue);
+                if(afflictionValue >= 0.99){
+                    adjustedAfflictionValue = afflictionValue;
+                }
+            #else
+                noiseHash = 1.0;
+            #endif           
+
+            surface.roughness = alterAfflictionRoughness(afflictionValue, surface.roughness, afflictionRoughness, noiseHash);
+            surface.metallic = alterAfflictionMetallic(afflictionValue, surface.metallic,  afflictionMetallic, noiseHash);
+            surface.albedo = alterAfflictionColor(afflictionValue, vec4(surface.albedo, 1.0), afflictionAlbedo, noiseHash).rgb;
+            surface.emission = alterAfflictionGlow(afflictionValue, vec4(surface.emission, 1.0), afflictionEmissive, noiseHash).rgb;
+            surface.ao = alterAfflictionAo(afflictionValue, surface.ao, vec3(afflictionAo), noiseHash); 
+            
+            if(surface.hasTangents == true){
+                surface.normal = alterAfflictionNormals(afflictionValue, surface.normal, afflictionNormal, noiseHash);      
+            }    
+            else{
+                surface.normal = alterAfflictionNormalsForTerrain(afflictionValue, surface.normal, afflictionNormal, noiseHash, surface.geometryNormal);
+            }    
+
+        #endif
+    }
+#endif
+
+
+
+
+

+ 21 - 0
jme3-terrain/src/main/resources/Common/MatDefs/Terrain/Modular/PBRTerrainTextureLayer.glsl

@@ -0,0 +1,21 @@
+#ifndef __TERRAIN_LAYER_MODULE__
+    #define __TERRAIN_LAYER_MODULE__
+
+    #ifndef PBRTerrainTextureLayer
+        #struct StdPBRTerrainTextureLayer
+
+            float blendValue;
+
+            vec4 albedo;
+            float alpha;
+            vec3 normal;
+            float height;  //parallax unused currently
+            float metallic;             
+            float roughness;
+            float ao;
+            vec4 emission;
+
+        #endstruct
+        #define PBRTerrainTextureLayer StdPBRTerrainTextureLayer    
+    #endif
+#endif

+ 170 - 0
jme3-terrain/src/main/resources/Common/MatDefs/Terrain/Modular/PBRTerrainUtils.glsllib

@@ -0,0 +1,170 @@
+#ifndef __PBR_TERRAIN_UTILS_MODULE__
+    #define __PBR_TERRAIN_UTILS_MODULE__
+
+    #import "Common/MatDefs/ShaderLib/PBRTerrainTextureLayer.glsl"    
+
+    #import "Common/ShaderLib/TangentUtils.glsllib"
+    #import "Common/ShaderLib/TriPlanarUtils.glsllib"
+
+    #ifdef ENABLE_PBRTerrainUtils_readPBRTerrainLayers   
+
+        //texture arrays:
+        uniform sampler2DArray m_AlbedoTextureArray;
+        uniform sampler2DArray m_NormalParallaxTextureArray;
+        uniform sampler2DArray m_MetallicRoughnessAoEiTextureArray;
+
+        //texture-slot params for 12 unique texture slots (0-11) where the integer value points to the desired texture's index in the corresponding texture array:
+        #for i=0..12 (#ifdef ALBEDOMAP_$i $0 #endif)
+            uniform int m_AfflictionMode_$i;
+            uniform float m_Roughness_$i;
+            uniform float m_Metallic_$i;
+            uniform float m_AlbedoMap_$i_scale;
+            uniform vec4 m_EmissiveColor_$i;
+
+            uniform int m_AlbedoMap_$i;
+
+        #endfor 
+        #for n=0..12 (#ifdef METALLICROUGHNESSMAP_$n $0 #endif)
+            uniform int m_MetallicRoughnessMap_$n;
+        #endfor
+        #for x=0..12 (#ifdef NORMALMAP_$x $0 #endif)
+            uniform int m_NormalMap_$x;
+        #endfor
+
+        //3 alpha maps :
+        #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
+        vec4 alphaBlend_0, alphaBlend_1, alphaBlend_2;
+
+
+        void PBRTerrainUtils_readAlphaMaps(){
+
+            #ifdef ALPHAMAP  
+                alphaBlend_0 = texture2D( m_AlphaMap, texCoord.xy );
+            #endif
+            #ifdef ALPHAMAP_1
+                alphaBlend_1 = texture2D( m_AlphaMap_1, texCoord.xy );
+            #endif
+            #ifdef ALPHAMAP_2
+                alphaBlend_2 = texture2D( m_AlphaMap_2, texCoord.xy );
+            #endif
+            
+            
+        }
+
+        float PBRTerrainUtils_getAlphaBlendFromChannel(int layer){
+            float finalAlphaBlendForLayer = 0.0;
+            vec4 alphaBlend;
+            if(layer <= 3.0){
+                alphaBlend = alphaBlend_0;       
+            }else if(layer <= 7.0){
+                alphaBlend = alphaBlend_1;
+            }else if(layer <= 11.0){
+                alphaBlend = alphaBlend_2;
+            }
+            int texChannelForAlphaBlending = int(mod(float(layer), 4.0)); //pick the correct channel (r g b or a) based on the layer's index
+            switch(texChannelForAlphaBlending) {
+                case 0:
+                    finalAlphaBlendForLayer = alphaBlend.r;
+                    break;
+                case 1:
+                    finalAlphaBlendForLayer = alphaBlend.g;
+                    break;
+                case 2:
+                    finalAlphaBlendForLayer = alphaBlend.b;
+                    break;
+                case 3:
+                    finalAlphaBlendForLayer = alphaBlend.a;
+                    break;            
+            }
+
+            return finalAlphaBlendForLayer;
+        }    
+              
+       
+        PBRTerrainTextureLayer PBRTerrainUtils_createAdvancedPBRTerrainLayer(int layerNum){
+            
+            PBRTerrainTextureLayer terrainTextureLayer;
+            terrainTextureLayer.blendValue = PBRTerrainUtils_getAlphaBlendFromChannel(layerNum);
+            
+            return terrainTextureLayer;
+        }
+        
+    //________      
+    
+        void updateLayerFromPackedAlbedoMap(inout vec4 packedAlbedoVec, inout PBRTerrainTextureLayer layer){
+            layer.albedo = packedAlbedoVec;
+            layer.alpha = packedAlbedoVec.a;
+        }
+        void updateLayerFromPackedNormalParallaxVec(inout vec4 packedNormalParallaxVec, inout PBRTerrainTextureLayer layer){
+            layer.normal = calculateTangentsAndApplyToNormals(packedNormalParallaxVec.rgb, PBRLightingUtils_getWorldNormal());
+            layer.height = packedNormalParallaxVec.a;   
+        }
+        void updateLayerFromPackedMRAoEiVec(inout vec4 packedMRAoEiVec, inout PBRTerrainTextureLayer layer){
+            layer.ao = packedMRAoEiVec.r;
+            layer.roughness = packedMRAoEiVec.g;
+            layer.metallic = packedMRAoEiVec.b;
+            layer.emission *= packedMRAoEiVec.a * layer.emission.a;            
+        }    
+    //________
+    
+        // read Triplanar Albedo from TextureArray:
+        void PBRTerrainUtils_readTriPlanarAlbedoTexArray(in int indexInTexArray, in float scale, in sampler2DArray texArray, inout PBRTerrainTextureLayer layer){         
+            vec4 packedAlbedoVec = getTriPlanarBlendFromTexArray(lPosition, indexInTexArray, scale, texArray);
+            updateLayerFromPackedAlbedoMap(packedAlbedoVec, layer);
+        }    
+        // read Triplanar normal from TextureArray:
+        void PBRTerrainUtils_readTriPlanarNormalTexArray(in int indexInTexArray, in float scale, in sampler2DArray texArray, inout PBRTerrainTextureLayer layer){
+            vec4 packedNormalParallaxVec = getTriPlanarBlendFromTexArray(lPosition, indexInTexArray, scale, texArray);
+            updateLayerFromPackedNormalParallaxVec(packedNormalParallaxVec, layer);
+        } 
+        // read TriPlanar metallicRoughnessAoEi from TextureArray:
+        void PBRTerrainUtils_readTriPlanarMetallicRoughnessAoEiTexArray(in int indexInTexArray, in float scale, in sampler2DArray texArray, inout PBRTerrainTextureLayer layer){
+            vec4 packedMRAoEi = getTriPlanarBlendFromTexArray(lPosition, indexInTexArray, scale, texArray);
+            updateLayerFromPackedMRAoEiVec(packedMRAoEi, layer);
+        }         
+     //________ 
+        
+        // read Albedo from TextureArray:
+        void PBRTerrainUtils_readAlbedoTexArray(in int indexInTexArray, in float scale, in sampler2DArray texArray, inout PBRTerrainTextureLayer layer){
+            vec4 packedAlbedoVec = texture2DArray(texArray, vec3(texCoord * scale, indexInTexArray));
+            updateLayerFromPackedAlbedoMap(packedAlbedoVec, layer);
+           
+        }    
+        // read Normal from TextureArray:
+        void PBRTerrainUtils_readNormalTexArray(in int indexInTexArray, in float scale, in sampler2DArray texArray, inout PBRTerrainTextureLayer layer){
+            vec4 packedNormalParallaxVec = texture2DArray(texArray, vec3(texCoord * scale, indexInTexArray));
+            updateLayerFromPackedNormalParallaxVec(packedNormalParallaxVec, layer);           
+        } 
+        // read metallicRoughnessAoEi from TextureArray:
+        void PBRTerrainUtils_readMetallicRoughnessAoEiTexArray(in int indexInTexArray, float scale, in sampler2DArray texArray, inout PBRTerrainTextureLayer layer){
+            vec4 packedMRAoEi = texture2DArray(texArray, vec3(texCoord * scale, indexInTexArray));
+            updateLayerFromPackedMRAoEiVec(packedMRAoEi, layer);
+           
+        } 
+     //________
+        
+
+    
+        void PBRTerrainUtils_blendPBRTerrainLayer(inout PBRSurface surface, inout PBRTerrainTextureLayer layer){
+
+
+        //mix values from this index layer to final output values based on finalAlphaBlendForLayer 
+            surface.albedo = mix(surface.albedo, layer.albedo.rgb, layer.blendValue);        
+            surface.normal = mix(surface.normal.rgb, layer.normal, layer.blendValue);        
+            surface.metallic = mix(surface.metallic, layer.metallic, layer.blendValue);
+            surface.roughness = mix(surface.roughness, layer.roughness, layer.blendValue);
+            surface.ao = mix(surface.ao, vec3(layer.ao), layer.blendValue);
+            surface.emission = mix(surface.emission, layer.emission.rgb, layer.blendValue);
+        }  
+
+    #endif
+#endif
+

+ 11 - 11
jme3-terrain/src/main/resources/Common/MatDefs/Terrain/PBRTerrain.vert

@@ -10,14 +10,16 @@ varying vec3 wPosition;
 varying vec3 wNormal;
 
 
- uniform vec4 g_AmbientLightColor;
+uniform vec4 g_AmbientLightColor;
 
-
-#ifdef TRI_PLANAR_MAPPING
-  varying vec4 wVertex;
+#ifdef USE_FOG
+    varying float fogDistance;
+    uniform vec3 g_CameraPosition;
 #endif
 
 
+varying vec4 lPosition;
+
 void main(){
     vec4 modelSpacePos = vec4(inPosition, 1.0);
 
@@ -28,13 +30,11 @@ void main(){
     wPosition = (g_WorldMatrix * vec4(inPosition, 1.0)).xyz;    
     
     wNormal  = normalize(TransformWorldNormal(inNormal));
-
-
-    #ifdef TRI_PLANAR_MAPPING
-       wVertex = vec4(inPosition,0.0);       
-    #endif
     
+    lPosition = vec4(inPosition, 0.0);       
     
-  
+    #ifdef USE_FOG
+        fogDistance = distance(g_CameraPosition, (g_WorldMatrix * modelSpacePos).xyz);
+    #endif
     
-}
+}