Elimination of Possible Next Move Location

Hi, this is a problem that is really getting me stuck.

Here's the thing, imagine a sphere inside of a tube.  When the sphere hits the inside surface of the tube, I want it to move in a new direction that would not cause another collision with the inside surface.  In other words, how do I make an object such as a sphere choose a different direction/ move in a different direction that will not make it to collide with the inside surface again.





This is what i'm using to make the sphere move and what direction it's moving in.



     

 anglea = (float) (Math.random()(2Math.PI));

       angleb = (float) (Math.random()(2Math.PI));



  

       

        chngx= (float)(Math.cos(angleb)*Math.cos(anglea));

       chngy= (float)(Math.sin(angleb));

       chngz= (float)(Math.sin(anglea)*Math.cos(angleb));





Thanks a lot

Hmm,…math is definetly not my strength and I'm in a hurry right now, but I think if you

hit the tube you will get one (or maybe more) Triangles you intersected. For that triangles you

have to calculate the normal. And that normal might be your new direction as the normal is pointing 90

This helps a bit, but I don't want the ball to necessarily travel in the normal direction.  It will be a random direction as shown in my first post, but with any direction that would cause a direct collision with the inside surface be eliminated.

If you know the normal of the triangle, doesn't that mean that you know which directions will be viable? (nearly 90 degrees in any direction from the normal). And then pick a random direction within those limits.

Alright, but then i would i go about finding the normal of the triangle?

Isn't there a method in triangle that gives you its normal?

You could cast a ray into the new random direction you want to move.

If the ray hits something within a certain distance, calculate a new random direction and cast a new ray until you find a possible direction.

Thanks for the replies guys.  But since I'm still fairly new to JME, I'm not sure how to use the rays.  LIke what code do I need to cast a ray in a random direction and see if the ray hits something.

i didnt see a reason why this thread should be locked (accidently maybe?),

unlocked it.

I made a little example to show what i meant.



In the Example you see a sphere which moves slowly forward. (SphereMover)

If something blocks its way which is nearer than 7 units, it rotates to the left.



I only cast a ray into the direction the sphere moves. (SphereRotater)

In your case, you could cast rays into several directions to find a free path.



import com.jme.app.SimpleGame;
import com.jme.bounding.BoundingBox;
import com.jme.intersection.BoundingPickResults;
import com.jme.intersection.PickResults;
import com.jme.math.FastMath;
import com.jme.math.Quaternion;
import com.jme.math.Ray;
import com.jme.math.Vector3f;
import com.jme.scene.Controller;
import com.jme.scene.Node;
import com.jme.scene.TriMesh;
import com.jme.scene.shape.Box;
import com.jme.scene.shape.Sphere;


public class TestRayPathfinding extends SimpleGame {
   Sphere obj = null;
   
   @Override
   protected void simpleInitGame() {
      obj = new Sphere("sp", 7, 7, 1);
      obj.setModelBound(new BoundingBox());
      obj.updateModelBound();
      rootNode.attachChild(obj);
      obj.addController(new SphereMover(obj));
      obj.addController(new SphereRotater(rootNode, obj));
      
      
      Box b1 = new Box("b1", new Vector3f(), 10, 10, 0.2f);
      b1.setModelBound(new BoundingBox());
      b1.updateModelBound();
      b1.setLocalTranslation(0, 0, 25);
      rootNode.attachChild(b1);

      Box b2 = new Box("b2", new Vector3f(), 0.2f, 10, 20);
      b2.setModelBound(new BoundingBox());
      b2.updateModelBound();
      b2.setLocalTranslation(13, 0, 20);
      rootNode.attachChild(b2);
      
      
      Box floor = new Box("floor", new Vector3f(), 100, 1, 100);
      floor.setModelBound(new BoundingBox());
      floor.updateModelBound();
      floor.setLocalTranslation(50, -10, 50);
      rootNode.attachChild(floor);
      
      cam.setLocation(new Vector3f(0, 50, -10));
      cam.lookAt(obj.getLocalTranslation().clone(), Vector3f.UNIT_Y);
      cam.update();
   }
   
   @Override
   protected void simpleUpdate() {
      super.simpleUpdate();
   }

   public static void main(String[] args) {
      TestRayPathfinding game = new TestRayPathfinding();
      game.setConfigShowMode(ConfigShowMode.AlwaysShow);
      game.start();
   }

}

class SphereMover extends Controller {
   private TriMesh obj;
   private float speed = 5;
   
   public SphereMover(TriMesh obj) {
      this.obj = obj;
   }
   @Override
   public void update(float time) {
      obj.getLocalTranslation().addLocal(
            obj.getLocalRotation().getRotationColumn(2).mult(time*speed));
   }
}


class SphereRotater extends Controller {
   private TriMesh obj;
   private Node scene;
   private float turnspeed = 150;
   
   public SphereRotater(Node scene, TriMesh obj) {
      this.obj = obj;
      this.scene = scene;
   }
   
   @Override
   public void update(float time) {
        Ray ray = new Ray(obj.getLocalTranslation().clone(), obj.getLocalRotation().getRotationColumn(2).clone());
        PickResults results = new BoundingPickResults();
        results.setCheckDistance(true);
        scene.findPick(ray, results);
        System.out.println("");
        for(int i = 0; i < results.getNumber(); i++) {
           if (results.getPickData(i).getTargetMesh() == obj) {
              // we need to ignore when the ray hits the sphere itself
              continue;
           }
           System.out.println("result: " +i +" " +results.getPickData(i).getTargetMesh().getName() +" ; " + " distance: " +results.getPickData(i).getDistance());
            if (results.getPickData(i).getDistance() < 7) {
               /* Danger !! */
               obj.getLocalRotation().multLocal(new Quaternion().fromAngleAxis(FastMath.DEG_TO_RAD*turnspeed*time, Vector3f.UNIT_Y));
            }
        }
   }
}

That Looks extremely promising. Thanks! I'll tinker with it and see if it is what i need.

Hmm… it doesn't seem to work since my sphere is inside the tube.  Hence, if (results.getPickData(i).getDistance() < 7)  is always true.

When picking, you need to be careful what you hit with the ray.

In my example, i ignored hits to my own sphere with:


           if (results.getPickData(i).getTargetMesh() == obj) {
              // we need to ignore when the ray hits the sphere itself
              continue;
           }



Ah right and if your sphere is inside another geometry, you need to use TrianglePickResults.
In my example i used BoundingPickResults for simplicity, since i just wanted simple checks.