Parcourir la source

in-pass-shadows: add spot / point light support

Kirill Vainer il y a 7 ans
Parent
commit
caad16626e
22 fichiers modifiés avec 909 ajouts et 313 suppressions
  1. 23 0
      jme3-core/src/main/java/com/jme3/material/logic/DefaultTechniqueDefLogic.java
  2. 0 9
      jme3-core/src/main/java/com/jme3/material/logic/ShadowStaticPassLightingLogic.java
  3. 140 100
      jme3-core/src/main/java/com/jme3/material/logic/SinglePassAndImageBasedLightingLogic.java
  4. 1 1
      jme3-core/src/main/java/com/jme3/material/logic/SinglePassLightingLogic.java
  5. 22 21
      jme3-core/src/main/java/com/jme3/material/logic/StaticPassLightingLogic.java
  6. 11 3
      jme3-core/src/main/java/com/jme3/shadow/next/PreShadowArrayRenderer.java
  7. 183 0
      jme3-core/src/main/java/com/jme3/shadow/next/PreShadowRenderer.java
  8. 99 0
      jme3-core/src/main/java/com/jme3/shadow/next/ShadowDebugControl.java
  9. 1 0
      jme3-core/src/main/java/com/jme3/shadow/next/array/BaseArrayShadowMapSlice.java
  10. 1 1
      jme3-core/src/main/java/com/jme3/shadow/next/array/PointArrayShadowMapSlice.java
  11. 11 1
      jme3-core/src/main/java/com/jme3/shadow/next/array/SpotArrayShadowMapSlice.java
  12. 87 0
      jme3-core/src/main/java/com/jme3/shadow/next/pssm/BaseShadowMapSlice.java
  13. 92 0
      jme3-core/src/main/java/com/jme3/shadow/next/pssm/DirectionalShadowMap.java
  14. 67 0
      jme3-core/src/main/java/com/jme3/shadow/next/pssm/DirectionalShadowMapSlice.java
  15. 21 4
      jme3-core/src/main/resources/Common/MatDefs/Light/PBRLighting.frag
  16. 6 1
      jme3-core/src/main/resources/Common/MatDefs/Light/PBRLighting.vert
  17. 35 86
      jme3-core/src/main/resources/Common/MatDefs/Light/StaticLighting.frag
  18. 1 1
      jme3-core/src/main/resources/Common/MatDefs/Shadow/PreShadow.vert
  19. 15 0
      jme3-core/src/main/resources/Common/MatDefs/Shadow/ShowShadowArray.frag
  20. 17 0
      jme3-core/src/main/resources/Common/MatDefs/Shadow/ShowShadowArray.j3md
  21. 74 83
      jme3-core/src/main/resources/Common/ShaderLib/InPassShadows.glsl
  22. 2 2
      jme3-core/src/main/resources/Common/ShaderLib/Lighting.glsllib

+ 23 - 0
jme3-core/src/main/java/com/jme3/material/logic/DefaultTechniqueDefLogic.java

@@ -43,6 +43,7 @@ import com.jme3.scene.Mesh;
 import com.jme3.scene.instancing.InstancedGeometry;
 import com.jme3.shader.DefineList;
 import com.jme3.shader.Shader;
+import com.jme3.shadow.next.array.ArrayShadowMap;
 import java.util.EnumSet;
 
 public class DefaultTechniqueDefLogic implements TechniqueDefLogic {
@@ -84,6 +85,28 @@ public class DefaultTechniqueDefLogic implements TechniqueDefLogic {
         renderManager.getLightFilter().filterLights(geom, filteredLightList);
         return filteredLightList;
     }
+    
+    protected float encodeLightType(Light light) {
+        switch (light.getType()) {
+            case Directional:
+                return 0.125f;
+            case Point:
+                return 0.25f;
+            case Spot:
+                return 0.5f;
+            default:
+                throw new UnsupportedOperationException("Invalid light type: " + light.getType());
+        }
+    }
+    
+    protected float encodeLightTypeAndShadowMapIndex(Light light) {
+        if (light.getShadowMap() == null) {
+            return encodeLightType(light);
+        } else {
+            ArrayShadowMap map = (ArrayShadowMap) light.getShadowMap();
+            return -(encodeLightType(light) + map.getFirstArraySlice());
+        }
+    }
 
     protected static ColorRGBA getAmbientColor(LightList lightList, boolean removeLights, ColorRGBA ambientLightColor) {
         ambientLightColor.set(0, 0, 0, 1);

+ 0 - 9
jme3-core/src/main/java/com/jme3/material/logic/ShadowStaticPassLightingLogic.java

@@ -138,15 +138,6 @@ public class ShadowStaticPassLightingLogic extends StaticPassLightingLogic {
         defines.set(numPssmSplitsDefineId, pssmSplits);
     }
 
-    @Override
-    protected float getShadowMapIndex(Light light) {
-        if (light.getShadowMap() == null) {
-            return -1.0f;
-        }
-        ArrayShadowMap map = (ArrayShadowMap) light.getShadowMap();
-        return (float) map.getFirstArraySlice();
-    }
-
     @Override
     protected void updateShadowUniforms(Renderer renderer, Shader shader, int nextTextureUnit) {
         TextureArray array = null;

+ 140 - 100
jme3-core/src/main/java/com/jme3/material/logic/SinglePassAndImageBasedLightingLogic.java

@@ -34,13 +34,19 @@ package com.jme3.material.logic;
 import com.jme3.asset.AssetManager;
 import com.jme3.bounding.BoundingSphere;
 import com.jme3.light.*;
+import static com.jme3.light.Light.Type.Directional;
+import static com.jme3.light.Light.Type.Spot;
 import com.jme3.material.*;
 import com.jme3.material.RenderState.BlendMode;
 import com.jme3.math.*;
 import com.jme3.renderer.*;
 import com.jme3.scene.Geometry;
 import com.jme3.shader.*;
-import com.jme3.util.TempVars;
+import com.jme3.shadow.next.array.ArrayShadowMap;
+import com.jme3.shadow.next.array.ArrayShadowMapSlice;
+import com.jme3.shadow.next.array.DirectionalArrayShadowMap;
+import com.jme3.texture.TextureArray;
+import java.util.Comparator;
 
 import java.util.EnumSet;
 
@@ -49,10 +55,15 @@ public final class SinglePassAndImageBasedLightingLogic extends DefaultTechnique
     private static final String DEFINE_SINGLE_PASS_LIGHTING = "SINGLE_PASS_LIGHTING";
     private static final String DEFINE_NB_LIGHTS = "NB_LIGHTS";
     private static final String DEFINE_INDIRECT_LIGHTING = "INDIRECT_LIGHTING";
+    private static final String DEFINE_IN_PASS_SHADOWS = "IN_PASS_SHADOWS";
+    private static final String DEFINE_NUM_PSSM_SPLITS = "NUM_PSSM_SPLITS";
     private static final RenderState ADDITIVE_LIGHT = new RenderState();
 
     private final ColorRGBA ambientLightColor = new ColorRGBA(0, 0, 0, 1);
-    private LightProbe lightProbe = null;
+    private LightProbe lightProbe;
+    private TextureArray shadowMapArray;
+    private Vector3f pssmSplitsPositions;
+    private int numPssmSplits;
 
     static {
         ADDITIVE_LIGHT.setBlendMode(BlendMode.AlphaAdditive);
@@ -60,20 +71,24 @@ public final class SinglePassAndImageBasedLightingLogic extends DefaultTechnique
     }
 
     private final int singlePassLightingDefineId;
+    private final int inPassShadowsDefineId;
     private final int nbLightsDefineId;
     private final int indirectLightingDefineId;
+    private final int numPssmSplitsDefineId;
 
     public SinglePassAndImageBasedLightingLogic(TechniqueDef techniqueDef) {
         super(techniqueDef);
+        numPssmSplitsDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_NUM_PSSM_SPLITS, VarType.Int);
         singlePassLightingDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_SINGLE_PASS_LIGHTING, VarType.Boolean);
         nbLightsDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_NB_LIGHTS, VarType.Int);
         indirectLightingDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_INDIRECT_LIGHTING, VarType.Boolean);
+        inPassShadowsDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_IN_PASS_SHADOWS, VarType.Boolean);
     }
 
     @Override
     public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager,
             EnumSet<Caps> rendererCaps, Geometry geometry, DefineList defines) {
-        defines.set(nbLightsDefineId, renderManager.getSinglePassLightBatchSize() * 3);
+        
         defines.set(singlePassLightingDefineId, true);
 
         // TODO: here we have a problem, this is called once before render, 
@@ -82,16 +97,52 @@ public final class SinglePassAndImageBasedLightingLogic extends DefaultTechnique
         // first pass like ambient light in phong lighting.
         // We cannot change the define between passes and the old technique, and 
         // for some reason the code fails on mac (renders nothing).
-        LightList lights = getFilteredLightList(renderManager, geometry);
-        if (lights != null) {
-            lightProbe = extractIndirectLights(lights, false);
-            if (lightProbe == null) {
-                defines.set(indirectLightingDefineId, false);
-            } else {
-                defines.set(indirectLightingDefineId, true);
+        getFilteredLightList(renderManager, geometry);
+       
+        ambientLightColor.set(0, 0, 0, 1);
+        lightProbe = null;
+        pssmSplitsPositions = null;
+        numPssmSplits = 0;
+        
+        for (int i = 0; i < filteredLightList.size(); i++) {
+            Light light = filteredLightList.get(i);
+            if (light instanceof AmbientLight) {
+                ambientLightColor.addLocal(light.getColor());
+                filteredLightList.remove(i--);
+            } else if (light instanceof LightProbe) {
+                lightProbe = (LightProbe) light;
+                filteredLightList.remove(i--);
+            } else if (light.getShadowMap() != null) {
+                ArrayShadowMap shadowMap = (ArrayShadowMap) light.getShadowMap();
+                shadowMapArray = shadowMap.getArray();
+                if (light.getType() == Light.Type.Directional) {
+                    numPssmSplits = shadowMap.getNumSlices();
+                    pssmSplitsPositions = ((DirectionalArrayShadowMap) shadowMap).getProjectionSplitPositions();
+                }
             }
         }
-
+        ambientLightColor.a = 1.0f;
+        
+        filteredLightList.sort(new Comparator<Light>() {
+            @Override
+            public int compare(Light a, Light b) {
+                boolean shadA = a.getShadowMap() != null;
+                boolean shadB = b.getShadowMap() != null;
+                if (shadA != shadB) {
+                    return shadA ? -1 : 1;
+                } else {
+                    int ordA = a.getType().ordinal();
+                    int ordB = b.getType().ordinal();
+                    return ordB - ordA;
+                }
+            }
+        });
+        
+        defines.set(nbLightsDefineId, renderManager.getSinglePassLightBatchSize() * 3);
+        defines.set(indirectLightingDefineId, lightProbe != null);
+        defines.set(inPassShadowsDefineId, shadowMapArray != null);
+        defines.set(numPssmSplitsDefineId, numPssmSplits);
+        
         return super.makeCurrent(assetManager, renderManager, rendererCaps, geometry, defines);
     }
 
@@ -123,13 +174,11 @@ public final class SinglePassAndImageBasedLightingLogic extends DefaultTechnique
         Uniform shCoeffs = shader.getUniform("g_ShCoeffs");
         Uniform lightProbePemMap = shader.getUniform("g_PrefEnvMap");
 
-        lightProbe = null;
         if (startIndex != 0) {
             // apply additive blending for 2nd and future passes
             rm.getRenderer().applyRenderState(ADDITIVE_LIGHT);
             ambientColor.setValue(VarType.Vector4, ColorRGBA.Black);
-        }else{
-            lightProbe = extractIndirectLights(lightList,true);
+        } else {
             ambientColor.setValue(VarType.Vector4, ambientLightColor);
         }
 
@@ -147,81 +196,97 @@ public final class SinglePassAndImageBasedLightingLogic extends DefaultTechnique
             lightProbeData.setVector4InArray(0,0,0,-1, 0);
         }
 
+        Uniform shadowMatricesUniform = shader.getUniform("g_ShadowMatrices");
+        shadowMatricesUniform.setMatrix4Length(numLights + numPssmSplits);
+        int shadowMatrixIndex = numPssmSplits;
         int lightDataIndex = 0;
-        TempVars vars = TempVars.get();
-        Vector4f tmpVec = vars.vect4f1;
         int curIndex;
-        int endIndex = numLights + startIndex;
-        for (curIndex = startIndex; curIndex < endIndex && curIndex < lightList.size(); curIndex++) {
-
-
-            Light l = lightList.get(curIndex);
-            if(l.getType() == Light.Type.Ambient){
-                endIndex++;
-                continue;
+        int endIndex = Math.min(startIndex + numLights, lightList.size());
+        
+        ArrayShadowMap directionalShadowMap = null;
+        
+        for (curIndex = startIndex; curIndex < endIndex; curIndex++) {
+            Light light = lightList.get(curIndex);
+            
+            if (light.getType() == Light.Type.Ambient || light.getType() == Light.Type.Probe) {
+                throw new AssertionError();
             }
-            ColorRGBA color = l.getColor();
-            //Color
-
-            if(l.getType() != Light.Type.Probe){
-                lightData.setVector4InArray(color.getRed(),
-                        color.getGreen(),
-                        color.getBlue(),
-                        l.getType().getId(),
-                        lightDataIndex);
-                lightDataIndex++;
+            
+            if (light.getShadowMap() != null) {
+                ArrayShadowMap shadowMap = (ArrayShadowMap) light.getShadowMap();
+                if (light.getType() == Directional) {
+                    directionalShadowMap = shadowMap;
+                } else if (light.getType() == Spot) {
+                    for (int j = 0; j < shadowMap.getNumSlices(); j++) {
+                        ArrayShadowMapSlice slice = (ArrayShadowMapSlice) shadowMap.getSlice(j);
+                        shadowMatricesUniform.setMatrix4InArray(
+                                slice.getBiasedViewProjectionMatrix(),
+                                shadowMatrixIndex);
+                        shadowMatrixIndex++;
+                    }
+                }
             }
+            
+            ColorRGBA color = light.getColor();
+            lightData.setVector4InArray(
+                    color.getRed(),
+                    color.getGreen(),
+                    color.getBlue(),
+                    encodeLightTypeAndShadowMapIndex(light),
+                    lightDataIndex++);
 
-            switch (l.getType()) {
-                case Directional:
-                    DirectionalLight dl = (DirectionalLight) l;
+            switch (light.getType()) {
+                case Directional: {
+                    DirectionalLight dl = (DirectionalLight) light;
                     Vector3f dir = dl.getDirection();
-                    //Data directly sent in view space to avoid a matrix mult for each pixel
-                    tmpVec.set(dir.getX(), dir.getY(), dir.getZ(), 0.0f);
-                    lightData.setVector4InArray(tmpVec.getX(), tmpVec.getY(), tmpVec.getZ(), -1, lightDataIndex);
-                    lightDataIndex++;
-                    //PADDING
-                    lightData.setVector4InArray(0,0,0,0, lightDataIndex);
-                    lightDataIndex++;
+                    lightData.setVector4InArray(dir.getX(), dir.getY(), dir.getZ(), -1, lightDataIndex++);
+                    lightData.setVector4InArray(0, 0, 0, 0, lightDataIndex++);
                     break;
-                case Point:
-                    PointLight pl = (PointLight) l;
+                }
+                case Point: {
+                    PointLight pl = (PointLight) light;
                     Vector3f pos = pl.getPosition();
                     float invRadius = pl.getInvRadius();
-                    tmpVec.set(pos.getX(), pos.getY(), pos.getZ(), 1.0f);
-
-                    lightData.setVector4InArray(tmpVec.getX(), tmpVec.getY(), tmpVec.getZ(), invRadius, lightDataIndex);
-                    lightDataIndex++;
-                    //PADDING
-                    lightData.setVector4InArray(0,0,0,0, lightDataIndex);
-                    lightDataIndex++;
+                    lightData.setVector4InArray(pos.getX(), pos.getY(), pos.getZ(), invRadius, lightDataIndex++);
+                    lightData.setVector4InArray(0, 0, 0, 0, lightDataIndex++);
                     break;
-                case Spot:
-                    SpotLight sl = (SpotLight) l;
-                    Vector3f pos2 = sl.getPosition();
-                    Vector3f dir2 = sl.getDirection();
+                }
+                case Spot: {
+                    SpotLight sl = (SpotLight) light;
+                    Vector3f pos = sl.getPosition();
+                    Vector3f dir = sl.getDirection();
                     float invRange = sl.getInvSpotRange();
                     float spotAngleCos = sl.getPackedAngleCos();
-                    tmpVec.set(pos2.getX(), pos2.getY(), pos2.getZ(),  1.0f);
-
-                    lightData.setVector4InArray(tmpVec.getX(), tmpVec.getY(), tmpVec.getZ(), invRange, lightDataIndex);
-                    lightDataIndex++;
-
-                    tmpVec.set(dir2.getX(), dir2.getY(), dir2.getZ(),  0.0f);
-                    lightData.setVector4InArray(tmpVec.getX(), tmpVec.getY(), tmpVec.getZ(), spotAngleCos, lightDataIndex);
-                    lightDataIndex++;
+                    lightData.setVector4InArray(pos.getX(), pos.getY(), pos.getZ(), invRange, lightDataIndex++);
+                    lightData.setVector4InArray(dir.getX(), dir.getY(), dir.getZ(), spotAngleCos, lightDataIndex++);
                     break;
+                }
                 default:
-                    throw new UnsupportedOperationException("Unknown type of light: " + l.getType());
+                    throw new UnsupportedOperationException("Unknown type of light: " + light.getType());
             }
         }
-        vars.release();
 
-        //Padding of unsued buffer space
-        while(lightDataIndex < numLights * 3) {
-            lightData.setVector4InArray(0f, 0f, 0f, 0f, lightDataIndex);
-            lightDataIndex++;
+        // Padding of unsued buffer space
+        while (lightDataIndex < numLights * 3) {
+            lightData.setVector4InArray(0f, 0f, 0f, 0f, lightDataIndex++);
+        }
+        
+        if (directionalShadowMap != null) {
+            for (int i = 0; i < numPssmSplits; i++) {
+                ArrayShadowMapSlice slice = (ArrayShadowMapSlice) directionalShadowMap.getSlice(i);
+                shadowMatricesUniform.setMatrix4InArray(slice.getBiasedViewProjectionMatrix(), i);
+            }
         }
+
+        if (shadowMapArray != null) {
+            rm.getRenderer().setTexture(lastTexUnit, shadowMapArray);
+            shader.getUniform("g_ShadowMapArray").setValue(VarType.Int, lastTexUnit);
+        }
+        
+        if (pssmSplitsPositions != null) {
+            shader.getUniform("g_PssmSplits").setValue(VarType.Vector3, pssmSplitsPositions);
+        }
+
         return curIndex;
     }
 
@@ -230,41 +295,16 @@ public final class SinglePassAndImageBasedLightingLogic extends DefaultTechnique
         int nbRenderedLights = 0;
         Renderer renderer = renderManager.getRenderer();
         int batchSize = renderManager.getSinglePassLightBatchSize();
-        LightList lights = getFilteredLightList(renderManager, geometry);
-        if (lights.size() == 0) {
-            updateLightListUniforms(shader, geometry, lights,batchSize, renderManager, 0, lastTexUnit);
+        if (filteredLightList.size() == 0) {
+            updateLightListUniforms(shader, geometry, filteredLightList,batchSize, renderManager, 0, lastTexUnit);
             renderer.setShader(shader);
             renderMeshFromGeometry(renderer, geometry);
         } else {
-            while (nbRenderedLights < lights.size()) {
-                nbRenderedLights = updateLightListUniforms(shader, geometry, lights, batchSize, renderManager, nbRenderedLights, lastTexUnit);
+            while (nbRenderedLights < filteredLightList.size()) {
+                nbRenderedLights = updateLightListUniforms(shader, geometry, filteredLightList, batchSize, renderManager, nbRenderedLights, lastTexUnit);
                 renderer.setShader(shader);
                 renderMeshFromGeometry(renderer, geometry);
             }
         }
     }
-
-    protected LightProbe extractIndirectLights(LightList lightList, boolean removeLights) {
-        ambientLightColor.set(0, 0, 0, 1);
-        LightProbe probe = null;
-        for (int j = 0; j < lightList.size(); j++) {
-            Light l = lightList.get(j);
-            if (l instanceof AmbientLight) {
-                ambientLightColor.addLocal(l.getColor());
-                if(removeLights){
-                    lightList.remove(l);
-                    j--;
-                }
-            }
-            if (l instanceof LightProbe) {
-                probe = (LightProbe)l;
-                if(removeLights){
-                    lightList.remove(l);
-                    j--;
-                }
-            }
-        }
-        ambientLightColor.a = 1.0f;
-        return probe;
-    }
 }

+ 1 - 1
jme3-core/src/main/java/com/jme3/material/logic/SinglePassLightingLogic.java

@@ -138,7 +138,7 @@ public final class SinglePassLightingLogic extends DefaultTechniqueDefLogic {
             lightData.setVector4InArray(color.getRed(),
                     color.getGreen(),
                     color.getBlue(),
-                    l.getType().getId(),
+                    encodeLightType(l),
                     lightDataIndex);
             lightDataIndex++;
 

+ 22 - 21
jme3-core/src/main/java/com/jme3/material/logic/StaticPassLightingLogic.java

@@ -126,10 +126,6 @@ public class StaticPassLightingLogic extends DefaultTechniqueDefLogic {
         return techniqueDef.getShader(assetManager, rendererCaps, defines);
     }
 
-    protected float getShadowMapIndex(Light light) {
-        return -1.0f;
-    }
-
     protected void updateLightListUniforms(Matrix4f viewMatrix, Shader shader) {
         Uniform ambientColor = shader.getUniform("g_AmbientLightColor");
         ambientColor.setValue(VarType.Vector4, ambientLightColor);
@@ -142,36 +138,41 @@ public class StaticPassLightingLogic extends DefaultTechniqueDefLogic {
         lightData.setVector4Length(totalSize);
 
         int index = 0;
+        
+        for (SpotLight light : tempSpotLights) {
+            ColorRGBA color = light.getColor();
+            float lightTypeAndShadowMap = encodeLightTypeAndShadowMapIndex(light);
+            lightData.setVector4InArray(color.r, color.g, color.b, lightTypeAndShadowMap, index++);
+
+            tempPosition.set(light.getPosition());
+            float invRange = light.getInvSpotRange();
+            lightData.setVector4InArray(tempPosition.x, tempPosition.y, tempPosition.z, invRange, index++);
+            
+            tempDirection.set(light.getDirection());
+            float spotAngleCos = light.getPackedAngleCos();
+            lightData.setVector4InArray(tempDirection.x, tempDirection.y, tempDirection.z, spotAngleCos, index++);
+        }
+        
         for (DirectionalLight light : tempDirLights) {
             ColorRGBA color = light.getColor();
-            float shadowMapIndex = getShadowMapIndex(light);
+            float lightTypeAndShadowMap = encodeLightTypeAndShadowMapIndex(light);
+            lightData.setVector4InArray(color.r, color.g, color.b, lightTypeAndShadowMap, index++);
+            
             tempDirection.set(light.getDirection());
-            lightData.setVector4InArray(color.r, color.g, color.b, shadowMapIndex, index++);
             lightData.setVector4InArray(tempDirection.x, tempDirection.y, tempDirection.z, 1f, index++);
         }
 
         for (PointLight light : tempPointLights) {
             ColorRGBA color = light.getColor();
-            float shadowMapIndex = getShadowMapIndex(light);
+            float lightTypeAndShadowMap = encodeLightTypeAndShadowMapIndex(light);
+            lightData.setVector4InArray(color.r, color.g, color.b, lightTypeAndShadowMap, index++);
+            
             tempPosition.set(light.getPosition());
             float invRadius = light.getInvRadius();
-            lightData.setVector4InArray(color.r, color.g, color.b, shadowMapIndex, index++);
             lightData.setVector4InArray(tempPosition.x, tempPosition.y, tempPosition.z, invRadius, index++);
         }
 
-        for (SpotLight light : tempSpotLights) {
-            ColorRGBA color = light.getColor();
-            float shadowMapIndex = getShadowMapIndex(light);
-
-            tempPosition.set(light.getPosition());
-            tempDirection.set(light.getDirection());
-
-            float invRange = light.getInvSpotRange();
-            float spotAngleCos = light.getPackedAngleCos();
-            lightData.setVector4InArray(color.r, color.g, color.b, shadowMapIndex, index++);
-            lightData.setVector4InArray(tempPosition.x, tempPosition.y, tempPosition.z, invRange, index++);
-            lightData.setVector4InArray(tempDirection.x, tempDirection.y, tempDirection.z, spotAngleCos, index++);
-        }
+        
     }
 
     protected void updateShadowUniforms(Renderer renderer, Shader shader, int nextTextureUnit) {

+ 11 - 3
jme3-core/src/main/java/com/jme3/shadow/next/PreShadowArrayRenderer.java

@@ -31,6 +31,7 @@
  */
 package com.jme3.shadow.next;
 
+import com.jme3.asset.AssetManager;
 import com.jme3.shadow.next.pssm.DirectionalShadowParameters;
 import com.jme3.light.DirectionalLight;
 import com.jme3.light.Light;
@@ -48,6 +49,7 @@ import com.jme3.renderer.ViewPort;
 import com.jme3.renderer.queue.GeometryList;
 import com.jme3.renderer.queue.OpaqueComparator;
 import com.jme3.renderer.queue.RenderQueue;
+import com.jme3.scene.Node;
 import com.jme3.shader.VarType;
 import com.jme3.shadow.next.array.DirectionalArrayShadowMap;
 import com.jme3.shadow.next.array.PointArrayShadowMap;
@@ -105,12 +107,14 @@ public class PreShadowArrayRenderer implements SceneProcessor {
 
         array.setAnisotropicFilter(1);
         array.setShadowCompareMode(ShadowCompareMode.LessOrEqual);
-        array.setMagFilter(MagFilter.Nearest);
-        array.setMinFilter(MinFilter.NearestNoMipMaps);
         
         array.setMagFilter(MagFilter.Bilinear);
         array.setMinFilter(MinFilter.BilinearNoMipMaps);
     }
+    
+    public void displayDebug(AssetManager assetManager, Node guiRoot) {
+        guiRoot.addControl(new ShadowDebugControl(assetManager, this));
+    }
 
     @Override
     public void initialize(RenderManager rm, ViewPort vp) {
@@ -135,10 +139,14 @@ public class PreShadowArrayRenderer implements SceneProcessor {
         this.textureSize = textureSize;
     }
     
+    public TextureArray getShadowMapTexture() {
+        return array;
+    }
+    
     public void addLight(Light light) {
         if (array.getImage() == null) {
             array.setImage(new Image(
-                    Format.Depth16,
+                    Format.Depth32F,
                     textureSize,
                     textureSize,
                     0,

+ 183 - 0
jme3-core/src/main/java/com/jme3/shadow/next/PreShadowRenderer.java

@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2009-2016 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 com.jme3.shadow.next;
+
+import com.jme3.shadow.next.pssm.DirectionalShadowParameters;
+import com.jme3.light.DirectionalLight;
+import com.jme3.light.Light;
+import com.jme3.material.RenderState;
+import com.jme3.math.Vector3f;
+import com.jme3.post.SceneProcessor;
+import com.jme3.profile.AppProfiler;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.Renderer;
+import com.jme3.renderer.ViewPort;
+import com.jme3.renderer.queue.GeometryList;
+import com.jme3.renderer.queue.OpaqueComparator;
+import com.jme3.renderer.queue.RenderQueue;
+import com.jme3.shadow.next.pssm.DirectionalShadowMap;
+import com.jme3.texture.FrameBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * The 4th generation of shadow mapping in jME3.
+ * <p>
+ * This version is primarily focused on rendering in-pass shadows, so pre-pass
+ * and subsequent stages are separated.
+ *
+ * @author Kirill Vainer
+ */
+public class PreShadowRenderer implements SceneProcessor {
+
+    private static final String PRE_SHADOW_TECHNIQUE_NAME = "PreShadow";
+
+    private RenderManager renderManager;
+    private ViewPort viewPort;
+    private final Vector3f[] points = new Vector3f[8];
+    private final GeometryList shadowCasters = new GeometryList(new OpaqueComparator());
+    private final List<ShadowMap> shadowMaps = new ArrayList<>();
+    private final RenderState prePassRenderState = RenderState.ADDITIONAL.clone();
+
+    private int textureSize = 1024;
+    
+    // parameters for directional lights
+    private final DirectionalShadowParameters directionalParams = new DirectionalShadowParameters();
+
+    public PreShadowRenderer() {
+        for (int i = 0; i < points.length; i++) {
+            points[i] = new Vector3f();
+        }
+
+        prePassRenderState.setFaceCullMode(RenderState.FaceCullMode.Off);
+        prePassRenderState.setColorWrite(false);
+        prePassRenderState.setDepthWrite(true);
+        prePassRenderState.setDepthTest(true);
+        prePassRenderState.setPolyOffset(1.2f, 0);
+    }
+
+    @Override
+    public void initialize(RenderManager rm, ViewPort vp) {
+        this.renderManager = rm;
+        this.viewPort = vp;
+    }
+
+    public DirectionalShadowParameters directional() {
+        return directionalParams;
+    }
+
+    public void setPolyOffset(float factor, float units) {
+        // TODO: might want to set this separately per model
+        prePassRenderState.setPolyOffset(factor, units);
+    }
+
+    public int getTextureSize() {
+        return textureSize;
+    }
+
+    public void setTextureSize(int textureSize) {
+        // TODO: support changing texture size after shadow maps are created
+        this.textureSize = textureSize;
+    }
+    
+    public void addLight(Light light) {
+        ShadowMap shadowMap;
+        switch (light.getType()) {
+            case Directional:
+                shadowMap = new DirectionalShadowMap(
+                        (DirectionalLight) light,
+                        textureSize,
+                        directionalParams.getNumSplits(),
+                        points);
+                break;
+            default:
+                throw new UnsupportedOperationException();
+        }
+        
+        light.setShadowMap(shadowMap);
+        shadowMaps.add(shadowMap);
+    }
+
+    @Override
+    public void reshape(ViewPort vp, int w, int h) {
+    }
+
+    @Override
+    public boolean isInitialized() {
+        return this.viewPort != null;
+    }
+
+    @Override
+    public void preFrame(float tpf) {
+    }
+
+    private void renderShadowMaps() {
+        renderManager.setForcedRenderState(prePassRenderState);
+        renderManager.setForcedTechnique(PRE_SHADOW_TECHNIQUE_NAME);
+
+        for (ShadowMap shadowMap : shadowMaps) {
+            switch (shadowMap.getLightType()) {
+                case Directional:
+                    DirectionalShadowMap directionalShadow = (DirectionalShadowMap) shadowMap;
+                    directionalShadow.renderShadowMap(renderManager, viewPort, directionalParams, shadowCasters);
+                    break;
+                default:
+                    throw new UnsupportedOperationException();
+            }
+        }
+
+        Renderer renderer = renderManager.getRenderer();
+        renderer.setFrameBuffer(viewPort.getOutputFrameBuffer());
+        renderManager.setForcedRenderState(null);
+        renderManager.setForcedTechnique(null);
+        renderManager.setCamera(viewPort.getCamera(), false);
+    }
+
+    @Override
+    public void postQueue(RenderQueue rq) {
+        directionalParams.updateSplitPositions(viewPort.getCamera());
+        renderShadowMaps();
+    }
+
+    @Override
+    public void postFrame(FrameBuffer out) {
+    }
+
+    @Override
+    public void cleanup() {
+    }
+
+    @Override
+    public void setProfiler(AppProfiler profiler) {
+    }
+
+}

+ 99 - 0
jme3-core/src/main/java/com/jme3/shadow/next/ShadowDebugControl.java

@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2009-2017 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 com.jme3.shadow.next;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.material.Material;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.ViewPort;
+import com.jme3.scene.Node;
+import com.jme3.scene.Spatial;
+import com.jme3.scene.control.AbstractControl;
+import com.jme3.shader.VarType;
+import com.jme3.texture.Image;
+import com.jme3.texture.TextureArray;
+import com.jme3.ui.Picture;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Shows the shadow maps on the screen
+ *
+ * @author Kirill Vainer
+ */
+final class ShadowDebugControl extends AbstractControl {
+
+    private final List<Picture> pictures = new ArrayList<>();
+
+    public ShadowDebugControl(AssetManager assetManager, PreShadowArrayRenderer shadowRenderer) {
+        TextureArray shadowMapArray = shadowRenderer.getShadowMapTexture();
+        Image shadowMap = shadowMapArray.getImage();
+        for (int i = 0; i < shadowMap.getDepth(); i++) {
+            Picture picture = new Picture("Shadow Map " + i);
+            picture.setPosition(20, i * 128 + 20);
+            picture.setWidth(128);
+            picture.setHeight(128);
+
+            Material material = new Material(assetManager, "Common/MatDefs/Shadow/ShowShadowArray.j3md");
+            material.setTexture("ShadowMapArray", shadowMapArray);
+            material.setFloat("ShadowMapSlice", i);
+            picture.setMaterial(material);
+
+            pictures.add(picture);
+        }
+    }
+
+    @Override
+    public void setSpatial(Spatial spatial) {
+        if (spatial != null) {
+            for (Picture picture : pictures) {
+                ((Node) spatial).detachChild(picture);
+            }
+        }
+        super.setSpatial(spatial);
+        if (spatial != null) {
+            for (Picture picture : pictures) {
+                ((Node) spatial).attachChild(picture);
+            }
+        }
+    }
+
+    @Override
+    protected void controlUpdate(float tpf) {
+
+    }
+
+    @Override
+    protected void controlRender(RenderManager rm, ViewPort vp) {
+    }
+
+}

+ 1 - 0
jme3-core/src/main/java/com/jme3/shadow/next/array/BaseArrayShadowMapSlice.java

@@ -82,6 +82,7 @@ public class BaseArrayShadowMapSlice<T extends Light> implements ArrayShadowMapS
 
         if (fbNeedClear) {
             renderer.setFrameBuffer(frameBuffer);
+            renderer.clearClipRect();
             renderer.clearBuffers(false, true, false);
             fbNeedClear = false;
         }

+ 1 - 1
jme3-core/src/main/java/com/jme3/shadow/next/array/PointArrayShadowMapSlice.java

@@ -51,7 +51,7 @@ public class PointArrayShadowMapSlice extends BaseArrayShadowMapSlice<PointLight
     }
 
     public void updateShadowCamera(ViewPort viewPort, PointLight light, GeometryList shadowCasters) {
-        shadowCamera.setFrustumPerspective(90f, 1f, 0.1f, light.getRadius());
+        shadowCamera.setFrustumPerspective(90f, 1f, 0.5f, light.getRadius());
         shadowCamera.setLocation(light.getPosition());
         for (Spatial scene : viewPort.getScenes()) {
             ShadowUtil.getGeometriesInCamFrustum(scene, shadowCamera, ShadowMode.Cast, shadowCasters);

+ 11 - 1
jme3-core/src/main/java/com/jme3/shadow/next/array/SpotArrayShadowMapSlice.java

@@ -49,10 +49,20 @@ public class SpotArrayShadowMapSlice extends BaseArrayShadowMapSlice<SpotLight>
     public SpotArrayShadowMapSlice(TextureArray array, int layer, int textureSize) {
         super(array, layer, textureSize, true);
     }
+    
+    private static boolean isParallelToYUp(Vector3f direction) {
+        return direction.x == 0 && direction.z == 0
+                && (direction.y == -1 || direction.y == 1);
+    }
 
     public void updateShadowCamera(ViewPort viewPort, SpotLight light, GeometryList shadowCasters) {
         shadowCamera.setLocation(light.getPosition());
-        shadowCamera.lookAtDirection(light.getDirection(), Vector3f.UNIT_Y);
+        if (isParallelToYUp(light.getDirection())) {
+            // direction and up cannot be parallel
+            shadowCamera.lookAtDirection(light.getDirection(), Vector3f.UNIT_Z);
+        } else {
+            shadowCamera.lookAtDirection(light.getDirection(), Vector3f.UNIT_Y);
+        }
         shadowCamera.setFrustumPerspective(light.getSpotOuterAngle() * FastMath.RAD_TO_DEG * 2.0f, 1, 1, light.getSpotRange());
         for (Spatial scene : viewPort.getScenes()) {
             ShadowUtil.getGeometriesInCamFrustum(scene, shadowCamera, RenderQueue.ShadowMode.Cast, shadowCasters);

+ 87 - 0
jme3-core/src/main/java/com/jme3/shadow/next/pssm/BaseShadowMapSlice.java

@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2009-2016 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 com.jme3.shadow.next.pssm;
+
+import com.jme3.light.Light;
+import com.jme3.math.Matrix4f;
+import com.jme3.math.Vector3f;
+import com.jme3.renderer.Camera;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.Renderer;
+import com.jme3.renderer.ViewPort;
+import com.jme3.renderer.queue.GeometryList;
+import com.jme3.texture.FrameBuffer;
+import com.jme3.texture.Image;
+import com.jme3.texture.Texture.MagFilter;
+import com.jme3.texture.Texture.MinFilter;
+import com.jme3.texture.Texture.ShadowCompareMode;
+import com.jme3.texture.Texture2D;
+import com.jme3.shadow.next.ShadowMapSlice;
+
+public abstract class BaseShadowMapSlice<T extends Light> implements ShadowMapSlice<T> {
+
+    protected final FrameBuffer frameBuffer;
+    protected final Texture2D depthTexture;
+    protected final Camera shadowCamera;
+    protected final Vector3f[] points;
+
+    public BaseShadowMapSlice(int size, Vector3f[] points) {
+        this.depthTexture = new Texture2D(size, size, Image.Format.Depth16);
+        this.depthTexture.setAnisotropicFilter(1);
+        this.depthTexture.setShadowCompareMode(ShadowCompareMode.LessOrEqual);
+        this.depthTexture.setMagFilter(MagFilter.Bilinear);
+        this.depthTexture.setMinFilter(MinFilter.BilinearNoMipMaps);
+        this.shadowCamera = new Camera(size, size);
+        this.frameBuffer = new FrameBuffer(size, size, 1);
+        this.frameBuffer.setDepthTexture(depthTexture);
+        this.points = points;
+    }
+
+    @Override
+    public void renderShadowMap(RenderManager renderManager, T light, ViewPort viewPort, GeometryList shadowCasters) {
+        Renderer renderer = renderManager.getRenderer();
+
+        renderer.setFrameBuffer(frameBuffer);
+        renderer.clearBuffers(false, true, false);
+
+        if (shadowCasters.size() > 0) {
+            renderManager.setCamera(shadowCamera, false);
+            viewPort.getQueue().renderShadowQueue(shadowCasters, renderManager, shadowCamera, true);
+        }
+    }
+
+    @Override
+    public Matrix4f getBiasedViewProjectionMatrix() {
+//        return shadowCamera.getViewProjectionMatrix();
+        throw new UnsupportedOperationException();
+    }
+}

+ 92 - 0
jme3-core/src/main/java/com/jme3/shadow/next/pssm/DirectionalShadowMap.java

@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2009-2016 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 com.jme3.shadow.next.pssm;
+
+import com.jme3.light.DirectionalLight;
+import com.jme3.light.Light.Type;
+import com.jme3.math.Vector3f;
+import com.jme3.math.Vector4f;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.ViewPort;
+import com.jme3.renderer.queue.GeometryList;
+import com.jme3.shadow.next.ShadowMapSlice;
+import com.jme3.shadow.next.ShadowMap;
+
+/**
+ * @author Kirill Vainer
+ */
+public class DirectionalShadowMap implements ShadowMap<DirectionalLight> {
+
+    private final DirectionalLight light;
+    private final DirectionalShadowMapSlice[] splits;
+    private final Vector3f projectionSplitPositions = new Vector3f();
+
+    public DirectionalShadowMap(DirectionalLight light, int textureSize, int numSplits, Vector3f[] points) {
+        this.light = light;
+        this.splits = new DirectionalShadowMapSlice[numSplits];
+        for (int i = 0; i < splits.length; i++) {
+            this.splits[i] = new DirectionalShadowMapSlice(textureSize, points);
+        }
+    }
+
+    public void renderShadowMap(RenderManager renderManager, ViewPort viewPort, DirectionalShadowParameters params, GeometryList shadowCasters) {
+        projectionSplitPositions.set(params.getProjectionSplitPositions());
+        float[] splitPositionsViewSpace = params.getSplitPositions();
+        for (int i = 0; i < splits.length; i++) {
+            float near = splitPositionsViewSpace[i];
+            float far = splitPositionsViewSpace[i + 1];
+            shadowCasters.clear();
+            splits[i].updateShadowCamera(viewPort, light, shadowCasters, near, far);
+            splits[i].renderShadowMap(renderManager, light, viewPort, shadowCasters);
+        }
+    }
+
+    public Vector3f getProjectionSplitPositions() {
+        return projectionSplitPositions;
+    }
+
+    @Override
+    public int getNumSlices() {
+        return splits.length;
+    }
+
+    @Override
+    public ShadowMapSlice getSlice(int index) {
+        return splits[index];
+    }
+
+    @Override
+    public Type getLightType() {
+        return Type.Directional;
+    }
+
+}

+ 67 - 0
jme3-core/src/main/java/com/jme3/shadow/next/pssm/DirectionalShadowMapSlice.java

@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2009-2016 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 com.jme3.shadow.next.pssm;
+
+import com.jme3.light.DirectionalLight;
+import com.jme3.math.Vector3f;
+import com.jme3.renderer.ViewPort;
+import com.jme3.renderer.queue.GeometryList;
+import com.jme3.shadow.ShadowUtil;
+import com.jme3.texture.Texture2D;
+
+/**
+ * @author Kirill Vainer
+ */
+public class DirectionalShadowMapSlice extends BaseShadowMapSlice<DirectionalLight> {
+
+    public DirectionalShadowMapSlice(int size, Vector3f[] points) {
+        super(size, points);
+        this.shadowCamera.setParallelProjection(true);
+    }
+
+    public void updateShadowCamera(
+            ViewPort viewPort,
+            DirectionalLight light,
+            GeometryList shadowCasters,
+            float near,
+            float far) {
+        ShadowUtil.updateFrustumPoints(viewPort.getCamera(), near, far, points);
+        shadowCamera.lookAtDirection(light.getDirection(), shadowCamera.getUp());
+        
+        int textureSize = frameBuffer.getWidth();
+        ShadowUtil.updateShadowCamera(viewPort, null, shadowCamera, points, shadowCasters, textureSize);
+    }
+
+    public Texture2D getTexture() {
+        return depthTexture;
+    }
+}

+ 21 - 4
jme3-core/src/main/resources/Common/MatDefs/Light/PBRLighting.frag

@@ -2,7 +2,7 @@
 #import "Common/ShaderLib/PBR.glsllib"
 #import "Common/ShaderLib/Parallax.glsllib"
 #import "Common/ShaderLib/Lighting.glsllib"
-
+#import "Common/ShaderLib/InPassShadows.glsl"
 
 varying vec2 texCoord;
 #ifdef SEPARATE_TEXCOORD
@@ -28,6 +28,8 @@ varying vec3 wPosition;
   uniform vec4 g_LightProbeData;
 #endif
 
+uniform vec4 g_AmbientLightColor;
+
 #ifdef BASECOLORMAP
   uniform sampler2D m_BaseColorMap;
 #endif
@@ -87,7 +89,7 @@ varying vec3 wNormal;
 uniform float m_AlphaDiscardThreshold;
 #endif
 
-void main(){
+void main() {
     vec2 newTexCoord;
     vec3 viewDir = normalize(g_CameraPosition - wPosition);
 
@@ -216,11 +218,20 @@ void main(){
        specularColor.rgb *= lightMapColor;
     #endif
 
+    Shadow_ProcessPssmSlice();
+
 
     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];                
+
+        float shadowMapIndex = -1.0;
+        if (lightColor.w < 0.0) {
+            shadowMapIndex = floor(-lightColor.w);
+            lightColor.w = fract(-lightColor.w);
+        }
+
+        vec4 lightData1 = g_LightData[i+1];
         vec4 lightDir;
         vec3 lightVec;            
         lightComputeDir(wPosition, lightColor.w, lightData1, lightDir, lightVec);
@@ -228,7 +239,7 @@ void main(){
         float fallOff = 1.0;
         #if __VERSION__ >= 110
             // allow use of control flow
-        if(lightColor.w > 1.0){
+        if(lightColor.w > 0.4){
         #endif
             fallOff =  computeSpotFalloff(g_LightData[i+2], lightDir.xyz);
         #if __VERSION__ >= 110
@@ -237,6 +248,10 @@ void main(){
         //point light attenuation
         fallOff *= lightDir.w;
 
+        if (shadowMapIndex >= 0.0) {
+            fallOff *= Shadow_Process(i / 3, lightColor.w, shadowMapIndex, lightVec, lightDir.xyz, wPosition, lightData1.w);
+        }
+       
         vec3 directDiffuse;
         vec3 directSpecular;
         
@@ -249,6 +264,8 @@ void main(){
         gl_FragColor.rgb += directLighting * fallOff;
     }
 
+    gl_FragColor.rgb += g_AmbientLightColor.rgb * diffuseColor.rgb;
+
     #ifdef INDIRECT_LIGHTING
         vec3 rv = reflect(-viewDir.xyz, normal.xyz);
         //prallax fix for spherical bounds from https://seblagarde.wordpress.com/2012/09/29/image-based-lighting-approaches-and-parallax-corrected-cubemap/

+ 6 - 1
jme3-core/src/main/resources/Common/MatDefs/Light/PBRLighting.vert

@@ -1,6 +1,7 @@
 #import "Common/ShaderLib/GLSLCompat.glsllib"
 #import "Common/ShaderLib/Instancing.glsllib"
 #import "Common/ShaderLib/Skinning.glsllib"
+#import "Common/ShaderLib/InPassShadows.glsl"
 
 
 uniform vec4 m_BaseColor;
@@ -52,7 +53,11 @@ void main(){
        texCoord2 = inTexCoord2;
     #endif
 
-    wPosition = TransformWorld(modelSpacePos).xyz;
+    vec3 worldPos = TransformWorld(modelSpacePos).xyz;
+
+    Shadow_ProcessProjCoord(worldPos);
+
+    wPosition = worldPos;
     wNormal  = TransformWorldNormal(modelSpaceNorm);
 
     #if defined(NORMALMAP) || defined(PARALLAXMAP)

+ 35 - 86
jme3-core/src/main/resources/Common/MatDefs/Light/StaticLighting.frag

@@ -1,5 +1,4 @@
 #import "Common/ShaderLib/GLSLCompat.glsllib"
-#import "Common/ShaderLib/BlinnPhongLighting.glsllib"
 #import "Common/ShaderLib/Lighting.glsllib"
 #import "Common/ShaderLib/InPassShadows.glsl"
 #import "Common/ShaderLib/PBR.glsllib"
@@ -34,7 +33,7 @@
 #define SPOT_LIGHT_START          (SPOT_SHADOW_LIGHT_END)
 #define SPOT_LIGHT_END            (SPOT_LIGHT_START + NUM_SPOT_LIGHTS * 3)
 
-#define LIGHT_DATA_SIZE           (SPOT_LIGHT_END)
+#define LIGHT_DATA_SIZE           (NUM_SHADOW_DIR_LIGHTS * 2 )
 
 uniform vec3 g_CameraPosition;
 
@@ -64,72 +63,34 @@ struct surface_t {
     float ndotv;
 };
 
-float Lighting_ProcessAttenuation(float invRadius, float dist) {
-    #ifdef SRGB
-        float invRadTimesDist = invRadius * dist;
-        float atten = (1.0 - invRadTimesDist) / (1.0 + invRadTimesDist * dist);
-        return clamp(atten, 0.0, 1.0);
-    #else
-        return max(0.0, 1.0 - invRadius * dist);
-    #endif
-}
-
-void Lighting_ProcessDirectional(int lightIndex, surface_t surface, out vec3 outDiffuse, out vec3 outSpecular) {
+void Lighting_Process(in int lightIndex, in surface_t surface, out vec3 outDiffuse, out vec3 outSpecular, inout int startProjIndex) {
     vec4 lightColor = g_LightData[lightIndex];
-    vec3 lightDirection = g_LightData[lightIndex + 1].xyz;
+    vec4 lightData1 = g_LightData[lightIndex + 1];
+    float shadowMapIndex = -1.0;
 
-    PBR_ComputeDirectLightSpecWF(surface.normal, -lightDirection, surface.viewDir,
-                                 lightColor.rgb, surface.specular.rgb, surface.roughness, surface.ndotv,
-                                 outDiffuse, outSpecular);
-}
-
-vec3 Lighting_ProcessPoint(in int lightIndex, in surface_t surface, out vec3 outDiffuse, out vec3 outSpecular) {
-    vec4 lightColor     = g_LightData[lightIndex];
-    vec4 lightPosition  = g_LightData[lightIndex + 1];
-    vec3 lightDirection = lightPosition.xyz - surface.position;
-    float dist = length(lightDirection);
-    lightDirection /= vec3(dist);
-    float atten = Lighting_ProcessAttenuation(lightPosition.w, dist);
-    if (atten == 0.0) {
-        outDiffuse = vec3(0.0);
-        outSpecular = vec3(0.0);
-        return lightDirection;
+    if (lightColor.w < 0.0) {
+        lightColor.w = -lightColor.w;
+        shadowMapIndex = floor(lightColor.w);
+        lightColor.w = lightColor.w - shadowMapIndex;
     }
-    PBR_ComputeDirectLightSpecWF(surface.normal, lightDirection, surface.viewDir,
-                                 lightColor.rgb, surface.specular.rgb, surface.roughness, surface.ndotv,
-                                 outDiffuse, outSpecular);
 
-    outDiffuse *= atten;
-    outSpecular *= atten;
+    vec4 lightDir;
+    vec3 lightVec;
+    lightComputeDir(surface.position, lightColor.w, lightData1, lightDir, lightVec);
 
-    return lightDirection;
-}
-
-void Lighting_ProcessSpot(in int lightIndex, in surface_t surface, out vec3 outDiffuse, out vec3 outSpecular) {
-    vec4 lightColor     = g_LightData[lightIndex];
-    vec4 lightPosition  = g_LightData[lightIndex + 1];
-    vec4 lightDirection = g_LightData[lightIndex + 2];
-    vec3 lightVector    = lightPosition.xyz - surface.position;
-    float dist          = length(lightVector);
-    lightVector        /= vec3(dist);
-    float atten         = computeSpotFalloff(lightDirection, lightVector);
-    if (atten == 0.0) {
-        outDiffuse = vec3(0.0);
-        outSpecular = vec3(0.0);
-        return;
+    if (shadowMapIndex >= 0.0) {
+        lightDir.w *= Shadow_Process(lightColor.w, lightDir.xyz, shadowMapIndex, startProjIndex);
     }
-    atten *= Lighting_ProcessAttenuation(lightPosition.w, dist);
-    if (atten == 0.0) {
-        outDiffuse = vec3(0.0);
-        outSpecular = vec3(0.0);
-        return;
+
+    if (lightColor.w >= 0.5) {
+        lightDir.w *= computeSpotFalloff(g_LightData[lightIndex + 2], lightDir.xyz);
     }
-    PBR_ComputeDirectLightSpecWF(surface.normal, lightVector, surface.viewDir,
+
+    lightColor.rgb *= lightDir.w;
+    
+    PBR_ComputeDirectLightSpecWF(surface.normal, lightDir.xyz, surface.viewDir,
                                  lightColor.rgb, surface.specular.rgb, surface.roughness, surface.ndotv,
                                  outDiffuse, outSpecular);
-
-    outDiffuse *= atten;
-    outSpecular *= atten;
 }
 
 void Lighting_ProcessAll(surface_t surface, out vec3 ambient, out vec3 diffuse, out vec3 specular) {
@@ -143,62 +104,50 @@ void Lighting_ProcessAll(surface_t surface, out vec3 ambient, out vec3 diffuse,
 #if LIGHT_DATA_SIZE > 0
     int projIndex = 0;
 
-    for (int i = DIR_SHADOW_LIGHT_START; i < DIR_SHADOW_LIGHT_END; i += 2) {
+    for (int i = SPOT_SHADOW_LIGHT_START; i < SPOT_SHADOW_LIGHT_END; i += 3) {
         vec3 outDiffuse, outSpecular;
-        Lighting_ProcessDirectional(i, surface, outDiffuse, outSpecular);
-
-        float shadow = Shadow_Process(0, vec3(0.0), g_LightData[i].w, projIndex);
-        outDiffuse *= shadow;
-        outSpecular *= shadow;
-
+        Lighting_Process(i, surface, outDiffuse, outSpecular, projIndex);
         diffuse   += outDiffuse;
         specular  += outSpecular;
     }
 
-    for (int i = DIR_LIGHT_START; i < DIR_LIGHT_END; i += 2) {
+    for (int i = SPOT_LIGHT_START; i < SPOT_LIGHT_END; i += 3) {
         vec3 outDiffuse, outSpecular;
-        Lighting_ProcessDirectional(i, surface, outDiffuse, outSpecular);
+        Lighting_Process(i, surface, outDiffuse, outSpecular, projIndex);
         diffuse   += outDiffuse;
         specular  += outSpecular;
     }
 
-    for (int i = POINT_SHADOW_LIGHT_START; i < POINT_SHADOW_LIGHT_END; i += 2) {
+    for (int i = DIR_SHADOW_LIGHT_START; i < DIR_SHADOW_LIGHT_END; i += 2) {
         vec3 outDiffuse, outSpecular;
-        vec3 lightDir = Lighting_ProcessPoint(i, surface, outDiffuse, outSpecular);
-
-        float shadow = Shadow_Process(1, lightDir, g_LightData[i].w, projIndex);
-        outDiffuse *= shadow;
-        outSpecular *= shadow;
-
+        Lighting_Process(i, surface, outDiffuse, outSpecular, projIndex);
         diffuse   += outDiffuse;
         specular  += outSpecular;
     }
-    for (int i = POINT_LIGHT_START; i < POINT_LIGHT_END; i += 2) {
+
+    for (int i = DIR_LIGHT_START; i < DIR_LIGHT_END; i += 2) {
         vec3 outDiffuse, outSpecular;
-        Lighting_ProcessPoint(i, surface, outDiffuse, outSpecular);
+        Lighting_Process(i, surface, outDiffuse, outSpecular, projIndex);
         diffuse   += outDiffuse;
         specular  += outSpecular;
     }
 
-    for (int i = SPOT_SHADOW_LIGHT_START; i < SPOT_SHADOW_LIGHT_END; i += 3) {
+    for (int i = POINT_SHADOW_LIGHT_START; i < POINT_SHADOW_LIGHT_END; i += 2) {
         vec3 outDiffuse, outSpecular;
-        Lighting_ProcessSpot(i, surface, outDiffuse, outSpecular);
-
-        float shadow = Shadow_Process(2, vec3(0.0), g_LightData[i].w, projIndex);
-        outDiffuse *= shadow;
-        outSpecular *= shadow;
-
+        Lighting_Process(i, surface, outDiffuse, outSpecular, projIndex);
         diffuse   += outDiffuse;
         specular  += outSpecular;
     }
 
-    for (int i = SPOT_LIGHT_START; i < SPOT_LIGHT_END; i += 3) {
+    for (int i = POINT_LIGHT_START; i < POINT_LIGHT_END; i += 2) {
         vec3 outDiffuse, outSpecular;
-        Lighting_ProcessSpot(i, surface, outDiffuse, outSpecular);
+        Lighting_Process(i, surface, outDiffuse, outSpecular, projIndex);
         diffuse   += outDiffuse;
         specular  += outSpecular;
     }
 
+    
+
 #endif
 }
 

+ 1 - 1
jme3-core/src/main/resources/Common/MatDefs/Shadow/PreShadow.vert

@@ -29,7 +29,7 @@ void main() {
         vec3 lightDir = g_CameraPosition - TransformWorld(modelSpacePos).xyz;
 
         // The Z value to write into the depth map, should be [0.0, 1.0]
-        float z = length(lightDir) / g_FrustumNearFar.y;
+        float z = sqrt(length(lightDir) / g_FrustumNearFar.y);
 
         // Remap [0.0, 1.0] into [-1.0, 1.0]
         gl_Position.z = (clamp(z, 0.0, 1.0) * 2.0 - 1.0) * gl_Position.w;

+ 15 - 0
jme3-core/src/main/resources/Common/MatDefs/Shadow/ShowShadowArray.frag

@@ -0,0 +1,15 @@
+#import "Common/ShaderLib/GLSLCompat.glsllib"
+
+uniform float m_ShadowMapSlice;
+uniform sampler2DArray m_ShadowMapArray;
+varying vec2 texCoord1;
+
+void main() {
+    float shadow = texture2D(m_ShadowMapArray, vec3(texCoord1, m_ShadowMapSlice)).r;
+
+    shadow = sqrt(shadow);
+
+    // TODO: make it betterer
+    gl_FragColor.rgb = vec3(shadow);
+    gl_FragColor.a = 1.0;
+}

+ 17 - 0
jme3-core/src/main/resources/Common/MatDefs/Shadow/ShowShadowArray.j3md

@@ -0,0 +1,17 @@
+MaterialDef Pre Shadow {
+
+    MaterialParameters {
+        TextureArray ShadowMapArray
+        Float ShadowMapSlice
+    }
+
+    Technique {
+        VertexShader   GLSL150 : Common/MatDefs/Misc/Unshaded.vert
+        FragmentShader GLSL150 : Common/MatDefs/Shadow/ShowShadowArray.frag
+
+        WorldParameters {
+            WorldViewProjectionMatrix
+            ViewProjectionMatrix
+        }
+    }
+}

+ 74 - 83
jme3-core/src/main/resources/Common/ShaderLib/InPassShadows.glsl

@@ -1,100 +1,98 @@
-#ifndef NUM_SHADOW_DIR_LIGHTS
-#define NUM_SHADOW_DIR_LIGHTS 0
-#endif
-#ifndef NUM_SHADOW_POINT_LIGHTS
-#define NUM_SHADOW_POINT_LIGHTS 0
-#endif
-#ifndef NUM_SHADOW_SPOT_LIGHTS
-#define NUM_SHADOW_SPOT_LIGHTS 0
-#endif
+#import "Common/ShaderLib/GLSLCompat.glsllib"
+
+#extension GL_EXT_texture_array : enable
+
 #ifndef NUM_PSSM_SPLITS
 #define NUM_PSSM_SPLITS 0
 #endif
 
-#define SHADOW_DATA_SIZE (NUM_SHADOW_DIR_LIGHTS * NUM_PSSM_SPLITS + NUM_SHADOW_POINT_LIGHTS * 6 + NUM_SHADOW_SPOT_LIGHTS)
+#ifdef IN_PASS_SHADOWS
 
-#if SHADOW_DATA_SIZE > 0
+    uniform mat4 g_ShadowMatrices[(NB_LIGHTS/3) + NUM_PSSM_SPLITS];
 
-    varying vec4 vProjCoord[SHADOW_DATA_SIZE];
+#if NUM_PSSM_SPLITS > 0
+    varying vec3 dirProjCoord[NUM_PSSM_SPLITS];
+#else
+    varying vec3 dirProjCoord[1];
+#endif
 
     #ifdef VERTEX_SHADER
-        uniform mat4 g_ShadowMatrices[SHADOW_DATA_SIZE];
-
         void Shadow_ProcessProjCoord(vec3 worldPos) {
-            for (int i = 0; i < SHADOW_DATA_SIZE; i++) {
-                vProjCoord[i] = g_ShadowMatrices[i] * vec4(worldPos, 1.0);
+#if NUM_PSSM_SPLITS > 0
+            for (int i = 0; i < NUM_PSSM_SPLITS; i++) {
+                #if __VERSION__ >= 150
+                    dirProjCoord[i] = mat4x3(g_ShadowMatrices[i]) * vec4(worldPos, 1.0);
+                #else
+                    dirProjCoord[i] = (g_ShadowMatrices[i] * vec4(worldPos, 1.0)).xyz;
+                #endif
             }
+#endif
         }
     #else
         uniform sampler2DArrayShadow g_ShadowMapArray;
         uniform vec3 g_PssmSplits;
 
-        int pssmSliceOffset;
+        float pssmSliceOffset;
 
         void Shadow_ProcessPssmSlice() {
-            #if defined(NUM_PSSM_SPLITS) && NUM_PSSM_SPLITS > 1
-                pssmSliceOffset = int(dot(step(g_PssmSplits.xyz, gl_FragCoord.zzz), vec3(1.0)));
+            #if NUM_PSSM_SPLITS > 1
+                pssmSliceOffset = dot(step(g_PssmSplits.xyz, gl_FragCoord.zzz), vec3(1.0));
             #else
-                pssmSliceOffset = 0;
+                pssmSliceOffset = 0.0;
             #endif
         }
 
-        /**
-         * Returns a float from 0.0 - 5.0 containing the index
-         * of the cubemap face to fetch for the given direction
-         */
-        float Shadow_GetCubeMapFace(in vec3 direction) {
-            vec3 mag = abs(direction);
-
-            // Compare each component against the other two
-            // Largest component is set to 1.0, the rest are 0.0
-            vec3 largestComp = step(mag.yzx, mag) * step(mag.zxy, mag);
-
-            // Negative components are set to 1.0, the positive are 0.0
-            vec3 negComp = step(direction, vec3(0.0));
-
-            // Each component contains the face index to use
-            vec3 faceIndices = vec3(0.0, 2.0, 4.0) + negComp;
-
-            // Pick the face index with the largest component
-            return dot(largestComp, faceIndices);
-        }
-
-        float Shadow_ProcessDirectional(in int lightType, in vec3 lightDir, in float startArrayLayer, inout int startProjIndex) {
-            float arraySlice = startArrayLayer + float(pssmSliceOffset);
-            vec3 projCoord = vProjCoord[startProjIndex + pssmSliceOffset].xyz;
-            startProjIndex += NUM_PSSM_SPLITS;
-            return texture(g_ShadowMapArray, vec4(projCoord.xy, arraySlice, projCoord.z));
-        }
-
-        float Shadow_ProcessSpot(in int lightType, in vec3 lightDir, in float startArrayLayer, inout int startProjIndex) {
-            vec4 projCoord = vProjCoord[startProjIndex];
-            projCoord.xyz /= projCoord.w;
-            startProjIndex ++;
-            return texture(g_ShadowMapArray, vec4(projCoord.xy, startArrayLayer, projCoord.z));
+        vec3 Shadow_GetCubeMapTC(in vec3 direction) {
+            vec3 axis = abs(direction);
+            float largest = max(axis.x, max(axis.y, axis.z));
+            vec3 tc;
+            if (largest == axis.x) {
+                if (direction.x > 0.0) {
+                    tc = vec3( direction.z, -direction.y, 0.0);
+                } else {
+                    tc = vec3(-direction.z, -direction.y, 1.0);
+                }
+            } else if (largest == axis.y) {
+                if (direction.y > 0.0) {
+                    tc = vec3(-direction.x, direction.z, 2.0);
+                } else {
+                    tc = vec3(-direction.x, -direction.z, 3.0);
+                }
+            } else {
+                if (direction.z > 0.0) {
+                    tc = vec3(-direction.x, -direction.y, 4.0);
+                } else {
+                    tc = vec3(direction.x,  -direction.y, 5.0);
+                }
+            }
+            largest = 1.0 / largest;
+            tc.xy = 0.5 * (tc.xy * vec2(largest) + 1.0);
+            return tc;
         }
 
-        float Shadow_Process(in int lightType, in vec3 lightDir, in float startArrayLayer, inout int startProjIndex) {
-            float arraySlice = startArrayLayer;
-            vec4 projCoord;
-
-            if (lightType == 0) {
-                arraySlice += float(pssmSliceOffset);
-                projCoord = vProjCoord[startProjIndex + pssmSliceOffset];
-                startProjIndex += NUM_PSSM_SPLITS;
-            } else if (lightType == 1) {
-                float face = Shadow_GetCubeMapFace(lightDir);
-                arraySlice += face;
-                projCoord = vProjCoord[startProjIndex + int(face)];
-                projCoord.xyz /= projCoord.w;
-                startProjIndex += 6;
+        float Shadow_Process(int lightIndex, float lightType, float shadowMapIndex, 
+                             vec3 lightVec, vec3 lightDir, 
+                             vec3 worldPos, float invRadius) {
+            vec4 tc;
+
+            if (lightType <= 0.2) {
+                vec3 projCoord = dirProjCoord[int(pssmSliceOffset)];
+                tc = vec4(projCoord.xy, shadowMapIndex + pssmSliceOffset, projCoord.z);
+            } else if (lightType <= 0.3) {
+                vec3 projCoord = Shadow_GetCubeMapTC(lightVec.xyz);
+                float dist = sqrt(length(lightVec) * invRadius);
+                tc = vec4(projCoord.xy, shadowMapIndex + projCoord.z, dist);
             } else {
-                projCoord = vProjCoord[startProjIndex];
-                projCoord.xyz /= projCoord.w;
-                startProjIndex += 1;
+                tc = g_ShadowMatrices[NUM_PSSM_SPLITS + lightIndex] * vec4(worldPos, 1.0);
+                tc.xyz /= tc.w;
+                tc = vec4(tc.xy, shadowMapIndex, tc.z);
             }
 
-            return texture(g_ShadowMapArray, vec4(projCoord.xy, arraySlice, projCoord.z));
+            #if __VERSION__ >= 150
+                return texture(g_ShadowMapArray, tc);
+            #else
+                return shadow2DArray(g_ShadowMapArray, tc).x;
+            #endif
         }
     #endif
 
@@ -149,10 +147,9 @@
         }
     #endif
 #else
-    #define NUM_SHADOW_DIR_LIGHTS 0
-    #define NUM_SHADOW_POINT_LIGHTS 0
-    #define NUM_SHADOW_SPOT_LIGHTS 0
     #define NUM_PSSM_SPLITS 0
+    
+    const int pssmSliceOffset = 0;
 
     void Shadow_ProcessProjCoord(vec3 worldPos) {
     }
@@ -160,15 +157,9 @@
     void Shadow_ProcessPssmSlice() {
     }
 
-    float Shadow_ProcessDirectional(int startLightIndex, float startArrayLayer) {
-        return 1.0;
-    }
-
-    float Shadow_ProcessSpot(int startLightIndex, float startArrayLayer) {
-        return 1.0;
-    }
-
-    float Shadow_Process(in int lightType, in vec3 lightDir, in float startArrayLayer, inout int startProjIndex) {
+    float Shadow_Process(int lightIndex, float lightType, float shadowMapIndex, 
+                             vec3 lightVec, vec3 lightDir, 
+                             vec3 worldPos, float invRadius) {
         return 1.0;
     }
 #endif

+ 2 - 2
jme3-core/src/main/resources/Common/ShaderLib/Lighting.glsllib

@@ -7,7 +7,7 @@
 * Outputs the light direction and the light half vector. 
 */
 void lightComputeDir(in vec3 worldPos, in float lightType, in vec4 position, out vec4 lightDir, out vec3 lightVec){
-    float posLight = step(0.5, lightType);    
+    float posLight = step(0.2, lightType);    
     vec3 tempVec = position.xyz * sign(posLight - 0.5) - (worldPos * posLight);
     lightVec = tempVec;          
     float dist = length(tempVec);
@@ -15,7 +15,7 @@ void lightComputeDir(in vec3 worldPos, in float lightType, in vec4 position, out
     lightDir.w = (1.0 - position.w * dist) / (1.0 + position.w * dist * dist);
     lightDir.w = clamp(lightDir.w, 1.0 - posLight, 1.0);
 #else
-    lightDir.w = clamp(1.0 - position.w * dist * posLight, 0.0, 1.0);
+    lightDir.w = 1.0; // clamp(1.0 - position.w * dist * posLight, 0.0, 1.0);
 #endif
     lightDir.xyz = tempVec / vec3(dist);
 }