From c630ac2e59bb7381cdd4a5aec13de9d4a8cd13de Mon Sep 17 00:00:00 2001 From: Nehon Date: Sat, 23 Dec 2017 16:12:37 +0100 Subject: [PATCH] better Armature debugger --- .../jme3/anim/util/AnimMigrationUtils.java | 24 ++ .../main/java/com/jme3/math/MathUtils.java | 63 +++++ .../jme3/scene/debug/custom/ArmatureBone.java | 199 -------------- .../debug/custom/ArmatureDebugAppState.java | 91 ++++--- .../scene/debug/custom/ArmatureDebugger.java | 151 ++++------- .../jme3/scene/debug/custom/ArmatureNode.java | 245 ++++++++++++++++++ .../jme3/scene/debug/custom/BoneShape.java | 171 ------------ .../jme3/scene/debug/custom/JointShape.java | 79 ++++++ .../Common/MatDefs/Misc/Billboard.j3md | 78 ++++++ .../MatDefs/ShaderNodes/Common/Billboard.j3sn | 35 +++ .../ShaderNodes/Common/Billboard100.frag | 19 ++ .../ShaderNodes/Common/FixedScale.j3sn | 41 +++ .../ShaderNodes/Common/FixedScale100.frag | 8 + .../MatDefs/ShaderNodes/Common/texCoord.j3sn | 57 ++++ .../ShaderNodes/Common/texCoord100.frag | 2 + .../main/resources/Common/Textures/dot.png | Bin 0 -> 367 bytes .../jme3test/model/anim/TestArmature.java | 15 +- 17 files changed, 753 insertions(+), 525 deletions(-) create mode 100644 jme3-core/src/main/java/com/jme3/anim/util/AnimMigrationUtils.java delete mode 100644 jme3-core/src/main/java/com/jme3/scene/debug/custom/ArmatureBone.java create mode 100644 jme3-core/src/main/java/com/jme3/scene/debug/custom/ArmatureNode.java delete mode 100644 jme3-core/src/main/java/com/jme3/scene/debug/custom/BoneShape.java create mode 100644 jme3-core/src/main/java/com/jme3/scene/debug/custom/JointShape.java create mode 100644 jme3-core/src/main/resources/Common/MatDefs/Misc/Billboard.j3md create mode 100644 jme3-core/src/main/resources/Common/MatDefs/ShaderNodes/Common/Billboard.j3sn create mode 100644 jme3-core/src/main/resources/Common/MatDefs/ShaderNodes/Common/Billboard100.frag create mode 100644 jme3-core/src/main/resources/Common/MatDefs/ShaderNodes/Common/FixedScale.j3sn create mode 100644 jme3-core/src/main/resources/Common/MatDefs/ShaderNodes/Common/FixedScale100.frag create mode 100644 jme3-core/src/main/resources/Common/MatDefs/ShaderNodes/Common/texCoord.j3sn create mode 100644 jme3-core/src/main/resources/Common/MatDefs/ShaderNodes/Common/texCoord100.frag create mode 100644 jme3-core/src/main/resources/Common/Textures/dot.png diff --git a/jme3-core/src/main/java/com/jme3/anim/util/AnimMigrationUtils.java b/jme3-core/src/main/java/com/jme3/anim/util/AnimMigrationUtils.java new file mode 100644 index 000000000..f11a0c43c --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/anim/util/AnimMigrationUtils.java @@ -0,0 +1,24 @@ +package com.jme3.anim.util; + +import com.jme3.animation.AnimControl; +import com.jme3.scene.SceneGraphVisitor; +import com.jme3.scene.Spatial; + +public class AnimMigrationUtils { + + public static Spatial migrate(Spatial source) { + //source.depthFirstTraversal(); + return source; + } + + private class AnimControlVisitor implements SceneGraphVisitor { + + @Override + public void visit(Spatial spatial) { + AnimControl control = spatial.getControl(AnimControl.class); + if (control != null) { + + } + } + } +} diff --git a/jme3-core/src/main/java/com/jme3/math/MathUtils.java b/jme3-core/src/main/java/com/jme3/math/MathUtils.java index a27c266ce..234d5f61b 100644 --- a/jme3-core/src/main/java/com/jme3/math/MathUtils.java +++ b/jme3-core/src/main/java/com/jme3/math/MathUtils.java @@ -1,5 +1,7 @@ package com.jme3.math; +import com.jme3.util.TempVars; + /** * Created by Nehon on 23/04/2017. */ @@ -162,4 +164,65 @@ public class MathUtils { } + public static float raySegmentShortestDistance(Ray ray, Vector3f segStart, Vector3f segEnd) { + // Algorithm is ported from the C algorithm of + // Paul Bourke at http://local.wasp.uwa.edu.au/~pbourke/geometry/lineline3d/ + TempVars vars = TempVars.get(); + Vector3f resultSegmentPoint1 = vars.vect1; + Vector3f resultSegmentPoint2 = vars.vect2; + + Vector3f p1 = segStart; + Vector3f p2 = segEnd; + Vector3f p3 = ray.origin; + Vector3f p4 = vars.vect3.set(ray.getDirection()).multLocal(Math.min(ray.getLimit(), 1000)).addLocal(ray.getOrigin()); + Vector3f p13 = vars.vect4.set(p1).subtractLocal(p3); + Vector3f p43 = vars.vect5.set(p4).subtractLocal(p3); + + if (p43.lengthSquared() < 0.0001) { + vars.release(); + return -1; + } + Vector3f p21 = vars.vect6.set(p2).subtractLocal(p1); + if (p21.lengthSquared() < 0.0001) { + vars.release(); + return -1; + } + + double d1343 = p13.x * (double) p43.x + (double) p13.y * p43.y + (double) p13.z * p43.z; + double d4321 = p43.x * (double) p21.x + (double) p43.y * p21.y + (double) p43.z * p21.z; + double d1321 = p13.x * (double) p21.x + (double) p13.y * p21.y + (double) p13.z * p21.z; + double d4343 = p43.x * (double) p43.x + (double) p43.y * p43.y + (double) p43.z * p43.z; + double d2121 = p21.x * (double) p21.x + (double) p21.y * p21.y + (double) p21.z * p21.z; + + double denom = d2121 * d4343 - d4321 * d4321; + if (Math.abs(denom) < 0.0001) { + vars.release(); + return -1; + } + double numer = d1343 * d4321 - d1321 * d4343; + + double mua = numer / denom; + double mub = (d1343 + d4321 * (mua)) / d4343; + + resultSegmentPoint1.x = (float) (p1.x + mua * p21.x); + resultSegmentPoint1.y = (float) (p1.y + mua * p21.y); + resultSegmentPoint1.z = (float) (p1.z + mua * p21.z); + resultSegmentPoint2.x = (float) (p3.x + mub * p43.x); + resultSegmentPoint2.y = (float) (p3.y + mub * p43.y); + resultSegmentPoint2.z = (float) (p3.z + mub * p43.z); + + //check if result 1 is in the segment section. + float startToPoint = vars.vect3.set(resultSegmentPoint1).subtractLocal(segStart).lengthSquared(); + float endToPoint = vars.vect3.set(resultSegmentPoint1).subtractLocal(segEnd).lengthSquared(); + float segLength = vars.vect3.set(segEnd).subtractLocal(segStart).lengthSquared(); + if (startToPoint > segLength || endToPoint > segLength) { + vars.release(); + return -1; + } + + float length = resultSegmentPoint1.subtractLocal(resultSegmentPoint2).length(); + vars.release(); + return length; + } + } diff --git a/jme3-core/src/main/java/com/jme3/scene/debug/custom/ArmatureBone.java b/jme3-core/src/main/java/com/jme3/scene/debug/custom/ArmatureBone.java deleted file mode 100644 index 3e3149f59..000000000 --- a/jme3-core/src/main/java/com/jme3/scene/debug/custom/ArmatureBone.java +++ /dev/null @@ -1,199 +0,0 @@ -package com.jme3.scene.debug.custom; - -/* - * 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. - */ - -import com.jme3.anim.Armature; -import com.jme3.anim.Joint; -import com.jme3.bounding.*; -import com.jme3.math.Quaternion; -import com.jme3.math.Vector3f; -import com.jme3.scene.*; -import com.jme3.scene.shape.Sphere; - -import java.nio.FloatBuffer; -import java.util.HashMap; -import java.util.Map; - -import static com.jme3.util.BufferUtils.createFloatBuffer; - -/** - * The class that displays either wires between the bones' heads if no length - * data is supplied and full bones' shapes otherwise. - */ -public class ArmatureBone extends Node { - - /** - * The armature to be displayed. - */ - private Armature armature; - /** - * The map between the bone index and its length. - */ - private Map jointNode = new HashMap<>(); - private Map nodeJoint = new HashMap<>(); - private Node selectedNode = null; - private boolean guessJointsOrientation = false; - - /** - * Creates a wire with bone lengths data. If the data is supplied then the - * wires will show each full bone (from head to tail). - * - * @param armature the armature that will be shown - * @param boneLengths a map between the bone's index and the bone's length - */ - public ArmatureBone(Armature armature, Map boneLengths, boolean guessJointsOrientation) { - this.armature = armature; - this.guessJointsOrientation = guessJointsOrientation; - - BoneShape boneShape = new BoneShape(); - Sphere jointShape = new Sphere(16, 16, 0.05f); - jointShape.setBuffer(VertexBuffer.Type.Color, 4, createFloatBuffer(jointShape.getVertexCount() * 4)); - FloatBuffer cb = jointShape.getFloatBuffer(VertexBuffer.Type.Color); - - cb.rewind(); - for (int i = 0; i < jointShape.getVertexCount(); i++) { - cb.put(0.05f).put(0.05f).put(0.05f).put(1f); - } - - for (Joint joint : armature.getRoots()) { - createSkeletonGeoms(joint, boneShape, jointShape, boneLengths, armature, this, guessJointsOrientation); - } - this.updateModelBound(); - - - Sphere originShape = new Sphere(16, 16, 0.02f); - originShape.setBuffer(VertexBuffer.Type.Color, 4, createFloatBuffer(originShape.getVertexCount() * 4)); - cb = originShape.getFloatBuffer(VertexBuffer.Type.Color); - cb.rewind(); - for (int i = 0; i < jointShape.getVertexCount(); i++) { - cb.put(0.4f).put(0.4f).put(0.05f).put(1f); - } - - Geometry origin = new Geometry("origin", originShape); - BoundingVolume bv = this.getWorldBound(); - float scale = 1; - if (bv.getType() == BoundingVolume.Type.AABB) { - BoundingBox bb = (BoundingBox) bv; - scale = (bb.getXExtent() + bb.getYExtent() + bb.getZExtent()) / 3f; - } else if (bv.getType() == BoundingVolume.Type.Sphere) { - BoundingSphere bs = (BoundingSphere) bv; - scale = bs.getRadius(); - } - origin.scale(scale); - attachChild(origin); - } - - protected final void createSkeletonGeoms(Joint joint, Mesh boneShape, Mesh jointShape, Map boneLengths, Armature armature, Node parent, boolean guessBonesOrientation) { - - Node n = new Node(joint.getName() + "Node"); - Geometry bGeom = new Geometry(joint.getName() + "Bone", boneShape); - Geometry jGeom = new Geometry(joint.getName() + "Joint", jointShape); - n.setLocalTransform(joint.getLocalTransform()); - - float boneLength = boneLengths.get(armature.getJointIndex(joint)); - - if (guessBonesOrientation) { - //One child only, the bone direction is from the parent joint to the child joint. - if (joint.getChildren().size() == 1) { - Vector3f v = joint.getChildren().get(0).getLocalTranslation(); - Quaternion q = new Quaternion(); - q.lookAt(v, Vector3f.UNIT_Z); - bGeom.setLocalRotation(q); - } - //no child, the bone has the same direction as the parent bone. - if (joint.getChildren().isEmpty()) { - //no parent, let's use the bind orientation of the bone - Spatial s = parent.getChild(0); - if (s != null) { - bGeom.setLocalRotation(s.getLocalRotation()); - } - } - } - - float boneScale = boneLength * 0.8f; - float scale = boneScale / 8f; - bGeom.setLocalScale(new Vector3f(scale, scale, boneScale)); - Vector3f offset = new Vector3f(0, 0, boneLength * 0.1f); - bGeom.getLocalRotation().multLocal(offset); - bGeom.setLocalTranslation(offset); - jGeom.setLocalScale(boneLength); - - if (joint.getChildren().size() <= 1) { - n.attachChild(bGeom); - } - n.attachChild(jGeom); - - jointNode.put(joint, n); - nodeJoint.put(n, joint); - parent.attachChild(n); - for (Joint child : joint.getChildren()) { - createSkeletonGeoms(child, boneShape, jointShape, boneLengths, armature, n, guessBonesOrientation); - } - } - - protected Joint select(Geometry g) { - Node parentNode = g.getParent(); - - if (parent != null) { - Joint j = nodeJoint.get(parentNode); - if (j != null) { - selectedNode = parentNode; - } - return j; - } - return null; - } - - protected Node getSelectedNode() { - return selectedNode; - } - - - protected final void updateSkeletonGeoms(Joint joint) { - Node n = jointNode.get(joint); - n.setLocalTransform(joint.getLocalTransform()); - - for (Joint child : joint.getChildren()) { - updateSkeletonGeoms(child); - } - } - - /** - * The method updates the geometry according to the positions of the bones. - */ - public void updateGeometry() { - for (Joint joint : armature.getRoots()) { - updateSkeletonGeoms(joint); - } - } -} 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 06661eff7..439316a95 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 @@ -8,12 +8,12 @@ import com.jme3.anim.*; import com.jme3.app.Application; import com.jme3.app.state.AbstractAppState; import com.jme3.app.state.AppStateManager; +import com.jme3.collision.CollisionResults; import com.jme3.input.MouseInput; import com.jme3.input.controls.ActionListener; import com.jme3.input.controls.MouseButtonTrigger; import com.jme3.light.DirectionalLight; -import com.jme3.math.ColorRGBA; -import com.jme3.math.Vector3f; +import com.jme3.math.*; import com.jme3.renderer.ViewPort; import com.jme3.scene.*; @@ -28,7 +28,6 @@ public class ArmatureDebugAppState extends AbstractAppState { private Map armatures = new HashMap<>(); private Map selectedBones = new HashMap<>(); private Application app; - @Override public void initialize(AppStateManager stateManager, Application app) { ViewPort vp = app.getRenderManager().createMainView("debug", app.getCamera()); @@ -46,7 +45,6 @@ public class ArmatureDebugAppState extends AbstractAppState { debugNode.addLight(new DirectionalLight(new Vector3f(-1f, -1f, -1f).normalizeLocal())); debugNode.addLight(new DirectionalLight(new Vector3f(1f, 1f, 1f).normalizeLocal(), new ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f))); - } @Override @@ -55,15 +53,15 @@ public class ArmatureDebugAppState extends AbstractAppState { debugNode.updateGeometricState(); } - public ArmatureDebugger addArmature(SkinningControl skinningControl, boolean guessJointsOrientation) { + public ArmatureDebugger addArmature(SkinningControl skinningControl) { Armature armature = skinningControl.getArmature(); Spatial forSpatial = skinningControl.getSpatial(); - return addArmature(armature, forSpatial, guessJointsOrientation); + return addArmature(armature, forSpatial); } - public ArmatureDebugger addArmature(Armature armature, Spatial forSpatial, boolean guessJointsOrientation) { + public ArmatureDebugger addArmature(Armature armature, Spatial forSpatial) { - ArmatureDebugger ad = new ArmatureDebugger(forSpatial.getName() + "_Armature", armature, guessJointsOrientation); + ArmatureDebugger ad = new ArmatureDebugger(forSpatial.getName() + "_Armature", armature); ad.setLocalTransform(forSpatial.getWorldTransform()); if (forSpatial instanceof Node) { List geoms = new ArrayList<>(); @@ -98,45 +96,44 @@ public class ArmatureDebugAppState extends AbstractAppState { */ private ActionListener actionListener = new ActionListener() { public void onAction(String name, boolean isPressed, float tpf) { - //if (name.equals("shoot") && isPressed) { -// CollisionResults results = new CollisionResults(); -// 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); -// -// debugNode.collideWith(ray, results); -// -// if (results.size() > 0) { -// // The closest result is the target that the player picked: -// Geometry target = results.getClosestCollision().getGeometry(); -// for (ArmatureDebugger skeleton : armatures.values()) { -// Joint selectedBone = skeleton.select(target); -// if (selectedBone != null) { -// selectedBones.put(skeleton.getArmature(), selectedBone); -// System.err.println("-----------------------"); -// System.err.println("Selected Bone : " + selectedBone.getName() + " in skeleton " + skeleton.getName()); -// System.err.println("Root Bone : " + (selectedBone.getParent() == null)); -// System.err.println("-----------------------"); -// System.err.println("Bind translation: " + selectedBone.getBindPosition()); -// System.err.println("Bind rotation: " + selectedBone.getBindRotation()); -// System.err.println("Bind scale: " + selectedBone.getBindScale()); -// System.err.println("---"); -// System.err.println("Local translation: " + selectedBone.getLocalPosition()); -// System.err.println("Local rotation: " + selectedBone.getLocalRotation()); -// System.err.println("Local scale: " + selectedBone.getLocalScale()); -// System.err.println("---"); -// System.err.println("Model translation: " + selectedBone.getModelSpacePosition()); -// System.err.println("Model rotation: " + selectedBone.getModelSpaceRotation()); -// System.err.println("Model scale: " + selectedBone.getModelSpaceScale()); -// System.err.println("---"); -// System.err.println("Bind inverse Transform: "); -// System.err.println(selectedBone.getBindInverseTransform()); -// return; -// } -// } -// } -// } + if (name.equals("shoot") && isPressed) { + CollisionResults results = new CollisionResults(); + 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); + + 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()) { + Joint selectedjoint = ad.select(target); + if (selectedjoint != null) { + selectedBones.put(ad.getArmature(), selectedjoint); + System.err.println("-----------------------"); + System.err.println("Selected Joint : " + selectedjoint.getName() + " in armature " + ad.getName()); + System.err.println("Root Bone : " + (selectedjoint.getParent() == null)); + System.err.println("-----------------------"); + System.err.println("Local translation: " + selectedjoint.getLocalTranslation()); + System.err.println("Local rotation: " + selectedjoint.getLocalRotation()); + System.err.println("Local scale: " + selectedjoint.getLocalScale()); + System.err.println("---"); + System.err.println("Model translation: " + selectedjoint.getModelTransform().getTranslation()); + System.err.println("Model rotation: " + selectedjoint.getModelTransform().getRotation()); + System.err.println("Model scale: " + selectedjoint.getModelTransform().getScale()); + System.err.println("---"); + System.err.println("Bind inverse Transform: "); + System.err.println(selectedjoint.getInverseModelBindMatrix()); + return; + } + } + } } }; 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 8d068c185..43a4e41d7 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 @@ -37,31 +37,39 @@ import com.jme3.anim.Joint; import com.jme3.animation.Bone; import com.jme3.asset.AssetManager; import com.jme3.material.Material; -import com.jme3.math.ColorRGBA; -import com.jme3.scene.*; +import com.jme3.material.RenderState; +import com.jme3.renderer.queue.RenderQueue; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.texture.Texture; -import java.nio.FloatBuffer; -import java.util.*; +import java.util.ArrayList; +import java.util.List; /** * The class that creates a mesh to display how bones behave. If it is supplied * with the bones' lengths it will show exactly how the bones look like on the * scene. If not then only connections between each bone heads will be shown. */ -public class ArmatureDebugger extends BatchNode { +public class ArmatureDebugger extends Node { /** * The lines of the bones or the wires between their heads. */ - private ArmatureBone bones; + private ArmatureNode armatureNode; private Armature armature; + + Node joints; + Node outlines; + Node wires; + /** * The dotted lines between a bone's tail and the had of its children. Not * available if the length data was not provided. */ private ArmatureInterJointsWire interJointWires; - private Geometry wires; + //private Geometry wires; private List selectedJoints = new ArrayList(); public ArmatureDebugger() { @@ -75,110 +83,74 @@ public class ArmatureDebugger extends BatchNode { * @param name the name of the debugger's node * @param armature the armature that will be shown */ - public ArmatureDebugger(String name, Armature armature, boolean guessJointsOrientation) { + public ArmatureDebugger(String name, Armature armature) { super(name); this.armature = armature; -// armature.reset(); armature.update(); - //Joints have no length we want to display the as bones so we compute their length - Map bonesLength = new HashMap(); - for (Joint joint : armature.getRoots()) { - computeLength(joint, bonesLength, armature); - } - bones = new ArmatureBone(armature, bonesLength, guessJointsOrientation); + joints = new Node("joints"); + outlines = new Node("outlines"); + wires = new Node("bones"); + this.attachChild(joints); + this.attachChild(outlines); + this.attachChild(wires); - this.attachChild(bones); + armatureNode = new ArmatureNode(armature, joints, wires, outlines); - interJointWires = new ArmatureInterJointsWire(armature, bonesLength, guessJointsOrientation); - wires = new Geometry(name + "_interwires", interJointWires); + this.attachChild(armatureNode); + + //interJointWires = new ArmatureInterJointsWire(armature, bonesLength, guessJointsOrientation); + //wires = new Geometry(name + "_interwires", interJointWires); // this.attachChild(wires); } protected void initialize(AssetManager assetManager) { - Material mat = new Material(assetManager, "Common/MatDefs/Misc/fakeLighting.j3md"); - mat.setColor("Color", new ColorRGBA(0.2f, 0.2f, 0.2f, 1)); - setMaterial(mat); - Material matWires = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); - matWires.setColor("Color", ColorRGBA.Black); + matWires.setBoolean("VertexColor", true); + matWires.getAdditionalRenderState().setLineWidth(3); wires.setMaterial(matWires); - //wires.setQueueBucket(RenderQueue.Bucket.Transparent); -// Material mat2 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); -// mat2.setBoolean("VertexColor", true); -// bones.setMaterial(mat2); -// batch(); - } - @Override - public final void setMaterial(Material material) { - if (batches.isEmpty()) { - for (int i = 0; i < children.size(); i++) { - children.get(i).setMaterial(material); - } - } else { - super.setMaterial(material); - } + Material matOutline = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + matOutline.setBoolean("VertexColor", true); + //matOutline.setColor("Color", ColorRGBA.White); + matOutline.getAdditionalRenderState().setLineWidth(5); + outlines.setMaterial(matOutline); + + Material matJoints = new Material(assetManager, "Common/MatDefs/Misc/Billboard.j3md"); + Texture t = assetManager.loadTexture("Common/Textures/dot.png"); +// matJoints.setBoolean("VertexColor", true); +// matJoints.setTexture("ColorMap", t); + matJoints.setTexture("Texture", t); + matJoints.getAdditionalRenderState().setDepthTest(false); + matJoints.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.Alpha); + joints.setQueueBucket(RenderQueue.Bucket.Translucent); + joints.setMaterial(matJoints); + } public Armature getArmature() { return armature; } - - private void computeLength(Joint joint, Map jointsLength, Armature armature) { - if (joint.getChildren().isEmpty()) { - if (joint.getParent() != null) { - jointsLength.put(armature.getJointIndex(joint), jointsLength.get(armature.getJointIndex(joint.getParent())) * 0.75f); - } else { - jointsLength.put(armature.getJointIndex(joint), 0.1f); - } - } else { - float length = Float.MAX_VALUE; - for (Joint child : joint.getChildren()) { - float len = joint.getModelTransform().getTranslation().subtract(child.getModelTransform().getTranslation()).length(); - if (len < length) { - length = len; - } - } - jointsLength.put(armature.getJointIndex(joint), length); - for (Joint child : joint.getChildren()) { - computeLength(child, jointsLength, armature); - } - } - } - @Override public void updateLogicalState(float tpf) { super.updateLogicalState(tpf); - bones.updateGeometry(); + armatureNode.updateGeometry(); if (interJointWires != null) { // interJointWires.updateGeometry(); } } - ColorRGBA selectedColor = ColorRGBA.Orange; - ColorRGBA baseColor = new ColorRGBA(0.05f, 0.05f, 0.05f, 1f); - protected Joint select(Geometry g) { - Node oldNode = bones.getSelectedNode(); - Joint b = bones.select(g); - if (b == null) { - return null; - } - if (oldNode != null) { - markSelected(oldNode, false); - } - markSelected(bones.getSelectedNode(), true); - return b; + return armatureNode.select(g); } /** * @return the armature wires */ - public ArmatureBone getBoneShapes() { - return bones; + public ArmatureNode getBoneShapes() { + return armatureNode; } /** @@ -187,29 +159,4 @@ public class ArmatureDebugger extends BatchNode { public ArmatureInterJointsWire getInterJointWires() { return interJointWires; } - - protected void markSelected(Node n, boolean selected) { - ColorRGBA c = baseColor; - if (selected) { - c = selectedColor; - } - for (Spatial spatial : n.getChildren()) { - if (spatial instanceof Geometry) { - Geometry geom = (Geometry) spatial; - - Geometry batch = (Geometry) getChild(getName() + "-batch0"); - VertexBuffer vb = batch.getMesh().getBuffer(VertexBuffer.Type.Color); - FloatBuffer color = (FloatBuffer) vb.getData(); - // System.err.println(getName() + "." + geom.getName() + " index " + getGeometryStartIndex(geom) * 4 + "/" + color.limit()); - - color.position(getGeometryStartIndex(geom) * 4); - - for (int i = 0; i < geom.getVertexCount(); i++) { - color.put(c.r).put(c.g).put(c.b).put(c.a); - } - color.rewind(); - vb.updateData(color); - } - } - } } \ No newline at end of file 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 new file mode 100644 index 000000000..2b717adfd --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/scene/debug/custom/ArmatureNode.java @@ -0,0 +1,245 @@ +package com.jme3.scene.debug.custom; + +/* + * 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. + */ + +import com.jme3.anim.Armature; +import com.jme3.anim.Joint; +import com.jme3.collision.*; +import com.jme3.math.*; +import com.jme3.renderer.queue.RenderQueue; +import com.jme3.scene.*; +import com.jme3.scene.shape.Line; + +import java.nio.FloatBuffer; +import java.util.HashMap; +import java.util.Map; + +/** + * The class that displays either wires between the bones' heads if no length + * data is supplied and full bones' shapes otherwise. + */ +public class ArmatureNode extends Node { + + /** + * The armature to be displayed. + */ + private Armature armature; + /** + * The map between the bone index and its length. + */ + private Map jointToGeoms = new HashMap<>(); + private Map geomToJoint = new HashMap<>(); + private Joint selectedJoint = null; + private Vector3f tmpStart = new Vector3f(); + private Vector3f tmpEnd = new Vector3f(); + ColorRGBA selectedColor = ColorRGBA.Orange; + ColorRGBA selectedColorJ = ColorRGBA.Yellow; + ;//new ColorRGBA(0.2f, 1f, 1.0f, 1.0f); + ColorRGBA baseColor = new ColorRGBA(0.05f, 0.05f, 0.05f, 1f); + + + /** + * Creates a wire with bone lengths data. If the data is supplied then the + * wires will show each full bone (from head to tail). + * + * @param armature the armature that will be shown + */ + public ArmatureNode(Armature armature, Node joints, Node wires, Node outlines) { + this.armature = armature; + + for (Joint joint : armature.getRoots()) { + createSkeletonGeoms(joint, joints, wires, outlines); + } + this.updateModelBound(); + + } + + protected final void createSkeletonGeoms(Joint joint, Node joints, Node wires, Node outlines) { + Vector3f start = joint.getModelTransform().getTranslation().clone(); + Vector3f end = null; + + //One child only, the bone direction is from the parent joint to the child joint. + if (joint.getChildren().size() == 1) { + end = joint.getChildren().get(0).getModelTransform().getTranslation().clone(); + } + + Geometry jGeom = new Geometry(joint.getName() + "Joint", new JointShape()); + jGeom.setLocalTranslation(start); + joints.attachChild(jGeom); + Geometry bGeom = null; + Geometry bGeomO = null; + if (end != null) { + bGeom = new Geometry(joint.getName() + "Bone", new Line(start, end)); + setColor(bGeom, baseColor); + geomToJoint.put(bGeom, joint); + bGeomO = new Geometry(joint.getName() + "BoneOutline", new Line(start, end)); + setColor(bGeomO, ColorRGBA.White); + bGeom.setUserData("start", wires.getWorldTransform().transformVector(start, start)); + bGeom.setUserData("end", wires.getWorldTransform().transformVector(end, end)); + bGeom.setQueueBucket(RenderQueue.Bucket.Transparent); + wires.attachChild(bGeom); + outlines.attachChild(bGeomO); + } + + jointToGeoms.put(joint, new Geometry[]{jGeom, bGeom, bGeomO}); + + for (Joint child : joint.getChildren()) { + createSkeletonGeoms(child, joints, wires, outlines); + } + } + + protected Joint select(Geometry g) { + if (g == null) { + resetSelection(); + return null; + } + Joint j = geomToJoint.get(g); + if (j != null) { + if (selectedJoint == j) { + return null; + } + resetSelection(); + selectedJoint = j; + Geometry[] geomArray = jointToGeoms.get(selectedJoint); + setColor(geomArray[0], selectedColorJ); + setColor(geomArray[1], selectedColor); + setColor(geomArray[2], baseColor); + return j; + } + return null; + } + + private void resetSelection() { + if (selectedJoint == null) { + return; + } + Geometry[] geoms = jointToGeoms.get(selectedJoint); + setColor(geoms[0], ColorRGBA.White); + setColor(geoms[1], baseColor); + setColor(geoms[2], ColorRGBA.White); + selectedJoint = null; + } + + protected Joint getSelectedJoint() { + return selectedJoint; + } + + + protected final void updateSkeletonGeoms(Joint joint) { + Geometry[] geoms = jointToGeoms.get(joint); + if (geoms != null) { + Geometry jGeom = geoms[0]; + jGeom.setLocalTranslation(joint.getModelTransform().getTranslation()); + Geometry bGeom = geoms[1]; + if (bGeom != null) { + tmpStart.set(joint.getModelTransform().getTranslation()); + boolean hasEnd = false; + if (joint.getChildren().size() == 1) { + tmpEnd.set(joint.getChildren().get(0).getModelTransform().getTranslation()); + hasEnd = true; + } + if (hasEnd) { + updateBoneMesh(bGeom); + Geometry bGeomO = geoms[2]; + updateBoneMesh(bGeomO); + Vector3f start = bGeom.getUserData("start"); + Vector3f end = bGeom.getUserData("end"); + bGeom.setUserData("start", bGeom.getParent().getWorldTransform().transformVector(tmpStart, start)); + bGeom.setUserData("end", bGeom.getParent().getWorldTransform().transformVector(tmpEnd, end)); + } + } + } + + for (Joint child : joint.getChildren()) { + updateSkeletonGeoms(child); + } + } + + @Override + public int collideWith(Collidable other, CollisionResults results) { + if (!(other instanceof Ray)) { + return 0; + } + int nbCol = 0; + for (Geometry g : geomToJoint.keySet()) { + float len = MathUtils.raySegmentShortestDistance((Ray) other, (Vector3f) g.getUserData("start"), (Vector3f) g.getUserData("end")); + if (len > 0 && len < 0.1f) { + CollisionResult res = new CollisionResult(); + res.setGeometry(g); + results.addCollision(res); + nbCol++; + } + } + return nbCol; + } + + private void updateBoneMesh(Geometry bGeom) { + VertexBuffer pos = bGeom.getMesh().getBuffer(VertexBuffer.Type.Position); + FloatBuffer fb = (FloatBuffer) pos.getData(); + fb.rewind(); + fb.put(new float[]{tmpStart.x, tmpStart.y, tmpStart.z, + tmpEnd.x, tmpEnd.y, tmpEnd.z,}); + pos.updateData(fb); + + bGeom.updateModelBound(); + } + + private void setColor(Geometry g, ColorRGBA color) { + float[] colors = new float[g.getMesh().getVertexCount() * 4]; + for (int i = 0; i < g.getMesh().getVertexCount() * 4; i += 4) { + colors[i] = color.r; + colors[i + 1] = color.g; + colors[i + 2] = color.b; + colors[i + 3] = color.a; + } + VertexBuffer colorBuff = g.getMesh().getBuffer(VertexBuffer.Type.Color); + if (colorBuff == null) { + g.getMesh().setBuffer(VertexBuffer.Type.Color, 4, colors); + } else { + FloatBuffer cBuff = (FloatBuffer) colorBuff.getData(); + cBuff.rewind(); + cBuff.put(colors); + colorBuff.updateData(cBuff); + } + } + + /** + * The method updates the geometry according to the positions of the bones. + */ + public void updateGeometry() { + armature.update(); + for (Joint joint : armature.getRoots()) { + updateSkeletonGeoms(joint); + } + } +} diff --git a/jme3-core/src/main/java/com/jme3/scene/debug/custom/BoneShape.java b/jme3-core/src/main/java/com/jme3/scene/debug/custom/BoneShape.java deleted file mode 100644 index 702ec5613..000000000 --- a/jme3-core/src/main/java/com/jme3/scene/debug/custom/BoneShape.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (c) 2009-2018 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. - */ -// $Id: Cylinder.java 4131 2009-03-19 20:15:28Z blaine.dev $ -package com.jme3.scene.debug.custom; - -import com.jme3.math.*; -import com.jme3.scene.VertexBuffer.Type; -import com.jme3.scene.shape.AbstractBox; -import com.jme3.util.BufferUtils; - -import java.nio.FloatBuffer; - -/** - * A simple cylinder, defined by its height and radius. - * (Ported to jME3) - * - * @author Mark Powell - * @version $Revision: 4131 $, $Date: 2009-03-19 16:15:28 -0400 (Thu, 19 Mar 2009) $ - */ -public class BoneShape extends AbstractBox { - - private static Vector3f topN = new Vector3f(0, 1, 0); - private static Vector3f botN = new Vector3f(0, -1, 0); - private static Vector3f rigN = new Vector3f(1, 0, 0); - private static Vector3f lefN = new Vector3f(-1, 0, 0); - - static { - Quaternion q = new Quaternion().fromAngleAxis(-FastMath.PI / 16f, Vector3f.UNIT_X); - q.multLocal(topN); - q.inverseLocal(); - q.multLocal(botN); - q = new Quaternion().fromAngleAxis(FastMath.PI / 16f, Vector3f.UNIT_Y); - q.multLocal(rigN); - q.inverseLocal(); - q.multLocal(lefN); - } - - private static final short[] GEOMETRY_INDICES_DATA = { - 2, 1, 0, 3, 2, 0, // back - 6, 5, 4, 7, 6, 4, // right - 10, 9, 8, 11, 10, 8, // front - 14, 13, 12, 15, 14, 12, // left - 18, 17, 16, 19, 18, 16, // top - 22, 21, 20, 23, 22, 20 // bottom - }; - - private static final float[] GEOMETRY_NORMALS_DATA = { - 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, // back - rigN.x, rigN.y, rigN.z, rigN.x, rigN.y, rigN.z, rigN.x, rigN.y, rigN.z, rigN.x, rigN.y, rigN.z, // right - 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, // front - lefN.x, lefN.y, lefN.z, lefN.x, lefN.y, lefN.z, lefN.x, lefN.y, lefN.z, lefN.x, lefN.y, lefN.z, // left - topN.x, topN.y, topN.z, topN.x, topN.y, topN.z, topN.x, topN.y, topN.z, topN.x, topN.y, topN.z, // top - botN.x, botN.y, botN.z, botN.x, botN.y, botN.z, botN.x, botN.y, botN.z, botN.x, botN.y, botN.z // bottom - }; - - private static final float[] GEOMETRY_TEXTURE_DATA = { - 1, 0, 0, 0, 0, 1, 1, 1, // back - 1, 0, 0, 0, 0, 1, 1, 1, // right - 1, 0, 0, 0, 0, 1, 1, 1, // front - 1, 0, 0, 0, 0, 1, 1, 1, // left - 1, 0, 0, 0, 0, 1, 1, 1, // top - 1, 0, 0, 0, 0, 1, 1, 1 // bottom - }; - - private static final float[] GEOMETRY_POSITION_DATA = { - -0.5f, -0.5f, 0, 0.5f, -0.5f, 0, 0.5f, 0.5f, 0, -0.5f, 0.5f, 0, //back - 0.5f, -0.5f, 0, 0.25f, -0.25f, 1, 0.25f, 0.25f, 1, 0.5f, 0.5f, 0, //right - 0.25f, -0.25f, 1, -0.25f, -0.25f, 1, -0.25f, 0.25f, 1, 0.25f, 0.25f, 1, //front - -0.25f, -0.25f, 1, -0.5f, -0.5f, 0, -0.5f, 0.5f, 0, -0.25f, 0.25f, 1, //left - 0.5f, 0.5f, 0, 0.25f, 0.25f, 1, -0.25f, 0.25f, 1, -0.5f, 0.5f, 0, // top - -0.5f, -0.5f, 0, -0.25f, -0.25f, 1, 0.25f, -0.25f, 1, 0.5f, -0.5f, 0 // bottom - }; - - //0,1,2,3 - //1,4,6,2 - //4,5,7,6 - //5,0,3,7, - //2,6,7,3 - //0,5,4,1 - - -// v[0].x, v[0].y, v[0].z, v[1].x, v[1].y, v[1].z, v[2].x, v[2].y, v[2].z, v[3].x, v[3].y, v[3].z, // back -// v[1].x, v[1].y, v[1].z, v[4].x, v[4].y, v[4].z, v[6].x, v[6].y, v[6].z, v[2].x, v[2].y, v[2].z, // right -// v[4].x, v[4].y, v[4].z, v[5].x, v[5].y, v[5].z, v[7].x, v[7].y, v[7].z, v[6].x, v[6].y, v[6].z, // front -// v[5].x, v[5].y, v[5].z, v[0].x, v[0].y, v[0].z, v[3].x, v[3].y, v[3].z, v[7].x, v[7].y, v[7].z, // left -// v[2].x, v[2].y, v[2].z, v[6].x, v[6].y, v[6].z, v[7].x, v[7].y, v[7].z, v[3].x, v[3].y, v[3].z, // top -// v[0].x, v[0].y, v[0].z, v[5].x, v[5].y, v[5].z, v[4].x, v[4].y, v[4].z, v[1].x, v[1].y, v[1].z // bottom - - /** - * Creates a new box. - *

- * The box has a center of 0,0,0 and extends in the out from the center by - * the given amount in each direction. So, for example, a box - * with extent of 0.5 would be the unit cube. - * - * @param x the size of the box along the x axis, in both directions. - * @param y the size of the box along the y axis, in both directions. - * @param z the size of the box along the z axis, in both directions. - */ - public BoneShape() { - super(); - updateGeometry(); - } - - /** - * Creates a clone of this box. - *

- * The cloned box will have '_clone' appended to it's name, but all other - * properties will be the same as this box. - */ - @Override - public BoneShape clone() { - return new BoneShape(); - } - - protected void doUpdateGeometryIndices() { - if (getBuffer(Type.Index) == null) { - setBuffer(Type.Index, 3, BufferUtils.createShortBuffer(GEOMETRY_INDICES_DATA)); - } - } - - protected void doUpdateGeometryNormals() { - if (getBuffer(Type.Normal) == null) { - setBuffer(Type.Normal, 3, BufferUtils.createFloatBuffer(GEOMETRY_NORMALS_DATA)); - } - } - - protected void doUpdateGeometryTextures() { - if (getBuffer(Type.TexCoord) == null) { - setBuffer(Type.TexCoord, 2, BufferUtils.createFloatBuffer(GEOMETRY_TEXTURE_DATA)); - } - } - - protected void doUpdateGeometryVertices() { - FloatBuffer fpb = BufferUtils.createVector3Buffer(24); - fpb.put(GEOMETRY_POSITION_DATA); - setBuffer(Type.Position, 3, fpb); - updateBound(); - } - - -} diff --git a/jme3-core/src/main/java/com/jme3/scene/debug/custom/JointShape.java b/jme3-core/src/main/java/com/jme3/scene/debug/custom/JointShape.java new file mode 100644 index 000000000..b854095b9 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/scene/debug/custom/JointShape.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2009-2010 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.scene.debug.custom; + +import com.jme3.scene.Mesh; +import com.jme3.scene.VertexBuffer.Type; + + +public class JointShape extends Mesh { + + + /** + * Serialization only. Do not use. + */ + public JointShape() { + float width = 1; + float height = 1; + setBuffer(Type.Position, 3, new float[]{-width * 0.5f, -width * 0.5f, 0, + width * 0.5f, -width * 0.5f, 0, + width * 0.5f, height * 0.5f, 0, + -width * 0.5f, height * 0.5f, 0 + }); + + + setBuffer(Type.TexCoord, 2, new float[]{0, 0, + 1, 0, + 1, 1, + 0, 1}); + + setBuffer(Type.Normal, 3, new float[]{0, 0, 1, + 0, 0, 1, + 0, 0, 1, + 0, 0, 1}); + + setBuffer(Type.Color, 4, new float[]{1, 1, 1, 1, + 1, 1, 1, 1, + 1, 1, 1, 1, + 1, 1, 1, 1}); + + setBuffer(Type.Index, 3, new short[]{0, 1, 2, + 0, 2, 3}); + + + updateBound(); + setStatic(); + } + + +} diff --git a/jme3-core/src/main/resources/Common/MatDefs/Misc/Billboard.j3md b/jme3-core/src/main/resources/Common/MatDefs/Misc/Billboard.j3md new file mode 100644 index 000000000..f97b3c736 --- /dev/null +++ b/jme3-core/src/main/resources/Common/MatDefs/Misc/Billboard.j3md @@ -0,0 +1,78 @@ +MaterialDef Billboard { + MaterialParameters { + Float SpriteHeight : 10 + Texture2D Texture + } + + Technique { + WorldParameters { + WorldViewMatrix + ProjectionMatrix + WorldMatrix + CameraDirection + ViewPort + CameraPosition + } + + VertexShaderNodes { + ShaderNode TexCoord { + Definition: AttributeToVarying: Common/MatDefs/ShaderNodes/Basic/AttributeToVarying.j3sn + InputMappings { + vec2Variable = Attr.inTexCoord + vec4Variable = Attr.inColor + } + OutputMappings { + } + } + ShaderNode FixedScale { + Definition: FixedScale: Common/MatDefs/ShaderNodes/Common/FixedScale.j3sn + InputMappings { + projectionMatrix = WorldParam.ProjectionMatrix + worldMatrix = WorldParam.WorldMatrix + cameraDir = WorldParam.CameraDirection + viewport = WorldParam.ViewPort + modelPosition = Attr.inPosition + cameraPos = WorldParam.CameraPosition + spriteHeight = MatParam.SpriteHeight + } + OutputMappings { + } + } + ShaderNode Billboard { + Definition: Billboard: Common/MatDefs/ShaderNodes/Common/Billboard.j3sn + InputMappings { + worldViewMatrix = WorldParam.WorldViewMatrix + projectionMatrix = WorldParam.ProjectionMatrix + modelPosition = Attr.inPosition + scale = FixedScale.scale + } + OutputMappings { + Global.position = projPosition + } + } + } + + FragmentShaderNodes { + ShaderNode TextureFetch { + Definition: TextureFetch: Common/MatDefs/ShaderNodes/Basic/TextureFetch.j3sn + InputMappings { + textureMap = MatParam.Texture + texCoord = TexCoord.vec2Variable + } + OutputMappings { + } + } + ShaderNode ColorMult { + Definition: ColorMult: Common/MatDefs/ShaderNodes/Basic/ColorMult.j3sn + InputMappings { + color1 = TextureFetch.outColor + color2 = TexCoord.vec4Variable + } + OutputMappings { + Global.color = outColor + } + } + } + + } +} diff --git a/jme3-core/src/main/resources/Common/MatDefs/ShaderNodes/Common/Billboard.j3sn b/jme3-core/src/main/resources/Common/MatDefs/ShaderNodes/Common/Billboard.j3sn new file mode 100644 index 000000000..a9421de4c --- /dev/null +++ b/jme3-core/src/main/resources/Common/MatDefs/ShaderNodes/Common/Billboard.j3sn @@ -0,0 +1,35 @@ +ShaderNodeDefinitions{ + ShaderNodeDefinition Billboard { + //Vertex/Fragment + Type: Vertex + + //Shader GLSL: + Shader GLSL100: Common/MatDefs/ShaderNodes/Common/Billboard100.frag + + Documentation{ + //type documentation here. This is optional but recommended + + //@input + @input mat4 worldViewMatrix The worldView matrix + @input mat4 projectionMatrix The projection matrix + @input vec3 modelPosition the vertex position + @input float scale the scale of the billboard (defautl 1) + + //@output + @output vec4 projPosition The position in projection space + } + Input { + //all the node inputs + // + mat4 worldViewMatrix + mat4 projectionMatrix + vec3 modelPosition + float scale 1 + } + Output { + //all the node outputs + // + vec4 projPosition + } + } +} \ No newline at end of file diff --git a/jme3-core/src/main/resources/Common/MatDefs/ShaderNodes/Common/Billboard100.frag b/jme3-core/src/main/resources/Common/MatDefs/ShaderNodes/Common/Billboard100.frag new file mode 100644 index 000000000..d85880760 --- /dev/null +++ b/jme3-core/src/main/resources/Common/MatDefs/ShaderNodes/Common/Billboard100.frag @@ -0,0 +1,19 @@ +void main(){ + // First colunm. + worldViewMatrix[0][0] = scale; + worldViewMatrix[0][1] = 0.0; + worldViewMatrix[0][2] = 0.0; + + // Second colunm. + worldViewMatrix[1][0] = 0.0; + worldViewMatrix[1][1] = scale; + worldViewMatrix[1][2] = 0.0; + + // Thrid colunm. + worldViewMatrix[2][0] = 0.0; + worldViewMatrix[2][1] = 0.0; + worldViewMatrix[2][2] = scale; + + vec4 position = worldViewMatrix * vec4(modelPosition,1.0); + projPosition = projectionMatrix * position; +} diff --git a/jme3-core/src/main/resources/Common/MatDefs/ShaderNodes/Common/FixedScale.j3sn b/jme3-core/src/main/resources/Common/MatDefs/ShaderNodes/Common/FixedScale.j3sn new file mode 100644 index 000000000..48a920474 --- /dev/null +++ b/jme3-core/src/main/resources/Common/MatDefs/ShaderNodes/Common/FixedScale.j3sn @@ -0,0 +1,41 @@ +ShaderNodeDefinitions{ + ShaderNodeDefinition FixedScale { + //Vertex/Fragment + Type: Vertex + + //Shader GLSL: + Shader GLSL100: Common/MatDefs/ShaderNodes/Common/FixedScale100.frag + + Documentation{ + //type documentation here. This is optional but recommended + + //@input + @input vec4 viewport The viewport information (right, top, left, bottom) + @input vec3 cameraDir The direction of the camera + @input vec3 cameraPos The position of the camera + @input mat4 worldMatrix The world matrix + @input mat4 projectionMatrix The projection matrix + @input vec3 modelPosition the vertex position + @input float spriteHeight the desired image height in pixel + + //@output + @output float scale The constant scale + } + Input { + //all the node inputs + // + vec4 viewport + vec3 cameraDir + vec3 cameraPos + mat4 worldMatrix + mat4 projectionMatrix + vec3 modelPosition + float spriteHeight 10.0 + } + Output { + //all the node outputs + // + float scale + } + } +} \ No newline at end of file diff --git a/jme3-core/src/main/resources/Common/MatDefs/ShaderNodes/Common/FixedScale100.frag b/jme3-core/src/main/resources/Common/MatDefs/ShaderNodes/Common/FixedScale100.frag new file mode 100644 index 000000000..b15415b5f --- /dev/null +++ b/jme3-core/src/main/resources/Common/MatDefs/ShaderNodes/Common/FixedScale100.frag @@ -0,0 +1,8 @@ +void main(){ + vec4 worldPos = worldMatrix * vec4(modelPosition, 1.0); + vec3 dir = worldPos.xyz - cameraPos; + float distance = dot(cameraDir, dir); + float m11 = projectionMatrix[1][1]; + float halfHeight = (viewport.w - viewport.y) * 0.5; + scale = ((distance/halfHeight) * spriteHeight)/m11; +} diff --git a/jme3-core/src/main/resources/Common/MatDefs/ShaderNodes/Common/texCoord.j3sn b/jme3-core/src/main/resources/Common/MatDefs/ShaderNodes/Common/texCoord.j3sn new file mode 100644 index 000000000..fcf1bddb9 --- /dev/null +++ b/jme3-core/src/main/resources/Common/MatDefs/ShaderNodes/Common/texCoord.j3sn @@ -0,0 +1,57 @@ +ShaderNodeDefinitions{ + ShaderNodeDefinition TexCoord { + //Vertex/Fragment + Type: Vertex + + //Shader GLSL: + Shader GLSL100: Common/MatDefs/ShaderNodes/Common/texCoord100.frag + + Documentation{ + //type documentation here. This is optional but recommended + + //@input + @input vec2 texCoord The input texture Coord + @input vec2 texCoord2 The input texture Coord + @input vec2 texCoord3 The input texture Coord + @input vec2 texCoord4 The input texture Coord + @input vec2 texCoord5 The input texture Coord + @input vec2 texCoord6 The input texture Coord + @input vec2 texCoord7 The input texture Coord + @input vec2 texCoord8 The input texture Coord + + //@output + @output vec2 texCoord The input texture Coord + @output vec2 texCoord2 The input texture Coord + @output vec2 texCoord3 The input texture Coord + @output vec2 texCoord4 The input texture Coord + @output vec2 texCoord5 The input texture Coord + @output vec2 texCoord6 The input texture Coord + @output vec2 texCoord7 The input texture Coord + @output vec2 texCoord8 The input texture Coord + } + Input { + //all the node inputs + // + vec2 texCoord + vec2 texCoord2 + vec2 texCoord3 + vec2 texCoord4 + vec2 texCoord5 + vec2 texCoord6 + vec2 texCoord7 + vec2 texCoord8 + } + Output { + //all the node outputs + // + vec2 texCoord + vec2 texCoord2 + vec2 texCoord3 + vec2 texCoord4 + vec2 texCoord5 + vec2 texCoord6 + vec2 texCoord7 + vec2 texCoord8 + } + } +} \ No newline at end of file diff --git a/jme3-core/src/main/resources/Common/MatDefs/ShaderNodes/Common/texCoord100.frag b/jme3-core/src/main/resources/Common/MatDefs/ShaderNodes/Common/texCoord100.frag new file mode 100644 index 000000000..61a3f2e67 --- /dev/null +++ b/jme3-core/src/main/resources/Common/MatDefs/ShaderNodes/Common/texCoord100.frag @@ -0,0 +1,2 @@ +void main(){ +} diff --git a/jme3-core/src/main/resources/Common/Textures/dot.png b/jme3-core/src/main/resources/Common/Textures/dot.png new file mode 100644 index 0000000000000000000000000000000000000000..59605f195b4374625969c89bd5e6a0fddb95515c GIT binary patch literal 367 zcmeAS@N?(olHy`uVBq!ia0vp^AT}2V8<6ZZI=>f4aTa()7Bet#3xhBt!>lt z;Q$f0^NS~Qt9S>uswDc zmpoJ2)~RZHGVr^wxqBxEgV##!2ckP3H?ZAvJ;IP`6% zDoXbmiWl5_va=+&`kC5!))kFAnfDwi{4+;|^RdM|NfyT3>#<>>q30Vee75nqZ`}I4 zlHnnb#M-T2j`{Gd-OBKob;ISTgTe~DWM4fD>#m^ literal 0 HcmV?d00001 diff --git a/jme3-examples/src/main/java/jme3test/model/anim/TestArmature.java b/jme3-examples/src/main/java/jme3test/model/anim/TestArmature.java index 0beb2d0ae..a3d4210d0 100644 --- a/jme3-examples/src/main/java/jme3test/model/anim/TestArmature.java +++ b/jme3-examples/src/main/java/jme3test/model/anim/TestArmature.java @@ -40,12 +40,15 @@ public class TestArmature extends SimpleApplication { Joint root = new Joint("Root_Joint"); j1 = new Joint("Joint_1"); j2 = new Joint("Joint_2"); + Joint j3 = new Joint("Joint_3"); root.addChild(j1); j1.addChild(j2); + j2.addChild(j3); root.setLocalTranslation(new Vector3f(0, 0, 0.5f)); j1.setLocalTranslation(new Vector3f(0, 0.0f, -0.5f)); - j2.setLocalTranslation(new Vector3f(0, 0.0f, -0.2f)); - Joint[] joints = new Joint[]{root, j1, j2}; + j2.setLocalTranslation(new Vector3f(0, 0.0f, -0.3f)); + j3.setLocalTranslation(new Vector3f(0, 0, -0.2f)); + Joint[] joints = new Joint[]{root, j1, j2, j3}; final Armature armature = new Armature(joints); armature.setBindPose(); @@ -64,16 +67,16 @@ public class TestArmature extends SimpleApplication { }; Vector3f[] scales = new Vector3f[]{ new Vector3f(1, 1, 1), - new Vector3f(2, 2, 2), + new Vector3f(1, 1, 2), new Vector3f(1, 1, 1), }; Vector3f[] scales2 = new Vector3f[]{ new Vector3f(1, 1, 1), - new Vector3f(0.5f, 0.5f, 0.5f), + new Vector3f(1, 1, 0.5f), new Vector3f(1, 1, 1), }; - JointTrack track1 = new JointTrack(j1, times, null, rotations, null); + JointTrack track1 = new JointTrack(j1, times, null, rotations, scales); JointTrack track2 = new JointTrack(j2, times, null, rotations, null); clip.addTrack(track1); clip.addTrack(track2); @@ -98,7 +101,7 @@ public class TestArmature extends SimpleApplication { composer.setCurrentAnimClip("anim"); ArmatureDebugAppState debugAppState = new ArmatureDebugAppState(); - debugAppState.addArmature(ac, true); + debugAppState.addArmature(ac); stateManager.attach(debugAppState); rootNode.addLight(new DirectionalLight(new Vector3f(-1f, -1f, -1f).normalizeLocal()));