From 02a1fd544a1e9868413ac1978e8e995f5607227a Mon Sep 17 00:00:00 2001 From: Nehon Date: Tue, 26 Dec 2017 10:30:54 +0100 Subject: [PATCH] Better armature joint selection --- .../debug/custom/ArmatureDebugAppState.java | 28 ++++++++++--- .../scene/debug/custom/ArmatureDebugger.java | 5 +++ .../jme3/scene/debug/custom/ArmatureNode.java | 39 +++++++++++++++---- .../model/anim/TestAnimMigration.java | 4 +- 4 files changed, 62 insertions(+), 14 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/scene/debug/custom/ArmatureDebugAppState.java b/jme3-core/src/main/java/com/jme3/scene/debug/custom/ArmatureDebugAppState.java index edcb287e6..fb16135e6 100644 --- a/jme3-core/src/main/java/com/jme3/scene/debug/custom/ArmatureDebugAppState.java +++ b/jme3-core/src/main/java/com/jme3/scene/debug/custom/ArmatureDebugAppState.java @@ -23,11 +23,13 @@ import java.util.*; */ public class ArmatureDebugAppState extends BaseAppState { + public static final float CLICK_MAX_DELAY = 0.2f; private Node debugNode = new Node("debugNode"); private Map armatures = new HashMap<>(); private Map selectedBones = new HashMap<>(); private Application app; private boolean displayAllJoints = false; + private float clickDelay = -1; ViewPort vp; @Override @@ -66,8 +68,12 @@ public class ArmatureDebugAppState extends BaseAppState { @Override public void update(float tpf) { + if (clickDelay > -1) { + clickDelay += tpf; + } debugNode.updateLogicalState(tpf); debugNode.updateGeometricState(); + } public ArmatureDebugger addArmatureFrom(SkinningControl skinningControl) { @@ -111,19 +117,31 @@ public class ArmatureDebugAppState extends BaseAppState { private ActionListener actionListener = new ActionListener() { public void onAction(String name, boolean isPressed, float tpf) { 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(); - 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); + CollisionResults results = new CollisionResults(); + //first check 2d collision with joints + 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) { for (ArmatureDebugger ad : armatures.values()) { ad.select(null); } return; } + // The closest result is the target that the player picked: Geometry target = results.getClosestCollision().getGeometry(); for (ArmatureDebugger ad : armatures.values()) { diff --git a/jme3-core/src/main/java/com/jme3/scene/debug/custom/ArmatureDebugger.java b/jme3-core/src/main/java/com/jme3/scene/debug/custom/ArmatureDebugger.java index e76f45253..ac93bfaaf 100644 --- a/jme3-core/src/main/java/com/jme3/scene/debug/custom/ArmatureDebugger.java +++ b/jme3-core/src/main/java/com/jme3/scene/debug/custom/ArmatureDebugger.java @@ -39,6 +39,7 @@ import com.jme3.collision.Collidable; import com.jme3.collision.CollisionResults; import com.jme3.material.Material; import com.jme3.material.RenderState; +import com.jme3.math.Vector2f; import com.jme3.renderer.Camera; import com.jme3.renderer.queue.RenderQueue; 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() { return armature; } diff --git a/jme3-core/src/main/java/com/jme3/scene/debug/custom/ArmatureNode.java b/jme3-core/src/main/java/com/jme3/scene/debug/custom/ArmatureNode.java index 121366b1a..7f8b26c2d 100644 --- a/jme3-core/src/main/java/com/jme3/scene/debug/custom/ArmatureNode.java +++ b/jme3-core/src/main/java/com/jme3/scene/debug/custom/ArmatureNode.java @@ -50,6 +50,7 @@ import java.util.*; */ public class ArmatureNode extends Node { + public static final float PIXEL_BOX = 10f; /** * The armature to be displayed. */ @@ -60,8 +61,7 @@ public class ArmatureNode extends Node { private Map jointToGeoms = new HashMap<>(); private Map geomToJoint = new HashMap<>(); private Joint selectedJoint = null; - private Vector3f tmpStart = new Vector3f(); - private List tmpEnds = new ArrayList<>(); + private Vector3f tmp = new Vector3f(); private final static ColorRGBA selectedColor = ColorRGBA.Orange; private final static ColorRGBA selectedColorJ = ColorRGBA.Yellow; private final static ColorRGBA outlineColor = ColorRGBA.LightGray; @@ -109,7 +109,9 @@ public class ArmatureNode extends Node { attach(joints, deforms, jGeom); Geometry bGeom = null; Geometry bGeomO = null; - if (ends != null) { + if (ends == null) { + geomToJoint.put(jGeom, joint); + } else { Mesh m = null; Mesh mO = null; Node wireAttach = wires; @@ -172,7 +174,10 @@ public class ArmatureNode extends Node { selectedJoint = j; Geometry[] geomArray = jointToGeoms.get(selectedJoint); setColor(geomArray[0], selectedColorJ); - setColor(geomArray[1], selectedColor); + + if (geomArray[1] != null) { + setColor(geomArray[1], selectedColor); + } if (geomArray[2] != null) { setColor(geomArray[2], baseColor); @@ -188,7 +193,9 @@ public class ArmatureNode extends Node { } Geometry[] geoms = jointToGeoms.get(selectedJoint); 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) { setColor(geoms[2], outlineColor); } @@ -211,7 +218,6 @@ public class ArmatureNode extends Node { Vector3f[] ends = bGeom.getUserData("end"); start.set(joint.getModelTransform().getTranslation()); if (ends != null) { - tmpEnds.clear(); for (int i = 0; i < joint.getChildren().size(); i++) { 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 public int collideWith(Collidable other, CollisionResults results) { if (!(other instanceof Ray)) { @@ -242,11 +264,14 @@ public class ArmatureNode extends Node { } int nbCol = 0; for (Geometry g : geomToJoint.keySet()) { + if (g.getMesh() instanceof JointShape) { + continue; + } Vector3f start = g.getUserData("start"); Vector3f[] ends = g.getUserData("end"); for (int i = 0; i < ends.length; i++) { 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(); res.setGeometry(g); results.addCollision(res); diff --git a/jme3-examples/src/main/java/jme3test/model/anim/TestAnimMigration.java b/jme3-examples/src/main/java/jme3test/model/anim/TestAnimMigration.java index 5bff5fdd5..3b0e8e0a3 100644 --- a/jme3-examples/src/main/java/jme3test/model/anim/TestAnimMigration.java +++ b/jme3-examples/src/main/java/jme3test/model/anim/TestAnimMigration.java @@ -41,8 +41,8 @@ public class TestAnimMigration extends SimpleApplication { rootNode.addLight(new DirectionalLight(new Vector3f(-1, -1, -1).normalizeLocal())); rootNode.addLight(new AmbientLight(ColorRGBA.DarkGray)); -// 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/Jaime/Jaime.j3o"); + // 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/Elephant/Elephant.mesh.xml").scale(0.02f);