better Armature debugger

monkanim
Nehon 7 years ago
parent 56065d0d70
commit c630ac2e59
  1. 24
      jme3-core/src/main/java/com/jme3/anim/util/AnimMigrationUtils.java
  2. 63
      jme3-core/src/main/java/com/jme3/math/MathUtils.java
  3. 199
      jme3-core/src/main/java/com/jme3/scene/debug/custom/ArmatureBone.java
  4. 91
      jme3-core/src/main/java/com/jme3/scene/debug/custom/ArmatureDebugAppState.java
  5. 151
      jme3-core/src/main/java/com/jme3/scene/debug/custom/ArmatureDebugger.java
  6. 245
      jme3-core/src/main/java/com/jme3/scene/debug/custom/ArmatureNode.java
  7. 171
      jme3-core/src/main/java/com/jme3/scene/debug/custom/BoneShape.java
  8. 79
      jme3-core/src/main/java/com/jme3/scene/debug/custom/JointShape.java
  9. 78
      jme3-core/src/main/resources/Common/MatDefs/Misc/Billboard.j3md
  10. 35
      jme3-core/src/main/resources/Common/MatDefs/ShaderNodes/Common/Billboard.j3sn
  11. 19
      jme3-core/src/main/resources/Common/MatDefs/ShaderNodes/Common/Billboard100.frag
  12. 41
      jme3-core/src/main/resources/Common/MatDefs/ShaderNodes/Common/FixedScale.j3sn
  13. 8
      jme3-core/src/main/resources/Common/MatDefs/ShaderNodes/Common/FixedScale100.frag
  14. 57
      jme3-core/src/main/resources/Common/MatDefs/ShaderNodes/Common/texCoord.j3sn
  15. 2
      jme3-core/src/main/resources/Common/MatDefs/ShaderNodes/Common/texCoord100.frag
  16. BIN
      jme3-core/src/main/resources/Common/Textures/dot.png
  17. 15
      jme3-examples/src/main/java/jme3test/model/anim/TestArmature.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) {
}
}
}
}

@ -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;
}
}

@ -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<Joint, Node> jointNode = new HashMap<>();
private Map<Node, Joint> 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<Integer, Float> 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<Integer, Float> 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);
}
}
}

@ -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<Armature, ArmatureDebugger> armatures = new HashMap<>();
private Map<Armature, Joint> 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<Geometry> 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;
}
}
}
}
};

@ -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<Bone> selectedJoints = new ArrayList<Bone>();
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<Integer, Float> bonesLength = new HashMap<Integer, Float>();
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<Integer, Float> 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);
}
}
}
}

@ -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<Joint, Geometry[]> jointToGeoms = new HashMap<>();
private Map<Geometry, Joint> 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);
}
}
}

@ -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.
* <p>
* The box has a center of 0,0,0 and extends in the out from the center by
* the given amount in <em>each</em> 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.
* <p>
* 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();
}
}

@ -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();
}
}

@ -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
}
}
}
}
}

@ -0,0 +1,35 @@
ShaderNodeDefinitions{
ShaderNodeDefinition Billboard {
//Vertex/Fragment
Type: Vertex
//Shader GLSL<version>: <Path to shader>
Shader GLSL100: Common/MatDefs/ShaderNodes/Common/Billboard100.frag
Documentation{
//type documentation here. This is optional but recommended
//@input <glsltype> <varName> <description>
@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 <glslType> <varName> <description>
@output vec4 projPosition The position in projection space
}
Input {
//all the node inputs
//<glslType> <varName>
mat4 worldViewMatrix
mat4 projectionMatrix
vec3 modelPosition
float scale 1
}
Output {
//all the node outputs
//<glslType> <varName>
vec4 projPosition
}
}
}

@ -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;
}

@ -0,0 +1,41 @@
ShaderNodeDefinitions{
ShaderNodeDefinition FixedScale {
//Vertex/Fragment
Type: Vertex
//Shader GLSL<version>: <Path to shader>
Shader GLSL100: Common/MatDefs/ShaderNodes/Common/FixedScale100.frag
Documentation{
//type documentation here. This is optional but recommended
//@input <glsltype> <varName> <description>
@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 <glslType> <varName> <description>
@output float scale The constant scale
}
Input {
//all the node inputs
//<glslType> <varName>
vec4 viewport
vec3 cameraDir
vec3 cameraPos
mat4 worldMatrix
mat4 projectionMatrix
vec3 modelPosition
float spriteHeight 10.0
}
Output {
//all the node outputs
//<glslType> <varName>
float scale
}
}
}

@ -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;
}

@ -0,0 +1,57 @@
ShaderNodeDefinitions{
ShaderNodeDefinition TexCoord {
//Vertex/Fragment
Type: Vertex
//Shader GLSL<version>: <Path to shader>
Shader GLSL100: Common/MatDefs/ShaderNodes/Common/texCoord100.frag
Documentation{
//type documentation here. This is optional but recommended
//@input <glsltype> <varName> <description>
@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 <glslType> <varName> <description>
@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
//<glslType> <varName>
vec2 texCoord
vec2 texCoord2
vec2 texCoord3
vec2 texCoord4
vec2 texCoord5
vec2 texCoord6
vec2 texCoord7
vec2 texCoord8
}
Output {
//all the node outputs
//<glslType> <varName>
vec2 texCoord
vec2 texCoord2
vec2 texCoord3
vec2 texCoord4
vec2 texCoord5
vec2 texCoord6
vec2 texCoord7
vec2 texCoord8
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 367 B

@ -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()));

Loading…
Cancel
Save