use of com.jme3.animation.Bone in project jmonkeyengine by jMonkeyEngine.
the class SkeletonLoader method startElement.
public void startElement(String uri, String localName, String qName, Attributes attribs) throws SAXException {
if (qName.equals("position") || qName.equals("translate")) {
position = SAXUtil.parseVector3(attribs);
} else if (qName.equals("rotation") || qName.equals("rotate")) {
angle = SAXUtil.parseFloat(attribs.getValue("angle"));
} else if (qName.equals("axis")) {
assert elementStack.peek().equals("rotation") || elementStack.peek().equals("rotate");
axis = SAXUtil.parseVector3(attribs);
} else if (qName.equals("scale")) {
scale = SAXUtil.parseVector3(attribs);
} else if (qName.equals("keyframe")) {
assert elementStack.peek().equals("keyframes");
time = SAXUtil.parseFloat(attribs.getValue("time"));
} else if (qName.equals("keyframes")) {
assert elementStack.peek().equals("track");
} else if (qName.equals("track")) {
assert elementStack.peek().equals("tracks");
String boneName = SAXUtil.parseString(attribs.getValue("bone"));
Bone bone = nameToBone.get(boneName);
int index = skeleton.getBoneIndex(bone);
track = new BoneTrack(index);
} else if (qName.equals("boneparent")) {
assert elementStack.peek().equals("bonehierarchy");
String boneName = attribs.getValue("bone");
String parentName = attribs.getValue("parent");
Bone bone = nameToBone.get(boneName);
Bone parent = nameToBone.get(parentName);
parent.addChild(bone);
} else if (qName.equals("bone")) {
assert elementStack.peek().equals("bones");
// insert bone into indexed map
bone = new Bone(attribs.getValue("name"));
int id = SAXUtil.parseInt(attribs.getValue("id"));
indexToBone.put(id, bone);
nameToBone.put(bone.getName(), bone);
} else if (qName.equals("tracks")) {
assert elementStack.peek().equals("animation");
tracks.clear();
} else if (qName.equals("animation")) {
assert elementStack.peek().equals("animations");
String name = SAXUtil.parseString(attribs.getValue("name"));
float length = SAXUtil.parseFloat(attribs.getValue("length"));
animation = new Animation(name, length);
} else if (qName.equals("bonehierarchy")) {
assert elementStack.peek().equals("skeleton");
} else if (qName.equals("animations")) {
assert elementStack.peek().equals("skeleton");
animations = new ArrayList<Animation>();
} else if (qName.equals("bones")) {
assert elementStack.peek().equals("skeleton");
} else if (qName.equals("skeleton")) {
assert elementStack.size() == 0;
}
elementStack.add(qName);
}
use of com.jme3.animation.Bone in project jmonkeyengine by jMonkeyEngine.
the class IrUtils method convertIrMeshToJmeMesh.
/**
* Convert IrMesh to jME3 mesh.
*/
public static Mesh convertIrMeshToJmeMesh(IrMesh mesh) {
Map<IrVertex, Integer> vertexToVertexIndex = new HashMap<IrVertex, Integer>();
List<IrVertex> vertices = new ArrayList<IrVertex>();
List<Integer> indexes = new ArrayList<Integer>();
int vertexIndex = 0;
for (IrPolygon polygon : mesh.polygons) {
if (polygon.vertices.length != 3) {
throw new UnsupportedOperationException("IrMesh must be triangulated first");
}
for (IrVertex vertex : polygon.vertices) {
// Is this vertex already indexed?
Integer existingIndex = vertexToVertexIndex.get(vertex);
if (existingIndex == null) {
// Not indexed yet, allocate index.
indexes.add(vertexIndex);
vertexToVertexIndex.put(vertex, vertexIndex);
vertices.add(vertex);
vertexIndex++;
} else {
// Index already allocated for this vertex, reuse it.
indexes.add(existingIndex);
}
}
}
Mesh jmeMesh = new Mesh();
jmeMesh.setMode(Mesh.Mode.Triangles);
FloatBuffer posBuf = null;
FloatBuffer normBuf = null;
FloatBuffer tangBuf = null;
FloatBuffer uv0Buf = null;
FloatBuffer uv1Buf = null;
ByteBuffer colorBuf = null;
ByteBuffer boneIndices = null;
FloatBuffer boneWeights = null;
IndexBuffer indexBuf = null;
IrVertex inspectionVertex = vertices.get(0);
if (inspectionVertex.pos != null) {
posBuf = BufferUtils.createVector3Buffer(vertices.size());
jmeMesh.setBuffer(VertexBuffer.Type.Position, 3, posBuf);
}
if (inspectionVertex.norm != null) {
normBuf = BufferUtils.createVector3Buffer(vertices.size());
jmeMesh.setBuffer(VertexBuffer.Type.Normal, 3, normBuf);
}
if (inspectionVertex.tang4d != null) {
tangBuf = BufferUtils.createFloatBuffer(vertices.size() * 4);
jmeMesh.setBuffer(VertexBuffer.Type.Tangent, 4, tangBuf);
}
if (inspectionVertex.tang != null || inspectionVertex.bitang != null) {
throw new IllegalStateException("Mesh is using 3D tangents, must be converted to 4D tangents first.");
}
if (inspectionVertex.uv0 != null) {
uv0Buf = BufferUtils.createVector2Buffer(vertices.size());
jmeMesh.setBuffer(VertexBuffer.Type.TexCoord, 2, uv0Buf);
}
if (inspectionVertex.uv1 != null) {
uv1Buf = BufferUtils.createVector2Buffer(vertices.size());
jmeMesh.setBuffer(VertexBuffer.Type.TexCoord2, 2, uv1Buf);
}
if (inspectionVertex.color != null) {
colorBuf = BufferUtils.createByteBuffer(vertices.size() * 4);
jmeMesh.setBuffer(VertexBuffer.Type.Color, 4, colorBuf);
jmeMesh.getBuffer(VertexBuffer.Type.Color).setNormalized(true);
}
if (inspectionVertex.boneWeightsIndices != null) {
boneIndices = BufferUtils.createByteBuffer(vertices.size() * 4);
boneWeights = BufferUtils.createFloatBuffer(vertices.size() * 4);
jmeMesh.setBuffer(VertexBuffer.Type.BoneIndex, 4, boneIndices);
jmeMesh.setBuffer(VertexBuffer.Type.BoneWeight, 4, boneWeights);
//creating empty buffers for HW skinning
//the buffers will be setup if ever used.
VertexBuffer weightsHW = new VertexBuffer(VertexBuffer.Type.HWBoneWeight);
VertexBuffer indicesHW = new VertexBuffer(VertexBuffer.Type.HWBoneIndex);
//setting usage to cpuOnly so that the buffer is not send empty to the GPU
indicesHW.setUsage(VertexBuffer.Usage.CpuOnly);
weightsHW.setUsage(VertexBuffer.Usage.CpuOnly);
jmeMesh.setBuffer(weightsHW);
jmeMesh.setBuffer(indicesHW);
}
if (vertices.size() >= 65536) {
// too many verticies: use intbuffer instead of shortbuffer
IntBuffer ib = BufferUtils.createIntBuffer(indexes.size());
jmeMesh.setBuffer(VertexBuffer.Type.Index, 3, ib);
indexBuf = new IndexIntBuffer(ib);
} else {
ShortBuffer sb = BufferUtils.createShortBuffer(indexes.size());
jmeMesh.setBuffer(VertexBuffer.Type.Index, 3, sb);
indexBuf = new IndexShortBuffer(sb);
}
jmeMesh.setStatic();
int maxBonesPerVertex = -1;
for (IrVertex vertex : vertices) {
if (posBuf != null) {
posBuf.put(vertex.pos.x).put(vertex.pos.y).put(vertex.pos.z);
}
if (normBuf != null) {
normBuf.put(vertex.norm.x).put(vertex.norm.y).put(vertex.norm.z);
}
if (tangBuf != null) {
tangBuf.put(vertex.tang4d.x).put(vertex.tang4d.y).put(vertex.tang4d.z).put(vertex.tang4d.w);
}
if (uv0Buf != null) {
uv0Buf.put(vertex.uv0.x).put(vertex.uv0.y);
}
if (uv1Buf != null) {
uv1Buf.put(vertex.uv1.x).put(vertex.uv1.y);
}
if (colorBuf != null) {
colorBuf.putInt(vertex.color.asIntABGR());
}
if (boneIndices != null) {
if (vertex.boneWeightsIndices != null) {
if (vertex.boneWeightsIndices.length > 4) {
throw new UnsupportedOperationException("Mesh uses more than 4 weights per bone. " + "Call trimBoneWeights() to allieviate this");
}
for (int i = 0; i < vertex.boneWeightsIndices.length; i++) {
boneIndices.put((byte) (vertex.boneWeightsIndices[i].boneIndex & 0xFF));
boneWeights.put(vertex.boneWeightsIndices[i].boneWeight);
}
for (int i = 0; i < 4 - vertex.boneWeightsIndices.length; i++) {
boneIndices.put((byte) 0);
boneWeights.put(0f);
}
} else {
boneIndices.putInt(0);
boneWeights.put(0f).put(0f).put(0f).put(0f);
}
maxBonesPerVertex = Math.max(maxBonesPerVertex, vertex.boneWeightsIndices.length);
}
}
for (int i = 0; i < indexes.size(); i++) {
indexBuf.put(i, indexes.get(i));
}
jmeMesh.updateCounts();
jmeMesh.updateBound();
if (boneIndices != null) {
jmeMesh.setMaxNumWeights(maxBonesPerVertex);
jmeMesh.prepareForAnim(true);
jmeMesh.generateBindPose(true);
}
return jmeMesh;
}
use of com.jme3.animation.Bone in project jmonkeyengine by jMonkeyEngine.
the class FbxLimbNode method getJmeBone.
public Bone getJmeBone() {
if (bone == null) {
bone = new Bone(name);
bone.setBindTransforms(jmeLocalBindPose.getTranslation(), jmeLocalBindPose.getRotation(), jmeLocalBindPose.getScale());
}
return bone;
}
use of com.jme3.animation.Bone in project jmonkeyengine by jMonkeyEngine.
the class FbxLoader method constructAnimations.
private void constructAnimations() {
// In FBX, animation are not attached to any root.
// They are implicitly global.
// So, we need to use hueristics to find which node(s)
// an animation is associated with, so we can create the AnimControl
// in the appropriate location in the scene.
Map<FbxToJmeTrack, FbxToJmeTrack> pairs = new HashMap<FbxToJmeTrack, FbxToJmeTrack>();
for (FbxAnimStack stack : animStacks) {
for (FbxAnimLayer layer : stack.getLayers()) {
for (FbxAnimCurveNode curveNode : layer.getAnimationCurveNodes()) {
for (Map.Entry<FbxNode, String> nodePropertyEntry : curveNode.getInfluencedNodeProperties().entrySet()) {
FbxToJmeTrack lookupPair = new FbxToJmeTrack();
lookupPair.animStack = stack;
lookupPair.animLayer = layer;
lookupPair.node = nodePropertyEntry.getKey();
// Find if this pair is already stored
FbxToJmeTrack storedPair = pairs.get(lookupPair);
if (storedPair == null) {
// If not, store it.
storedPair = lookupPair;
pairs.put(storedPair, storedPair);
}
String property = nodePropertyEntry.getValue();
storedPair.animCurves.put(property, curveNode);
}
}
}
}
// At this point we can construct the animation for all pairs ...
for (FbxToJmeTrack pair : pairs.values()) {
String animName = pair.animStack.getName();
float duration = pair.animStack.getDuration();
System.out.println("ANIMATION: " + animName + ", duration = " + duration);
System.out.println("NODE: " + pair.node.getName());
duration = pair.getDuration();
if (pair.node instanceof FbxLimbNode) {
// Find the spatial that has the skeleton for this limb.
FbxLimbNode limbNode = (FbxLimbNode) pair.node;
Bone bone = limbNode.getJmeBone();
Spatial jmeSpatial = limbNode.getSkeletonHolder().getJmeObject();
Skeleton skeleton = limbNode.getSkeletonHolder().getJmeSkeleton();
// Get the animation control (create if missing).
AnimControl animControl = jmeSpatial.getControl(AnimControl.class);
if (animControl.getSkeleton() != skeleton) {
throw new UnsupportedOperationException();
}
// Get the animation (create if missing).
Animation anim = animControl.getAnim(animName);
if (anim == null) {
anim = new Animation(animName, duration);
animControl.addAnim(anim);
}
// Find the bone index from the spatial's skeleton.
int boneIndex = skeleton.getBoneIndex(bone);
// Generate the bone track.
BoneTrack bt = pair.toJmeBoneTrack(boneIndex, bone.getBindInverseTransform());
// Add the bone track to the animation.
anim.addTrack(bt);
} else {
// Create the spatial animation
Animation anim = new Animation(animName, duration);
anim.setTracks(new Track[] { pair.toJmeSpatialTrack() });
// Get the animation control (create if missing).
Spatial jmeSpatial = pair.node.getJmeObject();
AnimControl animControl = jmeSpatial.getControl(AnimControl.class);
if (animControl == null) {
animControl = new AnimControl(null);
jmeSpatial.addControl(animControl);
}
// Add the spatial animation
animControl.addAnim(anim);
}
}
}
use of com.jme3.animation.Bone in project jmonkeyengine by jMonkeyEngine.
the class MaskModifier method readBoneNames.
/**
* Reads the names of the bones from the given bone base.
* @param boneBase
* the list of bone base structures
* @return a list of bones' names
* @throws BlenderFileException
* is thrown if problems with reading the child bones' bases occur
*/
private List<String> readBoneNames(List<Structure> boneBase) throws BlenderFileException {
List<String> result = new ArrayList<String>();
for (Structure boneStructure : boneBase) {
int flag = ((Number) boneStructure.getFieldValue("flag")).intValue();
if ((flag & BoneContext.SELECTED) != 0) {
result.add(boneStructure.getFieldValue("name").toString());
}
List<Structure> childbase = ((Structure) boneStructure.getFieldValue("childbase")).evaluateListBase();
result.addAll(this.readBoneNames(childbase));
}
return result;
}
Aggregations