Add PreShadowArrayRenderer

in-pass-shadows
Kirill Vainer 7 years ago
parent d159e1746c
commit 9c4fcac876
  1. 191
      jme3-core/src/main/java/com/jme3/material/logic/ShadowStaticPassLightingLogic.java
  2. 248
      jme3-core/src/main/java/com/jme3/shadow/next/PreShadowArrayRenderer.java
  3. 38
      jme3-core/src/main/java/com/jme3/shadow/next/ShadowParameters.java
  4. 47
      jme3-core/src/main/java/com/jme3/shadow/next/array/ArrayShadowMap.java
  5. 41
      jme3-core/src/main/java/com/jme3/shadow/next/array/ArrayShadowMapSlice.java
  6. 75
      jme3-core/src/main/java/com/jme3/shadow/next/array/BaseArrayShadowMap.java
  7. 85
      jme3-core/src/main/java/com/jme3/shadow/next/array/BaseArrayShadowMapSlice.java
  8. 82
      jme3-core/src/main/java/com/jme3/shadow/next/array/DirectionalArrayShadowMap.java
  9. 66
      jme3-core/src/main/java/com/jme3/shadow/next/array/DirectionalArrayShadowMapSlice.java
  10. 68
      jme3-core/src/main/java/com/jme3/shadow/next/array/SpotArrayShadowMap.java
  11. 72
      jme3-core/src/main/java/com/jme3/shadow/next/array/SpotArrayShadowMapSlice.java
  12. 138
      jme3-core/src/main/java/com/jme3/shadow/next/pssm/DirectionalShadowParameters.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);
}
}
}

@ -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) {
}
}

@ -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 {
}

@ -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();
}

@ -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> {
}

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

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

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

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

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

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

@ -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;
}
}
}
Loading…
Cancel
Save