From edfcbb4d78c1921bb1fbd7eae21e3a3ad8a55a01 Mon Sep 17 00:00:00 2001 From: Wyatt Gillette Date: Mon, 22 Sep 2025 14:55:40 +0200 Subject: [PATCH 01/11] AbstractShadowRenderer: fix debugFrustum --- .../jme3/shadow/AbstractShadowRenderer.java | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) 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 50db5a5a64..4047a52b2b 100644 --- a/jme3-core/src/main/java/com/jme3/shadow/AbstractShadowRenderer.java +++ b/jme3-core/src/main/java/com/jme3/shadow/AbstractShadowRenderer.java @@ -52,6 +52,7 @@ 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; import com.jme3.scene.debug.WireFrustum; import com.jme3.texture.FrameBuffer; @@ -396,6 +397,10 @@ public boolean isInitialized() { protected void doDisplayFrustumDebug(int shadowMapIndex) { } + protected Node getMainScene() { + return (Node) viewPort.getScenes().get(0); + } + @SuppressWarnings("fallthrough") @Override public void postQueue(RenderQueue rq) { @@ -413,15 +418,16 @@ public void postQueue(RenderQueue rq) { renderManager.setForcedTechnique("PreShadow"); for (int shadowMapIndex = 0; shadowMapIndex < nbShadowMaps; shadowMapIndex++) { - - if (debugfrustums) { - doDisplayFrustumDebug(shadowMapIndex); - } - renderShadowMap(shadowMapIndex); - + if (debugfrustums) { + doDisplayFrustumDebug(shadowMapIndex); } + renderShadowMap(shadowMapIndex); + } - debugfrustums = false; + if (debugfrustums) { + debugfrustums = false; + getMainScene().updateGeometricState(); + } //restore setting for future rendering r.setFrameBuffer(viewPort.getOutputFrameBuffer()); From 58971cdcf8648217c89ef5d232b5ba60d27c6325 Mon Sep 17 00:00:00 2001 From: Wyatt Gillette Date: Mon, 22 Sep 2025 14:56:46 +0200 Subject: [PATCH 02/11] PssmShadowRenderer: fix debugFrustum --- .../com/jme3/shadow/PssmShadowRenderer.java | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) 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 a0d405000b..49144c16b4 100644 --- a/jme3-core/src/main/java/com/jme3/shadow/PssmShadowRenderer.java +++ b/jme3-core/src/main/java/com/jme3/shadow/PssmShadowRenderer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2021 jMonkeyEngine + * Copyright (c) 2009-2025 jMonkeyEngine * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -438,13 +438,9 @@ public void postQueue(RenderQueue rq) { renderManager.setCamera(shadowCam, false); if (debugfrustums) { -// frustumFromBound(b.casterBB,ColorRGBA.Blue ); -// frustumFromBound(b.receiverBB,ColorRGBA.Green ); -// frustumFromBound(b.splitBB,ColorRGBA.Yellow ); - ((Node) viewPort.getScenes().get(0)).attachChild(createFrustum(points, i)); + getMainScene().attachChild(createFrustum(points, i)); ShadowUtil.updateFrustumPoints2(shadowCam, points); - ((Node) viewPort.getScenes().get(0)).attachChild(createFrustum(points, i)); - + getMainScene().attachChild(createFrustum(points, i)); } r.setFrameBuffer(shadowFB[i]); @@ -456,7 +452,11 @@ public void postQueue(RenderQueue rq) { viewPort.getQueue().renderShadowQueue(splitOccluders, renderManager, shadowCam, true); renderManager.setLightFilter(tmpLightFilter); } - debugfrustums = false; + + if (debugfrustums) { + debugfrustums = false; + getMainScene().updateGeometricState(); + } //restore setting for future rendering r.setFrameBuffer(viewPort.getOutputFrameBuffer()); @@ -465,6 +465,11 @@ public void postQueue(RenderQueue rq) { renderManager.setCamera(viewCam, false); } + + protected Node getMainScene() { + return (Node) viewPort.getScenes().get(0); + } + boolean debugfrustums = false; public void displayFrustum() { From 1a4008db7dac5ee8434158d0219fd001f85536a4 Mon Sep 17 00:00:00 2001 From: Wyatt Gillette Date: Mon, 22 Sep 2025 14:57:30 +0200 Subject: [PATCH 03/11] PointLightShadowRenderer: fix debugFrustum --- .../jme3/shadow/PointLightShadowRenderer.java | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/shadow/PointLightShadowRenderer.java b/jme3-core/src/main/java/com/jme3/shadow/PointLightShadowRenderer.java index 1999ba9e2d..8b5d03de2a 100644 --- a/jme3-core/src/main/java/com/jme3/shadow/PointLightShadowRenderer.java +++ b/jme3-core/src/main/java/com/jme3/shadow/PointLightShadowRenderer.java @@ -153,21 +153,20 @@ protected Camera getShadowCam(int shadowMapIndex) { @Override protected void doDisplayFrustumDebug(int shadowMapIndex) { - if (frustums == null) { - frustums = new Geometry[CAM_NUMBER]; - Vector3f[] points = new Vector3f[8]; - for (int i = 0; i < points.length; i++) { - points[i] = new Vector3f(); - } - for (int i = 0; i < CAM_NUMBER; i++) { - ShadowUtil.updateFrustumPoints2(shadowCams[i], points); - frustums[i] = createFrustum(points, i); - } + frustums = new Geometry[CAM_NUMBER]; + Vector3f[] points = new Vector3f[8]; + + for (int i = 0; i < points.length; i++) { + points[i] = new Vector3f(); } - Geometry geo = frustums[shadowMapIndex]; - if (geo.getParent() == null) { - ((Node) viewPort.getScenes().get(0)).attachChild(geo); + + for (int i = 0; i < CAM_NUMBER; i++) { + ShadowUtil.updateFrustumPoints2(shadowCams[i], points); + frustums[i] = createFrustum(points, i); } + + Geometry geo = frustums[shadowMapIndex]; + getMainScene().attachChild(geo); } @Override From e7ce097e1133aee45414a1ae93b1c12c1a7cf056 Mon Sep 17 00:00:00 2001 From: Wyatt Gillette Date: Mon, 22 Sep 2025 14:58:15 +0200 Subject: [PATCH 04/11] SpotLightShadowRenderer: fix debugFrustum --- .../main/java/com/jme3/shadow/SpotLightShadowRenderer.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 448857408b..6655050b12 100644 --- a/jme3-core/src/main/java/com/jme3/shadow/SpotLightShadowRenderer.java +++ b/jme3-core/src/main/java/com/jme3/shadow/SpotLightShadowRenderer.java @@ -89,7 +89,7 @@ public SpotLightShadowRenderer(AssetManager assetManager, int shadowMapSize) { init(shadowMapSize); } - + private void init(int shadowMapSize) { shadowCam = new Camera(shadowMapSize, shadowMapSize); for (int i = 0; i < points.length; i++) { @@ -175,9 +175,9 @@ protected Camera getShadowCam(int shadowMapIndex) { protected void doDisplayFrustumDebug(int shadowMapIndex) { Vector3f[] points2 = points.clone(); - ((Node) viewPort.getScenes().get(0)).attachChild(createFrustum(points, shadowMapIndex)); + getMainScene().attachChild(createFrustum(points, shadowMapIndex)); ShadowUtil.updateFrustumPoints2(shadowCam, points2); - ((Node) viewPort.getScenes().get(0)).attachChild(createFrustum(points2, shadowMapIndex)); + getMainScene().attachChild(createFrustum(points2, shadowMapIndex)); } @Override From 895c6dee6dd165953a782859f016cdc24ffb1c09 Mon Sep 17 00:00:00 2001 From: Wyatt Gillette Date: Mon, 22 Sep 2025 14:59:12 +0200 Subject: [PATCH 05/11] DirectionalLightShadowRenderer: fix debugFrustum --- .../java/com/jme3/shadow/DirectionalLightShadowRenderer.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 0b50f8be4b..4e9ad44636 100644 --- a/jme3-core/src/main/java/com/jme3/shadow/DirectionalLightShadowRenderer.java +++ b/jme3-core/src/main/java/com/jme3/shadow/DirectionalLightShadowRenderer.java @@ -212,9 +212,9 @@ protected Camera getShadowCam(int shadowMapIndex) { @Override protected void doDisplayFrustumDebug(int shadowMapIndex) { - ((Node) viewPort.getScenes().get(0)).attachChild(createFrustum(points, shadowMapIndex)); + getMainScene().attachChild(createFrustum(points, shadowMapIndex)); ShadowUtil.updateFrustumPoints2(shadowCam, points); - ((Node) viewPort.getScenes().get(0)).attachChild(createFrustum(points, shadowMapIndex)); + getMainScene().attachChild(createFrustum(points, shadowMapIndex)); } @Override From c3af0839aadd4fa50480cec2de658fea56a9dcb9 Mon Sep 17 00:00:00 2001 From: Wyatt Gillette Date: Mon, 22 Sep 2025 15:00:44 +0200 Subject: [PATCH 06/11] Update DirectionalLightShadowRenderer: remove unused imports --- .../java/com/jme3/shadow/DirectionalLightShadowRenderer.java | 1 - 1 file changed, 1 deletion(-) 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 4e9ad44636..c2e9e3ae5b 100644 --- a/jme3-core/src/main/java/com/jme3/shadow/DirectionalLightShadowRenderer.java +++ b/jme3-core/src/main/java/com/jme3/shadow/DirectionalLightShadowRenderer.java @@ -44,7 +44,6 @@ import com.jme3.renderer.Camera; import com.jme3.renderer.queue.GeometryList; import com.jme3.renderer.queue.RenderQueue; -import com.jme3.scene.Node; import com.jme3.scene.Spatial; import com.jme3.util.clone.Cloner; From 150337bb2e365ecc1f01d16a5d3a474212b418b9 Mon Sep 17 00:00:00 2001 From: Wyatt Gillette Date: Mon, 22 Sep 2025 15:01:37 +0200 Subject: [PATCH 07/11] Update PointLightShadowRenderer: remove unused imports --- .../src/main/java/com/jme3/shadow/PointLightShadowRenderer.java | 1 - 1 file changed, 1 deletion(-) diff --git a/jme3-core/src/main/java/com/jme3/shadow/PointLightShadowRenderer.java b/jme3-core/src/main/java/com/jme3/shadow/PointLightShadowRenderer.java index 8b5d03de2a..8454e258fc 100644 --- a/jme3-core/src/main/java/com/jme3/shadow/PointLightShadowRenderer.java +++ b/jme3-core/src/main/java/com/jme3/shadow/PointLightShadowRenderer.java @@ -43,7 +43,6 @@ import com.jme3.renderer.queue.GeometryList; import com.jme3.renderer.queue.RenderQueue; import com.jme3.scene.Geometry; -import com.jme3.scene.Node; import com.jme3.scene.Spatial; import com.jme3.util.TempVars; import com.jme3.util.clone.Cloner; From aab9e9b30491807b2c6950c9dc1b9bc8c4ec1739 Mon Sep 17 00:00:00 2001 From: Wyatt Gillette Date: Mon, 22 Sep 2025 15:01:59 +0200 Subject: [PATCH 08/11] Update SpotLightShadowRenderer: remove unused imports --- .../src/main/java/com/jme3/shadow/SpotLightShadowRenderer.java | 1 - 1 file changed, 1 deletion(-) 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 6655050b12..7f8eace53f 100644 --- a/jme3-core/src/main/java/com/jme3/shadow/SpotLightShadowRenderer.java +++ b/jme3-core/src/main/java/com/jme3/shadow/SpotLightShadowRenderer.java @@ -44,7 +44,6 @@ import com.jme3.renderer.Camera; import com.jme3.renderer.queue.GeometryList; import com.jme3.renderer.queue.RenderQueue; -import com.jme3.scene.Node; import com.jme3.scene.Spatial; import com.jme3.util.TempVars; import com.jme3.util.clone.Cloner; From 735132f0aac2d86e657d5b7ebc5b6f96cce2fcbf Mon Sep 17 00:00:00 2001 From: Wyatt Gillette Date: Mon, 22 Sep 2025 15:05:48 +0200 Subject: [PATCH 09/11] Update PointLightShadowFilter.java --- .../jme3/shadow/PointLightShadowFilter.java | 197 +++++++++++++++--- 1 file changed, 168 insertions(+), 29 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/shadow/PointLightShadowFilter.java b/jme3-core/src/main/java/com/jme3/shadow/PointLightShadowFilter.java index ef5e3dc19c..813aa6683a 100644 --- a/jme3-core/src/main/java/com/jme3/shadow/PointLightShadowFilter.java +++ b/jme3-core/src/main/java/com/jme3/shadow/PointLightShadowFilter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2024 jMonkeyEngine + * Copyright (c) 2009-2025 jMonkeyEngine * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -37,71 +37,210 @@ import com.jme3.export.JmeImporter; import com.jme3.export.OutputCapsule; import com.jme3.light.PointLight; +import com.jme3.material.Material; +import com.jme3.math.Vector3f; +import com.jme3.renderer.Camera; +import com.jme3.renderer.queue.GeometryList; +import com.jme3.renderer.queue.RenderQueue; +import com.jme3.scene.Geometry; +import com.jme3.scene.Spatial; +import com.jme3.util.TempVars; +import com.jme3.util.clone.Cloner; + import java.io.IOException; /** - * This Filter does basically the same as a PointLightShadowRenderer except it - * renders the post shadow pass as a fullscreen quad pass instead of a geometry - * pass. It's mostly faster than PointLightShadowRenderer as long as you have - * more than about ten shadow receiving objects. The expense is the drawback - * that the shadow Receive mode set on spatial is ignored. So basically all and - * only objects that render depth in the scene receive shadows. - * - * API is basically the same as the PssmShadowRenderer. + * Renders shadows for a {@link PointLight}. This renderer uses six cameras, + * one for each face of a cube map, to capture shadows from the point light's + * perspective. * * @author Rémy Bouquet aka Nehon */ -public class PointLightShadowFilter extends AbstractShadowFilter { +public class PointLightShadowRenderer extends AbstractShadowRenderer { + + /** + * The fixed number of cameras used for rendering point light shadows (6 for a cube map). + */ + public static final int CAM_NUMBER = 6; + + protected PointLight light; + protected Camera[] shadowCams; + protected Geometry[] frustums = null; + protected final Vector3f X_NEG = Vector3f.UNIT_X.mult(-1f); + protected final Vector3f Y_NEG = Vector3f.UNIT_Y.mult(-1f); + protected final Vector3f Z_NEG = Vector3f.UNIT_Z.mult(-1f); /** * For serialization only. Do not use. - * - * @see #PointLightShadowFilter(AssetManager assetManager, int shadowMapSize) */ - protected PointLightShadowFilter() { + protected PointLightShadowRenderer() { super(); } /** - * Creates a PointLightShadowFilter. + * Creates a new {@code PointLightShadowRenderer} instance. * - * @param assetManager the application's asset manager - * @param shadowMapSize the size of the rendered shadow maps (512, 1024, 2048, etc...) + * @param assetManager The application's asset manager. + * @param shadowMapSize The size of the rendered shadow maps (e.g., 512, 1024, 2048). + * Higher values produce better quality shadows but may impact performance. */ - public PointLightShadowFilter(AssetManager assetManager, int shadowMapSize) { - super(assetManager, shadowMapSize, new PointLightShadowRenderer(assetManager, shadowMapSize)); + public PointLightShadowRenderer(AssetManager assetManager, int shadowMapSize) { + super(assetManager, shadowMapSize, CAM_NUMBER); + init(shadowMapSize); + } + + private void init(int shadowMapSize) { + shadowCams = new Camera[CAM_NUMBER]; + for (int i = 0; i < shadowCams.length; i++) { + shadowCams[i] = new Camera(shadowMapSize, shadowMapSize); + } + } + + @Override + protected void initFrustumCam() { + Camera viewCam = viewPort.getCamera(); + frustumCam = viewCam.clone(); + frustumCam.setFrustum(viewCam.getFrustumNear(), zFarOverride, + viewCam.getFrustumLeft(), viewCam.getFrustumRight(), viewCam.getFrustumTop(), viewCam.getFrustumBottom()); + } + + @Override + protected void updateShadowCams(Camera viewCam) { + + if (light == null) { + logger.warning("The light can't be null for a " + getClass().getName()); + return; + } + + // Configure axes for each of the six cube map cameras (positive/negative X, Y, Z) + shadowCams[0].setAxes(X_NEG, Z_NEG, Y_NEG); // -Y (bottom) + shadowCams[1].setAxes(X_NEG, Vector3f.UNIT_Z, Vector3f.UNIT_Y); // +Y (top) + shadowCams[2].setAxes(X_NEG, Vector3f.UNIT_Y, Z_NEG); // +Z (forward) + shadowCams[3].setAxes(Vector3f.UNIT_X, Vector3f.UNIT_Y, Vector3f.UNIT_Z); // -Z (backward) + shadowCams[4].setAxes(Vector3f.UNIT_Z, Vector3f.UNIT_Y, X_NEG); // -X (left) + shadowCams[5].setAxes(Z_NEG, Vector3f.UNIT_Y, Vector3f.UNIT_X); // +X (right) + + // Set perspective and location for all shadow cameras + for (Camera shadowCam : shadowCams) { + shadowCam.setFrustumPerspective(90f, 1f, 0.1f, light.getRadius()); + shadowCam.setLocation(light.getPosition()); + shadowCam.update(); + shadowCam.updateViewProjection(); + } + } + + @Override + protected GeometryList getOccludersToRender(int shadowMapIndex, GeometryList shadowMapOccluders) { + for (Spatial scene : viewPort.getScenes()) { + ShadowUtil.getGeometriesInCamFrustum(scene, shadowCams[shadowMapIndex], RenderQueue.ShadowMode.Cast, shadowMapOccluders); + } + return shadowMapOccluders; + } + + @Override + protected void getReceivers(GeometryList lightReceivers) { + lightReceivers.clear(); + for (Spatial scene : viewPort.getScenes()) { + ShadowUtil.getLitGeometriesInViewPort(scene, viewPort.getCamera(), shadowCams, RenderQueue.ShadowMode.Receive, lightReceivers); + } + } + + @Override + protected Camera getShadowCam(int shadowMapIndex) { + return shadowCams[shadowMapIndex]; } + @Override + protected void doDisplayFrustumDebug(int shadowMapIndex) { + if (frustums == null) { + frustums = new Geometry[CAM_NUMBER]; + Vector3f[] points = new Vector3f[8]; + for (int i = 0; i < points.length; i++) { + points[i] = new Vector3f(); + } + for (int i = 0; i < CAM_NUMBER; i++) { + ShadowUtil.updateFrustumPoints2(shadowCams[i], points); + frustums[i] = createFrustum(points, i); + } + } + Geometry geo = frustums[shadowMapIndex]; + if (geo.getParent() == null) { + getMainScene().attachChild(geo); + } + } + + @Override + protected void setMaterialParameters(Material material) { + material.setVector3("LightPos", light == null ? new Vector3f() : light.getPosition()); + } + + @Override + protected void clearMaterialParameters(Material material) { + material.clearParam("LightPos"); + } + /** - * Returns the light used to cast shadows. + * gets the point light used to cast shadows with this processor * - * @return the PointLight + * @return the point light */ public PointLight getLight() { - return shadowRenderer.getLight(); + return light; } /** - * Sets the light to use to cast shadows. + * sets the light to use for casting shadows with this processor * - * @param light the PointLight + * @param light the point light */ public void setLight(PointLight light) { - shadowRenderer.setLight(light); + this.light = light; } @Override - public void write(JmeExporter ex) throws IOException { - super.write(ex); - OutputCapsule oc = ex.getCapsule(this); - oc.write(shadowRenderer, "shadowRenderer", null); + public void cloneFields(final Cloner cloner, final Object original) { + light = cloner.clone(light); + init((int) shadowMapSize); + frustums = null; + super.cloneFields(cloner, original); } @Override public void read(JmeImporter im) throws IOException { super.read(im); InputCapsule ic = im.getCapsule(this); - shadowRenderer = (PointLightShadowRenderer) ic.readSavable("shadowRenderer", null); + light = (PointLight) ic.readSavable("light", null); + init((int) shadowMapSize); + } + + @Override + public void write(JmeExporter ex) throws IOException { + super.write(ex); + OutputCapsule oc = ex.getCapsule(this); + oc.write(light, "light", null); } + /** + * + * @param viewCam a Camera to define the view frustum + * @return true if intersects + */ + @Override + protected boolean checkCulling(Camera viewCam) { + + if (light == null) { + return false; + } + + Camera cam = viewCam; + if (frustumCam != null) { + cam = frustumCam; + cam.setLocation(viewCam.getLocation()); + cam.setRotation(viewCam.getRotation()); + } + TempVars vars = TempVars.get(); + boolean intersects = light.intersectsFrustum(cam, vars); + vars.release(); + return intersects; + } } From e6b5468bd6fb6056971d9e621be4d695e78f58cd Mon Sep 17 00:00:00 2001 From: Wyatt Gillette Date: Mon, 22 Sep 2025 15:07:42 +0200 Subject: [PATCH 10/11] Update PointLightShadowRenderer.java --- .../jme3/shadow/PointLightShadowRenderer.java | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/shadow/PointLightShadowRenderer.java b/jme3-core/src/main/java/com/jme3/shadow/PointLightShadowRenderer.java index 8454e258fc..813aa6683a 100644 --- a/jme3-core/src/main/java/com/jme3/shadow/PointLightShadowRenderer.java +++ b/jme3-core/src/main/java/com/jme3/shadow/PointLightShadowRenderer.java @@ -152,20 +152,21 @@ protected Camera getShadowCam(int shadowMapIndex) { @Override protected void doDisplayFrustumDebug(int shadowMapIndex) { - frustums = new Geometry[CAM_NUMBER]; - Vector3f[] points = new Vector3f[8]; - - for (int i = 0; i < points.length; i++) { - points[i] = new Vector3f(); - } - - for (int i = 0; i < CAM_NUMBER; i++) { - ShadowUtil.updateFrustumPoints2(shadowCams[i], points); - frustums[i] = createFrustum(points, i); + if (frustums == null) { + frustums = new Geometry[CAM_NUMBER]; + Vector3f[] points = new Vector3f[8]; + for (int i = 0; i < points.length; i++) { + points[i] = new Vector3f(); + } + for (int i = 0; i < CAM_NUMBER; i++) { + ShadowUtil.updateFrustumPoints2(shadowCams[i], points); + frustums[i] = createFrustum(points, i); + } } - Geometry geo = frustums[shadowMapIndex]; - getMainScene().attachChild(geo); + if (geo.getParent() == null) { + getMainScene().attachChild(geo); + } } @Override From 5ef8b58ed05dd7e47602595bd0c15d36a94ed7fd Mon Sep 17 00:00:00 2001 From: Wyatt Gillette Date: Mon, 22 Sep 2025 15:08:36 +0200 Subject: [PATCH 11/11] Revert PointLightShadowFilter.java: oops --- .../jme3/shadow/PointLightShadowFilter.java | 197 +++--------------- 1 file changed, 29 insertions(+), 168 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/shadow/PointLightShadowFilter.java b/jme3-core/src/main/java/com/jme3/shadow/PointLightShadowFilter.java index 813aa6683a..ef5e3dc19c 100644 --- a/jme3-core/src/main/java/com/jme3/shadow/PointLightShadowFilter.java +++ b/jme3-core/src/main/java/com/jme3/shadow/PointLightShadowFilter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2025 jMonkeyEngine + * Copyright (c) 2009-2024 jMonkeyEngine * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -37,210 +37,71 @@ import com.jme3.export.JmeImporter; import com.jme3.export.OutputCapsule; import com.jme3.light.PointLight; -import com.jme3.material.Material; -import com.jme3.math.Vector3f; -import com.jme3.renderer.Camera; -import com.jme3.renderer.queue.GeometryList; -import com.jme3.renderer.queue.RenderQueue; -import com.jme3.scene.Geometry; -import com.jme3.scene.Spatial; -import com.jme3.util.TempVars; -import com.jme3.util.clone.Cloner; - import java.io.IOException; /** - * Renders shadows for a {@link PointLight}. This renderer uses six cameras, - * one for each face of a cube map, to capture shadows from the point light's - * perspective. + * This Filter does basically the same as a PointLightShadowRenderer except it + * renders the post shadow pass as a fullscreen quad pass instead of a geometry + * pass. It's mostly faster than PointLightShadowRenderer as long as you have + * more than about ten shadow receiving objects. The expense is the drawback + * that the shadow Receive mode set on spatial is ignored. So basically all and + * only objects that render depth in the scene receive shadows. + * + * API is basically the same as the PssmShadowRenderer. * * @author Rémy Bouquet aka Nehon */ -public class PointLightShadowRenderer extends AbstractShadowRenderer { - - /** - * The fixed number of cameras used for rendering point light shadows (6 for a cube map). - */ - public static final int CAM_NUMBER = 6; - - protected PointLight light; - protected Camera[] shadowCams; - protected Geometry[] frustums = null; - protected final Vector3f X_NEG = Vector3f.UNIT_X.mult(-1f); - protected final Vector3f Y_NEG = Vector3f.UNIT_Y.mult(-1f); - protected final Vector3f Z_NEG = Vector3f.UNIT_Z.mult(-1f); +public class PointLightShadowFilter extends AbstractShadowFilter { /** * For serialization only. Do not use. + * + * @see #PointLightShadowFilter(AssetManager assetManager, int shadowMapSize) */ - protected PointLightShadowRenderer() { + protected PointLightShadowFilter() { super(); } /** - * Creates a new {@code PointLightShadowRenderer} instance. + * Creates a PointLightShadowFilter. * - * @param assetManager The application's asset manager. - * @param shadowMapSize The size of the rendered shadow maps (e.g., 512, 1024, 2048). - * Higher values produce better quality shadows but may impact performance. + * @param assetManager the application's asset manager + * @param shadowMapSize the size of the rendered shadow maps (512, 1024, 2048, etc...) */ - public PointLightShadowRenderer(AssetManager assetManager, int shadowMapSize) { - super(assetManager, shadowMapSize, CAM_NUMBER); - init(shadowMapSize); - } - - private void init(int shadowMapSize) { - shadowCams = new Camera[CAM_NUMBER]; - for (int i = 0; i < shadowCams.length; i++) { - shadowCams[i] = new Camera(shadowMapSize, shadowMapSize); - } - } - - @Override - protected void initFrustumCam() { - Camera viewCam = viewPort.getCamera(); - frustumCam = viewCam.clone(); - frustumCam.setFrustum(viewCam.getFrustumNear(), zFarOverride, - viewCam.getFrustumLeft(), viewCam.getFrustumRight(), viewCam.getFrustumTop(), viewCam.getFrustumBottom()); - } - - @Override - protected void updateShadowCams(Camera viewCam) { - - if (light == null) { - logger.warning("The light can't be null for a " + getClass().getName()); - return; - } - - // Configure axes for each of the six cube map cameras (positive/negative X, Y, Z) - shadowCams[0].setAxes(X_NEG, Z_NEG, Y_NEG); // -Y (bottom) - shadowCams[1].setAxes(X_NEG, Vector3f.UNIT_Z, Vector3f.UNIT_Y); // +Y (top) - shadowCams[2].setAxes(X_NEG, Vector3f.UNIT_Y, Z_NEG); // +Z (forward) - shadowCams[3].setAxes(Vector3f.UNIT_X, Vector3f.UNIT_Y, Vector3f.UNIT_Z); // -Z (backward) - shadowCams[4].setAxes(Vector3f.UNIT_Z, Vector3f.UNIT_Y, X_NEG); // -X (left) - shadowCams[5].setAxes(Z_NEG, Vector3f.UNIT_Y, Vector3f.UNIT_X); // +X (right) - - // Set perspective and location for all shadow cameras - for (Camera shadowCam : shadowCams) { - shadowCam.setFrustumPerspective(90f, 1f, 0.1f, light.getRadius()); - shadowCam.setLocation(light.getPosition()); - shadowCam.update(); - shadowCam.updateViewProjection(); - } - } - - @Override - protected GeometryList getOccludersToRender(int shadowMapIndex, GeometryList shadowMapOccluders) { - for (Spatial scene : viewPort.getScenes()) { - ShadowUtil.getGeometriesInCamFrustum(scene, shadowCams[shadowMapIndex], RenderQueue.ShadowMode.Cast, shadowMapOccluders); - } - return shadowMapOccluders; - } - - @Override - protected void getReceivers(GeometryList lightReceivers) { - lightReceivers.clear(); - for (Spatial scene : viewPort.getScenes()) { - ShadowUtil.getLitGeometriesInViewPort(scene, viewPort.getCamera(), shadowCams, RenderQueue.ShadowMode.Receive, lightReceivers); - } - } - - @Override - protected Camera getShadowCam(int shadowMapIndex) { - return shadowCams[shadowMapIndex]; + public PointLightShadowFilter(AssetManager assetManager, int shadowMapSize) { + super(assetManager, shadowMapSize, new PointLightShadowRenderer(assetManager, shadowMapSize)); } - @Override - protected void doDisplayFrustumDebug(int shadowMapIndex) { - if (frustums == null) { - frustums = new Geometry[CAM_NUMBER]; - Vector3f[] points = new Vector3f[8]; - for (int i = 0; i < points.length; i++) { - points[i] = new Vector3f(); - } - for (int i = 0; i < CAM_NUMBER; i++) { - ShadowUtil.updateFrustumPoints2(shadowCams[i], points); - frustums[i] = createFrustum(points, i); - } - } - Geometry geo = frustums[shadowMapIndex]; - if (geo.getParent() == null) { - getMainScene().attachChild(geo); - } - } - - @Override - protected void setMaterialParameters(Material material) { - material.setVector3("LightPos", light == null ? new Vector3f() : light.getPosition()); - } - - @Override - protected void clearMaterialParameters(Material material) { - material.clearParam("LightPos"); - } - /** - * gets the point light used to cast shadows with this processor + * Returns the light used to cast shadows. * - * @return the point light + * @return the PointLight */ public PointLight getLight() { - return light; + return shadowRenderer.getLight(); } /** - * sets the light to use for casting shadows with this processor + * Sets the light to use to cast shadows. * - * @param light the point light + * @param light the PointLight */ public void setLight(PointLight light) { - this.light = light; + shadowRenderer.setLight(light); } @Override - public void cloneFields(final Cloner cloner, final Object original) { - light = cloner.clone(light); - init((int) shadowMapSize); - frustums = null; - super.cloneFields(cloner, original); + public void write(JmeExporter ex) throws IOException { + super.write(ex); + OutputCapsule oc = ex.getCapsule(this); + oc.write(shadowRenderer, "shadowRenderer", null); } @Override public void read(JmeImporter im) throws IOException { super.read(im); InputCapsule ic = im.getCapsule(this); - light = (PointLight) ic.readSavable("light", null); - init((int) shadowMapSize); - } - - @Override - public void write(JmeExporter ex) throws IOException { - super.write(ex); - OutputCapsule oc = ex.getCapsule(this); - oc.write(light, "light", null); + shadowRenderer = (PointLightShadowRenderer) ic.readSavable("shadowRenderer", null); } - /** - * - * @param viewCam a Camera to define the view frustum - * @return true if intersects - */ - @Override - protected boolean checkCulling(Camera viewCam) { - - if (light == null) { - return false; - } - - Camera cam = viewCam; - if (frustumCam != null) { - cam = frustumCam; - cam.setLocation(viewCam.getLocation()); - cam.setRotation(viewCam.getRotation()); - } - TempVars vars = TempVars.get(); - boolean intersects = light.intersectsFrustum(cam, vars); - vars.release(); - return intersects; - } }