diff --git a/jme3-core/src/main/java/com/jme3/light/DirectionalLight.java b/jme3-core/src/main/java/com/jme3/light/DirectionalLight.java
index ba142071f4..2d71d322a3 100644
--- a/jme3-core/src/main/java/com/jme3/light/DirectionalLight.java
+++ b/jme3-core/src/main/java/com/jme3/light/DirectionalLight.java
@@ -59,6 +59,17 @@ public class DirectionalLight extends Light {
* Creates a DirectionalLight
*/
public DirectionalLight() {
+ super();
+ }
+
+ /**
+ * Creates a DirectionalLight
+ * @param global if true, the light affects the entire tree from the root node,
+ * otherwise it only affects the children of the node in which it is attached.
+ */
+ public DirectionalLight(boolean global) {
+ this();
+ this.global = global;
}
/**
@@ -66,9 +77,21 @@ public DirectionalLight() {
* @param direction the light's direction
*/
public DirectionalLight(Vector3f direction) {
+ super();
setDirection(direction);
}
+ /**
+ * Creates a DirectionalLight with the given direction
+ * @param direction the light's direction
+ * @param global if true, the light affects the entire tree from the root node,
+ * otherwise it only affects the children of the node in which it is attached.
+ */
+ public DirectionalLight(Vector3f direction, boolean global) {
+ this(direction);
+ this.global = global;
+ }
+
/**
* Creates a DirectionalLight with the given direction and the given color
* @param direction the light's direction
@@ -79,6 +102,19 @@ public DirectionalLight(Vector3f direction, ColorRGBA color) {
setDirection(direction);
}
+ /**
+ * Creates a DirectionalLight with the given direction and the given color
+ * @param direction the light's direction
+ * @param color the light's color
+ * @param global if true, the light affects the entire tree from the root node,
+ * otherwise it only affects the children of the node in which it is attached.
+ */
+ public DirectionalLight(Vector3f direction, ColorRGBA color, boolean global) {
+ this(direction, color);
+ this.global = global;
+ }
+
+
@Override
public void computeLastDistance(Spatial owner) {
// directional lights are after ambient lights
diff --git a/jme3-core/src/main/java/com/jme3/light/Light.java b/jme3-core/src/main/java/com/jme3/light/Light.java
index cebb4ae2a0..4694243822 100644
--- a/jme3-core/src/main/java/com/jme3/light/Light.java
+++ b/jme3-core/src/main/java/com/jme3/light/Light.java
@@ -116,6 +116,7 @@ public int getId(){
* The light name.
*/
protected String name;
+ protected boolean global = false;
boolean frustumCheckNeeded = true;
boolean intersectsFrustum = false;
@@ -123,10 +124,30 @@ public int getId(){
protected Light() {
}
+
+ protected Light(boolean global) {
+ this.global = global;
+ }
+
+ protected Light(ColorRGBA color, boolean global) {
+ setColor(color);
+ }
+
protected Light(ColorRGBA color) {
setColor(color);
}
+
+ /**
+ * Returns true if this light affects the entire tree from the root node,
+ * otherwise returns false, meaning it only affects the children of the node
+ * in which it is attached.
+ * @return true if the light is global, otherwise false.
+ */
+ public boolean isGlobal() {
+ return global;
+ }
+
/**
* Returns the color of the light.
*
@@ -265,6 +286,7 @@ public void write(JmeExporter ex) throws IOException {
oc.write(color, "color", null);
oc.write(enabled, "enabled", true);
oc.write(name, "name", null);
+ oc.write(global, "global", false);
}
@Override
@@ -273,6 +295,7 @@ public void read(JmeImporter im) throws IOException {
color = (ColorRGBA) ic.readSavable("color", null);
enabled = ic.readBoolean("enabled", true);
name = ic.readString("name", null);
+ global = ic.readBoolean("global", false);
}
/**
diff --git a/jme3-core/src/main/java/com/jme3/light/LightList.java b/jme3-core/src/main/java/com/jme3/light/LightList.java
index 97c4c29820..d6179dd986 100644
--- a/jme3-core/src/main/java/com/jme3/light/LightList.java
+++ b/jme3-core/src/main/java/com/jme3/light/LightList.java
@@ -38,6 +38,7 @@
import com.jme3.util.SortUtil;
import java.io.IOException;
import java.util.*;
+import java.util.function.Predicate;
/**
* LightList is used internally by {@link Spatial}s to manage
@@ -230,6 +231,20 @@ public void sort(boolean transformChanged) {
* @param parent the parent's world-space LightList
*/
public void update(LightList local, LightList parent) {
+ update(local, parent, null);
+ }
+
+
+ /**
+ * Updates a "world-space" light list, using the spatial's local-space
+ * light list, its parent's world-space light list and an optional filter.
+ *
+ * @param local the local-space LightList (not null)
+ * @param parent the parent's world-space LightList
+ * @param filter an optional filter to apply to the lights
+ * (null means no filtering)
+ */
+ public void update(LightList local, LightList parent, Predicate filter) {
// clear the list as it will be reconstructed
// using the arguments
clear();
@@ -237,30 +252,32 @@ public void update(LightList local, LightList parent) {
while (list.length <= local.listSize) {
doubleSize();
}
-
- // add the lights from the local list
- System.arraycopy(local.list, 0, list, 0, local.listSize);
- for (int i = 0; i < local.listSize; i++) {
-// list[i] = local.list[i];
- distToOwner[i] = Float.NEGATIVE_INFINITY;
+
+ int localListSize = 0;// local.listSize;
+ for(int i=0;i children = n.getChildren();
+ for (int i = 0; i < children.size(); i++) {
+ Spatial child = children.get(i);
+ if ((child.refreshFlags & RF_GLOBAL_LIGHTS)!= 0) {
+ findGlobalLights(child, list);
+ }
+ }
+ }
+ }
+
@Override
public void updateGeometricState() {
if (refreshFlags == 0) {
@@ -249,6 +271,16 @@ public void updateGeometricState() {
if ((refreshFlags & RF_LIGHTLIST) != 0) {
updateWorldLightList();
}
+
+ boolean updateGlobalLights = (refreshFlags & RF_GLOBAL_LIGHTS) != 0;
+ if (updateGlobalLights){
+ // if root node, we collect the global lights
+ if (getParent() == null){
+ findGlobalLights(this, worldLights);
+ }
+ refreshFlags &= ~RF_GLOBAL_LIGHTS;
+ }
+
if ((refreshFlags & RF_TRANSFORM) != 0) {
// combine with parent transforms- same for all spatial
// subclasses.
@@ -266,6 +298,13 @@ public void updateGeometricState() {
// NOTE 9/19/09
// Although it does save a round trip,
for (Spatial child : children.getArray()) {
+ if (updateGlobalLights){
+ // we might have new global lights coming from a different
+ // branch of the scene graph, so we need to propagate the
+ // refresh flags down to all the children of every branch
+ child.refreshFlags |= RF_LIGHTLIST;
+ child.refreshFlags |= RF_GLOBAL_LIGHTS;
+ }
child.updateGeometricState();
}
}
diff --git a/jme3-core/src/main/java/com/jme3/scene/Spatial.java b/jme3-core/src/main/java/com/jme3/scene/Spatial.java
index 2fe1775d3e..384bbf643a 100644
--- a/jme3-core/src/main/java/com/jme3/scene/Spatial.java
+++ b/jme3-core/src/main/java/com/jme3/scene/Spatial.java
@@ -124,7 +124,8 @@ public enum BatchHint {
RF_BOUND = 0x02,
RF_LIGHTLIST = 0x04, // changes in light lists
RF_CHILD_LIGHTLIST = 0x08, // some child need geometry update
- RF_MATPARAM_OVERRIDE = 0x10;
+ RF_MATPARAM_OVERRIDE = 0x10,
+ RF_GLOBAL_LIGHTS = 0x20; // world affecting lights changed
protected CullHint cullHint = CullHint.Inherit;
protected BatchHint batchHint = BatchHint.Inherit;
@@ -282,18 +283,39 @@ protected void setTransformRefresh() {
setBoundRefresh();
}
+ protected boolean hasGlobalLights(){
+ for(int i = 0;i!l.isGlobal());
refreshFlags &= ~RF_LIGHTLIST;
} else {
assert (parent.refreshFlags & RF_LIGHTLIST) == 0 : "Illegal light list update. Problem spatial name: " + getName();
- worldLights.update(localLights, parent.worldLights);
+ worldLights.update(localLights, parent.worldLights, l->!l.isGlobal());
refreshFlags &= ~RF_LIGHTLIST;
}
}
@@ -952,6 +974,9 @@ public void updateGeometricState() {
if ((refreshFlags & RF_MATPARAM_OVERRIDE) != 0) {
updateMatParamOverrides();
}
+ if ((refreshFlags & RF_GLOBAL_LIGHTS) != 0) {
+ refreshFlags &= ~RF_GLOBAL_LIGHTS;
+ }
assert refreshFlags == 0 : "Illegal refresh flags state: " + refreshFlags + " for spatial " + getName();
}
@@ -1200,8 +1225,8 @@ public void addLight(Light light) {
* @see Spatial#addLight(com.jme3.light.Light)
*/
public void removeLight(Light light) {
- localLights.remove(light);
setLightListRefresh();
+ localLights.remove(light);
}
/**
diff --git a/jme3-plugins/src/gltf/java/com/jme3/scene/plugins/gltf/LightsPunctualExtensionLoader.java b/jme3-plugins/src/gltf/java/com/jme3/scene/plugins/gltf/LightsPunctualExtensionLoader.java
index 5b55c49b2e..9a9ecb7287 100644
--- a/jme3-plugins/src/gltf/java/com/jme3/scene/plugins/gltf/LightsPunctualExtensionLoader.java
+++ b/jme3-plugins/src/gltf/java/com/jme3/scene/plugins/gltf/LightsPunctualExtensionLoader.java
@@ -143,7 +143,7 @@ private SpotLight buildSpotLight(JsonObject obj) {
outerConeAngle = FastMath.HALF_PI - 0.000001f;
}
- SpotLight spotLight = new SpotLight();
+ SpotLight spotLight = new SpotLight(true);
spotLight.setName(name);
spotLight.setColor(color);
spotLight.setSpotRange(range);
@@ -167,7 +167,7 @@ private DirectionalLight buildDirectionalLight(JsonObject obj) {
ColorRGBA color = obj.has("color") ? GltfUtils.getAsColor(obj, "color") : new ColorRGBA(ColorRGBA.White);
color = lumensToColor(color, intensity);
- DirectionalLight directionalLight = new DirectionalLight();
+ DirectionalLight directionalLight = new DirectionalLight(true);
directionalLight.setName(name);
directionalLight.setColor(color);
directionalLight.setDirection(Vector3f.UNIT_Z.negate());
@@ -189,7 +189,7 @@ private PointLight buildPointLight(JsonObject obj) {
color = lumensToColor(color, intensity);
float range = obj.has("range") ? obj.get("range").getAsFloat() : Float.POSITIVE_INFINITY;
- PointLight pointLight = new PointLight();
+ PointLight pointLight = new PointLight(true);
pointLight.setName(name);
pointLight.setColor(color);
pointLight.setRadius(range);