11/*
2- * Copyright (c) 2009-2021 jMonkeyEngine
2+ * Copyright (c) 2009-2025 jMonkeyEngine
33 * All rights reserved.
44 *
55 * Redistribution and use in source and binary forms, with or without
4040import com.jme3.math.Vector2f;
4141import com.jme3.math.Vector3f;
4242import com.jme3.post.Filter;
43- import com.jme3.post.Filter.Pass;
4443import com.jme3.renderer.RenderManager;
4544import com.jme3.renderer.Renderer;
4645import com.jme3.renderer.ViewPort;
6261public class SSAOFilter extends Filter {
6362
6463 private Pass normalPass;
65- private Vector3f frustumCorner;
66- private Vector2f frustumNearFar;
67- private Vector2f[] samples = {new Vector2f(1.0f, 0.0f), new Vector2f(-1.0f, 0.0f), new Vector2f(0.0f, 1.0f), new Vector2f(0.0f, -1.0f)};
64+ private final Vector2f[] samples = {
65+ new Vector2f(1.0f, 0.0f),
66+ new Vector2f(-1.0f, 0.0f),
67+ new Vector2f(0.0f, 1.0f),
68+ new Vector2f(0.0f, -1.0f)
69+ };
6870 private float sampleRadius = 5.1f;
6971 private float intensity = 1.5f;
7072 private float scale = 0.2f;
7173 private float bias = 0.1f;
74+ private boolean approximateNormals = false;
7275 private boolean useOnlyAo = false;
7376 private boolean useAo = true;
7477 private Material ssaoMat;
75- private Pass ssaoPass;
76- // private Material downSampleMat;
77- // private Pass downSamplePass;
78- private float downSampleFactor = 1f;
7978 private RenderManager renderManager;
8079 private ViewPort viewPort;
81- private boolean approximateNormals = false;
8280
8381 /**
8482 * Create a Screen Space Ambient Occlusion Filter
@@ -89,10 +87,11 @@ public SSAOFilter() {
8987
9088 /**
9189 * Create a Screen Space Ambient Occlusion Filter
90+ *
9291 * @param sampleRadius The radius of the area where random samples will be picked. default 5.1f
93- * @param intensity intensity of the resulting AO. default 1.2f
94- * @param scale distance between occluders and occludee. default 0.2f
95- * @param bias the width of the occlusion cone considered by the occludee. default 0.1f
92+ * @param intensity intensity of the resulting AO. default 1.5f
93+ * @param scale distance between occluders and occludee. default 0.2f
94+ * @param bias the width of the occlusion cone considered by the occludee. default 0.1f
9695 */
9796 public SSAOFilter(float sampleRadius, float intensity, float scale, float bias) {
9897 this();
@@ -126,38 +125,32 @@ protected Material getMaterial() {
126125 }
127126
128127 @Override
129- protected void initFilter(AssetManager manager , RenderManager renderManager, ViewPort vp, int w, int h) {
128+ protected void initFilter(AssetManager assetManager , RenderManager renderManager, ViewPort vp, int w, int h) {
130129 this.renderManager = renderManager;
131130 this.viewPort = vp;
132131 int screenWidth = w;
133132 int screenHeight = h;
133+ float downSampleFactor = 1f;
134134 postRenderPasses = new ArrayList<Pass>();
135135
136136 normalPass = new Pass();
137137 normalPass.init(renderManager.getRenderer(), (int) (screenWidth / downSampleFactor), (int) (screenHeight / downSampleFactor), Format.RGBA8, Format.Depth);
138138
139-
140- frustumNearFar = new Vector2f();
141-
139+ Vector2f frustumNearFar = new Vector2f();
142140 float farY = (vp.getCamera().getFrustumTop() / vp.getCamera().getFrustumNear()) * vp.getCamera().getFrustumFar();
143141 float farX = farY * (screenWidth / (float) screenHeight);
144- frustumCorner = new Vector3f(farX, farY, vp.getCamera().getFrustumFar());
142+ Vector3f frustumCorner = new Vector3f(farX, farY, vp.getCamera().getFrustumFar());
145143 frustumNearFar.x = vp.getCamera().getFrustumNear();
146144 frustumNearFar.y = vp.getCamera().getFrustumFar();
147145
148-
149-
150-
151-
152146 //ssao Pass
153- ssaoMat = new Material(manager , "Common/MatDefs/SSAO/ssao.j3md");
147+ ssaoMat = new Material(assetManager , "Common/MatDefs/SSAO/ssao.j3md");
154148 ssaoMat.setTexture("Normals", normalPass.getRenderedTexture());
155- Texture random = manager .loadTexture("Common/MatDefs/SSAO/Textures/random.png");
149+ Texture random = assetManager .loadTexture("Common/MatDefs/SSAO/Textures/random.png");
156150 random.setWrap(Texture.WrapMode.Repeat);
157151 ssaoMat.setTexture("RandomMap", random);
158152
159- ssaoPass = new Pass("SSAO pass") {
160-
153+ Pass ssaoPass = new Pass("SSAO pass") {
161154 @Override
162155 public boolean requiresDepthAsTexture() {
163156 return true;
@@ -168,18 +161,18 @@ public boolean requiresDepthAsTexture() {
168161// ssaoPass.getRenderedTexture().setMinFilter(Texture.MinFilter.Trilinear);
169162// ssaoPass.getRenderedTexture().setMagFilter(Texture.MagFilter.Bilinear);
170163 postRenderPasses.add(ssaoPass);
171- material = new Material(manager , "Common/MatDefs/SSAO/ssaoBlur.j3md");
164+ material = new Material(assetManager , "Common/MatDefs/SSAO/ssaoBlur.j3md");
172165 material.setTexture("SSAOMap", ssaoPass.getRenderedTexture());
166+ material.setVector2("FrustumNearFar", frustumNearFar);
167+ material.setBoolean("UseAo", useAo);
168+ material.setBoolean("UseOnlyAo", useOnlyAo);
173169
174170 ssaoMat.setVector3("FrustumCorner", frustumCorner);
175171 ssaoMat.setFloat("SampleRadius", sampleRadius);
176172 ssaoMat.setFloat("Intensity", intensity);
177173 ssaoMat.setFloat("Scale", scale);
178174 ssaoMat.setFloat("Bias", bias);
179- material.setBoolean("UseAo", useAo);
180- material.setBoolean("UseOnlyAo", useOnlyAo);
181175 ssaoMat.setVector2("FrustumNearFar", frustumNearFar);
182- material.setVector2("FrustumNearFar", frustumNearFar);
183176 ssaoMat.setParam("Samples", VarType.Vector2Array, samples);
184177 ssaoMat.setBoolean("ApproximateNormals", approximateNormals);
185178
@@ -189,7 +182,6 @@ public boolean requiresDepthAsTexture() {
189182 float blurScale = 2f;
190183 material.setFloat("XScale", blurScale * xScale);
191184 material.setFloat("YScale", blurScale * yScale);
192-
193185 }
194186
195187 @Override
@@ -198,18 +190,20 @@ protected void cleanUpFilter(Renderer r) {
198190 }
199191
200192 /**
201- * Return the bias<br>
202- * see {@link #setBias(float bias)}
203- * @return bias
193+ * Returns the bias value used in the SSAO calculation.
194+ *
195+ * @return The bias value.
196+ * @see #setBias(float)
204197 */
205198 public float getBias() {
206199 return bias;
207200 }
208201
209202 /**
210- * Sets the width of the occlusion cone considered by the occludee default is 0.1f
203+ * Sets the width of the occlusion cone considered by the occludee.
204+ * A higher bias means a wider cone, resulting in less self-occlusion.
211205 *
212- * @param bias the desired width (default=0.1)
206+ * @param bias The desired bias value (default: 0.1f).
213207 */
214208 public void setBias(float bias) {
215209 this.bias = bias;
@@ -219,62 +213,65 @@ public void setBias(float bias) {
219213 }
220214
221215 /**
222- * returns the ambient occlusion intensity
223- * @return intensity
216+ * Returns the ambient occlusion intensity.
217+ *
218+ * @return The intensity value.
224219 */
225220 public float getIntensity() {
226221 return intensity;
227222 }
228223
229224 /**
230- * Sets the Ambient occlusion intensity default is 1.5
225+ * Sets the ambient occlusion intensity. A higher intensity makes the ambient
226+ * occlusion effect more pronounced.
231227 *
232- * @param intensity the desired intensity (default=1.5)
228+ * @param intensity The desired intensity (default: 1.5f).
233229 */
234230 public void setIntensity(float intensity) {
235231 this.intensity = intensity;
236232 if (ssaoMat != null) {
237233 ssaoMat.setFloat("Intensity", intensity);
238234 }
239-
240235 }
241236
242237 /**
243- * returns the sample radius<br>
244- * see {link setSampleRadius(float sampleRadius)}
245- * @return the sample radius
238+ * Returns the sample radius used in the SSAO calculation.
239+ *
240+ * @return The sample radius.
241+ * @see #setSampleRadius(float)
246242 */
247243 public float getSampleRadius() {
248244 return sampleRadius;
249245 }
250246
251247 /**
252- * Sets the radius of the area where random samples will be picked default 5.1f
248+ * Sets the radius of the area where random samples will be picked for SSAO.
249+ * A larger radius considers more distant occluders.
253250 *
254- * @param sampleRadius the desired radius (default=5.1)
251+ * @param sampleRadius The desired radius (default: 5.1f).
255252 */
256253 public void setSampleRadius(float sampleRadius) {
257254 this.sampleRadius = sampleRadius;
258255 if (ssaoMat != null) {
259256 ssaoMat.setFloat("SampleRadius", sampleRadius);
260257 }
261-
262258 }
263259
264260 /**
265- * returns the scale<br>
266- * see {@link #setScale(float scale)}
267- * @return scale
261+ * Returns the scale value used in the SSAO calculation.
262+ *
263+ * @return The scale value.
264+ * @see #setScale(float)
268265 */
269266 public float getScale() {
270267 return scale;
271268 }
272269
273270 /**
274- *
275- * Returns the distance between occluders and occludee. default 0.2f
271+ * Sets the distance between occluders and occludee for SSAO.
272+ * This essentially controls the "thickness" of the ambient occlusion.
276273 *
277- * @param scale the desired distance (default=0.2)
274+ * @param scale The desired distance (default: 0.2f).
278275 */
279276 public void setScale(float scale) {
280277 this.scale = scale;
@@ -284,15 +281,38 @@ public void setScale(float scale) {
284281 }
285282
286283 /**
287- * debugging only , will be removed
284+ * Sets whether to use approximate normals for the SSAO calculation.
285+ * If `true`, normals are derived from the depth buffer. If `false`, a separate
286+ * normal pass is rendered.
287+ *
288+ * @param approximateNormals `true` to use approximate normals, `false` to use a normal pass.
289+ */
290+ public void setApproximateNormals(boolean approximateNormals) {
291+ this.approximateNormals = approximateNormals;
292+ if (ssaoMat != null) {
293+ ssaoMat.setBoolean("ApproximateNormals", approximateNormals);
294+ }
295+ }
296+
297+ /**
298+ * Checks if approximate normals are being used for SSAO calculation.
299+ *
300+ * @return `true` if approximate normals are used, `false` otherwise.
301+ */
302+ public boolean isApproximateNormals() {
303+ return approximateNormals;
304+ }
305+
306+ /**
307+ * debugging only, will be removed
288308 * @return true if using ambient occlusion
289309 */
290310 public boolean isUseAo() {
291311 return useAo;
292312 }
293313
294314 /**
295- * debugging only , will be removed
315+ * debugging only, will be removed
296316 *
297317 * @param useAo true to enable, false to disable (default=true)
298318 */
@@ -301,30 +321,18 @@ public void setUseAo(boolean useAo) {
301321 if (material != null) {
302322 material.setBoolean("UseAo", useAo);
303323 }
304-
305- }
306-
307- public void setApproximateNormals(boolean approximateNormals) {
308- this.approximateNormals = approximateNormals;
309- if (ssaoMat != null) {
310- ssaoMat.setBoolean("ApproximateNormals", approximateNormals);
311- }
312- }
313-
314- public boolean isApproximateNormals() {
315- return approximateNormals;
316324 }
317325
318326 /**
319- * debugging only , will be removed
327+ * debugging only, will be removed
320328 * @return useOnlyAo
321329 */
322330 public boolean isUseOnlyAo() {
323331 return useOnlyAo;
324332 }
325333
326334 /**
327- * debugging only , will be removed
335+ * debugging only, will be removed
328336 *
329337 * @param useOnlyAo true to enable, false to disable (default=false)
330338 */
@@ -343,6 +351,7 @@ public void write(JmeExporter ex) throws IOException {
343351 oc.write(intensity, "intensity", 1.5f);
344352 oc.write(scale, "scale", 0.2f);
345353 oc.write(bias, "bias", 0.1f);
354+ oc.write(approximateNormals, "approximateNormals", false);
346355 }
347356
348357 @Override
@@ -353,5 +362,6 @@ public void read(JmeImporter im) throws IOException {
353362 intensity = ic.readFloat("intensity", 1.5f);
354363 scale = ic.readFloat("scale", 0.2f);
355364 bias = ic.readFloat("bias", 0.1f);
365+ approximateNormals = ic.readBoolean("approximateNormals", false);
356366 }
357367}
0 commit comments