Skip to content

Commit d73bac2

Browse files
authored
Merge pull request #2493 from capdevon/capdevon-ArmatureDebugger
Feat: Improve ArmatureDebugger
2 parents b7a0402 + fafaed4 commit d73bac2

File tree

3 files changed

+377
-117
lines changed

3 files changed

+377
-117
lines changed
Lines changed: 136 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
package com.jme3.scene.debug.custom;
2-
31
/*
4-
* Copyright (c) 2009-2021 jMonkeyEngine
2+
* Copyright (c) 2009-2025 jMonkeyEngine
53
* All rights reserved.
64
*
75
* Redistribution and use in source and binary forms, with or without
@@ -31,9 +29,11 @@
3129
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
3230
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3331
*/
32+
package com.jme3.scene.debug.custom;
3433

3534
import com.jme3.anim.Armature;
3635
import com.jme3.anim.Joint;
36+
import com.jme3.anim.SkinningControl;
3737
import com.jme3.asset.AssetManager;
3838
import com.jme3.collision.Collidable;
3939
import com.jme3.collision.CollisionResults;
@@ -55,104 +55,176 @@
5555
public class ArmatureDebugger extends Node {
5656

5757
/**
58-
* The lines of the bones or the wires between their heads.
58+
* The node responsible for rendering the bones/wires and their outlines.
5959
*/
6060
private ArmatureNode armatureNode;
61-
61+
/**
62+
* The {@link Armature} instance being debugged.
63+
*/
6264
private Armature armature;
63-
65+
/**
66+
* A node containing all {@link Geometry} objects representing the joint points.
67+
*/
6468
private Node joints;
69+
/**
70+
* A node containing all {@link Geometry} objects representing the bone outlines.
71+
*/
6572
private Node outlines;
73+
/**
74+
* A node containing all {@link Geometry} objects representing the bone wires/lines.
75+
*/
6676
private Node wires;
6777
/**
6878
* The dotted lines between a bone's tail and the had of its children. Not
6979
* available if the length data was not provided.
7080
*/
7181
private ArmatureInterJointsWire interJointWires;
72-
82+
/**
83+
* Default constructor for `ArmatureDebugger`.
84+
* Use {@link #ArmatureDebugger(String, Armature, List)} for a functional instance.
85+
*/
7386
public ArmatureDebugger() {
7487
}
7588

7689
/**
77-
* Creates a debugger with no length data. The wires will be a connection
78-
* between the bones' heads only. The points will show the bones' heads only
79-
* and no dotted line of inter bones connection will be visible.
90+
* Convenience constructor that creates an {@code ArmatureDebugger} and immediately
91+
* initializes its materials based on the provided {@code AssetManager}
92+
* and {@code SkinningControl}.
93+
*
94+
* @param assetManager The {@link AssetManager} used to load textures and materials
95+
* for the debug visualization.
96+
* @param skControl The {@link SkinningControl} from which to extract the
97+
* {@link Armature} and its associated joints.
98+
*/
99+
public ArmatureDebugger(AssetManager assetManager, SkinningControl skControl) {
100+
this(null, skControl.getArmature(), skControl.getArmature().getJointList());
101+
initialize(assetManager, null);
102+
}
103+
104+
/**
105+
* Creates an `ArmatureDebugger` instance without explicit bone length data.
106+
* In this configuration, the visual representation will consist of wires
107+
* connecting the bone heads, and points representing the bone heads.
108+
* No dotted lines for inter-bone connections will be visible.
80109
*
81-
* @param name the name of the debugger's node
82-
* @param armature the armature that will be shown
83-
* @param deformingJoints a list of joints
110+
* @param name The name of this debugger's root node.
111+
* @param armature The {@link Armature} to be visualized.
112+
* @param deformingJoints A {@link List} of {@link Joint} objects that are
113+
* considered deforming joints.
84114
*/
85115
public ArmatureDebugger(String name, Armature armature, List<Joint> deformingJoints) {
86116
super(name);
87117
this.armature = armature;
118+
// Ensure the armature's world transforms are up-to-date before visualization.
88119
armature.update();
89120

121+
// Initialize the main container nodes for different visual elements.
90122
joints = new Node("joints");
91123
outlines = new Node("outlines");
92124
wires = new Node("bones");
93125
this.attachChild(joints);
94126
this.attachChild(outlines);
95127
this.attachChild(wires);
96-
Node ndJoints = new Node("non deforming Joints");
97-
Node ndOutlines = new Node("non deforming Joints outlines");
98-
Node ndWires = new Node("non deforming Joints wires");
99-
joints.attachChild(ndJoints);
100-
outlines.attachChild(ndOutlines);
101-
wires.attachChild(ndWires);
102-
Node outlineDashed = new Node("Outlines Dashed");
103-
Node wiresDashed = new Node("Wires Dashed");
104-
wiresDashed.attachChild(new Node("dashed non defrom"));
105-
outlineDashed.attachChild(new Node("dashed non defrom"));
128+
129+
// Create child nodes specifically for non-deforming joints' visualization
130+
joints.attachChild(new Node("NonDeformingJoints"));
131+
outlines.attachChild(new Node("NonDeformingOutlines"));
132+
wires.attachChild(new Node("NonDeformingWires"));
133+
134+
Node outlineDashed = new Node("DashedOutlines");
135+
outlineDashed.attachChild(new Node("DashedNonDeformingOutlines"));
106136
outlines.attachChild(outlineDashed);
137+
138+
Node wiresDashed = new Node("DashedWires");
139+
wiresDashed.attachChild(new Node("DashedNonDeformingWires"));
107140
wires.attachChild(wiresDashed);
108141

142+
// Initialize the core ArmatureNode which handles the actual mesh generation.
109143
armatureNode = new ArmatureNode(armature, joints, wires, outlines, deformingJoints);
110-
111144
this.attachChild(armatureNode);
112145

146+
// By default, non-deforming joints are hidden.
113147
displayNonDeformingJoint(false);
114148
}
115149

150+
/**
151+
* Sets the visibility of non-deforming joints and their associated outlines and wires.
152+
*
153+
* @param display `true` to make non-deforming joints visible, `false` to hide them.
154+
*/
116155
public void displayNonDeformingJoint(boolean display) {
117-
joints.getChild(0).setCullHint(display ? CullHint.Dynamic : CullHint.Always);
118-
outlines.getChild(0).setCullHint(display ? CullHint.Dynamic : CullHint.Always);
119-
wires.getChild(0).setCullHint(display ? CullHint.Dynamic : CullHint.Always);
120-
((Node) outlines.getChild(1)).getChild(0).setCullHint(display ? CullHint.Dynamic : CullHint.Always);
121-
((Node) wires.getChild(1)).getChild(0).setCullHint(display ? CullHint.Dynamic : CullHint.Always);
156+
CullHint cullHint = display ? CullHint.Dynamic : CullHint.Always;
157+
158+
joints.getChild(0).setCullHint(cullHint);
159+
outlines.getChild(0).setCullHint(cullHint);
160+
wires.getChild(0).setCullHint(cullHint);
161+
162+
((Node) outlines.getChild(1)).getChild(0).setCullHint(cullHint);
163+
((Node) wires.getChild(1)).getChild(0).setCullHint(cullHint);
122164
}
123165

166+
/**
167+
* Initializes the materials and camera for the debugger's visual components.
168+
* This method should be called after the `ArmatureDebugger` is added to a scene graph
169+
* and an {@link AssetManager} and {@link Camera} are available.
170+
*
171+
* @param assetManager The {@link AssetManager} to load textures and materials.
172+
* @param camera The scene's primary {@link Camera}, used by the `ArmatureNode`
173+
* for billboard rendering of joint points.
174+
*/
124175
public void initialize(AssetManager assetManager, Camera camera) {
125176

126177
armatureNode.setCamera(camera);
127178

128-
Material matJoints = new Material(assetManager, "Common/MatDefs/Misc/Billboard.j3md");
129-
Texture t = assetManager.loadTexture("Common/Textures/dot.png");
130-
matJoints.setTexture("Texture", t);
131-
matJoints.getAdditionalRenderState().setDepthTest(false);
132-
matJoints.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.Alpha);
179+
// Material for joint points (billboard dots).
180+
Material matJoints = getJointMaterial(assetManager);
133181
joints.setQueueBucket(RenderQueue.Bucket.Translucent);
134182
joints.setMaterial(matJoints);
135183

136-
Material matWires = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
137-
matWires.setBoolean("VertexColor", true);
138-
matWires.getAdditionalRenderState().setLineWidth(1f);
184+
// Material for bone wires/lines (unshaded, vertex colored).
185+
Material matWires = getUnshadedMaterial(assetManager);
139186
wires.setMaterial(matWires);
140187

141-
Material matOutline = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
142-
matOutline.setBoolean("VertexColor", true);
143-
matOutline.getAdditionalRenderState().setLineWidth(1f);
188+
// Material for dashed wires ("DashedLine.j3md" shader).
189+
Material matWires2 = getDashedMaterial(assetManager);
190+
wires.getChild(1).setMaterial(matWires2);
191+
192+
// Material for bone outlines (unshaded, vertex colored).
193+
Material matOutline = getUnshadedMaterial(assetManager);
144194
outlines.setMaterial(matOutline);
145195

146-
Material matOutline2 = new Material(assetManager, "Common/MatDefs/Misc/DashedLine.j3md");
147-
matOutline2.getAdditionalRenderState().setLineWidth(1);
196+
// Material for dashed outlines ("DashedLine.j3md" shader).
197+
Material matOutline2 = getDashedMaterial(assetManager);
148198
outlines.getChild(1).setMaterial(matOutline2);
199+
}
149200

150-
Material matWires2 = new Material(assetManager, "Common/MatDefs/Misc/DashedLine.j3md");
151-
matWires2.getAdditionalRenderState().setLineWidth(1);
152-
wires.getChild(1).setMaterial(matWires2);
201+
private Material getJointMaterial(AssetManager asm) {
202+
Material mat = new Material(asm, "Common/MatDefs/Misc/Billboard.j3md");
203+
Texture tex = asm.loadTexture("Common/Textures/dot.png");
204+
mat.setTexture("Texture", tex);
205+
mat.getAdditionalRenderState().setDepthTest(false);
206+
mat.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.Alpha);
207+
return mat;
208+
}
209+
210+
private Material getUnshadedMaterial(AssetManager asm) {
211+
Material mat = new Material(asm, "Common/MatDefs/Misc/Unshaded.j3md");
212+
mat.setBoolean("VertexColor", true);
213+
mat.getAdditionalRenderState().setDepthTest(false);
214+
return mat;
215+
}
153216

217+
private Material getDashedMaterial(AssetManager asm) {
218+
Material mat = new Material(asm, "Common/MatDefs/Misc/DashedLine.j3md");
219+
mat.getAdditionalRenderState().setDepthTest(false);
220+
return mat;
154221
}
155222

223+
/**
224+
* Returns the {@link Armature} instance associated with this debugger.
225+
*
226+
* @return The {@link Armature} being debugged.
227+
*/
156228
public Armature getArmature() {
157229
return armature;
158230
}
@@ -168,21 +240,35 @@ public int collideWith(Collidable other, CollisionResults results) {
168240
return armatureNode.collideWith(other, results);
169241
}
170242

171-
protected Joint select(Geometry g) {
172-
return armatureNode.select(g);
243+
/**
244+
* Selects and returns the {@link Joint} associated with a given {@link Geometry}.
245+
* This is an internal helper method, likely used for picking operations.
246+
*
247+
* @param geo The {@link Geometry} representing a part of a joint.
248+
* @return The {@link Joint} corresponding to the geometry, or `null` if not found.
249+
*/
250+
protected Joint select(Geometry geo) {
251+
return armatureNode.select(geo);
173252
}
174253

175254
/**
176-
* @return the armature wires
255+
* Returns the {@link ArmatureNode} which is responsible for generating and
256+
* managing the visual mesh of the bones and wires.
257+
*
258+
* @return The {@link ArmatureNode} instance.
177259
*/
178260
public ArmatureNode getBoneShapes() {
179261
return armatureNode;
180262
}
181263

182264
/**
183-
* @return the dotted line between bones (can be null)
265+
* Returns the {@link ArmatureInterJointsWire} instance, which represents the
266+
* dotted lines connecting a bone's tail to the head of its children.
267+
* This will be `null` if the debugger was created without bone length data.
268+
*
269+
* @return The {@link ArmatureInterJointsWire} instance, or `null` if not present.
184270
*/
185271
public ArmatureInterJointsWire getInterJointWires() {
186272
return interJointWires;
187273
}
188-
}
274+
}

jme3-core/src/main/java/com/jme3/scene/debug/custom/ArmatureInterJointsWire.java

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
package com.jme3.scene.debug.custom;
2-
31
/*
4-
* Copyright (c) 2009-2021 jMonkeyEngine
2+
* Copyright (c) 2009-2025 jMonkeyEngine
53
* All rights reserved.
64
*
75
* Redistribution and use in source and binary forms, with or without
@@ -31,7 +29,7 @@
3129
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
3230
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3331
*/
34-
32+
package com.jme3.scene.debug.custom;
3533

3634
import com.jme3.math.Vector3f;
3735
import com.jme3.scene.Mesh;
@@ -46,20 +44,38 @@
4644
* @author Marcin Roguski (Kaelthas)
4745
*/
4846
public class ArmatureInterJointsWire extends Mesh {
49-
private final Vector3f tmp = new Vector3f();
5047

48+
/**
49+
* A temporary {@link Vector3f} used for calculations to avoid object allocation.
50+
*/
51+
private final Vector3f tempVec = new Vector3f();
52+
53+
/**
54+
* For serialization only. Do not use.
55+
*/
56+
protected ArmatureInterJointsWire() {
57+
}
5158

59+
/**
60+
* Creates a new {@code ArmatureInterJointsWire} mesh.
61+
* The mesh will be set up to draw lines from the {@code start} vector to each of the {@code ends} vectors.
62+
*
63+
* @param start The starting point of the lines (e.g., the bone tail's position). Not null.
64+
* @param ends An array of ending points for the lines (e.g., the children's head positions). Not null.
65+
*/
5266
public ArmatureInterJointsWire(Vector3f start, Vector3f[] ends) {
5367
setMode(Mode.Lines);
5468
updateGeometry(start, ends);
5569
}
5670

5771
/**
58-
* For serialization only. Do not use.
72+
* Updates the geometry of this mesh based on the provided start and end points.
73+
* This method re-generates the position, texture coordinate, normal, and index buffers
74+
* for the mesh.
75+
*
76+
* @param start The new starting point for the lines. Not null.
77+
* @param ends An array of new ending points for the lines. Not null.
5978
*/
60-
protected ArmatureInterJointsWire() {
61-
}
62-
6379
protected void updateGeometry(Vector3f start, Vector3f[] ends) {
6480
float[] pos = new float[ends.length * 3 + 3];
6581
pos[0] = start.x;
@@ -78,7 +94,7 @@ protected void updateGeometry(Vector3f start, Vector3f[] ends) {
7894
texCoord[0] = 0;
7995
texCoord[1] = 0;
8096
for (int i = 0; i < ends.length * 2; i++) {
81-
texCoord[i + 2] = tmp.set(start).subtractLocal(ends[i / 2]).length();
97+
texCoord[i + 2] = tempVec.set(start).subtractLocal(ends[i / 2]).length();
8298
}
8399
setBuffer(Type.TexCoord, 2, texCoord);
84100

0 commit comments

Comments
 (0)