com.jme3.environment.EnvironmentProbeControl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jme3-core Show documentation
Show all versions of jme3-core Show documentation
jMonkeyEngine is a 3-D game engine for adventurous Java developers
The newest version!
/*
* Copyright (c) 2009-2023 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.jme3.environment;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Predicate;
import com.jme3.asset.AssetManager;
import com.jme3.environment.baker.IBLGLEnvBakerLight;
import com.jme3.environment.baker.IBLHybridEnvBakerLight;
import com.jme3.export.InputCapsule;
import com.jme3.export.JmeExporter;
import com.jme3.export.JmeImporter;
import com.jme3.export.OutputCapsule;
import com.jme3.light.LightProbe;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.Control;
import com.jme3.texture.Image.Format;
/**
* A control that automatically handles environment bake and rebake including
* only tagged spatials.
*
* Simple usage example:
* 1. Load a scene
* Node scene=(Node)assetManager.loadModel("Scenes/MyScene.j3o");
* 2. Add one or more EnvironmentProbeControl to the root of the scene
* EnvironmentProbeControl ec1=new EnvironmentProbeControl(assetManager, 512);
* // EnvironmentProbeControl ec2=new EnvironmentProbeControl(assetManager, 512);
* 2b. (optional) Set the position of the probes
* ec1.setPosition(new Vector3f(0,0,0));
* // ec2.setPosition(new Vector3f(0,0,10));
* 3. Tag the spatials that are part of the environment
* scene.deepFirstTraversal(s->{
* if(s.getUserData("isEnvNode")!=null){
* EnvironmentProbeControl.tagGlobal(s);
* // or ec1.tag(s);
* // ec2.tag(s);
* }
* });
*
*
* @author Riccardo Balbo
*/
public class EnvironmentProbeControl extends LightProbe implements Control {
private static AtomicInteger instanceCounter = new AtomicInteger(0);
private AssetManager assetManager;
private boolean bakeNeeded = true;
private int envMapSize = 256;
private Spatial spatial;
private boolean requiredSavableResults = false;
private float frustumNear = 0.001f, frustumFar = 1000f;
private String uuid = "none";
private boolean enabled = true;
private Predicate filter = (s) -> {
return s.getUserData("tags.env") != null || s.getUserData("tags.env.env" + uuid) != null;
};
protected EnvironmentProbeControl() {
super();
uuid = System.currentTimeMillis() + "_" + instanceCounter.getAndIncrement();
this.setAreaType(AreaType.Spherical);
this.getArea().setRadius(Float.MAX_VALUE);
}
/**
* Creates a new environment probe control.
*
* @param assetManager
* the asset manager used to load the shaders needed for the
* baking
* @param size
* the size of side of the resulting cube map (eg. 1024)
*/
public EnvironmentProbeControl(AssetManager assetManager, int size) {
this();
this.envMapSize = size;
this.assetManager = assetManager;
}
/**
* Tags the specified spatial as part of the environment for this EnvironmentProbeControl.
* Only tagged spatials will be rendered in the environment map.
*
* @param s
* the spatial
*/
public void tag(Spatial s) {
if (s instanceof Node) {
Node n = (Node) s;
for (Spatial sx : n.getChildren()) {
tag(sx);
}
} else if (s instanceof Geometry) {
s.setUserData("tags.env.env" + uuid, true);
}
}
/**
* Untags the specified spatial as part of the environment for this
* EnvironmentProbeControl.
*
* @param s
* the spatial
*/
public void untag(Spatial s) {
if (s instanceof Node) {
Node n = (Node) s;
for (Spatial sx : n.getChildren()) {
untag(sx);
}
} else if (s instanceof Geometry) {
s.setUserData("tags.env.env" + uuid, null);
}
}
/**
* Tags the specified spatial as part of the environment for every EnvironmentProbeControl.
* Only tagged spatials will be rendered in the environment map.
*
* @param s
* the spatial
*/
public static void tagGlobal(Spatial s) {
if (s instanceof Node) {
Node n = (Node) s;
for (Spatial sx : n.getChildren()) {
tagGlobal(sx);
}
} else if (s instanceof Geometry) {
s.setUserData("tags.env", true);
}
}
/**
* Untags the specified spatial as part of the environment for every
* EnvironmentProbeControl.
*
* @param s the spatial
*/
public static void untagGlobal(Spatial s) {
if (s instanceof Node) {
Node n = (Node) s;
for (Spatial sx : n.getChildren()) {
untagGlobal(sx);
}
} else if (s instanceof Geometry) {
s.setUserData("tags.env", null);
}
}
@Override
public Control cloneForSpatial(Spatial spatial) {
throw new UnsupportedOperationException();
}
/**
* Requests savable results from the baking process. This will make the
* baking process slower and more memory intensive but will allow to
* serialize the results with the control.
*
* @param v
* true to enable (default: false)
*/
public void setRequiredSavableResults(boolean v) {
requiredSavableResults = v;
}
/**
* Returns true if savable results are required by this control.
*
* @return true if savable results are required.
*/
public boolean isRequiredSavableResults() {
return requiredSavableResults;
}
@Override
public void setSpatial(Spatial spatial) {
if (this.spatial != null && spatial != null && spatial != this.spatial) {
throw new IllegalStateException("This control has already been added to a Spatial");
}
this.spatial = spatial;
if (spatial != null) spatial.addLight(this);
}
@Override
public void update(float tpf) {
}
@Override
public void render(RenderManager rm, ViewPort vp) {
if (!isEnabled()) return;
if (bakeNeeded) {
bakeNeeded = false;
rebakeNow(rm);
}
}
/**
* Schedules a rebake of the environment map.
*/
public void rebake() {
bakeNeeded = true;
}
/**
* Sets the minimum distance to render.
*
* @param frustumNear the minimum distance to render
*/
public void setFrustumNear(float frustumNear) {
this.frustumNear = frustumNear;
}
/**
* Sets the maximum distance to render.
*
* @param frustumFar the maximum distance to render
*/
public void setFrustumFar(float frustumFar) {
this.frustumFar = frustumFar;
}
/**
* Gets the minimum distance to render.
*
* @return frustum near
*/
public float getFrustumNear() {
return frustumNear;
}
/**
* Gets the maximum distance to render.
*
* @return frustum far
*/
public float getFrustumFar() {
return frustumFar;
}
/**
* Sets the asset manager used to load the shaders needed for the baking.
*
* @param assetManager the asset manager
*/
public void setAssetManager(AssetManager assetManager) {
this.assetManager = assetManager;
}
void rebakeNow(RenderManager renderManager) {
IBLHybridEnvBakerLight baker = new IBLGLEnvBakerLight(renderManager, assetManager, Format.RGB16F, Format.Depth,
envMapSize, envMapSize);
baker.setTexturePulling(isRequiredSavableResults());
baker.bakeEnvironment(spatial, getPosition(), frustumNear, frustumFar, filter);
baker.bakeSpecularIBL();
baker.bakeSphericalHarmonicsCoefficients();
setPrefilteredMap(baker.getSpecularIBL());
int[] mipSizes = getPrefilteredEnvMap().getImage().getMipMapSizes();
setNbMipMaps(mipSizes != null ? mipSizes.length : 1);
setShCoeffs(baker.getSphericalHarmonicsCoefficients());
setPosition(Vector3f.ZERO);
setReady(true);
baker.clean();
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public boolean isEnabled() {
return enabled;
}
public Spatial getSpatial() {
return spatial;
}
@Override
public void write(JmeExporter ex) throws IOException {
super.write(ex);
OutputCapsule oc = ex.getCapsule(this);
oc.write(enabled, "enabled", true);
oc.write(spatial, "spatial", null);
oc.write(envMapSize, "size", 256);
oc.write(requiredSavableResults, "requiredSavableResults", false);
oc.write(bakeNeeded, "bakeNeeded", true);
oc.write(frustumFar, "frustumFar", 1000f);
oc.write(frustumNear, "frustumNear", 0.001f);
oc.write(uuid, "envProbeControlUUID", "none");
}
@Override
public void read(JmeImporter im) throws IOException {
super.read(im);
InputCapsule ic = im.getCapsule(this);
enabled = ic.readBoolean("enabled", true);
spatial = (Spatial) ic.readSavable("spatial", null);
envMapSize = ic.readInt("size", 256);
requiredSavableResults = ic.readBoolean("requiredSavableResults", false);
bakeNeeded = ic.readBoolean("bakeNeeded", true);
assetManager = im.getAssetManager();
frustumFar = ic.readFloat("frustumFar", 1000f);
frustumNear = ic.readFloat("frustumNear", 0.001f);
uuid = ic.readString("envProbeControlUUID", "none");
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy