- add new BulletDebugAppState for physics debugging

- fix non-displayed physics objects in debug view
- remove dependency of base physics objects to scenegraph api, only jme math dependencies are left

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@10342 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
3.0
nor..67 12 years ago
parent 2d5800d667
commit 8992563b86
  1. 78
      engine/src/bullet-common/com/jme3/bullet/BulletAppState.java
  2. 81
      engine/src/bullet-common/com/jme3/bullet/debug/AbstractPhysicsDebugControl.java
  3. 92
      engine/src/bullet-common/com/jme3/bullet/debug/BulletCharacterDebugControl.java
  4. 361
      engine/src/bullet-common/com/jme3/bullet/debug/BulletDebugAppState.java
  5. 91
      engine/src/bullet-common/com/jme3/bullet/debug/BulletGhostObjectDebugControl.java
  6. 106
      engine/src/bullet-common/com/jme3/bullet/debug/BulletJointDebugControl.java
  7. 95
      engine/src/bullet-common/com/jme3/bullet/debug/BulletRigidBodyDebugControl.java
  8. 142
      engine/src/bullet-common/com/jme3/bullet/debug/BulletVehicleDebugControl.java
  9. 2
      engine/src/bullet/com/jme3/bullet/PhysicsSpace.java
  10. 2
      engine/src/jbullet/com/jme3/bullet/PhysicsSpace.java

@ -35,6 +35,7 @@ import com.jme3.app.Application;
import com.jme3.app.state.AppState; import com.jme3.app.state.AppState;
import com.jme3.app.state.AppStateManager; import com.jme3.app.state.AppStateManager;
import com.jme3.bullet.PhysicsSpace.BroadphaseType; import com.jme3.bullet.PhysicsSpace.BroadphaseType;
import com.jme3.bullet.debug.BulletDebugAppState;
import com.jme3.math.Vector3f; import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager; import com.jme3.renderer.RenderManager;
import java.util.concurrent.*; import java.util.concurrent.*;
@ -43,6 +44,7 @@ import java.util.logging.Logger;
/** /**
* <code>BulletAppState</code> allows using bullet physics in an Application. * <code>BulletAppState</code> allows using bullet physics in an Application.
*
* @author normenhansen * @author normenhansen
*/ */
public class BulletAppState implements AppState, PhysicsTickListener { public class BulletAppState implements AppState, PhysicsTickListener {
@ -56,31 +58,38 @@ public class BulletAppState implements AppState, PhysicsTickListener {
protected BroadphaseType broadphaseType = BroadphaseType.DBVT; protected BroadphaseType broadphaseType = BroadphaseType.DBVT;
protected Vector3f worldMin = new Vector3f(-10000f, -10000f, -10000f); protected Vector3f worldMin = new Vector3f(-10000f, -10000f, -10000f);
protected Vector3f worldMax = new Vector3f(10000f, 10000f, 10000f); protected Vector3f worldMax = new Vector3f(10000f, 10000f, 10000f);
private float speed = 1; protected float speed = 1;
protected boolean active = true; protected boolean active = true;
protected boolean debugEnabled = false;
protected BulletDebugAppState debugAppState;
protected float tpf; protected float tpf;
protected Future physicsFuture; protected Future physicsFuture;
/** /**
* Creates a new BulletAppState running a PhysicsSpace for physics simulation, * Creates a new BulletAppState running a PhysicsSpace for physics
* use getStateManager().addState(bulletAppState) to enable physics for an Application. * simulation, use getStateManager().addState(bulletAppState) to enable
* physics for an Application.
*/ */
public BulletAppState() { public BulletAppState() {
} }
/** /**
* Creates a new BulletAppState running a PhysicsSpace for physics simulation, * Creates a new BulletAppState running a PhysicsSpace for physics
* use getStateManager().addState(bulletAppState) to enable physics for an Application. * simulation, use getStateManager().addState(bulletAppState) to enable
* @param broadphaseType The type of broadphase collision detection, BroadphaseType.DVBT is the default * physics for an Application.
*
* @param broadphaseType The type of broadphase collision detection,
* BroadphaseType.DVBT is the default
*/ */
public BulletAppState(BroadphaseType broadphaseType) { public BulletAppState(BroadphaseType broadphaseType) {
this(new Vector3f(-10000f, -10000f, -10000f), new Vector3f(10000f, 10000f, 10000f), broadphaseType); this(new Vector3f(-10000f, -10000f, -10000f), new Vector3f(10000f, 10000f, 10000f), broadphaseType);
} }
/** /**
* Creates a new BulletAppState running a PhysicsSpace for physics simulation, * Creates a new BulletAppState running a PhysicsSpace for physics
* use getStateManager().addState(bulletAppState) to enable physics for an Application. * simulation, use getStateManager().addState(bulletAppState) to enable
* An AxisSweep broadphase is used. * physics for an Application. An AxisSweep broadphase is used.
*
* @param worldMin The minimum world extent * @param worldMin The minimum world extent
* @param worldMax The maximum world extent * @param worldMax The maximum world extent
*/ */
@ -101,7 +110,6 @@ public class BulletAppState implements AppState, PhysicsTickListener {
executor = new ScheduledThreadPoolExecutor(1); executor = new ScheduledThreadPoolExecutor(1);
final BulletAppState app = this; final BulletAppState app = this;
Callable<Boolean> call = new Callable<Boolean>() { Callable<Boolean> call = new Callable<Boolean>() {
public Boolean call() throws Exception { public Boolean call() throws Exception {
detachedPhysicsLastUpdate = System.currentTimeMillis(); detachedPhysicsLastUpdate = System.currentTimeMillis();
pSpace = new PhysicsSpace(worldMin, worldMax, broadphaseType); pSpace = new PhysicsSpace(worldMin, worldMax, broadphaseType);
@ -120,7 +128,6 @@ public class BulletAppState implements AppState, PhysicsTickListener {
} }
} }
private Callable<Boolean> parallelPhysicsUpdate = new Callable<Boolean>() { private Callable<Boolean> parallelPhysicsUpdate = new Callable<Boolean>() {
public Boolean call() throws Exception { public Boolean call() throws Exception {
pSpace.update(tpf * getSpeed()); pSpace.update(tpf * getSpeed());
return true; return true;
@ -128,7 +135,6 @@ public class BulletAppState implements AppState, PhysicsTickListener {
}; };
long detachedPhysicsLastUpdate = 0; long detachedPhysicsLastUpdate = 0;
private Callable<Boolean> detachedPhysicsUpdate = new Callable<Boolean>() { private Callable<Boolean> detachedPhysicsUpdate = new Callable<Boolean>() {
public Boolean call() throws Exception { public Boolean call() throws Exception {
pSpace.update(getPhysicsSpace().getAccuracy() * getSpeed()); pSpace.update(getPhysicsSpace().getAccuracy() * getSpeed());
pSpace.distributeEvents(); pSpace.distributeEvents();
@ -144,8 +150,8 @@ public class BulletAppState implements AppState, PhysicsTickListener {
} }
/** /**
* The physics system is started automatically on attaching, if you want to start it * The physics system is started automatically on attaching, if you want to
* before for some reason, you can use this method. * start it before for some reason, you can use this method.
*/ */
public void startPhysics() { public void startPhysics() {
//start physics thread(pool) //start physics thread(pool)
@ -165,6 +171,7 @@ public class BulletAppState implements AppState, PhysicsTickListener {
if (!initialized) { if (!initialized) {
startPhysics(); startPhysics();
} }
this.stateManager = stateManager;
initialized = true; initialized = true;
} }
@ -180,6 +187,14 @@ public class BulletAppState implements AppState, PhysicsTickListener {
return active; return active;
} }
public void setDebugEnabled(boolean debugEnabled) {
this.debugEnabled = debugEnabled;
}
public boolean isDebugEnabled() {
return debugEnabled;
}
public void stateAttached(AppStateManager stateManager) { public void stateAttached(AppStateManager stateManager) {
if (!initialized) { if (!initialized) {
startPhysics(); startPhysics();
@ -187,12 +202,31 @@ public class BulletAppState implements AppState, PhysicsTickListener {
if (threadingType == ThreadingType.PARALLEL) { if (threadingType == ThreadingType.PARALLEL) {
PhysicsSpace.setLocalThreadPhysicsSpace(pSpace); PhysicsSpace.setLocalThreadPhysicsSpace(pSpace);
} }
if (debugEnabled) {
debugAppState = new BulletDebugAppState(pSpace);
stateManager.attach(debugAppState);
}
} }
public void stateDetached(AppStateManager stateManager) { public void stateDetached(AppStateManager stateManager) {
} }
public void update(float tpf) { public void update(float tpf) {
if (debugEnabled && debugAppState == null) {
debugAppState = new BulletDebugAppState(pSpace);
stateManager.attach(debugAppState);
pSpace.enableDebug(app.getAssetManager());
} else if (!debugEnabled && debugAppState != null) {
stateManager.detach(debugAppState);
debugAppState = null;
pSpace.enableDebug(null);
}
//TODO: remove when deprecation of PhysicsSpace.enableDebug is through
if (pSpace.getDebugManager() != null && !debugEnabled) {
debugEnabled = true;
} else if (pSpace.getDebugManager() == null && debugEnabled) {
debugEnabled = false;
}
if (!active) { if (!active) {
return; return;
} }
@ -228,6 +262,10 @@ public class BulletAppState implements AppState, PhysicsTickListener {
} }
public void cleanup() { public void cleanup() {
if (debugAppState != null) {
stateManager.detach(debugAppState);
debugAppState = null;
}
if (executor != null) { if (executor != null) {
executor.shutdown(); executor.shutdown();
executor = null; executor = null;
@ -245,6 +283,7 @@ public class BulletAppState implements AppState, PhysicsTickListener {
/** /**
* Use before attaching state * Use before attaching state
*
* @param threadingType the threadingType to set * @param threadingType the threadingType to set
*/ */
public void setThreadingType(ThreadingType threadingType) { public void setThreadingType(ThreadingType threadingType) {
@ -289,13 +328,14 @@ public class BulletAppState implements AppState, PhysicsTickListener {
public enum ThreadingType { public enum ThreadingType {
/** /**
* Default mode; user update, physics update and rendering happen sequentially (single threaded) * Default mode; user update, physics update and rendering happen
* sequentially (single threaded)
*/ */
SEQUENTIAL, SEQUENTIAL,
/** /**
* Parallel threaded mode; physics update and rendering are executed in parallel, update order is kept.<br/> * Parallel threaded mode; physics update and rendering are executed in
* Multiple BulletAppStates will execute in parallel in this mode. * parallel, update order is kept.<br/> Multiple BulletAppStates will
* execute in parallel in this mode.
*/ */
PARALLEL, PARALLEL,}
}
} }

@ -0,0 +1,81 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.jme3.bullet.debug;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.AbstractControl;
/**
*
* @author normenhansen
*/
public abstract class AbstractPhysicsDebugControl extends AbstractControl {
private final Quaternion tmp_inverseWorldRotation = new Quaternion();
protected final BulletDebugAppState debugAppState;
public AbstractPhysicsDebugControl(BulletDebugAppState debugAppState) {
this.debugAppState = debugAppState;
}
/**
* This is called on the physics thread for debug controls
*/
@Override
protected abstract void controlUpdate(float tpf);
protected void applyPhysicsTransform(Vector3f worldLocation, Quaternion worldRotation) {
applyPhysicsTransform(worldLocation, worldRotation, this.spatial);
}
protected void applyPhysicsTransform(Vector3f worldLocation, Quaternion worldRotation, Spatial spatial) {
if (spatial != null) {
Vector3f localLocation = spatial.getLocalTranslation();
Quaternion localRotationQuat = spatial.getLocalRotation();
if (spatial.getParent() != null) {
localLocation.set(worldLocation).subtractLocal(spatial.getParent().getWorldTranslation());
localLocation.divideLocal(spatial.getParent().getWorldScale());
tmp_inverseWorldRotation.set(spatial.getParent().getWorldRotation()).inverseLocal().multLocal(localLocation);
localRotationQuat.set(worldRotation);
tmp_inverseWorldRotation.set(spatial.getParent().getWorldRotation()).inverseLocal().mult(localRotationQuat, localRotationQuat);
spatial.setLocalTranslation(localLocation);
spatial.setLocalRotation(localRotationQuat);
} else {
spatial.setLocalTranslation(worldLocation);
spatial.setLocalRotation(worldRotation);
}
}
}
}

@ -0,0 +1,92 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.jme3.bullet.debug;
import com.jme3.bullet.objects.PhysicsCharacter;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.Geometry;
import com.jme3.scene.Mesh;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
/**
*
* @author normenhansen
*/
public class BulletCharacterDebugControl extends AbstractPhysicsDebugControl {
protected final PhysicsCharacter body;
protected final Geometry geom;
protected final Vector3f location = new Vector3f();
protected final Quaternion rotation = new Quaternion();
public BulletCharacterDebugControl(BulletDebugAppState debugAppState, PhysicsCharacter body) {
super(debugAppState);
this.body = body;
this.geom = new Geometry(body.toString());
geom.setMaterial(debugAppState.DEBUG_PINK);
}
@Override
public void setSpatial(Spatial spatial) {
if (spatial != null && spatial instanceof Node) {
Node node = (Node) spatial;
node.attachChild(geom);
} else if (spatial == null && this.spatial != null) {
Node node = (Node) this.spatial;
node.detachChild(geom);
}
super.setSpatial(spatial);
}
@Override
protected void controlUpdate(float tpf) {
Mesh mesh = debugAppState.getShapeBuffer().getShapeMesh(body.getCollisionShape());
if (mesh != null) {
if (geom.getMesh() != mesh) {
geom.setMesh(mesh);
}
} else {
if (geom.getMesh() != BulletDebugAppState.CollisionShapeBuffer.NO_MESH) {
geom.setMesh(BulletDebugAppState.CollisionShapeBuffer.NO_MESH);
}
}
applyPhysicsTransform(body.getPhysicsLocation(location), Quaternion.IDENTITY);
}
@Override
protected void controlRender(RenderManager rm, ViewPort vp) {
}
}

@ -0,0 +1,361 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.jme3.bullet.debug;
import com.jme3.app.Application;
import com.jme3.app.state.AbstractAppState;
import com.jme3.app.state.AppStateManager;
import com.jme3.asset.AssetManager;
import com.jme3.bullet.PhysicsSpace;
import com.jme3.bullet.collision.shapes.CollisionShape;
import com.jme3.bullet.joints.PhysicsJoint;
import com.jme3.bullet.objects.PhysicsCharacter;
import com.jme3.bullet.objects.PhysicsGhostObject;
import com.jme3.bullet.objects.PhysicsRigidBody;
import com.jme3.bullet.objects.PhysicsVehicle;
import com.jme3.bullet.util.DebugShapeFactory;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.Mesh;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.debug.Arrow;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* @author normenhansen
*/
public class BulletDebugAppState extends AbstractAppState {
protected static final Logger logger = Logger.getLogger(BulletDebugAppState.class.getName());
protected final PhysicsSpace space;
protected final CollisionShapeBuffer shapeBuffer = new CollisionShapeBuffer();
protected final ArrowBuffer arrowBuffer = new ArrowBuffer();
protected final Node physicsDebugRootNode = new Node("Physics Debug Root Node");
protected ViewPort viewPort;
protected RenderManager rm;
public Material DEBUG_BLUE;
public Material DEBUG_RED;
public Material DEBUG_GREEN;
public Material DEBUG_YELLOW;
public Material DEBUG_MAGENTA;
public Material DEBUG_PINK;
protected HashMap<PhysicsRigidBody, Spatial> bodies = new HashMap<PhysicsRigidBody, Spatial>();
protected HashMap<PhysicsJoint, Spatial> joints = new HashMap<PhysicsJoint, Spatial>();
protected HashMap<PhysicsGhostObject, Spatial> ghosts = new HashMap<PhysicsGhostObject, Spatial>();
protected HashMap<PhysicsCharacter, Spatial> characters = new HashMap<PhysicsCharacter, Spatial>();
protected HashMap<PhysicsVehicle, Spatial> vehicles = new HashMap<PhysicsVehicle, Spatial>();
public BulletDebugAppState(PhysicsSpace space) {
this.space = space;
}
@Override
public void initialize(AppStateManager stateManager, Application app) {
super.initialize(stateManager, app);
this.rm = app.getRenderManager();
setupMaterials(app);
physicsDebugRootNode.setCullHint(Spatial.CullHint.Never);
viewPort = rm.createMainView("Physics Debug Overlay", app.getCamera());
viewPort.setClearFlags(false, true, false);
viewPort.attachScene(physicsDebugRootNode);
}
@Override
public void cleanup() {
rm.removeMainView(viewPort);
super.cleanup();
}
@Override
public void update(float tpf) {
super.update(tpf);
//update all object links
updateRigidBodies();
updateGhosts();
updateCharacters();
updateJoints();
updateVehicles();
//update our debug root node
physicsDebugRootNode.updateLogicalState(tpf);
physicsDebugRootNode.updateGeometricState();
//reset shapes -> this removes all meshes for shapes that were not used this update cycle
shapeBuffer.resetShapes();
//reset arrows -> this makes arrow meshes available for the next update cycle
arrowBuffer.resetArrows();
}
@Override
public void render(RenderManager rm) {
super.render(rm);
if (viewPort != null) {
rm.renderScene(physicsDebugRootNode, viewPort);
}
}
private void setupMaterials(Application app) {
AssetManager manager = app.getAssetManager();
DEBUG_BLUE = new Material(manager, "Common/MatDefs/Misc/Unshaded.j3md");
DEBUG_BLUE.getAdditionalRenderState().setWireframe(true);
DEBUG_BLUE.setColor("Color", ColorRGBA.Blue);
DEBUG_GREEN = new Material(manager, "Common/MatDefs/Misc/Unshaded.j3md");
DEBUG_GREEN.getAdditionalRenderState().setWireframe(true);
DEBUG_GREEN.setColor("Color", ColorRGBA.Green);
DEBUG_RED = new Material(manager, "Common/MatDefs/Misc/Unshaded.j3md");
DEBUG_RED.getAdditionalRenderState().setWireframe(true);
DEBUG_RED.setColor("Color", ColorRGBA.Red);
DEBUG_YELLOW = new Material(manager, "Common/MatDefs/Misc/Unshaded.j3md");
DEBUG_YELLOW.getAdditionalRenderState().setWireframe(true);
DEBUG_YELLOW.setColor("Color", ColorRGBA.Yellow);
DEBUG_MAGENTA = new Material(manager, "Common/MatDefs/Misc/Unshaded.j3md");
DEBUG_MAGENTA.getAdditionalRenderState().setWireframe(true);
DEBUG_MAGENTA.setColor("Color", ColorRGBA.Magenta);
DEBUG_PINK = new Material(manager, "Common/MatDefs/Misc/Unshaded.j3md");
DEBUG_PINK.getAdditionalRenderState().setWireframe(true);
DEBUG_PINK.setColor("Color", ColorRGBA.Pink);
}
private void updateRigidBodies() {
HashMap<PhysicsRigidBody, Spatial> oldObjects = bodies;
bodies = new HashMap<PhysicsRigidBody, Spatial>();
Collection<PhysicsRigidBody> current = space.getRigidBodyList();
//create new map
for (Iterator<PhysicsRigidBody> it = current.iterator(); it.hasNext();) {
PhysicsRigidBody physicsObject = it.next();
//copy existing spatials
if (oldObjects.containsKey(physicsObject)) {
Spatial spat = oldObjects.get(physicsObject);
bodies.put(physicsObject, spat);
oldObjects.remove(physicsObject);
} else {
logger.log(Level.FINE, "Create new debug RigidBody");
//create new spatial
Node node = new Node(physicsObject.toString());
node.addControl(new BulletRigidBodyDebugControl(this, physicsObject));
bodies.put(physicsObject, node);
physicsDebugRootNode.attachChild(node);
}
}
//remove leftover spatials
for (Map.Entry<PhysicsRigidBody, Spatial> entry : oldObjects.entrySet()) {
PhysicsRigidBody object = entry.getKey();
Spatial spatial = entry.getValue();
spatial.removeFromParent();
}
}
private void updateJoints() {
HashMap<PhysicsJoint, Spatial> oldObjects = joints;
joints = new HashMap<PhysicsJoint, Spatial>();
Collection<PhysicsJoint> current = space.getJointList();
//create new map
for (Iterator<PhysicsJoint> it = current.iterator(); it.hasNext();) {
PhysicsJoint physicsObject = it.next();
//copy existing spatials
if (oldObjects.containsKey(physicsObject)) {
Spatial spat = oldObjects.get(physicsObject);
joints.put(physicsObject, spat);
oldObjects.remove(physicsObject);
} else {
logger.log(Level.FINE, "Create new debug Joint");
//create new spatial
Node node = new Node(physicsObject.toString());
node.addControl(new BulletJointDebugControl(this, physicsObject));
joints.put(physicsObject, node);
physicsDebugRootNode.attachChild(node);
}
}
//remove leftover spatials
for (Map.Entry<PhysicsJoint, Spatial> entry : oldObjects.entrySet()) {
PhysicsJoint object = entry.getKey();
Spatial spatial = entry.getValue();
spatial.removeFromParent();
}
}
private void updateGhosts() {
HashMap<PhysicsGhostObject, Spatial> oldObjects = ghosts;
ghosts = new HashMap<PhysicsGhostObject, Spatial>();
Collection<PhysicsGhostObject> current = space.getGhostObjectList();
//create new map
for (Iterator<PhysicsGhostObject> it = current.iterator(); it.hasNext();) {
PhysicsGhostObject physicsObject = it.next();
//copy existing spatials
if (oldObjects.containsKey(physicsObject)) {
Spatial spat = oldObjects.get(physicsObject);
ghosts.put(physicsObject, spat);
oldObjects.remove(physicsObject);
} else {
logger.log(Level.FINE, "Create new debug GhostObject");
//create new spatial
Node node = new Node(physicsObject.toString());
node.addControl(new BulletGhostObjectDebugControl(this, physicsObject));
ghosts.put(physicsObject, node);
physicsDebugRootNode.attachChild(node);
}
}
//remove leftover spatials
for (Map.Entry<PhysicsGhostObject, Spatial> entry : oldObjects.entrySet()) {
PhysicsGhostObject object = entry.getKey();
Spatial spatial = entry.getValue();
spatial.removeFromParent();
}
}
private void updateCharacters() {
HashMap<PhysicsCharacter, Spatial> oldObjects = characters;
characters = new HashMap<PhysicsCharacter, Spatial>();
Collection<PhysicsCharacter> current = space.getCharacterList();
//create new map
for (Iterator<PhysicsCharacter> it = current.iterator(); it.hasNext();) {
PhysicsCharacter physicsObject = it.next();
//copy existing spatials
if (oldObjects.containsKey(physicsObject)) {
Spatial spat = oldObjects.get(physicsObject);
characters.put(physicsObject, spat);
oldObjects.remove(physicsObject);
} else {
logger.log(Level.FINE, "Create new debug Character");
//create new spatial
Node node = new Node(physicsObject.toString());
node.addControl(new BulletCharacterDebugControl(this, physicsObject));
characters.put(physicsObject, node);
physicsDebugRootNode.attachChild(node);
}
}
//remove leftover spatials
for (Map.Entry<PhysicsCharacter, Spatial> entry : oldObjects.entrySet()) {
PhysicsCharacter object = entry.getKey();
Spatial spatial = entry.getValue();
spatial.removeFromParent();
}
}
private void updateVehicles() {
HashMap<PhysicsVehicle, Spatial> oldObjects = vehicles;
vehicles = new HashMap<PhysicsVehicle, Spatial>();
Collection<PhysicsVehicle> current = space.getVehicleList();
//create new map
for (Iterator<PhysicsVehicle> it = current.iterator(); it.hasNext();) {
PhysicsVehicle physicsObject = it.next();
//copy existing spatials
if (oldObjects.containsKey(physicsObject)) {
Spatial spat = oldObjects.get(physicsObject);
vehicles.put(physicsObject, spat);
oldObjects.remove(physicsObject);
} else {
logger.log(Level.FINE, "Create new debug Vehicle");
//create new spatial
Node node = new Node(physicsObject.toString());
node.addControl(new BulletVehicleDebugControl(this, physicsObject));
vehicles.put(physicsObject, node);
physicsDebugRootNode.attachChild(node);
}
}
//remove leftover spatials
for (Map.Entry<PhysicsVehicle, Spatial> entry : oldObjects.entrySet()) {
PhysicsVehicle object = entry.getKey();
Spatial spatial = entry.getValue();
spatial.removeFromParent();
}
}
public ArrowBuffer getArrowBuffer() {
return arrowBuffer;
}
public CollisionShapeBuffer getShapeBuffer() {
return shapeBuffer;
}
public static class CollisionShapeBuffer {
public static final Mesh NO_MESH = new Arrow(new Vector3f(0, 0, 0));
private HashMap<CollisionShape, Mesh> shapes = new HashMap<CollisionShape, Mesh>();
private HashMap<CollisionShape, Mesh> usedShapes = new HashMap<CollisionShape, Mesh>();
public void resetShapes() {
shapes = usedShapes;
usedShapes = new HashMap<CollisionShape, Mesh>();
}
public Mesh getShapeMesh(CollisionShape shape) {
if (shape == null) {
return null;
}
Mesh mesh = shapes.get(shape);
if (mesh == null) {
logger.log(Level.FINE, "Create new debug MESH");
mesh = DebugShapeFactory.getDebugMesh(shape);
shapes.put(shape, mesh);
}
usedShapes.put(shape, mesh);
return mesh;
}
}
public static class ArrowBuffer {
private final Queue<Arrow> arrows = new ConcurrentLinkedQueue<Arrow>();
private final Queue<Arrow> usedArrows = new ConcurrentLinkedQueue<Arrow>();
public void resetArrows() {
arrows.addAll(usedArrows);
}
public Arrow getArrow() {
return getArrow(Vector3f.UNIT_Y);
}
public Arrow getArrow(Vector3f extent) {
Arrow arrow = arrows.poll();
if (arrow == null) {
arrow = new Arrow(extent);
} else {
arrow.setArrowExtent(extent);
}
usedArrows.add(arrow);
return arrow;
}
}
}

@ -0,0 +1,91 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.jme3.bullet.debug;
import com.jme3.bullet.objects.PhysicsGhostObject;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.Geometry;
import com.jme3.scene.Mesh;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
/**
*
* @author normenhansen
*/
public class BulletGhostObjectDebugControl extends AbstractPhysicsDebugControl{
protected final PhysicsGhostObject body;
protected final Geometry geom;
protected final Vector3f location = new Vector3f();
protected final Quaternion rotation = new Quaternion();
public BulletGhostObjectDebugControl(BulletDebugAppState debugAppState, PhysicsGhostObject body) {
super(debugAppState);
this.body = body;
this.geom = new Geometry(body.toString());
geom.setMaterial(debugAppState.DEBUG_YELLOW);
}
@Override
public void setSpatial(Spatial spatial) {
if (spatial != null && spatial instanceof Node) {
Node node = (Node) spatial;
node.attachChild(geom);
} else if (spatial == null && this.spatial != null) {
Node node = (Node) this.spatial;
node.detachChild(geom);
}
super.setSpatial(spatial);
}
@Override
protected void controlUpdate(float tpf) {
Mesh mesh = debugAppState.getShapeBuffer().getShapeMesh(body.getCollisionShape());
if (mesh != null) {
if (geom.getMesh() != mesh) {
geom.setMesh(mesh);
}
} else {
if (geom.getMesh() != BulletDebugAppState.CollisionShapeBuffer.NO_MESH) {
geom.setMesh(BulletDebugAppState.CollisionShapeBuffer.NO_MESH);
}
}
applyPhysicsTransform(body.getPhysicsLocation(location), Quaternion.IDENTITY);
}
@Override
protected void controlRender(RenderManager rm, ViewPort vp) {
}
}

@ -0,0 +1,106 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.jme3.bullet.debug;
import com.jme3.bullet.joints.PhysicsJoint;
import com.jme3.math.Quaternion;
import com.jme3.math.Transform;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.debug.Arrow;
/**
*
* @author normenhansen
*/
public class BulletJointDebugControl extends AbstractPhysicsDebugControl {
protected final PhysicsJoint body;
protected final Geometry geomA;
protected final Arrow arrowA;
protected final Geometry geomB;
protected final Arrow arrowB;
protected final Transform a = new Transform(new Vector3f(), new Quaternion());
protected final Transform b = new Transform(new Vector3f(), new Quaternion());
protected final Vector3f offA = new Vector3f();
protected final Vector3f offB = new Vector3f();
public BulletJointDebugControl(BulletDebugAppState debugAppState, PhysicsJoint body) {
super(debugAppState);
this.body = body;
this.geomA = new Geometry(body.toString());
arrowA = new Arrow(Vector3f.ZERO);
geomA.setMesh(arrowA);
geomA.setMaterial(debugAppState.DEBUG_GREEN);
this.geomB = new Geometry(body.toString());
arrowB = new Arrow(Vector3f.ZERO);
geomB.setMesh(arrowB);
geomB.setMaterial(debugAppState.DEBUG_GREEN);
}
@Override
public void setSpatial(Spatial spatial) {
if (spatial != null && spatial instanceof Node) {
Node node = (Node) spatial;
node.attachChild(geomA);
node.attachChild(geomB);
} else if (spatial == null && this.spatial != null) {
Node node = (Node) this.spatial;
node.detachChild(geomA);
node.detachChild(geomB);
}
super.setSpatial(spatial);
}
@Override
protected void controlUpdate(float tpf) {
body.getBodyA().getPhysicsLocation(a.getTranslation());
body.getBodyA().getPhysicsRotation(a.getRotation());
body.getBodyB().getPhysicsLocation(b.getTranslation());
body.getBodyB().getPhysicsRotation(b.getRotation());
geomA.setLocalTransform(a);
geomB.setLocalTransform(b);
arrowA.setArrowExtent(body.getPivotA());
arrowB.setArrowExtent(body.getPivotB());
}
@Override
protected void controlRender(RenderManager rm, ViewPort vp) {
}
}

@ -0,0 +1,95 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.jme3.bullet.debug;
import com.jme3.bullet.debug.BulletDebugAppState.CollisionShapeBuffer;
import com.jme3.bullet.objects.PhysicsRigidBody;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.Geometry;
import com.jme3.scene.Mesh;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import java.util.logging.Logger;
/**
*
* @author normenhansen
*/
public class BulletRigidBodyDebugControl extends AbstractPhysicsDebugControl {
private static final Logger logger = Logger.getLogger(BulletRigidBodyDebugControl.class.getName());
protected final PhysicsRigidBody body;
protected final Geometry geom;
protected final Vector3f location = new Vector3f();
protected final Quaternion rotation = new Quaternion();
public BulletRigidBodyDebugControl(BulletDebugAppState debugAppState, PhysicsRigidBody body) {
super(debugAppState);
this.body = body;
this.geom = new Geometry(body.toString());
geom.setMaterial(debugAppState.DEBUG_BLUE);
}
@Override
public void setSpatial(Spatial spatial) {
if (spatial != null && spatial instanceof Node) {
Node node = (Node) spatial;
node.attachChild(geom);
} else if (spatial == null && this.spatial != null) {
Node node = (Node) this.spatial;
node.detachChild(geom);
}
super.setSpatial(spatial);
}
@Override
protected void controlUpdate(float tpf) {
Mesh mesh = debugAppState.getShapeBuffer().getShapeMesh(body.getCollisionShape());
if (mesh != null) {
if (geom.getMesh() != mesh) {
geom.setMesh(mesh);
}
} else {
if (geom.getMesh() != CollisionShapeBuffer.NO_MESH) {
geom.setMesh(CollisionShapeBuffer.NO_MESH);
}
}
applyPhysicsTransform(body.getPhysicsLocation(location), body.getPhysicsRotation(rotation));
}
@Override
protected void controlRender(RenderManager rm, ViewPort vp) {
}
}

@ -0,0 +1,142 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.jme3.bullet.debug;
import com.jme3.bullet.objects.PhysicsVehicle;
import com.jme3.bullet.objects.VehicleWheel;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.debug.Arrow;
/**
*
* @author normenhansen
*/
public class BulletVehicleDebugControl extends AbstractPhysicsDebugControl {
protected final PhysicsVehicle body;
protected final Node suspensionNode;
protected final Vector3f location = new Vector3f();
protected final Quaternion rotation = new Quaternion();
public BulletVehicleDebugControl(BulletDebugAppState debugAppState, PhysicsVehicle body) {
super(debugAppState);
this.body = body;
suspensionNode = new Node("Suspension");
createVehicle();
}
@Override
public void setSpatial(Spatial spatial) {
if (spatial != null && spatial instanceof Node) {
Node node = (Node) spatial;
node.attachChild(suspensionNode);
} else if (spatial == null && this.spatial != null) {
Node node = (Node) this.spatial;
node.detachChild(suspensionNode);
}
super.setSpatial(spatial);
}
private void createVehicle() {
suspensionNode.detachAllChildren();
for (int i = 0; i < body.getNumWheels(); i++) {
VehicleWheel physicsVehicleWheel = body.getWheel(i);
Vector3f location = physicsVehicleWheel.getLocation().clone();
Vector3f direction = physicsVehicleWheel.getDirection().clone();
Vector3f axle = physicsVehicleWheel.getAxle().clone();
float restLength = physicsVehicleWheel.getRestLength();
float radius = physicsVehicleWheel.getRadius();
Arrow locArrow = new Arrow(location);
Arrow axleArrow = new Arrow(axle.normalizeLocal().multLocal(0.3f));
Arrow wheelArrow = new Arrow(direction.normalizeLocal().multLocal(radius));
Arrow dirArrow = new Arrow(direction.normalizeLocal().multLocal(restLength));
Geometry locGeom = new Geometry("WheelLocationDebugShape" + i, locArrow);
Geometry dirGeom = new Geometry("WheelDirectionDebugShape" + i, dirArrow);
Geometry axleGeom = new Geometry("WheelAxleDebugShape" + i, axleArrow);
Geometry wheelGeom = new Geometry("WheelRadiusDebugShape" + i, wheelArrow);
dirGeom.setLocalTranslation(location);
axleGeom.setLocalTranslation(location.add(direction));
wheelGeom.setLocalTranslation(location.add(direction));
locGeom.setMaterial(debugAppState.DEBUG_GREEN);
dirGeom.setMaterial(debugAppState.DEBUG_GREEN);
axleGeom.setMaterial(debugAppState.DEBUG_GREEN);
wheelGeom.setMaterial(debugAppState.DEBUG_GREEN);
suspensionNode.attachChild(locGeom);
suspensionNode.attachChild(dirGeom);
suspensionNode.attachChild(axleGeom);
suspensionNode.attachChild(wheelGeom);
}
}
@Override
protected void controlUpdate(float tpf) {
for (int i = 0; i < body.getNumWheels(); i++) {
VehicleWheel physicsVehicleWheel = body.getWheel(i);
Vector3f location = physicsVehicleWheel.getLocation().clone();
Vector3f direction = physicsVehicleWheel.getDirection().clone();
Vector3f axle = physicsVehicleWheel.getAxle().clone();
float restLength = physicsVehicleWheel.getRestLength();
float radius = physicsVehicleWheel.getRadius();
Geometry locGeom = (Geometry) suspensionNode.getChild("WheelLocationDebugShape" + i);
Geometry dirGeom = (Geometry) suspensionNode.getChild("WheelDirectionDebugShape" + i);
Geometry axleGeom = (Geometry) suspensionNode.getChild("WheelAxleDebugShape" + i);
Geometry wheelGeom = (Geometry) suspensionNode.getChild("WheelRadiusDebugShape" + i);
Arrow locArrow = (Arrow) locGeom.getMesh();
locArrow.setArrowExtent(location);
Arrow axleArrow = (Arrow) axleGeom.getMesh();
axleArrow.setArrowExtent(axle.normalizeLocal().multLocal(0.3f));
Arrow wheelArrow = (Arrow) wheelGeom.getMesh();
wheelArrow.setArrowExtent(direction.normalizeLocal().multLocal(radius));
Arrow dirArrow = (Arrow) dirGeom.getMesh();
dirArrow.setArrowExtent(direction.normalizeLocal().multLocal(restLength));
dirGeom.setLocalTranslation(location);
axleGeom.setLocalTranslation(location.addLocal(direction));
wheelGeom.setLocalTranslation(location);
i++;
}
applyPhysicsTransform(body.getPhysicsLocation(location), body.getPhysicsRotation(rotation));
}
@Override
protected void controlRender(RenderManager rm, ViewPort vp) {
}
}

@ -920,7 +920,7 @@ public class PhysicsSpace {
/** /**
* Enable debug display for physics * Enable debug display for physics
* @param manager AssetManager to use to create debug materials * @param manager AssetManager to use to create debug materials
* @Deprecated in favor of BulletDebugAppState, use BulletAppState.enableDebug() to add automatically * @Deprecated in favor of BulletDebugAppState, use BulletAppState.setDebugEnabled(boolean) to add automatically
*/ */
@Deprecated @Deprecated
public void enableDebug(AssetManager manager) { public void enableDebug(AssetManager manager) {

@ -859,7 +859,7 @@ public class PhysicsSpace {
/** /**
* Enable debug display for physics * Enable debug display for physics
* @param manager AssetManager to use to create debug materials * @param manager AssetManager to use to create debug materials
* @Deprecated in favor of BulletDebugAppState, use BulletAppState.enableDebug() to add automatically * @Deprecated in favor of BulletDebugAppState, use BulletAppState.setDebugEnabled(boolean) to add automatically
*/ */
@Deprecated @Deprecated
public void enableDebug(AssetManager manager) { public void enableDebug(AssetManager manager) {

Loading…
Cancel
Save