When you deal with complex game engine features like animations or physics it is handy to get feedback from the engine how it interpreted the current state. Is the physical object's collision shape really where you think it is? Is the skeleton of the animated character moveing like you think it should? This document shows you how to activate visual debug aides.
What if you just want to quickly write code that loads models and brings them in their start position? You may not want to hunt for a sample model, convert it, add lights, and load materials. Instead you use "hasslefree" simple shapes a wireframe material: No model, no light source, no materials are needed to see them in the scene.
If you ever have problems with objects appearing in the wrong spot, with the wrong scale, or wrong orientation, simply attach debug shapes to your scene to have a point of reference in 3D space – just like a giant ruler. If your code positions the debug shapes correctly, but models remain invisible when you apply the same code to them, you know that the problem must be the model or the light or its material – and not the positioning code.
Here are some different debug shapes:
The coordinate axes (com.jme3.scene.debug.Arrow) help you see the cardinal directions (X,Y,Z) from their center point. Scale the arrows to use them as a "ruler" for a certain length.
private void attachCoordinateAxes(Vector3f pos){ Arrow arrow = new Arrow(Vector3f.UNIT_X); arrow.setLineWidth(4); // make arrow thicker putShape(arrow, ColorRGBA.Red).setLocalTranslation(pos); arrow = new Arrow(Vector3f.UNIT_Y); arrow.setLineWidth(4); // make arrow thicker putShape(arrow, ColorRGBA.Green).setLocalTranslation(pos); arrow = new Arrow(Vector3f.UNIT_Z); arrow.setLineWidth(4); // make arrow thicker putShape(arrow, ColorRGBA.Blue).setLocalTranslation(pos); } private Geometry putShape(Mesh shape, ColorRGBA color){ Geometry g = new Geometry("coordinate axis", shape); Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); mat.getAdditionalRenderState().setWireframe(true); mat.setColor("Color", color); g.setMaterial(mat); rootNode.attachChild(g); return g; }
Use a wireframe grid (com.jme3.scene.debug.Grid) as a ruler or simple floor.
private void attachGrid(Vector3f pos, float size, ColorRGBA color){ Geometry g = new Geometry("wireframe grid", new Grid(size, size, 0.2f) ); Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); mat.getAdditionalRenderState().setWireframe(true); mat.setColor("Color", color); g.setMaterial(mat); g.center().move(pos); rootNode.attachChild(g); return g; }
Use a wireframe cube (com.jme3.scene.debug.WireBox) as a stand-in object to see whether your code scales, positions, or orients, loaded models right.
public void attachWireBox(Vector3f pos, float size, ColorRGBA color){ Geometry g = new Geometry("wireframe cube", new WireBox(size, size, size)); Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); mat.getAdditionalRenderState().setWireframe(true); mat.setColor("Color", color); g.setMaterial(mat); g.setLocalTranslation(pos); rootNode.attachChild(g); return g; }
Use a wireframe sphere (com.jme3.scene.debug.WireSphere) as a stand-in object to see whether your code scales, positions, or orients, loaded models right.
private void attachWireSphere(Vector3f pos, float size, ColorRGBA color){ Geometry g = new Geometry("wireframe sphere", new WireSphere(size)); Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); mat.getAdditionalRenderState().setWireframe(true); mat.setColor("Color", color); g.setMaterial(mat); g.setLocalTranslation(pos); rootNode.attachChild(g); return g; }
You can display a wireframe of the (usually invisible) collision shape around all physical objects. Use this for debugging when analyzing unexpected behaviour. Does not work with DETACHED physics, please switch to PARALLEL or SEQUENTIAL for debugging.
physicsSpace.enableDebug(assetManager);
Making the skeleton visible inside animated models can be handy for debugging animations. The control
object is an AnimControl, player
is the loaded model.
SkeletonDebugger skeletonDebug = new SkeletonDebugger("skeleton", control.getSkeleton()); Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); mat.setColor("Color", ColorRGBA.Green); mat.getAdditionalRenderState().setDepthTest(false); skeletonDebug.setMaterial(mat); player.attachChild(skeletonDebug);
We assume that you have loaded a model with a material mat
.
Then you can add a switch to toggle the model's wireframe on and off, like this:
inputManager.addMapping("toggle wireframe", new KeyTrigger(KeyInput.KEY_T)); inputManager.addListener(actionListener, "toggle wireframe");
private ActionListener() { @Override public void onAction(String name, boolean pressed, float tpf) { // toggle wireframe if (name.equals("toggle wireframe") && !pressed) { wireframe = !wireframe; // toggle boolean mat.getAdditionalRenderState().setWireframe(wireframe); } // else ... other input tests. } };