Better armature joint selection

shader-nodes-enhancement
Nehon 7 years ago committed by Rémy Bouquet
parent a32c34939a
commit 02a1fd544a
  1. 28
      jme3-core/src/main/java/com/jme3/scene/debug/custom/ArmatureDebugAppState.java
  2. 5
      jme3-core/src/main/java/com/jme3/scene/debug/custom/ArmatureDebugger.java
  3. 39
      jme3-core/src/main/java/com/jme3/scene/debug/custom/ArmatureNode.java
  4. 4
      jme3-examples/src/main/java/jme3test/model/anim/TestAnimMigration.java

@ -23,11 +23,13 @@ import java.util.*;
*/ */
public class ArmatureDebugAppState extends BaseAppState { public class ArmatureDebugAppState extends BaseAppState {
public static final float CLICK_MAX_DELAY = 0.2f;
private Node debugNode = new Node("debugNode"); private Node debugNode = new Node("debugNode");
private Map<Armature, ArmatureDebugger> armatures = new HashMap<>(); private Map<Armature, ArmatureDebugger> armatures = new HashMap<>();
private Map<Armature, Joint> selectedBones = new HashMap<>(); private Map<Armature, Joint> selectedBones = new HashMap<>();
private Application app; private Application app;
private boolean displayAllJoints = false; private boolean displayAllJoints = false;
private float clickDelay = -1;
ViewPort vp; ViewPort vp;
@Override @Override
@ -66,8 +68,12 @@ public class ArmatureDebugAppState extends BaseAppState {
@Override @Override
public void update(float tpf) { public void update(float tpf) {
if (clickDelay > -1) {
clickDelay += tpf;
}
debugNode.updateLogicalState(tpf); debugNode.updateLogicalState(tpf);
debugNode.updateGeometricState(); debugNode.updateGeometricState();
} }
public ArmatureDebugger addArmatureFrom(SkinningControl skinningControl) { public ArmatureDebugger addArmatureFrom(SkinningControl skinningControl) {
@ -111,19 +117,31 @@ public class ArmatureDebugAppState extends BaseAppState {
private ActionListener actionListener = new ActionListener() { private ActionListener actionListener = new ActionListener() {
public void onAction(String name, boolean isPressed, float tpf) { public void onAction(String name, boolean isPressed, float tpf) {
if (name.equals("shoot") && isPressed) { if (name.equals("shoot") && isPressed) {
CollisionResults results = new CollisionResults(); clickDelay = 0;
}
if (name.equals("shoot") && !isPressed && clickDelay < CLICK_MAX_DELAY) {
Vector2f click2d = app.getInputManager().getCursorPosition(); Vector2f click2d = app.getInputManager().getCursorPosition();
Vector3f click3d = app.getCamera().getWorldCoordinates(new Vector2f(click2d.x, click2d.y), 0f).clone(); CollisionResults results = new CollisionResults();
Vector3f dir = app.getCamera().getWorldCoordinates(new Vector2f(click2d.x, click2d.y), 1f).subtractLocal(click3d); //first check 2d collision with joints
Ray ray = new Ray(click3d, dir); for (ArmatureDebugger ad : armatures.values()) {
ad.pick(click2d, results);
}
if (results.size() == 0) {
//no result, let's ray cast for bone geometries
Vector3f click3d = app.getCamera().getWorldCoordinates(new Vector2f(click2d.x, click2d.y), 0f).clone();
Vector3f dir = app.getCamera().getWorldCoordinates(new Vector2f(click2d.x, click2d.y), 1f).subtractLocal(click3d);
Ray ray = new Ray(click3d, dir);
debugNode.collideWith(ray, results);
}
debugNode.collideWith(ray, results);
if (results.size() == 0) { if (results.size() == 0) {
for (ArmatureDebugger ad : armatures.values()) { for (ArmatureDebugger ad : armatures.values()) {
ad.select(null); ad.select(null);
} }
return; return;
} }
// The closest result is the target that the player picked: // The closest result is the target that the player picked:
Geometry target = results.getClosestCollision().getGeometry(); Geometry target = results.getClosestCollision().getGeometry();
for (ArmatureDebugger ad : armatures.values()) { for (ArmatureDebugger ad : armatures.values()) {

@ -39,6 +39,7 @@ import com.jme3.collision.Collidable;
import com.jme3.collision.CollisionResults; import com.jme3.collision.CollisionResults;
import com.jme3.material.Material; import com.jme3.material.Material;
import com.jme3.material.RenderState; import com.jme3.material.RenderState;
import com.jme3.math.Vector2f;
import com.jme3.renderer.Camera; import com.jme3.renderer.Camera;
import com.jme3.renderer.queue.RenderQueue; import com.jme3.renderer.queue.RenderQueue;
import com.jme3.scene.Geometry; import com.jme3.scene.Geometry;
@ -152,6 +153,10 @@ public class ArmatureDebugger extends Node {
} }
public int pick(Vector2f cursor, CollisionResults results) {
return armatureNode.pick(cursor, results);
}
public Armature getArmature() { public Armature getArmature() {
return armature; return armature;
} }

@ -50,6 +50,7 @@ import java.util.*;
*/ */
public class ArmatureNode extends Node { public class ArmatureNode extends Node {
public static final float PIXEL_BOX = 10f;
/** /**
* The armature to be displayed. * The armature to be displayed.
*/ */
@ -60,8 +61,7 @@ public class ArmatureNode extends Node {
private Map<Joint, Geometry[]> jointToGeoms = new HashMap<>(); private Map<Joint, Geometry[]> jointToGeoms = new HashMap<>();
private Map<Geometry, Joint> geomToJoint = new HashMap<>(); private Map<Geometry, Joint> geomToJoint = new HashMap<>();
private Joint selectedJoint = null; private Joint selectedJoint = null;
private Vector3f tmpStart = new Vector3f(); private Vector3f tmp = new Vector3f();
private List<Vector3f> tmpEnds = new ArrayList<>();
private final static ColorRGBA selectedColor = ColorRGBA.Orange; private final static ColorRGBA selectedColor = ColorRGBA.Orange;
private final static ColorRGBA selectedColorJ = ColorRGBA.Yellow; private final static ColorRGBA selectedColorJ = ColorRGBA.Yellow;
private final static ColorRGBA outlineColor = ColorRGBA.LightGray; private final static ColorRGBA outlineColor = ColorRGBA.LightGray;
@ -109,7 +109,9 @@ public class ArmatureNode extends Node {
attach(joints, deforms, jGeom); attach(joints, deforms, jGeom);
Geometry bGeom = null; Geometry bGeom = null;
Geometry bGeomO = null; Geometry bGeomO = null;
if (ends != null) { if (ends == null) {
geomToJoint.put(jGeom, joint);
} else {
Mesh m = null; Mesh m = null;
Mesh mO = null; Mesh mO = null;
Node wireAttach = wires; Node wireAttach = wires;
@ -172,7 +174,10 @@ public class ArmatureNode extends Node {
selectedJoint = j; selectedJoint = j;
Geometry[] geomArray = jointToGeoms.get(selectedJoint); Geometry[] geomArray = jointToGeoms.get(selectedJoint);
setColor(geomArray[0], selectedColorJ); setColor(geomArray[0], selectedColorJ);
setColor(geomArray[1], selectedColor);
if (geomArray[1] != null) {
setColor(geomArray[1], selectedColor);
}
if (geomArray[2] != null) { if (geomArray[2] != null) {
setColor(geomArray[2], baseColor); setColor(geomArray[2], baseColor);
@ -188,7 +193,9 @@ public class ArmatureNode extends Node {
} }
Geometry[] geoms = jointToGeoms.get(selectedJoint); Geometry[] geoms = jointToGeoms.get(selectedJoint);
setColor(geoms[0], ColorRGBA.White); setColor(geoms[0], ColorRGBA.White);
setColor(geoms[1], geoms[2] == null ? outlineColor : baseColor); if (geoms[1] != null) {
setColor(geoms[1], geoms[2] == null ? outlineColor : baseColor);
}
if (geoms[2] != null) { if (geoms[2] != null) {
setColor(geoms[2], outlineColor); setColor(geoms[2], outlineColor);
} }
@ -211,7 +218,6 @@ public class ArmatureNode extends Node {
Vector3f[] ends = bGeom.getUserData("end"); Vector3f[] ends = bGeom.getUserData("end");
start.set(joint.getModelTransform().getTranslation()); start.set(joint.getModelTransform().getTranslation());
if (ends != null) { if (ends != null) {
tmpEnds.clear();
for (int i = 0; i < joint.getChildren().size(); i++) { for (int i = 0; i < joint.getChildren().size(); i++) {
ends[i].set(joint.getChildren().get(i).getModelTransform().getTranslation()); ends[i].set(joint.getChildren().get(i).getModelTransform().getTranslation());
} }
@ -235,6 +241,22 @@ public class ArmatureNode extends Node {
} }
} }
public int pick(Vector2f cursor, CollisionResults results) {
for (Geometry g : geomToJoint.keySet()) {
if (g.getMesh() instanceof JointShape) {
camera.getScreenCoordinates(g.getWorldTranslation(), tmp);
if (cursor.x <= tmp.x + PIXEL_BOX && cursor.x >= tmp.x - PIXEL_BOX
&& cursor.y <= tmp.y + PIXEL_BOX && cursor.y >= tmp.y - PIXEL_BOX) {
CollisionResult res = new CollisionResult();
res.setGeometry(g);
results.addCollision(res);
}
}
}
return 0;
}
@Override @Override
public int collideWith(Collidable other, CollisionResults results) { public int collideWith(Collidable other, CollisionResults results) {
if (!(other instanceof Ray)) { if (!(other instanceof Ray)) {
@ -242,11 +264,14 @@ public class ArmatureNode extends Node {
} }
int nbCol = 0; int nbCol = 0;
for (Geometry g : geomToJoint.keySet()) { for (Geometry g : geomToJoint.keySet()) {
if (g.getMesh() instanceof JointShape) {
continue;
}
Vector3f start = g.getUserData("start"); Vector3f start = g.getUserData("start");
Vector3f[] ends = g.getUserData("end"); Vector3f[] ends = g.getUserData("end");
for (int i = 0; i < ends.length; i++) { for (int i = 0; i < ends.length; i++) {
float len = MathUtils.raySegmentShortestDistance((Ray) other, start, ends[i], camera); float len = MathUtils.raySegmentShortestDistance((Ray) other, start, ends[i], camera);
if (len > 0 && len < 10f) { if (len > 0 && len < PIXEL_BOX) {
CollisionResult res = new CollisionResult(); CollisionResult res = new CollisionResult();
res.setGeometry(g); res.setGeometry(g);
results.addCollision(res); results.addCollision(res);

@ -41,8 +41,8 @@ public class TestAnimMigration extends SimpleApplication {
rootNode.addLight(new DirectionalLight(new Vector3f(-1, -1, -1).normalizeLocal())); rootNode.addLight(new DirectionalLight(new Vector3f(-1, -1, -1).normalizeLocal()));
rootNode.addLight(new AmbientLight(ColorRGBA.DarkGray)); rootNode.addLight(new AmbientLight(ColorRGBA.DarkGray));
// Spatial model = assetManager.loadModel("Models/Jaime/Jaime.j3o"); Spatial model = assetManager.loadModel("Models/Jaime/Jaime.j3o");
Spatial model = assetManager.loadModel("Models/Oto/Oto.mesh.xml").scale(0.2f).move(0, 1, 0); // Spatial model = assetManager.loadModel("Models/Oto/Oto.mesh.xml").scale(0.2f).move(0, 1, 0);
//Spatial model = assetManager.loadModel("Models/Sinbad/Sinbad.mesh.xml"); //Spatial model = assetManager.loadModel("Models/Sinbad/Sinbad.mesh.xml");
// Spatial model = assetManager.loadModel("Models/Elephant/Elephant.mesh.xml").scale(0.02f); // Spatial model = assetManager.loadModel("Models/Elephant/Elephant.mesh.xml").scale(0.02f);

Loading…
Cancel
Save