소스 검색

Add PreShadowArrayRenderer

Kirill Vainer 8 년 전
부모
커밋
9c4fcac876

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

@@ -0,0 +1,191 @@
+/*
+ * 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.material.logic;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.light.DirectionalLight;
+import com.jme3.light.Light;
+import com.jme3.light.LightList;
+import com.jme3.light.PointLight;
+import com.jme3.light.SpotLight;
+import com.jme3.material.TechniqueDef;
+import com.jme3.math.Matrix4f;
+import com.jme3.math.Vector4f;
+import com.jme3.renderer.Caps;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.Renderer;
+import com.jme3.shader.DefineList;
+import com.jme3.shader.Shader;
+import com.jme3.shader.Uniform;
+import com.jme3.shader.VarType;
+import com.jme3.shadow.next.array.ArrayShadowMap;
+import com.jme3.shadow.next.array.ArrayShadowMapSlice;
+import com.jme3.shadow.next.array.DirectionalArrayShadowMap;
+import com.jme3.shadow.next.array.SpotArrayShadowMap;
+import com.jme3.shadow.next.array.SpotArrayShadowMapSlice;
+import com.jme3.texture.TextureArray;
+import java.util.EnumSet;
+
+public class ShadowStaticPassLightingLogic extends StaticPassLightingLogic {
+
+    private static final String DEFINE_NUM_PSSM_SPLITS = "NUM_PSSM_SPLITS";
+    private static final String DEFINE_NUM_SHADOW_DIR_LIGHTS = "NUM_SHADOW_DIR_LIGHTS";
+    private static final String DEFINE_NUM_SHADOW_POINT_LIGHTS = "NUM_SHADOW_POINT_LIGHTS";
+    private static final String DEFINE_NUM_SHADOW_SPOT_LIGHTS = "NUM_SHADOW_SPOT_LIGHTS";
+
+    private final int numPssmSplitsDefineId;
+    private final int numShadowDirLightsDefineId;
+    private final int numShadowPointLightsDefineId;
+    private final int numShadowSpotLightsDefineId;
+    private int numShadowDirLights = 0;
+    private int numShadowPointLights = 0;
+    private int numShadowSpotLights = 0;
+    private final Matrix4f[] shadowMatrices = new Matrix4f[5];
+
+    public ShadowStaticPassLightingLogic(TechniqueDef techniqueDef) {
+        super(techniqueDef);
+        numPssmSplitsDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_NUM_PSSM_SPLITS, VarType.Int);
+        numShadowDirLightsDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_NUM_SHADOW_DIR_LIGHTS, VarType.Int);
+        numShadowPointLightsDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_NUM_SHADOW_POINT_LIGHTS, VarType.Int);
+        numShadowSpotLightsDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_NUM_SHADOW_SPOT_LIGHTS, VarType.Int);
+
+        for (int i = 0; i < shadowMatrices.length; i++) {
+            shadowMatrices[i] = new Matrix4f();
+        }
+    }
+
+    @Override
+    protected void makeCurrentBase(AssetManager assetManager, RenderManager renderManager,
+            EnumSet<Caps> rendererCaps, LightList lights, DefineList defines) {
+
+        tempDirLights.clear();
+        tempPointLights.clear();
+        tempSpotLights.clear();
+        ambientLightColor.set(0, 0, 0, 1);
+        numShadowDirLights = 0;
+        numShadowPointLights = 0;
+        numShadowSpotLights = 0;
+
+        int pssmSplits = 0;
+
+        for (Light light : lights) {
+            switch (light.getType()) {
+                case Directional:
+                    if (light.getShadowMap() != null) {
+                        pssmSplits = light.getShadowMap().getNumSlices();
+                        tempDirLights.add(numShadowDirLights, (DirectionalLight) light);
+                        numShadowDirLights++;
+                    } else {
+                        tempDirLights.add((DirectionalLight) light);
+                    }
+                    break;
+                case Point:
+                    if (light.getShadowMap() != null) {
+                        tempPointLights.add(numShadowPointLights, (PointLight) light);
+                        numShadowPointLights++;
+                    } else {
+                        tempPointLights.add((PointLight) light);
+                    }
+                    break;
+                case Spot:
+                    if (light.getShadowMap() != null) {
+                        tempSpotLights.add(numShadowSpotLights, (SpotLight) light);
+                        numShadowSpotLights++;
+                    } else {
+                        tempSpotLights.add((SpotLight) light);
+                    }
+                    break;
+                case Ambient:
+                    ambientLightColor.addLocal(light.getColor());
+                    break;
+            }
+        }
+        ambientLightColor.a = 1.0f;
+
+        defines.set(numDirLightsDefineId, tempDirLights.size());
+        defines.set(numPointLightsDefineId, tempPointLights.size());
+        defines.set(numSpotLightsDefineId, tempSpotLights.size());
+
+        defines.set(numShadowDirLightsDefineId, numShadowDirLights);
+        defines.set(numShadowPointLightsDefineId, numShadowPointLights);
+        defines.set(numShadowSpotLightsDefineId, numShadowSpotLights);
+
+        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;
+        Vector4f pssmSplits = null;
+
+        Uniform shadowMatricesUniform = shader.getUniform("g_ShadowMatrices");
+        int shadowMatrixIndex = 0;
+        for (int i = 0; i < numShadowDirLights; i++) {
+            DirectionalArrayShadowMap map = (DirectionalArrayShadowMap) tempDirLights.get(i).getShadowMap();
+            array = map.getArray();
+            pssmSplits = map.getProjectionSplitPositions();
+            for (int j = 0; j < map.getNumSlices(); j++) {
+                ArrayShadowMapSlice slice = (ArrayShadowMapSlice) map.getSlice(j);
+                BIAS_MATRIX.mult(slice.getViewProjectionMatrix(), shadowMatrices[shadowMatrixIndex]);
+                shadowMatrixIndex++;
+            }
+        }
+
+        for (int i = 0; i < numShadowSpotLights; i++) {
+            SpotArrayShadowMap map = (SpotArrayShadowMap) tempSpotLights.get(i).getShadowMap();
+            array = map.getArray();
+            SpotArrayShadowMapSlice slice = map.getSlice(0);
+            BIAS_MATRIX.mult(slice.getViewProjectionMatrix(), shadowMatrices[shadowMatrixIndex]);
+            shadowMatrixIndex++;
+        }
+
+        shadowMatricesUniform.setValue(VarType.Matrix4Array, shadowMatrices);
+        if (array != null) {
+            renderer.setTexture(nextTextureUnit, array);
+            Uniform shadowMapArrayUniform = shader.getUniform("g_ShadowMapArray");
+            shadowMapArrayUniform.setValue(VarType.Int, nextTextureUnit);
+        }
+        if (pssmSplits != null) {
+            Uniform pssmSplitsUniform = shader.getUniform("g_PssmSplits");
+            pssmSplitsUniform.setValue(VarType.Vector4, pssmSplits);
+        }
+    }
+}

+ 248 - 0
jme3-core/src/main/java/com/jme3/shadow/next/PreShadowArrayRenderer.java

@@ -0,0 +1,248 @@
+/*
+ * 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.light.SpotLight;
+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.array.DirectionalArrayShadowMap;
+import com.jme3.shadow.next.array.SpotArrayShadowMap;
+import com.jme3.texture.FrameBuffer;
+import com.jme3.texture.Image;
+import com.jme3.texture.Image.Format;
+import com.jme3.texture.Texture.MagFilter;
+import com.jme3.texture.Texture.MinFilter;
+import com.jme3.texture.Texture.ShadowCompareMode;
+import com.jme3.texture.TextureArray;
+import com.jme3.texture.image.ColorSpace;
+import com.jme3.util.ListMap;
+import com.jme3.util.TempVars;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+
+/**
+ * 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 PreShadowArrayRenderer 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 ListMap<Light, ShadowMap> shadowedLights = new ListMap<>();
+    private final RenderState prePassRenderState = RenderState.ADDITIONAL.clone();
+    private final TextureArray array = new TextureArray();
+    
+    private int textureSize = 1024;
+    private int nextArraySlice = 0;
+
+    // parameters for directional lights
+    private final DirectionalShadowParameters directionalParams = new DirectionalShadowParameters();
+
+    public PreShadowArrayRenderer() {
+        for (int i = 0; i < points.length; i++) {
+            points[i] = new Vector3f();
+        }
+
+        prePassRenderState.setFaceCullMode(RenderState.FaceCullMode.Front);
+        prePassRenderState.setColorWrite(false);
+        prePassRenderState.setDepthWrite(true);
+        prePassRenderState.setDepthTest(true);
+        prePassRenderState.setPolyOffset(0, 0);
+
+        array.setAnisotropicFilter(1);
+        array.setShadowCompareMode(ShadowCompareMode.LessOrEqual);
+        array.setMagFilter(MagFilter.Nearest);
+        array.setMinFilter(MinFilter.NearestNoMipMaps);
+        
+        array.setMagFilter(MagFilter.Bilinear);
+        array.setMinFilter(MinFilter.BilinearNoMipMaps);
+    }
+
+    @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) {
+        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) {
+        if (array.getImage() == null) {
+            array.setImage(new Image(
+                    Format.Depth32F,
+                    textureSize,
+                    textureSize,
+                    0,
+                    new ArrayList<ByteBuffer>(),
+                    ColorSpace.Linear));
+        }
+
+        ShadowMap shadowMap;
+        switch (light.getType()) {
+            case Directional:
+                shadowMap = new DirectionalArrayShadowMap(
+                        (DirectionalLight) light,
+                        array,
+                        nextArraySlice,
+                        textureSize,
+                        directionalParams.getNumSplits(),
+                        points);
+                break;
+            case Spot:
+                shadowMap = new SpotArrayShadowMap(
+                        (SpotLight) light,
+                        array,
+                        nextArraySlice,
+                        textureSize,
+                        points);
+                break;
+            default:
+                throw new UnsupportedOperationException();
+        }
+        
+        shadowedLights.put(light, shadowMap);
+        nextArraySlice += shadowMap.getNumSlices();
+    }
+
+    @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(ViewPort viewPort) {
+        renderManager.setForcedRenderState(prePassRenderState);
+        renderManager.setForcedTechnique(PRE_SHADOW_TECHNIQUE_NAME);
+
+        for (int i = 0; i < shadowedLights.size(); i++) {
+            Light light = shadowedLights.getKey(i);
+            ShadowMap shadowMap = shadowedLights.getValue(i);
+
+            TempVars vars = TempVars.get();
+            try {
+                light.setFrustumCheckNeeded(false);
+                light.setIntersectsFrustum(light.intersectsFrustum(viewPort.getCamera(), vars));
+                if (!light.isIntersectsFrustum()) {
+                    continue;
+                }
+            } finally {
+                vars.release();
+            }
+
+            switch (shadowMap.getLightType()) {
+                case Directional:
+                    DirectionalArrayShadowMap directionalShadow = (DirectionalArrayShadowMap) shadowMap;
+                    directionalShadow.renderShadowMap(renderManager, viewPort, directionalParams, shadowCasters);
+                    break;
+                case Spot:
+                    SpotArrayShadowMap spotShadow = (SpotArrayShadowMap) shadowMap;
+                    spotShadow.renderShadowMap(renderManager, viewPort, shadowCasters);
+                    break;
+                default:
+                    throw new UnsupportedOperationException();
+            }
+            
+            light.setShadowMap(shadowMap);
+        }
+
+        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(viewPort);
+    }
+
+    @Override
+    public void postFrame(FrameBuffer out) {
+        // TODO: call discard contents on all the framebuffers.
+        for (int i = 0; i < shadowedLights.size(); i++) {
+            Light light = shadowedLights.getKey(i);
+            light.setShadowMap(null);
+        }
+    }
+
+    @Override
+    public void cleanup() {
+    }
+
+    @Override
+    public void setProfiler(AppProfiler profiler) {
+    }
+
+}

+ 38 - 0
jme3-core/src/main/java/com/jme3/shadow/next/ShadowParameters.java

@@ -0,0 +1,38 @@
+/*
+ * 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;
+
+/**
+ * @author Kirill Vainer
+ */
+public interface ShadowParameters {
+}

+ 47 - 0
jme3-core/src/main/java/com/jme3/shadow/next/array/ArrayShadowMap.java

@@ -0,0 +1,47 @@
+/*
+ * 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.array;
+
+import com.jme3.shadow.next.ShadowMap;
+import com.jme3.texture.TextureArray;
+
+/**
+ * Represents shadow information for a light, uses texture arrays.
+ *
+ * @author Kirill Vainer
+ */
+public interface ArrayShadowMap extends ShadowMap {
+
+    public TextureArray getArray();
+
+    public int getFirstArraySlice();
+}

+ 41 - 0
jme3-core/src/main/java/com/jme3/shadow/next/array/ArrayShadowMapSlice.java

@@ -0,0 +1,41 @@
+/*
+ * 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.array;
+
+import com.jme3.light.Light;
+import com.jme3.shadow.next.ShadowMapSlice;
+
+/**
+ * @author Kirill Vainer
+ */
+public interface ArrayShadowMapSlice<T extends Light> extends ShadowMapSlice<T> {
+}

+ 75 - 0
jme3-core/src/main/java/com/jme3/shadow/next/array/BaseArrayShadowMap.java

@@ -0,0 +1,75 @@
+/*
+ * 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.array;
+
+import com.jme3.light.Light;
+import com.jme3.texture.TextureArray;
+
+/**
+ *
+ * @author Kirill Vainer
+ */
+public abstract class BaseArrayShadowMap<T extends ArrayShadowMapSlice> implements ArrayShadowMap {
+
+    protected final TextureArray array;
+    protected final int firstArraySlice;
+    protected T[] slices;
+
+    public BaseArrayShadowMap(TextureArray array, int firstArraySlice) {
+        this.array = array;
+        this.firstArraySlice = firstArraySlice;
+    }
+
+    @Override
+    public TextureArray getArray() {
+        return array;
+    }
+
+    @Override
+    public int getFirstArraySlice() {
+        return firstArraySlice;
+    }
+
+    @Override
+    public abstract Light.Type getLightType();
+
+    @Override
+    public int getNumSlices() {
+        return slices.length;
+    }
+
+    @Override
+    public T getSlice(int index) {
+        return slices[index];
+    }
+
+}

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

@@ -0,0 +1,85 @@
+/*
+ * 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.array;
+
+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.TextureArray;
+
+/**
+ * @param <T>
+ * @author Kirill Vainer
+ */
+public class BaseArrayShadowMapSlice<T extends Light> implements ArrayShadowMapSlice<T> {
+
+    protected final FrameBuffer frameBuffer;
+    protected final Camera shadowCamera;
+    protected final Vector3f[] points;
+
+    public BaseArrayShadowMapSlice(TextureArray array, int layer, int textureSize, Vector3f[] points) {
+        this.shadowCamera = new Camera(textureSize, textureSize);
+        this.shadowCamera.setParallelProjection(true);
+        this.frameBuffer = new FrameBuffer(textureSize, textureSize, 1);
+
+        Image image = array.getImage();
+        image.setDepth(image.getDepth() + 1);
+        image.addData(null);
+
+        this.frameBuffer.setDepthTexture(array, layer);
+        this.points = points;
+    }
+
+    @Override
+    public Matrix4f getViewProjectionMatrix() {
+        return shadowCamera.getViewProjectionMatrix();
+    }
+
+    @Override
+    public void renderShadowMap(RenderManager renderManager, Light light, ViewPort viewPort, GeometryList shadowCasters) {
+        Renderer renderer = renderManager.getRenderer();
+
+        renderer.setFrameBuffer(frameBuffer);
+        renderManager.setCamera(shadowCamera, false);
+        renderer.clearBuffers(false, true, false);
+
+        viewPort.getQueue().renderShadowQueue(shadowCasters, renderManager, shadowCamera, true);
+    }
+
+}

+ 82 - 0
jme3-core/src/main/java/com/jme3/shadow/next/array/DirectionalArrayShadowMap.java

@@ -0,0 +1,82 @@
+/*
+ * 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.array;
+
+import com.jme3.light.DirectionalLight;
+import com.jme3.light.Light;
+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.pssm.DirectionalShadowParameters;
+import com.jme3.texture.TextureArray;
+
+/**
+ * @author Kirill Vainer
+ */
+public class DirectionalArrayShadowMap extends BaseArrayShadowMap<DirectionalArrayShadowMapSlice> {
+
+    private final DirectionalLight light;
+    private final Vector4f projectionSplitPositions = new Vector4f();
+
+    public DirectionalArrayShadowMap(DirectionalLight light, TextureArray array, int firstArraySlice, int textureSize, int numSplits, Vector3f[] points) {
+        super(array, firstArraySlice);
+        this.light = light;
+        this.slices = new DirectionalArrayShadowMapSlice[numSplits];
+        for (int i = 0; i < numSplits; i++) {
+            this.slices[i] = new DirectionalArrayShadowMapSlice(array, firstArraySlice + i, 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 < slices.length; i++) {
+            float near = splitPositionsViewSpace[i];
+            float far = splitPositionsViewSpace[i + 1];
+            shadowCasters.clear();
+            slices[i].updateShadowCamera(viewPort, light, shadowCasters, near, far);
+            slices[i].renderShadowMap(renderManager, light, viewPort, shadowCasters);
+        }
+    }
+
+    public Vector4f getProjectionSplitPositions() {
+        return projectionSplitPositions;
+    }
+
+    @Override
+    public Light.Type getLightType() {
+        return Light.Type.Directional;
+    }
+
+}

+ 66 - 0
jme3-core/src/main/java/com/jme3/shadow/next/array/DirectionalArrayShadowMapSlice.java

@@ -0,0 +1,66 @@
+/*
+ * 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.array;
+
+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.TextureArray;
+
+/**
+ *
+ * @author Kirill Vainer
+ */
+public class DirectionalArrayShadowMapSlice extends BaseArrayShadowMapSlice<DirectionalLight> {
+
+    public DirectionalArrayShadowMapSlice(TextureArray array, int layer, int textureSize, Vector3f[] points) {
+        super(array, layer, textureSize, 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);
+    }
+
+}

+ 68 - 0
jme3-core/src/main/java/com/jme3/shadow/next/array/SpotArrayShadowMap.java

@@ -0,0 +1,68 @@
+/*
+ * 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.array;
+
+import com.jme3.light.Light;
+import com.jme3.light.SpotLight;
+import com.jme3.math.Vector3f;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.ViewPort;
+import com.jme3.renderer.queue.GeometryList;
+import com.jme3.texture.TextureArray;
+
+/**
+ * @author Kirill Vainer
+ */
+public class SpotArrayShadowMap extends BaseArrayShadowMap<SpotArrayShadowMapSlice> {
+
+    private final SpotLight light;
+
+    public SpotArrayShadowMap(SpotLight light, TextureArray array, int firstArraySlice, int textureSize, Vector3f[] points) {
+        super(array, firstArraySlice);
+        this.light = light;
+        slices = new SpotArrayShadowMapSlice[]{
+            new SpotArrayShadowMapSlice(array, firstArraySlice, textureSize, points)
+        };
+    }
+
+    public void renderShadowMap(RenderManager renderManager, ViewPort viewPort, GeometryList shadowCasters) {
+        shadowCasters.clear();
+        slices[0].updateShadowCamera(viewPort, light, shadowCasters);
+        slices[0].renderShadowMap(renderManager, light, viewPort, shadowCasters);
+    }
+
+    @Override
+    public Light.Type getLightType() {
+        return Light.Type.Spot;
+    }
+
+}

+ 72 - 0
jme3-core/src/main/java/com/jme3/shadow/next/array/SpotArrayShadowMapSlice.java

@@ -0,0 +1,72 @@
+/*
+ * 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.array;
+
+import com.jme3.light.SpotLight;
+import com.jme3.math.FastMath;
+import com.jme3.math.Matrix4f;
+import com.jme3.math.Vector3f;
+import com.jme3.renderer.Camera;
+import com.jme3.renderer.ViewPort;
+import com.jme3.renderer.queue.GeometryList;
+import com.jme3.shadow.ShadowUtil;
+import com.jme3.texture.TextureArray;
+
+/**
+ *
+ * @author Kirill Vainer
+ */
+public class SpotArrayShadowMapSlice extends BaseArrayShadowMapSlice<SpotLight> {
+
+    public SpotArrayShadowMapSlice(TextureArray array, int layer, int textureSize, Vector3f[] points) {
+        super(array, layer, textureSize, points);
+    }
+
+    public void updateShadowCamera(
+            ViewPort viewPort,
+            SpotLight light,
+            GeometryList shadowCasters) {
+
+        Camera viewCamera = viewPort.getCamera();
+        float near = viewCamera.getFrustumNear();
+        float far = viewCamera.getFrustumFar();
+
+        ShadowUtil.updateFrustumPoints(viewCamera, near, far, points);
+
+        shadowCamera.setFrustumPerspective(light.getSpotOuterAngle() * FastMath.RAD_TO_DEG * 2.0f, 1, 1, light.getSpotRange());
+        shadowCamera.lookAtDirection(light.getDirection(), shadowCamera.getUp());
+        shadowCamera.setLocation(light.getPosition());
+
+        int textureSize = frameBuffer.getWidth();
+        ShadowUtil.updateShadowCamera(viewPort, null, shadowCamera, points, shadowCasters, textureSize);
+    }
+}

+ 138 - 0
jme3-core/src/main/java/com/jme3/shadow/next/pssm/DirectionalShadowParameters.java

@@ -0,0 +1,138 @@
+/*
+ * 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.math.Vector4f;
+import com.jme3.renderer.Camera;
+import com.jme3.shadow.PssmShadowUtil;
+import com.jme3.shadow.next.ShadowParameters;
+
+/**
+ * @author Kirill Vainer
+ */
+public final class DirectionalShadowParameters implements ShadowParameters {
+
+    private float lambda = 0.65f;
+    private int numSplits = 4;
+    protected float zFarOverride = 0;
+    private float[] splitPositions = new float[numSplits + 1];
+    private final Vector4f projectionSplitPositions = new Vector4f();
+
+    public float getLambda() {
+        return lambda;
+    }
+
+    public void setLambda(float lambda) {
+        this.lambda = lambda;
+    }
+
+    public int getNumSplits() {
+        return numSplits;
+    }
+
+    public void setNumSplits(int numSplits) {
+        // TODO: ensure it is 1 to 4
+        this.numSplits = numSplits;
+        this.splitPositions = new float[numSplits + 1];
+    }
+
+    public float[] getSplitPositions() {
+        return splitPositions;
+    }
+
+    public Vector4f getProjectionSplitPositions() {
+        return projectionSplitPositions;
+    }
+
+    /**
+     * How far the shadows are rendered in the view
+     *
+     * @see #setShadowZExtend(float zFar)
+     * @return shadowZExtend
+     */
+    public float getShadowZExtend() {
+        return zFarOverride;
+    }
+    
+    /**
+     * Set the distance from the eye where the shadows will be rendered.
+     * 
+     * The default value is dynamically computed based on the shadow
+     * casters/receivers union bound zFar, capped to view frustum far value.
+     *
+     * @param zFar the zFar values that override the computed one
+     */
+    public void setShadowZExtend(float zFar) {
+        this.zFarOverride = zFar;
+        
+        // TODO: Fade length not supported yet
+//        if (zFarOverride == 0) {
+//            fadeInfo = null;
+//            frustumCam = null;
+//        } else {
+//            if (fadeInfo != null) {
+//                fadeInfo.set(zFarOverride - fadeLength, 1f / fadeLength);
+//            }
+//            if (frustumCam == null && viewPort != null) {
+//                initFrustumCam();
+//            }
+//        }
+    }
+    
+    public void updateSplitPositions(Camera viewCamera) {
+        float near = viewCamera.getFrustumNear();
+        float far = zFarOverride == 0f ? viewCamera.getFrustumFar() : zFarOverride;
+
+        PssmShadowUtil.updateFrustumSplits(splitPositions, near, far, lambda);
+
+        // TODO: Parallel projection can have negative near value, so split
+        //       positions must be adjusted.
+//        if (viewCamera.isParallelProjection()) {
+//            for (int i = 0; i < splitPositions.length; i++) {
+//                splitPositions[i] = splitPositions[i] / (far - near);
+//            }
+//        }
+
+        switch (splitPositions.length) {
+            case 5:
+                projectionSplitPositions.w = 1.0f; // = viewCamera.getViewToProjectionZ(splitPositions[4]);
+            case 4:
+                projectionSplitPositions.z = viewCamera.getViewToProjectionZ(splitPositions[3]);
+            case 3:
+                projectionSplitPositions.y = viewCamera.getViewToProjectionZ(splitPositions[2]);
+            case 2:
+            case 1:
+                projectionSplitPositions.x = viewCamera.getViewToProjectionZ(splitPositions[1]);
+                break;
+        }
+    }
+}