|
@@ -62,17 +62,36 @@ import java.util.logging.Level;
|
|
|
import java.util.logging.Logger;
|
|
|
|
|
|
/**
|
|
|
- * <p>PhysicsSpace - The central jbullet-jme physics space</p>
|
|
|
+ * A jbullet-jme physics space with its own btDynamicsWorld.
|
|
|
*
|
|
|
* @author normenhansen
|
|
|
*/
|
|
|
public class PhysicsSpace {
|
|
|
|
|
|
+ /**
|
|
|
+ * message logger for this class
|
|
|
+ */
|
|
|
private static final Logger logger = Logger.getLogger(PhysicsSpace.class.getName());
|
|
|
+ /**
|
|
|
+ * index of the X axis
|
|
|
+ */
|
|
|
public static final int AXIS_X = 0;
|
|
|
+ /**
|
|
|
+ * index of the Y axis
|
|
|
+ */
|
|
|
public static final int AXIS_Y = 1;
|
|
|
+ /**
|
|
|
+ * index of the Z axis
|
|
|
+ */
|
|
|
public static final int AXIS_Z = 2;
|
|
|
+ /**
|
|
|
+ * Bullet identifier of the physics space. The constructor sets this to a
|
|
|
+ * non-zero value.
|
|
|
+ */
|
|
|
private long physicsSpaceId = 0;
|
|
|
+ /**
|
|
|
+ * first-in/first-out (FIFO) queue of physics tasks for each thread
|
|
|
+ */
|
|
|
private static ThreadLocal<ConcurrentLinkedQueue<AppTask<?>>> pQueueTL =
|
|
|
new ThreadLocal<ConcurrentLinkedQueue<AppTask<?>>>() {
|
|
|
@Override
|
|
@@ -80,8 +99,17 @@ public class PhysicsSpace {
|
|
|
return new ConcurrentLinkedQueue<AppTask<?>>();
|
|
|
}
|
|
|
};
|
|
|
+ /**
|
|
|
+ * first-in/first-out (FIFO) queue of physics tasks
|
|
|
+ */
|
|
|
private ConcurrentLinkedQueue<AppTask<?>> pQueue = new ConcurrentLinkedQueue<AppTask<?>>();
|
|
|
+ /**
|
|
|
+ * physics space for each thread
|
|
|
+ */
|
|
|
private static ThreadLocal<PhysicsSpace> physicsSpaceTL = new ThreadLocal<PhysicsSpace>();
|
|
|
+ /**
|
|
|
+ * copy of type of acceleration structure used
|
|
|
+ */
|
|
|
private BroadphaseType broadphaseType = BroadphaseType.DBVT;
|
|
|
// private DiscreteDynamicsWorld dynamicsWorld = null;
|
|
|
// private BroadphaseInterface broadphase;
|
|
@@ -99,10 +127,32 @@ public class PhysicsSpace {
|
|
|
private Map<Integer, PhysicsCollisionGroupListener> collisionGroupListeners = new ConcurrentHashMap<Integer, PhysicsCollisionGroupListener>();
|
|
|
private ConcurrentLinkedQueue<PhysicsTickListener> tickListeners = new ConcurrentLinkedQueue<PhysicsTickListener>();
|
|
|
private PhysicsCollisionEventFactory eventFactory = new PhysicsCollisionEventFactory();
|
|
|
+ /**
|
|
|
+ * copy of minimum coordinate values when using AXIS_SWEEP broadphase
|
|
|
+ * algorithms
|
|
|
+ */
|
|
|
private Vector3f worldMin = new Vector3f(-10000f, -10000f, -10000f);
|
|
|
+ /**
|
|
|
+ * copy of maximum coordinate values when using AXIS_SWEEP broadphase
|
|
|
+ * algorithms
|
|
|
+ */
|
|
|
private Vector3f worldMax = new Vector3f(10000f, 10000f, 10000f);
|
|
|
+ /**
|
|
|
+ * physics time step (in seconds, >0)
|
|
|
+ */
|
|
|
private float accuracy = 1f / 60f;
|
|
|
- private int maxSubSteps = 4, rayTestFlags = 1 << 2;
|
|
|
+ /**
|
|
|
+ * maximum number of physics steps per frame (≥0, default=4)
|
|
|
+ */
|
|
|
+ private int maxSubSteps = 4;
|
|
|
+ /**
|
|
|
+ * flags used in ray tests
|
|
|
+ */
|
|
|
+ private int rayTestFlags = 1 << 2;
|
|
|
+ /**
|
|
|
+ * copy of number of iterations used by the contact-and-constraint solver
|
|
|
+ * (default=10)
|
|
|
+ */
|
|
|
private int solverNumIterations = 10;
|
|
|
|
|
|
static {
|
|
@@ -111,9 +161,8 @@ public class PhysicsSpace {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Get the current PhysicsSpace <b>running on this thread</b><br/> For
|
|
|
- * parallel physics, this can also be called from the OpenGL thread to
|
|
|
- * receive the PhysicsSpace
|
|
|
+ * Access the PhysicsSpace <b>running on this thread</b>. For parallel
|
|
|
+ * physics, this can be invoked from the OpenGL thread.
|
|
|
*
|
|
|
* @return the PhysicsSpace running on this thread
|
|
|
*/
|
|
@@ -124,24 +173,47 @@ public class PhysicsSpace {
|
|
|
/**
|
|
|
* Used internally
|
|
|
*
|
|
|
- * @param space
|
|
|
+ * @param space which physics space to simulate on this thread
|
|
|
*/
|
|
|
public static void setLocalThreadPhysicsSpace(PhysicsSpace space) {
|
|
|
physicsSpaceTL.set(space);
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Instantiate a PhysicsSpace. Must be invoked on the designated physics
|
|
|
+ * thread.
|
|
|
+ */
|
|
|
public PhysicsSpace() {
|
|
|
this(new Vector3f(-10000f, -10000f, -10000f), new Vector3f(10000f, 10000f, 10000f), BroadphaseType.DBVT);
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Instantiate a PhysicsSpace. Must be invoked on the designated physics
|
|
|
+ * thread.
|
|
|
+ */
|
|
|
public PhysicsSpace(BroadphaseType broadphaseType) {
|
|
|
this(new Vector3f(-10000f, -10000f, -10000f), new Vector3f(10000f, 10000f, 10000f), broadphaseType);
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Instantiate a PhysicsSpace. Must be invoked on the designated physics
|
|
|
+ * thread.
|
|
|
+ */
|
|
|
public PhysicsSpace(Vector3f worldMin, Vector3f worldMax) {
|
|
|
this(worldMin, worldMax, BroadphaseType.AXIS_SWEEP_3);
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Instantiate a PhysicsSpace. Must be invoked on the designated physics
|
|
|
+ * thread.
|
|
|
+ *
|
|
|
+ * @param worldMin the desired minimum coordinates values (not null,
|
|
|
+ * unaffected, default=-10k,-10k,-10k)
|
|
|
+ * @param worldMax the desired minimum coordinates values (not null,
|
|
|
+ * unaffected, default=10k,10k,10k)
|
|
|
+ * @param broadphaseType which broadphase collision-detection algorithm to
|
|
|
+ * use (not null)
|
|
|
+ */
|
|
|
public PhysicsSpace(Vector3f worldMin, Vector3f worldMax, BroadphaseType broadphaseType) {
|
|
|
this.worldMin.set(worldMin);
|
|
|
this.worldMax.set(worldMax);
|
|
@@ -150,7 +222,7 @@ public class PhysicsSpace {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Has to be called from the (designated) physics thread
|
|
|
+ * Must be invoked on the designated physics thread.
|
|
|
*/
|
|
|
public void create() {
|
|
|
physicsSpaceId = createPhysicsSpace(worldMin.x, worldMin.y, worldMin.z, worldMax.x, worldMax.y, worldMax.z, broadphaseType.ordinal(), false);
|
|
@@ -191,6 +263,13 @@ public class PhysicsSpace {
|
|
|
|
|
|
private native long createPhysicsSpace(float minX, float minY, float minZ, float maxX, float maxY, float maxZ, int broadphaseType, boolean threading);
|
|
|
|
|
|
+ /**
|
|
|
+ * Callback invoked just before the physics is stepped.
|
|
|
+ * <p>
|
|
|
+ * This method is invoked from native code.
|
|
|
+ *
|
|
|
+ * @param timeStep the time per physics step (in seconds, ≥0)
|
|
|
+ */
|
|
|
private void preTick_native(float f) {
|
|
|
AppTask task;
|
|
|
while((task=pQueue.poll())!=null){
|
|
@@ -208,6 +287,13 @@ public class PhysicsSpace {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Callback invoked just after the physics is stepped.
|
|
|
+ * <p>
|
|
|
+ * This method is invoked from native code.
|
|
|
+ *
|
|
|
+ * @param timeStep the time per physics step (in seconds, ≥0)
|
|
|
+ */
|
|
|
private void postTick_native(float f) {
|
|
|
for (Iterator<PhysicsTickListener> it = tickListeners.iterator(); it.hasNext();) {
|
|
|
PhysicsTickListener physicsTickCallback = it.next();
|
|
@@ -215,6 +301,9 @@ public class PhysicsSpace {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * This method is invoked from native code.
|
|
|
+ */
|
|
|
private void addCollision_native() {
|
|
|
}
|
|
|
|
|
@@ -334,6 +423,9 @@ public class PhysicsSpace {
|
|
|
collisionEvents.add(eventFactory.getEvent(PhysicsCollisionEvent.TYPE_PROCESSED, node, node1, manifoldPointObjectId));
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * This method is invoked from native code.
|
|
|
+ */
|
|
|
private boolean notifyCollisionGroupListeners_native(PhysicsCollisionObject node, PhysicsCollisionObject node1){
|
|
|
PhysicsCollisionGroupListener listener = collisionGroupListeners.get(node.getCollisionGroup());
|
|
|
PhysicsCollisionGroupListener listener1 = collisionGroupListeners.get(node1.getCollisionGroup());
|
|
@@ -350,19 +442,21 @@ public class PhysicsSpace {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * updates the physics space
|
|
|
+ * Update this space. Invoked (by the Bullet app state) once per frame while
|
|
|
+ * the app state is attached and enabled.
|
|
|
*
|
|
|
- * @param time the current time value
|
|
|
+ * @param time time-per-frame multiplied by speed (in seconds, ≥0)
|
|
|
*/
|
|
|
public void update(float time) {
|
|
|
update(time, maxSubSteps);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * updates the physics space, uses maxSteps<br>
|
|
|
+ * Simulate for the specified time interval, using no more than the
|
|
|
+ * specified number of steps.
|
|
|
*
|
|
|
- * @param time the current time value
|
|
|
- * @param maxSteps
|
|
|
+ * @param time the time interval (in seconds, ≥0)
|
|
|
+ * @param maxSteps the maximum number of steps (≥1)
|
|
|
*/
|
|
|
public void update(float time, int maxSteps) {
|
|
|
// if (getDynamicsWorld() == null) {
|
|
@@ -374,6 +468,9 @@ public class PhysicsSpace {
|
|
|
|
|
|
private native void stepSimulation(long space, float time, int maxSteps, float accuracy);
|
|
|
|
|
|
+ /**
|
|
|
+ * Distribute each collision event to all listeners.
|
|
|
+ */
|
|
|
public void distributeEvents() {
|
|
|
//add collision callbacks
|
|
|
int clistsize = collisionListeners.size();
|
|
@@ -387,6 +484,13 @@ public class PhysicsSpace {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Enqueue a callable on the currently executing thread.
|
|
|
+ *
|
|
|
+ * @param <V> the task's result type
|
|
|
+ * @param callable the task to be executed
|
|
|
+ * @return a new task (not null)
|
|
|
+ */
|
|
|
public static <V> Future<V> enqueueOnThisThread(Callable<V> callable) {
|
|
|
AppTask<V> task = new AppTask<V>(callable);
|
|
|
System.out.println("created apptask");
|
|
@@ -395,11 +499,11 @@ public class PhysicsSpace {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * calls the callable on the next physics tick (ensuring e.g. force
|
|
|
- * applying)
|
|
|
+ * Invoke the specified callable during the next physics tick. This is
|
|
|
+ * useful for applying forces.
|
|
|
*
|
|
|
- * @param <V>
|
|
|
- * @param callable
|
|
|
+ * @param <V> the return type of the callable
|
|
|
+ * @param callable which callable to invoke
|
|
|
* @return Future object
|
|
|
*/
|
|
|
public <V> Future<V> enqueue(Callable<V> callable) {
|
|
@@ -409,9 +513,10 @@ public class PhysicsSpace {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * adds an object to the physics space
|
|
|
+ * Add the specified object to this space.
|
|
|
*
|
|
|
- * @param obj the PhysicsControl or Spatial with PhysicsControl to add
|
|
|
+ * @param obj the PhysicsControl, Spatial-with-PhysicsControl,
|
|
|
+ * PhysicsCollisionObject, or PhysicsJoint to add (not null, modified)
|
|
|
*/
|
|
|
public void add(Object obj) {
|
|
|
if (obj instanceof PhysicsControl) {
|
|
@@ -432,6 +537,11 @@ public class PhysicsSpace {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Add the specified collision object to this space.
|
|
|
+ *
|
|
|
+ * @param obj the PhysicsCollisionObject to add (not null, modified)
|
|
|
+ */
|
|
|
public void addCollisionObject(PhysicsCollisionObject obj) {
|
|
|
if (obj instanceof PhysicsGhostObject) {
|
|
|
addGhostObject((PhysicsGhostObject) obj);
|
|
@@ -445,9 +555,9 @@ public class PhysicsSpace {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * removes an object from the physics space
|
|
|
+ * Remove the specified object from this space.
|
|
|
*
|
|
|
- * @param obj the PhysicsControl or Spatial with PhysicsControl to remove
|
|
|
+ * @param obj the PhysicsCollisionObject to add, or null (modified)
|
|
|
*/
|
|
|
public void remove(Object obj) {
|
|
|
if (obj == null) return;
|
|
@@ -469,6 +579,11 @@ public class PhysicsSpace {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Remove the specified collision object from this space.
|
|
|
+ *
|
|
|
+ * @param obj the PhysicsControl or Spatial with PhysicsControl to remove
|
|
|
+ */
|
|
|
public void removeCollisionObject(PhysicsCollisionObject obj) {
|
|
|
if (obj instanceof PhysicsGhostObject) {
|
|
|
removeGhostObject((PhysicsGhostObject) obj);
|
|
@@ -480,9 +595,10 @@ public class PhysicsSpace {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * adds all physics controls and joints in the given spatial node to the physics space
|
|
|
- * (e.g. after loading from disk) - recursive if node
|
|
|
- * @param spatial the rootnode containing the physics objects
|
|
|
+ * Add all physics controls and joints in the specified subtree of the scene
|
|
|
+ * graph to this space (e.g. after loading from disk). Note: recursive!
|
|
|
+ *
|
|
|
+ * @param spatial the root of the subtree (not null)
|
|
|
*/
|
|
|
public void addAll(Spatial spatial) {
|
|
|
add(spatial);
|
|
@@ -510,9 +626,11 @@ public class PhysicsSpace {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Removes all physics controls and joints in the given spatial from the physics space
|
|
|
- * (e.g. before saving to disk) - recursive if node
|
|
|
- * @param spatial the rootnode containing the physics objects
|
|
|
+ * Remove all physics controls and joints in the specified subtree of the
|
|
|
+ * scene graph from the physics space (e.g. before saving to disk) Note:
|
|
|
+ * recursive!
|
|
|
+ *
|
|
|
+ * @param spatial the root of the subtree (not null)
|
|
|
*/
|
|
|
public void removeAll(Spatial spatial) {
|
|
|
if (spatial.getControl(RigidBodyControl.class) != null) {
|
|
@@ -611,6 +729,12 @@ public class PhysicsSpace {
|
|
|
// dynamicsWorld.removeCollisionObject(node.getObjectId());
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * NOTE: When a rigid body is added, its gravity gets set to that of the
|
|
|
+ * physics space.
|
|
|
+ *
|
|
|
+ * @param node the body to add (not null, not already in the space)
|
|
|
+ */
|
|
|
private void addRigidBody(PhysicsRigidBody node) {
|
|
|
if (physicsBodies.containsKey(node.getObjectId())) {
|
|
|
logger.log(Level.WARNING, "RigidBody {0} already exists in PhysicsSpace, cannot add.", node);
|
|
@@ -619,7 +743,7 @@ public class PhysicsSpace {
|
|
|
physicsBodies.put(node.getObjectId(), node);
|
|
|
|
|
|
//Workaround
|
|
|
- //It seems that adding a Kinematic RigidBody to the dynamicWorld prevent it from being non kinematic again afterward.
|
|
|
+ //It seems that adding a Kinematic RigidBody to the dynamicWorld prevents it from being non-kinematic again afterward.
|
|
|
//so we add it non kinematic, then set it kinematic again.
|
|
|
boolean kinematic = false;
|
|
|
if (node.isKinematic()) {
|
|
@@ -682,30 +806,64 @@ public class PhysicsSpace {
|
|
|
// dynamicsWorld.removeConstraint(joint.getObjectId());
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Copy the list of rigid bodies that have been added to this space and not
|
|
|
+ * yet removed.
|
|
|
+ *
|
|
|
+ * @return a new list (not null)
|
|
|
+ */
|
|
|
public Collection<PhysicsRigidBody> getRigidBodyList() {
|
|
|
return new LinkedList<PhysicsRigidBody>(physicsBodies.values());
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Copy the list of ghost objects that have been added to this space and not
|
|
|
+ * yet removed.
|
|
|
+ *
|
|
|
+ * @return a new list (not null)
|
|
|
+ */
|
|
|
public Collection<PhysicsGhostObject> getGhostObjectList() {
|
|
|
return new LinkedList<PhysicsGhostObject>(physicsGhostObjects.values());
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Copy the list of physics characters that have been added to this space
|
|
|
+ * and not yet removed.
|
|
|
+ *
|
|
|
+ * @return a new list (not null)
|
|
|
+ */
|
|
|
public Collection<PhysicsCharacter> getCharacterList() {
|
|
|
return new LinkedList<PhysicsCharacter>(physicsCharacters.values());
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Copy the list of physics joints that have been added to this space and
|
|
|
+ * not yet removed.
|
|
|
+ *
|
|
|
+ * @return a new list (not null)
|
|
|
+ */
|
|
|
public Collection<PhysicsJoint> getJointList() {
|
|
|
return new LinkedList<PhysicsJoint>(physicsJoints.values());
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Copy the list of physics vehicles that have been added to this space and
|
|
|
+ * not yet removed.
|
|
|
+ *
|
|
|
+ * @return a new list (not null)
|
|
|
+ */
|
|
|
public Collection<PhysicsVehicle> getVehicleList() {
|
|
|
return new LinkedList<PhysicsVehicle>(physicsVehicles.values());
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Sets the gravity of the PhysicsSpace, set before adding physics objects!
|
|
|
+ * Alter the gravitational acceleration acting on newly-added bodies.
|
|
|
+ * <p>
|
|
|
+ * Whenever a rigid body is added to a space, the body's gravity gets set to
|
|
|
+ * that of the space. Thus it makes sense to set the space's vector before
|
|
|
+ * adding any bodies to the space.
|
|
|
*
|
|
|
- * @param gravity
|
|
|
+ * @param gravity the desired acceleration vector (not null, unaffected)
|
|
|
*/
|
|
|
public void setGravity(Vector3f gravity) {
|
|
|
this.gravity.set(gravity);
|
|
@@ -714,8 +872,17 @@ public class PhysicsSpace {
|
|
|
|
|
|
private native void setGravity(long spaceId, Vector3f gravity);
|
|
|
|
|
|
- //TODO: getGravity
|
|
|
+ /**
|
|
|
+ * copy of gravity-acceleration vector (default is 9.81 in the -Y direction,
|
|
|
+ * corresponding to Earth-normal in MKS units)
|
|
|
+ */
|
|
|
private final Vector3f gravity = new Vector3f(0,-9.81f,0);
|
|
|
+ /**
|
|
|
+ * Copy the gravitational acceleration acting on newly-added bodies.
|
|
|
+ *
|
|
|
+ * @param gravity storage for the result (not null, modified)
|
|
|
+ * @return acceleration (in the vector provided)
|
|
|
+ */
|
|
|
public Vector3f getGravity(Vector3f gravity) {
|
|
|
return gravity.set(this.gravity);
|
|
|
}
|
|
@@ -735,57 +902,89 @@ public class PhysicsSpace {
|
|
|
// }
|
|
|
//
|
|
|
/**
|
|
|
- * Adds the specified listener to the physics tick listeners. The listeners
|
|
|
- * are called on each physics step, which is not necessarily each frame but
|
|
|
- * is determined by the accuracy of the physics space.
|
|
|
+ * Register the specified tick listener with this space.
|
|
|
+ * <p>
|
|
|
+ * Tick listeners are notified before and after each physics step. A physics
|
|
|
+ * step is not necessarily the same as a frame; it is more influenced by the
|
|
|
+ * accuracy of the physics space.
|
|
|
*
|
|
|
- * @param listener
|
|
|
+ * @see #setAccuracy(float)
|
|
|
+ *
|
|
|
+ * @param listener the listener to register (not null)
|
|
|
*/
|
|
|
public void addTickListener(PhysicsTickListener listener) {
|
|
|
tickListeners.add(listener);
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * De-register the specified tick listener.
|
|
|
+ *
|
|
|
+ * @see #addTickListener(com.jme3.bullet.PhysicsTickListener)
|
|
|
+ * @param listener the listener to de-register (not null)
|
|
|
+ */
|
|
|
public void removeTickListener(PhysicsTickListener listener) {
|
|
|
tickListeners.remove(listener);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Adds a CollisionListener that will be informed about collision events
|
|
|
+ * Register the specified collision listener with this space.
|
|
|
+ * <p>
|
|
|
+ * Collision listeners are notified when collisions occur in the space.
|
|
|
*
|
|
|
- * @param listener the CollisionListener to add
|
|
|
+ * @param listener the listener to register (not null, alias created)
|
|
|
*/
|
|
|
public void addCollisionListener(PhysicsCollisionListener listener) {
|
|
|
collisionListeners.add(listener);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Removes a CollisionListener from the list
|
|
|
+ * De-register the specified collision listener.
|
|
|
*
|
|
|
- * @param listener the CollisionListener to remove
|
|
|
+ * @see
|
|
|
+ * #addCollisionListener(com.jme3.bullet.collision.PhysicsCollisionListener)
|
|
|
+ * @param listener the listener to de-register (not null)
|
|
|
*/
|
|
|
public void removeCollisionListener(PhysicsCollisionListener listener) {
|
|
|
collisionListeners.remove(listener);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Adds a listener for a specific collision group, such a listener can
|
|
|
- * disable collisions when they happen.<br> There can be only one listener
|
|
|
- * per collision group.
|
|
|
+ * Register the specified collision-group listener with the specified
|
|
|
+ * collision group of this space.
|
|
|
+ * <p>
|
|
|
+ * Such a listener can disable collisions when they occur. There can be only
|
|
|
+ * one listener per collision group per space.
|
|
|
*
|
|
|
- * @param listener
|
|
|
- * @param collisionGroup
|
|
|
+ * @param listener the listener to register (not null)
|
|
|
+ * @param collisionGroup which group it should listen for (bit mask with
|
|
|
+ * exactly one bit set)
|
|
|
*/
|
|
|
public void addCollisionGroupListener(PhysicsCollisionGroupListener listener, int collisionGroup) {
|
|
|
collisionGroupListeners.put(collisionGroup, listener);
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * De-register the specified collision-group listener.
|
|
|
+ *
|
|
|
+ * @see
|
|
|
+ * #addCollisionGroupListener(com.jme3.bullet.collision.PhysicsCollisionGroupListener,
|
|
|
+ * int)
|
|
|
+ * @param collisionGroup the group of the listener to de-register (bit mask
|
|
|
+ * with exactly one bit set)
|
|
|
+ */
|
|
|
public void removeCollisionGroupListener(int collisionGroup) {
|
|
|
collisionGroupListeners.remove(collisionGroup);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Performs a ray collision test and returns the results as a list of
|
|
|
- * PhysicsRayTestResults ordered by it hitFraction (lower to higher)
|
|
|
+ * Perform a ray-collision test and return the results as a list of
|
|
|
+ * PhysicsRayTestResults sorted by ascending hitFraction.
|
|
|
+ *
|
|
|
+ * @param from the starting location (physics-space coordinates, not null,
|
|
|
+ * unaffected)
|
|
|
+ * @param to the ending location (in physics-space coordinates, not null,
|
|
|
+ * unaffected)
|
|
|
+ * @return a new list of results (not null)
|
|
|
*/
|
|
|
public List rayTest(Vector3f from, Vector3f to) {
|
|
|
List<PhysicsRayTestResult> results = new ArrayList<PhysicsRayTestResult>();
|
|
@@ -795,8 +994,14 @@ public class PhysicsSpace {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Performs a ray collision test and returns the results as a list of
|
|
|
- * PhysicsRayTestResults without performing any sort operation
|
|
|
+ * Perform a ray-collision test and return the results as a list of
|
|
|
+ * PhysicsRayTestResults in arbitrary order.
|
|
|
+ *
|
|
|
+ * @param from the starting location (in physics-space coordinates, not
|
|
|
+ * null, unaffected)
|
|
|
+ * @param to the ending location (in physics-space coordinates, not null,
|
|
|
+ * unaffected)
|
|
|
+ * @return a new list of results (not null)
|
|
|
*/
|
|
|
public List rayTestRaw(Vector3f from, Vector3f to) {
|
|
|
List<PhysicsRayTestResult> results = new ArrayList<PhysicsRayTestResult>();
|
|
@@ -806,17 +1011,22 @@ public class PhysicsSpace {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Sets m_flags for raytest, see https://code.google.com/p/bullet/source/browse/trunk/src/BulletCollision/NarrowPhaseCollision/btRaycastCallback.h
|
|
|
+ * Alters the m_flags used in ray tests. see
|
|
|
+ * https://code.google.com/p/bullet/source/browse/trunk/src/BulletCollision/NarrowPhaseCollision/btRaycastCallback.h
|
|
|
* for possible options. Defaults to using the faster, approximate raytest.
|
|
|
+ *
|
|
|
+ * @param flags the desired flags, ORed together (default=0x4)
|
|
|
*/
|
|
|
public void SetRayTestFlags(int flags) {
|
|
|
rayTestFlags = flags;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Gets m_flags for raytest, see https://code.google.com/p/bullet/source/browse/trunk/src/BulletCollision/NarrowPhaseCollision/btRaycastCallback.h
|
|
|
+ * Reads m_flags used in ray tests. see
|
|
|
+ * https://code.google.com/p/bullet/source/browse/trunk/src/BulletCollision/NarrowPhaseCollision/btRaycastCallback.h
|
|
|
* for possible options.
|
|
|
- * @return rayTestFlags
|
|
|
+ *
|
|
|
+ * @return which flags are used
|
|
|
*/
|
|
|
public int GetRayTestFlags() {
|
|
|
return rayTestFlags;
|
|
@@ -831,8 +1041,15 @@ public class PhysicsSpace {
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
- * Performs a ray collision test and returns the results as a list of
|
|
|
- * PhysicsRayTestResults ordered by it hitFraction (lower to higher)
|
|
|
+ * Perform a ray-collision test and return the results as a list of
|
|
|
+ * PhysicsRayTestResults sorted by ascending hitFraction.
|
|
|
+ *
|
|
|
+ * @param from coordinates of the starting location (in physics space, not
|
|
|
+ * null, unaffected)
|
|
|
+ * @param to coordinates of the ending location (in physics space, not null,
|
|
|
+ * unaffected)
|
|
|
+ * @param results the list to hold results (not null, modified)
|
|
|
+ * @return results
|
|
|
*/
|
|
|
public List<PhysicsRayTestResult> rayTest(Vector3f from, Vector3f to, List<PhysicsRayTestResult> results) {
|
|
|
results.clear();
|
|
@@ -843,8 +1060,15 @@ public class PhysicsSpace {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Performs a ray collision test and returns the results as a list of
|
|
|
- * PhysicsRayTestResults without performing any sort operation
|
|
|
+ * Perform a ray-collision test and return the results as a list of
|
|
|
+ * PhysicsRayTestResults in arbitrary order.
|
|
|
+ *
|
|
|
+ * @param from coordinates of the starting location (in physics space, not
|
|
|
+ * null, unaffected)
|
|
|
+ * @param to coordinates of the ending location (in physics space, not null,
|
|
|
+ * unaffected)
|
|
|
+ * @param results the list to hold results (not null, modified)
|
|
|
+ * @return results
|
|
|
*/
|
|
|
public List<PhysicsRayTestResult> rayTestRaw(Vector3f from, Vector3f to, List<PhysicsRayTestResult> results) {
|
|
|
results.clear();
|
|
@@ -874,11 +1098,18 @@ public class PhysicsSpace {
|
|
|
|
|
|
|
|
|
/**
|
|
|
- * Performs a sweep collision test and returns the results as a list of
|
|
|
- * PhysicsSweepTestResults<br/> You have to use different Transforms for
|
|
|
- * start and end (at least distance > 0.4f). SweepTest will not see a
|
|
|
- * collision if it starts INSIDE an object and is moving AWAY from its
|
|
|
- * center.
|
|
|
+ * Perform a sweep-collision test and return the results as a new list.
|
|
|
+ * <p>
|
|
|
+ * The starting and ending locations must be at least 0.4f physics-space
|
|
|
+ * units apart.
|
|
|
+ * <p>
|
|
|
+ * A sweep test will miss a collision if it starts inside an object and
|
|
|
+ * sweeps away from the object's center.
|
|
|
+ *
|
|
|
+ * @param shape the shape to sweep (not null)
|
|
|
+ * @param start the starting physics-space transform (not null)
|
|
|
+ * @param end the ending physics-space transform (not null)
|
|
|
+ * @return a new list of results
|
|
|
*/
|
|
|
public List<PhysicsSweepTestResult> sweepTest(CollisionShape shape, Transform start, Transform end) {
|
|
|
List results = new LinkedList();
|
|
@@ -886,17 +1117,41 @@ public class PhysicsSpace {
|
|
|
return (List<PhysicsSweepTestResult>) results;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Perform a sweep-collision test and store the results in an existing list.
|
|
|
+ * <p>
|
|
|
+ * The starting and ending locations must be at least 0.4f physics-space
|
|
|
+ * units apart.
|
|
|
+ * <p>
|
|
|
+ * A sweep test will miss a collision if it starts inside an object and
|
|
|
+ * sweeps away from the object's center.
|
|
|
+ *
|
|
|
+ * @param shape the shape to sweep (not null)
|
|
|
+ * @param start the starting physics-space transform (not null)
|
|
|
+ * @param end the ending physics-space transform (not null)
|
|
|
+ * @param results the list to hold results (not null, modified)
|
|
|
+ * @return results
|
|
|
+ */
|
|
|
public List<PhysicsSweepTestResult> sweepTest(CollisionShape shape, Transform start, Transform end, List<PhysicsSweepTestResult> results) {
|
|
|
return sweepTest(shape, start, end, results, 0.0f);
|
|
|
}
|
|
|
|
|
|
public native void sweepTest_native(long shape, Transform from, Transform to, long physicsSpaceId, List<PhysicsSweepTestResult> results, float allowedCcdPenetration);
|
|
|
/**
|
|
|
- * Performs a sweep collision test and returns the results as a list of
|
|
|
- * PhysicsSweepTestResults<br/> You have to use different Transforms for
|
|
|
- * start and end (at least distance > allowedCcdPenetration). SweepTest will not see a
|
|
|
- * collision if it starts INSIDE an object and is moving AWAY from its
|
|
|
- * center.
|
|
|
+ * Perform a sweep-collision test and store the results in an existing list.
|
|
|
+ * <p>
|
|
|
+ * The starting and ending locations must be at least 0.4f physics-space
|
|
|
+ * units apart.
|
|
|
+ * <p>
|
|
|
+ * A sweep test will miss a collision if it starts inside an object and
|
|
|
+ * sweeps away from the object's center.
|
|
|
+ *
|
|
|
+ * @param shape the shape to sweep (not null)
|
|
|
+ * @param start the starting physics-space transform (not null)
|
|
|
+ * @param end the ending physics-space transform (not null)
|
|
|
+ * @param results the list to hold results (not null, modified)
|
|
|
+ * @param allowedCcdPenetration true→allow, false→disallow
|
|
|
+ * @return results
|
|
|
*/
|
|
|
public List<PhysicsSweepTestResult> sweepTest(CollisionShape shape, Transform start, Transform end, List<PhysicsSweepTestResult> results, float allowedCcdPenetration ) {
|
|
|
results.clear();
|
|
@@ -923,7 +1178,7 @@ public class PhysicsSpace {
|
|
|
*/
|
|
|
|
|
|
/**
|
|
|
- * destroys the current PhysicsSpace so that a new one can be created
|
|
|
+ * Destroy this space so that a new one can be instantiated.
|
|
|
*/
|
|
|
public void destroy() {
|
|
|
physicsBodies.clear();
|
|
@@ -942,59 +1197,87 @@ public class PhysicsSpace {
|
|
|
return physicsSpaceId;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Read the type of acceleration structure used.
|
|
|
+ *
|
|
|
+ * @return an enum value (not null)
|
|
|
+ */
|
|
|
public BroadphaseType getBroadphaseType() {
|
|
|
return broadphaseType;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Alter the type of acceleration structure used.
|
|
|
+ *
|
|
|
+ * @param broadphaseType the desired algorithm (not null)
|
|
|
+ */
|
|
|
public void setBroadphaseType(BroadphaseType broadphaseType) {
|
|
|
this.broadphaseType = broadphaseType;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Sets the maximum amount of extra steps that will be used to step the
|
|
|
- * physics when the fps is below the physics fps. Doing this maintains
|
|
|
- * determinism in physics. For example a maximum number of 2 can compensate
|
|
|
- * for framerates as low as 30fps when the physics has the default accuracy
|
|
|
- * of 60 fps. Note that setting this value too high can make the physics
|
|
|
- * drive down its own fps in case it's overloaded.
|
|
|
+ * Alter the maximum number of physics steps per frame.
|
|
|
+ * <p>
|
|
|
+ * Extra physics steps help maintain determinism when the render fps drops
|
|
|
+ * below 1/accuracy. For example a value of 2 can compensate for frame rates
|
|
|
+ * as low as 30fps, assuming the physics has an accuracy of 1/60 sec.
|
|
|
+ * <p>
|
|
|
+ * Setting this value too high can depress the frame rate.
|
|
|
*
|
|
|
- * @param steps The maximum number of extra steps, default is 4.
|
|
|
+ * @param steps the desired maximum number of steps per frame (≥1,
|
|
|
+ * default=4)
|
|
|
*/
|
|
|
public void setMaxSubSteps(int steps) {
|
|
|
maxSubSteps = steps;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * get the current accuracy of the physics computation
|
|
|
+ * Read the accuracy (time step) of the physics simulation.
|
|
|
*
|
|
|
- * @return the current accuracy
|
|
|
+ * @return the timestep (in seconds, >0)
|
|
|
*/
|
|
|
public float getAccuracy() {
|
|
|
return accuracy;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * sets the accuracy of the physics computation, default=1/60s<br>
|
|
|
+ * Alter the accuracy (time step) of the physics simulation.
|
|
|
+ * <p>
|
|
|
+ * In general, the smaller the time step, the more accurate (and
|
|
|
+ * compute-intensive) the simulation will be. Bullet works best with a
|
|
|
+ * timestep of no more than 1/60 second.
|
|
|
*
|
|
|
- * @param accuracy
|
|
|
+ * @param accuracy the desired time step (in seconds, >0, default=1/60)
|
|
|
*/
|
|
|
public void setAccuracy(float accuracy) {
|
|
|
this.accuracy = accuracy;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Access the minimum coordinate values for this space.
|
|
|
+ *
|
|
|
+ * @return the pre-existing vector
|
|
|
+ */
|
|
|
public Vector3f getWorldMin() {
|
|
|
return worldMin;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * only applies for AXIS_SWEEP broadphase
|
|
|
+ * Alter the minimum coordinate values for this space. (only affects
|
|
|
+ * AXIS_SWEEP broadphase algorithms)
|
|
|
*
|
|
|
- * @param worldMin
|
|
|
+ * @param worldMin the desired minimum coordinate values (not null,
|
|
|
+ * unaffected)
|
|
|
*/
|
|
|
public void setWorldMin(Vector3f worldMin) {
|
|
|
this.worldMin.set(worldMin);
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Access the maximum coordinate values for this space.
|
|
|
+ *
|
|
|
+ * @return the pre-existing vector (not null)
|
|
|
+ */
|
|
|
public Vector3f getWorldMax() {
|
|
|
return worldMax;
|
|
|
}
|
|
@@ -1009,11 +1292,11 @@ public class PhysicsSpace {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Set the number of iterations used by the contact solver.
|
|
|
- *
|
|
|
- * The default is 10. Use 4 for low quality, 20 for high quality.
|
|
|
- *
|
|
|
- * @param numIterations The number of iterations used by the contact & constraint solver.
|
|
|
+ * Alter the number of iterations used by the contact-and-constraint solver.
|
|
|
+ * <p>
|
|
|
+ * Use 4 for low quality, 20 for high quality.
|
|
|
+ *
|
|
|
+ * @param numIterations the desired number of iterations (≥1, default=10)
|
|
|
*/
|
|
|
public void setSolverNumIterations(int numIterations) {
|
|
|
this.solverNumIterations = numIterations;
|
|
@@ -1021,9 +1304,9 @@ public class PhysicsSpace {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Get the number of iterations used by the contact solver.
|
|
|
- *
|
|
|
- * @return The number of iterations used by the contact & constraint solver.
|
|
|
+ * Read the number of iterations used by the contact-and-constraint solver.
|
|
|
+ *
|
|
|
+ * @return the number of iterations used
|
|
|
*/
|
|
|
public int getSolverNumIterations() {
|
|
|
return solverNumIterations;
|
|
@@ -1034,28 +1317,40 @@ public class PhysicsSpace {
|
|
|
public static native void initNativePhysics();
|
|
|
|
|
|
/**
|
|
|
- * interface with Broadphase types
|
|
|
+ * Enumerate the available acceleration structures for broadphase collision
|
|
|
+ * detection.
|
|
|
*/
|
|
|
public enum BroadphaseType {
|
|
|
|
|
|
/**
|
|
|
- * basic Broadphase
|
|
|
+ * btSimpleBroadphase: a brute-force reference implementation for
|
|
|
+ * debugging purposes
|
|
|
*/
|
|
|
SIMPLE,
|
|
|
/**
|
|
|
- * better Broadphase, needs worldBounds , max Object number = 16384
|
|
|
+ * btAxisSweep3: uses incremental 3-D sweep and prune, requires world
|
|
|
+ * bounds, limited to 16_384 objects
|
|
|
*/
|
|
|
AXIS_SWEEP_3,
|
|
|
/**
|
|
|
- * better Broadphase, needs worldBounds , max Object number = 65536
|
|
|
+ * bt32BitAxisSweep3: uses incremental 3-D sweep and prune, requires
|
|
|
+ * world bounds, limited to 65_536 objects
|
|
|
*/
|
|
|
AXIS_SWEEP_3_32,
|
|
|
/**
|
|
|
- * Broadphase allowing quicker adding/removing of physics objects
|
|
|
+ * btDbvtBroadphase: uses a fast, dynamic bounding-volume hierarchy
|
|
|
+ * based on AABB tree to allow quicker addition/removal of physics
|
|
|
+ * objects
|
|
|
*/
|
|
|
DBVT;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Finalize this physics space just before it is destroyed. Should be
|
|
|
+ * invoked only by a subclass or by the garbage collector.
|
|
|
+ *
|
|
|
+ * @throws Throwable ignored by the garbage collector
|
|
|
+ */
|
|
|
@Override
|
|
|
protected void finalize() throws Throwable {
|
|
|
super.finalize();
|