Skip to content

Commit 7bd65d6

Browse files
authored
Improve IBL baker performance, Singlepass Spherical Harmonics baker and Hammersley based sampler (#2779)
* singlepass sph baker and fast path * fix cloning and improve baker performances
1 parent 6dc668b commit 7bd65d6

7 files changed

Lines changed: 336 additions & 89 deletions

File tree

jme3-core/src/main/java/com/jme3/environment/EnvironmentProbeControl.java

Lines changed: 64 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@
3636
import java.util.function.Predicate;
3737
import com.jme3.asset.AssetManager;
3838
import com.jme3.environment.baker.IBLGLEnvBakerLight;
39-
import com.jme3.environment.baker.IBLHybridEnvBakerLight;
4039
import com.jme3.export.InputCapsule;
4140
import com.jme3.export.JmeExporter;
4241
import com.jme3.export.JmeImporter;
@@ -49,7 +48,6 @@
4948
import com.jme3.scene.Node;
5049
import com.jme3.scene.Spatial;
5150
import com.jme3.scene.control.Control;
52-
import com.jme3.texture.Image.Format;
5351

5452
/**
5553
* A control that automatically handles environment bake and rebake including
@@ -87,10 +85,12 @@ public class EnvironmentProbeControl extends LightProbe implements Control {
8785
private float frustumNear = 0.001f, frustumFar = 1000f;
8886
private String uuid = "none";
8987
private boolean enabled = true;
90-
88+
private IBLGLEnvBakerLight.SphericalHarmonicsMode sphericalHarmonicsMode =
89+
IBLGLEnvBakerLight.SphericalHarmonicsMode.AUTO;
9190
private Predicate<Geometry> filter = (s) -> {
9291
return s.getUserData("tags.env") != null || s.getUserData("tags.env.env" + uuid) != null;
9392
};
93+
private transient IBLGLEnvBakerLight baker;
9494

9595
protected EnvironmentProbeControl() {
9696
super();
@@ -212,11 +212,47 @@ public boolean isRequiredSavableResults() {
212212
return requiredSavableResults;
213213
}
214214

215+
/**
216+
* Sets how spherical harmonics coefficients are baked by this control.
217+
*
218+
* @param mode the spherical harmonics bake mode
219+
*/
220+
public void setSphericalHarmonicsMode(IBLGLEnvBakerLight.SphericalHarmonicsMode mode) {
221+
if (mode == null) {
222+
throw new IllegalArgumentException("mode cannot be null");
223+
}
224+
sphericalHarmonicsMode = mode;
225+
}
226+
227+
/**
228+
* Returns the spherical harmonics bake mode used by this control.
229+
*
230+
* @return the spherical harmonics bake mode
231+
*/
232+
public IBLGLEnvBakerLight.SphericalHarmonicsMode getSphericalHarmonicsMode() {
233+
return sphericalHarmonicsMode;
234+
}
235+
236+
/**
237+
* Enables or disables the spherical harmonics fast path explicitly.
238+
*
239+
* @param enabled true to use the fast path, false to use the quality path
240+
*/
241+
public void setSphericalHarmonicsFastPathEnabled(boolean enabled) {
242+
setSphericalHarmonicsMode(enabled
243+
? IBLGLEnvBakerLight.SphericalHarmonicsMode.FAST
244+
: IBLGLEnvBakerLight.SphericalHarmonicsMode.QUALITY);
245+
}
246+
215247
@Override
216248
public void setSpatial(Spatial spatial) {
217249
if (this.spatial != null && spatial != null && spatial != this.spatial) {
218250
throw new IllegalStateException("This control has already been added to a Spatial");
219251
}
252+
if (spatial == null && baker != null) {
253+
baker.clean();
254+
baker = null;
255+
}
220256
this.spatial = spatial;
221257
if (spatial != null) spatial.addLight(this);
222258
}
@@ -231,7 +267,12 @@ public void render(RenderManager rm, ViewPort vp) {
231267
if (!isEnabled()) return;
232268
if (bakeNeeded) {
233269
bakeNeeded = false;
234-
rebakeNow(rm);
270+
try {
271+
rebakeNow(rm);
272+
} finally {
273+
rm.getRenderer().setFrameBuffer(vp.getOutputFrameBuffer());
274+
rm.setCamera(vp.getCamera(), false);
275+
}
235276
}
236277
}
237278

@@ -285,11 +326,23 @@ public float getFrustumFar() {
285326
*/
286327
public void setAssetManager(AssetManager assetManager) {
287328
this.assetManager = assetManager;
329+
if (baker != null) {
330+
baker.clean();
331+
baker = null;
332+
}
333+
}
334+
335+
private IBLGLEnvBakerLight getBaker(RenderManager renderManager) {
336+
if (baker == null) {
337+
baker = new IBLGLEnvBakerLight(renderManager, assetManager, null,
338+
null, envMapSize, envMapSize);
339+
}
340+
return baker;
288341
}
289342

290343
void rebakeNow(RenderManager renderManager) {
291-
IBLHybridEnvBakerLight baker = new IBLGLEnvBakerLight(renderManager, assetManager, null,
292-
null, envMapSize, envMapSize);
344+
IBLGLEnvBakerLight baker = getBaker(renderManager);
345+
baker.setSphericalHarmonicsMode(sphericalHarmonicsMode);
293346

294347
baker.setTexturePulling(isRequiredSavableResults());
295348
baker.bakeEnvironment(spatial, getPosition(), frustumNear, frustumFar, filter);
@@ -304,8 +357,6 @@ void rebakeNow(RenderManager renderManager) {
304357
setShCoeffs(baker.getSphericalHarmonicsCoefficients());
305358
setPosition(Vector3f.ZERO);
306359
setReady(true);
307-
308-
baker.clean();
309360
}
310361

311362
public void setEnabled(boolean enabled) {
@@ -332,6 +383,8 @@ public void write(JmeExporter ex) throws IOException {
332383
oc.write(frustumFar, "frustumFar", 1000f);
333384
oc.write(frustumNear, "frustumNear", 0.001f);
334385
oc.write(uuid, "envProbeControlUUID", "none");
386+
oc.write(sphericalHarmonicsMode, "sphericalHarmonicsMode",
387+
IBLGLEnvBakerLight.SphericalHarmonicsMode.AUTO);
335388
}
336389

337390
@Override
@@ -347,6 +400,9 @@ public void read(JmeImporter im) throws IOException {
347400
frustumFar = ic.readFloat("frustumFar", 1000f);
348401
frustumNear = ic.readFloat("frustumNear", 0.001f);
349402
uuid = ic.readString("envProbeControlUUID", "none");
403+
sphericalHarmonicsMode = ic.readEnum("sphericalHarmonicsMode",
404+
IBLGLEnvBakerLight.SphericalHarmonicsMode.class,
405+
IBLGLEnvBakerLight.SphericalHarmonicsMode.AUTO);
350406
}
351407

352408
}

jme3-core/src/main/java/com/jme3/environment/baker/GenericEnvBaker.java

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ public abstract class GenericEnvBaker implements EnvBaker {
105105
protected final Camera cam;
106106
protected boolean texturePulling = false;
107107
protected List<ByteArrayOutputStream> bos = new ArrayList<>();
108+
private FrameBuffer[] envBakers;
108109

109110
protected GenericEnvBaker(RenderManager rm, AssetManager am, Format colorFormat, Format depthFormat, int env_size) {
110111
this.depthFormat = depthFormat;
@@ -178,18 +179,35 @@ protected Camera updateAndGetInternalCamera(int faceId, int w, int h, Vector3f p
178179

179180
@Override
180181
public void clean() {
182+
if (envBakers != null) {
183+
for (FrameBuffer envBaker : envBakers) {
184+
if (envBaker != null) {
185+
envBaker.dispose();
186+
}
187+
}
188+
envBakers = null;
189+
}
181190

182191
}
183192

184-
@Override
185-
public void bakeEnvironment(Spatial scene, Vector3f position, float frustumNear, float frustumFar, Predicate<Geometry> filter) {
186-
FrameBuffer envbakers[] = new FrameBuffer[6];
193+
private FrameBuffer[] getEnvBakers() {
194+
if (envBakers != null) {
195+
return envBakers;
196+
}
197+
198+
envBakers = new FrameBuffer[6];
187199
for (int i = 0; i < 6; i++) {
188-
envbakers[i] = new FrameBuffer(envMap.getImage().getWidth(), envMap.getImage().getHeight(), 1);
189-
envbakers[i].setDepthTarget(FrameBufferTarget.newTarget(getDepthFormat()));
190-
envbakers[i].setSrgb(false);
191-
envbakers[i].addColorTarget(FrameBufferTarget.newTarget(envMap).face(TextureCubeMap.Face.values()[i]));
200+
envBakers[i] = new FrameBuffer(envMap.getImage().getWidth(), envMap.getImage().getHeight(), 1);
201+
envBakers[i].setDepthTarget(FrameBufferTarget.newTarget(getDepthFormat()));
202+
envBakers[i].setSrgb(false);
203+
envBakers[i].addColorTarget(FrameBufferTarget.newTarget(envMap).face(TextureCubeMap.Face.values()[i]));
192204
}
205+
return envBakers;
206+
}
207+
208+
@Override
209+
public void bakeEnvironment(Spatial scene, Vector3f position, float frustumNear, float frustumFar, Predicate<Geometry> filter) {
210+
FrameBuffer envbakers[] = getEnvBakers();
193211

194212
if (isTexturePulling()) {
195213
startPulling();
@@ -212,8 +230,11 @@ public void bakeEnvironment(Spatial scene, Vector3f position, float frustumNear,
212230
Predicate<Geometry> ofilter = renderManager.getRenderFilter();
213231

214232
renderManager.setRenderFilter(filter);
215-
renderManager.renderViewPort(viewPort, 0.16f);
216-
renderManager.setRenderFilter(ofilter);
233+
try {
234+
renderManager.renderViewPort(viewPort, 0.16f);
235+
} finally {
236+
renderManager.setRenderFilter(ofilter);
237+
}
217238

218239
if (isTexturePulling()) {
219240
pull(envbaker, envMap, i);
@@ -226,10 +247,6 @@ public void bakeEnvironment(Spatial scene, Vector3f position, float frustumNear,
226247
}
227248

228249
envMap.getImage().clearUpdateNeeded();
229-
230-
for (int i = 0; i < 6; i++) {
231-
envbakers[i].dispose();
232-
}
233250
}
234251

235252
/**

0 commit comments

Comments
 (0)