com.jme3.scene.plugins.blender.animations.BoneEnvelope Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jme3-blender Show documentation
Show all versions of jme3-blender Show documentation
jMonkeyEngine is a 3D game engine for adventurous Java developers
The newest version!
package com.jme3.scene.plugins.blender.animations;
import com.jme3.math.Matrix4f;
import com.jme3.math.Vector3f;
import com.jme3.scene.plugins.blender.file.DynamicArray;
import com.jme3.scene.plugins.blender.file.Structure;
/**
* An implementation of bone envelope. Used when assigning bones to the mesh by envelopes.
*
* @author Marcin Roguski
*/
public class BoneEnvelope {
/** A defined distance that will be included in the envelope space. */
private float distance;
/** The bone's weight. */
private float weight;
/** The radius of the bone's head. */
private float boneHeadRadius;
/** The radius of the bone's tail. */
private float boneTailRadius;
/** Head position in rest pose in world space. */
private Vector3f head;
/** Tail position in rest pose in world space. */
private Vector3f tail;
/**
* The constructor of bone envelope. It reads all the needed data. Take notice that the positions of head and tail
* are computed in the world space and that the points' positions given for computations should be in world space as well.
*
* @param boneStructure
* the blender bone structure
* @param armatureWorldMatrix
* the world matrix of the armature object
* @param fixUpAxis
* a variable that tells if we use the Y-is up axis orientation
*/
@SuppressWarnings("unchecked")
public BoneEnvelope(Structure boneStructure, Matrix4f armatureWorldMatrix, boolean fixUpAxis) {
distance = ((Number) boneStructure.getFieldValue("dist")).floatValue();
weight = ((Number) boneStructure.getFieldValue("weight")).floatValue();
boneHeadRadius = ((Number) boneStructure.getFieldValue("rad_head")).floatValue();
boneTailRadius = ((Number) boneStructure.getFieldValue("rad_tail")).floatValue();
DynamicArray headArray = (DynamicArray) boneStructure.getFieldValue("arm_head");
head = new Vector3f(headArray.get(0).floatValue(), headArray.get(1).floatValue(), headArray.get(2).floatValue());
if (fixUpAxis) {
float z = head.z;
head.z = -head.y;
head.y = z;
}
armatureWorldMatrix.mult(head, head);// move the head point to global space
DynamicArray tailArray = (DynamicArray) boneStructure.getFieldValue("arm_tail");
tail = new Vector3f(tailArray.get(0).floatValue(), tailArray.get(1).floatValue(), tailArray.get(2).floatValue());
if (fixUpAxis) {
float z = tail.z;
tail.z = -tail.y;
tail.y = z;
}
armatureWorldMatrix.mult(tail, tail);// move the tail point to global space
}
/**
* The method verifies if the given point is inside the envelope.
* @param point
* the point in 3D space (MUST be in a world coordinate space)
* @return true if the point is inside the envelope and false otherwise
*/
public boolean isInEnvelope(Vector3f point) {
Vector3f v = tail.subtract(head);
float boneLength = v.length();
v.normalizeLocal();
// computing a plane that contains 'point' and v is its normal vector
// the plane's equation is: Ax + By + Cz + D = 0, where v = [A, B, C]
float D = -v.dot(point);
// computing a point where a line that contains head and tail crosses the plane
float temp = -(v.dot(head) + D) / v.dot(v);
Vector3f p = head.add(v.x * temp, v.y * temp, v.z * temp);
// determining if the point p is on the same or other side of head than the tail point
Vector3f headToPointOnLineVector = p.subtract(head);
float headToPointLength = headToPointOnLineVector.length();
float cosinus = headToPointOnLineVector.dot(v) / headToPointLength;// the length of v is already = 1; cosinus should be either 1, 0 or -1
if (cosinus < 0 && headToPointLength > boneHeadRadius || headToPointLength > boneLength + boneTailRadius) {
return false;// the point is outside the anvelope
}
// now check if the point is inside and envelope
float pointDistanceFromLine = point.subtract(p).length(), maximumDistance = 0;
if (cosinus < 0) {
// checking if the distance from p to point is inside the half sphere defined by head envelope
// compute the distance from the line to the half sphere border
maximumDistance = boneHeadRadius;
} else if (headToPointLength < boneLength) {
// compute the maximum available distance
if (boneTailRadius > boneHeadRadius) {
// compute the distance from head to p
float headToPDistance = p.subtract(head).length();
// from tangens function we have
float x = headToPDistance * ((boneTailRadius - boneHeadRadius) / boneLength);
maximumDistance = x + boneHeadRadius;
} else if (boneTailRadius < boneHeadRadius) {
// compute the distance from head to p
float tailToPDistance = p.subtract(tail).length();
// from tangens function we have
float x = tailToPDistance * ((boneHeadRadius - boneTailRadius) / boneLength);
maximumDistance = x + boneTailRadius;
} else {
maximumDistance = boneTailRadius;
}
} else {
// checking if the distance from p to point is inside the half sphere defined by tail envelope
maximumDistance = boneTailRadius;
}
return pointDistanceFromLine <= maximumDistance + distance;
}
/**
* @return the weight of the bone
*/
public float getWeight() {
return weight;
}
@Override
public String toString() {
return "BoneEnvelope [d=" + distance + ", w=" + weight + ", hr=" + boneHeadRadius + ", tr=" + boneTailRadius + ", (" + head + ") -> (" + tail + ")]";
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy