Obs.: I am improving the explanation of this OP based on the discussions below.
Coming from this topic (wich is a completely different context that actually has an answer here),
I managed to get a more precise error report concerning such exception thrown at Spatial.checkCulling()
.
Yes, I understand I must learn how to avoid that exception by coding properly. But a more precise exception information would have been very helpful years ago when it first happened to me, and I simply made my project single threaded (but it is multi-threaded again now).
To just say the problem happened at “Root Node” left me clueless for several days (may be months).
So basically, patching Node.java
with this code, that will only be executed whenever the exception is ready to be thrown, makes things much easier to me, and I think will help other people too:
public ArrayList<Spatial> recursiveFindModifications(ArrayList<Spatial> asptIn){
if(asptIn==null)asptIn = new ArrayList<Spatial>();
for(Spatial sptChild : getChildren()){
if(sptChild.refreshFlags!=0){
asptIn.add(sptChild);
}
if(sptChild instanceof Node){
((Node) sptChild).recursiveFindModifications(asptIn);
}
}
return asptIn;
}
@Override
public boolean checkCulling(Camera cam) {
if (refreshFlags != 0) {
ArrayList<Spatial> aspt = recursiveFindModifications(null);
String strSpatialNames = getName();
for(Spatial spt : aspt){
strSpatialNames+=","+spt.getName();
}
throw new IllegalStateException("Scene graph is not properly updated for rendering.\n"
+ "State was changed after rootNode.updateGeometricState() call. \n"
+ "Make sure you do not modify the scene from another thread!\n"
+ "Problem spatial name(s): " + strSpatialNames);
}
return super.checkCulling(cam);
}
and here as a patch
--- ./src/com/jme3/scene/Node.java
+++ ./src/com/jme3/scene/Node.java
@@ -38,8 +38,10 @@
import com.jme3.export.JmeImporter;
import com.jme3.export.Savable;
import com.jme3.material.Material;
+import com.jme3.renderer.Camera;
import com.jme3.util.SafeArrayList;
import com.jme3.util.TempVars;
+
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@@ -231,7 +233,36 @@
s.updateLogicalState(tpf);
}
}
-
+
+ public ArrayList<Spatial> recursiveFindModifications(ArrayList<Spatial> asptIn){
+ if(asptIn==null)asptIn = new ArrayList<Spatial>();
+ for(Spatial sptChild : getChildren()){
+ if(sptChild.refreshFlags!=0){
+ asptIn.add(sptChild);
+ }
+ if(sptChild instanceof Node){
+ ((Node) sptChild).recursiveFindModifications(asptIn);
+ }
+ }
+ return asptIn;
+ }
+
+ @Override
+ public boolean checkCulling(Camera cam) {
+ if (refreshFlags != 0) {
+ ArrayList<Spatial> aspt = recursiveFindModifications(null);
+ String strSpatialNames = getName();
+ for(Spatial spt : aspt){
+ strSpatialNames+=","+spt.getName();
+ }
+ throw new IllegalStateException("Scene graph is not properly updated for rendering.\n"
+ + "State was changed after rootNode.updateGeometricState() call. \n"
+ + "Make sure you do not modify the scene from another thread!\n"
+ + "Problem spatial name(s): " + strSpatialNames);
+ }
+ return super.checkCulling(cam);
+ }
+
@Override
public void updateGeometricState(){
if (refreshFlags == 0) {
I believe it can be better implemented, so if you can improve it, post back please.
It will show not only the root node, but all other nodes and spatials (names) that got modified improperly. That is the important/precise clue to we pin-point the problem in our project.
This problem can also happen if you use someone else’s library incorrectly, what would make things even more difficult by not knowing enough about how that library works.
So basically, to make it actually useful, you have to set your Spatial names with high quality, like putting the name of a class, unique identifiers, your fancy types etc. Mine looks like this: “MySpecialSpatial.java:123:Hero2”. So now, the error message is like “Root Node,MySpecialSpatial.java:123:Hero2”.