SweepTest

Hey,

I am trying to create my own CharacterControl using sweeptests, but the sweeptest will sometimes not report a collision.



testcase:

[java]package mygame;



import com.jme3.app.SimpleApplication;

import com.jme3.bullet.BulletAppState;

import com.jme3.bullet.collision.PhysicsSweepTestResult;

import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;

import com.jme3.bullet.control.GhostControl;

import com.jme3.bullet.control.RigidBodyControl;

import com.jme3.input.KeyInput;

import com.jme3.input.controls.AnalogListener;

import com.jme3.input.controls.KeyTrigger;

import com.jme3.material.Material;

import com.jme3.math.ColorRGBA;

import com.jme3.math.Transform;

import com.jme3.math.Vector3f;

import com.jme3.renderer.RenderManager;

import com.jme3.scene.Geometry;

import com.jme3.scene.Node;

import com.jme3.scene.shape.Box;

import com.jme3.scene.shape.Sphere;

import com.jme3.system.AppSettings;

import java.util.List;



public class Main extends SimpleApplication {



private BulletAppState bulletAppState;



public static void main(String[] args) {

Main app = new Main();

AppSettings settings = new AppSettings(true);

settings.setFrameRate(100);

app.start();

}



private CapsuleCollisionShape playerShape;

private Node playerNode;



@Override

public void simpleInitApp() {

bulletAppState = new BulletAppState();

stateManager.attach(bulletAppState);

bulletAppState.getPhysicsSpace().enableDebug(assetManager);



Node geoNode = new Node("geometries");

rootNode.attachChild(geoNode);



Box b = new Box(new Vector3f(-5f, 0, 0), 1, 1, 1);

Geometry geom = new Geometry("Box1", b);

Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");

mat.setColor("Color", ColorRGBA.Blue);

geom.setMaterial(mat);

geoNode.attachChild(geom);



Box b2 = new Box(Vector3f.ZERO.add(6f, 0, 0), 1, 3, 1);

Geometry geom2 = new Geometry("Box2", b2);

Material mat2 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");

mat2.setColor("Color", ColorRGBA.Red);

geom2.setMaterial(mat2);

geoNode.attachChild(geom2);



Box floor = new Box(new Vector3f(0, -3f, 0), 16f, 0.5f, 16f);

Geometry floorGeo = new Geometry("Floor", floor);

Material floorMat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");

floorMat.setColor("Color", ColorRGBA.Green);

floorGeo.setMaterial(floorMat);

geoNode.attachChild(floorGeo);



Sphere s = new Sphere(5, 5, 1);

Geometry sGeo = new Geometry("Sphere", s);

sGeo.setLocalTranslation(1f, 0f, 3f);

Material sMat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");

sMat.setColor("Color", ColorRGBA.Orange);

sGeo.setMaterial(sMat);

geoNode.attachChild(sGeo);



RigidBodyControl coll = new RigidBodyControl(0.0f);

geoNode.addControl(coll);

bulletAppState.getPhysicsSpace().add(coll);





playerNode = new Node("Player");

playerShape = new CapsuleCollisionShape(1.2f, 3f);

GhostControl playerGhost = new GhostControl(playerShape);

playerNode.addControl(playerGhost);

rootNode.attachChild(playerNode);



flyCam.setMoveSpeed(0.0f);



inputManager.addMapping("forward", new KeyTrigger(KeyInput.KEY_W));

inputManager.addMapping("back", new KeyTrigger(KeyInput.KEY_S));

inputManager.addMapping("left", new KeyTrigger(KeyInput.KEY_A));

inputManager.addMapping("right", new KeyTrigger(KeyInput.KEY_D));

inputManager.addListener(anlistener, "forward", "back", "left", "right");

}



private AnalogListener anlistener = new AnalogListener() {



public void onAnalog(String name, float value, float tpf) {

Vector3f direction = cam.getDirection().normalize().mult(5*tpf);

Vector3f left = cam.getLeft().normalize().mult(0.1f);

if (name.equals("forward")) {

move(direction);

} else if (name.equals("back")) {

move(direction.negate());

} else if (name.equals("left")) {

move(left);

} else if (name.equals("right")) {

move(left.negate());

}

}

};



private void move(Vector3f moveDir) {

Transform startPos = new Transform(playerNode.getLocalTranslation());

Transform endPos = new Transform(playerNode.getLocalTranslation().add(moveDir));

List<PhysicsSweepTestResult> sweep = bulletAppState.getPhysicsSpace().sweepTest(playerShape, startPos, endPos);

if (sweep.isEmpty()) {

playerNode.move(moveDir);

}



}



@Override

public void simpleUpdate(float tpf) {

cam.setLocation(playerNode.getWorldTranslation());

}



@Override

public void simpleRender(RenderManager rm) {

//TODO: add render code

}

}

[/java]



In this testcase, you can fly around and will be blocked, if the sweeptest returns a result that is not empty. It works fine for the smaller objects - but the sweeptest will miss the floor under certain angles and you can move through it.

I tested it with different collisionshapes and sizes for the sweeptest but this behaviour stays the same, as long as the collisionshape is small enough to fit through a single triangle of the collisionmesh.



Can anyone help me out?



Thanks, alfred

The sweep is probably too short.

I edited the testcase so that the sweeptest has to be at least 0.5 long:



[java]package mygame;



import com.jme3.app.SimpleApplication;

import com.jme3.bullet.BulletAppState;

import com.jme3.bullet.collision.PhysicsSweepTestResult;

import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;

import com.jme3.bullet.control.GhostControl;

import com.jme3.bullet.control.RigidBodyControl;

import com.jme3.input.KeyInput;

import com.jme3.input.controls.AnalogListener;

import com.jme3.input.controls.KeyTrigger;

import com.jme3.material.Material;

import com.jme3.math.ColorRGBA;

import com.jme3.math.Transform;

import com.jme3.math.Vector3f;

import com.jme3.renderer.RenderManager;

import com.jme3.scene.Geometry;

import com.jme3.scene.Node;

import com.jme3.scene.shape.Box;

import com.jme3.scene.shape.Sphere;

import com.jme3.system.AppSettings;

import java.util.List;



public class Main extends SimpleApplication {



private BulletAppState bulletAppState;



public static void main(String[] args) {

Main app = new Main();

AppSettings settings = new AppSettings(true);

settings.setFrameRate(80);

app.start();

}



private CapsuleCollisionShape playerShape;

private Node playerNode;



@Override

public void simpleInitApp() {

bulletAppState = new BulletAppState();

stateManager.attach(bulletAppState);

bulletAppState.getPhysicsSpace().enableDebug(assetManager);



Node geoNode = new Node(“geometries”);

rootNode.attachChild(geoNode);



Box b = new Box(new Vector3f(-5f, 0, 0), 1, 1, 1);

Geometry geom = new Geometry(“Box1”, b);

Material mat = new Material(assetManager, “Common/MatDefs/Misc/Unshaded.j3md”);

mat.setColor(“Color”, ColorRGBA.Blue);

geom.setMaterial(mat);

geoNode.attachChild(geom);



Box b2 = new Box(Vector3f.ZERO.add(6f, 0, 0), 1, 3, 1);

Geometry geom2 = new Geometry(“Box2”, b2);

Material mat2 = new Material(assetManager, “Common/MatDefs/Misc/Unshaded.j3md”);

mat2.setColor(“Color”, ColorRGBA.Red);

geom2.setMaterial(mat2);

geoNode.attachChild(geom2);



Box floor = new Box(new Vector3f(0, -3f, 0), 64f, 0.5f, 64f);

Geometry floorGeo = new Geometry(“Floor”, floor);

Material floorMat = new Material(assetManager, “Common/MatDefs/Misc/Unshaded.j3md”);

floorMat.setColor(“Color”, ColorRGBA.Green);

floorGeo.setMaterial(floorMat);

geoNode.attachChild(floorGeo);



Sphere s = new Sphere(5, 5, 1);

Geometry sGeo = new Geometry(“Sphere”, s);

sGeo.setLocalTranslation(1f, 0f, 3f);

Material sMat = new Material(assetManager, “Common/MatDefs/Misc/Unshaded.j3md”);

sMat.setColor(“Color”, ColorRGBA.Orange);

sGeo.setMaterial(sMat);

geoNode.attachChild(sGeo);



RigidBodyControl coll = new RigidBodyControl(0.0f);

geoNode.addControl(coll);

bulletAppState.getPhysicsSpace().add(coll);





playerNode = new Node(“Player”);

playerShape = new CapsuleCollisionShape(1.2f, 3f);

GhostControl playerGhost = new GhostControl(playerShape);

playerNode.addControl(playerGhost);

rootNode.attachChild(playerNode);



flyCam.setMoveSpeed(0.0f);



inputManager.addMapping(“forward”, new KeyTrigger(KeyInput.KEY_W));

inputManager.addMapping(“back”, new KeyTrigger(KeyInput.KEY_S));

inputManager.addMapping(“left”, new KeyTrigger(KeyInput.KEY_A));

inputManager.addMapping(“right”, new KeyTrigger(KeyInput.KEY_D));

inputManager.addListener(anlistener, “forward”, “back”, “left”, “right”);

}



private AnalogListener anlistener = new AnalogListener() {



public void onAnalog(String name, float value, float tpf) {

Vector3f direction = cam.getDirection().normalize().mult(50*tpf);

Vector3f left = cam.getLeft().normalize().mult(0.1f);

if (name.equals(“forward”)) {

move(direction);

} else if (name.equals(“back”)) {

move(direction.negate());

} else if (name.equals(“left”)) {

move(left);

} else if (name.equals(“right”)) {

move(left.negate());

}

}

};



private void move(Vector3f moveDir) {

Transform startPos = new Transform(playerNode.getLocalTranslation());

Transform endPos = new Transform(playerNode.getLocalTranslation().add(moveDir));

if (moveDir.length() < 0.5f) {

return;

}

List<PhysicsSweepTestResult> sweep = bulletAppState.getPhysicsSpace().sweepTest(playerShape, startPos, endPos);

if (sweep.isEmpty()) {

playerNode.move(moveDir);

}



}



@Override

public void simpleUpdate(float tpf) {

cam.setLocation(playerNode.getWorldTranslation());

}



@Override

public void simpleRender(RenderManager rm) {

//TODO: add render code

}

}

[/java]



While the tunneling has disappeared under big angles, you can still move through the floor if you hit it under small, almost horizontal angles:



http://imgur.com/znJPE

Well then theres nothing we can do. Does this happen in native bullet too?