I’m trying to collide a node with a BoundingSphere, and it’s sometimes returns the following error: java.lang.NullPointerException: Geometry: has null mesh
I have a theory as to why it’s doing this, but cannot seem to get it to tell me which geometry has the null mesh. any ideas?
[java] public boolean checkSpawn(SimpleApplication app, Node information, Spatial area)
{
CollisionResults temp = new CollisionResults();
BoundingSphere sphere = new BoundingSphere(area.getLocalScale().getX(), area.getLocalTranslation());
if(information.collideWith(sphere, temp) > 0)
{
The variable “already” looks undefined. Please post the whole function code. Also, if you do not care about null geometries, maybe you could just ignore them by wrapping the code like this?
Here’s the whole exeption. It’s big, and ugly, and points to the collidewith line of code:
SEVERE: null
java.util.concurrent.ExecutionException: java.lang.NullPointerException: Geometry: has null mesh
at java.util.concurrent.FutureTask.report(FutureTask.java:122)
at java.util.concurrent.FutureTask.get(FutureTask.java:188)
at spellSeed.spells.SpellControl.controlUpdate(SpellControl.java:105)
at com.jme3.scene.control.AbstractControl.update(AbstractControl.java:112)
at com.jme3.scene.Spatial.runControlUpdate(Spatial.java:570)
at com.jme3.scene.Spatial.updateLogicalState(Spatial.java:688)
at com.jme3.scene.Node.updateLogicalState(Node.java:145)
at com.jme3.scene.Node.updateLogicalState(Node.java:152)
at com.jme3.scene.Node.updateLogicalState(Node.java:152)
at com.jme3.app.SimpleApplication.update(SimpleApplication.java:244)
at com.jme3.system.lwjgl.LwjglAbstractDisplay.runLoop(LwjglAbstractDisplay.java:151)
at com.jme3.system.lwjgl.LwjglDisplay.runLoop(LwjglDisplay.java:185)
at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:228)
at java.lang.Thread.run(Thread.java:744)
Already is just a list that contains things previously collided with. I call this function rapidly in sequence, and don’t want it to register collisions with the same object repeatedly… sticking them in already allows me to filter out which objects have already been collided with.
Multithreading…
Darnit, I should have thought of that. I AM accessing the node (containing geometries) from multiple threads. I’m not modifying them at all, just using them to gather information… but you’re right, I shouldn’t do that.
What is the best way to proceed? Should I pass it the equivalent of information.clone()?
I really can’t answer because I don’t understand why you need to be doing it in the first place. It’s never come up for me personally so I can only imagine… and most of those imagined solutions are not ones I would have chosen either.
Oh it points to this line? : if(information.collideWith(sphere, temp) > 0)
Yyyyeah… so my first guess would be that the “area” variable that you pass to the function is used accross more than 1 thread at the same time and thus, it crashes. I had this happen in my own project too. What I ended up doing (dirty but does work 100% reliably) is to duplicate the mesh before colliding with it. It’s probably not the best way to go about I guess, but it works. Something like this, where c1 == area in your case I guess. It worked for me with the multithreading collision problem:
[java]
Geometry g = new Geometry();
g.setMesh(c1.getGeometry().getMesh());
g.setLocalTransform(c1.getGeometry().getWorldTransform());
CollisionResults results = new CollisionResults();
g.collideWith(ray, results);
Perhaps it would be better if I just told you what I’m trying to do… This is a fairly messy solution, anyway… perhaps you can guide me to a better technique.
I’ve got a ball-shaped objects of varying sizes. When those objects collide with objects in another node, they need to spawn more ball-shaped objects. When I call this function, it returns a boolean representing whether I need to spawn another ball or not.
If your application extends PhysicsCollisionListener, you could use the overrideable collision(PhysicsCollisionEvent event) function that comes with JME3, this way, you’d always be in the same thread when checking for collisions, no? I do not understand why you need to implements a bunch of threads to do this, but I do understand there is probably a lot more code than what I see from what you posted, so it may or may not make sense for what you’re doing I guess.
There are physical objects in my game, but not all the objects I want to collide with will be physical. Furthermore, I don’t want these ball-shaped objects to actually have any mass/affect the game. It only exists to spawn more balls.
I’m multi-threading because in-game, quite a few of these objects may be zinging around, and detecting collision every frame began to really affect my framerate. Multithreading it fixed my framerate but broke the function.
From your reactions, I’m beginning (yes, you actually managed to get through my skull :lol:) to get the idea that I’m going about this the completely wrong way. Trouble is, I have no idea what a better way would be. Is there a collision listener that does not involve physics?
Oh, the area variable is just a placeholder for now. It’s a visual indicator to tell me where the balls are. Eventually I’ll replace it with something else.
I’ll see if I can try your duplicated-mesh approach, but I have to do it to a whole node… I’ll see what I can work up. In the meantime, if I’m being an idiot and there’s a significantly better way to do this, tell me.
@ulfgur said:
There are physical objects in my game, but not all the objects I want to collide with will be physical. Furthermore, I don't want these ball-shaped objects to actually have any mass/affect the game. It only exists to spawn more balls.
OK gotcha there. Makes sense I guess then, but… did you know you could actually make zero-mass physical objects? You could maybe give it a shot to have all objects you want to collide physical, some with mass, some without it. You could simply use a ghostControl on those. It’s zero-mass and will not “bounce” around on anything, it’s EXACTLY like if there was no physical control attached with the very convenient exception that it will appear in the collision event! So therefore, you could detect collisions between your physical objects that do have a mass (or not, your choice) and the ghost controls… and voila! Every collision will be handled in the same thread. Read this paragraph: https://wiki.jmonkeyengine.org/legacy/doku.php/jme3:advanced:physics_listeners#physicsghostobjects
OK now I understand threading could speed up things a little, especially on 6-8 cores computers, so I give it to you that it’s interesting to create your own multithreaded collision handler. But as stated before, spatials should not be used accross different threads. I had this problem on my project too, it just won’t work reliably, sometimes it will crash, sometimes not, so you could try with my (very) dirty solution, it takes 1 minute to implement and see if the fps is too low for your taste.
@ulfgur said:
Oh, the area variable is just a placeholder for now. It's a visual indicator to tell me where the balls are. Eventually I'll replace it with something else.
BUT the question here is: Are you 100% sure this CANNOT be used/passed accross threads? Your function is called from threads, no? Is this a global-like variable? Because if so, then you have 1 problem there already.
OK, I’ve completed the first draft of your copied-mesh method. Now I don’t get any errors, but nothing happens when I fire the ball into a wall. Here’s my code:
[java]//my collision thread will collide with a copied interactNode. It will be copied to currentInteract.
currentInteract = new Node();
//I’ll display distill below
ArrayList<Geometry> temp = distill(interactNode);
//transfer the contents of distill to currentInteract
for(Geometry g : temp)
{
currentInteract.attachChild(g);
}
//ignore this line for now.; I'm 97% certain it's not causing issues
currentCast = (Node) cast.clone();
//submit the collision detection for threading.
result = Main.executor.submit(checkForSpawn);[/java]
Aaand here’s my distill function, which copies geometries from a given node. It’s recursive.
[java] public ArrayList<Geometry> distill(Spatial s)
{
if(s instanceof Node)
{
List<Spatial> temp = ((Node) s).getChildren();
ArrayList<Geometry> solution = new ArrayList<Geometry>();
for(Spatial t : temp)
{
solution.addAll(distill(t));
}
return solution;
}
if(s instanceof Geometry)
{
if(((Geometry) s ).getMesh() != null)
{
ArrayList<Geometry> temp = new ArrayList<Geometry>();
Geometry g = new Geometry();
g.setMesh(((Geometry) s ).getMesh());
g.setLocalTransform(s.getWorldTransform());
temp.add(g);
return temp;
}else
{
System.out.println(s);
System.out.println(s.getParent());
System.out.println("_________-");
}
}
return null;
}[/java]
If we can’t figure out what’s wrong with this, I’ll try the physics ghost controls.
I stared at your code snippets for a while, but seriously, I think you should post the whole code, even if it’s irrelevant, because as it sits, it doesn’t seem complete enough for me to give you an answer. Even if it’s 8 pages long, I think it’s better than just /some/ portions of code. Also: are you editing any meshes/geometries outside the code portions you posted? This would explain all the crashes.
@.Ben. said:
Oh it points to this line? : if(information.collideWith(sphere, temp) > 0)
Yyyyeah… so my first guess would be that the “area” variable that you pass to the function is used accross more than 1 thread at the same time and thus, it crashes. I had this happen in my own project too. What I ended up doing (dirty but does work 100% reliably) is to duplicate the mesh before colliding with it. It’s probably not the best way to go about I guess, but it works. Something like this, where c1 == area in your case I guess. It worked for me with the multithreading collision problem:
[java]
Geometry g = new Geometry();
g.setMesh(c1.getGeometry().getMesh());
g.setLocalTransform(c1.getGeometry().getWorldTransform());
CollisionResults results = new CollisionResults();
g.collideWith(ray, results);
[/java]
Just a word of warning, this is not threadsafe, getWorldTransform() might calculate it on the first call, if another thread also calls this, bamm.
Same goes for the mesh, that part is only save, if the mesh itself is not mutated.
Oh really? I had this assumption that since it’s a GET method and does not modify anything, it was fine. I know that collideWith uses the model bounds and this is not thread safe but didn’t know about the getWorldTransform(). It never crashed on a getWorldTransform() line on my 8-core CPU tough, maybe i’ve been extremely lucky in the past 4 months, weird.
If we step back a little, theorically, are you confirming that ANY getMesh(), getGeometry() or collideWith() functions should only be called from within the main (render) thread? How are people managing to calculate collisions on multiple threads then? I may be interested to know, just like the OP.
EDIT: I just had this crazy idea where you could subdivide the geometry checks in like chunks so that your threads do not interfere with each other. Maybe launch a grid of threads that only check within their associated bounds. Since none of them would check the same geometries, it would not crash, would it?
Well for simplicity reasons (read about the java memory model for more details)
All getters are unsafe by nature, as with everything not atomic, you might get a few updated and a few old bytes of a int for example.
This does usually not crash, but it is still a wrong result for a few ms.
This mgiht or might not be acceptable, but be aware of it!
Additionally in your case its extra unsafe due to this
The best way would be to copy all necessary data to own workers (replicate the enqueue logic for this in your worker) then let the worker enqueue the result.
You might get your results a few frames delayed then, withotu further sync.
You could let the renderer and your workers run in a fork join logic to work against this.
Alternative approach -> Only use immutable objects, constructors are guranteed to be sync, replace objects as necessary, make sure the replacing happens atomically, or mutally exclusive to other threads (basically how you would write an multithreaded ES)
ConcurrentHashmaps might bring you quite some way there without using a synchronize modifier
LOL we kind of had the same idea at the same time! O.O Game programming is not as SIMPLE as one might think. There are so many under the hood stuff to think about. Very tiny little forgotten details can make a game crash. EDIT: +1’ed you for the explanation why getWorldTransform() is thread unsafe, I never realized there was an update() call inside the getWorldTransform(). I think I will reprogram some parts of my game based on this discussion, it couldn’t hurt.
I had a good night’s rest and came back to my code, and discovered two problems; one of which is in a truly bizarre location, one of which is not.
Anyways, I tried your (ben’s) method, and copying the node over has worked. My collision detection is now working fairly well.
Thank you guys for your patience and help!
for people who might come across this looking to solve their own problem
the important thing is to copy the node before any multithreaded process. Here is a clumsy sample of code that can do this.
[java]
public ArrayList<Geometry> distill(Spatial s)
{
if(s instanceof Node)
{
List<Spatial> temp = ((Node) s).getChildren();
ArrayList<Geometry> solution = new ArrayList<Geometry>();
for(Spatial t : temp)
{
solution.addAll(distill(t));
}
return solution;
}
if(s instanceof Geometry)
{
if(((Geometry) s ).getMesh() != null)
{
ArrayList<Geometry> temp = new ArrayList<Geometry>();
Geometry g = new Geometry();
g.setMesh(((Geometry) s ).getMesh());
g.setLocalTransform(s.getWorldTransform());
temp.add(g);
return temp;
}else
{
System.out.println(s);
System.out.println(s.getParent());
System.out.println("_________-");
}
}
return null;
}
///////////aaand elsewhere, right before multithreading, do this:
//blank node
currentInteract = new Node();
//create a temporary list to hold copied geometries
ArrayList<Geometry> temp = distill(interactNode);
//transfer the contents of distill to the blank node
for(Geometry g : temp)
{
currentInteract.attachChild(g);
}
//now, pass the currentInteract node to your multithreaded process
Yes, that works because as stated by Empire Phoenix, the getters are not called from within a thread. We’re all basically confirming the same thing. I’m glad we managed to resolve the issue. Have fun with your project! Can you show us what you’re working on using a screenshot?