|
@@ -31,24 +31,16 @@
|
|
*/
|
|
*/
|
|
package com.jme3.light;
|
|
package com.jme3.light;
|
|
|
|
|
|
-import com.jme3.asset.AssetManager;
|
|
|
|
-import com.jme3.bounding.BoundingBox;
|
|
|
|
-import com.jme3.bounding.BoundingSphere;
|
|
|
|
-import com.jme3.bounding.BoundingVolume;
|
|
|
|
|
|
+import com.jme3.bounding.*;
|
|
import com.jme3.environment.EnvironmentCamera;
|
|
import com.jme3.environment.EnvironmentCamera;
|
|
import com.jme3.environment.LightProbeFactory;
|
|
import com.jme3.environment.LightProbeFactory;
|
|
-import com.jme3.environment.util.EnvMapUtils;
|
|
|
|
-import com.jme3.export.InputCapsule;
|
|
|
|
-import com.jme3.export.JmeExporter;
|
|
|
|
-import com.jme3.export.JmeImporter;
|
|
|
|
-import com.jme3.export.OutputCapsule;
|
|
|
|
-import com.jme3.export.Savable;
|
|
|
|
-import com.jme3.math.Vector3f;
|
|
|
|
|
|
+import com.jme3.export.*;
|
|
|
|
+import com.jme3.math.*;
|
|
import com.jme3.renderer.Camera;
|
|
import com.jme3.renderer.Camera;
|
|
-import com.jme3.scene.Node;
|
|
|
|
import com.jme3.scene.Spatial;
|
|
import com.jme3.scene.Spatial;
|
|
import com.jme3.texture.TextureCubeMap;
|
|
import com.jme3.texture.TextureCubeMap;
|
|
import com.jme3.util.TempVars;
|
|
import com.jme3.util.TempVars;
|
|
|
|
+
|
|
import java.io.IOException;
|
|
import java.io.IOException;
|
|
import java.util.logging.Level;
|
|
import java.util.logging.Level;
|
|
import java.util.logging.Logger;
|
|
import java.util.logging.Logger;
|
|
@@ -56,7 +48,7 @@ import java.util.logging.Logger;
|
|
/**
|
|
/**
|
|
* A LightProbe is not exactly a light. It holds environment map information used for Image Based Lighting.
|
|
* A LightProbe is not exactly a light. It holds environment map information used for Image Based Lighting.
|
|
* This is used for indirect lighting in the Physically Based Rendering pipeline.
|
|
* This is used for indirect lighting in the Physically Based Rendering pipeline.
|
|
- *
|
|
|
|
|
|
+ *
|
|
* A light probe has a position in world space. This is the position from where the Environment Map are rendered.
|
|
* A light probe has a position in world space. This is the position from where the Environment Map are rendered.
|
|
* There are two environment data structure held by the LightProbe :
|
|
* There are two environment data structure held by the LightProbe :
|
|
* - The irradiance spherical harmonics factors (used for indirect diffuse lighting in the PBR pipeline).
|
|
* - The irradiance spherical harmonics factors (used for indirect diffuse lighting in the PBR pipeline).
|
|
@@ -64,10 +56,10 @@ import java.util.logging.Logger;
|
|
* Note that when instantiating the LightProbe, both of those structures are null.
|
|
* Note that when instantiating the LightProbe, both of those structures are null.
|
|
* To compute them see {@link LightProbeFactory#makeProbe(com.jme3.environment.EnvironmentCamera, com.jme3.scene.Node)}
|
|
* To compute them see {@link LightProbeFactory#makeProbe(com.jme3.environment.EnvironmentCamera, com.jme3.scene.Node)}
|
|
* and {@link EnvironmentCamera}.
|
|
* and {@link EnvironmentCamera}.
|
|
- *
|
|
|
|
- * The light probe has an area of effect that is a bounding volume centered on its position. (for now only Bounding spheres are supported).
|
|
|
|
- *
|
|
|
|
- * A LightProbe will only be taken into account when it's marked as ready.
|
|
|
|
|
|
+ *
|
|
|
|
+ * The light probe has an area of effect centered on its position. It can have a Spherical area or an Oriented Box area
|
|
|
|
+ *
|
|
|
|
+ * A LightProbe will only be taken into account when it's marked as ready and enabled.
|
|
* A light probe is ready when it has valid environment map data set.
|
|
* A light probe is ready when it has valid environment map data set.
|
|
* Note that you should never call setReady yourself.
|
|
* Note that you should never call setReady yourself.
|
|
*
|
|
*
|
|
@@ -78,20 +70,25 @@ import java.util.logging.Logger;
|
|
public class LightProbe extends Light implements Savable {
|
|
public class LightProbe extends Light implements Savable {
|
|
|
|
|
|
private static final Logger logger = Logger.getLogger(LightProbe.class.getName());
|
|
private static final Logger logger = Logger.getLogger(LightProbe.class.getName());
|
|
|
|
+ public static final Matrix4f FALLBACK_MATRIX = new Matrix4f(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1);
|
|
|
|
|
|
private Vector3f[] shCoeffs;
|
|
private Vector3f[] shCoeffs;
|
|
private TextureCubeMap prefilteredEnvMap;
|
|
private TextureCubeMap prefilteredEnvMap;
|
|
- private BoundingVolume bounds = new BoundingSphere(1.0f, Vector3f.ZERO);
|
|
|
|
|
|
+ private ProbeArea area = new SphereProbeArea(Vector3f.ZERO, 1.0f);
|
|
private boolean ready = false;
|
|
private boolean ready = false;
|
|
private Vector3f position = new Vector3f();
|
|
private Vector3f position = new Vector3f();
|
|
- private Node debugNode;
|
|
|
|
private int nbMipMaps;
|
|
private int nbMipMaps;
|
|
|
|
|
|
|
|
+ public enum AreaType{
|
|
|
|
+ Spherical,
|
|
|
|
+ OrientedBox
|
|
|
|
+ }
|
|
|
|
+
|
|
/**
|
|
/**
|
|
- * Empty constructor used for serialization.
|
|
|
|
|
|
+ * Empty constructor used for serialization.
|
|
* You should never call it, use {@link LightProbeFactory#makeProbe(com.jme3.environment.EnvironmentCamera, com.jme3.scene.Node)} instead
|
|
* You should never call it, use {@link LightProbeFactory#makeProbe(com.jme3.environment.EnvironmentCamera, com.jme3.scene.Node)} instead
|
|
*/
|
|
*/
|
|
- public LightProbe() {
|
|
|
|
|
|
+ public LightProbe() {
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -104,13 +101,59 @@ public class LightProbe extends Light implements Savable {
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
- * Sets the prefiltered environment map
|
|
|
|
- * @param prefileteredEnvMap the prefiltered environment map
|
|
|
|
|
|
+ * Sets the prefiltered environment map
|
|
|
|
+ * @param prefileteredEnvMap the prefiltered environment map
|
|
*/
|
|
*/
|
|
public void setPrefilteredMap(TextureCubeMap prefileteredEnvMap) {
|
|
public void setPrefilteredMap(TextureCubeMap prefileteredEnvMap) {
|
|
this.prefilteredEnvMap = prefileteredEnvMap;
|
|
this.prefilteredEnvMap = prefileteredEnvMap;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
+ * Returns the data to send to the shader.
|
|
|
|
+ * This is a column major matrix that is not a classic transform matrix, it's laid out in a particular way
|
|
|
|
+ // 3x3 rot mat|
|
|
|
|
+ // 0 1 2 | 3
|
|
|
|
+ // 0 | ax bx cx | px | )
|
|
|
|
+ // 1 | ay by cy | py | probe position
|
|
|
|
+ // 2 | az bz cz | pz | )
|
|
|
|
+ // --|----------|
|
|
|
|
+ // 3 | sx sy sz sp | -> 1/probe radius + nbMipMaps
|
|
|
|
+ // --scale--
|
|
|
|
+ * <p>
|
|
|
|
+ * (ax, ay, az) is the pitch rotation axis
|
|
|
|
+ * (bx, by, bz) is the yaw rotation axis
|
|
|
|
+ * (cx, cy, cz) is the roll rotation axis
|
|
|
|
+ * Like in a standard 3x3 rotation matrix.
|
|
|
|
+ * It's also the valid rotation matrix of the probe in world space.
|
|
|
|
+ * Note that for the Spherical Probe area this part is a 3x3 identity matrix.
|
|
|
|
+ * <p>
|
|
|
|
+ * (px, py, pz) is the position of the center of the probe in world space
|
|
|
|
+ * Like in a valid 4x4 transform matrix.
|
|
|
|
+ * <p>
|
|
|
|
+ * (sx, sy, sy) is the extent of the probe ( the scale )
|
|
|
|
+ * In a standard transform matrix the scale is applied to the rotation matrix part.
|
|
|
|
+ * In the shader we need the rotation and the scale to be separated, doing this avoid to extract
|
|
|
|
+ * the scale from a classic transform matrix in the shader
|
|
|
|
+ * <p>
|
|
|
|
+ * (sp) is a special entry, it contains the packed number of mip maps of the probe and the inverse radius for the probe.
|
|
|
|
+ * since the inverse radius in lower than 1, it's packed in the decimal part of the float.
|
|
|
|
+ * The number of mip maps is packed in the integer part of the float.
|
|
|
|
+ * (ie: for 6 mip maps and a radius of 3, sp= 6.3333333)
|
|
|
|
+ * <p>
|
|
|
|
+ * The radius is obvious for a SphereProbeArea,
|
|
|
|
+ * but in the case of a OrientedBoxProbeArea it's the max of the extent vector's components.
|
|
|
|
+ */
|
|
|
|
+ public Matrix4f getUniformMatrix(){
|
|
|
|
+
|
|
|
|
+ Matrix4f mat = area.getUniformMatrix();
|
|
|
|
+
|
|
|
|
+ // setting the (sp) entry of the matrix
|
|
|
|
+ mat.m33 = nbMipMaps + 1f / area.getRadius();
|
|
|
|
+
|
|
|
|
+ return mat;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
@Override
|
|
@Override
|
|
public void write(JmeExporter ex) throws IOException {
|
|
public void write(JmeExporter ex) throws IOException {
|
|
super.write(ex);
|
|
super.write(ex);
|
|
@@ -118,7 +161,7 @@ public class LightProbe extends Light implements Savable {
|
|
oc.write(shCoeffs, "shCoeffs", null);
|
|
oc.write(shCoeffs, "shCoeffs", null);
|
|
oc.write(prefilteredEnvMap, "prefilteredEnvMap", null);
|
|
oc.write(prefilteredEnvMap, "prefilteredEnvMap", null);
|
|
oc.write(position, "position", null);
|
|
oc.write(position, "position", null);
|
|
- oc.write(bounds, "bounds", new BoundingSphere(1.0f, Vector3f.ZERO));
|
|
|
|
|
|
+ oc.write(area, "area", new SphereProbeArea(Vector3f.ZERO, 1.0f));
|
|
oc.write(ready, "ready", false);
|
|
oc.write(ready, "ready", false);
|
|
oc.write(nbMipMaps, "nbMipMaps", 0);
|
|
oc.write(nbMipMaps, "nbMipMaps", 0);
|
|
}
|
|
}
|
|
@@ -127,10 +170,16 @@ public class LightProbe extends Light implements Savable {
|
|
public void read(JmeImporter im) throws IOException {
|
|
public void read(JmeImporter im) throws IOException {
|
|
super.read(im);
|
|
super.read(im);
|
|
InputCapsule ic = im.getCapsule(this);
|
|
InputCapsule ic = im.getCapsule(this);
|
|
-
|
|
|
|
|
|
+
|
|
prefilteredEnvMap = (TextureCubeMap) ic.readSavable("prefilteredEnvMap", null);
|
|
prefilteredEnvMap = (TextureCubeMap) ic.readSavable("prefilteredEnvMap", null);
|
|
position = (Vector3f) ic.readSavable("position", null);
|
|
position = (Vector3f) ic.readSavable("position", null);
|
|
- bounds = (BoundingVolume) ic.readSavable("bounds", new BoundingSphere(1.0f, Vector3f.ZERO));
|
|
|
|
|
|
+ area = (ProbeArea)ic.readSavable("area", null);
|
|
|
|
+ if(area == null) {
|
|
|
|
+ // retro compat
|
|
|
|
+ BoundingSphere bounds = (BoundingSphere) ic.readSavable("bounds", new BoundingSphere(1.0f, Vector3f.ZERO));
|
|
|
|
+ area = new SphereProbeArea(bounds.getCenter(), bounds.getRadius());
|
|
|
|
+ }
|
|
|
|
+ area.setCenter(position);
|
|
nbMipMaps = ic.readInt("nbMipMaps", 0);
|
|
nbMipMaps = ic.readInt("nbMipMaps", 0);
|
|
ready = ic.readBoolean("ready", false);
|
|
ready = ic.readBoolean("ready", false);
|
|
|
|
|
|
@@ -146,25 +195,49 @@ public class LightProbe extends Light implements Savable {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* returns the bounding volume of this LightProbe
|
|
* returns the bounding volume of this LightProbe
|
|
* @return a bounding volume.
|
|
* @return a bounding volume.
|
|
|
|
+ * @deprecated use {@link LightProbe#getArea()}
|
|
*/
|
|
*/
|
|
|
|
+ @Deprecated
|
|
public BoundingVolume getBounds() {
|
|
public BoundingVolume getBounds() {
|
|
- return bounds;
|
|
|
|
|
|
+ return new BoundingSphere(((SphereProbeArea)area).getRadius(), ((SphereProbeArea)area).getCenter());
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* Sets the bounds of this LightProbe
|
|
* Sets the bounds of this LightProbe
|
|
- * Note that for now only BoundingSphere is supported and this method will
|
|
|
|
|
|
+ * Note that for now only BoundingSphere is supported and this method will
|
|
* throw an UnsupportedOperationException with any other BoundingVolume type
|
|
* throw an UnsupportedOperationException with any other BoundingVolume type
|
|
* @param bounds the bounds of the LightProbe
|
|
* @param bounds the bounds of the LightProbe
|
|
|
|
+ * @deprecated
|
|
*/
|
|
*/
|
|
|
|
+ @Deprecated
|
|
public void setBounds(BoundingVolume bounds) {
|
|
public void setBounds(BoundingVolume bounds) {
|
|
- if( bounds.getType()!= BoundingVolume.Type.Sphere){
|
|
|
|
- throw new UnsupportedOperationException("For not only BoundingSphere are suported for LightProbe");
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public ProbeArea getArea() {
|
|
|
|
+ return area;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public void setAreaType(AreaType type){
|
|
|
|
+ switch (type){
|
|
|
|
+ case Spherical:
|
|
|
|
+ area = new SphereProbeArea(Vector3f.ZERO, 1.0f);
|
|
|
|
+ break;
|
|
|
|
+ case OrientedBox:
|
|
|
|
+ area = new OrientedBoxProbeArea(new Transform());
|
|
|
|
+ area.setCenter(position);
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public AreaType getAreaType(){
|
|
|
|
+ if(area instanceof SphereProbeArea){
|
|
|
|
+ return AreaType.Spherical;
|
|
}
|
|
}
|
|
- this.bounds = bounds;
|
|
|
|
|
|
+ return AreaType.OrientedBox;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -186,27 +259,6 @@ public class LightProbe extends Light implements Savable {
|
|
this.ready = ready;
|
|
this.ready = ready;
|
|
}
|
|
}
|
|
|
|
|
|
- /**
|
|
|
|
- * For debuging porpose only
|
|
|
|
- * Will return a Node meant to be added to a GUI presenting the 2 cube maps in a cross pattern with all the mip maps.
|
|
|
|
- *
|
|
|
|
- * @param manager the asset manager
|
|
|
|
- * @return a debug node
|
|
|
|
- */
|
|
|
|
- public Node getDebugGui(AssetManager manager) {
|
|
|
|
- if (!ready) {
|
|
|
|
- throw new UnsupportedOperationException("This EnvProbe is not ready yet, try to test isReady()");
|
|
|
|
- }
|
|
|
|
- if (debugNode == null) {
|
|
|
|
- debugNode = new Node("debug gui probe");
|
|
|
|
- Node debugPfemCm = EnvMapUtils.getCubeMapCrossDebugViewWithMipMaps(getPrefilteredEnvMap(), manager);
|
|
|
|
- debugNode.attachChild(debugPfemCm);
|
|
|
|
- debugPfemCm.setLocalTranslation(520, 0, 0);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return debugNode;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
public Vector3f[] getShCoeffs() {
|
|
public Vector3f[] getShCoeffs() {
|
|
return shCoeffs;
|
|
return shCoeffs;
|
|
}
|
|
}
|
|
@@ -229,7 +281,7 @@ public class LightProbe extends Light implements Savable {
|
|
*/
|
|
*/
|
|
public void setPosition(Vector3f position) {
|
|
public void setPosition(Vector3f position) {
|
|
this.position.set(position);
|
|
this.position.set(position);
|
|
- getBounds().setCenter(position);
|
|
|
|
|
|
+ area.setCenter(position);
|
|
}
|
|
}
|
|
|
|
|
|
public int getNbMipMaps() {
|
|
public int getNbMipMaps() {
|
|
@@ -242,12 +294,17 @@ public class LightProbe extends Light implements Savable {
|
|
|
|
|
|
@Override
|
|
@Override
|
|
public boolean intersectsBox(BoundingBox box, TempVars vars) {
|
|
public boolean intersectsBox(BoundingBox box, TempVars vars) {
|
|
- return getBounds().intersectsBoundingBox(box);
|
|
|
|
|
|
+ return area.intersectsBox(box, vars);
|
|
}
|
|
}
|
|
|
|
|
|
@Override
|
|
@Override
|
|
public boolean intersectsFrustum(Camera camera, TempVars vars) {
|
|
public boolean intersectsFrustum(Camera camera, TempVars vars) {
|
|
- return camera.contains(bounds) != Camera.FrustumIntersect.Outside;
|
|
|
|
|
|
+ return area.intersectsFrustum(camera, vars);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public boolean intersectsSphere(BoundingSphere sphere, TempVars vars) {
|
|
|
|
+ return area.intersectsSphere(sphere, vars);
|
|
}
|
|
}
|
|
|
|
|
|
@Override
|
|
@Override
|
|
@@ -267,14 +324,8 @@ public class LightProbe extends Light implements Savable {
|
|
|
|
|
|
@Override
|
|
@Override
|
|
public String toString() {
|
|
public String toString() {
|
|
- return "Light Probe : " + name + " at " + position + " / " + bounds;
|
|
|
|
|
|
+ return "Light Probe : " + name + " at " + position + " / " + area;
|
|
}
|
|
}
|
|
|
|
|
|
- @Override
|
|
|
|
- public boolean intersectsSphere(BoundingSphere sphere, TempVars vars) {
|
|
|
|
- return getBounds().intersectsSphere(sphere);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
-
|
|
|
|
|
|
|
|
}
|
|
}
|