Skip to content

Refactor: PointLightShadowRenderer reduce object allocations #2514

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -51,33 +51,39 @@
import java.io.IOException;

/**
* PointLightShadowRenderer renders shadows for a point light
* 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
* @author 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;
private Geometry[] frustums = null;
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);

/**
* Used for serialization.
* Use PointLightShadowRenderer#PointLightShadowRenderer(AssetManager
* assetManager, int shadowMapSize)
* instead.
* For serialization only. Do not use.
*/
protected PointLightShadowRenderer() {
super();
}

/**
* Creates a PointLightShadowRenderer
* Creates a new {@code PointLightShadowRenderer} instance.
*
* @param assetManager the application asset manager
* @param shadowMapSize the size of the rendered shadowmaps (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 PointLightShadowRenderer(AssetManager assetManager, int shadowMapSize) {
super(assetManager, shadowMapSize, CAM_NUMBER);
Expand All @@ -86,7 +92,7 @@ public PointLightShadowRenderer(AssetManager assetManager, int shadowMapSize) {

private void init(int shadowMapSize) {
shadowCams = new Camera[CAM_NUMBER];
for (int i = 0; i < CAM_NUMBER; i++) {
for (int i = 0; i < shadowCams.length; i++) {
shadowCams[i] = new Camera(shadowMapSize, shadowMapSize);
}
}
Expand All @@ -95,9 +101,9 @@ private void init(int shadowMapSize) {
protected void initFrustumCam() {
Camera viewCam = viewPort.getCamera();
frustumCam = viewCam.clone();
frustumCam.setFrustum(viewCam.getFrustumNear(), zFarOverride, viewCam.getFrustumLeft(), viewCam.getFrustumRight(), viewCam.getFrustumTop(), viewCam.getFrustumBottom());
frustumCam.setFrustum(viewCam.getFrustumNear(), zFarOverride,
viewCam.getFrustumLeft(), viewCam.getFrustumRight(), viewCam.getFrustumTop(), viewCam.getFrustumBottom());
}


@Override
protected void updateShadowCams(Camera viewCam) {
Expand All @@ -107,31 +113,21 @@ protected void updateShadowCams(Camera viewCam) {
return;
}

//bottom
shadowCams[0].setAxes(Vector3f.UNIT_X.mult(-1f), Vector3f.UNIT_Z.mult(-1f), Vector3f.UNIT_Y.mult(-1f));

//top
shadowCams[1].setAxes(Vector3f.UNIT_X.mult(-1f), Vector3f.UNIT_Z, Vector3f.UNIT_Y);

//forward
shadowCams[2].setAxes(Vector3f.UNIT_X.mult(-1f), Vector3f.UNIT_Y, Vector3f.UNIT_Z.mult(-1f));

//backward
shadowCams[3].setAxes(Vector3f.UNIT_X, Vector3f.UNIT_Y, Vector3f.UNIT_Z);

//left
shadowCams[4].setAxes(Vector3f.UNIT_Z, Vector3f.UNIT_Y, Vector3f.UNIT_X.mult(-1f));

//right
shadowCams[5].setAxes(Vector3f.UNIT_Z.mult(-1f), Vector3f.UNIT_Y, Vector3f.UNIT_X);

for (int i = 0; i < CAM_NUMBER; i++) {
shadowCams[i].setFrustumPerspective(90f, 1f, 0.1f, light.getRadius());
shadowCams[i].setLocation(light.getPosition());
shadowCams[i].update();
shadowCams[i].updateViewProjection();
// 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
Expand Down Expand Up @@ -160,16 +156,17 @@ protected void doDisplayFrustumDebug(int shadowMapIndex) {
if (frustums == null) {
frustums = new Geometry[CAM_NUMBER];
Vector3f[] points = new Vector3f[8];
for (int i = 0; i < 8; i++) {
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[shadowMapIndex].getParent() == null) {
((Node) viewPort.getScenes().get(0)).attachChild(frustums[shadowMapIndex]);
Geometry geo = frustums[shadowMapIndex];
if (geo.getParent() == null) {
((Node) viewPort.getScenes().get(0)).attachChild(geo);
}
}

Expand Down Expand Up @@ -237,13 +234,13 @@ protected boolean checkCulling(Camera viewCam) {
}

Camera cam = viewCam;
if(frustumCam != null){
cam = frustumCam;
if (frustumCam != null) {
cam = frustumCam;
cam.setLocation(viewCam.getLocation());
cam.setRotation(viewCam.getRotation());
}
TempVars vars = TempVars.get();
boolean intersects = light.intersectsFrustum(cam,vars);
boolean intersects = light.intersectsFrustum(cam, vars);
vars.release();
return intersects;
}
Expand Down