From 406c3144d84a7acbe79294b67b7d4c40613824ed Mon Sep 17 00:00:00 2001 From: Kirill Vainer Date: Sat, 9 Sep 2017 13:05:36 -0400 Subject: [PATCH 01/46] Use correct HALF_FLOAT constant for GLES --- .../java/com/jme3/renderer/opengl/GLExt.java | 1 + .../jme3/renderer/opengl/GLImageFormats.java | 26 +++++++++++++------ 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLExt.java b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLExt.java index c77ff6449f..c6d420cc79 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLExt.java +++ b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLExt.java @@ -61,6 +61,7 @@ public interface GLExt { public static final int GL_FRAMEBUFFER_SRGB_CAPABLE_EXT = 0x8DBA; public static final int GL_FRAMEBUFFER_SRGB_EXT = 0x8DB9; public static final int GL_HALF_FLOAT_ARB = 0x140B; + public static final int GL_HALF_FLOAT_OES = 0x8D61; public static final int GL_LUMINANCE16F_ARB = 0x881E; public static final int GL_LUMINANCE32F_ARB = 0x8818; public static final int GL_LUMINANCE_ALPHA16F_ARB = 0x881F; diff --git a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLImageFormats.java b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLImageFormats.java index f12bfd1bc9..5c34ec9746 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLImageFormats.java +++ b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLImageFormats.java @@ -103,14 +103,19 @@ private static void formatCompSrgb(GLImageFormat[][] formatToGL, Image.Format fo public static GLImageFormat[][] getFormatsForCaps(EnumSet caps) { GLImageFormat[][] formatToGL = new GLImageFormat[2][Image.Format.values().length]; + int halfFloatFormat = GLExt.GL_HALF_FLOAT_ARB; + if (caps.contains(Caps.OpenGLES20)) { + halfFloatFormat = GLExt.GL_HALF_FLOAT_OES; + } + // Core Profile Formats (supported by both OpenGL Core 3.3 and OpenGL ES 3.0+) if (caps.contains(Caps.CoreProfile)) { formatSwiz(formatToGL, Format.Alpha8, GL3.GL_R8, GL.GL_RED, GL.GL_UNSIGNED_BYTE); formatSwiz(formatToGL, Format.Luminance8, GL3.GL_R8, GL.GL_RED, GL.GL_UNSIGNED_BYTE); formatSwiz(formatToGL, Format.Luminance8Alpha8, GL3.GL_RG8, GL3.GL_RG, GL.GL_UNSIGNED_BYTE); - formatSwiz(formatToGL, Format.Luminance16F, GL3.GL_R16F, GL.GL_RED, GLExt.GL_HALF_FLOAT_ARB); + formatSwiz(formatToGL, Format.Luminance16F, GL3.GL_R16F, GL.GL_RED, halfFloatFormat); formatSwiz(formatToGL, Format.Luminance32F, GL3.GL_R32F, GL.GL_RED, GL.GL_FLOAT); - formatSwiz(formatToGL, Format.Luminance16FAlpha16F, GL3.GL_RG16F, GL3.GL_RG, GLExt.GL_HALF_FLOAT_ARB); + formatSwiz(formatToGL, Format.Luminance16FAlpha16F, GL3.GL_RG16F, GL3.GL_RG, halfFloatFormat); formatSrgbSwiz(formatToGL, Format.Luminance8, GLExt.GL_SRGB8_EXT, GL.GL_RED, GL.GL_UNSIGNED_BYTE); formatSrgbSwiz(formatToGL, Format.Luminance8Alpha8, GLExt.GL_SRGB8_ALPHA8_EXT, GL3.GL_RG, GL.GL_UNSIGNED_BYTE); @@ -163,6 +168,11 @@ public static GLImageFormat[][] getFormatsForCaps(EnumSet caps) { } format(formatToGL, Format.RGB8, GLExt.GL_RGBA8, GL.GL_RGB, GL.GL_UNSIGNED_BYTE); format(formatToGL, Format.RGBA8, GLExt.GL_RGBA8, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE); + + formatSwiz(formatToGL, Format.BGR8, GL2.GL_RGB8, GL2.GL_RGB, GL.GL_UNSIGNED_BYTE); + formatSwiz(formatToGL, Format.ARGB8, GLExt.GL_RGBA8, GL2.GL_RGBA, GL.GL_UNSIGNED_BYTE); + formatSwiz(formatToGL, Format.BGRA8, GLExt.GL_RGBA8, GL2.GL_RGBA, GL.GL_UNSIGNED_BYTE); + formatSwiz(formatToGL, Format.ABGR8, GLExt.GL_RGBA8, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE); } else { // Actually, the internal format isn't used for OpenGL ES 2! This is the same as the above.. if (!caps.contains(Caps.CoreProfile)) { @@ -182,25 +192,25 @@ public static GLImageFormat[][] getFormatsForCaps(EnumSet caps) { if (caps.contains(Caps.FloatTexture)) { if (!caps.contains(Caps.CoreProfile)) { - format(formatToGL, Format.Luminance16F, GLExt.GL_LUMINANCE16F_ARB, GL.GL_LUMINANCE, GLExt.GL_HALF_FLOAT_ARB); + format(formatToGL, Format.Luminance16F, GLExt.GL_LUMINANCE16F_ARB, GL.GL_LUMINANCE, halfFloatFormat); format(formatToGL, Format.Luminance32F, GLExt.GL_LUMINANCE32F_ARB, GL.GL_LUMINANCE, GL.GL_FLOAT); - format(formatToGL, Format.Luminance16FAlpha16F, GLExt.GL_LUMINANCE_ALPHA16F_ARB, GL.GL_LUMINANCE_ALPHA, GLExt.GL_HALF_FLOAT_ARB); + format(formatToGL, Format.Luminance16FAlpha16F, GLExt.GL_LUMINANCE_ALPHA16F_ARB, GL.GL_LUMINANCE_ALPHA, halfFloatFormat); } - format(formatToGL, Format.RGB16F, GLExt.GL_RGB16F_ARB, GL.GL_RGB, GLExt.GL_HALF_FLOAT_ARB); + format(formatToGL, Format.RGB16F, GLExt.GL_RGB16F_ARB, GL.GL_RGB, halfFloatFormat); format(formatToGL, Format.RGB32F, GLExt.GL_RGB32F_ARB, GL.GL_RGB, GL.GL_FLOAT); - format(formatToGL, Format.RGBA16F, GLExt.GL_RGBA16F_ARB, GL.GL_RGBA, GLExt.GL_HALF_FLOAT_ARB); + format(formatToGL, Format.RGBA16F, GLExt.GL_RGBA16F_ARB, GL.GL_RGBA, halfFloatFormat); format(formatToGL, Format.RGBA32F, GLExt.GL_RGBA32F_ARB, GL.GL_RGBA, GL.GL_FLOAT); } if (caps.contains(Caps.PackedFloatTexture)) { format(formatToGL, Format.RGB111110F, GLExt.GL_R11F_G11F_B10F_EXT, GL.GL_RGB, GLExt.GL_UNSIGNED_INT_10F_11F_11F_REV_EXT); if (caps.contains(Caps.FloatTexture)) { - format(formatToGL, Format.RGB16F_to_RGB111110F, GLExt.GL_R11F_G11F_B10F_EXT, GL.GL_RGB, GLExt.GL_HALF_FLOAT_ARB); + format(formatToGL, Format.RGB16F_to_RGB111110F, GLExt.GL_R11F_G11F_B10F_EXT, GL.GL_RGB, halfFloatFormat); } } if (caps.contains(Caps.SharedExponentTexture)) { format(formatToGL, Format.RGB9E5, GLExt.GL_RGB9_E5_EXT, GL.GL_RGB, GLExt.GL_UNSIGNED_INT_5_9_9_9_REV_EXT); if (caps.contains(Caps.FloatTexture)) { - format(formatToGL, Format.RGB16F_to_RGB9E5, GLExt.GL_RGB9_E5_EXT, GL.GL_RGB, GLExt.GL_HALF_FLOAT_ARB); + format(formatToGL, Format.RGB16F_to_RGB9E5, GLExt.GL_RGB9_E5_EXT, GL.GL_RGB, halfFloatFormat); } } From 259694605e03fc323aef45570d58fc27c7b14f77 Mon Sep 17 00:00:00 2001 From: Kirill Vainer Date: Sat, 9 Sep 2017 13:07:08 -0400 Subject: [PATCH 02/46] Support GLTracer and GL debug in Android --- .../com/jme3/system/android/OGLESContext.java | 10 ++++++++-- .../java/com/jme3/renderer/opengl/GLTracer.java | 15 ++++++++------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/jme3-android/src/main/java/com/jme3/system/android/OGLESContext.java b/jme3-android/src/main/java/com/jme3/system/android/OGLESContext.java index 35c3c3911b..508e810656 100644 --- a/jme3-android/src/main/java/com/jme3/system/android/OGLESContext.java +++ b/jme3-android/src/main/java/com/jme3/system/android/OGLESContext.java @@ -53,9 +53,11 @@ import com.jme3.input.dummy.DummyMouseInput; import com.jme3.renderer.android.AndroidGL; import com.jme3.renderer.opengl.GL; +import com.jme3.renderer.opengl.GLDebugES; import com.jme3.renderer.opengl.GLExt; import com.jme3.renderer.opengl.GLFbo; import com.jme3.renderer.opengl.GLRenderer; +import com.jme3.renderer.opengl.GLTracer; import com.jme3.system.*; import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Level; @@ -195,8 +197,12 @@ public void uncaughtException(Thread thread, Throwable thrown) { timer = new NanoTimer(); Object gl = new AndroidGL(); - // gl = GLTracer.createGlesTracer((GL)gl, (GLExt)gl); - // gl = new GLDebugES((GL)gl, (GLExt)gl); + if (settings.getBoolean("GraphicsDebug")) { + gl = new GLDebugES((GL) gl, (GLExt) gl, (GLFbo) gl); + } + if (settings.getBoolean("GraphicsTrace")) { + gl = GLTracer.createGlesTracer(gl, GL.class, GLFbo.class, GLExt.class); + } renderer = new GLRenderer((GL)gl, (GLExt)gl, (GLFbo)gl); renderer.initialize(); 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 f252d22dcb..82d16910aa 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 @@ -165,16 +165,17 @@ private static IntMap generateConstantMap(Class ... classes) { /** * Creates a tracer implementation that wraps OpenGL ES 2. - * + * * @param glInterface OGL object to wrap - * @param glInterfaceClass The interface to implement + * @param glInterfaceClasses The interface(s) to implement * @return A tracer that implements the given interface */ - public static Object createGlesTracer(Object glInterface, Class glInterfaceClass) { - IntMap constMap = generateConstantMap(GL.class, GLFbo.class, GLExt.class); - return Proxy.newProxyInstance(glInterface.getClass().getClassLoader(), - new Class[] { glInterfaceClass }, - new GLTracer(glInterface, constMap)); + public static Object createGlesTracer(Object glInterface, Class... glInterfaceClasses) { + IntMap constMap = generateConstantMap(GL.class, GL2.class, GL3.class, GLFbo.class, GLExt.class); + return Proxy.newProxyInstance( + glInterface.getClass().getClassLoader(), + glInterfaceClasses, + new GLTracer(glInterface, constMap)); } /** From 69139a1e9593f234bd32f7f00a27645d64c80b2c Mon Sep 17 00:00:00 2001 From: Kirill Vainer Date: Sat, 9 Sep 2017 13:07:52 -0400 Subject: [PATCH 03/46] Support instancing in GLTracer --- .../src/main/java/com/jme3/renderer/opengl/GLTracer.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 82d16910aa..003b97bef4 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 @@ -99,6 +99,7 @@ private static void noEnumArgs(String method, int... argSlots) { noEnumArgs("glEnableVertexAttribArray", 0); noEnumArgs("glDisableVertexAttribArray", 0); noEnumArgs("glVertexAttribPointer", 0, 1, 4, 5); + noEnumArgs("glVertexAttribDivisorARB", 0, 1); noEnumArgs("glDrawRangeElements", 1, 2, 3, 5); noEnumArgs("glDrawArrays", 1, 2); noEnumArgs("glDeleteBuffers", 0); @@ -302,7 +303,8 @@ private void printMethodName(String methodName) { // will be printed in darker color methodName = methodName.substring(2); if (methodName.equals("Clear") - || methodName.equals("DrawRangeElements")) { + || methodName.equals("DrawRangeElements") + || methodName.equals("DrawElementsInstancedARB")) { print(methodName); } else { if (methodName.endsWith("EXT")) { From 23700d5140c106ede658c3deec0fd0054b1c1116 Mon Sep 17 00:00:00 2001 From: Kirill Vainer Date: Sat, 9 Sep 2017 13:08:37 -0400 Subject: [PATCH 04/46] Don't use unsupported TEXTURE_{BASE,MAX}_LEVEL in GLES --- jme3-core/src/main/java/com/jme3/renderer/opengl/GL.java | 2 -- jme3-core/src/main/java/com/jme3/renderer/opengl/GL2.java | 2 ++ .../main/java/com/jme3/renderer/opengl/GLRenderer.java | 8 ++++++-- .../src/main/java/com/jme3/renderer/opengl/GLTracer.java | 4 ++-- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/renderer/opengl/GL.java b/jme3-core/src/main/java/com/jme3/renderer/opengl/GL.java index 5aa2cdb83f..45e4ce7159 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/opengl/GL.java +++ b/jme3-core/src/main/java/com/jme3/renderer/opengl/GL.java @@ -173,9 +173,7 @@ public interface GL { public static final int GL_TEXTURE_CUBE_MAP_NEGATIVE_Y = 0x8518; public static final int GL_TEXTURE_CUBE_MAP_POSITIVE_Z = 0x8519; public static final int GL_TEXTURE_CUBE_MAP_NEGATIVE_Z = 0x851A; - public static final int GL_TEXTURE_BASE_LEVEL = 0x813C; public static final int GL_TEXTURE_MAG_FILTER = 0x2800; - public static final int GL_TEXTURE_MAX_LEVEL = 0x813D; public static final int GL_TEXTURE_MIN_FILTER = 0x2801; public static final int GL_TEXTURE_WRAP_S = 0x2802; public static final int GL_TEXTURE_WRAP_T = 0x2803; diff --git a/jme3-core/src/main/java/com/jme3/renderer/opengl/GL2.java b/jme3-core/src/main/java/com/jme3/renderer/opengl/GL2.java index abf6a77d7b..8f7bb2f845 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/opengl/GL2.java +++ b/jme3-core/src/main/java/com/jme3/renderer/opengl/GL2.java @@ -65,6 +65,8 @@ public interface GL2 extends GL { public static final int GL_STACK_OVERFLOW = 0x503; public static final int GL_STACK_UNDERFLOW = 0x504; public static final int GL_TEXTURE_3D = 0x806F; + public static final int GL_TEXTURE_BASE_LEVEL = 0x813C; + public static final int GL_TEXTURE_MAX_LEVEL = 0x813D; public static final int GL_POINT_SPRITE = 0x8861; public static final int GL_TEXTURE_COMPARE_FUNC = 0x884D; public static final int GL_TEXTURE_COMPARE_MODE = 0x884C; diff --git a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java index db018cc642..97c6af85ed 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java +++ b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java @@ -2197,11 +2197,15 @@ public void updateTexImageData(Image img, Texture.Type type, int unit, boolean s } else if (img.hasMipmaps()) { // Image already has mipmaps, set the max level based on the // number of mipmaps we have. - gl.glTexParameteri(target, GL.GL_TEXTURE_MAX_LEVEL, img.getMipMapSizes().length - 1); + if (caps.contains(Caps.OpenGL20)) { + gl.glTexParameteri(target, GL2.GL_TEXTURE_MAX_LEVEL, img.getMipMapSizes().length - 1); + } } else { // Image does not have mipmaps and they are not required. // Specify that that the texture has no mipmaps. - gl.glTexParameteri(target, GL.GL_TEXTURE_MAX_LEVEL, 0); + if (caps.contains(Caps.OpenGL20)) { + gl.glTexParameteri(target, GL2.GL_TEXTURE_MAX_LEVEL, 0); + } } int imageSamples = img.getMultiSamples(); 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 003b97bef4..3bfad2c069 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 @@ -366,8 +366,8 @@ private void printArgsTexParameter(Object[] args) { printEnum(param); print(", "); - if (param == GL.GL_TEXTURE_BASE_LEVEL - || param == GL.GL_TEXTURE_MAX_LEVEL) { + if (param == GL2.GL_TEXTURE_BASE_LEVEL + || param == GL2.GL_TEXTURE_MAX_LEVEL) { printInt(value); } else { printEnum(value); From 7a22f8c9409c0a03d8bc3133381e4e19d6aa2851 Mon Sep 17 00:00:00 2001 From: Kirill Vainer Date: Sat, 9 Sep 2017 13:10:38 -0400 Subject: [PATCH 05/46] Support ABGR8 using swizzle extension --- .../src/main/java/com/jme3/renderer/opengl/GL.java | 1 + .../java/com/jme3/renderer/opengl/TextureUtil.java | 11 +++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/renderer/opengl/GL.java b/jme3-core/src/main/java/com/jme3/renderer/opengl/GL.java index 45e4ce7159..19bdfffffb 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/opengl/GL.java +++ b/jme3-core/src/main/java/com/jme3/renderer/opengl/GL.java @@ -50,6 +50,7 @@ public interface GL { public static final int GL_ARRAY_BUFFER = 0x8892; public static final int GL_BACK = 0x405; public static final int GL_BLEND = 0xBE2; + public static final int GL_BLUE = 0x1905; public static final int GL_BYTE = 0x1400; public static final int GL_CLAMP_TO_EDGE = 0x812F; public static final int GL_COLOR_BUFFER_BIT = 0x4000; diff --git a/jme3-core/src/main/java/com/jme3/renderer/opengl/TextureUtil.java b/jme3-core/src/main/java/com/jme3/renderer/opengl/TextureUtil.java index fb60323935..305da6d83b 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/opengl/TextureUtil.java +++ b/jme3-core/src/main/java/com/jme3/renderer/opengl/TextureUtil.java @@ -32,7 +32,6 @@ package com.jme3.renderer.opengl; import com.jme3.renderer.Caps; -import com.jme3.renderer.RenderContext; import com.jme3.renderer.RendererException; import com.jme3.texture.Image; import com.jme3.texture.Image.Format; @@ -91,7 +90,7 @@ public GLImageFormat getImageFormat(Format fmt, boolean isSrgb) { public GLImageFormat getImageFormatWithError(Format fmt, boolean isSrgb) { //if the passed format is one kind of depth there isno point in getting the srgb format; - isSrgb = isSrgb && fmt != Format.Depth && fmt != Format.Depth16 && fmt != Format.Depth24 && fmt != Format.Depth24Stencil8 && fmt != Format.Depth32 && fmt != Format.Depth32F; + isSrgb = isSrgb && !fmt.isDepthFormat(); GLImageFormat glFmt = getImageFormat(fmt, isSrgb); if (glFmt == null && isSrgb) { glFmt = getImageFormat(fmt, false); @@ -127,6 +126,14 @@ private void setupTextureSwizzle(int target, Format format) { gl.glTexParameteri(target, GL3.GL_TEXTURE_SWIZZLE_B, GL.GL_RED); gl.glTexParameteri(target, GL3.GL_TEXTURE_SWIZZLE_A, GL.GL_GREEN); break; + case ABGR8: + gl.glTexParameteri(target, GL3.GL_TEXTURE_SWIZZLE_R, GL.GL_ALPHA); + gl.glTexParameteri(target, GL3.GL_TEXTURE_SWIZZLE_G, GL.GL_BLUE); + gl.glTexParameteri(target, GL3.GL_TEXTURE_SWIZZLE_B, GL.GL_GREEN); + gl.glTexParameteri(target, GL3.GL_TEXTURE_SWIZZLE_A, GL.GL_RED); + break; + default: + throw new UnsupportedOperationException(); } } From af3a0c70ce4fd94d930b9b5b06f6398235456519 Mon Sep 17 00:00:00 2001 From: Kirill Vainer Date: Sat, 9 Sep 2017 13:16:21 -0400 Subject: [PATCH 06/46] Move glFramebufferTextureLayer to GLFbo --- .../src/main/java/com/jme3/renderer/android/AndroidGL.java | 5 +++++ jme3-core/src/main/java/com/jme3/renderer/opengl/GL3.java | 1 - .../main/java/com/jme3/renderer/opengl/GLDebugDesktop.java | 6 ------ .../src/main/java/com/jme3/renderer/opengl/GLDebugES.java | 7 +++++++ .../src/main/java/com/jme3/renderer/opengl/GLFbo.java | 1 + .../src/main/java/com/jme3/renderer/opengl/GLRenderer.java | 2 +- .../src/main/java/com/jme3/renderer/opengl/GLTracer.java | 1 + jme3-ios/src/main/java/com/jme3/renderer/ios/IosGL.java | 5 +++++ jme3-jogl/src/main/java/com/jme3/renderer/jogl/JoglGL.java | 6 ------ .../src/main/java/com/jme3/renderer/jogl/JoglGLFbo.java | 5 +++++ .../src/main/java/com/jme3/renderer/lwjgl/LwjglGL.java | 5 ----- .../main/java/com/jme3/renderer/lwjgl/LwjglGLFboEXT.java | 6 ++++++ .../main/java/com/jme3/renderer/lwjgl/LwjglGLFboGL3.java | 5 +++++ .../src/main/java/com/jme3/renderer/lwjgl/LwjglGL.java | 7 ------- .../main/java/com/jme3/renderer/lwjgl/LwjglGLFboEXT.java | 6 ++++++ .../main/java/com/jme3/renderer/lwjgl/LwjglGLFboGL3.java | 5 +++++ 16 files changed, 47 insertions(+), 26 deletions(-) diff --git a/jme3-android/src/main/java/com/jme3/renderer/android/AndroidGL.java b/jme3-android/src/main/java/com/jme3/renderer/android/AndroidGL.java index 3541eaa631..44e931104a 100644 --- a/jme3-android/src/main/java/com/jme3/renderer/android/AndroidGL.java +++ b/jme3-android/src/main/java/com/jme3/renderer/android/AndroidGL.java @@ -561,4 +561,9 @@ public Object glFenceSync(int condition, int flags) { public void glBlendEquationSeparate(int colorMode, int alphaMode) { GLES20.glBlendEquationSeparate(colorMode, alphaMode); } + + @Override + public void glFramebufferTextureLayerEXT(int target, int attachment, int texture, int level, int layer) { + throw new UnsupportedOperationException("OpenGL ES 2 does not support texture arrays"); + } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/opengl/GL3.java b/jme3-core/src/main/java/com/jme3/renderer/opengl/GL3.java index 9b01e46a54..b3e1125458 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/opengl/GL3.java +++ b/jme3-core/src/main/java/com/jme3/renderer/opengl/GL3.java @@ -86,7 +86,6 @@ public interface GL3 extends GL2 { public void glBindFragDataLocation(int param1, int param2, String param3); /// GL3+ public void glBindVertexArray(int param1); /// GL3+ public void glDeleteVertexArrays(IntBuffer arrays); /// GL3+ - public void glFramebufferTextureLayer(int param1, int param2, int param3, int param4, int param5); /// GL3+ public void glGenVertexArrays(IntBuffer param1); /// GL3+ public String glGetString(int param1, int param2); /// GL3+ } diff --git a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLDebugDesktop.java b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLDebugDesktop.java index 44dc3687ab..a945a1d853 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLDebugDesktop.java +++ b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLDebugDesktop.java @@ -95,12 +95,6 @@ public void glPatchParameter(int count) { checkError(); } - @Override - public void glFramebufferTextureLayer(int param1, int param2, int param3, int param4, int param5) { - gl3.glFramebufferTextureLayer(param1, param2, param3, param4, param5); - checkError(); - } - public void glBlendEquationSeparate(int colorMode, int alphaMode) { gl.glBlendEquationSeparate(colorMode, alphaMode); checkError(); 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 412d738f5a..8746d57edc 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 @@ -598,8 +598,15 @@ public Object glFenceSync(int condition, int flags) { return sync; } + @Override public void glBlendEquationSeparate(int colorMode, int alphaMode) { gl.glBlendEquationSeparate(colorMode, alphaMode); checkError(); } + + @Override + public void glFramebufferTextureLayerEXT(int param1, int param2, int param3, int param4, int param5) { + glfbo.glFramebufferTextureLayerEXT(param1, param2, param3, param4, param5); + checkError(); + } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLFbo.java b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLFbo.java index 737019ce25..97a5792035 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLFbo.java +++ b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLFbo.java @@ -89,6 +89,7 @@ public interface GLFbo { public void glDeleteRenderbuffersEXT(IntBuffer param1); public void glFramebufferRenderbufferEXT(int param1, int param2, int param3, int param4); public void glFramebufferTexture2DEXT(int param1, int param2, int param3, int param4, int param5); + public void glFramebufferTextureLayerEXT(int target, int attachment, int texture, int level, int layer); public void glGenFramebuffersEXT(IntBuffer param1); public void glGenRenderbuffersEXT(IntBuffer param1); public void glGenerateMipmapEXT(int param1); diff --git a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java index 97c6af85ed..902ef38420 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java +++ b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java @@ -1581,7 +1581,7 @@ public void updateRenderTexture(FrameBuffer fb, RenderBuffer rb) { image.getId(), 0); } else { - gl3.glFramebufferTextureLayer(GLFbo.GL_FRAMEBUFFER_EXT, + glfbo.glFramebufferTextureLayerEXT(GLFbo.GL_FRAMEBUFFER_EXT, convertAttachmentSlot(rb.getSlot()), image.getId(), 0, 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 3bfad2c069..ae3f17a8ca 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 @@ -112,6 +112,7 @@ private static void noEnumArgs(String method, int... argSlots) { noEnumArgs("glRenderbufferStorageMultisampleEXT", 1, 3, 4); noEnumArgs("glFramebufferRenderbufferEXT", 3); noEnumArgs("glFramebufferTexture2DEXT", 3, 4); + noEnumArgs("glFramebufferTextureLayerEXT", 2, 3, 4); noEnumArgs("glBlitFramebufferEXT", 0, 1, 2, 3, 4, 5, 6, 7, 8); noEnumArgs("glCreateProgram", -1); diff --git a/jme3-ios/src/main/java/com/jme3/renderer/ios/IosGL.java b/jme3-ios/src/main/java/com/jme3/renderer/ios/IosGL.java index 95e8a213ba..826ce82a2d 100644 --- a/jme3-ios/src/main/java/com/jme3/renderer/ios/IosGL.java +++ b/jme3-ios/src/main/java/com/jme3/renderer/ios/IosGL.java @@ -611,4 +611,9 @@ public void glDeleteSync(Object sync) { public Object glFenceSync(int condition, int flags) { throw new UnsupportedOperationException("OpenGL ES 2 does not support sync fences"); } + + @Override + public void glFramebufferTextureLayerEXT(int target, int attachment, int texture, int level, int layer) { + throw new UnsupportedOperationException("OpenGL ES 2 does not support texture arrays"); + } } diff --git a/jme3-jogl/src/main/java/com/jme3/renderer/jogl/JoglGL.java b/jme3-jogl/src/main/java/com/jme3/renderer/jogl/JoglGL.java index e927b4bb79..e6435e5c52 100644 --- a/jme3-jogl/src/main/java/com/jme3/renderer/jogl/JoglGL.java +++ b/jme3-jogl/src/main/java/com/jme3/renderer/jogl/JoglGL.java @@ -634,10 +634,4 @@ public void glDeleteVertexArrays(IntBuffer arrays) { checkLimit(arrays); GLContext.getCurrentGL().getGL2ES3().glDeleteVertexArrays(arrays.limit(), arrays); } - - @Override - public void glFramebufferTextureLayer(int param1, int param2, int param3, int param4, int param5) { - GLContext.getCurrentGL().getGL3().glFramebufferTextureLayer(param1, param2, param3, param4, param5); - } - } diff --git a/jme3-jogl/src/main/java/com/jme3/renderer/jogl/JoglGLFbo.java b/jme3-jogl/src/main/java/com/jme3/renderer/jogl/JoglGLFbo.java index 2691d2e24d..b3451be253 100644 --- a/jme3-jogl/src/main/java/com/jme3/renderer/jogl/JoglGLFbo.java +++ b/jme3-jogl/src/main/java/com/jme3/renderer/jogl/JoglGLFbo.java @@ -94,4 +94,9 @@ public void glGenerateMipmapEXT(int param1) { public void glRenderbufferStorageEXT(int param1, int param2, int param3, int param4) { GLContext.getCurrentGL().glRenderbufferStorage(param1, param2, param3, param4); } + + @Override + public void glFramebufferTextureLayerEXT(int param1, int param2, int param3, int param4, int param5) { + GLContext.getCurrentGL().getGL3().glFramebufferTextureLayer(param1, param2, param3, param4, param5); + } } diff --git a/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/LwjglGL.java b/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/LwjglGL.java index c2694988c8..5a74e06f01 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/LwjglGL.java +++ b/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/LwjglGL.java @@ -493,9 +493,4 @@ public void glDeleteVertexArrays(IntBuffer arrays) { checkLimit(arrays); ARBVertexArrayObject.glDeleteVertexArrays(arrays); } - - @Override - public void glFramebufferTextureLayer(int param1, int param2, int param3, int param4, int param5) { - GL30.glFramebufferTextureLayer(param1, param2, param3, param4, param5); - } } diff --git a/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/LwjglGLFboEXT.java b/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/LwjglGLFboEXT.java index 40571f5ed9..8f746b4d4e 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/LwjglGLFboEXT.java +++ b/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/LwjglGLFboEXT.java @@ -7,6 +7,7 @@ import org.lwjgl.opengl.EXTFramebufferBlit; import org.lwjgl.opengl.EXTFramebufferMultisample; import org.lwjgl.opengl.EXTFramebufferObject; +import org.lwjgl.opengl.EXTTextureArray; /** * Implements GLFbo via GL_EXT_framebuffer_object. @@ -95,4 +96,9 @@ public void glGenerateMipmapEXT(int param1) { public void glRenderbufferStorageEXT(int param1, int param2, int param3, int param4) { EXTFramebufferObject.glRenderbufferStorageEXT(param1, param2, param3, param4); } + + @Override + public void glFramebufferTextureLayerEXT(int target, int attachment, int texture, int level, int layer) { + EXTTextureArray.glFramebufferTextureLayerEXT(target, attachment, texture, level, layer); + } } diff --git a/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/LwjglGLFboGL3.java b/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/LwjglGLFboGL3.java index 14e0cc9e62..bec41d17f4 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/LwjglGLFboGL3.java +++ b/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/LwjglGLFboGL3.java @@ -93,4 +93,9 @@ public void glGenerateMipmapEXT(int param1) { public void glRenderbufferStorageEXT(int param1, int param2, int param3, int param4) { GL30.glRenderbufferStorage(param1, param2, param3, param4); } + + @Override + public void glFramebufferTextureLayerEXT(int param1, int param2, int param3, int param4, int param5) { + GL30.glFramebufferTextureLayer(param1, param2, param3, param4, param5); + } } diff --git a/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGL.java b/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGL.java index a905c9f018..915b185d1d 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGL.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGL.java @@ -36,8 +36,6 @@ import com.jme3.renderer.opengl.GL2; import com.jme3.renderer.opengl.GL3; import com.jme3.renderer.opengl.GL4; -import com.jme3.system.NativeLibraryLoader; -import com.jme3.system.Platform; import org.lwjgl.opengl.*; import java.nio.*; @@ -519,9 +517,4 @@ public void glDeleteVertexArrays(IntBuffer arrays) { checkLimit(arrays); ARBVertexArrayObject.glDeleteVertexArrays(arrays); } - - @Override - public void glFramebufferTextureLayer(int param1, int param2, int param3, int param4, int param5) { - GL30.glFramebufferTextureLayer(param1, param2, param3, param4, param5); - } } diff --git a/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGLFboEXT.java b/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGLFboEXT.java index 5d9fe8dc1b..ce2ebe806a 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGLFboEXT.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGLFboEXT.java @@ -39,6 +39,7 @@ import java.nio.Buffer; import java.nio.IntBuffer; +import org.lwjgl.opengl.EXTTextureArray; /** * Implements GLFbo via GL_EXT_framebuffer_object. @@ -127,4 +128,9 @@ public void glGenerateMipmapEXT(int param1) { public void glRenderbufferStorageEXT(int param1, int param2, int param3, int param4) { EXTFramebufferObject.glRenderbufferStorageEXT(param1, param2, param3, param4); } + + @Override + public void glFramebufferTextureLayerEXT(int target, int attachment, int texture, int level, int layer) { + EXTTextureArray.glFramebufferTextureLayerEXT(target, attachment, texture, level, layer); + } } diff --git a/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGLFboGL3.java b/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGLFboGL3.java index 5a7a9825eb..39ed0a647c 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGLFboGL3.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGLFboGL3.java @@ -125,4 +125,9 @@ public void glGenerateMipmapEXT(int param1) { public void glRenderbufferStorageEXT(int param1, int param2, int param3, int param4) { GL30.glRenderbufferStorage(param1, param2, param3, param4); } + + @Override + public void glFramebufferTextureLayerEXT(int param1, int param2, int param3, int param4, int param5) { + GL30.glFramebufferTextureLayer(param1, param2, param3, param4, param5); + } } From b0316e419c4c79754feebeeaa0a992bca31e5c03 Mon Sep 17 00:00:00 2001 From: Kirill Vainer Date: Sat, 9 Sep 2017 13:30:06 -0400 Subject: [PATCH 07/46] Avoid RGB111110F in filters unless its actually supported --- jme3-core/src/main/java/com/jme3/post/Filter.java | 7 ++----- .../java/com/jme3/post/FilterPostProcessor.java | 14 +++++++++++--- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/post/Filter.java b/jme3-core/src/main/java/com/jme3/post/Filter.java index b162ed5111..ff1f71017a 100644 --- a/jme3-core/src/main/java/com/jme3/post/Filter.java +++ b/jme3-core/src/main/java/com/jme3/post/Filter.java @@ -213,13 +213,10 @@ public String toString() { } /** - * returns the default pass texture format - * default is {@link Format#RGB111110F} - * - * @return + * returns the default pass texture format. */ protected Format getDefaultPassTextureFormat() { - return Format.RGB111110F; + return processor.getDefaultPassTextureFormat(); } /** diff --git a/jme3-core/src/main/java/com/jme3/post/FilterPostProcessor.java b/jme3-core/src/main/java/com/jme3/post/FilterPostProcessor.java index 7ccbbe5ae3..14539c53d1 100644 --- a/jme3-core/src/main/java/com/jme3/post/FilterPostProcessor.java +++ b/jme3-core/src/main/java/com/jme3/post/FilterPostProcessor.java @@ -143,9 +143,13 @@ public void initialize(RenderManager rm, ViewPort vp) { fsQuad = new Picture("filter full screen quad"); fsQuad.setWidth(1); fsQuad.setHeight(1); - - if (fbFormat == Format.RGB111110F && !renderer.getCaps().contains(Caps.PackedFloatTexture)) { - fbFormat = Format.RGB8; + + if (!renderer.getCaps().contains(Caps.PackedFloatTexture)) { + if (!renderer.getCaps().contains(Caps.FloatTexture)) { + fbFormat = Format.RGB8; + } else { + fbFormat = Format.RGB16F; + } } Camera cam = vp.getCamera(); @@ -161,6 +165,10 @@ public void initialize(RenderManager rm, ViewPort vp) { reshape(vp, cam.getWidth(), cam.getHeight()); } + public Format getDefaultPassTextureFormat() { + return fbFormat; + } + /** * init the given filter * @param filter From 88aaa079e3b8293a71c35c7751f5436e00ed6fc4 Mon Sep 17 00:00:00 2001 From: Kirill Vainer Date: Sat, 9 Sep 2017 13:30:43 -0400 Subject: [PATCH 08/46] Use the same depth format in all places in FPP --- .../main/java/com/jme3/post/FilterPostProcessor.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/post/FilterPostProcessor.java b/jme3-core/src/main/java/com/jme3/post/FilterPostProcessor.java index 14539c53d1..8abda3da4d 100644 --- a/jme3-core/src/main/java/com/jme3/post/FilterPostProcessor.java +++ b/jme3-core/src/main/java/com/jme3/post/FilterPostProcessor.java @@ -66,7 +66,7 @@ public class FilterPostProcessor implements SceneProcessor, Savable { private FrameBuffer renderFrameBuffer; private Texture2D filterTexture; private Texture2D depthTexture; - private SafeArrayList filters = new SafeArrayList(Filter.class); + private SafeArrayList filters = new SafeArrayList<>(Filter.class); private AssetManager assetManager; private Picture fsQuad; private boolean computeDepth = false; @@ -85,6 +85,7 @@ public class FilterPostProcessor implements SceneProcessor, Savable { private AppProfiler prof; private Format fbFormat = Format.RGB111110F; + private Format depthFormat = Format.Depth; /** * Create a FilterProcessor @@ -178,7 +179,7 @@ private void initFilter(Filter filter, ViewPort vp) { filter.setProcessor(this); if (filter.isRequiresDepthTexture()) { if (!computeDepth && renderFrameBuffer != null) { - depthTexture = new Texture2D(width, height, Format.Depth24); + depthTexture = new Texture2D(width, height, depthFormat); renderFrameBuffer.setDepthTexture(depthTexture); } computeDepth = true; @@ -477,20 +478,20 @@ public void reshape(ViewPort vp, int w, int h) { renderFrameBufferMS = new FrameBuffer(width, height, numSamples); if (caps.contains(Caps.OpenGL32)) { Texture2D msColor = new Texture2D(width, height, numSamples, fbFormat); - Texture2D msDepth = new Texture2D(width, height, numSamples, Format.Depth); + Texture2D msDepth = new Texture2D(width, height, numSamples, depthFormat); renderFrameBufferMS.setDepthTexture(msDepth); renderFrameBufferMS.setColorTexture(msColor); filterTexture = msColor; depthTexture = msDepth; } else { - renderFrameBufferMS.setDepthBuffer(Format.Depth); + renderFrameBufferMS.setDepthBuffer(depthFormat); renderFrameBufferMS.setColorBuffer(fbFormat); } } if (numSamples <= 1 || !caps.contains(Caps.OpenGL32)) { renderFrameBuffer = new FrameBuffer(width, height, 1); - renderFrameBuffer.setDepthBuffer(Format.Depth); + renderFrameBuffer.setDepthBuffer(depthFormat); filterTexture = new Texture2D(width, height, fbFormat); renderFrameBuffer.setColorTexture(filterTexture); } From 74418653074a79c1348ed157d93eda526a2b8daf Mon Sep 17 00:00:00 2001 From: Kirill Vainer Date: Sat, 9 Sep 2017 13:32:15 -0400 Subject: [PATCH 09/46] Print the object with the problem in NativeObjectManager --- .../src/main/java/com/jme3/util/NativeObjectManager.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/util/NativeObjectManager.java b/jme3-core/src/main/java/com/jme3/util/NativeObjectManager.java index 84e7319621..9df5853ca3 100644 --- a/jme3-core/src/main/java/com/jme3/util/NativeObjectManager.java +++ b/jme3-core/src/main/java/com/jme3/util/NativeObjectManager.java @@ -133,8 +133,8 @@ private void deleteNativeObject(Object rendererObject, NativeObject obj, NativeO // Unregister it from cleanup list. NativeObjectRef ref2 = refMap.remove(obj.getUniqueId()); if (ref2 == null) { - throw new IllegalArgumentException("This NativeObject is not " + - "registered in this NativeObjectManager"); + throw new IllegalArgumentException("The " + obj + " NativeObject is not " + + "registered in this NativeObjectManager"); } assert ref == null || ref == ref2; From bc50b09bf4edc7feb78cf293c933543d5d123000 Mon Sep 17 00:00:00 2001 From: Kirill Vainer Date: Sat, 9 Sep 2017 13:43:46 -0400 Subject: [PATCH 10/46] Don't upload NULL texture slices --- .../src/main/java/com/jme3/renderer/opengl/TextureUtil.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/jme3-core/src/main/java/com/jme3/renderer/opengl/TextureUtil.java b/jme3-core/src/main/java/com/jme3/renderer/opengl/TextureUtil.java index 305da6d83b..7adc3ff19f 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/opengl/TextureUtil.java +++ b/jme3-core/src/main/java/com/jme3/renderer/opengl/TextureUtil.java @@ -199,10 +199,12 @@ private void uploadTextureLevel(GLImageFormat format, int target, int level, int format.format, format.dataType, data); - } else { + } else if (data != null) { // For texture arrays, only upload 1 slice at a time. // zoffset specifies slice index, and depth is 1 to indicate // a single texture in the array. + // We don't need to do this for NULL data because the + // main texture storage was already allocated with slice == -1 gl2.glTexSubImage3D(target, level, // level 0, // xoffset From 16e472678abd38bf1c9e577a1bc2971dac8c4c8c Mon Sep 17 00:00:00 2001 From: Kirill Vainer Date: Sat, 9 Sep 2017 13:45:40 -0400 Subject: [PATCH 11/46] Support shadow maps in GLES --- jme3-core/src/main/resources/Common/ShaderLib/GLSLCompat.glsllib | 1 + 1 file changed, 1 insertion(+) diff --git a/jme3-core/src/main/resources/Common/ShaderLib/GLSLCompat.glsllib b/jme3-core/src/main/resources/Common/ShaderLib/GLSLCompat.glsllib index c1ace91d12..2a035e2f52 100644 --- a/jme3-core/src/main/resources/Common/ShaderLib/GLSLCompat.glsllib +++ b/jme3-core/src/main/resources/Common/ShaderLib/GLSLCompat.glsllib @@ -25,6 +25,7 @@ out vec4 outFragColor; # define texture3D texture # define textureCube texture # define texture2DLod textureLod +# define shadow2D(a,b) vec4(texture(a,b)) # define textureCubeLod textureLod # if defined VERTEX_SHADER # define varying out From 2ce2995956bab258931db8caa426336f5d1ed54d Mon Sep 17 00:00:00 2001 From: Kirill Vainer Date: Sat, 9 Sep 2017 13:47:35 -0400 Subject: [PATCH 12/46] Don't reset lights that were never checked in light filter --- jme3-core/src/main/java/com/jme3/light/DefaultLightFilter.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/jme3-core/src/main/java/com/jme3/light/DefaultLightFilter.java b/jme3-core/src/main/java/com/jme3/light/DefaultLightFilter.java index 84cdc17fc3..2710e6a29e 100644 --- a/jme3-core/src/main/java/com/jme3/light/DefaultLightFilter.java +++ b/jme3-core/src/main/java/com/jme3/light/DefaultLightFilter.java @@ -42,7 +42,7 @@ public final class DefaultLightFilter implements LightFilter { private Camera camera; - private final HashSet processedLights = new HashSet(); + private final HashSet processedLights = new HashSet<>(); private final LightProbeBlendingStrategy probeBlendStrat; public DefaultLightFilter() { @@ -59,6 +59,7 @@ public void setCamera(Camera camera) { for (Light light : processedLights) { light.frustumCheckNeeded = true; } + processedLights.clear(); } @Override From f5ad0274b3367afaa2e7b995547b0409f28dadf9 Mon Sep 17 00:00:00 2001 From: Kirill Vainer Date: Sat, 9 Sep 2017 13:51:57 -0400 Subject: [PATCH 13/46] Make tech logic impls responsible for light filtering --- .../main/java/com/jme3/material/Material.java | 49 +++++++------------ .../java/com/jme3/material/Technique.java | 11 +++-- .../logic/DefaultTechniqueDefLogic.java | 25 ++++++---- .../logic/MultiPassLightingLogic.java | 8 +-- .../SinglePassAndImageBasedLightingLogic.java | 21 ++++---- .../logic/SinglePassLightingLogic.java | 33 ++++++++----- .../material/logic/TechniqueDefLogic.java | 17 ++++--- .../java/com/jme3/renderer/RenderManager.java | 18 ++----- .../jme3/material/MaterialMatParamTest.java | 3 +- 9 files changed, 88 insertions(+), 97 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/material/Material.java b/jme3-core/src/main/java/com/jme3/material/Material.java index a14bc357d9..73cd1b485c 100644 --- a/jme3-core/src/main/java/com/jme3/material/Material.java +++ b/jme3-core/src/main/java/com/jme3/material/Material.java @@ -81,9 +81,9 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { private AssetKey key; private String name; private MaterialDef def; - private ListMap paramValues = new ListMap(); + private ListMap paramValues = new ListMap<>(); private Technique technique; - private HashMap techniques = new HashMap(); + private HashMap techniques = new HashMap<>(); private RenderState additionalState = null; private RenderState mergedRenderState = new RenderState(); private boolean transparent = false; @@ -143,10 +143,12 @@ public void setName(String name) { this.name = name; } + @Override public void setKey(AssetKey key) { this.key = key; } + @Override public AssetKey getKey() { return key; } @@ -200,9 +202,9 @@ public Material clone() { mat.additionalState = additionalState.clone(); } mat.technique = null; - mat.techniques = new HashMap(); + mat.techniques = new HashMap<>(); - mat.paramValues = new ListMap(); + mat.paramValues = new ListMap<>(); for (int i = 0; i < paramValues.size(); i++) { Map.Entry entry = paramValues.getEntry(i); mat.paramValues.put(entry.getKey(), entry.getValue().clone()); @@ -933,10 +935,9 @@ private void resetUniformsNotSetByCurrent(Shader shader) { * * * @param geometry The geometry to render - * @param lights Presorted and filtered light list to use for rendering * @param renderManager The render manager requesting the rendering */ - public void render(Geometry geometry, LightList lights, RenderManager renderManager) { + public void render(Geometry geometry, RenderManager renderManager) { if (technique == null) { selectTechnique(TechniqueDef.DEFAULT_TECHNIQUE_NAME, renderManager); } @@ -956,7 +957,7 @@ public void render(Geometry geometry, LightList lights, RenderManager renderMana SafeArrayList overrides = geometry.getWorldMatParamOverrides(); // Select shader to use - Shader shader = technique.makeCurrent(renderManager, overrides, renderManager.getForcedMatParams(), lights, rendererCaps); + Shader shader = technique.makeCurrent(renderManager, geometry, overrides, renderManager.getForcedMatParams(), rendererCaps); // Begin tracking which uniforms were changed by material. clearUniformsSetByCurrent(shader); @@ -965,29 +966,24 @@ public void render(Geometry geometry, LightList lights, RenderManager renderMana renderManager.updateUniformBindings(shader); // Set material parameters - int unit = updateShaderMaterialParameters(renderer, shader, overrides, renderManager.getForcedMatParams()); + int nextTextureUnit = updateShaderMaterialParameters(renderer, shader, overrides, renderManager.getForcedMatParams()); // Clear any uniforms not changed by material. resetUniformsNotSetByCurrent(shader); // Delegate rendering to the technique - technique.render(renderManager, shader, geometry, lights, unit); + technique.render(renderManager, shader, geometry, nextTextureUnit); } - /** - * Called by {@link RenderManager} to render the geometry by - * using this material. - * - * Note that this version of the render method - * does not perform light filtering. - * - * @param geom The geometry to render - * @param rm The render manager requesting the rendering - */ - public void render(Geometry geom, RenderManager rm) { - render(geom, geom.getWorldLightList(), rm); + @Override + public String toString() { + return "Material[name=" + name + + ", def=" + (def != null ? def.getName() : null) + + ", tech=" + (technique != null && technique.getDef() != null ? technique.getDef().getName() : null) + + "]"; } - + + @Override public void write(JmeExporter ex) throws IOException { OutputCapsule oc = ex.getCapsule(this); oc.write(def.getAssetName(), "material_def", null); @@ -998,13 +994,6 @@ public void write(JmeExporter ex) throws IOException { } @Override - public String toString() { - return "Material[name=" + name + - ", def=" + (def != null ? def.getName() : null) + - ", tech=" + (technique != null && technique.getDef() != null ? technique.getDef().getName() : null) + - "]"; - } - public void read(JmeImporter im) throws IOException { InputCapsule ic = im.getCapsule(this); @@ -1054,7 +1043,7 @@ public void read(JmeImporter im) throws IOException { } def = (MaterialDef) im.getAssetManager().loadAsset(new AssetKey(defName)); - paramValues = new ListMap(); + paramValues = new ListMap<>(); // load the textures and update nextTexUnit for (Map.Entry entry : params.entrySet()) { diff --git a/jme3-core/src/main/java/com/jme3/material/Technique.java b/jme3-core/src/main/java/com/jme3/material/Technique.java index 3ae32814ee..e482241ab7 100644 --- a/jme3-core/src/main/java/com/jme3/material/Technique.java +++ b/jme3-core/src/main/java/com/jme3/material/Technique.java @@ -133,9 +133,10 @@ private void applyOverrides(DefineList defineList, SafeArrayList worldOverrides, + Shader makeCurrent(RenderManager renderManager, Geometry geometry, + SafeArrayList worldOverrides, SafeArrayList forcedOverrides, - LightList lights, EnumSet rendererCaps) { + EnumSet rendererCaps) { TechniqueDefLogic logic = def.getLogic(); AssetManager assetManager = owner.getMaterialDef().getAssetManager(); @@ -149,7 +150,7 @@ Shader makeCurrent(RenderManager renderManager, SafeArrayList applyOverrides(dynamicDefines, forcedOverrides); } - return logic.makeCurrent(assetManager, renderManager, rendererCaps, lights, dynamicDefines); + return logic.makeCurrent(assetManager, renderManager, rendererCaps, geometry, dynamicDefines); } /** @@ -161,9 +162,9 @@ Shader makeCurrent(RenderManager renderManager, SafeArrayList * @param geometry The geometry to render * @param lights Lights which influence the geometry. */ - void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights, int lastTexUnit) { + void render(RenderManager renderManager, Shader shader, Geometry geometry, int lastTextureUnit) { TechniqueDefLogic logic = def.getLogic(); - logic.render(renderManager, shader, geometry, lights, lastTexUnit); + logic.render(renderManager, shader, geometry, lastTextureUnit); } /** 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 86ce66391f..ad6a6f72e6 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 @@ -48,6 +48,7 @@ public class DefaultTechniqueDefLogic implements TechniqueDefLogic { protected final TechniqueDef techniqueDef; + protected final LightList filteredLightList = new LightList(null); public DefaultTechniqueDefLogic(TechniqueDef techniqueDef) { this.techniqueDef = techniqueDef; @@ -55,7 +56,7 @@ public DefaultTechniqueDefLogic(TechniqueDef techniqueDef) { @Override public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager, - EnumSet rendererCaps, LightList lights, DefineList defines) { + EnumSet rendererCaps, Geometry geometry, DefineList defines) { return techniqueDef.getShader(assetManager, rendererCaps, defines); } @@ -70,6 +71,19 @@ public static void renderMeshFromGeometry(Renderer renderer, Geometry geom) { renderer.renderMesh(mesh, lodLevel, 1, null); } } + + @Override + public void render(RenderManager renderManager, Shader shader, Geometry geometry, int lastTexUnit) { + Renderer renderer = renderManager.getRenderer(); + renderer.setShader(shader); + renderMeshFromGeometry(renderer, geometry); + } + + protected LightList getFilteredLightList(RenderManager renderManager, Geometry geom) { + filteredLightList.clear(); + renderManager.getLightFilter().filterLights(geom, filteredLightList); + return filteredLightList; + } protected static ColorRGBA getAmbientColor(LightList lightList, boolean removeLights, ColorRGBA ambientLightColor) { ambientLightColor.set(0, 0, 0, 1); @@ -85,13 +99,4 @@ protected static ColorRGBA getAmbientColor(LightList lightList, boolean removeLi ambientLightColor.a = 1.0f; return ambientLightColor; } - - - - @Override - public void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights, int lastTexUnit) { - Renderer renderer = renderManager.getRenderer(); - renderer.setShader(shader); - renderMeshFromGeometry(renderer, geometry); - } } diff --git a/jme3-core/src/main/java/com/jme3/material/logic/MultiPassLightingLogic.java b/jme3-core/src/main/java/com/jme3/material/logic/MultiPassLightingLogic.java index 61e9f26cb0..25a22c3150 100644 --- a/jme3-core/src/main/java/com/jme3/material/logic/MultiPassLightingLogic.java +++ b/jme3-core/src/main/java/com/jme3/material/logic/MultiPassLightingLogic.java @@ -31,7 +31,6 @@ */ package com.jme3.material.logic; -import com.jme3.asset.AssetManager; import com.jme3.light.AmbientLight; import com.jme3.light.DirectionalLight; import com.jme3.light.Light; @@ -41,20 +40,16 @@ import com.jme3.material.RenderState; import com.jme3.material.TechniqueDef; import com.jme3.math.ColorRGBA; -import com.jme3.math.FastMath; import com.jme3.math.Quaternion; import com.jme3.math.Vector3f; import com.jme3.math.Vector4f; -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 com.jme3.util.TempVars; -import java.util.EnumSet; public final class MultiPassLightingLogic extends DefaultTechniqueDefLogic { @@ -73,7 +68,7 @@ public MultiPassLightingLogic(TechniqueDef techniqueDef) { } @Override - public void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights, int lastTexUnit) { + public void render(RenderManager renderManager, Shader shader, Geometry geometry, int lastTexUnit) { Renderer r = renderManager.getRenderer(); Uniform lightDir = shader.getUniform("g_LightDirection"); Uniform lightColor = shader.getUniform("g_LightColor"); @@ -82,6 +77,7 @@ public void render(RenderManager renderManager, Shader shader, Geometry geometry boolean isFirstLight = true; boolean isSecondLight = false; + LightList lights = getFilteredLightList(renderManager, geometry); getAmbientColor(lights, false, ambientLightColor); for (int i = 0; i < lights.size(); i++) { 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 f8139af0f6..3e397cadae 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 @@ -72,15 +72,18 @@ public SinglePassAndImageBasedLightingLogic(TechniqueDef techniqueDef) { @Override public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager, - EnumSet rendererCaps, LightList lights, DefineList defines) { + 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, so the define will be set for all passes (in case we have more than NB_LIGHTS lights) - //Though the second pass should not render IBL as it is taken care of on 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). - if(lights != null) { + // TODO: here we have a problem, this is called once before render, + // so the define will be set for all passes (in case we have more than NB_LIGHTS lights) + // Though the second pass should not render IBL as it is taken care of on + // 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); @@ -89,7 +92,7 @@ public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager } } - return super.makeCurrent(assetManager, renderManager, rendererCaps, lights, defines); + return super.makeCurrent(assetManager, renderManager, rendererCaps, geometry, defines); } /** @@ -224,10 +227,11 @@ protected int updateLightListUniforms(Shader shader, Geometry g, LightList light } @Override - public void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights, int lastTexUnit) { + public void render(RenderManager renderManager, Shader shader, Geometry geometry, int lastTexUnit) { 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); renderer.setShader(shader); @@ -239,7 +243,6 @@ public void render(RenderManager renderManager, Shader shader, Geometry geometry renderMeshFromGeometry(renderer, geometry); } } - return; } protected LightProbe extractIndirectLights(LightList lightList, boolean removeLights) { 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 015d6b1da5..469e7a73df 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 @@ -77,25 +77,31 @@ public SinglePassLightingLogic(TechniqueDef techniqueDef) { } @Override - public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager, - EnumSet rendererCaps, LightList lights, DefineList defines) { + public Shader makeCurrent( + AssetManager assetManager, + RenderManager renderManager, + EnumSet rendererCaps, + Geometry geometry, + DefineList defines) { defines.set(nbLightsDefineId, renderManager.getSinglePassLightBatchSize() * 3); defines.set(singlePassLightingDefineId, true); - return super.makeCurrent(assetManager, renderManager, rendererCaps, lights, defines); + return super.makeCurrent(assetManager, renderManager, rendererCaps, geometry, defines); } /** - * Uploads the lights in the light list as two uniform arrays.

* + * Uploads the lights in the light list as two uniform arrays.

+ * *

- * uniform vec4 g_LightColor[numLights];
// - * g_LightColor.rgb is the diffuse/specular color of the light.
// - * g_Lightcolor.a is the type of light, 0 = Directional, 1 = Point,
// - * 2 = Spot.

- * uniform vec4 g_LightPosition[numLights];
// - * g_LightPosition.xyz is the position of the light (for point lights)
- * // or the direction of the light (for directional lights).
// + * uniform vec4 g_LightColor[numLights];
+ * g_LightColor.rgb is the diffuse/specular color of the light.
+ * g_Lightcolor.a is the type of light, 0 = Directional, 1 = Point,
+ * 2 = Spot.

+ * uniform vec4 g_LightPosition[numLights];
+ * g_LightPosition.xyz is the position of the light (for point lights)
+ * // or the direction of the light (for directional lights).
* g_LightPosition.w is the inverse radius (1/r) of the light (for - * attenuation)

+ * attenuation)
+ *

*/ protected int updateLightListUniforms(Shader shader, Geometry g, LightList lightList, int numLights, RenderManager rm, int startIndex) { if (numLights == 0) { // this shader does not do lighting, ignore. @@ -201,10 +207,11 @@ protected int updateLightListUniforms(Shader shader, Geometry g, LightList light } @Override - public void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights, int lastTexUnit) { + public void render(RenderManager renderManager, Shader shader, Geometry geometry, int lastTexUnit) { 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); renderer.setShader(shader); diff --git a/jme3-core/src/main/java/com/jme3/material/logic/TechniqueDefLogic.java b/jme3-core/src/main/java/com/jme3/material/logic/TechniqueDefLogic.java index 18a8051861..38d5f4dbdc 100644 --- a/jme3-core/src/main/java/com/jme3/material/logic/TechniqueDefLogic.java +++ b/jme3-core/src/main/java/com/jme3/material/logic/TechniqueDefLogic.java @@ -32,7 +32,9 @@ package com.jme3.material.logic; import com.jme3.asset.AssetManager; -import com.jme3.light.LightList; +import com.jme3.material.MatParam; +import com.jme3.material.RenderState; +import com.jme3.material.TechniqueDef; import com.jme3.material.TechniqueDef.LightMode; import com.jme3.renderer.Caps; import com.jme3.renderer.RenderManager; @@ -63,19 +65,18 @@ public interface TechniqueDefLogic { * * @param assetManager The asset manager to use for loading shader source code, * shader nodes, and and lookup textures. + * @param geometry The geometry being rendered * @param renderManager The render manager for which rendering is to be performed. * @param rendererCaps Renderer capabilities. The returned shader must * support these capabilities. - * @param lights The lights with which the geometry shall be rendered. This - * list must not include culled lights. * @param defines The define list used by the technique, any * {@link TechniqueDef#addShaderUnmappedDefine(java.lang.String) unmapped defines} * should be set here to change shader behavior. * * @return The shader to use for rendering. */ - public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager, - EnumSet rendererCaps, LightList lights, DefineList defines); + public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager, + EnumSet rendererCaps, Geometry geometry, DefineList defines); /** * Requests that the TechniqueDefLogic renders the given geometry. @@ -88,10 +89,10 @@ public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager * can still be overriden. * * @param renderManager The render manager to perform the rendering against. - * * @param shader The shader that was selected by this logic in + * @param shader The shader that was selected by this logic in * {@link #makeCurrent(com.jme3.asset.AssetManager, com.jme3.renderer.RenderManager, java.util.EnumSet, com.jme3.shader.DefineList)}. * @param geometry The geometry to render - * @param lights Lights which influence the geometry. + * @param lastTextureUnit The last unused texture unit */ - public void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights, int lastTexUnit); + public void render(RenderManager renderManager, Shader shader, Geometry geometry, int lastTextureUnit); } diff --git a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java index 950f1a4a66..817ca6b54d 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java +++ b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java @@ -84,7 +84,6 @@ public class RenderManager { private final SafeArrayList forcedOverrides = new SafeArrayList<>(MatParamOverride.class); private int viewX, viewY, viewWidth, viewHeight; private final Matrix4f orthoMatrix = new Matrix4f(); - private final LightList filteredLightList = new LightList(null); private boolean handleTranlucentBucket = true; private AppProfiler prof; private LightFilter lightFilter = new DefaultLightFilter(); @@ -562,15 +561,6 @@ public void renderGeometry(Geometry geom) { } else { setWorldMatrix(geom.getWorldMatrix()); } - - // Perform light filtering if we have a light filter. - LightList lightList = geom.getWorldLightList(); - - if (lightFilter != null) { - filteredLightList.clear(); - lightFilter.filterLights(geom, filteredLightList); - lightList = filteredLightList; - } Material material = geom.getMaterial(); @@ -595,7 +585,7 @@ public void renderGeometry(Geometry geom) { forcedRenderState = geom.getMaterial().getActiveTechnique().getDef().getForcedRenderState(); } // use geometry's material - material.render(geom, lightList, this); + material.render(geom, this); material.selectTechnique(previousTechniqueName, this); //restoring forcedRenderState @@ -605,13 +595,13 @@ public void renderGeometry(Geometry geom) { //If forcedTechnique does not exists, and forcedMaterial is not set, the geom MUST NOT be rendered } else if (forcedMaterial != null) { // use forced material - forcedMaterial.render(geom, lightList, this); + forcedMaterial.render(geom, this); } } else if (forcedMaterial != null) { // use forced material - forcedMaterial.render(geom, lightList, this); + forcedMaterial.render(geom, this); } else { - material.render(geom, lightList, this); + material.render(geom, this); } } diff --git a/jme3-core/src/test/java/com/jme3/material/MaterialMatParamTest.java b/jme3-core/src/test/java/com/jme3/material/MaterialMatParamTest.java index fc4503b1aa..a8795fba97 100644 --- a/jme3-core/src/test/java/com/jme3/material/MaterialMatParamTest.java +++ b/jme3-core/src/test/java/com/jme3/material/MaterialMatParamTest.java @@ -430,7 +430,6 @@ public String toString() { private final Geometry geometry = new Geometry("Geometry", new Box(1, 1, 1)); private final Node root = new Node("Root Node"); - private final LightList lightList = new LightList(geometry); @Before public void setUp() { @@ -526,7 +525,7 @@ private void material(String path) { private void evaluateTechniqueDef() { Assert.assertFalse(evaluated); Material mat = geometry.getMaterial(); - mat.render(geometry, lightList, renderManager); + mat.render(geometry, renderManager); Assert.assertTrue(evaluated); } From 55e9fd067ae5333855821105ac7d23e16843833d Mon Sep 17 00:00:00 2001 From: Kirill Vainer Date: Sat, 9 Sep 2017 13:53:39 -0400 Subject: [PATCH 14/46] Remove scale from updateFrustumPoints since its always 1.0 --- .../com/jme3/shadow/BasicShadowRenderer.java | 1 - .../shadow/DirectionalLightShadowRenderer.java | 4 ++-- .../com/jme3/shadow/PssmShadowRenderer.java | 4 ++-- .../main/java/com/jme3/shadow/ShadowUtil.java | 17 ----------------- .../jme3/shadow/SpotLightShadowRenderer.java | 2 +- 5 files changed, 5 insertions(+), 23 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/shadow/BasicShadowRenderer.java b/jme3-core/src/main/java/com/jme3/shadow/BasicShadowRenderer.java index 4beb4000c9..e184b7fa24 100644 --- a/jme3-core/src/main/java/com/jme3/shadow/BasicShadowRenderer.java +++ b/jme3-core/src/main/java/com/jme3/shadow/BasicShadowRenderer.java @@ -158,7 +158,6 @@ public void postQueue(RenderQueue rq) { ShadowUtil.updateFrustumPoints(viewCam, viewCam.getFrustumNear(), viewCam.getFrustumFar(), - 1.0f, points); Vector3f frustaCenter = new Vector3f(); diff --git a/jme3-core/src/main/java/com/jme3/shadow/DirectionalLightShadowRenderer.java b/jme3-core/src/main/java/com/jme3/shadow/DirectionalLightShadowRenderer.java index 1ac016f15d..094c77c282 100644 --- a/jme3-core/src/main/java/com/jme3/shadow/DirectionalLightShadowRenderer.java +++ b/jme3-core/src/main/java/com/jme3/shadow/DirectionalLightShadowRenderer.java @@ -148,7 +148,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.setFrustumFar(zFar); shadowCam.getRotation().lookAt(light.getDirection(), shadowCam.getUp()); @@ -183,7 +183,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) { diff --git a/jme3-core/src/main/java/com/jme3/shadow/PssmShadowRenderer.java b/jme3-core/src/main/java/com/jme3/shadow/PssmShadowRenderer.java index 4b854ec377..022d4eb0c4 100644 --- a/jme3-core/src/main/java/com/jme3/shadow/PssmShadowRenderer.java +++ b/jme3-core/src/main/java/com/jme3/shadow/PssmShadowRenderer.java @@ -398,7 +398,7 @@ public void postQueue(RenderQueue rq) { //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(direction, shadowCam.getUp()); @@ -428,7 +428,7 @@ public void postQueue(RenderQueue rq) { for (int i = 0; i < nbSplits; i++) { // update frustum points based on current camera and split - ShadowUtil.updateFrustumPoints(viewCam, splitsArray[i], splitsArray[i + 1], 1.0f, points); + ShadowUtil.updateFrustumPoints(viewCam, splitsArray[i], splitsArray[i + 1], points); //Updating shadow cam with curent split frustra ShadowUtil.updateShadowCamera(viewPort, lightReceivers, shadowCam, points, splitOccluders, shadowMapSize); 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 51942cdac9..7b08f04f50 100644 --- a/jme3-core/src/main/java/com/jme3/shadow/ShadowUtil.java +++ b/jme3-core/src/main/java/com/jme3/shadow/ShadowUtil.java @@ -96,7 +96,6 @@ public static void updateFrustumPoints2(Camera viewCam, Vector3f[] points) { public static void updateFrustumPoints(Camera viewCam, float nearOverride, float farOverride, - float scale, Vector3f[] points) { Vector3f pos = viewCam.getLocation(); @@ -149,22 +148,6 @@ public static void updateFrustumPoints(Camera viewCam, points[5].set(farCenter).addLocal(farUp).subtractLocal(farRight); points[6].set(farCenter).addLocal(farUp).addLocal(farRight); points[7].set(farCenter).subtractLocal(farUp).addLocal(farRight); - - if (scale != 1.0f) { - // find center of frustum - Vector3f center = new Vector3f(); - for (int i = 0; i < 8; i++) { - center.addLocal(points[i]); - } - center.divideLocal(8f); - - Vector3f cDir = new Vector3f(); - for (int i = 0; i < 8; i++) { - cDir.set(points[i]).subtractLocal(center); - cDir.multLocal(scale - 1.0f); - points[i].addLocal(cDir); - } - } } /** diff --git a/jme3-core/src/main/java/com/jme3/shadow/SpotLightShadowRenderer.java b/jme3-core/src/main/java/com/jme3/shadow/SpotLightShadowRenderer.java index e1d7db05e1..d3c7fcb525 100644 --- a/jme3-core/src/main/java/com/jme3/shadow/SpotLightShadowRenderer.java +++ b/jme3-core/src/main/java/com/jme3/shadow/SpotLightShadowRenderer.java @@ -137,7 +137,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.setFrustumPerspective(light.getSpotOuterAngle() * FastMath.RAD_TO_DEG * 2.0f, 1, 1f, light.getSpotRange()); From cfcec44b9a4315e14e4ea5ed93d1dda30c8f08f1 Mon Sep 17 00:00:00 2001 From: Kirill Vainer Date: Sat, 9 Sep 2017 13:58:05 -0400 Subject: [PATCH 15/46] Add ShadowMap interface --- .../src/main/java/com/jme3/light/Light.java | 19 +++++++ .../java/com/jme3/shadow/next/ShadowMap.java | 50 +++++++++++++++++++ .../com/jme3/shadow/next/ShadowMapSlice.java | 50 +++++++++++++++++++ 3 files changed, 119 insertions(+) create mode 100755 jme3-core/src/main/java/com/jme3/shadow/next/ShadowMap.java create mode 100755 jme3-core/src/main/java/com/jme3/shadow/next/ShadowMapSlice.java diff --git a/jme3-core/src/main/java/com/jme3/light/Light.java b/jme3-core/src/main/java/com/jme3/light/Light.java index 0a66fb729a..af3a540746 100644 --- a/jme3-core/src/main/java/com/jme3/light/Light.java +++ b/jme3-core/src/main/java/com/jme3/light/Light.java @@ -37,6 +37,7 @@ import com.jme3.math.ColorRGBA; import com.jme3.renderer.Camera; import com.jme3.scene.Spatial; +import com.jme3.shadow.next.ShadowMap; import com.jme3.util.TempVars; import java.io.IOException; @@ -120,6 +121,8 @@ public int getId(){ boolean frustumCheckNeeded = true; boolean intersectsFrustum = false; + protected ShadowMap shadowMap; + protected Light() { } @@ -163,6 +166,22 @@ public float getLastDistance(){ return lastDistance; } */ + + /** + * @return the light's shadow map, or null if none was assigned. + */ + public ShadowMap getShadowMap() { + return shadowMap; + } + + /** + * Used internally to associate the light with a shadow map + * + * @param shadowMap the light's shadow map + */ + public void setShadowMap(ShadowMap shadowMap) { + this.shadowMap = shadowMap; + } /** * Sets the light color. diff --git a/jme3-core/src/main/java/com/jme3/shadow/next/ShadowMap.java b/jme3-core/src/main/java/com/jme3/shadow/next/ShadowMap.java new file mode 100755 index 0000000000..f0a7807ccf --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/shadow/next/ShadowMap.java @@ -0,0 +1,50 @@ +/* + * 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.light.Light; +import com.jme3.light.Light.Type; + +/** + * Represents shadow information for a light. + * @param Type of light + * @author Kirill Vainer + */ +public interface ShadowMap { + + public Type getLightType(); + + public int getNumSlices(); + + public ShadowMapSlice getSlice(int index); + +} 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 new file mode 100755 index 0000000000..bfd0cc6f7e --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/shadow/next/ShadowMapSlice.java @@ -0,0 +1,50 @@ +/* + * 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.light.Light; +import com.jme3.math.Matrix4f; +import com.jme3.renderer.RenderManager; +import com.jme3.renderer.ViewPort; +import com.jme3.renderer.queue.GeometryList; + +/** + * Represents a single slice of a shadow map. + * + * @author Kirill Vainer + */ +public interface ShadowMapSlice { + + public Matrix4f getViewProjectionMatrix(); + + public void renderShadowMap(RenderManager renderManager, T light, ViewPort viewPort, GeometryList shadowCasters); +} From 42051b045b92b61ac2ea730c90dd44cab5fd11ee Mon Sep 17 00:00:00 2001 From: Kirill Vainer Date: Sat, 9 Sep 2017 14:01:20 -0400 Subject: [PATCH 16/46] StaticPass supports setting shadow map index on light --- .../logic/StaticPassLightingLogic.java | 78 ++++++++++++------- 1 file changed, 52 insertions(+), 26 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 48995ba4f5..80ff395135 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 @@ -57,23 +57,29 @@ * * @author Kirill Vainer */ -public final class StaticPassLightingLogic extends DefaultTechniqueDefLogic { +public class StaticPassLightingLogic extends DefaultTechniqueDefLogic { - private static final String DEFINE_NUM_DIR_LIGHTS = "NUM_DIR_LIGHTS"; - private static final String DEFINE_NUM_POINT_LIGHTS = "NUM_POINT_LIGHTS"; - private static final String DEFINE_NUM_SPOT_LIGHTS = "NUM_SPOT_LIGHTS"; + 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"; - private final int numDirLightsDefineId; - private final int numPointLightsDefineId; - private final int numSpotLightsDefineId; + protected final int numDirLightsDefineId; + protected final int numPointLightsDefineId; + protected final int numSpotLightsDefineId; - private final ArrayList tempDirLights = new ArrayList(); - private final ArrayList tempPointLights = new ArrayList(); - private final ArrayList tempSpotLights = new ArrayList(); + protected final ColorRGBA ambientLightColor = new ColorRGBA(0, 0, 0, 1); + protected final Vector3f tempPosition = new Vector3f(); + protected final Vector3f tempDirection = new Vector3f(); - private final ColorRGBA ambientLightColor = new ColorRGBA(0, 0, 0, 1); - private final Vector3f tempPosition = new Vector3f(); - private final Vector3f tempDirection = new Vector3f(); + protected final ArrayList tempDirLights = new ArrayList<>(); + 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); @@ -83,8 +89,7 @@ public StaticPassLightingLogic(TechniqueDef techniqueDef) { numSpotLightsDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_NUM_SPOT_LIGHTS, VarType.Int); } - @Override - public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager, + protected void makeCurrentBase(AssetManager assetManager, RenderManager renderManager, EnumSet rendererCaps, LightList lights, DefineList defines) { // TODO: if it ever changes that render isn't called @@ -94,6 +99,8 @@ public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager tempDirLights.clear(); tempPointLights.clear(); tempSpotLights.clear(); + ambientLightColor.set(0, 0, 0, 1); + for (Light light : lights) { switch (light.getType()) { case Directional: @@ -105,27 +112,41 @@ public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager 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); } - private void transformDirection(Matrix4f viewMatrix, Vector3f direction) { + protected void transformDirection(Matrix4f viewMatrix, Vector3f direction) { viewMatrix.multNormal(direction, direction); } - private void transformPosition(Matrix4f viewMatrix, Vector3f location) { + protected void transformPosition(Matrix4f viewMatrix, Vector3f location) { viewMatrix.mult(location, location); } - private void updateLightListUniforms(Matrix4f viewMatrix, Shader shader, LightList lights) { + 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, getAmbientColor(lights, true, ambientLightColor)); + ambientColor.setValue(VarType.Vector4, ambientLightColor); Uniform lightData = shader.getUniform("g_LightData"); @@ -137,25 +158,26 @@ private void updateLightListUniforms(Matrix4f viewMatrix, Shader shader, LightLi int index = 0; for (DirectionalLight light : tempDirLights) { ColorRGBA color = light.getColor(); + float shadowMapIndex = getShadowMapIndex(light); tempDirection.set(light.getDirection()); transformDirection(viewMatrix, tempDirection); - lightData.setVector4InArray(color.r, color.g, color.b, 1f, index++); + 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); tempPosition.set(light.getPosition()); float invRadius = light.getInvRadius(); transformPosition(viewMatrix, tempPosition); - lightData.setVector4InArray(color.r, color.g, color.b, 1f, index++); + 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(); - Vector3f pos = light.getPosition(); - Vector3f dir = light.getDirection(); + float shadowMapIndex = getShadowMapIndex(light); tempPosition.set(light.getPosition()); tempDirection.set(light.getDirection()); @@ -164,17 +186,21 @@ private void updateLightListUniforms(Matrix4f viewMatrix, Shader shader, LightLi float invRange = light.getInvSpotRange(); float spotAngleCos = light.getPackedAngleCos(); - lightData.setVector4InArray(color.r, color.g, color.b, 1f, index++); + 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) { + } + @Override - public void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights, int lastTexUnit) { + public void render(RenderManager renderManager, Shader shader, Geometry geometry, int nextTextureUnit) { Renderer renderer = renderManager.getRenderer(); Matrix4f viewMatrix = renderManager.getCurrentCamera().getViewMatrix(); - updateLightListUniforms(viewMatrix, shader, lights); + updateLightListUniforms(viewMatrix, shader); + updateShadowUniforms(renderer, shader, nextTextureUnit); renderer.setShader(shader); renderMeshFromGeometry(renderer, geometry); } From ce28e35393cfd076899db22a78db7966871ccfdf Mon Sep 17 00:00:00 2001 From: Kirill Vainer Date: Sat, 9 Sep 2017 16:27:02 -0400 Subject: [PATCH 17/46] Fix additional render state missing apply = false --- jme3-core/src/main/java/com/jme3/material/RenderState.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/jme3-core/src/main/java/com/jme3/material/RenderState.java b/jme3-core/src/main/java/com/jme3/material/RenderState.java index f6236efd09..b58ea32db7 100644 --- a/jme3-core/src/main/java/com/jme3/material/RenderState.java +++ b/jme3-core/src/main/java/com/jme3/material/RenderState.java @@ -429,6 +429,9 @@ public enum StencilOperation { ADDITIONAL.applyBlendEquationAlpha = false; ADDITIONAL.applyBlendMode = false; ADDITIONAL.applyPolyOffset = false; + ADDITIONAL.applyStencilTest = false; + ADDITIONAL.applyLineWidth = false; + ADDITIONAL.applyDepthFunc = false; } boolean wireframe = false; boolean applyWireFrame = true; From 8a747276d721a830c1ab48c8069515f93bb74d21 Mon Sep 17 00:00:00 2001 From: Kirill Vainer Date: Sat, 9 Sep 2017 16:28:11 -0400 Subject: [PATCH 18/46] Make sure apply = false for all forced render states --- jme3-core/src/main/java/com/jme3/post/PreDepthProcessor.java | 2 +- .../src/main/java/com/jme3/shadow/AbstractShadowRenderer.java | 2 +- .../src/main/java/com/jme3/niftygui/JmeBatchRenderBackend.java | 2 +- .../src/main/java/com/jme3/niftygui/RenderDeviceJme.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/post/PreDepthProcessor.java b/jme3-core/src/main/java/com/jme3/post/PreDepthProcessor.java index a3125dd1e1..92828b8077 100644 --- a/jme3-core/src/main/java/com/jme3/post/PreDepthProcessor.java +++ b/jme3-core/src/main/java/com/jme3/post/PreDepthProcessor.java @@ -60,7 +60,7 @@ public PreDepthProcessor(AssetManager assetManager){ preDepth.getAdditionalRenderState().setPolyOffset(0, 0); preDepth.getAdditionalRenderState().setFaceCullMode(FaceCullMode.Back); - forcedRS = new RenderState(); + forcedRS = RenderState.ADDITIONAL.clone(); forcedRS.setDepthTest(true); forcedRS.setDepthWrite(false); } diff --git a/jme3-core/src/main/java/com/jme3/shadow/AbstractShadowRenderer.java b/jme3-core/src/main/java/com/jme3/shadow/AbstractShadowRenderer.java index ff967f5841..8494cd0b37 100644 --- a/jme3-core/src/main/java/com/jme3/shadow/AbstractShadowRenderer.java +++ b/jme3-core/src/main/java/com/jme3/shadow/AbstractShadowRenderer.java @@ -94,7 +94,7 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable, protected EdgeFilteringMode edgeFilteringMode = EdgeFilteringMode.Bilinear; protected CompareMode shadowCompareMode = CompareMode.Hardware; protected Picture[] dispPic; - protected RenderState forcedRenderState = new RenderState(); + protected RenderState forcedRenderState = RenderState.ADDITIONAL.clone(); protected boolean renderBackFacesShadows = true; protected AppProfiler prof; diff --git a/jme3-niftygui/src/main/java/com/jme3/niftygui/JmeBatchRenderBackend.java b/jme3-niftygui/src/main/java/com/jme3/niftygui/JmeBatchRenderBackend.java index 9dd8310207..cea3b75312 100644 --- a/jme3-niftygui/src/main/java/com/jme3/niftygui/JmeBatchRenderBackend.java +++ b/jme3-niftygui/src/main/java/com/jme3/niftygui/JmeBatchRenderBackend.java @@ -453,7 +453,7 @@ private class Batch { private final Mesh mesh = new Mesh(); private final Geometry meshGeometry = new Geometry("nifty-quad", mesh); - private final RenderState renderState = new RenderState(); + private final RenderState renderState = RenderState.ADDITIONAL.clone(); private FloatBuffer vertexPosBuffer; private FloatBuffer vertexTexCoordBuffer; diff --git a/jme3-niftygui/src/main/java/com/jme3/niftygui/RenderDeviceJme.java b/jme3-niftygui/src/main/java/com/jme3/niftygui/RenderDeviceJme.java index ab0fc6659e..071cbbe057 100644 --- a/jme3-niftygui/src/main/java/com/jme3/niftygui/RenderDeviceJme.java +++ b/jme3-niftygui/src/main/java/com/jme3/niftygui/RenderDeviceJme.java @@ -73,7 +73,7 @@ public class RenderDeviceJme implements RenderDevice { private VertexBuffer quadColor; private Matrix4f tempMat = new Matrix4f(); private ColorRGBA tempColor = new ColorRGBA(); - private RenderState renderState = new RenderState(); + private RenderState renderState = RenderState.ADDITIONAL.clone(); private Material colorMaterial; private Material textureColorMaterial; From d159e1746cca0ccd154100abda746d90b4ef77dd Mon Sep 17 00:00:00 2001 From: Kirill Vainer Date: Sat, 9 Sep 2017 16:29:12 -0400 Subject: [PATCH 19/46] Combine forced render state with the one in the technique --- .../src/main/java/com/jme3/material/Material.java | 9 ++++++++- .../src/main/java/com/jme3/renderer/RenderManager.java | 10 +--------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/material/Material.java b/jme3-core/src/main/java/com/jme3/material/Material.java index 73cd1b485c..719da47482 100644 --- a/jme3-core/src/main/java/com/jme3/material/Material.java +++ b/jme3-core/src/main/java/com/jme3/material/Material.java @@ -819,7 +819,14 @@ private int updateShaderMaterialParameters(Renderer renderer, Shader shader, private void updateRenderState(RenderManager renderManager, Renderer renderer, TechniqueDef techniqueDef) { if (renderManager.getForcedRenderState() != null) { - renderer.applyRenderState(renderManager.getForcedRenderState()); + if (techniqueDef.getForcedRenderState() != null) { + renderer.applyRenderState( + techniqueDef.getForcedRenderState().copyMergedTo( + renderManager.getForcedRenderState(), + mergedRenderState)); + } else { + renderer.applyRenderState(renderManager.getForcedRenderState()); + } } else { if (techniqueDef.getRenderState() != null) { renderer.applyRenderState(techniqueDef.getRenderState().copyMergedTo(additionalState, mergedRenderState)); diff --git a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java index 817ca6b54d..6479b32218 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java +++ b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java @@ -578,19 +578,11 @@ public void renderGeometry(Geometry geom) { : TechniqueDef.DEFAULT_TECHNIQUE_NAME; geom.getMaterial().selectTechnique(forcedTechnique, this); - //saving forcedRenderState for future calls - RenderState tmpRs = forcedRenderState; - if (geom.getMaterial().getActiveTechnique().getDef().getForcedRenderState() != null) { - //forcing forced technique renderState - forcedRenderState = geom.getMaterial().getActiveTechnique().getDef().getForcedRenderState(); - } + // use geometry's material material.render(geom, this); material.selectTechnique(previousTechniqueName, this); - //restoring forcedRenderState - forcedRenderState = tmpRs; - //Reverted this part from revision 6197 //If forcedTechnique does not exists, and forcedMaterial is not set, the geom MUST NOT be rendered } else if (forcedMaterial != null) { From 9c4fcac8769d7d02f0ec116d5a0422397c341505 Mon Sep 17 00:00:00 2001 From: Kirill Vainer Date: Sat, 9 Sep 2017 16:31:39 -0400 Subject: [PATCH 20/46] Add PreShadowArrayRenderer --- .../logic/ShadowStaticPassLightingLogic.java | 191 ++++++++++++++ .../shadow/next/PreShadowArrayRenderer.java | 248 ++++++++++++++++++ .../jme3/shadow/next/ShadowParameters.java | 38 +++ .../shadow/next/array/ArrayShadowMap.java | 47 ++++ .../next/array/ArrayShadowMapSlice.java | 41 +++ .../shadow/next/array/BaseArrayShadowMap.java | 75 ++++++ .../next/array/BaseArrayShadowMapSlice.java | 85 ++++++ .../next/array/DirectionalArrayShadowMap.java | 82 ++++++ .../array/DirectionalArrayShadowMapSlice.java | 66 +++++ .../shadow/next/array/SpotArrayShadowMap.java | 68 +++++ .../next/array/SpotArrayShadowMapSlice.java | 72 +++++ .../pssm/DirectionalShadowParameters.java | 138 ++++++++++ 12 files changed, 1151 insertions(+) create mode 100755 jme3-core/src/main/java/com/jme3/material/logic/ShadowStaticPassLightingLogic.java create mode 100755 jme3-core/src/main/java/com/jme3/shadow/next/PreShadowArrayRenderer.java create mode 100755 jme3-core/src/main/java/com/jme3/shadow/next/ShadowParameters.java create mode 100755 jme3-core/src/main/java/com/jme3/shadow/next/array/ArrayShadowMap.java create mode 100755 jme3-core/src/main/java/com/jme3/shadow/next/array/ArrayShadowMapSlice.java create mode 100755 jme3-core/src/main/java/com/jme3/shadow/next/array/BaseArrayShadowMap.java create mode 100755 jme3-core/src/main/java/com/jme3/shadow/next/array/BaseArrayShadowMapSlice.java create mode 100755 jme3-core/src/main/java/com/jme3/shadow/next/array/DirectionalArrayShadowMap.java create mode 100755 jme3-core/src/main/java/com/jme3/shadow/next/array/DirectionalArrayShadowMapSlice.java create mode 100755 jme3-core/src/main/java/com/jme3/shadow/next/array/SpotArrayShadowMap.java create mode 100755 jme3-core/src/main/java/com/jme3/shadow/next/array/SpotArrayShadowMapSlice.java create mode 100755 jme3-core/src/main/java/com/jme3/shadow/next/pssm/DirectionalShadowParameters.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 new file mode 100755 index 0000000000..54fad0f0f7 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/material/logic/ShadowStaticPassLightingLogic.java @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2009-2016 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.material.logic; + +import com.jme3.asset.AssetManager; +import com.jme3.light.DirectionalLight; +import com.jme3.light.Light; +import com.jme3.light.LightList; +import com.jme3.light.PointLight; +import com.jme3.light.SpotLight; +import com.jme3.material.TechniqueDef; +import com.jme3.math.Matrix4f; +import com.jme3.math.Vector4f; +import com.jme3.renderer.Caps; +import com.jme3.renderer.RenderManager; +import com.jme3.renderer.Renderer; +import com.jme3.shader.DefineList; +import com.jme3.shader.Shader; +import com.jme3.shader.Uniform; +import com.jme3.shader.VarType; +import com.jme3.shadow.next.array.ArrayShadowMap; +import com.jme3.shadow.next.array.ArrayShadowMapSlice; +import com.jme3.shadow.next.array.DirectionalArrayShadowMap; +import com.jme3.shadow.next.array.SpotArrayShadowMap; +import com.jme3.shadow.next.array.SpotArrayShadowMapSlice; +import com.jme3.texture.TextureArray; +import java.util.EnumSet; + +public class ShadowStaticPassLightingLogic extends StaticPassLightingLogic { + + private static final String DEFINE_NUM_PSSM_SPLITS = "NUM_PSSM_SPLITS"; + private static final String DEFINE_NUM_SHADOW_DIR_LIGHTS = "NUM_SHADOW_DIR_LIGHTS"; + private static final String DEFINE_NUM_SHADOW_POINT_LIGHTS = "NUM_SHADOW_POINT_LIGHTS"; + private static final String DEFINE_NUM_SHADOW_SPOT_LIGHTS = "NUM_SHADOW_SPOT_LIGHTS"; + + private final int numPssmSplitsDefineId; + private final int numShadowDirLightsDefineId; + private final int numShadowPointLightsDefineId; + private final int numShadowSpotLightsDefineId; + private int numShadowDirLights = 0; + private int numShadowPointLights = 0; + private int numShadowSpotLights = 0; + private final Matrix4f[] shadowMatrices = new Matrix4f[5]; + + public ShadowStaticPassLightingLogic(TechniqueDef techniqueDef) { + super(techniqueDef); + numPssmSplitsDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_NUM_PSSM_SPLITS, VarType.Int); + numShadowDirLightsDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_NUM_SHADOW_DIR_LIGHTS, VarType.Int); + numShadowPointLightsDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_NUM_SHADOW_POINT_LIGHTS, VarType.Int); + numShadowSpotLightsDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_NUM_SHADOW_SPOT_LIGHTS, VarType.Int); + + for (int i = 0; i < shadowMatrices.length; i++) { + shadowMatrices[i] = new Matrix4f(); + } + } + + @Override + protected void makeCurrentBase(AssetManager assetManager, RenderManager renderManager, + EnumSet 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