Main Menu

the swept

Started by theFALCO, December 17, 2006, 09:19:00 PM

Previous topic - Next topic

EgonOlsen

All of these methods map to the same one in World, so they don't really differ. What exactly is your problem with the collision detection? What do you expect it to do that it doesn't?

theFALCO

The cube doesn't go up the ramp, it gets blocked by everything that's not flat or lower, and doesn't go along the wall when I collide with it under an angle... according to the manual the Ellipsoid collision should not only stop the movement but also try to avoid the obstacle by modifying the vector

or maybe I got it all wrong and there's nothing like thet in jpct?

EgonOlsen

What's the recursion depth you are using? What's the size of the ellipsoid? Also try to play around with Config.collideEllipsoidThreshold as i did in the modified version of your here posted code. I can only recommend to look at the fps example again. It doesn't matter if it uses the camera instead of an Object3D for this...the algorithm uses the exactly same method internally. There you can see that it is possible to slide up ramps/obstacles and along walls

theFALCO

depth - i tried 1, 4, 6, 25
size - generated dynamically with the getMesh().getBoundingBox
threshold - i tried 0.01 and it started working but only for the smallest ramp (it's almost unnoticably rised)

EgonOlsen

Ok, i found the time to write a little example today. It lets a cube (move it via the CRSR-keys) collide with several primitives and a plane. Here it is, hope this helps:

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import com.threed.jpct.*;
import com.threed.jpct.util.*;

public class CollisionDemo extends JFrame {

   private Graphics g = null;
   private KeyMapper keyMapper = null;
   private FrameBuffer fb = null;
   private World world = null;
   private Object3D plane = null;
   private Object3D ramp = null;
   private Object3D cube = null;
   private Object3D cube2 = null;
   private Object3D sphere = null;

   private boolean up = false;
   private boolean down = false;
   private boolean left = false;
   private boolean right = false;

   private SimpleVector ellipsoid = new SimpleVector(2, 2, 2);

   public CollisionDemo() {
       setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       pack();
       setSize(800, 600);
       setResizable(false);
       setLocationRelativeTo(null);
       setVisible(true);
       g = getGraphics();
   }

   private void initStuff() {
       keyMapper = new KeyMapper(this);
       fb = new FrameBuffer(800, 600, FrameBuffer.SAMPLINGMODE_NORMAL);
       world = new World();
       fb.enableRenderer(IRenderer.RENDERER_SOFTWARE, IRenderer.MODE_OPENGL);

       plane = Primitives.getPlane(20, 10);
       ramp = Primitives.getCube(20);
       ramp.setAdditionalColor(Color.BLUE);
       plane.setAdditionalColor(Color.GREEN);
       sphere=Primitives.getSphere(30);
       sphere.setAdditionalColor(Color.CYAN);
       sphere.translate(-50,10,50);
       cube2=Primitives.getCube(20);
       cube2.setAdditionalColor(Color.ORANGE);
       cube2.translate(60,-20,60);

       plane.rotateX((float) Math.PI / 2f);
       ramp.rotateX((float) Math.PI / 2f);

       cube = Primitives.getCube(2);
       
       plane.setCollisionMode(Object3D.COLLISION_CHECK_OTHERS);
       ramp.setCollisionMode(Object3D.COLLISION_CHECK_OTHERS);
       sphere.setCollisionMode(Object3D.COLLISION_CHECK_OTHERS);
       cube2.setCollisionMode(Object3D.COLLISION_CHECK_OTHERS);
       cube.setCollisionMode(Object3D.COLLISION_CHECK_SELF);

       world.addObject(plane);
       world.addObject(ramp);
       world.addObject(cube);
       world.addObject(sphere);
       world.addObject(cube2);

       cube.translate( -50, -10, -50);

       Light light = new Light(world);
       light.setPosition(new SimpleVector(0, -80, 0));
       light.setIntensity(40, 25, 22);

       world.buildAllObjects();
   }

   private void move() {
       KeyState ks = null;
       while ((ks = keyMapper.poll()) != KeyState.NONE) {
           if (ks.getKeyCode() == KeyEvent.VK_UP) {
               up = ks.getState();
           }
           if (ks.getKeyCode() == KeyEvent.VK_DOWN) {
               down = ks.getState();
           }
           if (ks.getKeyCode() == KeyEvent.VK_LEFT) {
               left = ks.getState();
           }
           if (ks.getKeyCode() == KeyEvent.VK_RIGHT) {
               right = ks.getState();
           }
       }

       // move the cube
       if (up) {
           SimpleVector t = new SimpleVector(0, 0, 1);
           t = cube.checkForCollisionEllipsoid(t, ellipsoid, 5);
           cube.translate(t);
       }

       if (down) {
           SimpleVector t = new SimpleVector(0, 0, -1);
           t = cube.checkForCollisionEllipsoid(t, ellipsoid, 5);
           cube.translate(t);
       }

       if (left) {
           SimpleVector t = new SimpleVector( -1, 0, 0);
           t = cube.checkForCollisionEllipsoid(t, ellipsoid, 5);
           cube.translate(t);
       }

       if (right) {
           SimpleVector t = new SimpleVector(1, 0, 0);
           t = cube.checkForCollisionEllipsoid(t, ellipsoid, 5);
           cube.translate(t);
       }
       
       // finally apply the gravity:
       SimpleVector t=new SimpleVector(0,1,0);
       t=cube.checkForCollisionEllipsoid(t,ellipsoid,1);
       cube.translate(t);
   }

   private void doIt() throws Exception {
       Camera cam = world.getCamera();
       cam.moveCamera(Camera.CAMERA_MOVEOUT, 100);
       cam.moveCamera(Camera.CAMERA_MOVEUP, 100);
       cam.lookAt(ramp.getTransformedCenter());

       while (true) {
           move();
           fb.clear(Color.RED);
           world.renderScene(fb);
           world.draw(fb);
           fb.update();
           fb.display(g);
           //Thread.sleep(20);
       }
   }

   public static void main(String[] args) throws Exception {
       CollisionDemo cd = new CollisionDemo();
       cd.initStuff();
       cd.doIt();
   }
}

Melssj5

Well, The ellipsoid on the fps works with the gravity, when it detects an inferior limit it moves the camera up. but this doesnt really correct the angle of the objetcs.
Nada por ahora

theFALCO

YAY! (or not...)
I found it! I took this example, copy-pasted it, compiled... it works, so OK. Let's start adding things one by one so that it get's like my code until it stops working...
it stopped working after I set the speed (i mean the value which multiplies the vector which is checked and then added to the resultant) to 0.2

here is the code, the SPEED is set to 1 and it works, but if you change it to 0.2 (should be bigger than moveDamp) it stops working (oh, and BTW, I changed the renderer to OpenGL and made a camera on the back of the cube)

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import com.threed.jpct.*;
import com.threed.jpct.util.*;

public class CollisionDemo {

   private static float moveDamp = 0.1f;
   private static float SPEED = 1f;
   private static float MAXSPEED = 1f;

   private Graphics g = null;
   private KeyMapper keyMapper = null;
   private FrameBuffer fb = null;
   private World world = null;
   private Object3D plane = null;
   private Object3D ramp = null;
   private Object3D cube = null;
   private Object3D cube2 = null;
   private Object3D sphere = null;

   private SimpleVector moveRes = new SimpleVector(0, 0, 0);

   private boolean up = false;
   private boolean down = false;
   private boolean left = false;
   private boolean right = false;

   private boolean doloop = true;

   private SimpleVector ellipsoid = new SimpleVector(2, 2, 2);

   public CollisionDemo() {
       Config.glFullscreen=false;
   }

   private void initStuff() {
       //keyMapper = new KeyMapper(this);
       fb = new FrameBuffer(1024, 768, FrameBuffer.SAMPLINGMODE_NORMAL);
       world = new World();
       fb.enableRenderer(IRenderer.RENDERER_SOFTWARE);
       fb.enableRenderer(IRenderer.RENDERER_OPENGL, IRenderer.MODE_OPENGL);
       fb.disableRenderer(IRenderer.RENDERER_SOFTWARE);
       keyMapper = new KeyMapper();

       plane = Primitives.getPlane(20, 10);
       ramp = Primitives.getCube(20);
       ramp.setAdditionalColor(Color.BLUE);
       plane.setAdditionalColor(Color.GREEN);
       sphere=Primitives.getSphere(30);
       sphere.setAdditionalColor(Color.CYAN);
       sphere.translate(-50,10,50);
       cube2=Primitives.getCube(20);
       cube2.setAdditionalColor(Color.ORANGE);
       cube2.translate(60,-20,60);

       plane.rotateX((float) Math.PI / 2f);
       ramp.rotateX((float) Math.PI / 2f);

       cube = Primitives.getCube(2);

       plane.setCollisionMode(Object3D.COLLISION_CHECK_OTHERS);
       ramp.setCollisionMode(Object3D.COLLISION_CHECK_OTHERS);
       sphere.setCollisionMode(Object3D.COLLISION_CHECK_OTHERS);
       cube2.setCollisionMode(Object3D.COLLISION_CHECK_OTHERS);
       cube.setCollisionMode(Object3D.COLLISION_CHECK_SELF);

       world.addObject(plane);
       world.addObject(ramp);
       world.addObject(cube);
       world.addObject(sphere);
       world.addObject(cube2);

       cube.translate( -50, -10, -50);

       Light light = new Light(world);
       light.setPosition(new SimpleVector(0, -80, 0));
       light.setIntensity(40, 25, 22);

       world.buildAllObjects();
   }

   private void move() {
       KeyState ks = null;
       while ((ks = keyMapper.poll()) != KeyState.NONE) {
           if (ks.getKeyCode() == KeyEvent.VK_UP) {
               up = ks.getState();
           }
           if (ks.getKeyCode() == KeyEvent.VK_DOWN) {
               down = ks.getState();
           }
           if (ks.getKeyCode() == KeyEvent.VK_LEFT) {
               left = ks.getState();
           }
           if (ks.getKeyCode() == KeyEvent.VK_RIGHT) {
               right = ks.getState();
           }
           if(ks.getKeyCode() == KeyEvent.VK_ESCAPE) {
               doloop = false;
           }
       }

       // move the cube
       if (up) {
           SimpleVector t = cube.getZAxis();
           t.scalarMul(SPEED);
           //t = cube.checkForCollisionEllipsoid(t, ellipsoid, 5);
           //cube.translate(t);
           moveRes.add(t);
       }

       if (down) {
           SimpleVector t = cube.getZAxis();
           t.scalarMul(-SPEED);
           //t = cube.checkForCollisionEllipsoid(t, ellipsoid, 5);
           //cube.translate(t);
           moveRes.add(t);
       }

       if (left) {
           cube.rotateY((float)Math.toRadians(-1));
       }

       if (right) {
           cube.rotateY((float)Math.toRadians(1));
       }

       // finally apply the gravity:
       SimpleVector t=new SimpleVector(0,1,0);
       t=cube.checkForCollisionEllipsoid(t,ellipsoid,1);
       cube.translate(t);

       //avoid too high speed
       if(moveRes.length()>MAXSPEED) {
           moveRes.makeEqualLength(new SimpleVector(0,0,MAXSPEED));
       }

       moveRes = cube.checkForCollisionEllipsoid(moveRes, ellipsoid, 5);
       cube.translate(moveRes);

       //damping
       if(moveRes.length()>moveDamp) {
           moveRes.makeEqualLength(new SimpleVector(0,0,moveDamp));
       } else {
           moveRes = new SimpleVector(0,0,0);
       }
   }

   private void doIt() throws Exception {
       Camera cam = world.getCamera();
       cam.moveCamera(Camera.CAMERA_MOVEOUT, 100);
       cam.moveCamera(Camera.CAMERA_MOVEUP, 100);
       cam.lookAt(ramp.getTransformedCenter());

       while(doloop) {
           move();
           cam.setPositionToCenter(cube);
           cam.align(cube);
           cam.rotateCameraX((float)Math.toRadians(30));
           cam.moveCamera(Camera.CAMERA_MOVEOUT, 50);
           fb.clear(Color.RED);
           world.renderScene(fb);
           world.draw(fb);
           fb.update();
           fb.displayGLOnly();
       }
       fb.disableRenderer(IRenderer.RENDERER_OPENGL);
       System.exit(0);
   }

   public static void main(String[] args) throws Exception {
       CollisionDemo cd = new CollisionDemo();
       cd.initStuff();
       cd.doIt();
   }
}

EgonOlsen

Yes, 0.1 as the threshold is for sure below 0.2, but the possible movement vector may not. So it's a good idea to adjust that value to, let's say, 0.0001f when applying a rather small translation.
This improves the situation but it doesn't solve all problems. Climping up the sphere is still a problem....i'm not sure what causes this, but i assume that it's an accuracy problem, so that the box is detected as stuck in the sphere where it actually isn't. I worked around this in the example by moving the gravity effect after the actual translation (something that i recommend to do anyway) and adding a small y-offset before doing the actual check for collision, i.e. something like this:



cube.translate(0,-0.02f,0);

moveRes = cube.checkForCollisionEllipsoid(moveRes, ellipsoid, 8);
cube.translate(moveRes);

// finally apply the gravity:
SimpleVector t=new SimpleVector(0,1,0);
t=cube.checkForCollisionEllipsoid(t,ellipsoid,1);
cube.translate(t);


This still isn't 100% perfect. But to be honest, this kind of algorithm will never work 100%...it doesn't do this in any game that i know. Yeah, sounds like a lame excuse, but the stuff is definitely not bugged...just inaccurate in some situations. I'm saying this, because i checked every single instruction in the methods a dozen times ones, because there was a crazy "shaking bug" in it that i've found after doing so. The rest works as it is supposed to be. It's just not 100% in every situation. It can't be.

theFALCO

everything works great
i think that rescaling everything by 10 or 100 will do the job, cause I won't have to use so small values (I use such a small speed because even 1 is slightly too fast)

thanks for your effort