|
1 | 1 | /* |
2 | | - * Copyright (c) 2009-2025 jMonkeyEngine |
| 2 | + * Copyright (c) 2009-2024 jMonkeyEngine |
3 | 3 | * All rights reserved. |
4 | 4 | * |
5 | 5 | * Redistribution and use in source and binary forms, with or without |
|
37 | 37 | import com.jme3.export.JmeImporter; |
38 | 38 | import com.jme3.export.OutputCapsule; |
39 | 39 | import com.jme3.light.PointLight; |
40 | | -import com.jme3.material.Material; |
41 | | -import com.jme3.math.Vector3f; |
42 | | -import com.jme3.renderer.Camera; |
43 | | -import com.jme3.renderer.queue.GeometryList; |
44 | | -import com.jme3.renderer.queue.RenderQueue; |
45 | | -import com.jme3.scene.Geometry; |
46 | | -import com.jme3.scene.Spatial; |
47 | | -import com.jme3.util.TempVars; |
48 | | -import com.jme3.util.clone.Cloner; |
49 | | - |
50 | 40 | import java.io.IOException; |
51 | 41 |
|
52 | 42 | /** |
53 | | - * Renders shadows for a {@link PointLight}. This renderer uses six cameras, |
54 | | - * one for each face of a cube map, to capture shadows from the point light's |
55 | | - * perspective. |
| 43 | + * This Filter does basically the same as a PointLightShadowRenderer except it |
| 44 | + * renders the post shadow pass as a fullscreen quad pass instead of a geometry |
| 45 | + * pass. It's mostly faster than PointLightShadowRenderer as long as you have |
| 46 | + * more than about ten shadow receiving objects. The expense is the drawback |
| 47 | + * that the shadow Receive mode set on spatial is ignored. So basically all and |
| 48 | + * only objects that render depth in the scene receive shadows. |
| 49 | + * |
| 50 | + * API is basically the same as the PssmShadowRenderer. |
56 | 51 | * |
57 | 52 | * @author Rémy Bouquet aka Nehon |
58 | 53 | */ |
59 | | -public class PointLightShadowRenderer extends AbstractShadowRenderer { |
60 | | - |
61 | | - /** |
62 | | - * The fixed number of cameras used for rendering point light shadows (6 for a cube map). |
63 | | - */ |
64 | | - public static final int CAM_NUMBER = 6; |
65 | | - |
66 | | - protected PointLight light; |
67 | | - protected Camera[] shadowCams; |
68 | | - protected Geometry[] frustums = null; |
69 | | - protected final Vector3f X_NEG = Vector3f.UNIT_X.mult(-1f); |
70 | | - protected final Vector3f Y_NEG = Vector3f.UNIT_Y.mult(-1f); |
71 | | - protected final Vector3f Z_NEG = Vector3f.UNIT_Z.mult(-1f); |
| 54 | +public class PointLightShadowFilter extends AbstractShadowFilter<PointLightShadowRenderer> { |
72 | 55 |
|
73 | 56 | /** |
74 | 57 | * For serialization only. Do not use. |
| 58 | + * |
| 59 | + * @see #PointLightShadowFilter(AssetManager assetManager, int shadowMapSize) |
75 | 60 | */ |
76 | | - protected PointLightShadowRenderer() { |
| 61 | + protected PointLightShadowFilter() { |
77 | 62 | super(); |
78 | 63 | } |
79 | 64 |
|
80 | 65 | /** |
81 | | - * Creates a new {@code PointLightShadowRenderer} instance. |
| 66 | + * Creates a PointLightShadowFilter. |
82 | 67 | * |
83 | | - * @param assetManager The application's asset manager. |
84 | | - * @param shadowMapSize The size of the rendered shadow maps (e.g., 512, 1024, 2048). |
85 | | - * Higher values produce better quality shadows but may impact performance. |
| 68 | + * @param assetManager the application's asset manager |
| 69 | + * @param shadowMapSize the size of the rendered shadow maps (512, 1024, 2048, etc...) |
86 | 70 | */ |
87 | | - public PointLightShadowRenderer(AssetManager assetManager, int shadowMapSize) { |
88 | | - super(assetManager, shadowMapSize, CAM_NUMBER); |
89 | | - init(shadowMapSize); |
90 | | - } |
91 | | - |
92 | | - private void init(int shadowMapSize) { |
93 | | - shadowCams = new Camera[CAM_NUMBER]; |
94 | | - for (int i = 0; i < shadowCams.length; i++) { |
95 | | - shadowCams[i] = new Camera(shadowMapSize, shadowMapSize); |
96 | | - } |
97 | | - } |
98 | | - |
99 | | - @Override |
100 | | - protected void initFrustumCam() { |
101 | | - Camera viewCam = viewPort.getCamera(); |
102 | | - frustumCam = viewCam.clone(); |
103 | | - frustumCam.setFrustum(viewCam.getFrustumNear(), zFarOverride, |
104 | | - viewCam.getFrustumLeft(), viewCam.getFrustumRight(), viewCam.getFrustumTop(), viewCam.getFrustumBottom()); |
105 | | - } |
106 | | - |
107 | | - @Override |
108 | | - protected void updateShadowCams(Camera viewCam) { |
109 | | - |
110 | | - if (light == null) { |
111 | | - logger.warning("The light can't be null for a " + getClass().getName()); |
112 | | - return; |
113 | | - } |
114 | | - |
115 | | - // Configure axes for each of the six cube map cameras (positive/negative X, Y, Z) |
116 | | - shadowCams[0].setAxes(X_NEG, Z_NEG, Y_NEG); // -Y (bottom) |
117 | | - shadowCams[1].setAxes(X_NEG, Vector3f.UNIT_Z, Vector3f.UNIT_Y); // +Y (top) |
118 | | - shadowCams[2].setAxes(X_NEG, Vector3f.UNIT_Y, Z_NEG); // +Z (forward) |
119 | | - shadowCams[3].setAxes(Vector3f.UNIT_X, Vector3f.UNIT_Y, Vector3f.UNIT_Z); // -Z (backward) |
120 | | - shadowCams[4].setAxes(Vector3f.UNIT_Z, Vector3f.UNIT_Y, X_NEG); // -X (left) |
121 | | - shadowCams[5].setAxes(Z_NEG, Vector3f.UNIT_Y, Vector3f.UNIT_X); // +X (right) |
122 | | - |
123 | | - // Set perspective and location for all shadow cameras |
124 | | - for (Camera shadowCam : shadowCams) { |
125 | | - shadowCam.setFrustumPerspective(90f, 1f, 0.1f, light.getRadius()); |
126 | | - shadowCam.setLocation(light.getPosition()); |
127 | | - shadowCam.update(); |
128 | | - shadowCam.updateViewProjection(); |
129 | | - } |
130 | | - } |
131 | | - |
132 | | - @Override |
133 | | - protected GeometryList getOccludersToRender(int shadowMapIndex, GeometryList shadowMapOccluders) { |
134 | | - for (Spatial scene : viewPort.getScenes()) { |
135 | | - ShadowUtil.getGeometriesInCamFrustum(scene, shadowCams[shadowMapIndex], RenderQueue.ShadowMode.Cast, shadowMapOccluders); |
136 | | - } |
137 | | - return shadowMapOccluders; |
138 | | - } |
139 | | - |
140 | | - @Override |
141 | | - protected void getReceivers(GeometryList lightReceivers) { |
142 | | - lightReceivers.clear(); |
143 | | - for (Spatial scene : viewPort.getScenes()) { |
144 | | - ShadowUtil.getLitGeometriesInViewPort(scene, viewPort.getCamera(), shadowCams, RenderQueue.ShadowMode.Receive, lightReceivers); |
145 | | - } |
146 | | - } |
147 | | - |
148 | | - @Override |
149 | | - protected Camera getShadowCam(int shadowMapIndex) { |
150 | | - return shadowCams[shadowMapIndex]; |
| 71 | + public PointLightShadowFilter(AssetManager assetManager, int shadowMapSize) { |
| 72 | + super(assetManager, shadowMapSize, new PointLightShadowRenderer(assetManager, shadowMapSize)); |
151 | 73 | } |
152 | 74 |
|
153 | | - @Override |
154 | | - protected void doDisplayFrustumDebug(int shadowMapIndex) { |
155 | | - if (frustums == null) { |
156 | | - frustums = new Geometry[CAM_NUMBER]; |
157 | | - Vector3f[] points = new Vector3f[8]; |
158 | | - for (int i = 0; i < points.length; i++) { |
159 | | - points[i] = new Vector3f(); |
160 | | - } |
161 | | - for (int i = 0; i < CAM_NUMBER; i++) { |
162 | | - ShadowUtil.updateFrustumPoints2(shadowCams[i], points); |
163 | | - frustums[i] = createFrustum(points, i); |
164 | | - } |
165 | | - } |
166 | | - Geometry geo = frustums[shadowMapIndex]; |
167 | | - if (geo.getParent() == null) { |
168 | | - getMainScene().attachChild(geo); |
169 | | - } |
170 | | - } |
171 | | - |
172 | | - @Override |
173 | | - protected void setMaterialParameters(Material material) { |
174 | | - material.setVector3("LightPos", light == null ? new Vector3f() : light.getPosition()); |
175 | | - } |
176 | | - |
177 | | - @Override |
178 | | - protected void clearMaterialParameters(Material material) { |
179 | | - material.clearParam("LightPos"); |
180 | | - } |
181 | | - |
182 | 75 | /** |
183 | | - * gets the point light used to cast shadows with this processor |
| 76 | + * Returns the light used to cast shadows. |
184 | 77 | * |
185 | | - * @return the point light |
| 78 | + * @return the PointLight |
186 | 79 | */ |
187 | 80 | public PointLight getLight() { |
188 | | - return light; |
| 81 | + return shadowRenderer.getLight(); |
189 | 82 | } |
190 | 83 |
|
191 | 84 | /** |
192 | | - * sets the light to use for casting shadows with this processor |
| 85 | + * Sets the light to use to cast shadows. |
193 | 86 | * |
194 | | - * @param light the point light |
| 87 | + * @param light the PointLight |
195 | 88 | */ |
196 | 89 | public void setLight(PointLight light) { |
197 | | - this.light = light; |
| 90 | + shadowRenderer.setLight(light); |
198 | 91 | } |
199 | 92 |
|
200 | 93 | @Override |
201 | | - public void cloneFields(final Cloner cloner, final Object original) { |
202 | | - light = cloner.clone(light); |
203 | | - init((int) shadowMapSize); |
204 | | - frustums = null; |
205 | | - super.cloneFields(cloner, original); |
| 94 | + public void write(JmeExporter ex) throws IOException { |
| 95 | + super.write(ex); |
| 96 | + OutputCapsule oc = ex.getCapsule(this); |
| 97 | + oc.write(shadowRenderer, "shadowRenderer", null); |
206 | 98 | } |
207 | 99 |
|
208 | 100 | @Override |
209 | 101 | public void read(JmeImporter im) throws IOException { |
210 | 102 | super.read(im); |
211 | 103 | InputCapsule ic = im.getCapsule(this); |
212 | | - light = (PointLight) ic.readSavable("light", null); |
213 | | - init((int) shadowMapSize); |
214 | | - } |
215 | | - |
216 | | - @Override |
217 | | - public void write(JmeExporter ex) throws IOException { |
218 | | - super.write(ex); |
219 | | - OutputCapsule oc = ex.getCapsule(this); |
220 | | - oc.write(light, "light", null); |
| 104 | + shadowRenderer = (PointLightShadowRenderer) ic.readSavable("shadowRenderer", null); |
221 | 105 | } |
222 | 106 |
|
223 | | - /** |
224 | | - * |
225 | | - * @param viewCam a Camera to define the view frustum |
226 | | - * @return true if intersects |
227 | | - */ |
228 | | - @Override |
229 | | - protected boolean checkCulling(Camera viewCam) { |
230 | | - |
231 | | - if (light == null) { |
232 | | - return false; |
233 | | - } |
234 | | - |
235 | | - Camera cam = viewCam; |
236 | | - if (frustumCam != null) { |
237 | | - cam = frustumCam; |
238 | | - cam.setLocation(viewCam.getLocation()); |
239 | | - cam.setRotation(viewCam.getRotation()); |
240 | | - } |
241 | | - TempVars vars = TempVars.get(); |
242 | | - boolean intersects = light.intersectsFrustum(cam, vars); |
243 | | - vars.release(); |
244 | | - return intersects; |
245 | | - } |
246 | 107 | } |
0 commit comments