Collision Detection Bug in Java 3D 1.5.2

classic Classic list List threaded Threaded
11 messages Options
Reply | Threaded
Open this post in threaded view
|

Collision Detection Bug in Java 3D 1.5.2

Christian
Hello,

I am dealing with collision detection in Java 3d (Version 1.5.2). I have two shapes with the associated collision bounding box. If these both bounding box intersects and a third shape intersects both bounding boxes with a new WakeupOnCollisionxxxxx(thirdShape) the collision of the first intersected bounding box will detected. For the second bounding box no detection occurs.

I am not sure but there should be a detection for the second box as well.

Thank you!
Christian
Reply | Threaded
Open this post in threaded view
|

Re: Collision Detection Bug in Java 3D 1.5.2

gouessej
Administrator
Hi

Please switch to Java3D 1.6.0 and provide a SSCCE if your problem is still reproducible. I remind you that this forum subsection is exclusively about Java3D 1.6.0 as Java3D 1.5 is no longer maintained.

You can read this post for more information.
Julien Gouesse | Personal blog | Website
Reply | Threaded
Open this post in threaded view
|

Re: Collision Detection Bug in Java 3D 1.5.2

Christian
Dear gouessej,

Thank you for your answer. I tried it with Java3d 1.6.0 pre12 and the error still appears.

I wrote a example program, where the problem is reproducible.

package com.example.coll;

import java.util.Enumeration;

import javax.media.j3d.Behavior;
import javax.media.j3d.BoundingSphere;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.DirectionalLight;

import javax.media.j3d.Node;

import javax.media.j3d.Transform3D;
import javax.media.j3d.TransformGroup;
import javax.media.j3d.WakeupCriterion;
import javax.media.j3d.WakeupOnCollisionEntry;
import javax.media.j3d.WakeupOnCollisionExit;
import javax.media.j3d.WakeupOnCollisionMovement;
import javax.media.j3d.WakeupOr;
import javax.vecmath.Color3f;
import javax.vecmath.Point3d;

import javax.vecmath.Vector3d;
import javax.vecmath.Vector3f;


import com.sun.j3d.utils.geometry.Sphere;
import com.sun.j3d.utils.universe.SimpleUniverse;

public class CollisionBugExample {

        public CollisionBugExample() {
                SimpleUniverse universe = new SimpleUniverse();
                BranchGroup group = new BranchGroup();

                FixedSphere shape1 = new FixedSphere(0.3f);
                group.addChild(shape1.getSphereTGrp());
                shape1.setPosition(new Vector3d(+0.2, 0.0, 0.0));
           
                FixedSphere shape2 = new FixedSphere(0.3f);
                group.addChild(shape2.getSphereTGrp());
                shape2.setPosition(new Vector3d(-0.2, 0.0, 0.0));
           
                MovingSphere shape3 = new MovingSphere(0.1f);
                group.addChild(shape3.getSphereTGrp());
                group.addChild(shape3);

                Color3f light1Color = new Color3f(1.8f, 0.1f, 0.1f);
                BoundingSphere bounds = new BoundingSphere(new Point3d(0.0,0.0,0.0), 100.0);
                Vector3f light1Direction = new Vector3f(4.0f, -7.0f, -12.0f);
                DirectionalLight light1 = new DirectionalLight(light1Color, light1Direction);
                light1.setInfluencingBounds(bounds);
                group.addChild(light1);

                universe.getViewingPlatform().setNominalViewingTransform();
                universe.addBranchGraph(group);
           
                // move the moving sphere
           
                for(double i = 1.0; i > -1.0; i -= 0.01) {
                        shape3.setPosition(new Vector3d(i, 0.0, 0.0));
                        try {
                                Thread.sleep(100);
                        } catch (InterruptedException e) {
                                e.printStackTrace();
                        }
                }
        }

        public static void main(String[] args) {
                new CollisionBugExample();
        }
}

class FixedSphere {
       
        private Sphere sphere;
       
        private TransformGroup transGrp;
       
        public FixedSphere(float size) {
                transGrp = new TransformGroup();
                sphere = new Sphere(size);
                transGrp.addChild(sphere);
        }

        public TransformGroup getSphereTGrp() {
                return transGrp;
        }
       
        public void setPosition(Vector3d position) {
                Transform3D transform = new Transform3D();
                transform.setTranslation(position);
                transGrp.setTransform(transform);
        }
}

class MovingSphere extends Behavior {
       
        private Sphere sphere;
       
        private TransformGroup transGrp;
       
        private WakeupCriterion[] collisionCriteria;
        private WakeupOr oredCriteria;
       
        public MovingSphere(float size) {
                transGrp = new TransformGroup();
                transGrp.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
                sphere = new Sphere(size);
                transGrp.addChild(sphere);
               
                setSchedulingBounds(new BoundingSphere(new Point3d(0.0,0.0,0.0), 100.0));
        }

        public TransformGroup getSphereTGrp() {
                return transGrp;
        }
       
        public void setPosition(Vector3d position) {
                Transform3D transform = new Transform3D();
                transform.setTranslation(position);
                transGrp.setTransform(transform);
        }

        @Override
        public void initialize() {
                collisionCriteria = new WakeupCriterion[3];
                collisionCriteria[0] = new WakeupOnCollisionEntry(sphere);
                collisionCriteria[1] = new WakeupOnCollisionExit(sphere);
                collisionCriteria[2] = new WakeupOnCollisionMovement(sphere);
                oredCriteria = new WakeupOr(collisionCriteria);
                wakeupOn(oredCriteria);
        }

        @Override
        public void processStimulus(Enumeration criteria) {
                WakeupCriterion theCriterion = (WakeupCriterion) criteria.nextElement();
                Node collisionShape;

                if(theCriterion instanceof WakeupOnCollisionEntry) {
                        collisionShape = ((WakeupOnCollisionEntry) theCriterion).getTriggeringPath().getObject();
                } else if(theCriterion instanceof WakeupOnCollisionExit) {
                        collisionShape = ((WakeupOnCollisionExit) theCriterion).getTriggeringPath().getObject();
                } else {
                        collisionShape = ((WakeupOnCollisionMovement) theCriterion).getTriggeringPath().getObject();
                }
               
                System.out.println(theCriterion + " : collide with " + collisionShape);
               
                wakeupOn(oredCriteria);
        }
}

With this example you can see, that the collision bounds of the fixed spheres intersect and that a collision between the moved sphere and shape1 occurs, but no detection with the collision bounds of shape2 occurs. But it should with sphere2 as well.

If you change the position of fixed spheres to...
                FixedSphere shape1 = new FixedSphere(0.3f);
                group.addChild(shape1.getSphereTGrp());
                shape1.setPosition(new Vector3d(+0.5, 0.0, 0.0));
           
                FixedSphere shape2 = new FixedSphere(0.3f);
                group.addChild(shape2.getSphereTGrp());
                shape2.setPosition(new Vector3d(-0.5, 0.0, 0.0));
           
... the collision bounds don't intersect and everything is fine.

Christian
Reply | Threaded
Open this post in threaded view
|

Re: Collision Detection Bug in Java 3D 1.5.2

gouessej
Administrator
Why do you need to use those both lines? Isn't the first one enough?

group.addChild(shape3.getSphereTGrp());
group.addChild(shape3);
Julien Gouesse | Personal blog | Website
Reply | Threaded
Open this post in threaded view
|

Re: Collision Detection Bug in Java 3D 1.5.2

Christian
No one is not enough.

I need to add the TransformGroup with the shape to the BranchGroup and I need to attach the class itself, because the class extends Behavior for the collision detection.
Reply | Threaded
Open this post in threaded view
|

Re: Collision Detection Bug in Java 3D 1.5.2

gouessej
Administrator
Please look at the examples on java3d.org, there must be a clean way to do it without adding both a node and its parent into the branch group.
Julien Gouesse | Personal blog | Website
Reply | Threaded
Open this post in threaded view
|

Re: Collision Detection Bug in Java 3D 1.5.2

Christian
Fact is that I have to add the TransformGroup to the Scenegraph as well as the Behavior. Which other way should exist?
Reply | Threaded
Open this post in threaded view
|

Re: Collision Detection Bug in Java 3D 1.5.2

gouessej
Administrator
We have to investigate to find another way. Java3D is a bit too much permissive but only bad things can happen when you add a node and its children to the same node in a scene tree in any scenegraph API.

I advise you to look at the Java3D game "Arabian Flights" available on Sourceforge, it handles the collisions correctly.
Julien Gouesse | Personal blog | Website
Reply | Threaded
Open this post in threaded view
|

Re: Collision Detection Bug in Java 3D 1.5.2

Christian
I had a look to the source code of "Arabian Flights". The developer don't use the Behavior class for collision detection. If I see it right he made his own detection in class PhysicsEngine method collisionCheck(Particle part1, Particle part2). I think out intention should be to solve that the Java3D Behavior for collision detection is working properly.

I do not believe that the problem has to do with adding a node and a children of the node to the SceneGraph, because I didn't. The TransformGroup consisting the Sphere I added to the SceneGraph is not a children of the Behaviour class in the SceneGraph. It is just a attribute in the class.

If you concern about this I improved the code a bit to make it more clear:

package com.example.coll;

import java.util.Enumeration;

import javax.media.j3d.Behavior;
import javax.media.j3d.BoundingSphere;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.DirectionalLight;

import javax.media.j3d.Node;
import javax.media.j3d.Shape3D;
import javax.media.j3d.Transform3D;
import javax.media.j3d.TransformGroup;
import javax.media.j3d.WakeupCriterion;
import javax.media.j3d.WakeupOnCollisionEntry;
import javax.media.j3d.WakeupOnCollisionExit;
import javax.media.j3d.WakeupOnCollisionMovement;
import javax.media.j3d.WakeupOr;
import javax.vecmath.Color3f;
import javax.vecmath.Point3d;

import javax.vecmath.Vector3d;
import javax.vecmath.Vector3f;


import com.sun.j3d.utils.geometry.Sphere;
import com.sun.j3d.utils.universe.SimpleUniverse;

public class CollisionBugExample {

        public CollisionBugExample() {
                SimpleUniverse universe = new SimpleUniverse();
                BranchGroup group = new BranchGroup();

                Particle shape1 = new Particle(0.3f);
                group.addChild(shape1.getSphereTGrp());
                shape1.setPosition(new Vector3d(+0.2, 0.0, 0.0));
           
                Particle shape2 = new Particle(0.3f);
                group.addChild(shape2.getSphereTGrp());
                shape2.setPosition(new Vector3d(-0.2, 0.0, 0.0));
           
                Particle shape3 = new Particle(0.1f);
                group.addChild(shape3.getSphereTGrp());
               
                CollisionDetection collDet = new CollisionDetection(shape3.getShape());
                group.addChild(collDet);
               
                Color3f light1Color = new Color3f(1.8f, 0.1f, 0.1f);
                BoundingSphere bounds = new BoundingSphere(new Point3d(0.0,0.0,0.0), 100.0);
                Vector3f light1Direction = new Vector3f(4.0f, -7.0f, -12.0f);
                DirectionalLight light1 = new DirectionalLight(light1Color, light1Direction);
                light1.setInfluencingBounds(bounds);
                group.addChild(light1);

                universe.getViewingPlatform().setNominalViewingTransform();
                universe.addBranchGraph(group);
           
                // move the moving sphere
           
                for(double i = 1.0; i > -1.0; i -= 0.01) {
                        shape3.setPosition(new Vector3d(i, 0.0, 0.0));
                        try {
                                Thread.sleep(100);
                        } catch (InterruptedException e) {
                                e.printStackTrace();
                        }
                }
        }

        public static void main(String[] args) {
                new CollisionBugExample();
        }
}

class Particle {
       
        private Sphere sphere;
       
        private TransformGroup transGrp;
       
        public Particle(float size) {
                transGrp = new TransformGroup();
                transGrp.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
                sphere = new Sphere(size);
                transGrp.addChild(sphere);
        }

        public TransformGroup getSphereTGrp() {
                return transGrp;
        }
       
        public Shape3D getShape() {
                return sphere.getShape();
        }
       
        public void setPosition(Vector3d position) {
                Transform3D transform = new Transform3D();
                transform.setTranslation(position);
                transGrp.setTransform(transform);
        }
}

class CollisionDetection extends Behavior {
       
        private Shape3D shape;

        private WakeupCriterion[] collisionCriteria;
        private WakeupOr oredCriteria;
       
        public CollisionDetection(Shape3D shape) {
                this.shape = shape;
                setSchedulingBounds(new BoundingSphere(new Point3d(0.0,0.0,0.0), 100.0));
        }
       
        @Override
        public void initialize() {
                collisionCriteria = new WakeupCriterion[3];
                collisionCriteria[0] = new WakeupOnCollisionEntry(shape);
                collisionCriteria[1] = new WakeupOnCollisionExit(shape);
                collisionCriteria[2] = new WakeupOnCollisionMovement(shape);
                oredCriteria = new WakeupOr(collisionCriteria);
                wakeupOn(oredCriteria);
        }

        @Override
        public void processStimulus(Enumeration criteria) {
                WakeupCriterion theCriterion = (WakeupCriterion) criteria.nextElement();
                Node collisionShape;

                if(theCriterion instanceof WakeupOnCollisionEntry) {
                        collisionShape = ((WakeupOnCollisionEntry) theCriterion).getTriggeringPath().getObject();
                } else if(theCriterion instanceof WakeupOnCollisionExit) {
                        collisionShape = ((WakeupOnCollisionExit) theCriterion).getTriggeringPath().getObject();
                } else {
                        collisionShape = ((WakeupOnCollisionMovement) theCriterion).getTriggeringPath().getObject();
                }
               
                System.out.println(theCriterion + " : collide with " + collisionShape);
               
                wakeupOn(oredCriteria);
        }
}

With this implementation the problem still exists.

Christian
Reply | Threaded
Open this post in threaded view
|

Re: Collision Detection Bug in Java 3D 1.5.2

gouessej
Administrator
Actually, depending on the time step, you can miss some collisions when using "a posteriori" discrete collision detection, it's not a bug, it's a known limitation.

I advise you to look at the source code of the wake up collision system and to display the data of the moving volume each time you move it. Compare it with the fixed bounding volumes. Make the collision test by yourself to ensure that there are really 2 collisions at the same time even though Java3D indicates only one.
Julien Gouesse | Personal blog | Website
Reply | Threaded
Open this post in threaded view
|

Re: Collision Detection Bug in Java 3D 1.5.2

hharrison
I think this actuallymight be documented behavior of Java3d, in that some of the collision behaviors only get signaled once, not for each collision, you have to check yourself for multiple collisions as it sometimes only reports the firstone it finds, can't supply a good reference for it at the moment (it's been too long)