ソースを参照

Added PBR Terrain shaders (#1478)

* Add files via upload

* Add files via upload

* Add files via upload

* Update AfflictedAdvancedPBRTerrain.frag

* Update AfflictionLib.glsllib

* Update AfflictedAdvancedPBRTerrain.j3md

* Update AfflictedPBRTerrain.j3md

* Update AfflictedPBRTerrain.frag

* Rename AfflictedAdvancedPBRTerrain.frag to AdvancedPBRTerrain.frag

* Update AfflictedAdvancedPBRTerrain.j3md

* Update and rename AfflictedAdvancedPBRTerrain.j3md to AdvancedPBRTerrain.j3md

* Rename AfflictedPBRTerrain.frag to PBRTerrain.frag

* Update and rename AfflictedPBRTerrain.j3md to PBRTerrain.j3md

* Rename AfflictedPBRTerrain.vert to PBRTerrain.vert

* Update PBRTerrain.j3md

* Add files via upload

* first test case

uploaded new texture resources that better demonstrate the capabilities of PBR, and added keybinding for switching between day and night by toggling ambient light

* Update PBRTerrainTest.java

* Update PBRTerrainTest.java

fixed to use font thats already included in test data

* Update PBRTerrainTest.java

* add light probes used by test case

made a new folder for light probes since one did not exist where "defaultProbe.j3o" was located.

* Add files via upload

* test case for advanced pbr terrain shader

* Re-upload textures in same format

Had to fix the bit rate on some png images to make sure they were all the same exact format to fit into texture arrays.

* Add files via upload

* Update AdvancedPBRTerrain.j3md

* Update AdvancedPBRTerrain.j3md

* Update PBRTerrain.j3md

* Update PBRTerrain.frag

* Update AdvancedPBRTerrain.frag

* Delete fantasy-sky_Probe.j3o

* Add files via upload

* Delete sunset_Probe.j3o

* Update PBRTerrainAdvancedTest.java

update asset paths for textures, and set to use quarry probe

* Update PBRTerrainTest.java

* Update PBRTerrainAdvancedTest.java

* Add files via upload

* Add files via upload

added license file for textures from cc0textures.com

They say it is enough to just put "Contains assets from CC0Textures.com, licensed under CC0 1.0 Universal" but I still left some extra information pointing back to their site and the page that states this license information

* Update AfflictionLib.glsllib

* Update PBRTerrainTest.java

* Update PBRTerrainAdvancedTest.java

* Update PBRTerrainTest.java

* Update license.txt

* Update license.txt

* Update PBRTerrainTest.java

* Update PBRTerrainAdvancedTest.java

* Update license.txt

* Update PBRTerrainTest.java

fixed an assetpath

* Update AdvancedPBRTerrain.frag

remove a commented out and unused variable that slipped past my last check

* Update PBRTerrainAdvancedTest.java

* Update PBRTerrainTest.java

* added import for LightProbe.AreaType

* Update PBRTerrainAdvancedTest.java

* Update PBRTerrainAdvancedTest.java

* Update PBRTerrainTest.java

* Update PBRTerrainAdvancedTest.java

removed the comment from earlier review that I missed

* Update PBRTerrainAdvancedTest.java

Addressed recent reviews, and also made some other minor changes that should make the test case cleaner and easier to understand.

* Update PBRTerrainAdvancedTest.java

* Update PBRTerrainAdvancedTest.java

fixed emissive being applied to wrong texture slot and adjusted emissiveColor to look better

* removed unused HORIZON_FADE define

* Update PBRTerrainAdvancedTest.java

Fixed with proper way to load quarry_Probe, and added class variables for emissiveColors rather than defining them in-line where the values are sent to the shader

* Update PBRTerrainAdvancedTest.java

* Update PBRTerrainTest.java

fixed crashes and cleaned up code in standard test case

* Update PBRTerrainTest.java

fixed typo where I spelled "noticeably"  wrong

* Update PBRTerrainAdvancedTest.java

fixed typo for word "noticeably"

* Update PBRTerrainTest.java

added license text at top of class
Ryan McDonough 4 年 前
コミット
596ee0bcd5
54 ファイル変更4566 行追加0 行削除
  1. 465 0
      jme3-examples/src/main/java/jme3test/terrain/PBRTerrainAdvancedTest.java
  2. 383 0
      jme3-examples/src/main/java/jme3test/terrain/PBRTerrainTest.java
  3. 1358 0
      jme3-terrain/src/main/resources/Common/MatDefs/Terrain/AdvancedPBRTerrain.frag
  4. 404 0
      jme3-terrain/src/main/resources/Common/MatDefs/Terrain/AdvancedPBRTerrain.j3md
  5. 333 0
      jme3-terrain/src/main/resources/Common/MatDefs/Terrain/AfflictionLib.glsllib
  6. 107 0
      jme3-terrain/src/main/resources/Common/MatDefs/Terrain/NoiseLib.glsllib
  7. 1023 0
      jme3-terrain/src/main/resources/Common/MatDefs/Terrain/PBRTerrain.frag
  8. 380 0
      jme3-terrain/src/main/resources/Common/MatDefs/Terrain/PBRTerrain.j3md
  9. 40 0
      jme3-terrain/src/main/resources/Common/MatDefs/Terrain/PBRTerrain.vert
  10. 15 0
      jme3-testdata/src/main/resources/Scenes/LightProbes/license.txt
  11. BIN
      jme3-testdata/src/main/resources/Scenes/LightProbes/quarry_Probe.j3o
  12. BIN
      jme3-testdata/src/main/resources/Textures/Terrain/PBR/Gravel015_1K_AmbientOcclusion.png
  13. BIN
      jme3-testdata/src/main/resources/Textures/Terrain/PBR/Gravel015_1K_Color.png
  14. BIN
      jme3-testdata/src/main/resources/Textures/Terrain/PBR/Gravel015_1K_Displacement.png
  15. BIN
      jme3-testdata/src/main/resources/Textures/Terrain/PBR/Gravel015_1K_Normal.png
  16. BIN
      jme3-testdata/src/main/resources/Textures/Terrain/PBR/Gravel015_1K_Roughness.png
  17. BIN
      jme3-testdata/src/main/resources/Textures/Terrain/PBR/Gravel_015_PackedMetallicRoughnessMap.png
  18. BIN
      jme3-testdata/src/main/resources/Textures/Terrain/PBR/Ground036_1K_AmbientOcclusion.png
  19. BIN
      jme3-testdata/src/main/resources/Textures/Terrain/PBR/Ground036_1K_Color.png
  20. BIN
      jme3-testdata/src/main/resources/Textures/Terrain/PBR/Ground036_1K_Displacement.png
  21. BIN
      jme3-testdata/src/main/resources/Textures/Terrain/PBR/Ground036_1K_Normal.png
  22. BIN
      jme3-testdata/src/main/resources/Textures/Terrain/PBR/Ground036_1K_Roughness.png
  23. BIN
      jme3-testdata/src/main/resources/Textures/Terrain/PBR/Ground036_PackedMetallicRoughnessMap.png
  24. BIN
      jme3-testdata/src/main/resources/Textures/Terrain/PBR/Ground037_1K_AmbientOcclusion.png
  25. BIN
      jme3-testdata/src/main/resources/Textures/Terrain/PBR/Ground037_1K_Color.png
  26. BIN
      jme3-testdata/src/main/resources/Textures/Terrain/PBR/Ground037_1K_Displacement.png
  27. BIN
      jme3-testdata/src/main/resources/Textures/Terrain/PBR/Ground037_1K_Normal.png
  28. BIN
      jme3-testdata/src/main/resources/Textures/Terrain/PBR/Ground037_1K_Roughness.png
  29. BIN
      jme3-testdata/src/main/resources/Textures/Terrain/PBR/Ground037_PackedMetallicRoughnessMap.png
  30. BIN
      jme3-testdata/src/main/resources/Textures/Terrain/PBR/Marble013_1K_Color.png
  31. BIN
      jme3-testdata/src/main/resources/Textures/Terrain/PBR/Marble013_1K_Displacement.png
  32. BIN
      jme3-testdata/src/main/resources/Textures/Terrain/PBR/Marble013_1K_Normal.png
  33. BIN
      jme3-testdata/src/main/resources/Textures/Terrain/PBR/Marble013_1K_Roughness.png
  34. BIN
      jme3-testdata/src/main/resources/Textures/Terrain/PBR/Marble013_PackedMetallicRoughnessMap.png
  35. BIN
      jme3-testdata/src/main/resources/Textures/Terrain/PBR/Rock035_1K_AmbientOcclusion.png
  36. BIN
      jme3-testdata/src/main/resources/Textures/Terrain/PBR/Rock035_1K_Color.jpg
  37. BIN
      jme3-testdata/src/main/resources/Textures/Terrain/PBR/Rock035_1K_Color.png
  38. BIN
      jme3-testdata/src/main/resources/Textures/Terrain/PBR/Rock035_1K_Displacement.png
  39. BIN
      jme3-testdata/src/main/resources/Textures/Terrain/PBR/Rock035_1K_Normal.png
  40. BIN
      jme3-testdata/src/main/resources/Textures/Terrain/PBR/Rock035_1K_Roughness.png
  41. BIN
      jme3-testdata/src/main/resources/Textures/Terrain/PBR/Rock035_PackedMetallicRoughnessMap.png
  42. BIN
      jme3-testdata/src/main/resources/Textures/Terrain/PBR/Snow006_1K_AmbientOcclusion.png
  43. BIN
      jme3-testdata/src/main/resources/Textures/Terrain/PBR/Snow006_1K_Color.png
  44. BIN
      jme3-testdata/src/main/resources/Textures/Terrain/PBR/Snow006_1K_Displacement.png
  45. BIN
      jme3-testdata/src/main/resources/Textures/Terrain/PBR/Snow006_1K_Normal.png
  46. BIN
      jme3-testdata/src/main/resources/Textures/Terrain/PBR/Snow006_1K_Roughness.png
  47. BIN
      jme3-testdata/src/main/resources/Textures/Terrain/PBR/Snow006_PackedMetallicRoughnessMap.png
  48. BIN
      jme3-testdata/src/main/resources/Textures/Terrain/PBR/Tiles083_1K_AmbientOcclusion.png
  49. BIN
      jme3-testdata/src/main/resources/Textures/Terrain/PBR/Tiles083_1K_Color.png
  50. BIN
      jme3-testdata/src/main/resources/Textures/Terrain/PBR/Tiles083_1K_Displacement.png
  51. BIN
      jme3-testdata/src/main/resources/Textures/Terrain/PBR/Tiles083_1K_Normal.png
  52. BIN
      jme3-testdata/src/main/resources/Textures/Terrain/PBR/Tiles083_1K_Roughness.png
  53. BIN
      jme3-testdata/src/main/resources/Textures/Terrain/PBR/Tiles083_PackedMetallicRoughnessMap.png
  54. 58 0
      jme3-testdata/src/main/resources/Textures/Terrain/PBR/license.txt

+ 465 - 0
jme3-examples/src/main/java/jme3test/terrain/PBRTerrainAdvancedTest.java

@@ -0,0 +1,465 @@
+/*
+ * Copyright (c) 2009-2021 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ *   may be used to endorse or promote products derived from this software
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.terrain;
+
+
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.asset.TextureKey;
+import com.jme3.font.BitmapText;
+import com.jme3.input.KeyInput;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.input.controls.KeyTrigger;
+import com.jme3.light.AmbientLight;
+import com.jme3.light.DirectionalLight;
+import com.jme3.light.LightProbe;
+import com.jme3.light.LightProbe.AreaType;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.Vector3f;
+import com.jme3.shader.VarType;
+import com.jme3.system.AppSettings;
+import com.jme3.terrain.geomipmap.TerrainLodControl;
+import com.jme3.terrain.geomipmap.TerrainQuad;
+import com.jme3.terrain.geomipmap.lodcalc.DistanceLodCalculator;
+import com.jme3.terrain.heightmap.AbstractHeightMap;
+import com.jme3.terrain.heightmap.ImageBasedHeightMap;
+import com.jme3.texture.Image;
+import com.jme3.texture.Texture;
+import com.jme3.texture.Texture.WrapMode;
+import com.jme3.texture.TextureArray;
+import java.util.ArrayList;
+import java.util.List;
+
+
+
+/**
+    * This test uses the MatDef titled 'AdvancedPBRTerrain.j3md' to create a terrain Material that is capable of using more textures than a standard terrain shader by utilizing TextureArrays.
+    * This shader is still subject to the GLSL max limit of 16 textures, however each TextureArray counts as a single texture, and each TextureArray can store multiple Images
+    * 
+    * Upon running the app, the user should see a mountainous, terrain-based landscape with some grassy areas, some snowy areas, and some tiled roads and gravel paths weaving between the valleys. Snow should
+    * be slightly shiney/reflective, and marble texture should be even shinier. If you would like to know what each texture is supposed to look like, you can find the textures used for this test case
+    * located in jme-test-data 
+    * (Screenshots showing how this test-case should look will also be available soon so you can compare your results, and I will replace this comment with a link to their location as soon as they are posted)
+    *
+    * Users can press 'p' to toggle between tri-planar mode. Enabling tri-planar mode should prevent stretching of textures on the steep areas of the terrain
+    * 
+    * Users can press 'n' to toggle between night and day. Pressing 'n' will cause the light to gradually fade darker/brighter until the min/max lighting levels are reached.
+    * At night the scene should be noticeably darker, and the marble and tiled-road texture should be noticeably glowing from their emissiveColors and emissiveIntesnity map that is packed into
+    * the alpha channel of their MetallicRoughness maps
+    * 
+    * The MetallicRoughness map stores:
+    * - AmbientOcclusion in the Red channel
+    * - Roughness in the Green channel
+    * - Metallic in the Blue channel
+    * - EmissiveIntensity in the Alpha channel
+    * 
+    * This shader is still subject to the GLSL max limit of 16 textures, however each TextureArray counts as a single texture, and each TextureArray can store multiple Images 
+    * For more information on texture arrays see: https://www.khronos.org/opengl/wiki/Array_Texture    
+    * For more information on the TextureArray class/objcet in JME3 see: https://javadoc.jmonkeyengine.org/v3.3.0-beta2/com/jme3/texture/TextureArray.html
+    * 
+    *  Uses assets from CC0Textures.com, licensed under CC0 1.0 Universal. For more information on the textures this test case uses, 
+    *  view the license.txt file located in the jme3-test-data directory where these textures are located: jmonkeyengine/jme3-testdata/src/main/resources/Textures/Terrain/PBR
+    * 
+    * <p> 
+    * Notes: (as of 12 April, 2021)
+    * <ol>
+    * <li>
+    * results look better with anti-aliasing, especially at far distances. This may be due to the way that the terrain is generated from a heightmap,     
+    * as these same textures do not have this issue in my other project
+    * </li>    
+    * <li>
+    * The amount of images per texture array may still be limited by the value set to GL_MAX_ARRAY_TEXTURE_LAYERS, however this value should be high enough that users will likely run into issues with extremely low FPS
+    * from too many texture-reads long before you surpass the limit of texture-layers per textureArray. 
+    * If this ever becomes an issue, a secondary set of Albedo/Normal/MetallicRoughness texture arrays could be added to the shader to store any textures that surpass the limit of the primary textureArrays.   
+    * </li>
+    * </ol>
+    * author @yaRnMcDonuts
+    * </p>
+*/
+
+
+public class PBRTerrainAdvancedTest extends SimpleApplication {    
+    
+
+    private TerrainQuad terrain;    
+    private Material matTerrain;
+    private boolean triPlanar = false;
+    
+    private final int terrainSize = 512;
+    private final int patchSize = 256;
+    private final float dirtScale = 24;
+    private final float darkRockScale = 24;
+    private final float snowScale = 64;
+    private final float tileRoadScale = 64;
+    private final float grassScale = 24;
+    private final float marbleScale = 64;
+    private final float gravelScale = 64;
+   
+    private final ColorRGBA tilesEmissiveColor = new ColorRGBA(0.12f, 0.02f, 0.23f, 0.85f); //dim magents emssiveness
+    private final ColorRGBA marbleEmissiveColor = new ColorRGBA(0.0f, 0.0f, 1.0f, 1.0f); //fully saturated blue emissiveness
+    
+    
+    private AmbientLight ambientLight;
+    private DirectionalLight directionalLight;
+    private boolean isNight = false;
+    
+    private final float dayLightIntensity = 1.0f;
+    private final float nightLightIntensity = 0.03f;
+    
+    private BitmapText keybindingsText;
+    
+    private final float camMoveSpeed = 50f;
+
+    public static void main(String[] args) {
+        PBRTerrainAdvancedTest app = new PBRTerrainAdvancedTest();
+        AppSettings s = new AppSettings(true);
+        
+        s.put("GammaCorrection", true);
+        
+        app.setSettings(s);
+        app.start();
+       
+    }
+    
+    private final ActionListener actionListener = new ActionListener() {
+        @Override
+        public void onAction(String name, boolean pressed, float tpf) {
+            if (name.equals("triPlanar") && !pressed) {
+                triPlanar = !triPlanar;
+                if (triPlanar) {
+                    matTerrain.setBoolean("useTriPlanarMapping", true);
+                    // tri-planar textures don't use the mesh's texture coordinates but real world coordinates,
+                    // so we need to convert these texture coordinate scales into real world scales so it looks
+                    // the same when we switch to/from tr-planar mode 
+                    matTerrain.setFloat("AlbedoMap_0_scale", (dirtScale / terrainSize));
+                    matTerrain.setFloat("AlbedoMap_1_scale", (darkRockScale / terrainSize));
+                    matTerrain.setFloat("AlbedoMap_2_scale", (snowScale / terrainSize));
+                    matTerrain.setFloat("AlbedoMap_3_scale", (tileRoadScale / terrainSize));
+                    matTerrain.setFloat("AlbedoMap_4_scale", (grassScale / terrainSize));
+                    matTerrain.setFloat("AlbedoMap_5_scale", (marbleScale / terrainSize));
+                    matTerrain.setFloat("AlbedoMap_6_scale", (gravelScale / terrainSize));
+                } else {
+                    matTerrain.setBoolean("useTriPlanarMapping", false);
+
+                    matTerrain.setFloat("AlbedoMap_0_scale", dirtScale);
+                    matTerrain.setFloat("AlbedoMap_1_scale", darkRockScale);
+                    matTerrain.setFloat("AlbedoMap_2_scale", snowScale);
+                    matTerrain.setFloat("AlbedoMap_3_scale", tileRoadScale);
+                    matTerrain.setFloat("AlbedoMap_4_scale", grassScale);
+                    matTerrain.setFloat("AlbedoMap_5_scale", marbleScale);
+                    matTerrain.setFloat("AlbedoMap_6_scale", gravelScale);
+
+                }
+            }
+            if (name.equals("toggleNight") && !pressed) {
+                isNight = !isNight;
+                //ambient and direcitonal light are faded smoothly in update loop below !
+                
+            }
+        }
+    };
+    
+    @Override
+    public void simpleInitApp() {              
+        setupKeys();        
+        setUpTerrain();        
+        setUpTerrainMaterial(); // <- this method contains the important info about using 'AdvancedPBRTerrain.j3md'
+        setUpLights();        
+        setUpCamera();
+    }
+
+     private void setUpTerrainMaterial() {
+        // advanced pbr terrain matdef
+        matTerrain = new Material(assetManager, "Common/MatDefs/Terrain/AdvancedPBRTerrain.j3md");        
+        
+        matTerrain.setBoolean("useTriPlanarMapping", false);
+
+        // ALPHA map (for splat textures)
+        matTerrain.setTexture("AlphaMap", assetManager.loadTexture("Textures/Terrain/splat/alpha1.png"));
+        matTerrain.setTexture("AlphaMap_1", assetManager.loadTexture("Textures/Terrain/splat/alpha2.png"));
+        // this material also supports 'AlphaMap_2', so you can get up to 12 texture slots
+
+        
+        // load textures for texture arrays
+        // it is IMPORTANT that these MUST all have the same dimensions and format in order to be put into a texture array
+        
+        //ALBEDO MAPS
+        Texture dirt = assetManager.loadTexture("Textures/Terrain/PBR/Ground037_1K_Color.png");
+        Texture darkRock = assetManager.loadTexture("Textures/Terrain/PBR/Rock035_1K_Color.png");
+        Texture snow = assetManager.loadTexture("Textures/Terrain/PBR/Snow006_1K_Color.png");
+        Texture tileRoad = assetManager.loadTexture("Textures/Terrain/PBR/Tiles083_1K_Color.png");     
+        Texture grass = assetManager.loadTexture("Textures/Terrain/PBR/Ground037_1K_Color.png");
+        Texture marble = assetManager.loadTexture("Textures/Terrain/PBR/Marble013_1K_Color.png");
+        Texture gravel = assetManager.loadTexture("Textures/Terrain/PBR/Gravel015_1K_Color.png");
+         
+        // NORMAL MAPS
+        Texture normalMapDirt = assetManager.loadTexture("Textures/Terrain/PBR/Ground036_1K_Normal.png");
+        Texture normalMapDarkRock = assetManager.loadTexture("Textures/Terrain/PBR/Rock035_1K_Normal.png");        
+        Texture normalMapSnow = assetManager.loadTexture("Textures/Terrain/PBR/Snow006_1K_Normal.png");        
+        Texture normalMapGravel = assetManager.loadTexture("Textures/Terrain/PBR/Gravel015_1K_Normal.png");        
+        Texture normalMapGrass = assetManager.loadTexture("Textures/Terrain/PBR/Ground037_1K_Normal.png");        
+        Texture normalMapMarble = assetManager.loadTexture("Textures/Terrain/PBR/Marble013_1K_Normal.png");        
+        Texture normalMapRoad = assetManager.loadTexture("Textures/Terrain/PBR/Tiles083_1K_Normal.png");
+        
+        //PACKED METALLIC/ROUGHNESS / AMBIENT OCCLUSION / EMISSIVE INTENSITY MAPS
+        Texture metallicRoughnessAoEiMapDirt = assetManager.loadTexture("Textures/Terrain/PBR/Ground036_PackedMetallicRoughnessMap.png");
+        Texture metallicRoughnessAoEiMapDarkRock = assetManager.loadTexture("Textures/Terrain/PBR/Rock035_PackedMetallicRoughnessMap.png");        
+        Texture metallicRoughnessAoEiMapSnow = assetManager.loadTexture("Textures/Terrain/PBR/Snow006_PackedMetallicRoughnessMap.png");        
+        Texture metallicRoughnessAoEiMapGravel = assetManager.loadTexture("Textures/Terrain/PBR/Gravel_015_PackedMetallicRoughnessMap.png");        
+        Texture metallicRoughnessAoEiMapGrass = assetManager.loadTexture("Textures/Terrain/PBR/Ground037_PackedMetallicRoughnessMap.png");        
+        Texture metallicRoughnessAoEiMapMarble = assetManager.loadTexture("Textures/Terrain/PBR/Marble013_PackedMetallicRoughnessMap.png");        
+        Texture metallicRoughnessAoEiMapRoad = assetManager.loadTexture("Textures/Terrain/PBR/Tiles083_PackedMetallicRoughnessMap.png");
+        
+        
+        // put all images into lists to create texture arrays.
+        //IMPORTANT to note that the index of each image in its list will be sent to the material to tell the shader to choose that texture from the textureArray when setting up a texture slot's mat parans
+        
+        List<Image> albedoImages = new ArrayList<>();
+        List<Image> normalMapImages = new ArrayList<>();
+        List<Image> metallicRoughnessAoEiMapImages = new ArrayList<>();
+        
+        albedoImages.add(dirt.getImage());  //0
+        albedoImages.add(darkRock.getImage()); //1
+        albedoImages.add(snow.getImage()); //2
+        albedoImages.add(tileRoad.getImage()); //3
+        albedoImages.add(grass.getImage()); //4
+        albedoImages.add(marble.getImage()); //5
+        albedoImages.add(gravel.getImage()); //6        
+        
+        normalMapImages.add(normalMapDirt.getImage());  //0
+        normalMapImages.add(normalMapDarkRock.getImage());  //1
+        normalMapImages.add(normalMapSnow.getImage());  //2
+        normalMapImages.add(normalMapRoad.getImage());   //3
+        normalMapImages.add(normalMapGrass.getImage());   //4
+        normalMapImages.add(normalMapMarble.getImage());   //5
+        normalMapImages.add(normalMapGravel.getImage());   //6
+                                   
+        metallicRoughnessAoEiMapImages.add(metallicRoughnessAoEiMapDirt.getImage());  //0
+        metallicRoughnessAoEiMapImages.add(metallicRoughnessAoEiMapDarkRock.getImage());  //1
+        metallicRoughnessAoEiMapImages.add(metallicRoughnessAoEiMapSnow.getImage());  //2
+        metallicRoughnessAoEiMapImages.add(metallicRoughnessAoEiMapRoad.getImage());   //3
+        metallicRoughnessAoEiMapImages.add(metallicRoughnessAoEiMapGrass.getImage());   //4
+        metallicRoughnessAoEiMapImages.add(metallicRoughnessAoEiMapMarble.getImage());   //5
+        metallicRoughnessAoEiMapImages.add(metallicRoughnessAoEiMapGravel.getImage());   //6                
+        
+        //initiate texture arrays using 
+        TextureArray albedoTextureArray = new TextureArray(albedoImages);
+        TextureArray normalParallaxTextureArray = new TextureArray(normalMapImages); // parallax is not used currently
+        TextureArray metallicRoughnessAoEiTextureArray = new TextureArray(metallicRoughnessAoEiMapImages);  
+        
+        // important to apply wrapMode to the whole texture array, rather than each individual texture in the array
+        albedoTextureArray.setWrap(WrapMode.Repeat);
+        normalParallaxTextureArray.setWrap(WrapMode.Repeat);
+        metallicRoughnessAoEiTextureArray.setWrap(WrapMode.Repeat);        
+        
+        //assign texture array to materials
+        matTerrain.setParam("AlbedoTextureArray", VarType.TextureArray, albedoTextureArray);
+        matTerrain.setParam("NormalParallaxTextureArray", VarType.TextureArray, normalParallaxTextureArray);
+        matTerrain.setParam("MetallicRoughnessAoEiTextureArray", VarType.TextureArray, metallicRoughnessAoEiTextureArray);
+        
+        
+        
+        //set up texture slots:
+        
+        matTerrain.setInt("AlbedoMap_0", 0); // dirt is index 0 in the albedo image list
+        matTerrain.setFloat("AlbedoMap_0_scale", dirtScale);
+        matTerrain.setFloat("Roughness_0", 1);
+        matTerrain.setFloat("Metallic_0", 0.02f);
+
+        matTerrain.setInt("AlbedoMap_1", 1);   // darkRock is index 1 in the albedo image list
+        matTerrain.setFloat("AlbedoMap_1_scale", darkRockScale);
+        matTerrain.setFloat("Roughness_1", 1);
+        matTerrain.setFloat("Metallic_1", 0.04f);
+
+        matTerrain.setInt("AlbedoMap_2", 2); 
+        matTerrain.setFloat("AlbedoMap_2_scale", snowScale);
+        matTerrain.setFloat("Roughness_2", 0.72f);
+        matTerrain.setFloat("Metallic_2", 0.12f);
+
+        matTerrain.setInt("AlbedoMap_3", 3);
+        matTerrain.setFloat("AlbedoMap_3_scale", tileRoadScale);
+        matTerrain.setFloat("Roughness_3", 1);
+        matTerrain.setFloat("Metallic_3", 0.04f);
+
+        matTerrain.setInt("AlbedoMap_4", 4);
+        matTerrain.setFloat("AlbedoMap_4_scale", grassScale);
+        matTerrain.setFloat("Roughness_4", 1);
+        matTerrain.setFloat("Metallic_4", 0);
+
+        matTerrain.setInt("AlbedoMap_5", 5);
+        matTerrain.setFloat("AlbedoMap_5_scale", marbleScale);
+        matTerrain.setFloat("Roughness_5", 1);
+        matTerrain.setFloat("Metallic_5", 0.2f);
+
+        matTerrain.setInt("AlbedoMap_6", 6);
+        matTerrain.setFloat("AlbedoMap_6_scale", gravelScale);
+        matTerrain.setFloat("Roughness_6", 1);
+        matTerrain.setFloat("Metallic_6", 0.01f);        
+        
+        // NORMAL MAPS  (int being passed to shader corresponds to the index of the texture's image in the List of images used to create its texture array)      
+        matTerrain.setInt("NormalMap_0", 0);
+        matTerrain.setInt("NormalMap_1", 1);  
+        matTerrain.setInt("NormalMap_2", 2); 
+        matTerrain.setInt("NormalMap_3", 3); 
+        matTerrain.setInt("NormalMap_4", 4); 
+        matTerrain.setInt("NormalMap_5", 5);
+        matTerrain.setInt("NormalMap_6", 6);
+                
+                
+        //METALLIC/ROUGHNESS/AO/EI MAPS 
+        matTerrain.setInt("MetallicRoughnessMap_0", 0);
+        matTerrain.setInt("MetallicRoughnessMap_1", 1);  
+        matTerrain.setInt("MetallicRoughnessMap_2", 2); 
+        matTerrain.setInt("MetallicRoughnessMap_3", 3); 
+        matTerrain.setInt("MetallicRoughnessMap_4", 4); 
+        matTerrain.setInt("MetallicRoughnessMap_5", 5);
+        matTerrain.setInt("MetallicRoughnessMap_6", 6);
+        
+        
+        //EMISSIVE        
+        matTerrain.setColor("EmissiveColor_5", marbleEmissiveColor);
+        matTerrain.setColor("EmissiveColor_3", tilesEmissiveColor); //these two texture slots (marble & tiledRoad, indexed in each texturea array at 5 and 3 respectively) both 
+                                                                    // have packed MRAoEi maps with an emissiveTexture packed into the alpha channel
+    
+//        matTerrain.setColor("EmissiveColor_1", new ColorRGBA(0.08f, 0.01f, 0.1f, 0.4f)); //this texture slot does not have a unique emissiveIntensityMap packed into its MRAoEi map, 
+                                                                                            // so setting an emissiveColor will apply equal intensity to every pixel 
+        
+        terrain.setMaterial(matTerrain);        
+    }
+    
+    private void setupKeys() {
+        flyCam.setMoveSpeed(50);
+        inputManager.addMapping("triPlanar", new KeyTrigger(KeyInput.KEY_P));
+        inputManager.addMapping("toggleNight", new KeyTrigger(KeyInput.KEY_N));
+        
+        inputManager.addListener(actionListener, "triPlanar");
+        inputManager.addListener(actionListener, "toggleNight");        
+        
+        keybindingsText = new BitmapText(assetManager.loadFont("Interface/Fonts/Default.fnt"));
+        keybindingsText.setText("Press 'N' to toggle day/night fade (takes a moment) \nPress 'P' to toggle tri-planar mode");
+        
+        getGuiNode().attachChild(keybindingsText);
+        keybindingsText.move(new Vector3f(200,120,0));
+        
+    }
+    
+    @Override
+    public void simpleUpdate(float tpf) {
+        super.simpleUpdate(tpf);
+        
+          //smoothly transition from day to night        
+        float currentLightIntensity = ambientLight.getColor().getRed();        
+        float incrementPerFrame = tpf * 0.3f;
+        
+        if(isNight){
+            
+            if(ambientLight.getColor().getRed() > nightLightIntensity){
+                currentLightIntensity -= incrementPerFrame;
+                if(currentLightIntensity < nightLightIntensity){
+                    currentLightIntensity = nightLightIntensity;
+                }
+                
+                ambientLight.getColor().set(currentLightIntensity, currentLightIntensity, currentLightIntensity, 1.0f);
+                directionalLight.getColor().set(currentLightIntensity, currentLightIntensity, currentLightIntensity, 1.0f);
+            }
+        }
+        
+        else{
+            
+            if(ambientLight.getColor().getRed() < dayLightIntensity){
+                currentLightIntensity += incrementPerFrame;
+                if(currentLightIntensity > dayLightIntensity){
+                    currentLightIntensity = dayLightIntensity;
+                }
+                
+                ambientLight.getColor().set(currentLightIntensity, currentLightIntensity, currentLightIntensity, 1.0f);
+                directionalLight.getColor().set(currentLightIntensity, currentLightIntensity, currentLightIntensity, 1.0f);
+            }            
+        }        
+    }
+
+    private void setUpTerrain() {
+        // HEIGHTMAP image (for the terrain heightmap)
+        TextureKey hmKey = new TextureKey("Textures/Terrain/splat/mountains512.png", false);
+        Texture heightMapImage = assetManager.loadTexture(hmKey);
+
+        // CREATE HEIGHTMAP
+        AbstractHeightMap heightmap = null;
+        try {
+            heightmap = new ImageBasedHeightMap(heightMapImage.getImage(), 0.3f);
+            heightmap.load();
+            heightmap.smooth(0.9f, 1);
+
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        
+        terrain = new TerrainQuad("terrain", patchSize + 1, terrainSize + 1, heightmap.getHeightMap());//, new LodPerspectiveCalculatorFactory(getCamera(), 4)); // add this in to see it use entropy for LOD calculations
+        TerrainLodControl control = new TerrainLodControl(terrain, getCamera());
+        control.setLodCalculator(new DistanceLodCalculator(patchSize + 1, 2.7f)); // patch size, and a multiplier
+        terrain.addControl(control);
+        terrain.setMaterial(matTerrain);
+        terrain.setLocalTranslation(0, -100, 0);
+        terrain.setLocalScale(1f, 1f, 1f);
+        rootNode.attachChild(terrain);
+        
+        
+    }
+
+    private void setUpLights() {
+        
+        LightProbe probe = (LightProbe) assetManager.loadAsset("Scenes/LightProbes/quarry_Probe.j3o");
+        
+        probe.setAreaType(AreaType.Spherical);      
+        probe.getArea().setRadius(2000);
+        probe.getArea().setCenter(new Vector3f(0, 0, 0));        
+        rootNode.addLight(probe);
+        
+        directionalLight = new DirectionalLight();
+        directionalLight.setDirection((new Vector3f(-0.3f, -0.5f, -0.3f)).normalize());
+        directionalLight.setColor(ColorRGBA.White);
+        rootNode.addLight(directionalLight);
+        
+        ambientLight = new AmbientLight();
+        directionalLight.setColor(ColorRGBA.White);
+        rootNode.addLight(ambientLight);        
+    }
+
+    private void setUpCamera() {
+        cam.setLocation(new Vector3f(0, 10, -10));
+        cam.lookAtDirection(new Vector3f(0, -1.5f, -1).normalizeLocal(), Vector3f.UNIT_Y);
+        
+        getFlyByCamera().setMoveSpeed(camMoveSpeed);        
+    }    
+}

+ 383 - 0
jme3-examples/src/main/java/jme3test/terrain/PBRTerrainTest.java

@@ -0,0 +1,383 @@
+package jme3test.terrain;
+
+/*
+ * Copyright (c) 2009-2021 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ *   may be used to endorse or promote products derived from this software
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.asset.TextureKey;
+import com.jme3.font.BitmapText;
+import com.jme3.input.KeyInput;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.input.controls.KeyTrigger;
+import com.jme3.light.AmbientLight;
+import com.jme3.light.DirectionalLight;
+import com.jme3.light.LightProbe;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.Vector3f;
+import com.jme3.system.AppSettings;
+import com.jme3.terrain.geomipmap.TerrainLodControl;
+import com.jme3.terrain.geomipmap.TerrainQuad;
+import com.jme3.terrain.geomipmap.lodcalc.DistanceLodCalculator;
+import com.jme3.terrain.heightmap.AbstractHeightMap;
+import com.jme3.terrain.heightmap.ImageBasedHeightMap;
+import com.jme3.texture.Texture;
+import com.jme3.texture.Texture.WrapMode;
+
+
+/**
+    * This test uses the MatDef titled 'PBRTerrain.j3md' to create a terrain Material using the PBR workflow
+    * 
+    * Upon running the app, the user should see a mountainous, terrain-based landscape with some grassy areas, some snowy areas, and some tiled roads and gravel paths weaving between the valleys. Snow should
+    * be slightly shiney/reflective, and marble texture should be even shinier. If you would like to know what each texture is supposed to look like, you can find the textures used for this test case
+    * located in jme-test-data 
+    * (Screenshots showing how this test-case should look will also be available soon so you can compare your results, and I will replace this comment with a link to their location as soon as they are posted)
+    *
+    * Users can press 'p' to toggle between tri-planar mode. Enabling tri-planar mode should prevent stretching of textures on the steep areas of the terrain
+    * 
+    * Users can press 'n' to toggle between night and day. Pressing 'n' will cause the light to gradually fade darker/brighter until the min/max lighting levels are reached.
+    * At night the scene should be noticeably darker.
+    * 
+    *  Uses assets from CC0Textures.com, licensed under CC0 1.0 Universal. For more information on the textures this test case uses, 
+    *  view the license.txt file located in the jme3-test-data directory where these textures are located: jmonkeyengine/jme3-testdata/src/main/resources/Textures/Terrain/PBR
+    * 
+    * <p> 
+    * Notes: (as of 12 April, 2021)
+    * <ol>
+    * <li>
+    * This shader is subject to the GLSL max limit of 16 textures, and users should consider using "AdvancedPBRTerrain.j3md" instead if they need additional texture slots
+    * </li>    
+    * </ol>
+    * author @yaRnMcDonuts
+    * </p>
+*/
+
+
+public class PBRTerrainTest extends SimpleApplication {    
+    
+
+    private TerrainQuad terrain;    
+    private Material matTerrain;
+    private boolean triPlanar = false;
+    
+    private final int terrainSize = 512;
+    private final int patchSize = 256;
+    private final float dirtScale = 24;
+    private final float darkRockScale = 24;
+    private final float snowScale = 64;
+    private final float tileRoadScale = 64;
+    private final float grassScale = 24;
+    private final float marbleScale = 64;
+    private final float gravelScale = 64;
+    
+    private AmbientLight ambientLight;
+    private DirectionalLight directionalLight;
+    private boolean isNight = false;
+    
+    private final float dayLightIntensity = 1.0f;
+    private final float nightLightIntensity = 0.03f;
+    
+    private BitmapText keybindingsText;
+    
+    private final float camMoveSpeed = 50f;
+
+    public static void main(String[] args) {
+        PBRTerrainTest app = new PBRTerrainTest();
+        AppSettings s = new AppSettings(true);
+        
+        s.put("FrameRate", 140);
+        s.put("GammaCorrection", true);
+        
+                
+        app.setSettings(s);
+        app.start();
+       
+    }   
+    
+    private final ActionListener actionListener = new ActionListener() {
+        @Override
+        public void onAction(String name, boolean pressed, float tpf) {
+            if (name.equals("triPlanar") && !pressed) {
+                triPlanar = !triPlanar;
+                if (triPlanar) {
+                    matTerrain.setBoolean("useTriPlanarMapping", true);
+                    // tri-planar textures don't use the mesh's texture coordinates but real world coordinates,
+                    // so we need to convert these texture coordinate scales into real world scales so it looks
+                    // the same when we switch to/from tr-planar mode 
+                    matTerrain.setFloat("AlbedoMap_0_scale", (dirtScale / terrainSize));
+                    matTerrain.setFloat("AlbedoMap_1_scale", (darkRockScale / terrainSize));
+                    matTerrain.setFloat("AlbedoMap_2_scale", (snowScale / terrainSize));
+                    matTerrain.setFloat("AlbedoMap_3_scale", (tileRoadScale / terrainSize));
+                    matTerrain.setFloat("AlbedoMap_4_scale", (grassScale / terrainSize));
+                    matTerrain.setFloat("AlbedoMap_5_scale", (marbleScale / terrainSize));
+                    matTerrain.setFloat("AlbedoMap_6_scale", (gravelScale / terrainSize));
+                } else {
+                    matTerrain.setBoolean("useTriPlanarMapping", false);
+
+                    matTerrain.setFloat("AlbedoMap_0_scale", dirtScale);
+                    matTerrain.setFloat("AlbedoMap_1_scale", darkRockScale);
+                    matTerrain.setFloat("AlbedoMap_2_scale", snowScale);
+                    matTerrain.setFloat("AlbedoMap_3_scale", tileRoadScale);
+                    matTerrain.setFloat("AlbedoMap_4_scale", grassScale);
+                    matTerrain.setFloat("AlbedoMap_5_scale", marbleScale);
+                    matTerrain.setFloat("AlbedoMap_6_scale", gravelScale);
+
+                }
+            }
+            if (name.equals("toggleNight") && !pressed) {
+                isNight = !isNight;
+                //ambient and direcitonal light are faded smoothly in update loop below !
+                
+            }
+        }
+    };
+    
+    @Override
+    public void simpleInitApp() {              
+        setupKeys();        
+        setUpTerrain();        
+        setUpTerrainMaterial(); // <- this method contains the important info about using 'AdvancedPBRTerrain.j3md'
+        setUpLights();        
+        setUpCamera();
+    }
+    
+    private void setUpTerrainMaterial() {
+
+        // TERRAIN TEXTURE material
+        matTerrain = new Material(assetManager, "Common/MatDefs/Terrain/PBRTerrain.j3md");                
+        
+        matTerrain.setBoolean("useTriPlanarMapping", false);
+
+        // ALPHA map (for splat textures)
+        matTerrain.setTexture("AlphaMap", assetManager.loadTexture("Textures/Terrain/splat/alpha1.png"));
+        matTerrain.setTexture("AlphaMap_1", assetManager.loadTexture("Textures/Terrain/splat/alpha2.png"));
+        // this material also supports 'AlphaMap_2', so you can get up to 12 diffuse textures
+
+        // HEIGHTMAP image (for the terrain heightmap)
+        TextureKey hmKey = new TextureKey("Textures/Terrain/splat/mountains512.png", false);
+        Texture heightMapImage = assetManager.loadTexture(hmKey);
+
+        // DIRT texture, Diffuse textures 0 to 3 use the first AlphaMap
+        Texture dirt = assetManager.loadTexture("Textures/Terrain/PBR/Ground037_1K_Color.png");
+        dirt.setWrap(WrapMode.Repeat);
+        matTerrain.setTexture("AlbedoMap_0", dirt);
+        matTerrain.setFloat("AlbedoMap_0_scale", dirtScale);
+        matTerrain.setFloat("Roughness_0", 1);
+        matTerrain.setFloat("Metallic_0", 0);
+        //matTerrain.setInt("AfflictionMode_0", 0);
+
+        // DARK ROCK texture
+        Texture darkRock = assetManager.loadTexture("Textures/Terrain/PBR/Rock035_1K_Color.png");
+        darkRock.setWrap(WrapMode.Repeat);
+        matTerrain.setTexture("AlbedoMap_1", darkRock);
+        matTerrain.setFloat("AlbedoMap_1_scale", darkRockScale);
+        matTerrain.setFloat("Roughness_1", 0.92f);
+        matTerrain.setFloat("Metallic_1", 0.02f);
+        //matTerrain.setInt("AfflictionMode_1", 0);
+
+        // SNOW texture
+        Texture snow = assetManager.loadTexture("Textures/Terrain/PBR/Snow006_1K_Color.png");
+        snow.setWrap(WrapMode.Repeat);
+        matTerrain.setTexture("AlbedoMap_2", snow);
+        matTerrain.setFloat("AlbedoMap_2_scale", snowScale);
+        matTerrain.setFloat("Roughness_2", 0.55f);
+        matTerrain.setFloat("Metallic_2", 0.12f);
+        
+        Texture tiles = assetManager.loadTexture("Textures/Terrain/PBR/Tiles083_1K_Color.png");
+        tiles.setWrap(WrapMode.Repeat);
+        matTerrain.setTexture("AlbedoMap_3", tiles);
+        matTerrain.setFloat("AlbedoMap_3_scale", tileRoadScale);
+        matTerrain.setFloat("Roughness_3", 0.87f);
+        matTerrain.setFloat("Metallic_3", 0.08f);
+
+        // GRASS texture
+        Texture grass = assetManager.loadTexture("Textures/Terrain/PBR/Ground037_1K_Color.png");
+        grass.setWrap(WrapMode.Repeat);
+        matTerrain.setTexture("AlbedoMap_4", grass);
+        matTerrain.setFloat("AlbedoMap_4_scale", grassScale);
+        matTerrain.setFloat("Roughness_4", 1);
+        matTerrain.setFloat("Metallic_4", 0);
+
+        // MARBLE texture
+        Texture marble = assetManager.loadTexture("Textures/Terrain/PBR/Marble013_1K_Color.png");
+        marble.setWrap(WrapMode.Repeat);
+        matTerrain.setTexture("AlbedoMap_5", marble);
+        matTerrain.setFloat("AlbedoMap_5_scale", marbleScale);
+        matTerrain.setFloat("Roughness_5", 0.06f);
+        matTerrain.setFloat("Metallic_5", 0.8f);
+
+        // Gravel texture
+        Texture gravel = assetManager.loadTexture("Textures/Terrain/PBR/Gravel015_1K_Color.png");
+        gravel.setWrap(WrapMode.Repeat);
+        matTerrain.setTexture("AlbedoMap_6", gravel);
+        matTerrain.setFloat("AlbedoMap_6_scale", gravelScale);
+        matTerrain.setFloat("Roughness_6", 0.9f);
+        matTerrain.setFloat("Metallic_6", 0.07f);
+        // NORMAL MAPS
+        Texture normalMapDirt = assetManager.loadTexture("Textures/Terrain/PBR/Ground036_1K_Normal.png");
+        normalMapDirt.setWrap(WrapMode.Repeat);
+        
+        Texture normalMapDarkRock = assetManager.loadTexture("Textures/Terrain/PBR/Rock035_1K_Normal.png");
+        normalMapDarkRock.setWrap(WrapMode.Repeat);
+        
+        Texture normalMapSnow = assetManager.loadTexture("Textures/Terrain/PBR/Snow006_1K_Normal.png");
+        normalMapSnow.setWrap(WrapMode.Repeat);
+        
+        Texture normalMapGravel = assetManager.loadTexture("Textures/Terrain/PBR/Gravel015_1K_Normal.png");
+        normalMapGravel.setWrap(WrapMode.Repeat);
+        
+        Texture normalMapGrass = assetManager.loadTexture("Textures/Terrain/PBR/Ground037_1K_Normal.png");
+        normalMapGrass.setWrap(WrapMode.Repeat);
+        
+        Texture normalMapMarble = assetManager.loadTexture("Textures/Terrain/PBR/Marble013_1K_Normal.png");
+        normalMapGrass.setWrap(WrapMode.Repeat);
+        
+        Texture normalMapTiles = assetManager.loadTexture("Textures/Terrain/PBR/Tiles083_1K_Normal.png");
+        normalMapTiles.setWrap(WrapMode.Repeat);        
+
+        
+        matTerrain.setTexture("NormalMap_0", normalMapDirt);
+        matTerrain.setTexture("NormalMap_1", normalMapDarkRock);
+        matTerrain.setTexture("NormalMap_2", normalMapSnow);
+        matTerrain.setTexture("NormalMap_3", normalMapTiles);
+        matTerrain.setTexture("NormalMap_4", normalMapGrass);
+   //     matTerrain.setTexture("NormalMap_5", normalMapMarble);  //using this texture will surpass the 16 texture limit
+        matTerrain.setTexture("NormalMap_6", normalMapGravel);
+                
+        terrain.setMaterial(matTerrain);
+    }
+    
+    private void setupKeys() {
+        flyCam.setMoveSpeed(50);
+        inputManager.addMapping("triPlanar", new KeyTrigger(KeyInput.KEY_P));
+        inputManager.addMapping("toggleNight", new KeyTrigger(KeyInput.KEY_N));
+        
+        inputManager.addListener(actionListener, "triPlanar");
+        inputManager.addListener(actionListener, "toggleNight");        
+        
+        keybindingsText = new BitmapText(assetManager.loadFont("Interface/Fonts/Default.fnt"));
+        keybindingsText.setText("Press 'N' to toggle day/night fade (takes a moment) \nPress 'P' to toggle tri-planar mode");
+        
+        getGuiNode().attachChild(keybindingsText);
+        keybindingsText.move(new Vector3f(200,120,0));
+        
+    }
+    
+    @Override
+    public void simpleUpdate(float tpf) {
+        super.simpleUpdate(tpf);
+        
+          //smoothly transition from day to night        
+        float currentLightIntensity = ambientLight.getColor().getRed();        
+        float incrementPerFrame = tpf * 0.3f;
+        
+        if(isNight){
+            
+            if(ambientLight.getColor().getRed() > nightLightIntensity){
+                currentLightIntensity -= incrementPerFrame;
+                if(currentLightIntensity < nightLightIntensity){
+                    currentLightIntensity = nightLightIntensity;
+                }
+                
+                ambientLight.getColor().set(currentLightIntensity, currentLightIntensity, currentLightIntensity, 1.0f);
+                directionalLight.getColor().set(currentLightIntensity, currentLightIntensity, currentLightIntensity, 1.0f);
+            }
+        }
+        
+        else{
+            
+            if(ambientLight.getColor().getRed() < dayLightIntensity){
+                currentLightIntensity += incrementPerFrame;
+                if(currentLightIntensity > dayLightIntensity){
+                    currentLightIntensity = dayLightIntensity;
+                }
+                
+                ambientLight.getColor().set(currentLightIntensity, currentLightIntensity, currentLightIntensity, 1.0f);
+                directionalLight.getColor().set(currentLightIntensity, currentLightIntensity, currentLightIntensity, 1.0f);
+            }            
+        }        
+    }
+
+    private void setUpTerrain() {
+        // HEIGHTMAP image (for the terrain heightmap)
+        TextureKey hmKey = new TextureKey("Textures/Terrain/splat/mountains512.png", false);
+        Texture heightMapImage = assetManager.loadTexture(hmKey);
+
+        // CREATE HEIGHTMAP
+        AbstractHeightMap heightmap = null;
+        try {
+            heightmap = new ImageBasedHeightMap(heightMapImage.getImage(), 0.3f);
+            heightmap.load();
+            heightmap.smooth(0.9f, 1);
+
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        
+        terrain = new TerrainQuad("terrain", patchSize + 1, terrainSize + 1, heightmap.getHeightMap());//, new LodPerspectiveCalculatorFactory(getCamera(), 4)); // add this in to see it use entropy for LOD calculations
+        TerrainLodControl control = new TerrainLodControl(terrain, getCamera());
+        control.setLodCalculator(new DistanceLodCalculator(patchSize + 1, 2.7f)); // patch size, and a multiplier
+        terrain.addControl(control);
+        terrain.setMaterial(matTerrain);
+        terrain.setLocalTranslation(0, -100, 0);
+        terrain.setLocalScale(1f, 1f, 1f);
+        rootNode.attachChild(terrain);        
+        
+    }
+
+    private void setUpLights() {
+        
+        LightProbe probe = (LightProbe) assetManager.loadAsset("Scenes/LightProbes/quarry_Probe.j3o");
+        
+        probe.setAreaType(LightProbe.AreaType.Spherical);      
+        probe.getArea().setRadius(2000);
+        probe.getArea().setCenter(new Vector3f(0, 0, 0));        
+        rootNode.addLight(probe);
+        
+        directionalLight = new DirectionalLight();
+        directionalLight.setDirection((new Vector3f(-0.3f, -0.5f, -0.3f)).normalize());
+        directionalLight.setColor(ColorRGBA.White);
+        rootNode.addLight(directionalLight);
+        
+        ambientLight = new AmbientLight();
+        directionalLight.setColor(ColorRGBA.White);
+        rootNode.addLight(ambientLight);        
+    }
+
+    private void setUpCamera() {
+        cam.setLocation(new Vector3f(0, 10, -10));
+        cam.lookAtDirection(new Vector3f(0, -1.5f, -1).normalizeLocal(), Vector3f.UNIT_Y);
+        
+        getFlyByCamera().setMoveSpeed(camMoveSpeed);        
+    }    
+}
+

+ 1358 - 0
jme3-terrain/src/main/resources/Common/MatDefs/Terrain/AdvancedPBRTerrain.frag

@@ -0,0 +1,1358 @@
+#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"
+
+
+
+#ifdef DEBUG_VALUES_MODE
+  uniform int m_DebugValuesMode;
+#endif
+
+uniform vec4 g_LightData[NB_LIGHTS];
+
+uniform vec4 g_AmbientLightColor;
+
+varying vec3 wPosition;
+varying vec3 vNormal;
+varying vec2 texCoord;
+
+#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
+
+vec2 newTexCoord;
+
+
+uniform vec3 g_CameraPosition;
+
+
+#ifdef USE_FOG
+  #import "Common/ShaderLib/MaterialFog.glsllib"
+  uniform vec4 m_FogColor;
+  float fogDistance;
+
+  uniform vec2 m_LinearFog;
+#endif
+
+#ifdef FOG_EXP
+  uniform float m_ExpFog;
+#endif
+
+#ifdef FOG_EXPSQ
+  uniform float m_ExpSqFog;
+#endif
+
+
+
+
+varying vec3 vPosition;
+varying vec3 vnPosition;
+varying vec3 vViewDir;
+varying vec4 vLightDir;
+varying vec4 vnLightDir;
+varying vec3 lightVec;
+varying vec3 inNormal;
+
+vec3 norm;
+
+uniform sampler2DArray m_AlbedoTextureArray;
+uniform sampler2DArray m_NormalParallaxTextureArray;
+uniform sampler2DArray m_MetallicRoughnessAoEiTextureArray;
+
+
+#ifdef DISCARD_ALPHA
+    uniform float m_AlphaDiscardThreshold;
+#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
+
+
+
+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 vec4 m_EmissiveColor_0;
+uniform vec4 m_EmissiveColor_1;
+uniform vec4 m_EmissiveColor_2;
+uniform vec4 m_EmissiveColor_3;
+uniform vec4 m_EmissiveColor_4;
+uniform vec4 m_EmissiveColor_5;
+uniform vec4 m_EmissiveColor_6;
+uniform vec4 m_EmissiveColor_7;
+uniform vec4 m_EmissiveColor_8;
+uniform vec4 m_EmissiveColor_9;
+uniform vec4 m_EmissiveColor_10;
+uniform vec4 m_EmissiveColor_11;
+
+
+
+#ifdef ALBEDOMAP_0
+  uniform int m_AlbedoMap_0;
+#endif
+#ifdef ALBEDOMAP_1
+  uniform int m_AlbedoMap_1;
+#endif
+#ifdef ALBEDOMAP_2
+  uniform int m_AlbedoMap_2;
+#endif
+#ifdef ALBEDOMAP_3
+  uniform int m_AlbedoMap_3;
+#endif
+#ifdef ALBEDOMAP_4
+  uniform int m_AlbedoMap_4;
+#endif
+#ifdef ALBEDOMAP_5
+  uniform int m_AlbedoMap_5;
+#endif
+#ifdef ALBEDOMAP_6
+  uniform int m_AlbedoMap_6;
+#endif
+#ifdef ALBEDOMAP_7
+  uniform int m_AlbedoMap_7;
+#endif
+#ifdef ALBEDOMAP_8
+  uniform int m_AlbedoMap_8;
+#endif
+#ifdef ALBEDOMAP_9
+  uniform int m_AlbedoMap_9;
+#endif
+#ifdef ALBEDOMAP_10
+  uniform int m_AlbedoMap_10;
+#endif
+#ifdef ALBEDOMAP_11
+  uniform int m_AlbedoMap_11;
+#endif
+
+
+
+
+uniform float m_AlbedoMap_0_scale;
+uniform float m_AlbedoMap_1_scale;
+uniform float m_AlbedoMap_2_scale;
+uniform float m_AlbedoMap_3_scale;
+uniform float m_AlbedoMap_4_scale;
+uniform float m_AlbedoMap_5_scale;
+uniform float m_AlbedoMap_6_scale;
+uniform float m_AlbedoMap_7_scale;
+uniform float m_AlbedoMap_8_scale;
+uniform float m_AlbedoMap_9_scale;
+uniform float m_AlbedoMap_10_scale;
+uniform float m_AlbedoMap_11_scale;
+
+
+#ifdef NORMALMAP_0
+  uniform int m_NormalMap_0;
+#endif
+#ifdef NORMALMAP_1
+  uniform int m_NormalMap_1;
+#endif
+#ifdef NORMALMAP_2
+  uniform int m_NormalMap_2;
+#endif
+#ifdef NORMALMAP_3
+  uniform int m_NormalMap_3;
+#endif
+#ifdef NORMALMAP_4
+  uniform int m_NormalMap_4;
+#endif
+#ifdef NORMALMAP_5
+  uniform int m_NormalMap_5;
+#endif
+#ifdef NORMALMAP_6
+  uniform int m_NormalMap_6;
+#endif
+#ifdef NORMALMAP_7
+  uniform int m_NormalMap_7;
+#endif
+#ifdef NORMALMAP_8
+  uniform int m_NormalMap_8;
+#endif
+#ifdef NORMALMAP_9
+  uniform int m_NormalMap_9;
+#endif
+#ifdef NORMALMAP_10
+  uniform int m_NormalMap_10;
+#endif
+#ifdef NORMALMAP_11
+  uniform int m_NormalMap_11;
+#endif
+
+
+#ifdef METALLICROUGHNESSMAP_0
+  uniform int m_MetallicRoughnessMap_0;
+#endif
+#ifdef METALLICROUGHNESSMAP_1
+  uniform int m_MetallicRoughnessMap_1;
+#endif
+#ifdef METALLICROUGHNESSMAP_2
+  uniform int m_MetallicRoughnessMap_2;
+#endif
+#ifdef METALLICROUGHNESSMAP_3
+  uniform int m_MetallicRoughnessMap_3;
+#endif
+#ifdef METALLICROUGHNESSMAP_4
+  uniform int m_MetallicRoughnessMap_4;
+#endif
+#ifdef METALLICROUGHNESSMAP_5
+  uniform int m_MetallicRoughnessMap_5;
+#endif
+#ifdef METALLICROUGHNESSMAP_6
+  uniform int m_MetallicRoughnessMap_6;
+#endif
+#ifdef METALLICROUGHNESSMAP_7
+  uniform int m_MetallicRoughnessMap_7;
+#endif
+#ifdef METALLICROUGHNESSMAP_8
+  uniform int m_MetallicRoughnessMap_8;
+#endif
+#ifdef METALLICROUGHNESSMAP_9
+  uniform int m_MetallicRoughnessMap_9;
+#endif
+#ifdef METALLICROUGHNESSMAP_10
+  uniform int m_MetallicRoughnessMap_10;
+#endif
+#ifdef METALLICROUGHNESSMAP_11
+  uniform int m_MetallicRoughnessMap_11;
+#endif
+
+
+#if defined(USE_VERTEX_COLORS_AS_SUN_INTENSITY) 
+    varying vec4 vertColors;
+#endif
+
+#ifdef STATIC_SUN_INTENSITY
+    uniform float m_StaticSunIntensity;
+#endif
+
+float brightestPointLight = 0.0;
+
+
+
+vec4 afflictionVector;
+//Optional 'Affliction' variables (used for dynamic desaturation and texture splatting)
+#ifdef AFFLICTIONTEXTURE
+    uniform sampler2D m_AfflictionAlphaMap;
+#endif
+
+#ifdef USE_SPLAT_NOISE
+     uniform float m_SplatNoiseVar;
+#endif
+
+//defined for sub terrains that arent equal to each map tile size
+#ifdef TILELOCATION
+    uniform float m_TileWidth;
+    uniform vec3 m_TileLocation;
+#endif
+
+uniform int m_AfflictionSplatScale;
+#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 float m_AfflictionRoughnessValue;
+uniform float m_AfflictionMetallicValue;
+uniform float m_AfflictionEmissiveValue;
+uniform vec4 m_AfflictionEmissiveColor;
+
+
+
+uniform int m_AfflictionMode_0;
+uniform int m_AfflictionMode_1;
+uniform int m_AfflictionMode_2;
+uniform int m_AfflictionMode_3;
+uniform int m_AfflictionMode_4;
+uniform int m_AfflictionMode_5;
+uniform int m_AfflictionMode_6;
+uniform int m_AfflictionMode_7;
+uniform int m_AfflictionMode_8;
+uniform int m_AfflictionMode_9;
+uniform int m_AfflictionMode_10;
+uniform int m_AfflictionMode_11;
+
+
+
+
+
+
+  varying vec3 wNormal;
+
+#ifdef TRI_PLANAR_MAPPING
+  varying vec4 wVertex;
+
+#endif
+
+vec3 viewDir;
+
+
+
+
+vec2 coord;
+vec4 albedo;
+vec3 normal = vec3(0.5,0.5,1);
+vec3 newNormal;
+float Metallic;
+float Roughness;
+float packedAoValue = 1.0;
+vec4 emissive;
+float emissiveIntensity = 1.0;
+
+vec4 packedMetallicRoughnessAoEiVec;
+vec4 packedNormalParallaxVec;
+
+vec4 tempAlbedo, tempNormal, tempEmissiveColor;
+float tempParallax, tempMetallic, tempRoughness, tempAo, tempEmissiveIntensity;
+
+float noiseHash;
+float livelinessValue;
+float afflictionValue;
+int afflictionMode = 1;
+
+
+#define DEFINE_COORD(index) vec2 coord##index = texCoord * m_AlbedoMap##index##_scale;
+
+
+
+
+#define BLEND_MR_VALUES(index, ab)\
+    packedAoValue = mix(packedAoValue , 1, ab);\
+    Metallic = mix(Metallic, m_Metallic##index, ab);\
+    Roughness = mix(Roughness, m_Roughness##index, ab);\
+    emissive = mix(emissive, m_EmissiveColor##index, ab);
+    
+#define BLEND_MRAOEI_MAP(index, ab)\
+    packedMetallicRoughnessAoEiVec.rgba = texture2DArray(m_MetallicRoughnessAoEiTextureArray, vec3(coord##index, m_MetallicRoughnessMap##index)).rgba;\
+    tempRoughness = packedMetallicRoughnessAoEiVec.g* m_Roughness##index;\
+    tempMetallic = m_Metallic##index;\
+    tempMetallic = tempMetallic * packedMetallicRoughnessAoEiVec.b;\
+    tempAo = packedMetallicRoughnessAoEiVec.r;\
+    tempEmissiveIntensity = packedMetallicRoughnessAoEiVec.a;\
+    emissiveIntensity = mix(emissiveIntensity, tempEmissiveIntensity, ab);\
+    tempEmissiveColor = m_EmissiveColor##index;\
+    tempEmissiveColor *= tempEmissiveIntensity;\
+    packedAoValue = mix(packedAoValue, tempAo, ab);\
+    Metallic = mix(Metallic, tempMetallic, ab);\
+    Roughness = mix(Roughness, tempRoughness, ab);\
+    emissive = mix(emissive, tempEmissiveColor, ab);
+    
+
+
+
+#define BLEND(index, ab)\
+    afflictionMode = m_AfflictionMode##index;\
+    tempAlbedo.rgb =  texture2DArray(m_AlbedoTextureArray, vec3(coord##index, m_AlbedoMap##index)).rgb;\
+    tempAlbedo.rgb = alterLiveliness(tempAlbedo.rgb, livelinessValue, afflictionMode);\
+    albedo.rgb = mix( albedo.rgb, tempAlbedo.rgb ,ab );\
+    normal.rgb = mix(normal.xyz, wNormal.rgb, ab);
+ 
+   
+
+#define BLEND_NORMAL(index, ab)\
+    afflictionMode = m_AfflictionMode##index;\
+    tempAlbedo.rgb =  texture2DArray(m_AlbedoTextureArray, vec3(coord##index, m_AlbedoMap##index)).rgb;\
+    tempAlbedo.rgb = alterLiveliness(tempAlbedo.rgb, livelinessValue, afflictionMode);\
+    albedo.rgb = mix( albedo.rgb, tempAlbedo.rgb ,ab );\
+    packedNormalParallaxVec.rgba = texture2DArray(m_NormalParallaxTextureArray, vec3(coord##index,  m_NormalMap##index)).rgba;\
+    tempNormal.xyz = calculateTangentsAndApplyToNormals(packedNormalParallaxVec.xyz, wNormal);\
+    normal.xyz = mix(normal.xyz, tempNormal.xyz, ab);
+    
+    
+#define TRI_BLEND_MR_VALUES(index, ab)\
+    packedAoValue = mix(packedAoValue , 1, ab);\
+    Metallic = mix(Metallic, m_Metallic##index, ab);\
+    Roughness = mix(Roughness, m_Roughness##index, ab);\
+    emissive = mix(emissive, m_EmissiveColor##index, ab);
+    
+#define TRI_BLEND_MRAOEI_MAP(worldCoords, index, ab, blending)\
+    packedMetallicRoughnessAoEiVec.rgba = getTriPlanarBlendFromTexArray(worldCoords, blending, m_MetallicRoughnessMap##index, m_AlbedoMap##index##_scale, m_MetallicRoughnessAoEiTextureArray).rgba;\
+    tempRoughness = packedMetallicRoughnessAoEiVec.g* m_Roughness##index;\
+    tempMetallic = m_Metallic##index;\
+    tempMetallic = tempMetallic * packedMetallicRoughnessAoEiVec.b;\
+    tempAo = packedMetallicRoughnessAoEiVec.r;\
+    tempEmissiveIntensity = packedMetallicRoughnessAoEiVec.a;\
+    emissiveIntensity = mix(emissiveIntensity, tempEmissiveIntensity, ab);\
+    tempEmissiveColor = m_EmissiveColor##index;\
+    tempEmissiveColor *= tempEmissiveIntensity;\
+    packedAoValue = mix(packedAoValue, tempAo, ab);\
+    Metallic = mix(Metallic, tempMetallic, ab);\
+    Roughness = mix(Roughness, tempRoughness, ab);\
+    emissive = mix(emissive, tempEmissiveColor, ab);
+
+#define TRI_BLEND(index, ab, worldCoords, blending)\
+    afflictionMode = m_AfflictionMode##index;\
+    tempAlbedo = getTriPlanarBlendFromTexArray(worldCoords, blending, m_AlbedoMap##index, m_AlbedoMap##index##_scale, m_AlbedoTextureArray);\
+    tempAlbedo.rgb = alterLiveliness(tempAlbedo.rgb, livelinessValue, afflictionMode);\
+    albedo = mix( albedo, tempAlbedo ,ab );\
+    normal.rgb = mix(normal.xyz, wNormal.rgb, ab);    
+
+   
+
+#define TRI_BLEND_NORMAL(index, ab, worldCoords, blending)\
+    afflictionMode = m_AfflictionMode##index;\
+    tempAlbedo.rgb = getTriPlanarBlendFromTexArray(worldCoords, blending, m_AlbedoMap##index, m_AlbedoMap##index##_scale, m_AlbedoTextureArray).rgb;\
+    packedNormalParallaxVec.rgba = getTriPlanarBlendFromTexArray(worldCoords, blending, m_NormalMap##index, m_AlbedoMap##index##_scale, m_NormalParallaxTextureArray).rgba;\
+    tempAlbedo.rgb = alterLiveliness(tempAlbedo.rgb, livelinessValue, afflictionMode);\
+    albedo.rgb = mix( albedo.rgb, tempAlbedo.rgb ,ab );\
+    tempNormal.xyz = packedNormalParallaxVec.xyz;\
+    tempNormal.xyz = calculateTangentsAndApplyToNormals(tempNormal.xyz, wNormal);\
+    normal.xyz = mix(normal.xyz, tempNormal.xyz, ab);
+    
+    
+
+
+    
+    
+ #define BLEND_PARALLAX(index, ab)\
+    albedo.r = alvedo.r;
+    
+
+
+#ifdef ALPHAMAP
+
+//parallax removed for now
+// calculateParallax(coord##index, m_ParallaxHeight##index, ab, m_NormalMap##index);
+
+void calculateParallax(inout vec2 parallaxTexCoord, in float parallaxHeight, in float intensity, in int texIndex) {
+//    #ifdef PARALLAX_OCCLUSION
+//        #ifdef PARALLAX_LOD_DISTANCE  
+//            if(camDist < m_ParallaxLODDistance && intensity > 0.2){
+//                vec3 vViewDir =  viewDir * tbnMat;
+//                Parallax_initFor(vViewDir,parallaxHeight);
+//                Parallax_TextureArray_displaceCoords(parallaxTexCoord, m_NormalParallaxTextureArray, texIndex);
+//            }
+//        #else
+//            if(intensity > 0.2){
+//                vec3 vViewDir =  viewDir * tbnMat;
+//                Parallax_initFor(vViewDir,parallaxHeight);
+//                Parallax_TextureArray_displaceCoords(parallaxTexCoord, m_NormalParallaxTextureArray, texIndex);
+//            }
+//        #endif
+ //   #else
+//      #ifdef STEEP_PARALLAX
+           //parallax map is stored in the alpha channel of the normal map         
+ //          newTexCoord = steepParallaxOffset(m_NormalMap, vViewDir, texCoord, m_ParallaxHeight);    
+ //       #else
+                //parallax map is stored in the alpha channel of the normal map         
+//            newTexCoord = classicParallaxOffset(m_NormalMap, vViewDir, texCoord, m_ParallaxHeight);
+//        #endif
+    
+ //   #endif
+}
+
+void calculateTriParallax(inout vec2 parallaxTexCoord, in float parallaxHeight, in float intensity, in int texIndex) {
+//    #ifdef PARALLAX_OCCLUSION
+//        #ifdef PARALLAX_LOD_DISTANCE  
+//            if(camDist < m_ParallaxLODDistance && intensity > 0.2){
+//                vec3 vViewDir =  viewDir * tbnMat;
+//                Parallax_initFor(vViewDir,parallaxHeight);
+//                Tri_Parallax_TextureArray_displaceCoords(parallaxTexCoord, m_NormalParallaxTextureArray, texIndex);
+//            }
+//        #else
+//            if(intensity > 0.2){
+//                vec3 vViewDir =  viewDir * tbnMat;
+//                Parallax_initFor(vViewDir,parallaxHeight);
+//                Tri_Parallax_TextureArray_displaceCoords(parallaxTexCoord, m_NormalParallaxTextureArray, texIndex);
+//            }
+//        #endif
+ //   #else
+//      #ifdef STEEP_PARALLAX
+           //parallax map is stored in the alpha channel of the normal map         
+ //          newTexCoord = steepParallaxOffset(m_NormalMap, vViewDir, texCoord, m_ParallaxHeight);    
+ //       #else
+                //parallax map is stored in the alpha channel of the normal map         
+//            newTexCoord = classicParallaxOffset(m_NormalMap, vViewDir, texCoord, m_ParallaxHeight);
+//        #endif
+    
+ //   #endif
+}
+
+
+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;
+}
+
+vec4 calculateAlbedoBlend(in vec2 texCoord) {
+    vec4 alphaBlend = texture2D( m_AlphaMap, texCoord.xy );
+    vec4 albedo = vec4(1.0);
+    
+    
+
+    Roughness = m_Roughness_0;
+    Metallic = m_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);
+
+
+    #ifdef ALPHAMAP_1
+      vec4 alphaBlend1   = texture2D( m_AlphaMap_1, texCoord.xy );
+    #endif
+    #ifdef ALPHAMAP_2
+      vec4 alphaBlend2   = texture2D( m_AlphaMap_2, texCoord.xy );
+    #endif
+    #ifdef ALBEDOMAP_0   
+                    //NOTE! the old (phong) TerrainLighting.j3md shadesr do not have an "_0" for the first diffuse map, it is just "DiffuseMap"
+        DEFINE_COORD(_0)
+        #ifdef PARALLAXHEIGHT_0
+            BLEND_PARALLAX(_0, alphaBlend.r)
+        #endif
+        
+        #ifdef NORMALMAP_0
+            BLEND_NORMAL(_0,  alphaBlend.r)
+        #else
+            BLEND(_0,  alphaBlend.r)
+        #endif
+        #ifdef METALLICROUGHNESSMAP_0            
+            BLEND_MRAOEI_MAP(_0,  alphaBlend.r)
+        #else
+            BLEND_MR_VALUES(_0,  alphaBlend.r)
+        #endif
+        
+    #endif
+    #ifdef ALBEDOMAP_1
+        DEFINE_COORD(_1)
+        #ifdef PARALLAXHEIGHT_1
+            BLEND_PARALLAX(_1, alphaBlend.g)
+        #endif
+                
+        #ifdef NORMALMAP_1
+            BLEND_NORMAL(_1,  alphaBlend.g)
+        #else
+            BLEND(_1,  alphaBlend.g)
+        #endif
+        #ifdef METALLICROUGHNESSMAP_1
+            BLEND_MRAOEI_MAP(_1,  alphaBlend.g)
+        #else
+            BLEND_MR_VALUES(_1,  alphaBlend.g)
+        #endif
+        
+    #endif
+    #ifdef ALBEDOMAP_2
+        DEFINE_COORD(_2)
+        
+        #ifdef PARALLAXHEIGHT_2
+            BLEND_PARALLAX(_2, alphaBlend.b)
+        #endif
+        
+        #ifdef NORMALMAP_2
+            BLEND_NORMAL(_2,  alphaBlend.b)
+        #else
+            BLEND(_2,  alphaBlend.b)
+        #endif
+        #ifdef METALLICROUGHNESSMAP_2
+            BLEND_MRAOEI_MAP(_2,  alphaBlend.b)
+        #else
+            BLEND_MR_VALUES(_2,  alphaBlend.b)
+        #endif        
+        
+        
+    #endif
+    #ifdef ALBEDOMAP_3 
+        DEFINE_COORD(_3)
+         #ifdef PARALLAXHEIGHT_3
+            BLEND_PARALLAX(_3, alphaBlend.a)
+        #endif
+        
+        #ifdef NORMALMAP_3
+            BLEND_NORMAL(_3,  alphaBlend.a)
+        #else
+            BLEND(_3,  alphaBlend.a)
+        #endif
+        #ifdef METALLICROUGHNESSMAP_3
+            BLEND_MRAOEI_MAP(_3,  alphaBlend.a)
+        #else
+            BLEND_MR_VALUES(_3,  alphaBlend.a)
+        #endif
+    #endif
+
+    #ifdef ALPHAMAP_1
+        #ifdef ALBEDOMAP_4
+            DEFINE_COORD(_4)
+            #ifdef PARALLAXHEIGHT_4
+                  BLEND_PARALLAX(_4, alphaBlend.r)
+            #endif
+        
+            #ifdef NORMALMAP_4
+                BLEND_NORMAL(_4,  alphaBlend1.r)
+            #else
+                BLEND(_4,  alphaBlend1.r)
+            #endif
+            #ifdef METALLICROUGHNESSMAP_4
+                BLEND_MRAOEI_MAP(_4,  alphaBlend1.r)
+            #else
+                BLEND_MR_VALUES(_4,  alphaBlend1.r)
+            #endif
+           
+        #endif
+        #ifdef ALBEDOMAP_5
+            DEFINE_COORD(_5)
+            #ifdef PARALLAXHEIGHT_5
+                BLEND_PARALLAX(_5, alphaBlend.g)
+            #endif
+            #ifdef NORMALMAP_5
+                BLEND_NORMAL(_5,  alphaBlend1.g)
+            #else
+                BLEND(_5,  alphaBlend1.g)
+            #endif
+            #ifdef METALLICROUGHNESSMAP_5
+                BLEND_MRAOEI_MAP(_5,  alphaBlend1.g)
+            #else
+                BLEND_MR_VALUES(_5,  alphaBlend1.g)
+            #endif
+             
+        #endif
+        #ifdef ALBEDOMAP_6
+            DEFINE_COORD(_6)
+             #ifdef PARALLAXHEIGHT_6
+                BLEND_PARALLAX(_6, alphaBlend.b)
+            #endif
+            #ifdef NORMALMAP_6
+                BLEND_NORMAL(_6,  alphaBlend1.b)
+            #else
+                BLEND(_6,  alphaBlend1.b)
+            #endif
+            #ifdef METALLICROUGHNESSMAP_6
+                BLEND_MRAOEI_MAP(_6,  alphaBlend1.b)
+            #else
+                BLEND_MR_VALUES(_6,  alphaBlend1.b)
+            #endif
+            
+             
+        #endif
+        #ifdef ALBEDOMAP_7
+            DEFINE_COORD(_7)
+             #ifdef PARALLAXHEIGHT_7
+                BLEND_PARALLAX(_7, alphaBlend.a)
+            #endif
+            #ifdef NORMALMAP_7
+                BLEND_NORMAL(_7,  alphaBlend1.a)
+            #else
+                BLEND(_7,  alphaBlend1.a)
+            #endif
+            #ifdef METALLICROUGHNESSMAP_7
+                BLEND_MRAOEI_MAP(_7,  alphaBlend1.a)
+            #else
+                BLEND_MR_VALUES(_7,  alphaBlend1.a)
+            #endif
+             
+        #endif
+    #endif
+
+    #ifdef ALPHAMAP_2
+        #ifdef ALBEDOMAP_8
+            DEFINE_COORD(_8)
+             #ifdef PARALLAXHEIGHT_8
+                BLEND_PARALLAX(_8, alphaBlend.r)
+            #endif
+             #ifdef NORMALMAP_8
+                BLEND_NORMAL(_8,  alphaBlend2.r)
+            #else
+                BLEND(_8,  alphaBlend2.r)
+            #endif
+            #ifdef METALLICROUGHNESSMAP_8
+                BLEND_MRAOEI_MAP(_8,  alphaBlend2.r)
+            #else
+                BLEND_MR_VALUES(_8,  alphaBlend2.r)
+            #endif
+             
+        #endif
+        #ifdef ALBEDOMAP_9
+            DEFINE_COORD(_9)
+             #ifdef PARALLAXHEIGHT_9
+                BLEND_PARALLAX(_9, alphaBlend.g)
+            #endif
+             #ifdef NORMALMAP_9
+                BLEND_NORMAL(_9,  alphaBlend2.g)
+            #else
+                BLEND(_9,  alphaBlend2.g)
+            #endif
+            #ifdef METALLICROUGHNESSMAP_8
+                BLEND_MRAOEI_MAP(_9,  alphaBlend2.g)
+            #else
+                BLEND_MR_VALUES(_9,  ,alphaBlend2.g)
+            #endif
+             
+        #endif
+        #ifdef ALBEDOMAP_10
+            DEFINE_COORD(_10)
+             #ifdef PARALLAXHEIGHT_10
+                BLEND_PARALLAX(_10, alphaBlend.b)
+            #endif
+            #ifdef NORMALMAP_10
+                BLEND_NORMAL(_10,  alphaBlend2.b)
+            #else
+                BLEND(_10,  alphaBlend2.b)
+            #endif
+            #ifdef METALLICROUGHNESSMAP_8
+                BLEND_MRAOEI_MAP(_10,  alphaBlend2.b)
+            #else
+                BLEND_MR_VALUES(_10,  alphaBlend2.b)
+            #endif
+            
+        #endif
+        #ifdef ALBEDOMAP_11
+             DEFINE_COORD(_11)
+              #ifdef PARALLAXHEIGHT_11
+                BLEND_PARALLAX(_11, alphaBlend.a)
+            #endif
+             #ifdef NORMALMAP_11
+                BLEND_NORMAL(_11,  alphaBlend2.a)
+            #else
+                BLEND(_11,  alphaBlend2.a)
+            #endif
+            #ifdef METALLICROUGHNESSMAP_8
+                BLEND_MRAOEI_MAP(_11,  alphaBlend2.a)
+            #else
+                BLEND_MR_VALUES(_11,  alphaBlend2.a)
+            #endif
+             
+        #endif                   
+    #endif
+
+    return albedo;
+  }
+
+
+// TRI PLANAR ALPHA MAP TEXTURES_ _ _ _    \/
+
+  #ifdef TRI_PLANAR_MAPPING
+
+
+    vec4 calculateTriPlanarAlbedoBlend(in vec3 wNorm, in vec4 wVert, in vec2 texCoord, vec3 blending) {
+            // tri-planar texture bending factor for this fragment's normal
+         vec4 alphaBlend = texture2D( m_AlphaMap, texCoord.xy );
+        vec4 albedo = vec4(1.0);
+
+
+
+        Roughness = m_Roughness_0;
+        Metallic = m_Metallic_0 ;
+
+    
+
+
+        #ifdef ALPHAMAP_1
+          vec4 alphaBlend1   = texture2D( m_AlphaMap_1, texCoord.xy );
+        #endif
+        #ifdef ALPHAMAP_2
+          vec4 alphaBlend2   = texture2D( m_AlphaMap_2, texCoord.xy );
+        #endif
+        
+        #ifdef ALBEDOMAP_0   
+                        //NOTE! the old (phong) terrain shaders do not have an "_0" for the first diffuse map, it is just "DiffuseMap"
+            #ifdef NORMALMAP_0
+                TRI_BLEND_NORMAL(_0,  alphaBlend.r, wVertex, blending)
+            #else
+                TRI_BLEND(_0,  alphaBlend.r, wVertex, blending)
+            #endif            
+            #ifdef METALLICROUGHNESSMAP_0
+                TRI_BLEND_MRAOEI_MAP(wVertex,_0,  alphaBlend.r, blending)
+            #else
+                TRI_BLEND_MR_VALUES(_0,  alphaBlend.r)
+            #endif
+
+        #endif
+        #ifdef ALBEDOMAP_1
+            #ifdef NORMALMAP_1
+                TRI_BLEND_NORMAL(_1,  alphaBlend.g, wVertex, blending)
+            #else
+                TRI_BLEND(_1,  alphaBlend.g, wVertex, blending)
+            #endif            
+            #ifdef METALLICROUGHNESSMAP_1
+                TRI_BLEND_MRAOEI_MAP(wVertex,_1,  alphaBlend.g, blending)
+            #else
+                TRI_BLEND_MR_VALUES(_1,  alphaBlend.g)
+            #endif
+
+        #endif
+        #ifdef ALBEDOMAP_2
+            #ifdef NORMALMAP_2
+                TRI_BLEND_NORMAL(_2,  alphaBlend.b, wVertex, blending)
+            #else
+                TRI_BLEND(_2,  alphaBlend.b, wVertex, blending)
+            #endif            
+            #ifdef METALLICROUGHNESSMAP_2
+                TRI_BLEND_MRAOEI_MAP(wVertex,_2,  alphaBlend.b, blending)
+            #else
+                TRI_BLEND_MR_VALUES(_2,  alphaBlend.b)
+            #endif
+
+        #endif
+        #ifdef ALBEDOMAP_3 
+            #ifdef NORMALMAP_3
+                TRI_BLEND_NORMAL(_3,  alphaBlend.a, wVertex, blending)
+            #else
+                TRI_BLEND(_3,  alphaBlend.a, wVertex, blending)
+            #endif            
+            #ifdef METALLICROUGHNESSMAP_3
+                TRI_BLEND_MRAOEI_MAP(wVertex,_3,  alphaBlend.a, blending)
+            #else
+                TRI_BLEND_MR_VALUES(_3,  alphaBlend.a)
+            #endif
+
+        #endif
+
+        #ifdef ALPHAMAP_1
+            #ifdef ALBEDOMAP_4
+                #ifdef NORMALMAP_4
+                    TRI_BLEND_NORMAL(_4,  alphaBlend1.r, wVertex, blending)
+                #else
+                    TRI_BLEND(_4,  alphaBlend1.r, wVertex, blending)
+                #endif                
+                #ifdef METALLICROUGHNESSMAP_4
+                    TRI_BLEND_MRAOEI_MAP(wVertex,_4,  alphaBlend1.r, blending)
+                #else
+                    TRI_BLEND_MR_VALUES(_4,  alphaBlend1.r)
+                #endif
+
+            #endif
+            #ifdef ALBEDOMAP_5
+                #ifdef NORMALMAP_5
+                    TRI_BLEND_NORMAL(_5,  alphaBlend1.g, wVertex, blending)
+                #else
+                    TRI_BLEND(_5,  alphaBlend1.g, wVertex, blending)
+                #endif
+                #ifdef METALLICROUGHNESSMAP_5
+                    TRI_BLEND_MRAOEI_MAP(wVertex,_5,  alphaBlend1.g, blending)
+                #else
+                    TRI_BLEND_MR_VALUES(_5,  alphaBlend1.g)
+                #endif
+
+            #endif
+            #ifdef ALBEDOMAP_6
+                #ifdef NORMALMAP_6
+                    TRI_BLEND_NORMAL(_6,  alphaBlend1.b, wVertex, blending)
+                #else
+                    TRI_BLEND(_6,  alphaBlend1.b, wVertex, blending)
+                #endif
+                #ifdef METALLICROUGHNESSMAP_6
+                    TRI_BLEND_MRAOEI_MAP(wVertex,_6,  alphaBlend1.b, blending)
+                #else
+                    TRI_BLEND_MR_VALUES(_6,  alphaBlend1.b)
+                #endif
+
+            #endif
+            #ifdef ALBEDOMAP_7
+                #ifdef NORMALMAP_7
+                    TRI_BLEND_NORMAL(_7,  alphaBlend1.a, wVertex, blending)
+                #else
+                    TRI_BLEND(_7,  alphaBlend1.a, wVertex, blending)
+                #endif
+                #ifdef METALLICROUGHNESSMAP_7
+                    TRI_BLEND_MRAOEI_MAP(wVertex,_7,  alphaBlend1.a, blending)
+                #else
+                    TRI_BLEND_MR_VALUES(_7,  alphaBlend1.a)
+                #endif
+
+            #endif
+        #endif
+
+        #ifdef ALPHAMAP_2
+            #ifdef ALBEDOMAP_8
+                 #ifdef NORMALMAP_8
+                    TRI_BLEND_NORMAL(_8,  alphaBlend2.r, wVertex, blending)
+                #else
+                    TRI_BLEND(_8,  alphaBlend2.r, wVertex, blending)
+                #endif
+                #ifdef METALLICROUGHNESSMAP_8
+                    TRI_BLEND_MRAOEI_MAP(wVertex,_8,  alphaBlend2.r, blending)
+                #else
+                    TRI_BLEND_MR_VALUES(_8,  alphaBlend2.r)
+                #endif
+
+            #endif
+            #ifdef ALBEDOMAP_9
+                 #ifdef NORMALMAP_9
+                    TRI_BLEND_NORMAL(_9,  alphaBlend2.g, wVertex, blending)
+                #else
+                    TRI_BLEND(_9,  alphaBlend2.g, wVertex, blending)
+                #endif
+                #ifdef METALLICROUGHNESSMAP_9
+                    TRI_BLEND_MRAOEI_MAP(wVertex,_9,  alphaBlend2.g, blending)
+                #else
+                    TRI_BLEND_MR_VALUES(_9,  alphaBlend2.g)
+                #endif
+
+            #endif
+            #ifdef ALBEDOMAP_10
+                #ifdef NORMALMAP_10
+                    TRI_BLEND_NORMAL(_10,  alphaBlend2.b, wVertex, blending)
+                #else
+                    TRI_BLEND(_10,  alphaBlend2.b, wVertex, blending)
+                #endif
+                #ifdef METALLICROUGHNESSMAP_10
+                    TRI_BLEND_MRAOEI_MAP(wVertex,_10,  alphaBlend2.b, blending)
+                #else
+                    TRI_BLEND_MR_VALUES(_10,  alphaBlend2.b)
+                #endif
+
+            #endif
+            #ifdef ALBEDOMAP_11
+                 #ifdef NORMALMAP_11
+                    TRI_BLEND_NORMAL(_11,  alphaBlend2.a, wVertex, blending)
+                #else
+                    TRI_BLEND(_11,  alphaBlend2.a, wVertex, blending)
+                #endif
+                #ifdef METALLICROUGHNESSMAP_11
+                    TRI_BLEND_MRAOEI_MAP(wVertex,_11,  alphaBlend2.a, blending)
+                #else
+                    TRI_BLEND_MR_VALUES(_11,  alphaBlend2.a)
+                #endif
+
+            #endif                   
+        #endif
+        
+
+
+        return albedo;
+    }
+
+    
+  #endif
+
+#endif
+
+
+
+void main(){    
+    
+    #ifdef USE_FOG
+        fogDistance = distance(g_CameraPosition, wPosition.xyz);
+    #endif
+    
+    float indoorSunLightExposure = 1.0;
+    
+    viewDir = normalize(g_CameraPosition - wPosition);
+
+    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)
+    
+    #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);
+
+            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
+    #endif
+
+    livelinessValue = afflictionVector.r;
+    afflictionValue = afflictionVector.g;
+
+
+
+
+    vec3 blending;
+    #ifdef ALBEDOMAP_0
+      #ifdef ALPHAMAP
+        #ifdef TRI_PLANAR_MAPPING
+             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);
+
+
+            albedo = calculateTriPlanarAlbedoBlend(wNormal, wVertex, texCoord, blending);
+            
+        #else
+            albedo = calculateAlbedoBlend(texCoord);
+        #endif
+      #else
+        albedo = texture2D(m_AlbedoMap_0, texCoord);
+      #endif
+    #endif
+
+    float alpha = albedo.a;
+    #ifdef DISCARD_ALPHA
+        if(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 = texture2D(m_SplatRoughnessMetallicMap, newScaledCoords);
+        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 = texture2D(m_SplatEmissiveMap, newScaledCoords);
+        afflictionEmissive *= emissiveMapColor;
+    #endif
+    
+    float adjustedAfflictionValue = afflictionValue;
+        #ifdef USE_SPLAT_NOISE
+            noiseHash = getStaticNoiseVar0(wPosition, afflictionValue * m_SplatNoiseVar);
+            
+            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);
+    
+    #ifdef AFFLICTIONTEXTURE
+        ao = alterAfflictionAo(afflictionValue, ao, vec3(afflictionAo), noiseHash); // alter the AO map for affliction values
+    #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);
+    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;
+            
+        #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
+
+
+
+    if(emissive.a > 0){    
+        emissive = emissive * pow(emissive.a * 5, emissiveIntensity) * emissiveIntensity * 20 * 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
+    #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 
+    
+    //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);               
+
+        }
+        
+    #endif
+    
+    gl_FragColor.a = albedo.a;
+
+}

+ 404 - 0
jme3-terrain/src/main/resources/Common/MatDefs/Terrain/AdvancedPBRTerrain.j3md

@@ -0,0 +1,404 @@
+// NOTE: Doesn't support OpenGL1
+MaterialDef Advanced PBR Terrain {
+
+    MaterialParameters {
+
+    
+        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 indooes can have the DirectionalLight dimmed accordingly.
+
+        Boolean BrightenIndoorShadows  //set true if shadows are enabled and indoor areas withour full sun exposure are too dark compared to when shadows are turned off in settings
+
+  
+        TextureArray AlbedoTextureArray
+        TextureArray NormalParallaxTextureArray -LINEAR
+        TextureArray MetallicRoughnessAoEiTextureArray -LINEAR
+
+
+
+        Int AfflictionSplatScale : 8
+        Float AfflictionRoughnessValue : 1.0
+        Float AfflictionMetallicValue : 0.0
+        Float AfflictionEmissiveValue : 0.0   //note that this is simplified into one value, rather than 2 with power and intensity like the regular pbr values.
+
+
+     // affliction texture splatting & desaturation functionality
+        Boolean UseTriplanarAfflictionMapping
+
+        Texture2D AfflictionAlphaMap
+
+        Texture2D SplatAlbedoMap  -LINEAR
+        Texture2D SplatNormalMap  -LINEAR
+        Texture2D SplatRoughnessMetallicMap -LINEAR
+        Texture2D SplatEmissiveMap -LINEAR
+
+        Color AfflictionEmissiveColor : 0.0 0.0 0.0 0.0
+
+        Float SplatNoiseVar
+
+
+        Int AfflictionMode_0 : 1
+        Int AfflictionMode_1 : 1
+        Int AfflictionMode_2 : 1
+        Int AfflictionMode_3 : 1
+        Int AfflictionMode_4 : 1
+        Int AfflictionMode_5 : 1
+        Int AfflictionMode_6 : 1
+        Int AfflictionMode_7 : 1
+        Int AfflictionMode_8 : 1
+        Int AfflictionMode_9 : 1
+        Int AfflictionMode_10 : 1
+        Int AfflictionMode_11 : 1
+
+        Color EmissiveColor_0 : 0.0 0.0 0.0 0.0
+        Color EmissiveColor_1 : 0.0 0.0 0.0 0.0
+        Color EmissiveColor_2 : 0.0 0.0 0.0 0.0
+        Color EmissiveColor_3 : 0.0 0.0 0.0 0.0
+        Color EmissiveColor_4 : 0.0 0.0 0.0 0.0
+        Color EmissiveColor_5 : 0.0 0.0 0.0 0.0
+        Color EmissiveColor_6 : 0.0 0.0 0.0 0.0
+        Color EmissiveColor_7 : 0.0 0.0 0.0 0.0
+        Color EmissiveColor_8 : 0.0 0.0 0.0 0.0
+        Color EmissiveColor_9 : 0.0 0.0 0.0 0.0
+        Color EmissiveColor_10 : 0.0 0.0 0.0 0.0
+        Color EmissiveColor_11 : 0.0 0.0 0.0 0.0
+
+        Float Roughness_0 : 0.0
+        Float Roughness_1 : 0.0
+        Float Roughness_2 : 0.0
+        Float Roughness_3 : 0.0
+        Float Roughness_4 : 0.0
+        Float Roughness_5 : 0.0
+        Float Roughness_6 : 0.0
+        Float Roughness_7 : 0.0
+        Float Roughness_8 : 0.0
+        Float Roughness_9 : 0.0
+        Float Roughness_10 : 0.0
+        Float Roughness_11 : 0.0
+
+        Float Metallic_0 : 0.0
+        Float Metallic_1 : 0.0
+        Float Metallic_2 : 0.0
+        Float Metallic_3 : 0.0
+        Float Metallic_4 : 0.0
+        Float Metallic_5 : 0.0
+        Float Metallic_6 : 0.0
+        Float Metallic_7 : 0.0
+        Float Metallic_8 : 0.0
+        Float Metallic_9 : 0.0
+        Float Metallic_10 : 0.0
+        Float Metallic_11 : 0.0
+
+        Int AlbedoMap_0
+        Int AlbedoMap_1
+        Int AlbedoMap_2
+        Int AlbedoMap_3
+        Int AlbedoMap_4
+        Int AlbedoMap_5
+        Int AlbedoMap_6
+        Int AlbedoMap_7
+        Int AlbedoMap_8
+        Int AlbedoMap_9
+        Int AlbedoMap_10
+        Int AlbedoMap_11
+
+
+        Float AlbedoMap_0_scale : 1
+        Float AlbedoMap_1_scale : 1
+        Float AlbedoMap_2_scale : 1
+        Float AlbedoMap_3_scale : 1
+        Float AlbedoMap_4_scale : 1
+        Float AlbedoMap_5_scale : 1
+        Float AlbedoMap_6_scale : 1
+        Float AlbedoMap_7_scale : 1
+        Float AlbedoMap_8_scale : 1
+        Float AlbedoMap_9_scale : 1
+        Float AlbedoMap_10_scale : 1
+        Float AlbedoMap_11_scale : 1
+
+
+        Int NormalMap_0
+        Int NormalMap_1
+        Int NormalMap_2
+        Int NormalMap_3
+        Int NormalMap_4
+        Int NormalMap_5
+        Int NormalMap_6
+        Int NormalMap_7
+        Int NormalMap_8
+        Int NormalMap_9
+        Int NormalMap_10
+        Int NormalMap_11
+
+
+        Int MetallicRoughnessMap_0
+        Int MetallicRoughnessMap_1
+        Int MetallicRoughnessMap_2
+        Int MetallicRoughnessMap_3
+        Int MetallicRoughnessMap_4
+        Int MetallicRoughnessMap_5
+        Int MetallicRoughnessMap_6
+        Int MetallicRoughnessMap_7
+        Int MetallicRoughnessMap_8
+        Int MetallicRoughnessMap_9 
+        Int MetallicRoughnessMap_10
+        Int MetallicRoughnessMap_11
+
+
+        Float ParallaxHeight_0
+        Float ParallaxHeight_1
+        Float ParallaxHeight_2
+        Float ParallaxHeight_3
+        Float ParallaxHeight_4
+        Float ParallaxHeight_5
+        Float ParallaxHeight_6
+        Float ParallaxHeight_7
+        Float ParallaxHeight_8
+        Float ParallaxHeight_9
+        Float ParallaxHeight_10
+        Float ParallaxHeight_11
+
+
+
+        // debug the final value of the selected layer as a color output            
+        Int DebugValuesMode
+
+            // Layers:
+            //   0 - albedo (un-shaded)
+            //   1 - normals
+            //   2 - roughness
+            //   3 - metallic
+            //   4 - ao
+            //   5  - emissive
+
+
+        // use tri-planar mapping
+        Boolean useTriPlanarMapping
+
+        // Texture that specifies alpha values
+        Texture2D AlphaMap -LINEAR
+        Texture2D AlphaMap_1 -LINEAR
+        Texture2D AlphaMap_2 -LINEAR
+
+        Boolean UseSpecGloss
+        Texture2D SpecularMap
+        Texture2D GlossinessMap
+        Texture2D SpecularGlossinessMap
+        Color Specular : 1.0 1.0 1.0 1.0
+        Float Glossiness : 1.0
+
+        Vector4 ProbeData
+
+        // Prefiltered Env Map for indirect specular lighting
+        TextureCubeMap PrefEnvMap -LINEAR
+        
+        // Irradiance map for indirect diffuse lighting
+        TextureCubeMap IrradianceMap -LINEAR
+
+        //integrate BRDF map for indirect Lighting
+        Texture2D IntegrateBRDF -LINEAR
+
+
+        //shadows
+        Int FilterMode
+        Boolean HardwareShadows
+
+        Texture2D ShadowMap0
+        Texture2D ShadowMap1
+        Texture2D ShadowMap2
+        Texture2D ShadowMap3
+        //pointLights
+        Texture2D ShadowMap4
+        Texture2D ShadowMap5
+        
+        Float ShadowIntensity
+        Vector4 Splits
+        Vector2 FadeInfo
+
+        Matrix4 LightViewProjectionMatrix0
+        Matrix4 LightViewProjectionMatrix1
+        Matrix4 LightViewProjectionMatrix2
+        Matrix4 LightViewProjectionMatrix3
+        //pointLight
+        Matrix4 LightViewProjectionMatrix4
+        Matrix4 LightViewProjectionMatrix5   
+        Vector3 LightPos
+        Vector3 LightDir
+
+        Float PCFEdge
+        Float ShadowMapSize
+
+        // For hardware skinning
+        Int NumberOfBones
+        Matrix4Array BoneMatrices
+                
+        //For instancing
+        Boolean UseInstancing
+
+        //For Vertex Color
+        Boolean UseVertexColor
+
+        Boolean BackfaceShadows : false
+
+        Boolean UseFog
+        Color FogColor
+        Vector2 LinearFog
+        Float ExpFog
+        Float ExpSqFog
+
+        // Alpha threshold for fragment discarding
+        Float AlphaDiscardThreshold (AlphaTestFallOff)
+    }
+
+    Technique {
+
+        LightMode SinglePassAndImageBased
+
+        VertexShader  GLSL150:   Common/MatDefs/Terrain/PBRTerrain.vert
+        FragmentShader GLSL150: Common/MatDefs/Terrain/AdvancedPBRTerrain.frag
+
+        WorldParameters {
+            WorldViewProjectionMatrix
+            CameraPosition
+            WorldMatrix
+            WorldNormalMatrix
+            ViewProjectionMatrix
+            ViewMatrix
+            Time
+
+        }
+
+        Defines {
+                
+            AFFLICTIONTEXTURE : AfflictionAlphaMap
+            AFFLICTIONALBEDOMAP: SplatAlbedoMap 
+            AFFLICTIONNORMALMAP : SplatNormalMap 
+            AFFLICTIONROUGHNESSMETALLICMAP : SplatRoughnessMetallicMap
+            AFFLICTIONEMISSIVEMAP : SplatEmissiveMap
+            USE_SPLAT_NOISE : SplatNoiseVar
+
+            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
+            ALBEDOMAP_3 : AlbedoMap_3
+            ALBEDOMAP_4 : AlbedoMap_4
+            ALBEDOMAP_5 : AlbedoMap_5
+            ALBEDOMAP_6 : AlbedoMap_6
+            ALBEDOMAP_7 : AlbedoMap_7
+            ALBEDOMAP_8 : AlbedoMap_8
+            ALBEDOMAP_9 : AlbedoMap_9
+            ALBEDOMAP_10 : AlbedoMap_10
+            ALBEDOMAP_11 : AlbedoMap_11
+
+            NORMALMAP_0 : NormalMap_0
+            NORMALMAP_1 : NormalMap_1
+            NORMALMAP_2 : NormalMap_2
+            NORMALMAP_3 : NormalMap_3
+            NORMALMAP_4 : NormalMap_4
+            NORMALMAP_5 : NormalMap_5
+            NORMALMAP_6 : NormalMap_6
+            NORMALMAP_7 : NormalMap_7
+            NORMALMAP_8 : NormalMap_8
+            NORMALMAP_9 : NormalMap_9
+            NORMALMAP_10 : NormalMap_10
+            NORMALMAP_11 : NormalMap_11
+
+            METALLICROUGHNESSMAP_0 : MetallicRoughnessMap_0
+            METALLICROUGHNESSMAP_1 : MetallicRoughnessMap_1
+            METALLICROUGHNESSMAP_2 : MetallicRoughnessMap_2
+            METALLICROUGHNESSMAP_3 : MetallicRoughnessMap_3
+            METALLICROUGHNESSMAP_4 : MetallicRoughnessMap_4
+            METALLICROUGHNESSMAP_5 : MetallicRoughnessMap_5
+            METALLICROUGHNESSMAP_6 : MetallicRoughnessMap_6
+            METALLICROUGHNESSMAP_7 : MetallicRoughnessMap_7
+            METALLICROUGHNESSMAP_8 : MetallicRoughnessMap_8
+            METALLICROUGHNESSMAP_9 : MetallicRoughnessMap_9
+            METALLICROUGHNESSMAP_10 : MetallicRoughnessMap_10
+            METALLICROUGHNESSMAP_11 : MetallicRoughnessMap_11
+
+            DEBUG_VALUES_MODE : DebugValuesMode
+
+
+
+        }
+    }
+
+
+    Technique PreShadow {
+
+        VertexShader GLSL100 GLSL150 :   Common/MatDefs/Shadow/PreShadow.vert
+        FragmentShader GLSL100 GLSL150 : Common/MatDefs/Shadow/PreShadow.frag
+
+        WorldParameters {
+            WorldViewProjectionMatrix
+            WorldViewMatrix
+            ViewProjectionMatrix
+            ViewMatrix
+        }
+
+        Defines {
+            DISCARD_ALPHA : AlphaDiscardThreshold
+            NUM_BONES : NumberOfBones
+            INSTANCING : UseInstancing
+        }
+
+        ForcedRenderState {
+            FaceCull Off
+            DepthTest On
+            DepthWrite On
+            PolyOffset 5 3
+            ColorWrite Off
+        }
+
+    }
+
+
+    Technique PostShadow{
+        VertexShader GLSL100 GLSL150:   Common/MatDefs/Shadow/PostShadow.vert
+        FragmentShader GLSL100 GLSL150: Common/MatDefs/Shadow/PostShadow.frag
+
+        WorldParameters {
+            WorldViewProjectionMatrix
+            WorldMatrix
+            ViewProjectionMatrix
+            ViewMatrix
+        }
+
+        Defines {
+            HARDWARE_SHADOWS : HardwareShadows
+            FILTER_MODE : FilterMode
+            PCFEDGE : PCFEdge
+            DISCARD_ALPHA : AlphaDiscardThreshold           
+            SHADOWMAP_SIZE : ShadowMapSize
+            FADE : FadeInfo
+            PSSM : Splits
+            POINTLIGHT : LightViewProjectionMatrix5
+            NUM_BONES : NumberOfBones
+            INSTANCING : UseInstancing
+            BACKFACE_SHADOWS: BackfaceShadows
+        }
+
+        ForcedRenderState {
+            Blend Modulate
+            DepthWrite Off   
+            PolyOffset -0.1 0  
+        }
+    }
+    
+
+    
+}

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

@@ -0,0 +1,333 @@
+#import "Common/MatDefs/Terrain/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;
+}
+
+
+//used for mixing normal map normals with the world normals. texure 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;
+}
+
+
+
+
+
+
+
+

+ 107 - 0
jme3-terrain/src/main/resources/Common/MatDefs/Terrain/NoiseLib.glsllib

@@ -0,0 +1,107 @@
+//2d noise functions
+float rand(float n){return fract(sin(n) * 43758.5453123);}
+float rand(vec2 n) { 
+	return fract(sin(dot(n, vec2(12.9898, 4.1414))) * 43758.5453);
+}
+
+float noise(vec2 n) {
+	const vec2 d = vec2(0.0, 1.0);
+  vec2 b = floor(n), f = smoothstep(vec2(0.0), vec2(1.0), fract(n));
+	return mix(mix(rand(b), rand(b + d.yx), f.x), mix(rand(b + d.xy), rand(b + d.yy), f.x), f.y);
+}
+
+
+float prand(vec2 c){
+	return fract(sin(dot(c.xy ,vec2(12.9898,78.233))) * 43758.5453);
+}
+
+float pnoise(vec2 p, float freqPct){
+	//float unit = circ/freq;
+        float unit = freqPct;
+
+	vec2 ij = floor(p/unit);
+	vec2 xy = mod(p,unit)/unit;
+	//xy = 3.*xy*xy-2.*xy*xy*xy;
+	xy = .5*(1.-cos(3.1415926535*xy));
+	float a = prand((ij+vec2(0.,0.)));
+	float b = prand((ij+vec2(1.,0.)));
+	float c = prand((ij+vec2(0.,1.)));
+	float d = prand((ij+vec2(1.,1.)));
+	float x1 = mix(a, b, xy.x);
+	float x2 = mix(c, d, xy.x);
+	return mix(x1, x2, xy.y);
+}
+    
+float rand2D(in vec2 co){
+    return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
+}
+
+// - - - - 
+
+//3d noise functions
+float rand3D(in vec3 co){
+    return fract(sin(dot(co.xyz ,vec3(12.9898,78.233,144.7272))) * 43758.5453);
+}
+    
+float simple_interpolate(in float a, in float b, in float x)
+{
+   return a + smoothstep(0.0,1.0,x) * (b-a);
+}
+float interpolatedNoise3D(in float x, in float y, in float z)
+{
+    float integer_x = x - fract(x);
+    float fractional_x = x - integer_x;
+
+    float integer_y = y - fract(y);
+    float fractional_y = y - integer_y;
+
+    float integer_z = z - fract(z);
+    float fractional_z = z - integer_z;
+
+    float v1 = rand3D(vec3(integer_x, integer_y, integer_z));
+    float v2 = rand3D(vec3(integer_x+1.0, integer_y, integer_z));
+    float v3 = rand3D(vec3(integer_x, integer_y+1.0, integer_z));
+    float v4 = rand3D(vec3(integer_x+1.0, integer_y +1.0, integer_z));
+
+    float v5 = rand3D(vec3(integer_x, integer_y, integer_z+1.0));
+    float v6 = rand3D(vec3(integer_x+1.0, integer_y, integer_z+1.0));
+    float v7 = rand3D(vec3(integer_x, integer_y+1.0, integer_z+1.0));
+    float v8 = rand3D(vec3(integer_x+1.0, integer_y +1.0, integer_z+1.0));
+
+    float i1 = simple_interpolate(v1,v5, fractional_z);
+    float i2 = simple_interpolate(v2,v6, fractional_z);
+    float i3 = simple_interpolate(v3,v7, fractional_z);
+    float i4 = simple_interpolate(v4,v8, fractional_z);
+
+    float ii1 = simple_interpolate(i1,i2,fractional_x);
+    float ii2 = simple_interpolate(i3,i4,fractional_x);
+
+    return simple_interpolate(ii1 , ii2 , fractional_y);
+}
+
+float Noise3D(in vec3 coord, in float wavelength)
+{
+   return interpolatedNoise3D(coord.x/wavelength, coord.y/wavelength, coord.z/wavelength);
+}
+
+
+//used to reference the same float generated by noise for all shaders, so afflictionness appears to spread and splat naturally
+float getStaticNoiseVar0(vec3 wPos, float afflictionVar){
+    float noiseVar0 = Noise3D(wPos, 28);
+    float noiseVar1 = Noise3D(wPos, 3);
+    float noiseVar2 = Noise3D(wPos, 0.8);
+
+    float noiseVar = ((noiseVar0 + noiseVar1) * 0.4) + (noiseVar2 * 0.2 * afflictionVar);
+
+
+    if(noiseVar > 0.7){
+        noiseVar -= noiseVar2 * 0.07;
+     //   noiseVar = min(noiseVar, 0.3);
+
+    }
+
+    noiseVar = min(noiseVar, 1.0);
+     noiseVar = max(noiseVar, 0.0);
+    
+    return noiseVar;
+}

+ 1023 - 0
jme3-terrain/src/main/resources/Common/MatDefs/Terrain/PBRTerrain.frag

@@ -0,0 +1,1023 @@
+#import "Common/ShaderLib/GLSLCompat.glsllib"
+#import "Common/ShaderLib/PBR.glsllib"
+#import "Common/ShaderLib/Parallax.glsllib"
+#import "Common/ShaderLib/Lighting.glsllib"
+
+#import "Common/MatDefs/Terrain/AfflictionLib.glsllib"
+
+#ifdef DEBUG_VALUES_MODE
+  uniform int m_DebugValuesMode;
+#endif
+
+
+uniform vec4 g_LightData[NB_LIGHTS];
+uniform vec4 g_AmbientLightColor;
+
+varying vec3 wPosition;
+
+#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
+
+
+varying vec3 vNormal;
+varying vec2 texCoord;
+
+uniform vec3 g_CameraPosition;
+
+
+vec3 norm;
+
+
+
+#ifdef USE_FOG
+#import "Common/ShaderLib/MaterialFog.glsllib"
+    uniform vec4 m_FogColor;
+    float fogDistance;
+
+    uniform vec2 m_LinearFog;
+#endif
+
+#ifdef FOG_EXP
+    uniform float m_ExpFog;
+#endif
+
+#ifdef FOG_EXPSQ
+    uniform  float m_ExpSqFog;
+#endif
+
+
+varying vec3 vPosition;
+varying vec3 vnPosition;
+varying vec3 vViewDir;
+varying vec4 vLightDir;
+varying vec4 vnLightDir;
+varying vec3 lightVec;
+varying vec3 inNormal;
+
+uniform int m_AfflictionMode_0;
+uniform int m_AfflictionMode_1;
+uniform int m_AfflictionMode_2;
+uniform int m_AfflictionMode_3;
+uniform int m_AfflictionMode_4;
+uniform int m_AfflictionMode_5;
+uniform int m_AfflictionMode_6;
+uniform int m_AfflictionMode_7;
+uniform int m_AfflictionMode_8;
+uniform int m_AfflictionMode_9;
+uniform int m_AfflictionMode_10;
+uniform int m_AfflictionMode_11;
+
+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;
+
+
+#ifdef AFFLICTIONTEXTURE
+    uniform sampler2D m_AfflictionAlphaMap;
+#endif
+
+#ifdef USE_SPLAT_NOISE
+     uniform float m_SplatNoiseVar;
+#endif
+
+//defined for sub terrains that arent equal to each map tile size when AfflictionAlphaMap is defined 
+#ifdef TILELOCATION
+    uniform float m_TileWidth;
+    uniform vec3 m_TileLocation;
+#endif
+
+uniform int m_AfflictionSplatScale;
+#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 float m_AfflictionRoughnessValue;
+uniform float m_AfflictionMetallicValue;
+uniform float m_AfflictionEmissiveValue;
+uniform vec4 m_AfflictionEmissiveColor;
+
+
+#ifdef ALBEDOMAP_0
+  uniform sampler2D m_AlbedoMap_0;
+#endif
+#ifdef ALBEDOMAP_1
+  uniform sampler2D m_AlbedoMap_1;
+#endif
+#ifdef ALBEDOMAP_2
+  uniform sampler2D m_AlbedoMap_2;
+#endif
+#ifdef ALBEDOMAP_3
+  uniform sampler2D m_AlbedoMap_3;
+#endif
+#ifdef ALBEDOMAP_4
+  uniform sampler2D m_AlbedoMap_4;
+#endif
+#ifdef ALBEDOMAP_5
+  uniform sampler2D m_AlbedoMap_5;
+#endif
+#ifdef ALBEDOMAP_6
+  uniform sampler2D m_AlbedoMap_6;
+#endif
+#ifdef ALBEDOMAP_7
+  uniform sampler2D m_AlbedoMap_7;
+#endif
+#ifdef ALBEDOMAP_8
+  uniform sampler2D m_AlbedoMap_8;
+#endif
+#ifdef ALBEDOMAP_9
+  uniform sampler2D m_AlbedoMap_9;
+#endif
+#ifdef ALBEDOMAP_10
+  uniform sampler2D m_AlbedoMap_10;
+#endif
+#ifdef ALBEDOMAP_11
+  uniform sampler2D m_AlbedoMap_11;
+#endif
+
+
+#ifdef ALBEDOMAP_0_SCALE
+  uniform float m_AlbedoMap_0_scale;
+#endif
+#ifdef ALBEDOMAP_1_SCALE
+  uniform float m_AlbedoMap_1_scale;
+#endif
+#ifdef ALBEDOMAP_2_SCALE
+  uniform float m_AlbedoMap_2_scale;
+#endif
+#ifdef ALBEDOMAP_3_SCALE
+  uniform float m_AlbedoMap_3_scale;
+#endif
+#ifdef ALBEDOMAP_4_SCALE
+  uniform float m_AlbedoMap_4_scale;
+#endif
+#ifdef ALBEDOMAP_5_SCALE
+  uniform float m_AlbedoMap_5_scale;
+#endif
+#ifdef ALBEDOMAP_6_SCALE
+  uniform float m_AlbedoMap_6_scale;
+#endif
+#ifdef ALBEDOMAP_7_SCALE
+  uniform float m_AlbedoMap_7_scale;
+#endif
+#ifdef ALBEDOMAP_8_SCALE
+  uniform float m_AlbedoMap_8_scale;
+#endif
+#ifdef ALBEDOMAP_9_SCALE
+  uniform float m_AlbedoMap_9_scale;
+#endif
+#ifdef ALBEDOMAP_10_SCALE
+  uniform float m_AlbedoMap_10_scale;
+#endif
+#ifdef ALBEDOMAP_11_SCALE
+  uniform float m_AlbedoMap_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 NORMALMAP_0
+  uniform sampler2D m_NormalMap_0;
+#endif
+#ifdef NORMALMAP_1
+  uniform sampler2D m_NormalMap_1;
+#endif
+#ifdef NORMALMAP_2
+  uniform sampler2D m_NormalMap_2;
+#endif
+#ifdef NORMALMAP_3
+  uniform sampler2D m_NormalMap_3;
+#endif
+#ifdef NORMALMAP_4
+  uniform sampler2D m_NormalMap_4;
+#endif
+#ifdef NORMALMAP_5
+  uniform sampler2D m_NormalMap_5;
+#endif
+#ifdef NORMALMAP_6
+  uniform sampler2D m_NormalMap_6;
+#endif
+#ifdef NORMALMAP_7
+  uniform sampler2D m_NormalMap_7;
+#endif
+#ifdef NORMALMAP_8
+  uniform sampler2D m_NormalMap_8;
+#endif
+#ifdef NORMALMAP_9
+  uniform sampler2D m_NormalMap_9;
+#endif
+#ifdef NORMALMAP_10
+  uniform sampler2D m_NormalMap_10;
+#endif
+#ifdef NORMALMAP_11
+  uniform sampler2D m_NormalMap_11;
+#endif
+
+#ifdef DISCARD_ALPHA
+    uniform float m_AlphaDiscardThreshold;
+#endif
+
+
+
+
+vec4 afflictionVector;
+
+varying vec3 wNormal;
+
+#ifdef TRI_PLANAR_MAPPING
+  varying vec4 wVertex;
+ 
+#endif
+
+
+vec3 viewDir;
+
+vec2 coord;
+vec4 albedo;
+vec3 normal = vec3(0.5,0.5,1);
+vec3 newNormal;
+float Metallic;
+float Roughness;
+float packedAoValue = 1.0;
+vec4 emissive;
+float emissiveIntensity = 1.0;
+
+vec4 packedMetallicRoughnessAoEiVec;
+vec4 packedNormalParallaxVec;
+
+vec4 tempAlbedo, tempNormal, tempEmissiveColor;
+float tempParallax, tempMetallic, tempRoughness, tempAo, tempEmissiveIntensity;
+
+float noiseHash;
+float livelinessValue;
+float afflictionValue;
+int afflictionMode = 1;
+   
+
+
+#define DEFINE_COORD(index) vec2 coord##index = texCoord * m_AlbedoMap##index##_scale;
+
+#define BLEND(index, ab)\
+    DEFINE_COORD(index)\
+    afflictionMode = m_AfflictionMode##index;\
+    tempAlbedo.rgb = texture2D(m_AlbedoMap##index, coord##index).rgb;\
+    tempAlbedo.rgb = alterLiveliness(tempAlbedo.rgb, livelinessValue, afflictionMode);\
+    albedo.rgb = mix( albedo.rgb, tempAlbedo.rgb ,ab );\
+    normal.rgb = mix(normal.xyz, wNormal.rgb, ab);\
+    Metallic = mix(Metallic, m_Metallic##index, ab);\
+    Roughness = mix(Roughness, m_Roughness##index, ab);
+
+    
+    
+
+#define BLEND_NORMAL(index, ab)\
+    DEFINE_COORD(index)\
+    afflictionMode = m_AfflictionMode##index;\
+    tempAlbedo.rgb = texture2D(m_AlbedoMap##index, coord##index).rgb;\
+    tempAlbedo.rgb = alterLiveliness(tempAlbedo.rgb, livelinessValue, afflictionMode);\
+    albedo.rgb = mix( albedo.rgb, tempAlbedo.rgb ,ab );\
+    Metallic = mix(Metallic, m_Metallic##index, ab);\
+    Roughness = mix(Roughness, m_Roughness##index, ab);\
+    tempNormal.xyz = texture2D(m_NormalMap##index, coord##index).xyz;\
+    tempNormal.rgb = calculateTangentsAndApplyToNormals(tempNormal.rgb, wNormal);\
+    normal.rgb = mix(normal.xyz, tempNormal.xyz, ab);
+
+//BLEND METHODS FOR TRIPLANAR...  
+#define TRI_BLEND(index, ab, worldCoords, blending)\
+    afflictionMode = m_AfflictionMode##index;\
+    tempAlbedo = getTriPlanarBlend(worldCoords, blending, m_AlbedoMap##index, m_AlbedoMap##index##_scale);\
+    tempAlbedo.rgb = alterLiveliness(tempAlbedo.rgb, livelinessValue, afflictionMode);\
+    albedo = mix( albedo, tempAlbedo ,ab );\
+    normal.rgb = mix(normal.rgb, wNormal.rgb, ab);\
+    Metallic = mix(Metallic, m_Metallic##index, ab);\
+    Roughness = mix(Roughness, m_Roughness##index, ab);    
+
+
+#define TRI_BLEND_NORMAL(index, ab, worldCoords, blending)\
+    afflictionMode = m_AfflictionMode##index;\
+    tempAlbedo.rgb = getTriPlanarBlend(worldCoords, blending, m_AlbedoMap##index, m_AlbedoMap##index##_scale).rgb;\
+    tempNormal.rgb = getTriPlanarBlend(worldCoords, blending, m_NormalMap##index, m_AlbedoMap##index##_scale).rgb;\
+    tempAlbedo.rgb = alterLiveliness(tempAlbedo.rgb, livelinessValue, afflictionMode);\
+    albedo.rgb = mix( albedo.rgb, tempAlbedo.rgb ,ab );\
+    tempNormal.rgb = calculateTangentsAndApplyToNormals(tempNormal.rgb, wNormal);\
+    normal.rgb = mix(normal.xyz, tempNormal.xyz, ab);\
+    Metallic = mix(Metallic, m_Metallic##index, ab);\
+    Roughness = mix(Roughness, m_Roughness##index, ab);
+
+#ifdef ALPHAMAP
+
+vec4 calculateAlbedoBlend(in vec2 texCoord) {
+    vec4 alphaBlend = texture2D( m_AlphaMap, texCoord.xy );
+    vec4 albedo = vec4(1.0);
+    
+    
+
+    Roughness = m_Roughness_0;
+    Metallic = m_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);
+
+
+    #ifdef ALPHAMAP_1
+      vec4 alphaBlend1   = texture2D( m_AlphaMap_1, texCoord.xy );
+    #endif
+    #ifdef ALPHAMAP_2
+      vec4 alphaBlend2   = texture2D( m_AlphaMap_2, texCoord.xy );
+    #endif
+    #ifdef ALBEDOMAP_0   
+                    //NOTE! the old (phong) terrain shaders do not have an "_0" for the first diffuse map, it is just "DiffuseMap"
+        #ifdef NORMALMAP_0
+            BLEND_NORMAL(_0,  alphaBlend.r)
+        #else
+            BLEND(_0,  alphaBlend.r)
+        #endif
+        
+    #endif
+    #ifdef ALBEDOMAP_1
+        #ifdef NORMALMAP_1
+            BLEND_NORMAL(_1,  alphaBlend.g)
+        #else
+            BLEND(_1,  alphaBlend.g)
+        #endif
+        
+    #endif
+    #ifdef ALBEDOMAP_2
+        #ifdef NORMALMAP_2
+            BLEND_NORMAL(_2,  alphaBlend.b)
+        #else
+            BLEND(_2,  alphaBlend.b)
+        #endif
+        
+    #endif
+    #ifdef ALBEDOMAP_3 
+        #ifdef NORMALMAP_3
+            BLEND_NORMAL(_3,  alphaBlend.a)
+        #else
+            BLEND(_3,  alphaBlend.a)
+        #endif
+       
+    #endif
+
+    #ifdef ALPHAMAP_1
+        #ifdef ALBEDOMAP_4
+            #ifdef NORMALMAP_4
+                BLEND_NORMAL(_4,  alphaBlend1.r)
+            #else
+                BLEND(_4,  alphaBlend1.r)
+            #endif
+           
+        #endif
+        #ifdef ALBEDOMAP_5
+            #ifdef NORMALMAP_5
+                BLEND_NORMAL(_5,  alphaBlend1.g)
+            #else
+                BLEND(_5,  alphaBlend1.g)
+            #endif
+             
+        #endif
+        #ifdef ALBEDOMAP_6
+            #ifdef NORMALMAP_6
+                BLEND_NORMAL(_6,  alphaBlend1.b)
+            #else
+                BLEND(_6,  alphaBlend1.b)
+            #endif
+             
+        #endif
+        #ifdef ALBEDOMAP_7
+            #ifdef NORMALMAP_7
+                BLEND_NORMAL(_7,  alphaBlend1.a)
+            #else
+                BLEND(_7,  alphaBlend1.a)
+            #endif
+             
+        #endif
+    #endif
+
+    #ifdef ALPHAMAP_2
+        #ifdef ALBEDOMAP_8
+             #ifdef NORMALMAP_8
+                BLEND_NORMAL(_8,  alphaBlend2.r)
+            #else
+                BLEND(_8,  alphaBlend2.r)
+            #endif
+             
+        #endif
+        #ifdef ALBEDOMAP_9
+             #ifdef NORMALMAP_9
+                BLEND_NORMAL(_9,  alphaBlend2.g)
+            #else
+                BLEND(_9,  alphaBlend2.g)
+            #endif
+             
+        #endif
+        #ifdef ALBEDOMAP_10
+            #ifdef NORMALMAP_10
+                BLEND_NORMAL(_10,  alphaBlend2.b)
+            #else
+                BLEND(_10,  alphaBlend2.b)
+            #endif
+             
+        #endif
+        #ifdef ALBEDOMAP_11
+             #ifdef NORMALMAP_11
+                BLEND_NORMAL(_11,  alphaBlend2.a)
+            #else
+                BLEND(_11,  alphaBlend2.a)
+            #endif
+             
+        #endif                   
+    #endif
+
+    return albedo;
+  }
+
+
+
+// TRI PLANAR ALPHA MAP TEXTURES_ _ _ _    \/
+
+  #ifdef TRI_PLANAR_MAPPING
+
+
+    vec4 calculateTriPlanarAlbedoBlend(in vec3 wNorm, in vec4 wVert, in vec2 texCoord, vec3 blending) {
+         vec4 alphaBlend = texture2D( m_AlphaMap, texCoord.xy );
+        vec4 albedo = vec4(1.0);
+
+
+
+        Roughness = m_Roughness_0;
+        Metallic = m_Metallic_0 ;
+
+    
+
+
+        #ifdef ALPHAMAP_1
+          vec4 alphaBlend1   = texture2D( m_AlphaMap_1, texCoord.xy );
+        #endif
+        #ifdef ALPHAMAP_2
+          vec4 alphaBlend2   = texture2D( m_AlphaMap_2, texCoord.xy );
+        #endif
+        #ifdef ALBEDOMAP_0   
+                        //NOTE! the old (phong) terrain shaders do not have an "_0" for the first diffuse map, it is just "DiffuseMap"
+            #ifdef NORMALMAP_0
+                TRI_BLEND_NORMAL(_0,  alphaBlend.r, wVertex, blending)
+            #else
+                TRI_BLEND(_0,  alphaBlend.r, wVertex, blending)
+            #endif
+
+        #endif
+        #ifdef ALBEDOMAP_1
+            #ifdef NORMALMAP_1
+                TRI_BLEND_NORMAL(_1,  alphaBlend.g, wVertex, blending)
+            #else
+                TRI_BLEND(_1,  alphaBlend.g, wVertex, blending)
+            #endif
+
+        #endif
+        #ifdef ALBEDOMAP_2
+            #ifdef NORMALMAP_2
+                TRI_BLEND_NORMAL(_2,  alphaBlend.b, wVertex, blending)
+            #else
+                TRI_BLEND(_2,  alphaBlend.b, wVertex, blending)
+            #endif
+
+        #endif
+        #ifdef ALBEDOMAP_3 
+            #ifdef NORMALMAP_3
+                TRI_BLEND_NORMAL(_3,  alphaBlend.a, wVertex, blending)
+            #else
+                TRI_BLEND(_3,  alphaBlend.a, wVertex, blending)
+            #endif
+
+        #endif
+
+        #ifdef ALPHAMAP_1
+            #ifdef ALBEDOMAP_4
+                #ifdef NORMALMAP_4
+                    TRI_BLEND_NORMAL(_4,  alphaBlend1.r, wVertex, blending)
+                #else
+                    TRI_BLEND(_4,  alphaBlend1.r, wVertex, blending)
+                #endif
+
+            #endif
+            #ifdef ALBEDOMAP_5
+                #ifdef NORMALMAP_5
+                    TRI_BLEND_NORMAL(_5,  alphaBlend1.g, wVertex, blending)
+                #else
+                    TRI_BLEND(_5,  alphaBlend1.g, wVertex, blending)
+                #endif
+
+            #endif
+            #ifdef ALBEDOMAP_6
+                #ifdef NORMALMAP_6
+                    TRI_BLEND_NORMAL(_6,  alphaBlend1.b, wVertex, blending)
+                #else
+                    TRI_BLEND(_6,  alphaBlend1.b, wVertex, blending)
+                #endif
+
+            #endif
+            #ifdef ALBEDOMAP_7
+                #ifdef NORMALMAP_7
+                    TRI_BLEND_NORMAL(_7,  alphaBlend1.a, wVertex, blending)
+                #else
+                    TRI_BLEND(_7,  alphaBlend1.a, wVertex, blending)
+                #endif
+
+            #endif
+        #endif
+
+        #ifdef ALPHAMAP_2
+            #ifdef ALBEDOMAP_8
+                 #ifdef NORMALMAP_8
+                    TRI_BLEND_NORMAL(_8,  alphaBlend2.r, wVertex, blending)
+                #else
+                    TRI_BLEND(_8,  alphaBlend2.r, wVertex, blending)
+                #endif
+
+            #endif
+            #ifdef ALBEDOMAP_9
+                 #ifdef NORMALMAP_9
+                    TRI_BLEND_NORMAL(_9,  alphaBlend2.g, wVertex, blending)
+                #else
+                    TRI_BLEND(_9,  alphaBlend2.g, wVertex, blending)
+                #endif
+
+            #endif
+            #ifdef ALBEDOMAP_10
+                #ifdef NORMALMAP_10
+                    TRI_BLEND_NORMAL(_10,  alphaBlend2.b, wVertex, blending)
+                #else
+                    TRI_BLEND(_10,  alphaBlend2.b, wVertex, blending)
+                #endif
+
+            #endif
+            #ifdef ALBEDOMAP_11
+                 #ifdef NORMALMAP_11
+                    TRI_BLEND_NORMAL(_11,  alphaBlend2.a, wVertex, blending)
+                #else
+                    TRI_BLEND(_11,  alphaBlend2.a, wVertex, blending)
+                #endif
+
+            #endif                   
+        #endif
+        
+
+
+        return albedo;
+    }
+
+    
+  #endif
+
+#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 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 to determine how the light probe's ambient light should be scaled later on..
+float brightestPointLight = 0.0;
+
+
+
+void main(){
+    
+    
+    #ifdef USE_FOG
+        fogDistance = distance(g_CameraPosition, wPosition.xyz);
+    #endif
+    
+    float indoorSunLightExposure = 1.0;
+    
+    viewDir = normalize(g_CameraPosition - wPosition);
+
+    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)
+    
+    #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);
+
+            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
+    #endif
+
+    livelinessValue = afflictionVector.r;
+    afflictionValue = afflictionVector.g;
+
+
+
+
+    vec3 blending;
+    #ifdef ALBEDOMAP_0
+      #ifdef ALPHAMAP
+        #ifdef TRI_PLANAR_MAPPING
+             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);
+
+
+            albedo = calculateTriPlanarAlbedoBlend(norm, wVertex, texCoord, blending);
+            
+        #else
+            albedo = calculateAlbedoBlend(texCoord);
+        #endif
+      #else
+        albedo = texture2D(m_AlbedoMap_0, texCoord);
+      #endif
+    #endif
+
+
+    float alpha = albedo.a;
+    #ifdef DISCARD_ALPHA
+        if(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 = texture2D(m_SplatRoughnessMetallicMap, newScaledCoords);
+            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 = texture2D(m_SplatEmissiveMap, newScaledCoords);
+            afflictionEmissive *= emissiveMapColor;
+        #endif
+
+        float adjustedAfflictionValue = afflictionValue;
+            #ifdef USE_SPLAT_NOISE
+                noiseHash = getStaticNoiseVar0(wPosition, afflictionValue * m_SplatNoiseVar);
+
+                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);
+    
+    #ifdef AFFLICTIONTEXTURE
+        ao = alterAfflictionAo(afflictionValue, ao, vec3(afflictionAo), noiseHash); // alter the AO map for affliction values
+    #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);
+    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;
+            
+        #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
+
+
+
+    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
+    #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 
+    
+    //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);  
+        }
+        
+    #endif
+    
+    gl_FragColor.a = albedo.a;
+
+}

+ 380 - 0
jme3-terrain/src/main/resources/Common/MatDefs/Terrain/PBRTerrain.j3md

@@ -0,0 +1,380 @@
+// NOTE: Doesn't support OpenGL1
+MaterialDef PBR Terrain {
+
+    MaterialParameters {
+
+
+        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 indooes can have the DirectionalLight dimmed accordingly.
+
+        Boolean BrightenIndoorShadows  //set true if shadows are enabled and indoor areas withour full sun exposure are too dark compared to when shadows are turned off in settings
+
+
+        Int AfflictionSplatScale : 8
+
+        Float AfflictionRoughnessValue : 1.0
+        Float AfflictionMetallicValue : 0.0
+        Float AfflictionEmissiveValue : 0.0 //note that this is simplified into one value, rather than 2 with power and intensity like the regular pbr values.
+
+        Texture2D AfflictionAlphaMap
+        Texture2D SplatAlbedoMap  -LINEAR
+        Texture2D SplatNormalMap  -LINEAR
+        Texture2D SplatRoughnessMetallicMap -LINEAR
+        Texture2D SplatEmissiveMap -LINEAR
+
+        Color AfflictionEmissiveColor : 0.0 0.0 0.0 0.0
+
+        Float SplatNoiseVar
+
+        //used for decal mapping with afflictionMap, in order to convert world coords to tex coords so afflictionTexture accurately represents the world
+        Float TileWidth : 0
+        Vector3 TileLocation
+
+        Int AfflictionMode_0 : 1
+        Int AfflictionMode_1 : 1
+        Int AfflictionMode_2 : 1
+        Int AfflictionMode_3 : 1
+        Int AfflictionMode_4 : 1
+        Int AfflictionMode_5 : 1
+        Int AfflictionMode_6 : 1
+        Int AfflictionMode_7 : 1
+        Int AfflictionMode_8 : 1
+        Int AfflictionMode_9 : 1
+        Int AfflictionMode_10 : 1
+        Int AfflictionMode_11 : 1
+
+        Float Roughness_0 : 0.0
+        Float Roughness_1 : 0.0
+        Float Roughness_2 : 0.0
+        Float Roughness_3 : 0.0
+        Float Roughness_4 : 0.0
+        Float Roughness_5 : 0.0
+        Float Roughness_6 : 0.0
+        Float Roughness_7 : 0.0
+        Float Roughness_8 : 0.0
+        Float Roughness_9 : 0.0
+        Float Roughness_10 : 0.0
+        Float Roughness_11 : 0.0
+
+        Float Metallic_0 : 0.0
+        Float Metallic_1 : 0.0
+        Float Metallic_2 : 0.0
+        Float Metallic_3 : 0.0
+        Float Metallic_4 : 0.0
+        Float Metallic_5 : 0.0
+        Float Metallic_6 : 0.0
+        Float Metallic_7 : 0.0
+        Float Metallic_8 : 0.0
+        Float Metallic_9 : 0.0
+        Float Metallic_10 : 0.0
+        Float Metallic_11 : 0.0
+
+
+        // debug the final value of the selected layer as a color output            
+        Int DebugValuesMode
+
+            // Layers:
+            //   0 - albedo (un-shaded)
+            //   1 - normals
+            //   2 - roughness
+            //   3 - metallic
+            //   4 - ao
+            //   5  - emissive
+
+
+        // use tri-planar mapping
+        Boolean useTriPlanarMapping
+
+        // Texture map #0
+        Texture2D AlbedoMap_0
+        Float AlbedoMap_0_scale
+        Texture2D NormalMap_0 -LINEAR
+
+        // Texture map #1
+        Texture2D AlbedoMap_1
+        Float AlbedoMap_1_scale
+        Texture2D NormalMap_1 -LINEAR
+
+        // Texture map #2
+        Texture2D AlbedoMap_2
+        Float AlbedoMap_2_scale
+        Texture2D NormalMap_2 -LINEAR
+
+        // Texture map #3
+        Texture2D AlbedoMap_3
+        Float AlbedoMap_3_scale
+        Texture2D NormalMap_3 -LINEAR
+
+        // Texture map #4
+        Texture2D AlbedoMap_4
+        Float AlbedoMap_4_scale
+        Texture2D NormalMap_4 -LINEAR
+
+        // Texture map #5
+        Texture2D AlbedoMap_5
+        Float AlbedoMap_5_scale
+        Texture2D NormalMap_5 -LINEAR
+
+        // Texture map #6
+        Texture2D AlbedoMap_6
+        Float AlbedoMap_6_scale
+        Texture2D NormalMap_6 -LINEAR
+
+        // Texture map #7
+        Texture2D AlbedoMap_7
+        Float AlbedoMap_7_scale
+        Texture2D NormalMap_7 -LINEAR
+
+        // Texture map #8
+        Texture2D AlbedoMap_8
+        Float AlbedoMap_8_scale
+        Texture2D NormalMap_8 -LINEAR
+
+        // Texture map #9
+        Texture2D AlbedoMap_9
+        Float AlbedoMap_9_scale
+        Texture2D NormalMap_9 -LINEAR
+
+        // Texture map #10
+        Texture2D AlbedoMap_10
+        Float AlbedoMap_10_scale
+        Texture2D NormalMap_10 -LINEAR
+
+        // Texture map #11
+        Texture2D AlbedoMap_11
+        Float AlbedoMap_11_scale
+        Texture2D NormalMap_11 -LINEAR
+
+
+
+        // Texture that specifies alpha values
+        Texture2D AlphaMap -LINEAR
+        Texture2D AlphaMap_1 -LINEAR
+        Texture2D AlphaMap_2 -LINEAR
+
+        // For Spec gloss pipeline
+        Boolean UseSpecGloss
+        Texture2D SpecularMap
+        Texture2D GlossinessMap
+        Texture2D SpecularGlossinessMap
+        Color Specular : 1.0 1.0 1.0 1.0
+        Float Glossiness : 1.0
+
+        Vector4 ProbeData
+
+        // Prefiltered Env Map for indirect specular lighting
+        TextureCubeMap PrefEnvMap -LINEAR
+        
+        // Irradiance map for indirect diffuse lighting
+        TextureCubeMap IrradianceMap -LINEAR
+
+        //integrate BRDF map for indirect Lighting
+        Texture2D IntegrateBRDF -LINEAR
+
+        //shadows
+        Int FilterMode
+        Boolean HardwareShadows
+
+        Texture2D ShadowMap0
+        Texture2D ShadowMap1
+        Texture2D ShadowMap2
+        Texture2D ShadowMap3
+        //pointLights
+        Texture2D ShadowMap4
+        Texture2D ShadowMap5
+        
+        Float ShadowIntensity
+        Vector4 Splits
+        Vector2 FadeInfo
+
+        Matrix4 LightViewProjectionMatrix0
+        Matrix4 LightViewProjectionMatrix1
+        Matrix4 LightViewProjectionMatrix2
+        Matrix4 LightViewProjectionMatrix3
+        //pointLight
+        Matrix4 LightViewProjectionMatrix4
+        Matrix4 LightViewProjectionMatrix5   
+        Vector3 LightPos
+        Vector3 LightDir
+
+        Float PCFEdge
+        Float ShadowMapSize
+
+        // For hardware skinning
+        Int NumberOfBones
+        Matrix4Array BoneMatrices
+                
+        //For instancing
+        Boolean UseInstancing
+
+        //For Vertex Color
+        Boolean UseVertexColor
+
+        Boolean BackfaceShadows : false
+
+
+        Boolean UseFog
+        Color FogColor
+        Vector2 LinearFog
+        Float ExpFog
+        Float ExpSqFog
+
+        // Alpha threshold for fragment discarding
+        Float AlphaDiscardThreshold (AlphaTestFallOff)
+    }
+
+    Technique {
+
+        LightMode SinglePassAndImageBased
+
+        VertexShader GLSL100 GLSL130 GLSL150:   Common/MatDefs/Terrain/PBRTerrain.vert
+        FragmentShader GLSL100 GLSL130 GLSL150: Common/MatDefs/Terrain/PBRTerrain.frag
+
+        WorldParameters {
+            WorldViewProjectionMatrix
+            CameraPosition
+            WorldMatrix
+            WorldNormalMatrix
+            ViewProjectionMatrix
+            ViewMatrix
+            Time
+
+        }
+
+        Defines {
+                
+            TILELOCATION : TileLocation
+            AFFLICTIONTEXTURE : AfflictionAlphaMap
+
+            AFFLICTIONALBEDOMAP: SplatAlbedoMap 
+            AFFLICTIONNORMALMAP : SplatNormalMap 
+            AFFLICTIONROUGHNESSMETALLICMAP : SplatRoughnessMetallicMap
+            AFFLICTIONEMISSIVEMAP : SplatEmissiveMap
+
+            USE_SPLAT_NOISE : SplatNoiseVar
+
+
+            USE_VERTEX_COLORS_AS_SUN_INTENSITY : UseVertexColorsAsSunIntensity
+            STATIC_SUN_INTENSITY : StaticSunIntensity
+            BRIGHTEN_INDOOR_SHADOWS : BrightenIndoorShadows
+
+            DISCARD_ALPHA : AlphaDiscardThreshold
+
+            USE_FOG : UseFog
+            FOG_LINEAR : LinearFog
+            FOG_EXP : ExpFog
+            FOG_EXPSQ : ExpSqFog
+
+            TRI_PLANAR_MAPPING : useTriPlanarMapping
+
+            ALBEDOMAP_0 : AlbedoMap_0
+            ALBEDOMAP_1 : AlbedoMap_1
+            ALBEDOMAP_2 : AlbedoMap_2
+            ALBEDOMAP_3 : AlbedoMap_3
+            ALBEDOMAP_4 : AlbedoMap_4
+            ALBEDOMAP_5 : AlbedoMap_5
+            ALBEDOMAP_6 : AlbedoMap_6
+            ALBEDOMAP_7 : AlbedoMap_7
+            ALBEDOMAP_8 : AlbedoMap_8
+            ALBEDOMAP_9 : AlbedoMap_9
+            ALBEDOMAP_10 : AlbedoMap_10
+            ALBEDOMAP_11 : AlbedoMap_11
+
+            NORMALMAP_0 : NormalMap_0
+            NORMALMAP_1 : NormalMap_1
+            NORMALMAP_2 : NormalMap_2
+            NORMALMAP_3 : NormalMap_3
+            NORMALMAP_4 : NormalMap_4
+            NORMALMAP_5 : NormalMap_5
+            NORMALMAP_6 : NormalMap_6
+            NORMALMAP_7 : NormalMap_7
+            NORMALMAP_8 : NormalMap_8
+            NORMALMAP_9 : NormalMap_9
+            NORMALMAP_10 : NormalMap_10
+            NORMALMAP_11 : NormalMap_11
+
+            ALPHAMAP : AlphaMap
+            ALPHAMAP_1 : AlphaMap_1
+            ALPHAMAP_2 : AlphaMap_2
+            ALBEDOMAP_0_SCALE : AlbedoMap_0_scale
+            ALBEDOMAP_1_SCALE : AlbedoMap_1_scale
+            ALBEDOMAP_2_SCALE : AlbedoMap_2_scale
+            ALBEDOMAP_3_SCALE : AlbedoMap_3_scale
+            ALBEDOMAP_4_SCALE : AlbedoMap_4_scale
+            ALBEDOMAP_5_SCALE : AlbedoMap_5_scale
+            ALBEDOMAP_6_SCALE : AlbedoMap_6_scale
+            ALBEDOMAP_7_SCALE : AlbedoMap_7_scale
+            ALBEDOMAP_8_SCALE : AlbedoMap_8_scale
+            ALBEDOMAP_9_SCALE : AlbedoMap_9_scale
+            ALBEDOMAP_10_SCALE : AlbedoMap_10_scale
+            ALBEDOMAP_11_SCALE : AlbedoMap_11_scale
+
+            DEBUG_VALUES_MODE : DebugValuesMode
+            
+        }
+    }
+
+
+    Technique PreShadow {
+
+        VertexShader GLSL100 GLSL150 :   Common/MatDefs/Shadow/PreShadow.vert
+        FragmentShader GLSL100 GLSL150 : Common/MatDefs/Shadow/PreShadow.frag
+
+        WorldParameters {
+            WorldViewProjectionMatrix
+            WorldViewMatrix
+            ViewProjectionMatrix
+            ViewMatrix
+        }
+
+        Defines {
+            DISCARD_ALPHA : AlphaDiscardThreshold
+            NUM_BONES : NumberOfBones
+            INSTANCING : UseInstancing
+        }
+
+        ForcedRenderState {
+            FaceCull Off
+            DepthTest On
+            DepthWrite On
+            PolyOffset 5 3
+            ColorWrite Off
+        }
+
+    }
+
+
+    Technique PostShadow{
+        VertexShader GLSL100 GLSL150:   Common/MatDefs/Shadow/PostShadow.vert
+        FragmentShader GLSL100 GLSL150: Common/MatDefs/Shadow/PostShadow.frag
+
+        WorldParameters {
+            WorldViewProjectionMatrix
+            WorldMatrix
+            ViewProjectionMatrix
+            ViewMatrix
+        }
+
+        Defines {
+            HARDWARE_SHADOWS : HardwareShadows
+            FILTER_MODE : FilterMode
+            PCFEDGE : PCFEdge
+            DISCARD_ALPHA : AlphaDiscardThreshold           
+            SHADOWMAP_SIZE : ShadowMapSize
+            FADE : FadeInfo
+            PSSM : Splits
+            POINTLIGHT : LightViewProjectionMatrix5
+            NUM_BONES : NumberOfBones
+            INSTANCING : UseInstancing
+            BACKFACE_SHADOWS: BackfaceShadows
+        }
+
+        ForcedRenderState {
+            Blend Modulate
+            DepthWrite Off   
+            PolyOffset -0.1 0  
+        }
+    }
+    
+}

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

@@ -0,0 +1,40 @@
+#import "Common/ShaderLib/GLSLCompat.glsllib"
+#import "Common/ShaderLib/Instancing.glsllib"
+
+attribute vec3 inPosition;
+attribute vec3 inNormal;
+attribute vec2 inTexCoord;
+
+varying vec2 texCoord;
+varying vec3 wPosition;
+varying vec3 wNormal;
+
+
+ uniform vec4 g_AmbientLightColor;
+
+
+#ifdef TRI_PLANAR_MAPPING
+  varying vec4 wVertex;
+#endif
+
+
+void main(){
+    vec4 modelSpacePos = vec4(inPosition, 1.0);
+
+    gl_Position = TransformWorldViewProjection(modelSpacePos);
+
+    texCoord = inTexCoord;
+
+    wPosition = (g_WorldMatrix * vec4(inPosition, 1.0)).xyz;    
+    
+    wNormal  = normalize(TransformWorldNormal(inNormal));
+
+
+    #ifdef TRI_PLANAR_MAPPING
+       wVertex = vec4(inPosition,0.0);       
+    #endif
+    
+    
+  
+    
+}

+ 15 - 0
jme3-testdata/src/main/resources/Scenes/LightProbes/license.txt

@@ -0,0 +1,15 @@
+Licensing history for files in "src/main/resources/Scenes/LightProbes"
+
+Based on "Quarry 03":
+* download file:     quarry_03.jpg
+* downloaded from:   https://hdrihaven.com/hdri/?h=quarry_03
+* author:            Sergej Majboroda
+* author URL:        https://hdrihaven.com/hdris/?a=Sergej%20Majboroda
+* license type:      CC0
+* license URL:       https://creativecommons.org/publicdomain/zero/1.0/
+
+Derived files (also licensed CC0):
+* quarry_Probe.j3o
+
+Added files (also licensed CC0):
+* license.txt

BIN
jme3-testdata/src/main/resources/Scenes/LightProbes/quarry_Probe.j3o


BIN
jme3-testdata/src/main/resources/Textures/Terrain/PBR/Gravel015_1K_AmbientOcclusion.png


BIN
jme3-testdata/src/main/resources/Textures/Terrain/PBR/Gravel015_1K_Color.png


BIN
jme3-testdata/src/main/resources/Textures/Terrain/PBR/Gravel015_1K_Displacement.png


BIN
jme3-testdata/src/main/resources/Textures/Terrain/PBR/Gravel015_1K_Normal.png


BIN
jme3-testdata/src/main/resources/Textures/Terrain/PBR/Gravel015_1K_Roughness.png


BIN
jme3-testdata/src/main/resources/Textures/Terrain/PBR/Gravel_015_PackedMetallicRoughnessMap.png


BIN
jme3-testdata/src/main/resources/Textures/Terrain/PBR/Ground036_1K_AmbientOcclusion.png


BIN
jme3-testdata/src/main/resources/Textures/Terrain/PBR/Ground036_1K_Color.png


BIN
jme3-testdata/src/main/resources/Textures/Terrain/PBR/Ground036_1K_Displacement.png


BIN
jme3-testdata/src/main/resources/Textures/Terrain/PBR/Ground036_1K_Normal.png


BIN
jme3-testdata/src/main/resources/Textures/Terrain/PBR/Ground036_1K_Roughness.png


BIN
jme3-testdata/src/main/resources/Textures/Terrain/PBR/Ground036_PackedMetallicRoughnessMap.png


BIN
jme3-testdata/src/main/resources/Textures/Terrain/PBR/Ground037_1K_AmbientOcclusion.png


BIN
jme3-testdata/src/main/resources/Textures/Terrain/PBR/Ground037_1K_Color.png


BIN
jme3-testdata/src/main/resources/Textures/Terrain/PBR/Ground037_1K_Displacement.png


BIN
jme3-testdata/src/main/resources/Textures/Terrain/PBR/Ground037_1K_Normal.png


BIN
jme3-testdata/src/main/resources/Textures/Terrain/PBR/Ground037_1K_Roughness.png


BIN
jme3-testdata/src/main/resources/Textures/Terrain/PBR/Ground037_PackedMetallicRoughnessMap.png


BIN
jme3-testdata/src/main/resources/Textures/Terrain/PBR/Marble013_1K_Color.png


BIN
jme3-testdata/src/main/resources/Textures/Terrain/PBR/Marble013_1K_Displacement.png


BIN
jme3-testdata/src/main/resources/Textures/Terrain/PBR/Marble013_1K_Normal.png


BIN
jme3-testdata/src/main/resources/Textures/Terrain/PBR/Marble013_1K_Roughness.png


BIN
jme3-testdata/src/main/resources/Textures/Terrain/PBR/Marble013_PackedMetallicRoughnessMap.png


BIN
jme3-testdata/src/main/resources/Textures/Terrain/PBR/Rock035_1K_AmbientOcclusion.png


BIN
jme3-testdata/src/main/resources/Textures/Terrain/PBR/Rock035_1K_Color.jpg


BIN
jme3-testdata/src/main/resources/Textures/Terrain/PBR/Rock035_1K_Color.png


BIN
jme3-testdata/src/main/resources/Textures/Terrain/PBR/Rock035_1K_Displacement.png


BIN
jme3-testdata/src/main/resources/Textures/Terrain/PBR/Rock035_1K_Normal.png


BIN
jme3-testdata/src/main/resources/Textures/Terrain/PBR/Rock035_1K_Roughness.png


BIN
jme3-testdata/src/main/resources/Textures/Terrain/PBR/Rock035_PackedMetallicRoughnessMap.png


BIN
jme3-testdata/src/main/resources/Textures/Terrain/PBR/Snow006_1K_AmbientOcclusion.png


BIN
jme3-testdata/src/main/resources/Textures/Terrain/PBR/Snow006_1K_Color.png


BIN
jme3-testdata/src/main/resources/Textures/Terrain/PBR/Snow006_1K_Displacement.png


BIN
jme3-testdata/src/main/resources/Textures/Terrain/PBR/Snow006_1K_Normal.png


BIN
jme3-testdata/src/main/resources/Textures/Terrain/PBR/Snow006_1K_Roughness.png


BIN
jme3-testdata/src/main/resources/Textures/Terrain/PBR/Snow006_PackedMetallicRoughnessMap.png


BIN
jme3-testdata/src/main/resources/Textures/Terrain/PBR/Tiles083_1K_AmbientOcclusion.png


BIN
jme3-testdata/src/main/resources/Textures/Terrain/PBR/Tiles083_1K_Color.png


BIN
jme3-testdata/src/main/resources/Textures/Terrain/PBR/Tiles083_1K_Displacement.png


BIN
jme3-testdata/src/main/resources/Textures/Terrain/PBR/Tiles083_1K_Normal.png


BIN
jme3-testdata/src/main/resources/Textures/Terrain/PBR/Tiles083_1K_Roughness.png


BIN
jme3-testdata/src/main/resources/Textures/Terrain/PBR/Tiles083_PackedMetallicRoughnessMap.png


+ 58 - 0
jme3-testdata/src/main/resources/Textures/Terrain/PBR/license.txt

@@ -0,0 +1,58 @@
+Licensing history for files in "src/main/resources/Textures/Terrain/PBR"
+
+All textures were downloaded and derrived from:
+* downloaded from:   https://cc0textures.com/
+* license type:      CC0
+* license URL:       https://docs.cc0textures.com/licensing.html
+
+* Files Downloaded:
+Gravel015_1K_Color.png
+Gravel015_1K_Normal.png
+Ground036_1K_Color.png
+Ground036_1K_Normal.png
+Ground037_1K_Color.png
+Ground037_1K_Normal.png
+Marble013_1K_Color.png
+Marble013_1K_Normal.png
+Rock035_1K_Color.png
+Rock035_1K_Normal.png
+Snow006_1K_Color.png
+Snow006_1K_Normal.png
+Tiles083_1K_Color.png
+Tiles083_1K_Normal.png
+Gravel015_1K_Displacement.png
+Gravel015_1K_AmbientOcclusion.png
+Ground036_1K_Displacement.png
+Ground036_1K_AmbientOcclusion.png
+Ground037_1K_Displacement.png
+Ground037_1K_AmbientOcclusion.png
+Marble013_1K_Displacement.png
+Marble013_1K_AmbientOcclusion.png
+Rock035_1K_Displacement.png
+Rock035_1K_AmbientOcclusion.png
+Snow006_1K_Displacement.png
+Snow006_1K_AmbientOcclusion.png
+Tiles083_1K_Displacement.png
+Tiles083_1K_AmbientOcclusion.png
+Gravel015_1K_Roughness.png
+Ground036_1K_Roughness.png
+Ground037_1K_Roughness.png
+Marble013_1K_Roughness.png
+Rock035_1K_Roughness.png
+Snow006_1K_Roughness.png
+Tiles083_1K_Roughness.png
+
+
+
+*Files Derrived:
+Gravel_015_PackedMetallicRoughnessMap.png
+Ground036_PackedMetallicRoughnessMap.png
+Ground037_PackedMetallicRoughnessMap.png
+Marble013_PackedMetallicRoughnessMap.png
+Rock035_PackedMetallicRoughnessMap.png
+Snow006_PackedMetallicRoughnessMap.png
+Tiles083_PackedMetallicRoughnessMap.png
+
+
+
+Contains assets from CC0Textures.com, licensed under CC0 1.0 Universal.