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);
+ }
+ }
+}
diff --git a/jme3-core/src/main/java/com/jme3/shadow/next/PreShadowArrayRenderer.java b/jme3-core/src/main/java/com/jme3/shadow/next/PreShadowArrayRenderer.java
new file mode 100755
index 0000000000..fd9bd6e585
--- /dev/null
+++ b/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.
+ *
+ * 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 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(),
+ 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) {
+ }
+
+}
diff --git a/jme3-core/src/main/java/com/jme3/shadow/next/ShadowParameters.java b/jme3-core/src/main/java/com/jme3/shadow/next/ShadowParameters.java
new file mode 100755
index 0000000000..37df980ab3
--- /dev/null
+++ b/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 {
+}
diff --git a/jme3-core/src/main/java/com/jme3/shadow/next/array/ArrayShadowMap.java b/jme3-core/src/main/java/com/jme3/shadow/next/array/ArrayShadowMap.java
new file mode 100755
index 0000000000..fe5fdcc834
--- /dev/null
+++ b/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();
+}
diff --git a/jme3-core/src/main/java/com/jme3/shadow/next/array/ArrayShadowMapSlice.java b/jme3-core/src/main/java/com/jme3/shadow/next/array/ArrayShadowMapSlice.java
new file mode 100755
index 0000000000..6d3897db28
--- /dev/null
+++ b/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 extends ShadowMapSlice {
+}
diff --git a/jme3-core/src/main/java/com/jme3/shadow/next/array/BaseArrayShadowMap.java b/jme3-core/src/main/java/com/jme3/shadow/next/array/BaseArrayShadowMap.java
new file mode 100755
index 0000000000..bb7e8024c5
--- /dev/null
+++ b/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 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];
+ }
+
+}
diff --git a/jme3-core/src/main/java/com/jme3/shadow/next/array/BaseArrayShadowMapSlice.java b/jme3-core/src/main/java/com/jme3/shadow/next/array/BaseArrayShadowMapSlice.java
new file mode 100755
index 0000000000..b554fb92f9
--- /dev/null
+++ b/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
+ * @author Kirill Vainer
+ */
+public class BaseArrayShadowMapSlice implements ArrayShadowMapSlice {
+
+ 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);
+ }
+
+}
diff --git a/jme3-core/src/main/java/com/jme3/shadow/next/array/DirectionalArrayShadowMap.java b/jme3-core/src/main/java/com/jme3/shadow/next/array/DirectionalArrayShadowMap.java
new file mode 100755
index 0000000000..32151e42ad
--- /dev/null
+++ b/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 {
+
+ 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;
+ }
+
+}
diff --git a/jme3-core/src/main/java/com/jme3/shadow/next/array/DirectionalArrayShadowMapSlice.java b/jme3-core/src/main/java/com/jme3/shadow/next/array/DirectionalArrayShadowMapSlice.java
new file mode 100755
index 0000000000..580023005c
--- /dev/null
+++ b/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 {
+
+ 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);
+ }
+
+}
diff --git a/jme3-core/src/main/java/com/jme3/shadow/next/array/SpotArrayShadowMap.java b/jme3-core/src/main/java/com/jme3/shadow/next/array/SpotArrayShadowMap.java
new file mode 100755
index 0000000000..5046bc976a
--- /dev/null
+++ b/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 {
+
+ 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;
+ }
+
+}
diff --git a/jme3-core/src/main/java/com/jme3/shadow/next/array/SpotArrayShadowMapSlice.java b/jme3-core/src/main/java/com/jme3/shadow/next/array/SpotArrayShadowMapSlice.java
new file mode 100755
index 0000000000..874da428bc
--- /dev/null
+++ b/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 {
+
+ 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);
+ }
+}
diff --git a/jme3-core/src/main/java/com/jme3/shadow/next/pssm/DirectionalShadowParameters.java b/jme3-core/src/main/java/com/jme3/shadow/next/pssm/DirectionalShadowParameters.java
new file mode 100755
index 0000000000..57f5646beb
--- /dev/null
+++ b/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;
+ }
+ }
+}
From 77e552f551c06c7d70adef572c061f3c23d712cc Mon Sep 17 00:00:00 2001
From: Kirill Vainer
Date: Sat, 9 Sep 2017 16:33:49 -0400
Subject: [PATCH 21/46] Implement static pass in the lighting material
---
.../Common/MatDefs/Light/Lighting.j3md | 26 ++-
.../Common/MatDefs/Light/StaticLighting.frag | 203 ++++++++++++++++++
.../Common/MatDefs/Light/StaticLighting.vert | 32 +++
.../Common/ShaderLib/InPassShadows.glsl | 133 ++++++++++++
.../com/jme3/material/plugins/J3MLoader.java | 2 +-
.../com/jme3/shader/plugins/GLSLLoader.java | 7 +-
6 files changed, 398 insertions(+), 5 deletions(-)
create mode 100755 jme3-core/src/main/resources/Common/MatDefs/Light/StaticLighting.frag
create mode 100755 jme3-core/src/main/resources/Common/MatDefs/Light/StaticLighting.vert
create mode 100755 jme3-core/src/main/resources/Common/ShaderLib/InPassShadows.glsl
diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.j3md b/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.j3md
index bc699e6b12..cdd1bdcff4 100644
--- a/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.j3md
+++ b/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.j3md
@@ -27,6 +27,9 @@ MaterialDef Phong Lighting {
// Specular power/shininess
Float Shininess : 1
+ // Ambient map
+ Texture2D AmbientMap
+
// Diffuse map
Texture2D DiffuseMap
@@ -79,7 +82,7 @@ MaterialDef Phong Lighting {
Boolean EnvMapAsSphereMap
//shadows
- Int FilterMode
+ Int FilterMode
Boolean HardwareShadows
Texture2D ShadowMap0
@@ -117,6 +120,27 @@ MaterialDef Phong Lighting {
Boolean BackfaceShadows : false
}
+ Technique {
+ LightMode StaticPass
+
+ VertexShader GLSL100 GLSL150 : Common/MatDefs/Light/StaticLighting.vert
+ FragmentShader GLSL100 GLSL150 : Common/MatDefs/Light/StaticLighting.frag
+
+ WorldParameters {
+ WorldViewProjectionMatrix
+ NormalMatrix
+ WorldViewMatrix
+ ViewMatrix
+ CameraPosition
+ WorldMatrix
+ ViewProjectionMatrix
+ }
+
+ Defines {
+ AMBIENTMAP : AmbientMap
+ }
+ }
+
Technique {
LightMode SinglePass
diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/StaticLighting.frag b/jme3-core/src/main/resources/Common/MatDefs/Light/StaticLighting.frag
new file mode 100755
index 0000000000..962e2c1221
--- /dev/null
+++ b/jme3-core/src/main/resources/Common/MatDefs/Light/StaticLighting.frag
@@ -0,0 +1,203 @@
+#import "Common/ShaderLib/GLSLCompat.glsllib"
+#import "Common/ShaderLib/BlinnPhongLighting.glsllib"
+#import "Common/ShaderLib/Lighting.glsllib"
+#import "Common/ShaderLib/InPassShadows.glsl"
+
+#ifndef NUM_DIR_LIGHTS
+#define NUM_DIR_LIGHTS 0
+#endif
+
+#ifndef NUM_POINT_LIGHTS
+#define NUM_POINT_LIGHTS 0
+#endif
+
+#ifndef NUM_SPOT_LIGHTS
+#define NUM_SPOT_LIGHTS 0
+#endif
+
+#define DIR_SHADOW_LIGHT_START (0)
+#define DIR_SHADOW_LIGHT_END (NUM_SHADOW_DIR_LIGHTS * 2)
+
+#define DIR_LIGHT_START (DIR_SHADOW_LIGHT_END)
+#define DIR_LIGHT_END (NUM_DIR_LIGHTS * 2)
+
+#define POINT_LIGHT_START (DIR_LIGHT_END)
+#define POINT_LIGHT_END (POINT_LIGHT_START + NUM_POINT_LIGHTS * 2)
+
+#define SPOT_SHADOW_LIGHT_START (POINT_LIGHT_END)
+#define SPOT_SHADOW_LIGHT_END (SPOT_SHADOW_LIGHT_START + NUM_SHADOW_SPOT_LIGHTS * 3)
+
+#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)
+
+uniform sampler2D m_AmbientMap;
+uniform float m_AlphaDiscardThreshold;
+uniform float m_Shininess;
+uniform vec4 g_AmbientLightColor;
+
+#if LIGHT_DATA_SIZE > 0
+uniform vec4 g_LightData[LIGHT_DATA_SIZE];
+#else
+const vec4 g_LightData[1] = vec4[]( vec4(1.0) );
+#endif
+
+varying vec3 vPos;
+varying vec3 vNormal;
+varying vec2 vTexCoord;
+
+struct surface_t {
+ vec3 position;
+ vec3 normal;
+ vec3 viewDir;
+ vec3 ambient;
+ vec4 diffuse;
+ vec4 specular;
+ float shininess;
+};
+
+vec2 Lighting_ProcessLighting(vec3 norm, vec3 viewDir, vec3 lightDir, float attenuation, float shininess) {
+ float diffuseFactor = max(0.0, dot(norm, lightDir));
+ vec3 H = normalize(viewDir + lightDir);
+ float HdotN = max(0.0, dot(H, norm));
+ float specularFactor = pow(HdotN, shininess);
+ return vec2(diffuseFactor, diffuseFactor * specularFactor) * vec2(attenuation);
+}
+
+vec2 Lighting_ProcessDirectional(int lightIndex, surface_t surface) {
+ vec3 lightDirection = g_LightData[lightIndex + 1].xyz;
+ vec2 light = Lighting_ProcessLighting(surface.normal, surface.viewDir, -lightDirection, 1.0, surface.shininess);
+ return light;
+}
+
+float Lighting_ProcessAttenuation(float invRadius, float dist) {
+ #ifdef SRGB
+ float atten = (1.0 - invRadius * dist) / (1.0 + invRadius * dist * dist);
+ return clamp(atten, 0.0, 1.0);
+ #else
+ return max(0.0, 1.0 - invRadius * dist);
+ #endif
+}
+
+vec2 Lighting_ProcessPoint(int lightIndex, surface_t surface) {
+ 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);
+ return Lighting_ProcessLighting(surface.normal, surface.viewDir, lightDirection, atten, surface.shininess);
+}
+
+vec2 Lighting_ProcessSpot(int lightIndex, surface_t surface) {
+ 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 = Lighting_ProcessAttenuation(lightPosition.w, dist);
+ atten *= computeSpotFalloff(lightDirection, lightVector);
+ return Lighting_ProcessLighting(surface.normal, surface.viewDir, lightVector, atten, surface.shininess);
+}
+
+void Lighting_ProcessAll(surface_t surface, out vec3 ambient, out vec3 diffuse, out vec3 specular) {
+
+ ambient = g_AmbientLightColor.rgb;
+ diffuse = vec3(0.0);
+ specular = vec3(0.0);
+
+ Shadow_ProcessPssmSlice();
+
+#if LIGHT_DATA_SIZE > 0
+ int projIndex = 0;
+
+ for (int i = DIR_SHADOW_LIGHT_START; i < DIR_SHADOW_LIGHT_END; i += 2) {
+ vec4 lightColor = g_LightData[i];
+ vec2 lightDiffSpec = Lighting_ProcessDirectional(i, surface);
+ float shadow = Shadow_ProcessDirectional(projIndex, lightColor.w);
+ lightDiffSpec *= vec2(shadow);
+ diffuse += lightColor.rgb * lightDiffSpec.x;
+ specular += lightColor.rgb * lightDiffSpec.y;
+ projIndex += NUM_PSSM_SPLITS;
+ }
+
+ for (int i = DIR_LIGHT_START; i < DIR_LIGHT_END; i += 2) {
+ vec3 lightColor = g_LightData[i].rgb;
+ vec2 lightDiffSpec = Lighting_ProcessDirectional(i, surface);
+ diffuse += lightColor.rgb * lightDiffSpec.x;
+ specular += lightColor.rgb * lightDiffSpec.y;
+ }
+
+ for (int i = POINT_LIGHT_START; i < POINT_LIGHT_END; i += 2) {
+ vec3 lightColor = g_LightData[i].rgb;
+ vec2 lightDiffSpec = Lighting_ProcessPoint(i, surface);
+ diffuse += lightColor.rgb * lightDiffSpec.x;
+ specular += lightColor.rgb * lightDiffSpec.y;
+ }
+
+ for (int i = SPOT_SHADOW_LIGHT_START; i < SPOT_SHADOW_LIGHT_END; i += 3) {
+ vec4 lightColor = g_LightData[i];
+ vec2 lightDiffSpec = Lighting_ProcessSpot(i, surface);
+ float shadow = Shadow_ProcessSpot(projIndex, lightColor.w);
+ lightDiffSpec *= vec2(shadow);
+ diffuse += lightColor.rgb * lightDiffSpec.x;
+ specular += lightColor.rgb * lightDiffSpec.y;
+ projIndex++;
+ }
+
+ for (int i = SPOT_LIGHT_START; i < SPOT_LIGHT_END; i += 3) {
+ vec3 lightColor = g_LightData[i].rgb;
+ vec2 lightDiffSpec = Lighting_ProcessSpot(i, surface);
+ diffuse += lightColor * lightDiffSpec.x;
+ specular += lightColor * lightDiffSpec.y;
+ }
+
+#endif
+}
+
+surface_t getSurface() {
+ surface_t s;
+ s.position = vPos;
+ s.normal = normalize(vNormal);
+ if (!gl_FrontFacing) {
+ s.normal = -s.normal;
+ }
+ s.viewDir = normalize(-vPos);
+#ifdef AMBIENTMAP
+ s.ambient = texture2D(m_AmbientMap, vTexCoord).rgb;
+#else
+ s.ambient = vec3(1.0);
+#endif
+ s.diffuse = vec4(1.0);
+ s.specular = vec4(1.0);
+ s.shininess = m_Shininess;
+ return s;
+}
+
+void main() {
+ vec3 ambient, diffuse, specular;
+
+ surface_t surface = getSurface();
+ Lighting_ProcessAll(surface, ambient, diffuse, specular);
+
+ vec4 color = vec4(1.0);
+ color.rgb = surface.ambient.rgb * ambient +
+ surface.diffuse.rgb * diffuse +
+ surface.specular.rgb * specular;
+
+ #ifdef DISCARD_ALPHA
+ if (color.a < m_AlphaDiscardThreshold) {
+ discard;
+ }
+ #endif
+
+ gl_FragColor = color;
+
+/*
+ vec4 projCoord = vProjCoord[0];
+ projCoord.xyz /= projCoord.w;
+ float shad = shadow2D(g_ShadowMapArray, vec4(projCoord.xy, 0.0, projCoord.z)).r;
+ vec3 amb = texture2D(m_AmbientMap, vTexCoord).rgb;
+ gl_FragColor = vec4(amb * vec3(shad), 1.0);
+*/
+}
\ No newline at end of file
diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/StaticLighting.vert b/jme3-core/src/main/resources/Common/MatDefs/Light/StaticLighting.vert
new file mode 100755
index 0000000000..354afec0ca
--- /dev/null
+++ b/jme3-core/src/main/resources/Common/MatDefs/Light/StaticLighting.vert
@@ -0,0 +1,32 @@
+#import "Common/ShaderLib/GLSLCompat.glsllib"
+#import "Common/ShaderLib/Skinning.glsllib"
+#import "Common/ShaderLib/Instancing.glsllib"
+#import "Common/ShaderLib/InPassShadows.glsl"
+
+attribute vec3 inPosition;
+attribute vec3 inNormal;
+attribute vec2 inTexCoord;
+attribute vec4 inColor;
+
+varying vec3 vPos;
+varying vec3 vNormal;
+varying vec2 vTexCoord;
+
+void main() {
+ vTexCoord = inTexCoord;
+
+ vec4 modelSpacePos = vec4(inPosition, 1.0);
+ vec3 modelSpaceNorm = inNormal;
+
+ #ifdef NUM_BONES
+ Skinning_Compute(modelSpacePos, modelSpaceNorm);
+ #endif
+
+ vPos = TransformWorldView(modelSpacePos).xyz;
+ vNormal = TransformNormal(modelSpaceNorm);
+
+ vec3 shadowPos = TransformWorld(modelSpacePos).xyz;
+ Shadow_ProcessProjCoord(shadowPos);
+
+ gl_Position = TransformWorldViewProjection(modelSpacePos);
+}
\ No newline at end of file
diff --git a/jme3-core/src/main/resources/Common/ShaderLib/InPassShadows.glsl b/jme3-core/src/main/resources/Common/ShaderLib/InPassShadows.glsl
new file mode 100755
index 0000000000..7fec2be831
--- /dev/null
+++ b/jme3-core/src/main/resources/Common/ShaderLib/InPassShadows.glsl
@@ -0,0 +1,133 @@
+#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
+#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)
+
+#if SHADOW_DATA_SIZE > 0
+
+ varying vec4 vProjCoord[SHADOW_DATA_SIZE];
+
+ #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);
+ }
+ }
+ #else
+ uniform sampler2DArrayShadow g_ShadowMapArray;
+ uniform vec4 g_PssmSplits;
+
+ int pssmSliceOffset;
+
+ void Shadow_ProcessPssmSlice() {
+ #ifdef NUM_PSSM_SPLITS
+ float z = gl_FragCoord.z;
+ if (z < g_PssmSplits[0]) {
+ pssmSliceOffset = 0;
+ } else if (z < g_PssmSplits[1]) {
+ pssmSliceOffset = 1;
+ } else if (z < g_PssmSplits[2]) {
+ pssmSliceOffset = 2;
+ } else {
+ pssmSliceOffset = 3;
+ }
+ #else
+ pssmSliceOffset = 0;
+ #endif
+ }
+
+ float Shadow_ProcessDirectional(int startProjIndex, float startArrayLayer) {
+ float arraySlice = startArrayLayer + float(pssmSliceOffset);
+ vec3 projCoord = vProjCoord[startProjIndex + pssmSliceOffset].xyz;
+ return texture(g_ShadowMapArray, vec4(projCoord.xy, arraySlice, projCoord.z));
+ }
+
+ float Shadow_ProcessSpot(int startProjIndex, float startArrayLayer) {
+ vec4 projCoord = vProjCoord[startProjIndex];
+ projCoord.xyz /= projCoord.w;
+ return texture(g_ShadowMapArray, vec4(projCoord.xy, startArrayLayer, projCoord.z));
+ }
+ #endif
+
+#elif NUM_PSSM_SPLITS > 0
+
+ // A lightweight version of in-pass lighting that only handles directional lights
+ // Control flow and loop iteration count are static
+
+ varying vec4 vProjCoord[NUM_PSSM_SPLITS];
+
+ #ifdef VERTEX_SHADER
+ uniform mat4 g_DirectionalShadowMatrix[NUM_PSSM_SPLITS];
+ void Shadow_ProcessProjCoord(vec3 worldPos) {
+ for (int i = 0; i < NUM_PSSM_SPLITS; i++) {
+ vProjCoord[i] = g_DirectionalShadowMatrix[i] * vec4(worldPos, 1.0);
+ }
+ }
+ #else
+ uniform sampler2DShadow g_DirectionalShadowMap[NUM_PSSM_SPLITS];
+ uniform vec4 g_PssmSplits;
+
+ const vec2 invTexSize = vec2(1.0 / 1024.0);
+
+ float Shadow_SampleOffset(sampler2DShadow shadowMap, vec4 projCoord, vec2 offset) {
+ return shadow2D(shadowMap, vec3(projCoord.xy + offset * invTexSize, projCoord.z)).r;
+ }
+
+ float Shadow_Sample(sampler2DShadow shadowMap, vec4 projCoord) {
+ return shadow2D(shadowMap, projCoord.xyz).r;
+ }
+
+ #define GET_SHADOW(i) if (z < g_PssmSplits[i]) return Shadow_Sample(g_DirectionalShadowMap[i], vProjCoord[i]);
+
+ void Shadow_ProcessPssmSlice() {
+ }
+
+ float Shadow_ProcessDirectional() {
+ float z = gl_FragCoord.z;
+
+ GET_SHADOW(0);
+ #if NUM_PSSM_SPLITS > 1
+ GET_SHADOW(1)
+ #if NUM_PSSM_SPLITS > 2
+ GET_SHADOW(2)
+ #if NUM_PSSM_SPLITS > 3
+ GET_SHADOW(3)
+ #endif
+ #endif
+ #endif
+
+ return 1.0;
+ }
+ #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
+
+ void Shadow_ProcessProjCoord(vec3 worldPos) {
+ }
+
+ void Shadow_ProcessPssmSlice() {
+ }
+
+ float Shadow_ProcessDirectional(int startLightIndex, float startArrayLayer) {
+ return 1.0;
+ }
+
+ float Shadow_ProcessSpot(int startLightIndex, float startArrayLayer) {
+ return 1.0;
+ }
+#endif
diff --git a/jme3-core/src/plugins/java/com/jme3/material/plugins/J3MLoader.java b/jme3-core/src/plugins/java/com/jme3/material/plugins/J3MLoader.java
index d0c36afc6d..7d6184b3f6 100644
--- a/jme3-core/src/plugins/java/com/jme3/material/plugins/J3MLoader.java
+++ b/jme3-core/src/plugins/java/com/jme3/material/plugins/J3MLoader.java
@@ -646,7 +646,7 @@ private void readTechnique(Statement techStat) throws IOException{
technique.setLogic(new SinglePassLightingLogic(technique));
break;
case StaticPass:
- technique.setLogic(new StaticPassLightingLogic(technique));
+ technique.setLogic(new ShadowStaticPassLightingLogic(technique));
break;
case SinglePassAndImageBased:
technique.setLogic(new SinglePassAndImageBasedLightingLogic(technique));
diff --git a/jme3-core/src/plugins/java/com/jme3/shader/plugins/GLSLLoader.java b/jme3-core/src/plugins/java/com/jme3/shader/plugins/GLSLLoader.java
index f1ef392626..1dc25da8e0 100644
--- a/jme3-core/src/plugins/java/com/jme3/shader/plugins/GLSLLoader.java
+++ b/jme3-core/src/plugins/java/com/jme3/shader/plugins/GLSLLoader.java
@@ -49,7 +49,7 @@
public class GLSLLoader implements AssetLoader {
private AssetManager assetManager;
- private Map dependCache = new HashMap();
+ private final Map dependCache = new HashMap<>();
/**
* Used to load {@link ShaderDependencyNode}s.
@@ -168,7 +168,7 @@ private String resolveDependencies(ShaderDependencyNode node, Set resolvedShaderNodes = new ArrayList();
+ List resolvedShaderNodes = new ArrayList<>();
for (ShaderDependencyNode dependencyNode : node.getDependencies()) {
resolvedShaderNodes.add(resolveDependencies(dependencyNode, alreadyInjectedSet, extensions));
@@ -187,7 +187,8 @@ public Object load(AssetInfo info) throws IOException {
// to retrieve the fragment shader, use the content manager
this.assetManager = info.getManager();
Reader reader = new InputStreamReader(info.openStream());
- if (info.getKey().getExtension().equals("glsllib")) {
+ String extension = info.getKey().getExtension();
+ if (extension.equals("glsllib") || extension.equals("glsl")) {
// NOTE: Loopback, GLSLLIB is loaded by this loader
// and needs data as InputStream
return reader;
From 5aa2c722fe020009ba79c2dc7f24e11a09cec2c5 Mon Sep 17 00:00:00 2001
From: Kirill Vainer
Date: Sun, 10 Sep 2017 18:34:47 -0400
Subject: [PATCH 22/46] Fix syntax error
---
.../com/jme3/shadow/DirectionalLightShadowRendererVR.java | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/jme3-vr/src/main/java/com/jme3/shadow/DirectionalLightShadowRendererVR.java b/jme3-vr/src/main/java/com/jme3/shadow/DirectionalLightShadowRendererVR.java
index f9bdd1f595..e82fcc8bef 100644
--- a/jme3-vr/src/main/java/com/jme3/shadow/DirectionalLightShadowRendererVR.java
+++ b/jme3-vr/src/main/java/com/jme3/shadow/DirectionalLightShadowRendererVR.java
@@ -145,7 +145,7 @@ protected void updateShadowCams(Camera viewCam) {
//We prevent computing the frustum points and splits with zeroed or negative near clip value
float frustumNear = Math.max(viewCam.getFrustumNear(), 0.001f);
- ShadowUtil.updateFrustumPoints(viewCam, frustumNear, zFar, 1.0f, points);
+ ShadowUtil.updateFrustumPoints(viewCam, frustumNear, zFar, points);
//shadowCam.setDirection(direction);
shadowCam.getRotation().lookAt(light.getDirection(), shadowCam.getUp());
@@ -180,7 +180,7 @@ protected void updateShadowCams(Camera viewCam) {
protected GeometryList getOccludersToRender(int shadowMapIndex, GeometryList shadowMapOccluders) {
// update frustum points based on current camera and split
- ShadowUtil.updateFrustumPoints(viewPort.getCamera(), splitsArray[shadowMapIndex], splitsArray[shadowMapIndex + 1], 1.0f, points);
+ ShadowUtil.updateFrustumPoints(viewPort.getCamera(), splitsArray[shadowMapIndex], splitsArray[shadowMapIndex + 1], points);
//Updating shadow cam with curent split frustra
if (lightReceivers.size()==0) {
From a3145885d9265d667acedf7c032004132239767a Mon Sep 17 00:00:00 2001
From: Kirill Vainer
Date: Sun, 10 Sep 2017 18:36:16 -0400
Subject: [PATCH 23/46] Support dynamic number of shadow maps
---
.../logic/ShadowStaticPassLightingLogic.java | 18 ++++----
.../logic/StaticPassLightingLogic.java | 6 ---
.../src/main/java/com/jme3/math/Matrix4f.java | 1 -
.../main/java/com/jme3/shader/Uniform.java | 42 +++++++++++++++----
.../com/jme3/shadow/next/ShadowMapSlice.java | 12 +++++-
.../next/array/BaseArrayShadowMapSlice.java | 8 ++--
.../shadow/next/array/SpotArrayShadowMap.java | 1 -
.../next/array/SpotArrayShadowMapSlice.java | 2 -
8 files changed, 60 insertions(+), 30 deletions(-)
diff --git a/jme3-core/src/main/java/com/jme3/material/logic/ShadowStaticPassLightingLogic.java b/jme3-core/src/main/java/com/jme3/material/logic/ShadowStaticPassLightingLogic.java
index 54fad0f0f7..1c6164ba1b 100755
--- a/jme3-core/src/main/java/com/jme3/material/logic/ShadowStaticPassLightingLogic.java
+++ b/jme3-core/src/main/java/com/jme3/material/logic/ShadowStaticPassLightingLogic.java
@@ -69,7 +69,6 @@ public class ShadowStaticPassLightingLogic extends StaticPassLightingLogic {
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);
@@ -77,10 +76,6 @@ public ShadowStaticPassLightingLogic(TechniqueDef techniqueDef) {
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
@@ -157,6 +152,9 @@ protected void updateShadowUniforms(Renderer renderer, Shader shader, int nextTe
Vector4f pssmSplits = null;
Uniform shadowMatricesUniform = shader.getUniform("g_ShadowMatrices");
+
+ shadowMatricesUniform.setMatrix4Length(numShadowDirLights * 4 + numShadowSpotLights);
+
int shadowMatrixIndex = 0;
for (int i = 0; i < numShadowDirLights; i++) {
DirectionalArrayShadowMap map = (DirectionalArrayShadowMap) tempDirLights.get(i).getShadowMap();
@@ -164,7 +162,9 @@ protected void updateShadowUniforms(Renderer renderer, Shader shader, int nextTe
pssmSplits = map.getProjectionSplitPositions();
for (int j = 0; j < map.getNumSlices(); j++) {
ArrayShadowMapSlice slice = (ArrayShadowMapSlice) map.getSlice(j);
- BIAS_MATRIX.mult(slice.getViewProjectionMatrix(), shadowMatrices[shadowMatrixIndex]);
+ shadowMatricesUniform.setMatrix4InArray(
+ slice.getBiasedViewProjectionMatrix(),
+ shadowMatrixIndex);
shadowMatrixIndex++;
}
}
@@ -173,16 +173,18 @@ protected void updateShadowUniforms(Renderer renderer, Shader shader, int nextTe
SpotArrayShadowMap map = (SpotArrayShadowMap) tempSpotLights.get(i).getShadowMap();
array = map.getArray();
SpotArrayShadowMapSlice slice = map.getSlice(0);
- BIAS_MATRIX.mult(slice.getViewProjectionMatrix(), shadowMatrices[shadowMatrixIndex]);
+ shadowMatricesUniform.setMatrix4InArray(
+ slice.getBiasedViewProjectionMatrix(),
+ 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);
diff --git a/jme3-core/src/main/java/com/jme3/material/logic/StaticPassLightingLogic.java b/jme3-core/src/main/java/com/jme3/material/logic/StaticPassLightingLogic.java
index 80ff395135..7dfc0f5596 100644
--- a/jme3-core/src/main/java/com/jme3/material/logic/StaticPassLightingLogic.java
+++ b/jme3-core/src/main/java/com/jme3/material/logic/StaticPassLightingLogic.java
@@ -75,12 +75,6 @@ public class StaticPassLightingLogic extends DefaultTechniqueDefLogic {
protected final ArrayList tempPointLights = new ArrayList<>();
protected final ArrayList tempSpotLights = new ArrayList<>();
- protected static final Matrix4f BIAS_MATRIX = new Matrix4f(
- 0.5f, 0.0f, 0.0f, 0.5f,
- 0.0f, 0.5f, 0.0f, 0.5f,
- 0.0f, 0.0f, 0.5f, 0.5f,
- 0.0f, 0.0f, 0.0f, 1.0f);
-
public StaticPassLightingLogic(TechniqueDef techniqueDef) {
super(techniqueDef);
diff --git a/jme3-core/src/main/java/com/jme3/math/Matrix4f.java b/jme3-core/src/main/java/com/jme3/math/Matrix4f.java
index 159e399321..92de093320 100644
--- a/jme3-core/src/main/java/com/jme3/math/Matrix4f.java
+++ b/jme3-core/src/main/java/com/jme3/math/Matrix4f.java
@@ -752,7 +752,6 @@ public FloatBuffer fillFloatBuffer(FloatBuffer fb, boolean columnMajor) {
TempVars vars = TempVars.get();
-
fillFloatArray(vars.matrixWrite, columnMajor);
fb.put(vars.matrixWrite, 0, 16);
diff --git a/jme3-core/src/main/java/com/jme3/shader/Uniform.java b/jme3-core/src/main/java/com/jme3/shader/Uniform.java
index c377b8ebfb..5475e8e2cd 100644
--- a/jme3-core/src/main/java/com/jme3/shader/Uniform.java
+++ b/jme3-core/src/main/java/com/jme3/shader/Uniform.java
@@ -197,7 +197,7 @@ public void clearValue(){
}
}
- public void setValue(VarType type, Object value){
+ public void setValue(VarType type, Object value) {
if (location == LOC_NOT_DEFINED) {
return;
}
@@ -386,12 +386,40 @@ public void setValue(VarType type, Object value){
varType = type;
updateNeeded = true;
}
+
+ public void setMatrix4Length(int length) {
+ if (location == LOC_NOT_DEFINED) {
+ return;
+ }
+
+ multiData = BufferUtils.ensureLargeEnough(multiData, length * 4 * 4);
+ value = multiData;
+ varType = VarType.Matrix4Array;
+ updateNeeded = true;
+ setByCurrentMaterial = true;
+ }
+
+ public void setMatrix4InArray(Matrix4f matrix, int index) {
+ if (location == LOC_NOT_DEFINED) {
+ return;
+ }
- public void setVector4Length(int length){
- if (location == -1) {
+ if (varType != null && varType != VarType.Matrix4Array) {
+ throw new IllegalArgumentException("Expected a " + varType.name() + " value!");
+ }
+
+ multiData.position(index * 4 * 4);
+ matrix.fillFloatBuffer(multiData, true);
+ multiData.rewind();
+ updateNeeded = true;
+ setByCurrentMaterial = true;
+ }
+
+ public void setVector4Length(int length) {
+ if (location == LOC_NOT_DEFINED) {
return;
}
-
+
multiData = BufferUtils.ensureLargeEnough(multiData, length * 4);
value = multiData;
varType = VarType.Vector4Array;
@@ -399,8 +427,8 @@ public void setVector4Length(int length){
setByCurrentMaterial = true;
}
- public void setVector4InArray(float x, float y, float z, float w, int index){
- if (location == -1) {
+ public void setVector4InArray(float x, float y, float z, float w, int index) {
+ if (location == LOC_NOT_DEFINED) {
return;
}
@@ -414,7 +442,7 @@ public void setVector4InArray(float x, float y, float z, float w, int index){
updateNeeded = true;
setByCurrentMaterial = true;
}
-
+
public boolean isUpdateNeeded(){
return updateNeeded;
}
diff --git a/jme3-core/src/main/java/com/jme3/shadow/next/ShadowMapSlice.java b/jme3-core/src/main/java/com/jme3/shadow/next/ShadowMapSlice.java
index bfd0cc6f7e..8f5bb210cc 100755
--- a/jme3-core/src/main/java/com/jme3/shadow/next/ShadowMapSlice.java
+++ b/jme3-core/src/main/java/com/jme3/shadow/next/ShadowMapSlice.java
@@ -39,12 +39,20 @@
/**
* Represents a single slice of a shadow map.
- *
+ *
+ * @param Type of light
+ *
* @author Kirill Vainer
*/
public interface ShadowMapSlice {
- public Matrix4f getViewProjectionMatrix();
+ public static final Matrix4f BIAS_MATRIX = new Matrix4f(
+ 0.5f, 0.0f, 0.0f, 0.5f,
+ 0.0f, 0.5f, 0.0f, 0.5f,
+ 0.0f, 0.0f, 0.5f, 0.5f,
+ 0.0f, 0.0f, 0.0f, 1.0f);
+
+ public Matrix4f getBiasedViewProjectionMatrix();
public void renderShadowMap(RenderManager renderManager, T light, ViewPort viewPort, GeometryList shadowCasters);
}
diff --git a/jme3-core/src/main/java/com/jme3/shadow/next/array/BaseArrayShadowMapSlice.java b/jme3-core/src/main/java/com/jme3/shadow/next/array/BaseArrayShadowMapSlice.java
index b554fb92f9..a7a7ffc0aa 100755
--- a/jme3-core/src/main/java/com/jme3/shadow/next/array/BaseArrayShadowMapSlice.java
+++ b/jme3-core/src/main/java/com/jme3/shadow/next/array/BaseArrayShadowMapSlice.java
@@ -52,6 +52,7 @@ public class BaseArrayShadowMapSlice implements ArrayShadowMapS
protected final FrameBuffer frameBuffer;
protected final Camera shadowCamera;
protected final Vector3f[] points;
+ protected final Matrix4f biasedViewProjectionMatrix = new Matrix4f();
public BaseArrayShadowMapSlice(TextureArray array, int layer, int textureSize, Vector3f[] points) {
this.shadowCamera = new Camera(textureSize, textureSize);
@@ -67,8 +68,8 @@ public BaseArrayShadowMapSlice(TextureArray array, int layer, int textureSize, V
}
@Override
- public Matrix4f getViewProjectionMatrix() {
- return shadowCamera.getViewProjectionMatrix();
+ public Matrix4f getBiasedViewProjectionMatrix() {
+ return biasedViewProjectionMatrix;
}
@Override
@@ -80,6 +81,7 @@ public void renderShadowMap(RenderManager renderManager, Light light, ViewPort v
renderer.clearBuffers(false, true, false);
viewPort.getQueue().renderShadowQueue(shadowCasters, renderManager, shadowCamera, true);
+
+ BIAS_MATRIX.mult(shadowCamera.getViewProjectionMatrix(), biasedViewProjectionMatrix);
}
-
}
diff --git a/jme3-core/src/main/java/com/jme3/shadow/next/array/SpotArrayShadowMap.java b/jme3-core/src/main/java/com/jme3/shadow/next/array/SpotArrayShadowMap.java
index 5046bc976a..9d6d05559c 100755
--- a/jme3-core/src/main/java/com/jme3/shadow/next/array/SpotArrayShadowMap.java
+++ b/jme3-core/src/main/java/com/jme3/shadow/next/array/SpotArrayShadowMap.java
@@ -64,5 +64,4 @@ public void renderShadowMap(RenderManager renderManager, ViewPort viewPort, Geom
public Light.Type getLightType() {
return Light.Type.Spot;
}
-
}
diff --git a/jme3-core/src/main/java/com/jme3/shadow/next/array/SpotArrayShadowMapSlice.java b/jme3-core/src/main/java/com/jme3/shadow/next/array/SpotArrayShadowMapSlice.java
index 874da428bc..67972a4065 100755
--- a/jme3-core/src/main/java/com/jme3/shadow/next/array/SpotArrayShadowMapSlice.java
+++ b/jme3-core/src/main/java/com/jme3/shadow/next/array/SpotArrayShadowMapSlice.java
@@ -33,7 +33,6 @@
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;
@@ -42,7 +41,6 @@
import com.jme3.texture.TextureArray;
/**
- *
* @author Kirill Vainer
*/
public class SpotArrayShadowMapSlice extends BaseArrayShadowMapSlice {
From 0a4a43974556ff7b8088c6cd029cd6e596bd4f09 Mon Sep 17 00:00:00 2001
From: Kirill Vainer
Date: Sun, 17 Sep 2017 22:04:30 -0400
Subject: [PATCH 24/46] optimize pssm split calculation
---
.../logic/ShadowStaticPassLightingLogic.java | 2 +-
.../next/array/DirectionalArrayShadowMap.java | 5 ++---
.../next/pssm/DirectionalShadowParameters.java | 7 ++++---
.../resources/Common/ShaderLib/InPassShadows.glsl | 15 +++------------
4 files changed, 10 insertions(+), 19 deletions(-)
diff --git a/jme3-core/src/main/java/com/jme3/material/logic/ShadowStaticPassLightingLogic.java b/jme3-core/src/main/java/com/jme3/material/logic/ShadowStaticPassLightingLogic.java
index 1c6164ba1b..f01f444294 100755
--- a/jme3-core/src/main/java/com/jme3/material/logic/ShadowStaticPassLightingLogic.java
+++ b/jme3-core/src/main/java/com/jme3/material/logic/ShadowStaticPassLightingLogic.java
@@ -187,7 +187,7 @@ protected void updateShadowUniforms(Renderer renderer, Shader shader, int nextTe
if (pssmSplits != null) {
Uniform pssmSplitsUniform = shader.getUniform("g_PssmSplits");
- pssmSplitsUniform.setValue(VarType.Vector4, pssmSplits);
+ pssmSplitsUniform.setValue(VarType.Vector3, pssmSplits);
}
}
}
diff --git a/jme3-core/src/main/java/com/jme3/shadow/next/array/DirectionalArrayShadowMap.java b/jme3-core/src/main/java/com/jme3/shadow/next/array/DirectionalArrayShadowMap.java
index 32151e42ad..445a522032 100755
--- a/jme3-core/src/main/java/com/jme3/shadow/next/array/DirectionalArrayShadowMap.java
+++ b/jme3-core/src/main/java/com/jme3/shadow/next/array/DirectionalArrayShadowMap.java
@@ -34,7 +34,6 @@
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;
@@ -47,7 +46,7 @@
public class DirectionalArrayShadowMap extends BaseArrayShadowMap {
private final DirectionalLight light;
- private final Vector4f projectionSplitPositions = new Vector4f();
+ private final Vector3f projectionSplitPositions = new Vector3f();
public DirectionalArrayShadowMap(DirectionalLight light, TextureArray array, int firstArraySlice, int textureSize, int numSplits, Vector3f[] points) {
super(array, firstArraySlice);
@@ -70,7 +69,7 @@ public void renderShadowMap(RenderManager renderManager, ViewPort viewPort, Dire
}
}
- public Vector4f getProjectionSplitPositions() {
+ public Vector3f getProjectionSplitPositions() {
return projectionSplitPositions;
}
diff --git a/jme3-core/src/main/java/com/jme3/shadow/next/pssm/DirectionalShadowParameters.java b/jme3-core/src/main/java/com/jme3/shadow/next/pssm/DirectionalShadowParameters.java
index 57f5646beb..9b63a2fd9b 100755
--- a/jme3-core/src/main/java/com/jme3/shadow/next/pssm/DirectionalShadowParameters.java
+++ b/jme3-core/src/main/java/com/jme3/shadow/next/pssm/DirectionalShadowParameters.java
@@ -31,6 +31,7 @@
*/
package com.jme3.shadow.next.pssm;
+import com.jme3.math.Vector3f;
import com.jme3.math.Vector4f;
import com.jme3.renderer.Camera;
import com.jme3.shadow.PssmShadowUtil;
@@ -45,7 +46,7 @@ public final class DirectionalShadowParameters implements ShadowParameters {
private int numSplits = 4;
protected float zFarOverride = 0;
private float[] splitPositions = new float[numSplits + 1];
- private final Vector4f projectionSplitPositions = new Vector4f();
+ private final Vector3f projectionSplitPositions = new Vector3f();
public float getLambda() {
return lambda;
@@ -69,7 +70,7 @@ public float[] getSplitPositions() {
return splitPositions;
}
- public Vector4f getProjectionSplitPositions() {
+ public Vector3f getProjectionSplitPositions() {
return projectionSplitPositions;
}
@@ -124,7 +125,7 @@ public void updateSplitPositions(Camera viewCamera) {
switch (splitPositions.length) {
case 5:
- projectionSplitPositions.w = 1.0f; // = viewCamera.getViewToProjectionZ(splitPositions[4]);
+// projectionSplitPositions.w = 1.0f;
case 4:
projectionSplitPositions.z = viewCamera.getViewToProjectionZ(splitPositions[3]);
case 3:
diff --git a/jme3-core/src/main/resources/Common/ShaderLib/InPassShadows.glsl b/jme3-core/src/main/resources/Common/ShaderLib/InPassShadows.glsl
index 7fec2be831..9577927512 100755
--- a/jme3-core/src/main/resources/Common/ShaderLib/InPassShadows.glsl
+++ b/jme3-core/src/main/resources/Common/ShaderLib/InPassShadows.glsl
@@ -27,22 +27,13 @@
}
#else
uniform sampler2DArrayShadow g_ShadowMapArray;
- uniform vec4 g_PssmSplits;
+ uniform vec3 g_PssmSplits;
int pssmSliceOffset;
void Shadow_ProcessPssmSlice() {
- #ifdef NUM_PSSM_SPLITS
- float z = gl_FragCoord.z;
- if (z < g_PssmSplits[0]) {
- pssmSliceOffset = 0;
- } else if (z < g_PssmSplits[1]) {
- pssmSliceOffset = 1;
- } else if (z < g_PssmSplits[2]) {
- pssmSliceOffset = 2;
- } else {
- pssmSliceOffset = 3;
- }
+ #if defined(NUM_PSSM_SPLITS) && NUM_PSSM_SPLITS > 1
+ pssmSliceOffset = int(dot(step(g_PssmSplits.xyz, gl_FragCoord.zzz), vec3(1.0)));
#else
pssmSliceOffset = 0;
#endif
From 2c385914c6ea2d95bf77a9fb849cb0540e8c8b10 Mon Sep 17 00:00:00 2001
From: Kirill Vainer
Date: Sun, 17 Sep 2017 22:04:30 -0400
Subject: [PATCH 25/46] optimize pssm split calculation
---
.../logic/ShadowStaticPassLightingLogic.java | 6 +++---
.../next/array/DirectionalArrayShadowMap.java | 5 ++---
.../next/pssm/DirectionalShadowParameters.java | 7 ++++---
.../resources/Common/ShaderLib/InPassShadows.glsl | 15 +++------------
4 files changed, 12 insertions(+), 21 deletions(-)
diff --git a/jme3-core/src/main/java/com/jme3/material/logic/ShadowStaticPassLightingLogic.java b/jme3-core/src/main/java/com/jme3/material/logic/ShadowStaticPassLightingLogic.java
index 1c6164ba1b..5bc4c7fedf 100755
--- a/jme3-core/src/main/java/com/jme3/material/logic/ShadowStaticPassLightingLogic.java
+++ b/jme3-core/src/main/java/com/jme3/material/logic/ShadowStaticPassLightingLogic.java
@@ -39,7 +39,7 @@
import com.jme3.light.SpotLight;
import com.jme3.material.TechniqueDef;
import com.jme3.math.Matrix4f;
-import com.jme3.math.Vector4f;
+import com.jme3.math.Vector3f;
import com.jme3.renderer.Caps;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.Renderer;
@@ -149,7 +149,7 @@ protected float getShadowMapIndex(Light light) {
@Override
protected void updateShadowUniforms(Renderer renderer, Shader shader, int nextTextureUnit) {
TextureArray array = null;
- Vector4f pssmSplits = null;
+ Vector3f pssmSplits = null;
Uniform shadowMatricesUniform = shader.getUniform("g_ShadowMatrices");
@@ -187,7 +187,7 @@ protected void updateShadowUniforms(Renderer renderer, Shader shader, int nextTe
if (pssmSplits != null) {
Uniform pssmSplitsUniform = shader.getUniform("g_PssmSplits");
- pssmSplitsUniform.setValue(VarType.Vector4, pssmSplits);
+ pssmSplitsUniform.setValue(VarType.Vector3, pssmSplits);
}
}
}
diff --git a/jme3-core/src/main/java/com/jme3/shadow/next/array/DirectionalArrayShadowMap.java b/jme3-core/src/main/java/com/jme3/shadow/next/array/DirectionalArrayShadowMap.java
index 32151e42ad..445a522032 100755
--- a/jme3-core/src/main/java/com/jme3/shadow/next/array/DirectionalArrayShadowMap.java
+++ b/jme3-core/src/main/java/com/jme3/shadow/next/array/DirectionalArrayShadowMap.java
@@ -34,7 +34,6 @@
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;
@@ -47,7 +46,7 @@
public class DirectionalArrayShadowMap extends BaseArrayShadowMap {
private final DirectionalLight light;
- private final Vector4f projectionSplitPositions = new Vector4f();
+ private final Vector3f projectionSplitPositions = new Vector3f();
public DirectionalArrayShadowMap(DirectionalLight light, TextureArray array, int firstArraySlice, int textureSize, int numSplits, Vector3f[] points) {
super(array, firstArraySlice);
@@ -70,7 +69,7 @@ public void renderShadowMap(RenderManager renderManager, ViewPort viewPort, Dire
}
}
- public Vector4f getProjectionSplitPositions() {
+ public Vector3f getProjectionSplitPositions() {
return projectionSplitPositions;
}
diff --git a/jme3-core/src/main/java/com/jme3/shadow/next/pssm/DirectionalShadowParameters.java b/jme3-core/src/main/java/com/jme3/shadow/next/pssm/DirectionalShadowParameters.java
index 57f5646beb..9b63a2fd9b 100755
--- a/jme3-core/src/main/java/com/jme3/shadow/next/pssm/DirectionalShadowParameters.java
+++ b/jme3-core/src/main/java/com/jme3/shadow/next/pssm/DirectionalShadowParameters.java
@@ -31,6 +31,7 @@
*/
package com.jme3.shadow.next.pssm;
+import com.jme3.math.Vector3f;
import com.jme3.math.Vector4f;
import com.jme3.renderer.Camera;
import com.jme3.shadow.PssmShadowUtil;
@@ -45,7 +46,7 @@ public final class DirectionalShadowParameters implements ShadowParameters {
private int numSplits = 4;
protected float zFarOverride = 0;
private float[] splitPositions = new float[numSplits + 1];
- private final Vector4f projectionSplitPositions = new Vector4f();
+ private final Vector3f projectionSplitPositions = new Vector3f();
public float getLambda() {
return lambda;
@@ -69,7 +70,7 @@ public float[] getSplitPositions() {
return splitPositions;
}
- public Vector4f getProjectionSplitPositions() {
+ public Vector3f getProjectionSplitPositions() {
return projectionSplitPositions;
}
@@ -124,7 +125,7 @@ public void updateSplitPositions(Camera viewCamera) {
switch (splitPositions.length) {
case 5:
- projectionSplitPositions.w = 1.0f; // = viewCamera.getViewToProjectionZ(splitPositions[4]);
+// projectionSplitPositions.w = 1.0f;
case 4:
projectionSplitPositions.z = viewCamera.getViewToProjectionZ(splitPositions[3]);
case 3:
diff --git a/jme3-core/src/main/resources/Common/ShaderLib/InPassShadows.glsl b/jme3-core/src/main/resources/Common/ShaderLib/InPassShadows.glsl
index 7fec2be831..9577927512 100755
--- a/jme3-core/src/main/resources/Common/ShaderLib/InPassShadows.glsl
+++ b/jme3-core/src/main/resources/Common/ShaderLib/InPassShadows.glsl
@@ -27,22 +27,13 @@
}
#else
uniform sampler2DArrayShadow g_ShadowMapArray;
- uniform vec4 g_PssmSplits;
+ uniform vec3 g_PssmSplits;
int pssmSliceOffset;
void Shadow_ProcessPssmSlice() {
- #ifdef NUM_PSSM_SPLITS
- float z = gl_FragCoord.z;
- if (z < g_PssmSplits[0]) {
- pssmSliceOffset = 0;
- } else if (z < g_PssmSplits[1]) {
- pssmSliceOffset = 1;
- } else if (z < g_PssmSplits[2]) {
- pssmSliceOffset = 2;
- } else {
- pssmSliceOffset = 3;
- }
+ #if defined(NUM_PSSM_SPLITS) && NUM_PSSM_SPLITS > 1
+ pssmSliceOffset = int(dot(step(g_PssmSplits.xyz, gl_FragCoord.zzz), vec3(1.0)));
#else
pssmSliceOffset = 0;
#endif
From 3889cb47b7216ac682c6dcf659306184a91442dd Mon Sep 17 00:00:00 2001
From: Kirill Vainer
Date: Sun, 17 Sep 2017 22:11:42 -0400
Subject: [PATCH 26/46] calculate lighting in world space
---
.../jme3/material/logic/StaticPassLightingLogic.java | 12 ------------
.../Common/MatDefs/Light/StaticLighting.frag | 2 +-
.../Common/MatDefs/Light/StaticLighting.vert | 4 ++--
3 files changed, 3 insertions(+), 15 deletions(-)
diff --git a/jme3-core/src/main/java/com/jme3/material/logic/StaticPassLightingLogic.java b/jme3-core/src/main/java/com/jme3/material/logic/StaticPassLightingLogic.java
index 7dfc0f5596..c99ef68e76 100644
--- a/jme3-core/src/main/java/com/jme3/material/logic/StaticPassLightingLogic.java
+++ b/jme3-core/src/main/java/com/jme3/material/logic/StaticPassLightingLogic.java
@@ -126,14 +126,6 @@ public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager
return techniqueDef.getShader(assetManager, rendererCaps, defines);
}
- protected void transformDirection(Matrix4f viewMatrix, Vector3f direction) {
- viewMatrix.multNormal(direction, direction);
- }
-
- protected void transformPosition(Matrix4f viewMatrix, Vector3f location) {
- viewMatrix.mult(location, location);
- }
-
protected float getShadowMapIndex(Light light) {
return 1.0f;
}
@@ -154,7 +146,6 @@ protected void updateLightListUniforms(Matrix4f viewMatrix, Shader shader) {
ColorRGBA color = light.getColor();
float shadowMapIndex = getShadowMapIndex(light);
tempDirection.set(light.getDirection());
- transformDirection(viewMatrix, tempDirection);
lightData.setVector4InArray(color.r, color.g, color.b, shadowMapIndex, index++);
lightData.setVector4InArray(tempDirection.x, tempDirection.y, tempDirection.z, 1f, index++);
}
@@ -164,7 +155,6 @@ protected void updateLightListUniforms(Matrix4f viewMatrix, Shader shader) {
float shadowMapIndex = getShadowMapIndex(light);
tempPosition.set(light.getPosition());
float invRadius = light.getInvRadius();
- transformPosition(viewMatrix, tempPosition);
lightData.setVector4InArray(color.r, color.g, color.b, shadowMapIndex, index++);
lightData.setVector4InArray(tempPosition.x, tempPosition.y, tempPosition.z, invRadius, index++);
}
@@ -175,8 +165,6 @@ protected void updateLightListUniforms(Matrix4f viewMatrix, Shader shader) {
tempPosition.set(light.getPosition());
tempDirection.set(light.getDirection());
- transformPosition(viewMatrix, tempPosition);
- transformDirection(viewMatrix, tempDirection);
float invRange = light.getInvSpotRange();
float spotAngleCos = light.getPackedAngleCos();
diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/StaticLighting.frag b/jme3-core/src/main/resources/Common/MatDefs/Light/StaticLighting.frag
index 962e2c1221..890cdba034 100755
--- a/jme3-core/src/main/resources/Common/MatDefs/Light/StaticLighting.frag
+++ b/jme3-core/src/main/resources/Common/MatDefs/Light/StaticLighting.frag
@@ -162,7 +162,7 @@ surface_t getSurface() {
if (!gl_FrontFacing) {
s.normal = -s.normal;
}
- s.viewDir = normalize(-vPos);
+ s.viewDir = normalize(g_CameraPosition - s.position);
#ifdef AMBIENTMAP
s.ambient = texture2D(m_AmbientMap, vTexCoord).rgb;
#else
diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/StaticLighting.vert b/jme3-core/src/main/resources/Common/MatDefs/Light/StaticLighting.vert
index 354afec0ca..c974fa4400 100755
--- a/jme3-core/src/main/resources/Common/MatDefs/Light/StaticLighting.vert
+++ b/jme3-core/src/main/resources/Common/MatDefs/Light/StaticLighting.vert
@@ -22,8 +22,8 @@ void main() {
Skinning_Compute(modelSpacePos, modelSpaceNorm);
#endif
- vPos = TransformWorldView(modelSpacePos).xyz;
- vNormal = TransformNormal(modelSpaceNorm);
+ vPos = TransformWorld(modelSpacePos).xyz;
+ vNormal = TransformWorldNormal(modelSpaceNorm);
vec3 shadowPos = TransformWorld(modelSpacePos).xyz;
Shadow_ProcessProjCoord(shadowPos);
From b52d0e3743906a9166f19a051a5d7dbafa3e9ea8 Mon Sep 17 00:00:00 2001
From: Kirill Vainer
Date: Sun, 17 Sep 2017 22:13:27 -0400
Subject: [PATCH 27/46] fix wrong counts
---
.../material/logic/ShadowStaticPassLightingLogic.java | 11 +++++++----
.../jme3/material/logic/StaticPassLightingLogic.java | 2 +-
.../Common/MatDefs/Light/StaticLighting.frag | 9 +++++++--
3 files changed, 15 insertions(+), 7 deletions(-)
diff --git a/jme3-core/src/main/java/com/jme3/material/logic/ShadowStaticPassLightingLogic.java b/jme3-core/src/main/java/com/jme3/material/logic/ShadowStaticPassLightingLogic.java
index 5bc4c7fedf..dfeec2c2bc 100755
--- a/jme3-core/src/main/java/com/jme3/material/logic/ShadowStaticPassLightingLogic.java
+++ b/jme3-core/src/main/java/com/jme3/material/logic/ShadowStaticPassLightingLogic.java
@@ -126,9 +126,9 @@ protected void makeCurrentBase(AssetManager assetManager, RenderManager renderMa
}
ambientLightColor.a = 1.0f;
- defines.set(numDirLightsDefineId, tempDirLights.size());
- defines.set(numPointLightsDefineId, tempPointLights.size());
- defines.set(numSpotLightsDefineId, tempSpotLights.size());
+ defines.set(numDirLightsDefineId, tempDirLights.size() - numShadowDirLights);
+ defines.set(numPointLightsDefineId, tempPointLights.size() - numShadowPointLights);
+ defines.set(numSpotLightsDefineId, tempSpotLights.size() - numShadowSpotLights);
defines.set(numShadowDirLightsDefineId, numShadowDirLights);
defines.set(numShadowPointLightsDefineId, numShadowPointLights);
@@ -153,7 +153,10 @@ protected void updateShadowUniforms(Renderer renderer, Shader shader, int nextTe
Uniform shadowMatricesUniform = shader.getUniform("g_ShadowMatrices");
- shadowMatricesUniform.setMatrix4Length(numShadowDirLights * 4 + numShadowSpotLights);
+ shadowMatricesUniform.setMatrix4Length(
+ numShadowDirLights * 4 +
+ numShadowPointLights * 6 +
+ numShadowSpotLights);
int shadowMatrixIndex = 0;
for (int i = 0; i < numShadowDirLights; i++) {
diff --git a/jme3-core/src/main/java/com/jme3/material/logic/StaticPassLightingLogic.java b/jme3-core/src/main/java/com/jme3/material/logic/StaticPassLightingLogic.java
index c99ef68e76..630814e379 100644
--- a/jme3-core/src/main/java/com/jme3/material/logic/StaticPassLightingLogic.java
+++ b/jme3-core/src/main/java/com/jme3/material/logic/StaticPassLightingLogic.java
@@ -127,7 +127,7 @@ public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager
}
protected float getShadowMapIndex(Light light) {
- return 1.0f;
+ return -1.0f;
}
protected void updateLightListUniforms(Matrix4f viewMatrix, Shader shader) {
diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/StaticLighting.frag b/jme3-core/src/main/resources/Common/MatDefs/Light/StaticLighting.frag
index 890cdba034..d53b88cc70 100755
--- a/jme3-core/src/main/resources/Common/MatDefs/Light/StaticLighting.frag
+++ b/jme3-core/src/main/resources/Common/MatDefs/Light/StaticLighting.frag
@@ -19,9 +19,12 @@
#define DIR_SHADOW_LIGHT_END (NUM_SHADOW_DIR_LIGHTS * 2)
#define DIR_LIGHT_START (DIR_SHADOW_LIGHT_END)
-#define DIR_LIGHT_END (NUM_DIR_LIGHTS * 2)
+#define DIR_LIGHT_END (DIR_LIGHT_START + NUM_DIR_LIGHTS * 2)
-#define POINT_LIGHT_START (DIR_LIGHT_END)
+#define POINT_SHADOW_LIGHT_START (DIR_LIGHT_END)
+#define POINT_SHADOW_LIGHT_END (POINT_SHADOW_LIGHT_START + NUM_SHADOW_POINT_LIGHTS * 2)
+
+#define POINT_LIGHT_START (POINT_SHADOW_LIGHT_END)
#define POINT_LIGHT_END (POINT_LIGHT_START + NUM_POINT_LIGHTS * 2)
#define SPOT_SHADOW_LIGHT_START (POINT_LIGHT_END)
@@ -32,6 +35,8 @@
#define LIGHT_DATA_SIZE (SPOT_LIGHT_END)
+uniform vec3 g_CameraPosition;
+
uniform sampler2D m_AmbientMap;
uniform float m_AlphaDiscardThreshold;
uniform float m_Shininess;
From 47b34c6de595f4bc8a0e0d057a5909d5a35ee63c Mon Sep 17 00:00:00 2001
From: Kirill Vainer
Date: Sun, 17 Sep 2017 22:21:50 -0400
Subject: [PATCH 28/46] optimize clearing shadow maps
---
.../shadow/next/PreShadowArrayRenderer.java | 8 ++---
.../next/array/BaseArrayShadowMapSlice.java | 30 ++++++++++++-------
.../next/array/DirectionalArrayShadowMap.java | 8 ++---
.../array/DirectionalArrayShadowMapSlice.java | 13 ++++----
.../shadow/next/array/SpotArrayShadowMap.java | 5 ++--
.../next/array/SpotArrayShadowMapSlice.java | 29 +++++++-----------
6 files changed, 45 insertions(+), 48 deletions(-)
diff --git a/jme3-core/src/main/java/com/jme3/shadow/next/PreShadowArrayRenderer.java b/jme3-core/src/main/java/com/jme3/shadow/next/PreShadowArrayRenderer.java
index fd9bd6e585..e3e00b636c 100755
--- a/jme3-core/src/main/java/com/jme3/shadow/next/PreShadowArrayRenderer.java
+++ b/jme3-core/src/main/java/com/jme3/shadow/next/PreShadowArrayRenderer.java
@@ -148,16 +148,14 @@ public void addLight(Light light) {
array,
nextArraySlice,
textureSize,
- directionalParams.getNumSplits(),
- points);
+ directionalParams.getNumSplits());
break;
case Spot:
shadowMap = new SpotArrayShadowMap(
(SpotLight) light,
array,
nextArraySlice,
- textureSize,
- points);
+ textureSize);
break;
default:
throw new UnsupportedOperationException();
@@ -202,7 +200,7 @@ private void renderShadowMaps(ViewPort viewPort) {
switch (shadowMap.getLightType()) {
case Directional:
DirectionalArrayShadowMap directionalShadow = (DirectionalArrayShadowMap) shadowMap;
- directionalShadow.renderShadowMap(renderManager, viewPort, directionalParams, shadowCasters);
+ directionalShadow.renderShadowMap(renderManager, viewPort, directionalParams, shadowCasters, points);
break;
case Spot:
SpotArrayShadowMap spotShadow = (SpotArrayShadowMap) shadowMap;
diff --git a/jme3-core/src/main/java/com/jme3/shadow/next/array/BaseArrayShadowMapSlice.java b/jme3-core/src/main/java/com/jme3/shadow/next/array/BaseArrayShadowMapSlice.java
index a7a7ffc0aa..7e22ad05bd 100755
--- a/jme3-core/src/main/java/com/jme3/shadow/next/array/BaseArrayShadowMapSlice.java
+++ b/jme3-core/src/main/java/com/jme3/shadow/next/array/BaseArrayShadowMapSlice.java
@@ -33,7 +33,6 @@
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;
@@ -51,12 +50,18 @@ public class BaseArrayShadowMapSlice implements ArrayShadowMapS
protected final FrameBuffer frameBuffer;
protected final Camera shadowCamera;
- protected final Vector3f[] points;
protected final Matrix4f biasedViewProjectionMatrix = new Matrix4f();
- public BaseArrayShadowMapSlice(TextureArray array, int layer, int textureSize, Vector3f[] points) {
+ protected boolean fbNeedClear = true;
+
+ public BaseArrayShadowMapSlice(TextureArray array, int layer, int textureSize, boolean useBorder) {
this.shadowCamera = new Camera(textureSize, textureSize);
- this.shadowCamera.setParallelProjection(true);
+
+ if (useBorder) {
+ float onePx = 1f / textureSize;
+ this.shadowCamera.setViewPort(onePx, 1f - onePx, onePx, 1f - onePx);
+ }
+
this.frameBuffer = new FrameBuffer(textureSize, textureSize, 1);
Image image = array.getImage();
@@ -64,7 +69,6 @@ public BaseArrayShadowMapSlice(TextureArray array, int layer, int textureSize, V
image.addData(null);
this.frameBuffer.setDepthTexture(array, layer);
- this.points = points;
}
@Override
@@ -76,12 +80,18 @@ public Matrix4f getBiasedViewProjectionMatrix() {
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);
+ if (fbNeedClear) {
+ renderer.setFrameBuffer(frameBuffer);
+ renderer.clearBuffers(false, true, false);
+ fbNeedClear = false;
+ }
+
+ if (shadowCasters.size() > 0) {
+ renderManager.setCamera(shadowCamera, false);
+ viewPort.getQueue().renderShadowQueue(shadowCasters, renderManager, shadowCamera, true);
+ fbNeedClear = true;
+ }
- viewPort.getQueue().renderShadowQueue(shadowCasters, renderManager, shadowCamera, true);
-
BIAS_MATRIX.mult(shadowCamera.getViewProjectionMatrix(), biasedViewProjectionMatrix);
}
}
diff --git a/jme3-core/src/main/java/com/jme3/shadow/next/array/DirectionalArrayShadowMap.java b/jme3-core/src/main/java/com/jme3/shadow/next/array/DirectionalArrayShadowMap.java
index 445a522032..f9cf303ac5 100755
--- a/jme3-core/src/main/java/com/jme3/shadow/next/array/DirectionalArrayShadowMap.java
+++ b/jme3-core/src/main/java/com/jme3/shadow/next/array/DirectionalArrayShadowMap.java
@@ -48,23 +48,23 @@ public class DirectionalArrayShadowMap extends BaseArrayShadowMap {
- public DirectionalArrayShadowMapSlice(TextureArray array, int layer, int textureSize, Vector3f[] points) {
- super(array, layer, textureSize, points);
+ public DirectionalArrayShadowMapSlice(TextureArray array, int layer, int textureSize) {
+ super(array, layer, textureSize, true);
this.shadowCamera.setParallelProjection(true);
}
@@ -54,12 +53,12 @@ public void updateShadowCamera(
DirectionalLight light,
GeometryList shadowCasters,
float near,
- float far) {
-
- ShadowUtil.updateFrustumPoints(viewPort.getCamera(), near, far, points);
+ float far,
+ Vector3f[] points) {
shadowCamera.lookAtDirection(light.getDirection(), shadowCamera.getUp());
-
+
int textureSize = frameBuffer.getWidth();
+ ShadowUtil.updateFrustumPoints(viewPort.getCamera(), near, far, points);
ShadowUtil.updateShadowCamera(viewPort, null, shadowCamera, points, shadowCasters, textureSize);
}
diff --git a/jme3-core/src/main/java/com/jme3/shadow/next/array/SpotArrayShadowMap.java b/jme3-core/src/main/java/com/jme3/shadow/next/array/SpotArrayShadowMap.java
index 9d6d05559c..f6c72a762d 100755
--- a/jme3-core/src/main/java/com/jme3/shadow/next/array/SpotArrayShadowMap.java
+++ b/jme3-core/src/main/java/com/jme3/shadow/next/array/SpotArrayShadowMap.java
@@ -33,7 +33,6 @@
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;
@@ -46,11 +45,11 @@ public class SpotArrayShadowMap extends BaseArrayShadowMap {
- public SpotArrayShadowMapSlice(TextureArray array, int layer, int textureSize, Vector3f[] points) {
- super(array, layer, textureSize, points);
+ public SpotArrayShadowMapSlice(TextureArray array, int layer, int textureSize) {
+ super(array, layer, textureSize, true);
}
- 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());
+ public void updateShadowCamera(ViewPort viewPort, SpotLight light, GeometryList shadowCasters) {
shadowCamera.setLocation(light.getPosition());
-
- int textureSize = frameBuffer.getWidth();
- ShadowUtil.updateShadowCamera(viewPort, null, shadowCamera, points, shadowCasters, textureSize);
+ 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);
+ }
}
}
From ec0fcd24d2c92b17cbbc7845f9420d138fa244f5 Mon Sep 17 00:00:00 2001
From: Kirill Vainer
Date: Sun, 17 Sep 2017 22:23:51 -0400
Subject: [PATCH 29/46] support point light shadows
---
.../logic/ShadowStaticPassLightingLogic.java | 13 +++
.../shadow/next/PreShadowArrayRenderer.java | 13 +++
.../next/array/PointArrayShadowMap.java | 99 +++++++++++++++++++
.../next/array/PointArrayShadowMapSlice.java | 60 +++++++++++
4 files changed, 185 insertions(+)
create mode 100644 jme3-core/src/main/java/com/jme3/shadow/next/array/PointArrayShadowMap.java
create mode 100644 jme3-core/src/main/java/com/jme3/shadow/next/array/PointArrayShadowMapSlice.java
diff --git a/jme3-core/src/main/java/com/jme3/material/logic/ShadowStaticPassLightingLogic.java b/jme3-core/src/main/java/com/jme3/material/logic/ShadowStaticPassLightingLogic.java
index dfeec2c2bc..c5c11c32d0 100755
--- a/jme3-core/src/main/java/com/jme3/material/logic/ShadowStaticPassLightingLogic.java
+++ b/jme3-core/src/main/java/com/jme3/material/logic/ShadowStaticPassLightingLogic.java
@@ -50,6 +50,7 @@
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.PointArrayShadowMap;
import com.jme3.shadow.next.array.SpotArrayShadowMap;
import com.jme3.shadow.next.array.SpotArrayShadowMapSlice;
import com.jme3.texture.TextureArray;
@@ -171,6 +172,18 @@ protected void updateShadowUniforms(Renderer renderer, Shader shader, int nextTe
shadowMatrixIndex++;
}
}
+
+ for (int i = 0; i < numShadowPointLights; i++) {
+ PointArrayShadowMap map = (PointArrayShadowMap) tempPointLights.get(i).getShadowMap();
+ array = map.getArray();
+ for (int j = 0; j < map.getNumSlices(); j++) {
+ ArrayShadowMapSlice slice = (ArrayShadowMapSlice) map.getSlice(j);
+ shadowMatricesUniform.setMatrix4InArray(
+ slice.getBiasedViewProjectionMatrix(),
+ shadowMatrixIndex);
+ shadowMatrixIndex++;
+ }
+ }
for (int i = 0; i < numShadowSpotLights; i++) {
SpotArrayShadowMap map = (SpotArrayShadowMap) tempSpotLights.get(i).getShadowMap();
diff --git a/jme3-core/src/main/java/com/jme3/shadow/next/PreShadowArrayRenderer.java b/jme3-core/src/main/java/com/jme3/shadow/next/PreShadowArrayRenderer.java
index e3e00b636c..78b9507fe5 100755
--- a/jme3-core/src/main/java/com/jme3/shadow/next/PreShadowArrayRenderer.java
+++ b/jme3-core/src/main/java/com/jme3/shadow/next/PreShadowArrayRenderer.java
@@ -34,6 +34,7 @@
import com.jme3.shadow.next.pssm.DirectionalShadowParameters;
import com.jme3.light.DirectionalLight;
import com.jme3.light.Light;
+import com.jme3.light.PointLight;
import com.jme3.light.SpotLight;
import com.jme3.material.RenderState;
import com.jme3.math.Vector3f;
@@ -46,6 +47,7 @@
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.PointArrayShadowMap;
import com.jme3.shadow.next.array.SpotArrayShadowMap;
import com.jme3.texture.FrameBuffer;
import com.jme3.texture.Image;
@@ -150,6 +152,13 @@ public void addLight(Light light) {
textureSize,
directionalParams.getNumSplits());
break;
+ case Point:
+ shadowMap = new PointArrayShadowMap(
+ (PointLight) light,
+ array,
+ nextArraySlice,
+ textureSize);
+ break;
case Spot:
shadowMap = new SpotArrayShadowMap(
(SpotLight) light,
@@ -202,6 +211,10 @@ private void renderShadowMaps(ViewPort viewPort) {
DirectionalArrayShadowMap directionalShadow = (DirectionalArrayShadowMap) shadowMap;
directionalShadow.renderShadowMap(renderManager, viewPort, directionalParams, shadowCasters, points);
break;
+ case Point:
+ PointArrayShadowMap pointShadow = (PointArrayShadowMap) shadowMap;
+ pointShadow.renderShadowMap(renderManager, viewPort, shadowCasters);
+ break;
case Spot:
SpotArrayShadowMap spotShadow = (SpotArrayShadowMap) shadowMap;
spotShadow.renderShadowMap(renderManager, viewPort, shadowCasters);
diff --git a/jme3-core/src/main/java/com/jme3/shadow/next/array/PointArrayShadowMap.java b/jme3-core/src/main/java/com/jme3/shadow/next/array/PointArrayShadowMap.java
new file mode 100644
index 0000000000..67e2bd35d2
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/shadow/next/array/PointArrayShadowMap.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.array;
+
+import com.jme3.light.Light;
+import com.jme3.light.Light.Type;
+import com.jme3.light.PointLight;
+import com.jme3.math.Quaternion;
+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 PointArrayShadowMap extends BaseArrayShadowMap {
+
+ private final PointLight light;
+
+ private static final Quaternion[] ROTATIONS = new Quaternion[6];
+
+ static {
+ for (int i = 0; i < ROTATIONS.length; i++) {
+ ROTATIONS[i] = new Quaternion();
+ }
+
+ // left
+ ROTATIONS[0].fromAxes(Vector3f.UNIT_Z, Vector3f.UNIT_Y, Vector3f.UNIT_X.mult(-1f));
+
+ // right
+ ROTATIONS[1].fromAxes(Vector3f.UNIT_Z.mult(-1f), Vector3f.UNIT_Y, Vector3f.UNIT_X);
+
+ // bottom
+ ROTATIONS[2].fromAxes(Vector3f.UNIT_X.mult(-1f), Vector3f.UNIT_Z.mult(-1f), Vector3f.UNIT_Y.mult(-1f));
+
+ // top
+ ROTATIONS[3].fromAxes(Vector3f.UNIT_X.mult(-1f), Vector3f.UNIT_Z, Vector3f.UNIT_Y);
+
+ // forward
+ ROTATIONS[4].fromAxes(Vector3f.UNIT_X.mult(-1f), Vector3f.UNIT_Y, Vector3f.UNIT_Z.mult(-1f));
+
+ // backward
+ ROTATIONS[5].fromAxes(Vector3f.UNIT_X, Vector3f.UNIT_Y, Vector3f.UNIT_Z);
+ }
+
+ public PointArrayShadowMap(PointLight light, TextureArray array, int firstArraySlice, int textureSize) {
+ super(array, firstArraySlice);
+ this.light = light;
+ this.slices = new PointArrayShadowMapSlice[6];
+ for (int i = 0; i < slices.length; i++) {
+ this.slices[i] = new PointArrayShadowMapSlice(array, firstArraySlice + i, textureSize, ROTATIONS[i]);
+ }
+ }
+
+ public void renderShadowMap(RenderManager renderManager, ViewPort viewPort, GeometryList shadowCasters) {
+ for (int i = 0; i < slices.length; i++) {
+ shadowCasters.clear();
+ slices[i].updateShadowCamera(viewPort, light, shadowCasters);
+ slices[i].renderShadowMap(renderManager, light, viewPort, shadowCasters);
+ }
+ }
+
+ @Override
+ public Light.Type getLightType() {
+ return Type.Point;
+ }
+
+}
diff --git a/jme3-core/src/main/java/com/jme3/shadow/next/array/PointArrayShadowMapSlice.java b/jme3-core/src/main/java/com/jme3/shadow/next/array/PointArrayShadowMapSlice.java
new file mode 100644
index 0000000000..06b8f0a682
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/shadow/next/array/PointArrayShadowMapSlice.java
@@ -0,0 +1,60 @@
+/*
+ * 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.array;
+
+import com.jme3.light.PointLight;
+import com.jme3.math.Quaternion;
+import com.jme3.renderer.ViewPort;
+import com.jme3.renderer.queue.GeometryList;
+import com.jme3.renderer.queue.RenderQueue.ShadowMode;
+import com.jme3.scene.Spatial;
+import com.jme3.shadow.ShadowUtil;
+import com.jme3.texture.TextureArray;
+
+/**
+ * @author Kirill Vainer
+ */
+public class PointArrayShadowMapSlice extends BaseArrayShadowMapSlice {
+
+ public PointArrayShadowMapSlice(TextureArray array, int layer, int textureSize, Quaternion axes) {
+ super(array, layer, textureSize, false);
+ shadowCamera.setAxes(axes);
+ }
+
+ public void updateShadowCamera(ViewPort viewPort, PointLight light, GeometryList shadowCasters) {
+ shadowCamera.setFrustumPerspective(90f, 1f, 0.1f, light.getRadius());
+ shadowCamera.setLocation(light.getPosition());
+ for (Spatial scene : viewPort.getScenes()) {
+ ShadowUtil.getGeometriesInCamFrustum(scene, shadowCamera, ShadowMode.Cast, shadowCasters);
+ }
+ }
+}
From c136a4212e8ca86e73684532b7d55aa745d9a895 Mon Sep 17 00:00:00 2001
From: Kirill Vainer
Date: Sun, 17 Sep 2017 22:27:10 -0400
Subject: [PATCH 30/46] use PBR + support point light shadows in shader
---
.../Common/MatDefs/Light/StaticLighting.frag | 149 +++++++++++-------
.../Common/ShaderLib/InPassShadows.glsl | 54 ++++++-
2 files changed, 148 insertions(+), 55 deletions(-)
diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/StaticLighting.frag b/jme3-core/src/main/resources/Common/MatDefs/Light/StaticLighting.frag
index d53b88cc70..f0f76e70ce 100755
--- a/jme3-core/src/main/resources/Common/MatDefs/Light/StaticLighting.frag
+++ b/jme3-core/src/main/resources/Common/MatDefs/Light/StaticLighting.frag
@@ -2,6 +2,7 @@
#import "Common/ShaderLib/BlinnPhongLighting.glsllib"
#import "Common/ShaderLib/Lighting.glsllib"
#import "Common/ShaderLib/InPassShadows.glsl"
+#import "Common/ShaderLib/PBR.glsllib"
#ifndef NUM_DIR_LIGHTS
#define NUM_DIR_LIGHTS 0
@@ -59,50 +60,76 @@ struct surface_t {
vec3 ambient;
vec4 diffuse;
vec4 specular;
- float shininess;
+ float roughness;
+ float ndotv;
};
-vec2 Lighting_ProcessLighting(vec3 norm, vec3 viewDir, vec3 lightDir, float attenuation, float shininess) {
- float diffuseFactor = max(0.0, dot(norm, lightDir));
- vec3 H = normalize(viewDir + lightDir);
- float HdotN = max(0.0, dot(H, norm));
- float specularFactor = pow(HdotN, shininess);
- return vec2(diffuseFactor, diffuseFactor * specularFactor) * vec2(attenuation);
-}
-
-vec2 Lighting_ProcessDirectional(int lightIndex, surface_t surface) {
- vec3 lightDirection = g_LightData[lightIndex + 1].xyz;
- vec2 light = Lighting_ProcessLighting(surface.normal, surface.viewDir, -lightDirection, 1.0, surface.shininess);
- return light;
-}
-
float Lighting_ProcessAttenuation(float invRadius, float dist) {
#ifdef SRGB
- float atten = (1.0 - invRadius * dist) / (1.0 + invRadius * dist * dist);
+ 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
}
-vec2 Lighting_ProcessPoint(int lightIndex, surface_t surface) {
+void Lighting_ProcessDirectional(int lightIndex, surface_t surface, out vec3 outDiffuse, out vec3 outSpecular) {
+ vec4 lightColor = g_LightData[lightIndex];
+ vec3 lightDirection = g_LightData[lightIndex + 1].xyz;
+
+ 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);
- return Lighting_ProcessLighting(surface.normal, surface.viewDir, lightDirection, atten, surface.shininess);
+ if (atten == 0.0) {
+ outDiffuse = vec3(0.0);
+ outSpecular = vec3(0.0);
+ return lightDirection;
+ }
+ PBR_ComputeDirectLightSpecWF(surface.normal, lightDirection, surface.viewDir,
+ lightColor.rgb, surface.specular.rgb, surface.roughness, surface.ndotv,
+ outDiffuse, outSpecular);
+
+ outDiffuse *= atten;
+ outSpecular *= atten;
+
+ return lightDirection;
}
-vec2 Lighting_ProcessSpot(int lightIndex, surface_t surface) {
+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 = Lighting_ProcessAttenuation(lightPosition.w, dist);
- atten *= computeSpotFalloff(lightDirection, lightVector);
- return Lighting_ProcessLighting(surface.normal, surface.viewDir, lightVector, atten, surface.shininess);
+ float atten = computeSpotFalloff(lightDirection, lightVector);
+ if (atten == 0.0) {
+ outDiffuse = vec3(0.0);
+ outSpecular = vec3(0.0);
+ return;
+ }
+ atten *= Lighting_ProcessAttenuation(lightPosition.w, dist);
+ if (atten == 0.0) {
+ outDiffuse = vec3(0.0);
+ outSpecular = vec3(0.0);
+ return;
+ }
+ PBR_ComputeDirectLightSpecWF(surface.normal, lightVector, 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) {
@@ -117,44 +144,59 @@ void Lighting_ProcessAll(surface_t surface, out vec3 ambient, out vec3 diffuse,
int projIndex = 0;
for (int i = DIR_SHADOW_LIGHT_START; i < DIR_SHADOW_LIGHT_END; i += 2) {
- vec4 lightColor = g_LightData[i];
- vec2 lightDiffSpec = Lighting_ProcessDirectional(i, surface);
- float shadow = Shadow_ProcessDirectional(projIndex, lightColor.w);
- lightDiffSpec *= vec2(shadow);
- diffuse += lightColor.rgb * lightDiffSpec.x;
- specular += lightColor.rgb * lightDiffSpec.y;
- projIndex += NUM_PSSM_SPLITS;
+ 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;
+
+ diffuse += outDiffuse;
+ specular += outSpecular;
}
for (int i = DIR_LIGHT_START; i < DIR_LIGHT_END; i += 2) {
- vec3 lightColor = g_LightData[i].rgb;
- vec2 lightDiffSpec = Lighting_ProcessDirectional(i, surface);
- diffuse += lightColor.rgb * lightDiffSpec.x;
- specular += lightColor.rgb * lightDiffSpec.y;
+ vec3 outDiffuse, outSpecular;
+ Lighting_ProcessDirectional(i, surface, outDiffuse, outSpecular);
+ diffuse += outDiffuse;
+ specular += outSpecular;
}
+ for (int i = POINT_SHADOW_LIGHT_START; i < POINT_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;
+
+ diffuse += outDiffuse;
+ specular += outSpecular;
+ }
for (int i = POINT_LIGHT_START; i < POINT_LIGHT_END; i += 2) {
- vec3 lightColor = g_LightData[i].rgb;
- vec2 lightDiffSpec = Lighting_ProcessPoint(i, surface);
- diffuse += lightColor.rgb * lightDiffSpec.x;
- specular += lightColor.rgb * lightDiffSpec.y;
+ vec3 outDiffuse, outSpecular;
+ Lighting_ProcessPoint(i, surface, outDiffuse, outSpecular);
+ diffuse += outDiffuse;
+ specular += outSpecular;
}
for (int i = SPOT_SHADOW_LIGHT_START; i < SPOT_SHADOW_LIGHT_END; i += 3) {
- vec4 lightColor = g_LightData[i];
- vec2 lightDiffSpec = Lighting_ProcessSpot(i, surface);
- float shadow = Shadow_ProcessSpot(projIndex, lightColor.w);
- lightDiffSpec *= vec2(shadow);
- diffuse += lightColor.rgb * lightDiffSpec.x;
- specular += lightColor.rgb * lightDiffSpec.y;
- projIndex++;
+ 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;
+
+ diffuse += outDiffuse;
+ specular += outSpecular;
}
for (int i = SPOT_LIGHT_START; i < SPOT_LIGHT_END; i += 3) {
- vec3 lightColor = g_LightData[i].rgb;
- vec2 lightDiffSpec = Lighting_ProcessSpot(i, surface);
- diffuse += lightColor * lightDiffSpec.x;
- specular += lightColor * lightDiffSpec.y;
+ vec3 outDiffuse, outSpecular;
+ Lighting_ProcessSpot(i, surface, outDiffuse, outSpecular);
+ diffuse += outDiffuse;
+ specular += outSpecular;
}
#endif
@@ -174,8 +216,9 @@ surface_t getSurface() {
s.ambient = vec3(1.0);
#endif
s.diffuse = vec4(1.0);
- s.specular = vec4(1.0);
- s.shininess = m_Shininess;
+ s.specular = vec4(0.04, 0.04, 0.04, 1.0);
+ s.roughness = 0.1;
+ s.ndotv = max(0.0, dot(s.viewDir, s.normal));
return s;
}
@@ -186,9 +229,9 @@ void main() {
Lighting_ProcessAll(surface, ambient, diffuse, specular);
vec4 color = vec4(1.0);
- color.rgb = surface.ambient.rgb * ambient +
- surface.diffuse.rgb * diffuse +
- surface.specular.rgb * specular;
+ color.rgb = ambient * surface.ambient.rgb +
+ diffuse * surface.diffuse.rgb +
+ specular;
#ifdef DISCARD_ALPHA
if (color.a < m_AlphaDiscardThreshold) {
diff --git a/jme3-core/src/main/resources/Common/ShaderLib/InPassShadows.glsl b/jme3-core/src/main/resources/Common/ShaderLib/InPassShadows.glsl
index 9577927512..05e3955c34 100755
--- a/jme3-core/src/main/resources/Common/ShaderLib/InPassShadows.glsl
+++ b/jme3-core/src/main/resources/Common/ShaderLib/InPassShadows.glsl
@@ -39,17 +39,63 @@
#endif
}
- float Shadow_ProcessDirectional(int startProjIndex, float startArrayLayer) {
+ /**
+ * 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(int startProjIndex, float startArrayLayer) {
+ 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));
}
+
+ 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;
+ } else {
+ projCoord = vProjCoord[startProjIndex];
+ projCoord.xyz /= projCoord.w;
+ startProjIndex += 1;
+ }
+
+ return texture(g_ShadowMapArray, vec4(projCoord.xy, arraySlice, projCoord.z));
+ }
#endif
#elif NUM_PSSM_SPLITS > 0
@@ -121,4 +167,8 @@
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) {
+ return 1.0;
+ }
#endif
From c3cfab65c650eff51748949f296801d93d058d5d Mon Sep 17 00:00:00 2001
From: Kirill Vainer
Date: Sun, 17 Sep 2017 22:28:31 -0400
Subject: [PATCH 31/46] use 16-bit depth by default
---
.../java/com/jme3/shadow/next/PreShadowArrayRenderer.java | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/jme3-core/src/main/java/com/jme3/shadow/next/PreShadowArrayRenderer.java b/jme3-core/src/main/java/com/jme3/shadow/next/PreShadowArrayRenderer.java
index 78b9507fe5..1d2d11ae82 100755
--- a/jme3-core/src/main/java/com/jme3/shadow/next/PreShadowArrayRenderer.java
+++ b/jme3-core/src/main/java/com/jme3/shadow/next/PreShadowArrayRenderer.java
@@ -93,7 +93,7 @@ public PreShadowArrayRenderer() {
points[i] = new Vector3f();
}
- prePassRenderState.setFaceCullMode(RenderState.FaceCullMode.Front);
+ prePassRenderState.setFaceCullMode(RenderState.FaceCullMode.Back);
prePassRenderState.setColorWrite(false);
prePassRenderState.setDepthWrite(true);
prePassRenderState.setDepthTest(true);
@@ -134,7 +134,7 @@ public void setTextureSize(int textureSize) {
public void addLight(Light light) {
if (array.getImage() == null) {
array.setImage(new Image(
- Format.Depth32F,
+ Format.Depth16,
textureSize,
textureSize,
0,
From 0fae3839d3d9f8a6120debdb8c5084895a1ad594 Mon Sep 17 00:00:00 2001
From: Kirill Vainer
Date: Sun, 17 Sep 2017 22:33:13 -0400
Subject: [PATCH 32/46] remove unused methods
---
.../java/com/jme3/shadow/PssmShadowUtil.java | 11 ----
.../main/java/com/jme3/shadow/ShadowUtil.java | 61 +------------------
2 files changed, 2 insertions(+), 70 deletions(-)
diff --git a/jme3-core/src/main/java/com/jme3/shadow/PssmShadowUtil.java b/jme3-core/src/main/java/com/jme3/shadow/PssmShadowUtil.java
index 888dc2fa81..64b36379b9 100644
--- a/jme3-core/src/main/java/com/jme3/shadow/PssmShadowUtil.java
+++ b/jme3-core/src/main/java/com/jme3/shadow/PssmShadowUtil.java
@@ -67,15 +67,4 @@ public static void updateFrustumSplits(float[] splits, float near, float far, fl
splits[0] = near;
splits[splits.length - 1] = far;
}
-
- /**
- * Compute the Zfar in the model vieuw to adjust the Zfar distance for the splits calculation
- */
- public static float computeZFar(GeometryList occ, GeometryList recv, Camera cam) {
- Matrix4f mat = cam.getViewMatrix();
- BoundingBox bbOcc = ShadowUtil.computeUnionBound(occ, mat);
- BoundingBox bbRecv = ShadowUtil.computeUnionBound(recv, mat);
-
- return min(max(bbOcc.getZExtent() - bbOcc.getCenter().z, bbRecv.getZExtent() - bbRecv.getCenter().z), cam.getFrustumFar());
- }
}
diff --git a/jme3-core/src/main/java/com/jme3/shadow/ShadowUtil.java b/jme3-core/src/main/java/com/jme3/shadow/ShadowUtil.java
index 7b08f04f50..5bac37b907 100644
--- a/jme3-core/src/main/java/com/jme3/shadow/ShadowUtil.java
+++ b/jme3-core/src/main/java/com/jme3/shadow/ShadowUtil.java
@@ -253,65 +253,8 @@ public static BoundingBox computeBoundForPoints(Vector3f[] pts, Matrix4f mat) {
max.maxLocal(temp);
}
vars.release();
- Vector3f center = min.add(max).multLocal(0.5f);
- Vector3f extent = max.subtract(min).multLocal(0.5f);
- //Nehon 08/18/2010 : Added an offset to the extend to avoid banding artifacts when the frustum are aligned
- return new BoundingBox(center, extent.x + 2.0f, extent.y + 2.0f, extent.z + 2.5f);
- }
-
- /**
- * Updates the shadow camera to properly contain the given points (which
- * contain the eye camera frustum corners)
- *
- * @param shadowCam
- * @param points
- */
- public static void updateShadowCamera(Camera shadowCam, Vector3f[] points) {
- boolean ortho = shadowCam.isParallelProjection();
- shadowCam.setProjectionMatrix(null);
-
- if (ortho) {
- shadowCam.setFrustum(-1, 1, -1, 1, 1, -1);
- } else {
- shadowCam.setFrustumPerspective(45, 1, 1, 150);
- }
-
- Matrix4f viewProjMatrix = shadowCam.getViewProjectionMatrix();
- Matrix4f projMatrix = shadowCam.getProjectionMatrix();
-
- BoundingBox splitBB = computeBoundForPoints(points, viewProjMatrix);
-
- TempVars vars = TempVars.get();
-
- Vector3f splitMin = splitBB.getMin(vars.vect1);
- Vector3f splitMax = splitBB.getMax(vars.vect2);
-
-// splitMin.z = 0;
-
- // Create the crop matrix.
- float scaleX, scaleY, scaleZ;
- float offsetX, offsetY, offsetZ;
-
- scaleX = 2.0f / (splitMax.x - splitMin.x);
- scaleY = 2.0f / (splitMax.y - splitMin.y);
- offsetX = -0.5f * (splitMax.x + splitMin.x) * scaleX;
- offsetY = -0.5f * (splitMax.y + splitMin.y) * scaleY;
- scaleZ = 1.0f / (splitMax.z - splitMin.z);
- offsetZ = -splitMin.z * scaleZ;
-
- Matrix4f cropMatrix = vars.tempMat4;
- cropMatrix.set(scaleX, 0f, 0f, offsetX,
- 0f, scaleY, 0f, offsetY,
- 0f, 0f, scaleZ, offsetZ,
- 0f, 0f, 0f, 1f);
-
-
- Matrix4f result = new Matrix4f();
- result.set(cropMatrix);
- result.multLocal(projMatrix);
-
- vars.release();
- shadowCam.setProjectionMatrix(result);
+
+ return new BoundingBox(min, max);
}
/**
From 4b4bf24127f6991aec2c17ce72d738581d5c7f02 Mon Sep 17 00:00:00 2001
From: Kirill Vainer
Date: Sun, 17 Sep 2017 22:34:06 -0400
Subject: [PATCH 33/46] fix shadow disappearing when frustum in front of caster
---
.../main/java/com/jme3/shadow/ShadowUtil.java | 115 +++++++++---------
1 file changed, 58 insertions(+), 57 deletions(-)
diff --git a/jme3-core/src/main/java/com/jme3/shadow/ShadowUtil.java b/jme3-core/src/main/java/com/jme3/shadow/ShadowUtil.java
index 5bac37b907..8c6b1ab910 100644
--- a/jme3-core/src/main/java/com/jme3/shadow/ShadowUtil.java
+++ b/jme3-core/src/main/java/com/jme3/shadow/ShadowUtil.java
@@ -32,7 +32,9 @@
package com.jme3.shadow;
import com.jme3.bounding.BoundingBox;
+import com.jme3.bounding.BoundingSphere;
import com.jme3.bounding.BoundingVolume;
+import com.jme3.collision.UnsupportedCollisionException;
import com.jme3.math.FastMath;
import com.jme3.math.Matrix4f;
import com.jme3.math.Transform;
@@ -42,6 +44,7 @@
import com.jme3.renderer.ViewPort;
import com.jme3.renderer.queue.GeometryList;
import com.jme3.renderer.queue.RenderQueue;
+import com.jme3.renderer.queue.RenderQueue.ShadowMode;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
@@ -295,46 +298,64 @@ public int addOccluders(Spatial scene) {
return casterCount;
}
+ private boolean intersectsIgnoreNearZ(BoundingBox splitBB, BoundingSphere occSphere) {
+ float distSqr = occSphere.getRadius() * occSphere.getRadius();
+
+ float minX = splitBB.getCenter().x - splitBB.getXExtent();
+ float maxX = splitBB.getCenter().x + splitBB.getXExtent();
+
+ float minY = splitBB.getCenter().y - splitBB.getYExtent();
+ float maxY = splitBB.getCenter().y + splitBB.getYExtent();
+
+ float maxZ = splitBB.getCenter().z + splitBB.getZExtent();
+
+ if (occSphere.getCenter().x < minX) distSqr -= FastMath.sqr(occSphere.getCenter().x - minX);
+ else if (occSphere.getCenter().x > maxX) distSqr -= FastMath.sqr(occSphere.getCenter().x - maxX);
+
+ if (occSphere.getCenter().y < minY) distSqr -= FastMath.sqr(occSphere.getCenter().y - minY);
+ else if (occSphere.getCenter().y > maxY) distSqr -= FastMath.sqr(occSphere.getCenter().y - maxY);
+
+ if (occSphere.getCenter().z > maxZ) distSqr -= FastMath.sqr(occSphere.getCenter().z - maxZ);
+
+ return distSqr > 0;
+ }
+
+ private boolean intersectsIgnoreNearZ(BoundingBox splitBB, BoundingBox occBB) {
+ if (splitBB.getCenter().x + splitBB.getXExtent() < occBB.getCenter().x - occBB.getXExtent()
+ || splitBB.getCenter().x - splitBB.getXExtent() > occBB.getCenter().x + occBB.getXExtent()) {
+ return false;
+ } else if (splitBB.getCenter().y + splitBB.getYExtent() < occBB.getCenter().y - occBB.getYExtent()
+ || splitBB.getCenter().y - splitBB.getYExtent() > occBB.getCenter().y + occBB.getYExtent()) {
+ return false;
+ } else if (splitBB.getCenter().z + splitBB.getZExtent() < occBB.getCenter().z - occBB.getZExtent()) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ private boolean intersectsIgnoreNearZ(BoundingBox splitBB, BoundingVolume occBV) {
+ if (occBV instanceof BoundingBox) {
+ return intersectsIgnoreNearZ(splitBB, (BoundingBox) occBV);
+ } else if (occBV instanceof BoundingSphere) {
+ return intersectsIgnoreNearZ(splitBB, (BoundingSphere) occBV);
+ } else {
+ throw new UnsupportedCollisionException("With: " + occBV.getClass().getSimpleName());
+ }
+ }
+
private void process(Spatial scene) {
if (scene.getCullHint() == Spatial.CullHint.Always) return;
- RenderQueue.ShadowMode shadowMode = scene.getShadowMode();
- if ( scene instanceof Geometry )
- {
+ if (scene instanceof Geometry) {
// convert bounding box to light's viewproj space
- Geometry occluder = (Geometry)scene;
- if (shadowMode != RenderQueue.ShadowMode.Off && shadowMode != RenderQueue.ShadowMode.Receive
- && !occluder.isGrouped() && occluder.getWorldBound()!=null) {
+ Geometry occluder = (Geometry) scene;
+ ShadowMode shadowMode = scene.getShadowMode();
+ if (shadowMode != ShadowMode.Off && shadowMode != ShadowMode.Receive
+ && !occluder.isGrouped()) {
BoundingVolume bv = occluder.getWorldBound();
BoundingVolume occBox = bv.transform(viewProjMatrix, vars.bbox);
-
- boolean intersects = splitBB.intersects(occBox);
- if (!intersects && occBox instanceof BoundingBox) {
- BoundingBox occBB = (BoundingBox) occBox;
- //Kirill 01/10/2011
- // Extend the occluder further into the frustum
- // This fixes shadow dissapearing issues when
- // the caster itself is not in the view camera
- // but its shadow is in the camera
- // The number is in world units
- occBB.setZExtent(occBB.getZExtent() + 50);
- occBB.setCenter(occBB.getCenter().addLocal(0, 0, 25));
- if (splitBB.intersects(occBB)) {
- //Nehon : prevent NaN and infinity values to screw the final bounding box
- if (!Float.isNaN(occBox.getCenter().x) && !Float.isInfinite(occBox.getCenter().x)) {
- // To prevent extending the depth range too much
- // We return the bound to its former shape
- // Before adding it
- occBB.setZExtent(occBB.getZExtent() - 50);
- occBB.setCenter(occBB.getCenter().subtractLocal(0, 0, 25));
- casterBB.mergeLocal(occBox);
- casterCount++;
- }
- if (splitOccluders != null) {
- splitOccluders.add(occluder);
- }
- }
- } else if (intersects) {
+ if (intersectsIgnoreNearZ(splitBB, occBox)) {
casterBB.mergeLocal(occBox);
casterCount++;
if (splitOccluders != null) {
@@ -342,30 +363,10 @@ private void process(Spatial scene) {
}
}
}
- }
- else if ( scene instanceof Node && ((Node)scene).getWorldBound()!=null )
- {
- Node nodeOcc = (Node)scene;
- boolean intersects = false;
- // some
- BoundingVolume bv = nodeOcc.getWorldBound();
+ } else if (scene instanceof Node) {
+ BoundingVolume bv = scene.getWorldBound();
BoundingVolume occBox = bv.transform(viewProjMatrix, vars.bbox);
-
- intersects = splitBB.intersects(occBox);
- if (!intersects && occBox instanceof BoundingBox) {
- BoundingBox occBB = (BoundingBox) occBox;
- //Kirill 01/10/2011
- // Extend the occluder further into the frustum
- // This fixes shadow dissapearing issues when
- // the caster itself is not in the view camera
- // but its shadow is in the camera
- // The number is in world units
- occBB.setZExtent(occBB.getZExtent() + 50);
- occBB.setCenter(occBB.getCenter().addLocal(0, 0, 25));
- intersects = splitBB.intersects(occBB);
- }
-
- if ( intersects ) {
+ if (intersectsIgnoreNearZ(splitBB, occBox)) {
for (Spatial child : ((Node)scene).getChildren()) {
process(child);
}
From 628fa23059e45f3ea2b45b314476304a120ed271 Mon Sep 17 00:00:00 2001
From: Kirill Vainer
Date: Sat, 30 Sep 2017 17:53:45 -0400
Subject: [PATCH 34/46] remove useless normalization in lighting shaders
---
.../src/main/resources/Common/MatDefs/Light/Lighting.frag | 2 +-
.../src/main/resources/Common/MatDefs/Light/Lighting.vert | 2 +-
.../main/resources/Common/MatDefs/Light/PBRLighting.frag | 3 +--
.../src/main/resources/Common/MatDefs/Light/SPLighting.frag | 2 +-
.../src/main/resources/Common/MatDefs/Light/SPLighting.vert | 2 +-
.../src/main/resources/Common/ShaderLib/Lighting.glsllib | 6 +++---
6 files changed, 8 insertions(+), 9 deletions(-)
diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.frag b/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.frag
index 9b8aa27097..17db8f7b10 100644
--- a/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.frag
+++ b/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.frag
@@ -173,7 +173,7 @@ void main(){
// allow use of control flow
if(g_LightDirection.w != 0.0){
#endif
- spotFallOff = computeSpotFalloff(g_LightDirection, lightVec);
+ spotFallOff = computeSpotFalloff(g_LightDirection, lightDir.xyz);
#if __VERSION__ >= 110
if(spotFallOff <= 0.0){
gl_FragColor.rgb = AmbientSum * diffuseColor.rgb;
diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.vert b/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.vert
index 395bc1bcae..f2d4a3a899 100644
--- a/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.vert
+++ b/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.vert
@@ -158,7 +158,7 @@ void main(){
// allow use of control flow
if(lightColor.w > 1.0){
#endif
- spotFallOff = computeSpotFalloff(g_LightDirection, lightVec);
+ spotFallOff = computeSpotFalloff(g_LightDirection, vLightDir.xyz);
#if __VERSION__ >= 110
}
#endif
diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLighting.frag b/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLighting.frag
index 118ebbe198..3e130d415e 100644
--- a/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLighting.frag
+++ b/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLighting.frag
@@ -223,14 +223,13 @@ void main(){
// allow use of control flow
if(lightColor.w > 1.0){
#endif
- fallOff = computeSpotFalloff(g_LightData[i+2], lightVec);
+ fallOff = computeSpotFalloff(g_LightData[i+2], lightDir.xyz);
#if __VERSION__ >= 110
}
#endif
//point light attenuation
fallOff *= lightDir.w;
- lightDir.xyz = normalize(lightDir.xyz);
vec3 directDiffuse;
vec3 directSpecular;
diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/SPLighting.frag b/jme3-core/src/main/resources/Common/MatDefs/Light/SPLighting.frag
index a510fc1dbc..472b7c1283 100644
--- a/jme3-core/src/main/resources/Common/MatDefs/Light/SPLighting.frag
+++ b/jme3-core/src/main/resources/Common/MatDefs/Light/SPLighting.frag
@@ -188,7 +188,7 @@ void main(){
// allow use of control flow
if(lightColor.w > 1.0){
#endif
- spotFallOff = computeSpotFalloff(g_LightData[i+2], lightVec);
+ spotFallOff = computeSpotFalloff(g_LightData[i+2], lightDir.xyz);
#if __VERSION__ >= 110
}
#endif
diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/SPLighting.vert b/jme3-core/src/main/resources/Common/MatDefs/Light/SPLighting.vert
index 49cc5b96ee..c24ee7f19c 100644
--- a/jme3-core/src/main/resources/Common/MatDefs/Light/SPLighting.vert
+++ b/jme3-core/src/main/resources/Common/MatDefs/Light/SPLighting.vert
@@ -155,7 +155,7 @@ void main(){
if(lightColor.w > 1.0){
#endif
vec4 lightDirection = g_LightData[i+2];
- spotFallOff = computeSpotFalloff(lightDirection, lightVec);
+ spotFallOff = computeSpotFalloff(lightDirection, lightDir.xyz);
#if __VERSION__ >= 110
}
#endif
diff --git a/jme3-core/src/main/resources/Common/ShaderLib/Lighting.glsllib b/jme3-core/src/main/resources/Common/ShaderLib/Lighting.glsllib
index fb8f40524f..d75f4eb9c0 100644
--- a/jme3-core/src/main/resources/Common/ShaderLib/Lighting.glsllib
+++ b/jme3-core/src/main/resources/Common/ShaderLib/Lighting.glsllib
@@ -23,9 +23,9 @@ void lightComputeDir(in vec3 worldPos, in float lightType, in vec4 position, out
/*
* Computes the spot falloff for a spotlight
*/
-float computeSpotFalloff(in vec4 lightDirection, in vec3 lightVector){
- vec3 L=normalize(lightVector);
- vec3 spotdir = normalize(lightDirection.xyz);
+float computeSpotFalloff(in vec4 lightDirection, in vec3 lightVector) {
+ vec3 L = lightVector;
+ vec3 spotdir = lightDirection.xyz;
float curAngleCos = dot(-L, spotdir);
float innerAngleCos = floor(lightDirection.w) * 0.001;
float outerAngleCos = fract(lightDirection.w);
From fe158e7b31b673264de52853d35b5f2ef09cbdbb Mon Sep 17 00:00:00 2001
From: Kirill Vainer
Date: Sat, 30 Sep 2017 17:54:32 -0400
Subject: [PATCH 35/46] fix infinite recursive loop
---
jme3-core/src/main/java/com/jme3/renderer/opengl/GLDebugES.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLDebugES.java b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLDebugES.java
index 8746d57edc..27709bfec3 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLDebugES.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLDebugES.java
@@ -221,7 +221,7 @@ public void glGenTextures(IntBuffer textures) {
@Override
public void glGenQueries(int num, IntBuffer ids) {
- glGenQueries(num, ids);
+ gl.glGenQueries(num, ids);
checkError();
}
From e4536808ca208c46ef41e3df9e3dc2da524fa608 Mon Sep 17 00:00:00 2001
From: Kirill Vainer
Date: Sat, 30 Sep 2017 18:01:17 -0400
Subject: [PATCH 36/46] add point light mode for pre shadow techniques
---
.../shadow/next/PreShadowArrayRenderer.java | 8 +++++
.../Common/MatDefs/Light/Lighting.j3md | 7 ++++
.../Common/MatDefs/Light/PBRLighting.j3md | 7 ++++
.../Common/MatDefs/Misc/Particle.j3md | 7 ++++
.../Common/MatDefs/Misc/Unshaded.j3md | 7 ++++
.../Common/MatDefs/Shadow/PreShadow.j3md | 13 ++++++++
.../Common/MatDefs/Shadow/PreShadow.vert | 32 +++++++++++++++----
7 files changed, 75 insertions(+), 6 deletions(-)
diff --git a/jme3-core/src/main/java/com/jme3/shadow/next/PreShadowArrayRenderer.java b/jme3-core/src/main/java/com/jme3/shadow/next/PreShadowArrayRenderer.java
index 1d2d11ae82..07cc74eed1 100755
--- a/jme3-core/src/main/java/com/jme3/shadow/next/PreShadowArrayRenderer.java
+++ b/jme3-core/src/main/java/com/jme3/shadow/next/PreShadowArrayRenderer.java
@@ -34,8 +34,10 @@
import com.jme3.shadow.next.pssm.DirectionalShadowParameters;
import com.jme3.light.DirectionalLight;
import com.jme3.light.Light;
+import com.jme3.light.Light.Type;
import com.jme3.light.PointLight;
import com.jme3.light.SpotLight;
+import com.jme3.material.MatParamOverride;
import com.jme3.material.RenderState;
import com.jme3.math.Vector3f;
import com.jme3.post.SceneProcessor;
@@ -46,6 +48,7 @@
import com.jme3.renderer.queue.GeometryList;
import com.jme3.renderer.queue.OpaqueComparator;
import com.jme3.renderer.queue.RenderQueue;
+import com.jme3.shader.VarType;
import com.jme3.shadow.next.array.DirectionalArrayShadowMap;
import com.jme3.shadow.next.array.PointArrayShadowMap;
import com.jme3.shadow.next.array.SpotArrayShadowMap;
@@ -80,6 +83,7 @@ public class PreShadowArrayRenderer implements SceneProcessor {
private final GeometryList shadowCasters = new GeometryList(new OpaqueComparator());
private final ListMap shadowedLights = new ListMap<>();
private final RenderState prePassRenderState = RenderState.ADDITIONAL.clone();
+ private final MatParamOverride pointLightOverride = new MatParamOverride(VarType.Boolean, "IsPointLight", true);
private final TextureArray array = new TextureArray();
private int textureSize = 1024;
@@ -190,6 +194,7 @@ public void preFrame(float tpf) {
private void renderShadowMaps(ViewPort viewPort) {
renderManager.setForcedRenderState(prePassRenderState);
renderManager.setForcedTechnique(PRE_SHADOW_TECHNIQUE_NAME);
+ renderManager.addForcedMatParam(pointLightOverride);
for (int i = 0; i < shadowedLights.size(); i++) {
Light light = shadowedLights.getKey(i);
@@ -206,6 +211,8 @@ private void renderShadowMaps(ViewPort viewPort) {
vars.release();
}
+ pointLightOverride.setEnabled(shadowMap.getLightType() == Type.Point);
+
switch (shadowMap.getLightType()) {
case Directional:
DirectionalArrayShadowMap directionalShadow = (DirectionalArrayShadowMap) shadowMap;
@@ -228,6 +235,7 @@ private void renderShadowMaps(ViewPort viewPort) {
Renderer renderer = renderManager.getRenderer();
renderer.setFrameBuffer(viewPort.getOutputFrameBuffer());
+ renderManager.removeForcedMatParam(pointLightOverride);
renderManager.setForcedRenderState(null);
renderManager.setForcedTechnique(null);
renderManager.setCamera(viewPort.getCamera(), false);
diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.j3md b/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.j3md
index cdd1bdcff4..9aac24591e 100644
--- a/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.j3md
+++ b/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.j3md
@@ -118,6 +118,9 @@ MaterialDef Phong Lighting {
Boolean UseInstancing
Boolean BackfaceShadows : false
+
+ // PreShadow: use point light mode for depth
+ Boolean IsPointLight
}
Technique {
@@ -228,12 +231,16 @@ MaterialDef Phong Lighting {
WorldViewMatrix
ViewProjectionMatrix
ViewMatrix
+ WorldMatrix
+ CameraPosition
+ FrustumNearFar
}
Defines {
DISCARD_ALPHA : AlphaDiscardThreshold
NUM_BONES : NumberOfBones
INSTANCING : UseInstancing
+ POINT_LIGHT : IsPointLight
}
ForcedRenderState {
diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLighting.j3md b/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLighting.j3md
index 61edf8e0dc..59d24acfc6 100644
--- a/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLighting.j3md
+++ b/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLighting.j3md
@@ -118,6 +118,9 @@ MaterialDef PBR Lighting {
Boolean UseVertexColor
Boolean BackfaceShadows : false
+
+ // PreShadow: use point light mode for depth
+ Boolean IsPointLight
}
Technique {
@@ -171,12 +174,16 @@ MaterialDef PBR Lighting {
WorldViewMatrix
ViewProjectionMatrix
ViewMatrix
+ WorldMatrix
+ CameraPosition
+ FrustumNearFar
}
Defines {
DISCARD_ALPHA : AlphaDiscardThreshold
NUM_BONES : NumberOfBones
INSTANCING : UseInstancing
+ POINT_LIGHT : IsPointLight
}
ForcedRenderState {
diff --git a/jme3-core/src/main/resources/Common/MatDefs/Misc/Particle.j3md b/jme3-core/src/main/resources/Common/MatDefs/Misc/Particle.j3md
index 504062ffaa..f51825aef5 100644
--- a/jme3-core/src/main/resources/Common/MatDefs/Misc/Particle.j3md
+++ b/jme3-core/src/main/resources/Common/MatDefs/Misc/Particle.j3md
@@ -14,6 +14,9 @@ MaterialDef Point Sprite {
Texture2D GlowMap
// The glow color of the object
Color GlowColor
+
+ // PreShadow: use point light mode for depth
+ Boolean IsPointLight
}
Technique {
@@ -56,10 +59,14 @@ MaterialDef Point Sprite {
WorldViewMatrix
ViewProjectionMatrix
ViewMatrix
+ WorldMatrix
+ CameraPosition
+ FrustumNearFar
}
Defines {
COLOR_MAP : Texture
+ POINT_LIGHT : IsPointLight
}
ForcedRenderState {
diff --git a/jme3-core/src/main/resources/Common/MatDefs/Misc/Unshaded.j3md b/jme3-core/src/main/resources/Common/MatDefs/Misc/Unshaded.j3md
index 826a44e45b..a194c15d70 100644
--- a/jme3-core/src/main/resources/Common/MatDefs/Misc/Unshaded.j3md
+++ b/jme3-core/src/main/resources/Common/MatDefs/Misc/Unshaded.j3md
@@ -54,6 +54,9 @@ MaterialDef Unshaded {
Float ShadowMapSize
Boolean BackfaceShadows: true
+
+ // PreShadow: use point light mode for depth
+ Boolean IsPointLight
}
Technique {
@@ -108,6 +111,9 @@ MaterialDef Unshaded {
WorldViewMatrix
ViewProjectionMatrix
ViewMatrix
+ WorldMatrix
+ CameraPosition
+ FrustumNearFar
}
Defines {
@@ -115,6 +121,7 @@ MaterialDef Unshaded {
DISCARD_ALPHA : AlphaDiscardThreshold
NUM_BONES : NumberOfBones
INSTANCING : UseInstancing
+ POINT_LIGHT : IsPointLight
}
ForcedRenderState {
diff --git a/jme3-core/src/main/resources/Common/MatDefs/Shadow/PreShadow.j3md b/jme3-core/src/main/resources/Common/MatDefs/Shadow/PreShadow.j3md
index a76b36310b..629eb165b2 100644
--- a/jme3-core/src/main/resources/Common/MatDefs/Shadow/PreShadow.j3md
+++ b/jme3-core/src/main/resources/Common/MatDefs/Shadow/PreShadow.j3md
@@ -1,11 +1,24 @@
MaterialDef Pre Shadow {
+
+ MaterialParameters {
+ // PreShadow: use point light mode for depth
+ Boolean IsPointLight
+ }
+
Technique {
VertexShader GLSL100 GLSL150 : Common/MatDefs/Shadow/PreShadow.vert
FragmentShader GLSL100 GLSL150 : Common/MatDefs/Shadow/PreShadow.frag
+ Defines {
+ POINT_LIGHT : IsPointLight
+ }
+
WorldParameters {
WorldViewProjectionMatrix
WorldViewMatrix
+ WorldMatrix
+ CameraPosition
+ FrustumNearFar
}
RenderState {
diff --git a/jme3-core/src/main/resources/Common/MatDefs/Shadow/PreShadow.vert b/jme3-core/src/main/resources/Common/MatDefs/Shadow/PreShadow.vert
index 4e3023d7f9..f8ca36fae3 100644
--- a/jme3-core/src/main/resources/Common/MatDefs/Shadow/PreShadow.vert
+++ b/jme3-core/src/main/resources/Common/MatDefs/Shadow/PreShadow.vert
@@ -2,16 +2,36 @@
#import "Common/ShaderLib/Instancing.glsllib"
#import "Common/ShaderLib/Skinning.glsllib"
attribute vec3 inPosition;
+#ifdef DISCARD_ALPHA
attribute vec2 inTexCoord;
-
varying vec2 texCoord;
+#endif
+
+#ifdef POINT_LIGHT
+uniform vec3 g_CameraPosition;
+uniform vec2 g_FrustumNearFar;
+#endif
-void main(){
+void main() {
vec4 modelSpacePos = vec4(inPosition, 1.0);
- #ifdef NUM_BONES
- Skinning_Compute(modelSpacePos);
- #endif
+ #ifdef NUM_BONES
+ Skinning_Compute(modelSpacePos);
+ #endif
+
+ #ifdef DISCARD_ALPHA
+ texCoord = inTexCoord;
+ #endif
+
gl_Position = TransformWorldViewProjection(modelSpacePos);
- texCoord = inTexCoord;
+
+ #ifdef POINT_LIGHT
+ 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;
+
+ // 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;
+ #endif
}
\ No newline at end of file
From 6487def9d3bdc39c980e9d1085b5c7ccc8d49c73 Mon Sep 17 00:00:00 2001
From: Kirill Vainer
Date: Sat, 30 Sep 2017 18:08:21 -0400
Subject: [PATCH 37/46] update GLTracer
---
jme3-core/src/main/java/com/jme3/renderer/opengl/GLTracer.java | 2 ++
1 file changed, 2 insertions(+)
diff --git a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLTracer.java b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLTracer.java
index ae3f17a8ca..33b0bef51b 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLTracer.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLTracer.java
@@ -90,6 +90,7 @@ private static void noEnumArgs(String method, int... argSlots) {
noEnumArgs("glTexImage3D", 1, 3, 4, 5, 6);
noEnumArgs("glTexSubImage2D", 1, 2, 3, 4, 5);
noEnumArgs("glTexSubImage3D", 1, 2, 3, 4, 5, 6, 7);
+ noEnumArgs("glTexImage2DMultisample", 1, 3, 4);
noEnumArgs("glCompressedTexImage2D", 1, 3, 4, 5);
noEnumArgs("glCompressedTexSubImage3D", 1, 2, 3, 4, 5, 6, 7);
noEnumArgs("glDeleteTextures", 0);
@@ -101,6 +102,7 @@ private static void noEnumArgs(String method, int... argSlots) {
noEnumArgs("glVertexAttribPointer", 0, 1, 4, 5);
noEnumArgs("glVertexAttribDivisorARB", 0, 1);
noEnumArgs("glDrawRangeElements", 1, 2, 3, 5);
+ noEnumArgs("glDrawElementsInstancedARB", 1, 3, 4);
noEnumArgs("glDrawArrays", 1, 2);
noEnumArgs("glDeleteBuffers", 0);
noEnumArgs("glBindVertexArray", 0);
From 42432ed4ea335a31d55cb1dce6953e7ea6db604c Mon Sep 17 00:00:00 2001
From: Kirill Vainer
Date: Sat, 30 Sep 2017 18:15:30 -0400
Subject: [PATCH 38/46] remove hacks from ShadowUtil
---
.../main/java/com/jme3/shadow/ShadowUtil.java | 82 ++++++++-----------
1 file changed, 36 insertions(+), 46 deletions(-)
diff --git a/jme3-core/src/main/java/com/jme3/shadow/ShadowUtil.java b/jme3-core/src/main/java/com/jme3/shadow/ShadowUtil.java
index 8c6b1ab910..89081670d9 100644
--- a/jme3-core/src/main/java/com/jme3/shadow/ShadowUtil.java
+++ b/jme3-core/src/main/java/com/jme3/shadow/ShadowUtil.java
@@ -271,7 +271,6 @@ public static class OccludersExtractor
{
// global variables set in order not to have recursive process method with too many parameters
Matrix4f viewProjMatrix;
- public Integer casterCount;
BoundingBox splitBB, casterBB;
GeometryList splitOccluders;
TempVars vars;
@@ -279,9 +278,8 @@ public static class OccludersExtractor
public OccludersExtractor() {}
// initialize the global OccludersExtractor variables
- public OccludersExtractor(Matrix4f vpm, int cc, BoundingBox sBB, BoundingBox cBB, GeometryList sOCC, TempVars v) {
- viewProjMatrix = vpm;
- casterCount = cc;
+ public OccludersExtractor(Matrix4f vpm, BoundingBox sBB, BoundingBox cBB, GeometryList sOCC, TempVars v) {
+ viewProjMatrix = vpm;
splitBB = sBB;
casterBB = cBB;
splitOccluders = sOCC;
@@ -293,9 +291,8 @@ public OccludersExtractor(Matrix4f vpm, int cc, BoundingBox sBB, BoundingBox cBB
* The global OccludersExtractor variables need to be initialized first.
* Variables are updated and used in {@link ShadowUtil#updateShadowCamera} at last.
*/
- public int addOccluders(Spatial scene) {
+ public void addOccluders(Spatial scene) {
if ( scene != null ) process(scene);
- return casterCount;
}
private boolean intersectsIgnoreNearZ(BoundingBox splitBB, BoundingSphere occSphere) {
@@ -357,7 +354,6 @@ private void process(Spatial scene) {
BoundingVolume occBox = bv.transform(viewProjMatrix, vars.bbox);
if (intersectsIgnoreNearZ(splitBB, occBox)) {
casterBB.mergeLocal(occBox);
- casterCount++;
if (splitOccluders != null) {
splitOccluders.add(occluder);
}
@@ -384,7 +380,7 @@ public static void updateShadowCamera(ViewPort viewPort,
GeometryList receivers,
Camera shadowCam,
Vector3f[] points,
- GeometryList splitOccluders,
+ GeometryList shadowCasters,
float shadowMapSize) {
boolean ortho = shadowCam.isParallelProjection();
@@ -392,7 +388,7 @@ public static void updateShadowCamera(ViewPort viewPort,
shadowCam.setProjectionMatrix(null);
if (ortho) {
- shadowCam.setFrustum(-shadowCam.getFrustumFar(), shadowCam.getFrustumFar(), -1, 1, 1, -1);
+ shadowCam.setFrustum(-1, 1, -1, 1, 1, -1);
}
// create transform to rotate points to viewspace
@@ -405,36 +401,31 @@ public static void updateShadowCamera(ViewPort viewPort,
BoundingBox casterBB = new BoundingBox();
BoundingBox receiverBB = new BoundingBox();
- int casterCount = 0, receiverCount = 0;
-
- for (int i = 0; i < receivers.size(); i++) {
- // convert bounding box to light's viewproj space
- Geometry receiver = receivers.get(i);
- BoundingVolume bv = receiver.getWorldBound();
- BoundingVolume recvBox = bv.transform(viewProjMatrix, vars.bbox);
-
- if (splitBB.intersects(recvBox)) {
- //Nehon : prevent NaN and infinity values to screw the final bounding box
- if (!Float.isNaN(recvBox.getCenter().x) && !Float.isInfinite(recvBox.getCenter().x)) {
- receiverBB.mergeLocal(recvBox);
- receiverCount++;
+ if (receivers != null && receivers.size() != 0) {
+ for (int i = 0; i < receivers.size(); i++) {
+ // convert bounding box to light's viewproj space
+ Geometry receiver = receivers.get(i);
+ BoundingVolume bv = receiver.getWorldBound();
+ BoundingVolume recvBox = bv.transform(viewProjMatrix, vars.bbox);
+
+ if (splitBB.intersects(recvBox)) {
+ //Nehon : prevent NaN and infinity values to screw the final bounding box
+ if (!Float.isNaN(recvBox.getCenter().x) && !Float.isInfinite(recvBox.getCenter().x)) {
+ receiverBB.mergeLocal(recvBox);
+ }
}
}
+ } else {
+ receiverBB.setXExtent(Float.POSITIVE_INFINITY);
+ receiverBB.setYExtent(Float.POSITIVE_INFINITY);
+ receiverBB.setZExtent(Float.POSITIVE_INFINITY);
}
// collect splitOccluders through scene recursive traverse
- OccludersExtractor occExt = new OccludersExtractor(viewProjMatrix, casterCount, splitBB, casterBB, splitOccluders, vars);
+ OccludersExtractor occExt = new OccludersExtractor(viewProjMatrix, splitBB, casterBB, shadowCasters, vars);
for (Spatial scene : viewPort.getScenes()) {
occExt.addOccluders(scene);
}
- casterCount = occExt.casterCount;
-
- //Nehon 08/18/2010 this is to avoid shadow bleeding when the ground is set to only receive shadows
- if (casterCount != receiverCount) {
- casterBB.setXExtent(casterBB.getXExtent() + 2.0f);
- casterBB.setYExtent(casterBB.getYExtent() + 2.0f);
- casterBB.setZExtent(casterBB.getZExtent() + 2.0f);
- }
Vector3f casterMin = casterBB.getMin(vars.vect1);
Vector3f casterMax = casterBB.getMax(vars.vect2);
@@ -445,27 +436,26 @@ public static void updateShadowCamera(ViewPort viewPort,
Vector3f splitMin = splitBB.getMin(vars.vect5);
Vector3f splitMax = splitBB.getMax(vars.vect6);
- splitMin.z = 0;
-
-// if (!ortho) {
-// shadowCam.setFrustumPerspective(45, 1, 1, splitMax.z);
-// }
Matrix4f projMatrix = shadowCam.getProjectionMatrix();
Vector3f cropMin = vars.vect7;
Vector3f cropMax = vars.vect8;
- // IMPORTANT: Special handling for Z values
- cropMin.x = max(max(casterMin.x, receiverMin.x), splitMin.x);
- cropMax.x = min(min(casterMax.x, receiverMax.x), splitMax.x);
-
- cropMin.y = max(max(casterMin.y, receiverMin.y), splitMin.y);
- cropMax.y = min(min(casterMax.y, receiverMax.y), splitMax.y);
-
- cropMin.z = min(casterMin.z, splitMin.z);
- cropMax.z = min(receiverMax.z, splitMax.z);
-
+ if (shadowCasters.size() > 0) {
+ // IMPORTANT: Special handling for Z values
+ cropMin.x = max(max(casterMin.x, receiverMin.x), splitMin.x);
+ cropMax.x = min(min(casterMax.x, receiverMax.x), splitMax.x);
+ cropMin.y = max(max(casterMin.y, receiverMin.y), splitMin.y);
+ cropMax.y = min(min(casterMax.y, receiverMax.y), splitMax.y);
+ cropMin.z = min(casterMin.z, splitMin.z);
+ cropMax.z = min(receiverMax.z, splitMax.z);
+ } else {
+ // Set crop = split so that everything in the scene has a depth < 1.0 in light space.
+ // This avoids shadowing everything when there are no casters.
+ cropMin.set(splitMin);
+ cropMax.set(splitMax);
+ }
// Create the crop matrix.
float scaleX, scaleY, scaleZ;
From caad16626e12babfc6ebc7da489f72d5d75cd2ba Mon Sep 17 00:00:00 2001
From: Kirill Vainer
Date: Mon, 19 Mar 2018 14:46:54 -0400
Subject: [PATCH 39/46] in-pass-shadows: add spot / point light support
---
.../logic/DefaultTechniqueDefLogic.java | 23 ++
.../logic/ShadowStaticPassLightingLogic.java | 9 -
.../SinglePassAndImageBasedLightingLogic.java | 240 ++++++++++--------
.../logic/SinglePassLightingLogic.java | 2 +-
.../logic/StaticPassLightingLogic.java | 43 ++--
.../shadow/next/PreShadowArrayRenderer.java | 14 +-
.../jme3/shadow/next/PreShadowRenderer.java | 183 +++++++++++++
.../jme3/shadow/next/ShadowDebugControl.java | 99 ++++++++
.../next/array/BaseArrayShadowMapSlice.java | 1 +
.../next/array/PointArrayShadowMapSlice.java | 2 +-
.../next/array/SpotArrayShadowMapSlice.java | 12 +-
.../shadow/next/pssm/BaseShadowMapSlice.java | 87 +++++++
.../next/pssm/DirectionalShadowMap.java | 92 +++++++
.../next/pssm/DirectionalShadowMapSlice.java | 67 +++++
.../Common/MatDefs/Light/PBRLighting.frag | 25 +-
.../Common/MatDefs/Light/PBRLighting.vert | 7 +-
.../Common/MatDefs/Light/StaticLighting.frag | 121 +++------
.../Common/MatDefs/Shadow/PreShadow.vert | 2 +-
.../MatDefs/Shadow/ShowShadowArray.frag | 15 ++
.../MatDefs/Shadow/ShowShadowArray.j3md | 17 ++
.../Common/ShaderLib/InPassShadows.glsl | 157 ++++++------
.../Common/ShaderLib/Lighting.glsllib | 4 +-
22 files changed, 909 insertions(+), 313 deletions(-)
create mode 100755 jme3-core/src/main/java/com/jme3/shadow/next/PreShadowRenderer.java
create mode 100644 jme3-core/src/main/java/com/jme3/shadow/next/ShadowDebugControl.java
create mode 100755 jme3-core/src/main/java/com/jme3/shadow/next/pssm/BaseShadowMapSlice.java
create mode 100755 jme3-core/src/main/java/com/jme3/shadow/next/pssm/DirectionalShadowMap.java
create mode 100755 jme3-core/src/main/java/com/jme3/shadow/next/pssm/DirectionalShadowMapSlice.java
create mode 100644 jme3-core/src/main/resources/Common/MatDefs/Shadow/ShowShadowArray.frag
create mode 100644 jme3-core/src/main/resources/Common/MatDefs/Shadow/ShowShadowArray.j3md
diff --git a/jme3-core/src/main/java/com/jme3/material/logic/DefaultTechniqueDefLogic.java b/jme3-core/src/main/java/com/jme3/material/logic/DefaultTechniqueDefLogic.java
index ad6a6f72e6..873029d993 100644
--- a/jme3-core/src/main/java/com/jme3/material/logic/DefaultTechniqueDefLogic.java
+++ b/jme3-core/src/main/java/com/jme3/material/logic/DefaultTechniqueDefLogic.java
@@ -43,6 +43,7 @@
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 @@ protected LightList getFilteredLightList(RenderManager renderManager, Geometry g
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);
diff --git a/jme3-core/src/main/java/com/jme3/material/logic/ShadowStaticPassLightingLogic.java b/jme3-core/src/main/java/com/jme3/material/logic/ShadowStaticPassLightingLogic.java
index c5c11c32d0..04bdc226f3 100755
--- a/jme3-core/src/main/java/com/jme3/material/logic/ShadowStaticPassLightingLogic.java
+++ b/jme3-core/src/main/java/com/jme3/material/logic/ShadowStaticPassLightingLogic.java
@@ -138,15 +138,6 @@ protected void makeCurrentBase(AssetManager assetManager, RenderManager renderMa
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;
diff --git a/jme3-core/src/main/java/com/jme3/material/logic/SinglePassAndImageBasedLightingLogic.java b/jme3-core/src/main/java/com/jme3/material/logic/SinglePassAndImageBasedLightingLogic.java
index 2a42a84403..23970f95f1 100644
--- a/jme3-core/src/main/java/com/jme3/material/logic/SinglePassAndImageBasedLightingLogic.java
+++ b/jme3-core/src/main/java/com/jme3/material/logic/SinglePassAndImageBasedLightingLogic.java
@@ -34,13 +34,19 @@
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 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 Shader makeCurrent(AssetManager assetManager, RenderManager renderManager
// 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() {
+ @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 @@ protected int updateLightListUniforms(Shader shader, Geometry g, LightList light
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 @@ protected int updateLightListUniforms(Shader shader, Geometry g, LightList light
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 void render(RenderManager renderManager, Shader shader, Geometry geometry
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;
- }
}
diff --git a/jme3-core/src/main/java/com/jme3/material/logic/SinglePassLightingLogic.java b/jme3-core/src/main/java/com/jme3/material/logic/SinglePassLightingLogic.java
index 469e7a73df..c901c8f81c 100644
--- a/jme3-core/src/main/java/com/jme3/material/logic/SinglePassLightingLogic.java
+++ b/jme3-core/src/main/java/com/jme3/material/logic/SinglePassLightingLogic.java
@@ -138,7 +138,7 @@ protected int updateLightListUniforms(Shader shader, Geometry g, LightList light
lightData.setVector4InArray(color.getRed(),
color.getGreen(),
color.getBlue(),
- l.getType().getId(),
+ encodeLightType(l),
lightDataIndex);
lightDataIndex++;
diff --git a/jme3-core/src/main/java/com/jme3/material/logic/StaticPassLightingLogic.java b/jme3-core/src/main/java/com/jme3/material/logic/StaticPassLightingLogic.java
index 630814e379..6ba92e10b0 100644
--- a/jme3-core/src/main/java/com/jme3/material/logic/StaticPassLightingLogic.java
+++ b/jme3-core/src/main/java/com/jme3/material/logic/StaticPassLightingLogic.java
@@ -126,10 +126,6 @@ public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager
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 @@ protected void updateLightListUniforms(Matrix4f viewMatrix, Shader shader) {
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) {
diff --git a/jme3-core/src/main/java/com/jme3/shadow/next/PreShadowArrayRenderer.java b/jme3-core/src/main/java/com/jme3/shadow/next/PreShadowArrayRenderer.java
index 07cc74eed1..06d3eca5d9 100755
--- a/jme3-core/src/main/java/com/jme3/shadow/next/PreShadowArrayRenderer.java
+++ b/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.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 PreShadowArrayRenderer() {
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 void setTextureSize(int textureSize) {
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,
diff --git a/jme3-core/src/main/java/com/jme3/shadow/next/PreShadowRenderer.java b/jme3-core/src/main/java/com/jme3/shadow/next/PreShadowRenderer.java
new file mode 100755
index 0000000000..ef05b1dcdb
--- /dev/null
+++ b/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.
+ *
+ * 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 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) {
+ }
+
+}
diff --git a/jme3-core/src/main/java/com/jme3/shadow/next/ShadowDebugControl.java b/jme3-core/src/main/java/com/jme3/shadow/next/ShadowDebugControl.java
new file mode 100644
index 0000000000..45db107d53
--- /dev/null
+++ b/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 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) {
+ }
+
+}
diff --git a/jme3-core/src/main/java/com/jme3/shadow/next/array/BaseArrayShadowMapSlice.java b/jme3-core/src/main/java/com/jme3/shadow/next/array/BaseArrayShadowMapSlice.java
index 7e22ad05bd..5cbd37396a 100755
--- a/jme3-core/src/main/java/com/jme3/shadow/next/array/BaseArrayShadowMapSlice.java
+++ b/jme3-core/src/main/java/com/jme3/shadow/next/array/BaseArrayShadowMapSlice.java
@@ -82,6 +82,7 @@ public void renderShadowMap(RenderManager renderManager, Light light, ViewPort v
if (fbNeedClear) {
renderer.setFrameBuffer(frameBuffer);
+ renderer.clearClipRect();
renderer.clearBuffers(false, true, false);
fbNeedClear = false;
}
diff --git a/jme3-core/src/main/java/com/jme3/shadow/next/array/PointArrayShadowMapSlice.java b/jme3-core/src/main/java/com/jme3/shadow/next/array/PointArrayShadowMapSlice.java
index 06b8f0a682..91d46fcd3d 100644
--- a/jme3-core/src/main/java/com/jme3/shadow/next/array/PointArrayShadowMapSlice.java
+++ b/jme3-core/src/main/java/com/jme3/shadow/next/array/PointArrayShadowMapSlice.java
@@ -51,7 +51,7 @@ public PointArrayShadowMapSlice(TextureArray array, int layer, int textureSize,
}
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);
diff --git a/jme3-core/src/main/java/com/jme3/shadow/next/array/SpotArrayShadowMapSlice.java b/jme3-core/src/main/java/com/jme3/shadow/next/array/SpotArrayShadowMapSlice.java
index d28d8230f5..eb93a2c3ab 100755
--- a/jme3-core/src/main/java/com/jme3/shadow/next/array/SpotArrayShadowMapSlice.java
+++ b/jme3-core/src/main/java/com/jme3/shadow/next/array/SpotArrayShadowMapSlice.java
@@ -49,10 +49,20 @@ public class SpotArrayShadowMapSlice extends BaseArrayShadowMapSlice
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);
diff --git a/jme3-core/src/main/java/com/jme3/shadow/next/pssm/BaseShadowMapSlice.java b/jme3-core/src/main/java/com/jme3/shadow/next/pssm/BaseShadowMapSlice.java
new file mode 100755
index 0000000000..e9b999fbed
--- /dev/null
+++ b/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 implements ShadowMapSlice {
+
+ 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();
+ }
+}
diff --git a/jme3-core/src/main/java/com/jme3/shadow/next/pssm/DirectionalShadowMap.java b/jme3-core/src/main/java/com/jme3/shadow/next/pssm/DirectionalShadowMap.java
new file mode 100755
index 0000000000..bc30b9affb
--- /dev/null
+++ b/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 {
+
+ 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;
+ }
+
+}
diff --git a/jme3-core/src/main/java/com/jme3/shadow/next/pssm/DirectionalShadowMapSlice.java b/jme3-core/src/main/java/com/jme3/shadow/next/pssm/DirectionalShadowMapSlice.java
new file mode 100755
index 0000000000..494dec1c24
--- /dev/null
+++ b/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 {
+
+ 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;
+ }
+}
diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLighting.frag b/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLighting.frag
index 0f5225f394..b6581888bc 100644
--- a/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLighting.frag
+++ b/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/
diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLighting.vert b/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLighting.vert
index 77782456ba..99c50564f7 100644
--- a/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLighting.vert
+++ b/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)
diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/StaticLighting.frag b/jme3-core/src/main/resources/Common/MatDefs/Light/StaticLighting.frag
index f0f76e70ce..7366a60d8f 100755
--- a/jme3-core/src/main/resources/Common/MatDefs/Light/StaticLighting.frag
+++ b/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
}
diff --git a/jme3-core/src/main/resources/Common/MatDefs/Shadow/PreShadow.vert b/jme3-core/src/main/resources/Common/MatDefs/Shadow/PreShadow.vert
index f8ca36fae3..c62d504881 100644
--- a/jme3-core/src/main/resources/Common/MatDefs/Shadow/PreShadow.vert
+++ b/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;
diff --git a/jme3-core/src/main/resources/Common/MatDefs/Shadow/ShowShadowArray.frag b/jme3-core/src/main/resources/Common/MatDefs/Shadow/ShowShadowArray.frag
new file mode 100644
index 0000000000..ad44a891db
--- /dev/null
+++ b/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;
+}
diff --git a/jme3-core/src/main/resources/Common/MatDefs/Shadow/ShowShadowArray.j3md b/jme3-core/src/main/resources/Common/MatDefs/Shadow/ShowShadowArray.j3md
new file mode 100644
index 0000000000..6c89f2043d
--- /dev/null
+++ b/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
+ }
+ }
+}
diff --git a/jme3-core/src/main/resources/Common/ShaderLib/InPassShadows.glsl b/jme3-core/src/main/resources/Common/ShaderLib/InPassShadows.glsl
index 05e3955c34..3cf681f84f 100755
--- a/jme3-core/src/main/resources/Common/ShaderLib/InPassShadows.glsl
+++ b/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
diff --git a/jme3-core/src/main/resources/Common/ShaderLib/Lighting.glsllib b/jme3-core/src/main/resources/Common/ShaderLib/Lighting.glsllib
index d75f4eb9c0..f5536afe5e 100644
--- a/jme3-core/src/main/resources/Common/ShaderLib/Lighting.glsllib
+++ b/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);
}
From 5b800952f02f191c164d94770efc005c273484be Mon Sep 17 00:00:00 2001
From: Kirill Vainer
Date: Mon, 19 Mar 2018 14:52:22 -0400
Subject: [PATCH 40/46] in-pass-shadows: fix syntax errors
---
.../main/java/com/jme3/shadow/ShadowUtil.java | 3 ++
.../com/jme3/shader/plugins/GLSLLoader.java | 37 +++++++++++--------
2 files changed, 24 insertions(+), 16 deletions(-)
diff --git a/jme3-core/src/main/java/com/jme3/shadow/ShadowUtil.java b/jme3-core/src/main/java/com/jme3/shadow/ShadowUtil.java
index b6ed551351..a7ea7b380a 100644
--- a/jme3-core/src/main/java/com/jme3/shadow/ShadowUtil.java
+++ b/jme3-core/src/main/java/com/jme3/shadow/ShadowUtil.java
@@ -32,7 +32,9 @@
package com.jme3.shadow;
import com.jme3.bounding.BoundingBox;
+import com.jme3.bounding.BoundingSphere;
import com.jme3.bounding.BoundingVolume;
+import com.jme3.collision.UnsupportedCollisionException;
import com.jme3.math.FastMath;
import com.jme3.math.Matrix4f;
import com.jme3.math.Transform;
@@ -42,6 +44,7 @@
import com.jme3.renderer.ViewPort;
import com.jme3.renderer.queue.GeometryList;
import com.jme3.renderer.queue.RenderQueue;
+import com.jme3.renderer.queue.RenderQueue.ShadowMode;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
diff --git a/jme3-core/src/plugins/java/com/jme3/shader/plugins/GLSLLoader.java b/jme3-core/src/plugins/java/com/jme3/shader/plugins/GLSLLoader.java
index 5545f480d6..ce3264b2d5 100644
--- a/jme3-core/src/plugins/java/com/jme3/shader/plugins/GLSLLoader.java
+++ b/jme3-core/src/plugins/java/com/jme3/shader/plugins/GLSLLoader.java
@@ -34,10 +34,7 @@
import com.jme3.asset.*;
import com.jme3.asset.cache.AssetCache;
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.Reader;
+import java.io.*;
import java.util.*;
/**
@@ -160,18 +157,27 @@ private String resolveDependencies(ShaderDependencyNode node, Set resolvedShaderNodes = new ArrayList<>();
+ if (injectDependencies) {
+ StringBuilder sb = new StringBuilder(node.getSource());
+ List resolvedShaderNodes = new ArrayList<>();
- for (ShaderDependencyNode dependencyNode : node.getDependencies()) {
- resolvedShaderNodes.add(resolveDependencies(dependencyNode, alreadyInjectedSet, extensions));
- }
- List injectIndices = node.getDependencyInjectIndices();
- for (int i = resolvedShaderNodes.size() - 1; i >= 0; i--) {
- // Must insert them backwards ..
- sb.insert(injectIndices.get(i), resolvedShaderNodes.get(i));
+ for (ShaderDependencyNode dependencyNode : node.getDependencies()) {
+ resolvedShaderNodes.add(resolveDependencies(dependencyNode, alreadyInjectedSet, extensions, injectDependencies));
+ }
+
+ List injectIndices = node.getDependencyInjectIndices();
+ for (int i = resolvedShaderNodes.size() - 1; i >= 0; i--) {
+ // Must insert them backwards ..
+ sb.insert(injectIndices.get(i), resolvedShaderNodes.get(i));
+ }
+ return sb.toString();
+ } else {
+ for (ShaderDependencyNode dependencyNode : node.getDependencies()) {
+ resolveDependencies(dependencyNode, alreadyInjectedSet, extensions, injectDependencies);
+ }
+ return null;
}
- return sb.toString();
+
}
}
@@ -185,8 +191,7 @@ public Object load(AssetInfo info) throws IOException {
if (info.getKey() instanceof ShaderAssetKey) {
injectDependencies = ((ShaderAssetKey) info.getKey()).isInjectDependencies();
}
- String extension = info.getKey().getExtension();
- if (extension.equals("glsllib") || extension.equals("glsl")) {
+ if (info.getKey().getExtension().equals("glsllib")) {
// NOTE: Loopback, GLSLLIB is loaded by this loader
// and needs data as InputStream
return reader;
From 5f66eeacb4e853ebf4f3d9fb97c7fda07aa2663d Mon Sep 17 00:00:00 2001
From: Kirill Vainer
Date: Mon, 19 Mar 2018 14:57:15 -0400
Subject: [PATCH 41/46] in-pass-shadows: use glsllib extension
---
.../src/main/resources/Common/MatDefs/Light/PBRLighting.frag | 2 +-
.../src/main/resources/Common/MatDefs/Light/PBRLighting.vert | 2 +-
.../src/main/resources/Common/MatDefs/Light/StaticLighting.frag | 2 +-
.../src/main/resources/Common/MatDefs/Light/StaticLighting.vert | 2 +-
.../ShaderLib/{InPassShadows.glsl => InPassShadows.glsllib} | 0
5 files changed, 4 insertions(+), 4 deletions(-)
rename jme3-core/src/main/resources/Common/ShaderLib/{InPassShadows.glsl => InPassShadows.glsllib} (100%)
diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLighting.frag b/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLighting.frag
index b6581888bc..a38cbc1387 100644
--- a/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLighting.frag
+++ b/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"
+#import "Common/ShaderLib/InPassShadows.glsllib"
varying vec2 texCoord;
#ifdef SEPARATE_TEXCOORD
diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLighting.vert b/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLighting.vert
index 99c50564f7..45d484181d 100644
--- a/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLighting.vert
+++ b/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLighting.vert
@@ -1,7 +1,7 @@
#import "Common/ShaderLib/GLSLCompat.glsllib"
#import "Common/ShaderLib/Instancing.glsllib"
#import "Common/ShaderLib/Skinning.glsllib"
-#import "Common/ShaderLib/InPassShadows.glsl"
+#import "Common/ShaderLib/InPassShadows.glsllib"
uniform vec4 m_BaseColor;
diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/StaticLighting.frag b/jme3-core/src/main/resources/Common/MatDefs/Light/StaticLighting.frag
index 7366a60d8f..f458a556c2 100755
--- a/jme3-core/src/main/resources/Common/MatDefs/Light/StaticLighting.frag
+++ b/jme3-core/src/main/resources/Common/MatDefs/Light/StaticLighting.frag
@@ -1,6 +1,6 @@
#import "Common/ShaderLib/GLSLCompat.glsllib"
#import "Common/ShaderLib/Lighting.glsllib"
-#import "Common/ShaderLib/InPassShadows.glsl"
+#import "Common/ShaderLib/InPassShadows.glsllib"
#import "Common/ShaderLib/PBR.glsllib"
#ifndef NUM_DIR_LIGHTS
diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/StaticLighting.vert b/jme3-core/src/main/resources/Common/MatDefs/Light/StaticLighting.vert
index c974fa4400..9a78fa67a3 100755
--- a/jme3-core/src/main/resources/Common/MatDefs/Light/StaticLighting.vert
+++ b/jme3-core/src/main/resources/Common/MatDefs/Light/StaticLighting.vert
@@ -1,7 +1,7 @@
#import "Common/ShaderLib/GLSLCompat.glsllib"
#import "Common/ShaderLib/Skinning.glsllib"
#import "Common/ShaderLib/Instancing.glsllib"
-#import "Common/ShaderLib/InPassShadows.glsl"
+#import "Common/ShaderLib/InPassShadows.glsllib"
attribute vec3 inPosition;
attribute vec3 inNormal;
diff --git a/jme3-core/src/main/resources/Common/ShaderLib/InPassShadows.glsl b/jme3-core/src/main/resources/Common/ShaderLib/InPassShadows.glsllib
similarity index 100%
rename from jme3-core/src/main/resources/Common/ShaderLib/InPassShadows.glsl
rename to jme3-core/src/main/resources/Common/ShaderLib/InPassShadows.glsllib
From 2e9996d498411cdebf36353955949ac23be6f0a3 Mon Sep 17 00:00:00 2001
From: Kirill Vainer
Date: Mon, 19 Mar 2018 14:58:08 -0400
Subject: [PATCH 42/46] in-pass-shadows: add test example
---
.../jme3test/light/TestInPassShadows.java | 207 ++++++++++++++++++
1 file changed, 207 insertions(+)
create mode 100755 jme3-examples/src/main/java/jme3test/light/TestInPassShadows.java
diff --git a/jme3-examples/src/main/java/jme3test/light/TestInPassShadows.java b/jme3-examples/src/main/java/jme3test/light/TestInPassShadows.java
new file mode 100755
index 0000000000..33eefde8e4
--- /dev/null
+++ b/jme3-examples/src/main/java/jme3test/light/TestInPassShadows.java
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2009-2018 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jme3test.light;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.input.KeyInput;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.input.controls.AnalogListener;
+import com.jme3.input.controls.KeyTrigger;
+import com.jme3.light.AmbientLight;
+import com.jme3.light.DirectionalLight;
+import com.jme3.light.PointLight;
+import com.jme3.light.SpotLight;
+import com.jme3.material.Material;
+import com.jme3.material.TechniqueDef.LightMode;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.FastMath;
+import com.jme3.math.Quaternion;
+import com.jme3.math.Vector3f;
+import com.jme3.post.FilterPostProcessor;
+import com.jme3.post.filters.ToneMapFilter;
+import com.jme3.renderer.queue.RenderQueue.ShadowMode;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.shape.Box;
+import com.jme3.scene.shape.Quad;
+import com.jme3.shadow.next.PreShadowArrayRenderer;
+import com.jme3.system.AppSettings;
+
+public class TestInPassShadows extends SimpleApplication {
+
+ private DirectionalLight dl;
+ private SpotLight sl;
+ private PointLight pl;
+ private PreShadowArrayRenderer psr;
+ private ToneMapFilter tmf;
+
+ public static void main(String[] args) {
+ TestInPassShadows app = new TestInPassShadows();
+ app.setShowSettings(false);
+ AppSettings settings = new AppSettings(true);
+ settings.setGammaCorrection(true);
+ app.setSettings(settings);
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ renderManager.setPreferredLightMode(LightMode.SinglePassAndImageBased);
+ renderManager.setSinglePassLightBatchSize(3);
+
+ cam.setLocation(new Vector3f(8.079489f, 10.792628f, -6.714233f));
+ cam.setRotation(new Quaternion(0.38442945f, -0.35025623f, 0.16050051f, 0.8389125f));
+ flyCam.setMoveSpeed(5);
+
+ tmf = new ToneMapFilter(new Vector3f(50, 50, 50));
+ FilterPostProcessor fpp = new FilterPostProcessor(assetManager);
+ fpp.addFilter(tmf);
+ viewPort.addProcessor(fpp);
+
+ loadLights();
+ loadScene();
+ loadInputs();
+ }
+
+ private void loadLights() {
+ AmbientLight al = new AmbientLight(new ColorRGBA(0.2f, 0.2f, 0.3f, 1.0f).mult(2f));
+ rootNode.addLight(al);
+
+ dl = new DirectionalLight();
+ dl.setDirection(new Vector3f(-1, -0.5f, -1).normalizeLocal());
+ dl.setColor(new ColorRGBA(1, 0.9f, 0.8f, 1).mult(2.5f));
+ rootNode.addLight(dl);
+
+ sl = new SpotLight();
+ sl.setSpotRange(15);
+ sl.setSpotInnerAngle(20 * FastMath.DEG_TO_RAD);
+ sl.setSpotOuterAngle(25 * FastMath.DEG_TO_RAD);
+ sl.setPosition(new Vector3f(-5.2193f, -0.5851393f, 4.831882f));
+ sl.setDirection(new Vector3f(0.8429418f, -0.42458484f, -0.33041906f));
+ sl.setColor(new ColorRGBA(0.5f, 0.7f, 1.0f, 1.0f).mult(50));
+ rootNode.addLight(sl);
+
+ pl = new PointLight(
+ new Vector3f(-0.10135013f, 1.9986207f, -2.0745828f),
+ new ColorRGBA(0.5f, 0.3f, 0.1f, 1f).mult(20),
+ 30);
+ rootNode.addLight(pl);
+
+ psr = new PreShadowArrayRenderer();
+ psr.setTextureSize(512);
+ psr.setPolyOffset(5, 0);
+ psr.directional().setNumSplits(1);
+ psr.addLight(dl);
+ psr.addLight(sl);
+ psr.addLight(pl);
+ viewPort.addProcessor(psr);
+ }
+
+ private void loadScene() {
+ Geometry box = new Geometry("Box", new Box(1, 1, 1));
+ box.setShadowMode(ShadowMode.CastAndReceive);
+ Material boxMat = new Material(assetManager, "Common/MatDefs/Light/PBRLighting.j3md");
+ boxMat.setFloat("Roughness", 0.5f);
+ boxMat.setFloat("Metallic", 0f);
+ box.setMaterial(boxMat);
+ rootNode.attachChild(box);
+
+ Geometry box2 = box.clone(true);
+ box2.move(3, 0, 0);
+ rootNode.attachChild(box2);
+
+ Geometry box3 = box.clone(true);
+ box3.move(-3, 0, 0);
+ rootNode.attachChild(box3);
+
+ Geometry floor = new Geometry("floor", new Quad(100, 100));
+ floor.rotate(-FastMath.HALF_PI, 0, 0);
+ floor.center();
+ floor.move(0, -1, 0);
+ floor.setShadowMode(ShadowMode.Receive);
+ Material floorMat = new Material(assetManager, "Common/MatDefs/Light/PBRLighting.j3md");
+ floorMat.setFloat("Roughness", 0.5f);
+ floorMat.setFloat("Metallic", 0f);
+ floor.setMaterial(floorMat);
+ rootNode.attachChild(floor);
+ }
+
+ private boolean moveLight = false;
+
+ private void loadInputs() {
+ inputManager.addMapping("MoveLight", new KeyTrigger(KeyInput.KEY_SPACE));
+ inputManager.addListener(new ActionListener() {
+ @Override
+ public void onAction(String name, boolean isPressed, float tpf) {
+ moveLight = isPressed;
+ }
+ }, "MoveLight");
+
+ inputManager.addMapping("OffsetFactorUp", new KeyTrigger(KeyInput.KEY_U));
+ inputManager.addMapping("OffsetFactorDown", new KeyTrigger(KeyInput.KEY_J));
+ inputManager.addMapping("OffsetUnitsUp", new KeyTrigger(KeyInput.KEY_I));
+ inputManager.addMapping("OffsetUnitsDown", new KeyTrigger(KeyInput.KEY_K));
+ inputManager.addListener(new AnalogListener() {
+ private float factor, units;
+ @Override
+ public void onAnalog(String name, float value, float tpf) {
+ switch (name) {
+ case "OffsetFactorUp":
+ factor += tpf * 5f;
+ break;
+ case "OffsetFactorDown":
+ factor -= tpf * 5f;
+ break;
+ case "OffsetUnitsUp":
+ units += tpf * 50f;
+ break;
+ case "OffsetUnitsDown":
+ units -= tpf * 50f;
+ break;
+ }
+ psr.setPolyOffset(factor, units);
+ System.out.println("PolyOffset(" + factor + ", " + units + ")");
+ }
+
+ }, "OffsetFactorUp", "OffsetFactorDown", "OffsetUnitsUp", "OffsetUnitsDown");
+ }
+
+ @Override
+ public void simpleUpdate(float tpf) {
+ if (moveLight) {
+ sl.setPosition(cam.getLocation());
+ sl.setDirection(cam.getDirection());
+ System.out.println(sl.getPosition());
+ System.out.println(sl.getDirection());
+ }
+ }
+
+}
From 251511ee00acafe1aa96d4947645463f861c77ab Mon Sep 17 00:00:00 2001
From: Kirill Vainer
Date: Mon, 19 Mar 2018 14:59:47 -0400
Subject: [PATCH 43/46] in-pass-shadows: add customized light sort
---
.../src/main/java/com/jme3/light/LightList.java | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/jme3-core/src/main/java/com/jme3/light/LightList.java b/jme3-core/src/main/java/com/jme3/light/LightList.java
index dfeb654057..5ae42ea589 100644
--- a/jme3-core/src/main/java/com/jme3/light/LightList.java
+++ b/jme3-core/src/main/java/com/jme3/light/LightList.java
@@ -186,7 +186,7 @@ public void clear() {
listSize = 0;
}
-
+
/**
* Sorts the elements in the list according to their Comparator.
* There are two reasons why lights should be resorted.
@@ -219,6 +219,18 @@ public void sort(boolean transformChanged) {
}
}
+ public void sort(Comparator comparator) {
+ if (listSize > 1) {
+ if (tlist == null || tlist.length != list.length) {
+ tlist = list.clone();
+ } else {
+ System.arraycopy(list, 0, tlist, 0, list.length);
+ }
+
+ SortUtil.msort(tlist, list, 0, listSize - 1, comparator);
+ }
+ }
+
/**
* Updates a "world-space" light list, using the spatial's local-space
* light list and its parent's world-space light list.
From cbf6ffaad83a47fadf61ffc55b79f91ca03d8d95 Mon Sep 17 00:00:00 2001
From: Kirill Vainer
Date: Mon, 19 Mar 2018 15:04:41 -0400
Subject: [PATCH 44/46] in-pass-shadows: show cfg dialog for test
---
.../src/main/java/jme3test/light/TestInPassShadows.java | 1 -
1 file changed, 1 deletion(-)
diff --git a/jme3-examples/src/main/java/jme3test/light/TestInPassShadows.java b/jme3-examples/src/main/java/jme3test/light/TestInPassShadows.java
index 33eefde8e4..5a01b4c7c8 100755
--- a/jme3-examples/src/main/java/jme3test/light/TestInPassShadows.java
+++ b/jme3-examples/src/main/java/jme3test/light/TestInPassShadows.java
@@ -65,7 +65,6 @@ public class TestInPassShadows extends SimpleApplication {
public static void main(String[] args) {
TestInPassShadows app = new TestInPassShadows();
- app.setShowSettings(false);
AppSettings settings = new AppSettings(true);
settings.setGammaCorrection(true);
app.setSettings(settings);
From d444c2818372edbfadf9d289bf66d8637f889330 Mon Sep 17 00:00:00 2001
From: Nehon
Date: Sun, 27 May 2018 20:59:02 +0200
Subject: [PATCH 45/46] Changes the name of the array shadow renderer to
InPassShadowRenderer. Also addressed some comments on the PR
---
.../java/com/jme3/material/TechniqueDef.java | 11 -
.../logic/ShadowStaticPassLightingLogic.java | 200 ------------------
.../logic/StaticPassLightingLogic.java | 191 -----------------
...enderer.java => InPassShadowRenderer.java} | 4 +-
.../jme3/shadow/next/ShadowDebugControl.java | 3 +-
.../jme3/shadow/next/ShadowParameters.java | 38 ----
.../array/DirectionalArrayShadowMapSlice.java | 12 +-
.../shadow/next/pssm/BaseShadowMapSlice.java | 4 +-
.../pssm/DirectionalShadowParameters.java | 8 +-
.../Common/ShaderLib/Lighting.glsllib | 2 +-
.../com/jme3/material/plugins/J3MLoader.java | 4 -
.../jme3test/light/TestInPassShadows.java | 22 +-
12 files changed, 32 insertions(+), 467 deletions(-)
delete mode 100755 jme3-core/src/main/java/com/jme3/material/logic/ShadowStaticPassLightingLogic.java
delete mode 100644 jme3-core/src/main/java/com/jme3/material/logic/StaticPassLightingLogic.java
rename jme3-core/src/main/java/com/jme3/shadow/next/{PreShadowArrayRenderer.java => InPassShadowRenderer.java} (98%)
mode change 100755 => 100644
delete mode 100755 jme3-core/src/main/java/com/jme3/shadow/next/ShadowParameters.java
diff --git a/jme3-core/src/main/java/com/jme3/material/TechniqueDef.java b/jme3-core/src/main/java/com/jme3/material/TechniqueDef.java
index 1b01115220..d85612fa87 100644
--- a/jme3-core/src/main/java/com/jme3/material/TechniqueDef.java
+++ b/jme3-core/src/main/java/com/jme3/material/TechniqueDef.java
@@ -105,17 +105,6 @@ public enum LightMode {
*/
@Deprecated
FixedPipeline,
- /**
- * Similar to {@link #SinglePass} except the type of each light is known
- * at shader compile time.
- *
- * The advantage is that the shader can be much more efficient, i.e. not
- * do operations required for spot and point lights if it knows the
- * light is a directional light. The disadvantage is that the number of
- * shaders used balloons because of the variations in the number of
- * lights used by objects.
- */
- StaticPass
}
public enum ShadowMode {
diff --git a/jme3-core/src/main/java/com/jme3/material/logic/ShadowStaticPassLightingLogic.java b/jme3-core/src/main/java/com/jme3/material/logic/ShadowStaticPassLightingLogic.java
deleted file mode 100755
index 04bdc226f3..0000000000
--- a/jme3-core/src/main/java/com/jme3/material/logic/ShadowStaticPassLightingLogic.java
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * 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.Vector3f;
-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.PointArrayShadowMap;
-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;
-
- 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);
- }
-
- @Override
- protected void makeCurrentBase(AssetManager assetManager, RenderManager renderManager,
- EnumSet 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() - numShadowDirLights);
- defines.set(numPointLightsDefineId, tempPointLights.size() - numShadowPointLights);
- defines.set(numSpotLightsDefineId, tempSpotLights.size() - numShadowSpotLights);
-
- defines.set(numShadowDirLightsDefineId, numShadowDirLights);
- defines.set(numShadowPointLightsDefineId, numShadowPointLights);
- defines.set(numShadowSpotLightsDefineId, numShadowSpotLights);
-
- defines.set(numPssmSplitsDefineId, pssmSplits);
- }
-
- @Override
- protected void updateShadowUniforms(Renderer renderer, Shader shader, int nextTextureUnit) {
- TextureArray array = null;
- Vector3f pssmSplits = null;
-
- Uniform shadowMatricesUniform = shader.getUniform("g_ShadowMatrices");
-
- shadowMatricesUniform.setMatrix4Length(
- numShadowDirLights * 4 +
- numShadowPointLights * 6 +
- numShadowSpotLights);
-
- 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);
- shadowMatricesUniform.setMatrix4InArray(
- slice.getBiasedViewProjectionMatrix(),
- shadowMatrixIndex);
- shadowMatrixIndex++;
- }
- }
-
- for (int i = 0; i < numShadowPointLights; i++) {
- PointArrayShadowMap map = (PointArrayShadowMap) tempPointLights.get(i).getShadowMap();
- array = map.getArray();
- for (int j = 0; j < map.getNumSlices(); j++) {
- ArrayShadowMapSlice slice = (ArrayShadowMapSlice) map.getSlice(j);
- shadowMatricesUniform.setMatrix4InArray(
- slice.getBiasedViewProjectionMatrix(),
- shadowMatrixIndex);
- shadowMatrixIndex++;
- }
- }
-
- for (int i = 0; i < numShadowSpotLights; i++) {
- SpotArrayShadowMap map = (SpotArrayShadowMap) tempSpotLights.get(i).getShadowMap();
- array = map.getArray();
- SpotArrayShadowMapSlice slice = map.getSlice(0);
- shadowMatricesUniform.setMatrix4InArray(
- slice.getBiasedViewProjectionMatrix(),
- shadowMatrixIndex);
- shadowMatrixIndex++;
- }
-
- 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.Vector3, pssmSplits);
- }
- }
-}
diff --git a/jme3-core/src/main/java/com/jme3/material/logic/StaticPassLightingLogic.java b/jme3-core/src/main/java/com/jme3/material/logic/StaticPassLightingLogic.java
deleted file mode 100644
index 6ba92e10b0..0000000000
--- a/jme3-core/src/main/java/com/jme3/material/logic/StaticPassLightingLogic.java
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * Copyright (c) 2009-2015 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.ColorRGBA;
-import com.jme3.math.Matrix4f;
-import com.jme3.math.Vector3f;
-import com.jme3.renderer.Caps;
-import com.jme3.renderer.RenderManager;
-import com.jme3.renderer.Renderer;
-import com.jme3.scene.Geometry;
-import com.jme3.shader.DefineList;
-import com.jme3.shader.Shader;
-import com.jme3.shader.Uniform;
-import com.jme3.shader.VarType;
-import java.util.ArrayList;
-import java.util.EnumSet;
-
-/**
- * Rendering logic for static pass.
- *
- * @author Kirill Vainer
- */
-public class StaticPassLightingLogic extends DefaultTechniqueDefLogic {
-
- protected static final String DEFINE_NUM_DIR_LIGHTS = "NUM_DIR_LIGHTS";
- protected static final String DEFINE_NUM_POINT_LIGHTS = "NUM_POINT_LIGHTS";
- protected static final String DEFINE_NUM_SPOT_LIGHTS = "NUM_SPOT_LIGHTS";
-
- protected final int numDirLightsDefineId;
- protected final int numPointLightsDefineId;
- protected final int numSpotLightsDefineId;
-
- protected final ColorRGBA ambientLightColor = new ColorRGBA(0, 0, 0, 1);
- protected final Vector3f tempPosition = new Vector3f();
- protected final Vector3f tempDirection = new Vector3f();
-
- protected final ArrayList tempDirLights = new ArrayList<>();
- protected final ArrayList tempPointLights = new ArrayList<>();
- protected final ArrayList tempSpotLights = new ArrayList<>();
-
- public StaticPassLightingLogic(TechniqueDef techniqueDef) {
- super(techniqueDef);
-
- numDirLightsDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_NUM_DIR_LIGHTS, VarType.Int);
- numPointLightsDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_NUM_POINT_LIGHTS, VarType.Int);
- numSpotLightsDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_NUM_SPOT_LIGHTS, VarType.Int);
- }
-
- protected void makeCurrentBase(AssetManager assetManager, RenderManager renderManager,
- EnumSet rendererCaps, LightList lights, DefineList defines) {
-
- // TODO: if it ever changes that render isn't called
- // right away with the same geometry after makeCurrent, it would be
- // a problem.
- // Do a radix sort.
- tempDirLights.clear();
- tempPointLights.clear();
- tempSpotLights.clear();
- ambientLightColor.set(0, 0, 0, 1);
-
- for (Light light : lights) {
- switch (light.getType()) {
- case Directional:
- tempDirLights.add((DirectionalLight) light);
- break;
- case Point:
- tempPointLights.add((PointLight) light);
- break;
- case Spot:
- 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());
- }
-
- @Override
- public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager,
- EnumSet rendererCaps, Geometry geometry, DefineList defines) {
- LightList lights = getFilteredLightList(renderManager, geometry);
- makeCurrentBase(assetManager, renderManager, rendererCaps, lights, defines);
- return techniqueDef.getShader(assetManager, rendererCaps, defines);
- }
-
- protected void updateLightListUniforms(Matrix4f viewMatrix, Shader shader) {
- Uniform ambientColor = shader.getUniform("g_AmbientLightColor");
- ambientColor.setValue(VarType.Vector4, ambientLightColor);
-
- Uniform lightData = shader.getUniform("g_LightData");
-
- int totalSize = tempDirLights.size() * 2
- + tempPointLights.size() * 2
- + tempSpotLights.size() * 3;
- 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 lightTypeAndShadowMap = encodeLightTypeAndShadowMapIndex(light);
- lightData.setVector4InArray(color.r, color.g, color.b, lightTypeAndShadowMap, index++);
-
- tempDirection.set(light.getDirection());
- lightData.setVector4InArray(tempDirection.x, tempDirection.y, tempDirection.z, 1f, index++);
- }
-
- for (PointLight light : tempPointLights) {
- ColorRGBA color = light.getColor();
- float lightTypeAndShadowMap = encodeLightTypeAndShadowMapIndex(light);
- lightData.setVector4InArray(color.r, color.g, color.b, lightTypeAndShadowMap, index++);
-
- tempPosition.set(light.getPosition());
- float invRadius = light.getInvRadius();
- lightData.setVector4InArray(tempPosition.x, tempPosition.y, tempPosition.z, invRadius, index++);
- }
-
-
- }
-
- protected void updateShadowUniforms(Renderer renderer, Shader shader, int nextTextureUnit) {
- }
-
- @Override
- public void render(RenderManager renderManager, Shader shader, Geometry geometry, int nextTextureUnit) {
- Renderer renderer = renderManager.getRenderer();
- Matrix4f viewMatrix = renderManager.getCurrentCamera().getViewMatrix();
- updateLightListUniforms(viewMatrix, shader);
- updateShadowUniforms(renderer, shader, nextTextureUnit);
- renderer.setShader(shader);
- renderMeshFromGeometry(renderer, geometry);
- }
-
-}
diff --git a/jme3-core/src/main/java/com/jme3/shadow/next/PreShadowArrayRenderer.java b/jme3-core/src/main/java/com/jme3/shadow/next/InPassShadowRenderer.java
old mode 100755
new mode 100644
similarity index 98%
rename from jme3-core/src/main/java/com/jme3/shadow/next/PreShadowArrayRenderer.java
rename to jme3-core/src/main/java/com/jme3/shadow/next/InPassShadowRenderer.java
index 06d3eca5d9..c36a004da5
--- a/jme3-core/src/main/java/com/jme3/shadow/next/PreShadowArrayRenderer.java
+++ b/jme3-core/src/main/java/com/jme3/shadow/next/InPassShadowRenderer.java
@@ -75,7 +75,7 @@
*
* @author Kirill Vainer
*/
-public class PreShadowArrayRenderer implements SceneProcessor {
+public class InPassShadowRenderer implements SceneProcessor {
private static final String PRE_SHADOW_TECHNIQUE_NAME = "PreShadow";
@@ -94,7 +94,7 @@ public class PreShadowArrayRenderer implements SceneProcessor {
// parameters for directional lights
private final DirectionalShadowParameters directionalParams = new DirectionalShadowParameters();
- public PreShadowArrayRenderer() {
+ public InPassShadowRenderer() {
for (int i = 0; i < points.length; i++) {
points[i] = new Vector3f();
}
diff --git a/jme3-core/src/main/java/com/jme3/shadow/next/ShadowDebugControl.java b/jme3-core/src/main/java/com/jme3/shadow/next/ShadowDebugControl.java
index 45db107d53..2607525e7c 100644
--- a/jme3-core/src/main/java/com/jme3/shadow/next/ShadowDebugControl.java
+++ b/jme3-core/src/main/java/com/jme3/shadow/next/ShadowDebugControl.java
@@ -38,7 +38,6 @@
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;
@@ -54,7 +53,7 @@ final class ShadowDebugControl extends AbstractControl {
private final List pictures = new ArrayList<>();
- public ShadowDebugControl(AssetManager assetManager, PreShadowArrayRenderer shadowRenderer) {
+ public ShadowDebugControl(AssetManager assetManager, InPassShadowRenderer shadowRenderer) {
TextureArray shadowMapArray = shadowRenderer.getShadowMapTexture();
Image shadowMap = shadowMapArray.getImage();
for (int i = 0; i < shadowMap.getDepth(); i++) {
diff --git a/jme3-core/src/main/java/com/jme3/shadow/next/ShadowParameters.java b/jme3-core/src/main/java/com/jme3/shadow/next/ShadowParameters.java
deleted file mode 100755
index 37df980ab3..0000000000
--- a/jme3-core/src/main/java/com/jme3/shadow/next/ShadowParameters.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * 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 {
-}
diff --git a/jme3-core/src/main/java/com/jme3/shadow/next/array/DirectionalArrayShadowMapSlice.java b/jme3-core/src/main/java/com/jme3/shadow/next/array/DirectionalArrayShadowMapSlice.java
index 38e9aaca07..edb9ae810d 100755
--- a/jme3-core/src/main/java/com/jme3/shadow/next/array/DirectionalArrayShadowMapSlice.java
+++ b/jme3-core/src/main/java/com/jme3/shadow/next/array/DirectionalArrayShadowMapSlice.java
@@ -48,6 +48,11 @@ public DirectionalArrayShadowMapSlice(TextureArray array, int layer, int texture
this.shadowCamera.setParallelProjection(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,
DirectionalLight light,
@@ -55,7 +60,12 @@ public void updateShadowCamera(
float near,
float far,
Vector3f[] points) {
- shadowCamera.lookAtDirection(light.getDirection(), shadowCamera.getUp());
+ 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);
+ }
int textureSize = frameBuffer.getWidth();
ShadowUtil.updateFrustumPoints(viewPort.getCamera(), near, far, points);
diff --git a/jme3-core/src/main/java/com/jme3/shadow/next/pssm/BaseShadowMapSlice.java b/jme3-core/src/main/java/com/jme3/shadow/next/pssm/BaseShadowMapSlice.java
index e9b999fbed..9a46890e16 100755
--- a/jme3-core/src/main/java/com/jme3/shadow/next/pssm/BaseShadowMapSlice.java
+++ b/jme3-core/src/main/java/com/jme3/shadow/next/pssm/BaseShadowMapSlice.java
@@ -53,6 +53,7 @@ public abstract class BaseShadowMapSlice implements ShadowMapSl
protected final Texture2D depthTexture;
protected final Camera shadowCamera;
protected final Vector3f[] points;
+ protected final Matrix4f biasedViewProjectionMatrix = new Matrix4f();
public BaseShadowMapSlice(int size, Vector3f[] points) {
this.depthTexture = new Texture2D(size, size, Image.Format.Depth16);
@@ -81,7 +82,6 @@ public void renderShadowMap(RenderManager renderManager, T light, ViewPort viewP
@Override
public Matrix4f getBiasedViewProjectionMatrix() {
-// return shadowCamera.getViewProjectionMatrix();
- throw new UnsupportedOperationException();
+ return BIAS_MATRIX.mult(shadowCamera.getViewProjectionMatrix(), biasedViewProjectionMatrix);
}
}
diff --git a/jme3-core/src/main/java/com/jme3/shadow/next/pssm/DirectionalShadowParameters.java b/jme3-core/src/main/java/com/jme3/shadow/next/pssm/DirectionalShadowParameters.java
index 9b63a2fd9b..0738cce0bd 100755
--- a/jme3-core/src/main/java/com/jme3/shadow/next/pssm/DirectionalShadowParameters.java
+++ b/jme3-core/src/main/java/com/jme3/shadow/next/pssm/DirectionalShadowParameters.java
@@ -32,15 +32,13 @@
package com.jme3.shadow.next.pssm;
import com.jme3.math.Vector3f;
-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 {
+public final class DirectionalShadowParameters {
private float lambda = 0.65f;
private int numSplits = 4;
@@ -61,7 +59,9 @@ public int getNumSplits() {
}
public void setNumSplits(int numSplits) {
- // TODO: ensure it is 1 to 4
+ if (numSplits < 1 || numSplits > 4) {
+ throw new IllegalArgumentException("Number of splits must be between 1 and 4");
+ }
this.numSplits = numSplits;
this.splitPositions = new float[numSplits + 1];
}
diff --git a/jme3-core/src/main/resources/Common/ShaderLib/Lighting.glsllib b/jme3-core/src/main/resources/Common/ShaderLib/Lighting.glsllib
index f5536afe5e..dadb665714 100644
--- a/jme3-core/src/main/resources/Common/ShaderLib/Lighting.glsllib
+++ b/jme3-core/src/main/resources/Common/ShaderLib/Lighting.glsllib
@@ -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 = 1.0; // clamp(1.0 - position.w * dist * posLight, 0.0, 1.0);
+ lightDir.w = clamp(1.0 - position.w * dist * posLight, 0.0, 1.0);
#endif
lightDir.xyz = tempVec / vec3(dist);
}
diff --git a/jme3-core/src/plugins/java/com/jme3/material/plugins/J3MLoader.java b/jme3-core/src/plugins/java/com/jme3/material/plugins/J3MLoader.java
index 04873b9ddf..80c19dc7da 100644
--- a/jme3-core/src/plugins/java/com/jme3/material/plugins/J3MLoader.java
+++ b/jme3-core/src/plugins/java/com/jme3/material/plugins/J3MLoader.java
@@ -39,7 +39,6 @@
import com.jme3.material.RenderState.FaceCullMode;
import com.jme3.material.TechniqueDef.LightMode;
import com.jme3.material.TechniqueDef.ShadowMode;
-import com.jme3.material.logic.StaticPassLightingLogic;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
@@ -645,9 +644,6 @@ private void readTechnique(Statement techStat) throws IOException{
case SinglePass:
technique.setLogic(new SinglePassLightingLogic(technique));
break;
- case StaticPass:
- technique.setLogic(new ShadowStaticPassLightingLogic(technique));
- break;
case SinglePassAndImageBased:
technique.setLogic(new SinglePassAndImageBasedLightingLogic(technique));
break;
diff --git a/jme3-examples/src/main/java/jme3test/light/TestInPassShadows.java b/jme3-examples/src/main/java/jme3test/light/TestInPassShadows.java
index 5a01b4c7c8..6a1ad74c39 100755
--- a/jme3-examples/src/main/java/jme3test/light/TestInPassShadows.java
+++ b/jme3-examples/src/main/java/jme3test/light/TestInPassShadows.java
@@ -52,7 +52,7 @@
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Box;
import com.jme3.scene.shape.Quad;
-import com.jme3.shadow.next.PreShadowArrayRenderer;
+import com.jme3.shadow.next.InPassShadowRenderer;
import com.jme3.system.AppSettings;
public class TestInPassShadows extends SimpleApplication {
@@ -60,7 +60,7 @@ public class TestInPassShadows extends SimpleApplication {
private DirectionalLight dl;
private SpotLight sl;
private PointLight pl;
- private PreShadowArrayRenderer psr;
+ private InPassShadowRenderer ipsr;
private ToneMapFilter tmf;
public static void main(String[] args) {
@@ -114,14 +114,14 @@ private void loadLights() {
30);
rootNode.addLight(pl);
- psr = new PreShadowArrayRenderer();
- psr.setTextureSize(512);
- psr.setPolyOffset(5, 0);
- psr.directional().setNumSplits(1);
- psr.addLight(dl);
- psr.addLight(sl);
- psr.addLight(pl);
- viewPort.addProcessor(psr);
+ ipsr = new InPassShadowRenderer();
+ ipsr.setTextureSize(512);
+ ipsr.setPolyOffset(5, 0);
+ ipsr.directional().setNumSplits(1);
+ ipsr.addLight(dl);
+ ipsr.addLight(sl);
+ ipsr.addLight(pl);
+ viewPort.addProcessor(ipsr);
}
private void loadScene() {
@@ -186,7 +186,7 @@ public void onAnalog(String name, float value, float tpf) {
units -= tpf * 50f;
break;
}
- psr.setPolyOffset(factor, units);
+ ipsr.setPolyOffset(factor, units);
System.out.println("PolyOffset(" + factor + ", " + units + ")");
}
From dd2626c5604d43e4f9c9d353a27a9a1447093a9f Mon Sep 17 00:00:00 2001
From: Nehon
Date: Sun, 27 May 2018 21:17:37 +0200
Subject: [PATCH 46/46] Properly remove static pass
---
.../Common/MatDefs/Light/Lighting.j3md | 33 +--
.../Common/MatDefs/Light/StaticLighting.frag | 200 ------------------
.../Common/MatDefs/Light/StaticLighting.vert | 32 ---
3 files changed, 6 insertions(+), 259 deletions(-)
delete mode 100755 jme3-core/src/main/resources/Common/MatDefs/Light/StaticLighting.frag
delete mode 100755 jme3-core/src/main/resources/Common/MatDefs/Light/StaticLighting.vert
diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.j3md b/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.j3md
index 19dbd13bcb..980ac650bf 100644
--- a/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.j3md
+++ b/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.j3md
@@ -128,27 +128,6 @@ MaterialDef Phong Lighting {
Boolean IsPointLight
}
- Technique {
- LightMode StaticPass
-
- VertexShader GLSL100 GLSL150 : Common/MatDefs/Light/StaticLighting.vert
- FragmentShader GLSL100 GLSL150 : Common/MatDefs/Light/StaticLighting.frag
-
- WorldParameters {
- WorldViewProjectionMatrix
- NormalMatrix
- WorldViewMatrix
- ViewMatrix
- CameraPosition
- WorldMatrix
- ViewProjectionMatrix
- }
-
- Defines {
- AMBIENTMAP : AmbientMap
- }
- }
-
Technique {
LightMode SinglePass
@@ -162,13 +141,13 @@ MaterialDef Phong Lighting {
ViewMatrix
CameraPosition
WorldMatrix
- ViewProjectionMatrix
+ ViewProjectionMatrix
}
- Defines {
+ Defines {
VERTEX_COLOR : UseVertexColor
- VERTEX_LIGHTING : VertexLighting
- MATERIAL_COLORS : UseMaterialColors
+ VERTEX_LIGHTING : VertexLighting
+ MATERIAL_COLORS : UseMaterialColors
DIFFUSEMAP : DiffuseMap
NORMALMAP : NormalMap
SPECULARMAP : SpecularMap
@@ -181,8 +160,8 @@ MaterialDef Phong Lighting {
SEPARATE_TEXCOORD : SeparateTexCoord
DISCARD_ALPHA : AlphaDiscardThreshold
USE_REFLECTION : EnvMap
- SPHERE_MAP : EnvMapAsSphereMap
- NUM_BONES : NumberOfBones
+ SPHERE_MAP : EnvMapAsSphereMap
+ NUM_BONES : NumberOfBones
INSTANCING : UseInstancing
NUM_MORPH_TARGETS: NumberOfMorphTargets
NUM_TARGETS_BUFFERS: NumberOfTargetsBuffers
diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/StaticLighting.frag b/jme3-core/src/main/resources/Common/MatDefs/Light/StaticLighting.frag
deleted file mode 100755
index f458a556c2..0000000000
--- a/jme3-core/src/main/resources/Common/MatDefs/Light/StaticLighting.frag
+++ /dev/null
@@ -1,200 +0,0 @@
-#import "Common/ShaderLib/GLSLCompat.glsllib"
-#import "Common/ShaderLib/Lighting.glsllib"
-#import "Common/ShaderLib/InPassShadows.glsllib"
-#import "Common/ShaderLib/PBR.glsllib"
-
-#ifndef NUM_DIR_LIGHTS
-#define NUM_DIR_LIGHTS 0
-#endif
-
-#ifndef NUM_POINT_LIGHTS
-#define NUM_POINT_LIGHTS 0
-#endif
-
-#ifndef NUM_SPOT_LIGHTS
-#define NUM_SPOT_LIGHTS 0
-#endif
-
-#define DIR_SHADOW_LIGHT_START (0)
-#define DIR_SHADOW_LIGHT_END (NUM_SHADOW_DIR_LIGHTS * 2)
-
-#define DIR_LIGHT_START (DIR_SHADOW_LIGHT_END)
-#define DIR_LIGHT_END (DIR_LIGHT_START + NUM_DIR_LIGHTS * 2)
-
-#define POINT_SHADOW_LIGHT_START (DIR_LIGHT_END)
-#define POINT_SHADOW_LIGHT_END (POINT_SHADOW_LIGHT_START + NUM_SHADOW_POINT_LIGHTS * 2)
-
-#define POINT_LIGHT_START (POINT_SHADOW_LIGHT_END)
-#define POINT_LIGHT_END (POINT_LIGHT_START + NUM_POINT_LIGHTS * 2)
-
-#define SPOT_SHADOW_LIGHT_START (POINT_LIGHT_END)
-#define SPOT_SHADOW_LIGHT_END (SPOT_SHADOW_LIGHT_START + NUM_SHADOW_SPOT_LIGHTS * 3)
-
-#define SPOT_LIGHT_START (SPOT_SHADOW_LIGHT_END)
-#define SPOT_LIGHT_END (SPOT_LIGHT_START + NUM_SPOT_LIGHTS * 3)
-
-#define LIGHT_DATA_SIZE (NUM_SHADOW_DIR_LIGHTS * 2 )
-
-uniform vec3 g_CameraPosition;
-
-uniform sampler2D m_AmbientMap;
-uniform float m_AlphaDiscardThreshold;
-uniform float m_Shininess;
-uniform vec4 g_AmbientLightColor;
-
-#if LIGHT_DATA_SIZE > 0
-uniform vec4 g_LightData[LIGHT_DATA_SIZE];
-#else
-const vec4 g_LightData[1] = vec4[]( vec4(1.0) );
-#endif
-
-varying vec3 vPos;
-varying vec3 vNormal;
-varying vec2 vTexCoord;
-
-struct surface_t {
- vec3 position;
- vec3 normal;
- vec3 viewDir;
- vec3 ambient;
- vec4 diffuse;
- vec4 specular;
- float roughness;
- float ndotv;
-};
-
-void Lighting_Process(in int lightIndex, in surface_t surface, out vec3 outDiffuse, out vec3 outSpecular, inout int startProjIndex) {
- vec4 lightColor = g_LightData[lightIndex];
- vec4 lightData1 = g_LightData[lightIndex + 1];
- float shadowMapIndex = -1.0;
-
- if (lightColor.w < 0.0) {
- lightColor.w = -lightColor.w;
- shadowMapIndex = floor(lightColor.w);
- lightColor.w = lightColor.w - shadowMapIndex;
- }
-
- vec4 lightDir;
- vec3 lightVec;
- lightComputeDir(surface.position, lightColor.w, lightData1, lightDir, lightVec);
-
- if (shadowMapIndex >= 0.0) {
- lightDir.w *= Shadow_Process(lightColor.w, lightDir.xyz, shadowMapIndex, startProjIndex);
- }
-
- if (lightColor.w >= 0.5) {
- lightDir.w *= computeSpotFalloff(g_LightData[lightIndex + 2], lightDir.xyz);
- }
-
- lightColor.rgb *= lightDir.w;
-
- PBR_ComputeDirectLightSpecWF(surface.normal, lightDir.xyz, surface.viewDir,
- lightColor.rgb, surface.specular.rgb, surface.roughness, surface.ndotv,
- outDiffuse, outSpecular);
-}
-
-void Lighting_ProcessAll(surface_t surface, out vec3 ambient, out vec3 diffuse, out vec3 specular) {
-
- ambient = g_AmbientLightColor.rgb;
- diffuse = vec3(0.0);
- specular = vec3(0.0);
-
- Shadow_ProcessPssmSlice();
-
-#if LIGHT_DATA_SIZE > 0
- int projIndex = 0;
-
- for (int i = SPOT_SHADOW_LIGHT_START; i < SPOT_SHADOW_LIGHT_END; i += 3) {
- vec3 outDiffuse, outSpecular;
- Lighting_Process(i, surface, outDiffuse, outSpecular, projIndex);
- diffuse += outDiffuse;
- specular += outSpecular;
- }
-
- for (int i = SPOT_LIGHT_START; i < SPOT_LIGHT_END; i += 3) {
- vec3 outDiffuse, outSpecular;
- Lighting_Process(i, surface, outDiffuse, outSpecular, projIndex);
- diffuse += outDiffuse;
- specular += outSpecular;
- }
-
- for (int i = DIR_SHADOW_LIGHT_START; i < DIR_SHADOW_LIGHT_END; i += 2) {
- vec3 outDiffuse, outSpecular;
- Lighting_Process(i, surface, outDiffuse, outSpecular, projIndex);
- diffuse += outDiffuse;
- specular += outSpecular;
- }
-
- for (int i = DIR_LIGHT_START; i < DIR_LIGHT_END; i += 2) {
- vec3 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) {
- vec3 outDiffuse, outSpecular;
- Lighting_Process(i, surface, outDiffuse, outSpecular, projIndex);
- diffuse += outDiffuse;
- specular += outSpecular;
- }
-
- for (int i = POINT_LIGHT_START; i < POINT_LIGHT_END; i += 2) {
- vec3 outDiffuse, outSpecular;
- Lighting_Process(i, surface, outDiffuse, outSpecular, projIndex);
- diffuse += outDiffuse;
- specular += outSpecular;
- }
-
-
-
-#endif
-}
-
-surface_t getSurface() {
- surface_t s;
- s.position = vPos;
- s.normal = normalize(vNormal);
- if (!gl_FrontFacing) {
- s.normal = -s.normal;
- }
- s.viewDir = normalize(g_CameraPosition - s.position);
-#ifdef AMBIENTMAP
- s.ambient = texture2D(m_AmbientMap, vTexCoord).rgb;
-#else
- s.ambient = vec3(1.0);
-#endif
- s.diffuse = vec4(1.0);
- s.specular = vec4(0.04, 0.04, 0.04, 1.0);
- s.roughness = 0.1;
- s.ndotv = max(0.0, dot(s.viewDir, s.normal));
- return s;
-}
-
-void main() {
- vec3 ambient, diffuse, specular;
-
- surface_t surface = getSurface();
- Lighting_ProcessAll(surface, ambient, diffuse, specular);
-
- vec4 color = vec4(1.0);
- color.rgb = ambient * surface.ambient.rgb +
- diffuse * surface.diffuse.rgb +
- specular;
-
- #ifdef DISCARD_ALPHA
- if (color.a < m_AlphaDiscardThreshold) {
- discard;
- }
- #endif
-
- gl_FragColor = color;
-
-/*
- vec4 projCoord = vProjCoord[0];
- projCoord.xyz /= projCoord.w;
- float shad = shadow2D(g_ShadowMapArray, vec4(projCoord.xy, 0.0, projCoord.z)).r;
- vec3 amb = texture2D(m_AmbientMap, vTexCoord).rgb;
- gl_FragColor = vec4(amb * vec3(shad), 1.0);
-*/
-}
\ No newline at end of file
diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/StaticLighting.vert b/jme3-core/src/main/resources/Common/MatDefs/Light/StaticLighting.vert
deleted file mode 100755
index 9a78fa67a3..0000000000
--- a/jme3-core/src/main/resources/Common/MatDefs/Light/StaticLighting.vert
+++ /dev/null
@@ -1,32 +0,0 @@
-#import "Common/ShaderLib/GLSLCompat.glsllib"
-#import "Common/ShaderLib/Skinning.glsllib"
-#import "Common/ShaderLib/Instancing.glsllib"
-#import "Common/ShaderLib/InPassShadows.glsllib"
-
-attribute vec3 inPosition;
-attribute vec3 inNormal;
-attribute vec2 inTexCoord;
-attribute vec4 inColor;
-
-varying vec3 vPos;
-varying vec3 vNormal;
-varying vec2 vTexCoord;
-
-void main() {
- vTexCoord = inTexCoord;
-
- vec4 modelSpacePos = vec4(inPosition, 1.0);
- vec3 modelSpaceNorm = inNormal;
-
- #ifdef NUM_BONES
- Skinning_Compute(modelSpacePos, modelSpaceNorm);
- #endif
-
- vPos = TransformWorld(modelSpacePos).xyz;
- vNormal = TransformWorldNormal(modelSpaceNorm);
-
- vec3 shadowPos = TransformWorld(modelSpacePos).xyz;
- Shadow_ProcessProjCoord(shadowPos);
-
- gl_Position = TransformWorldViewProjection(modelSpacePos);
-}
\ No newline at end of file