use of org.rajawali3d.animation.mesh.SkeletalAnimationChildObject3D in project Rajawali by Rajawali.
the class BlockAnimator method buildSkeleton.
// apply joint hierarchy to joint pose frames
private void buildSkeleton(BlockHeader blockHeader, long skelAddr) throws ParsingException {
SkeletonJoint[] joints = lookupSkeleton(blockHeader, skelAddr);
SkeletalAnimationSequence[] skelAnims = new SkeletalAnimationSequence[mAnimSet.length];
for (int i = 0; i < mAnimSet.length; i++) skelAnims[i] = (SkeletalAnimationSequence) mAnimSet[i];
Matrix4 scratch1 = new Matrix4();
Matrix4 scratch2 = new Matrix4();
for (SkeletalAnimationSequence skelSeq : skelAnims) {
for (SkeletalAnimationFrame frame : skelSeq.getFrames()) {
SkeletonJoint[] poses = frame.getSkeleton().getJoints();
// apply parent transforms
for (int i = 0; i < poses.length; i++) {
// matrix and index already set, need parent & other attribs
poses[i].setParentIndex(joints[i].getParentIndex());
if (// has parent joint
poses[i].getParentIndex() >= 0) {
SkeletonJoint parentPose = poses[poses[i].getParentIndex()];
scratch1.setAll(parentPose.getMatrix()).multiply(scratch2.setAll(poses[i].getMatrix()));
poses[i].setMatrix(scratch1.getDoubleValues());
} else
scratch1.setAll(poses[i].getMatrix());
// assign pos + rot from final matrix
scratch1.getTranslation(poses[i].getPosition());
poses[i].getOrientation().fromMatrix(scratch1);
poses[i].getOrientation().computeW();
}
}
}
for (int i = 0; i < mTargets.length; i++) {
SkeletalAnimationObject3D obj = (SkeletalAnimationObject3D) mTargets[i];
// assigns INVBP, builds BP, sets joints
obj.setJointsWithInverseBindPoseMatrices(joints);
for (int j = 0; j < obj.getNumChildren(); j++) {
SkeletalAnimationChildObject3D child = (SkeletalAnimationChildObject3D) obj.getChildAt(j);
SkeletalAnimationMaterialPlugin plugin = new SkeletalAnimationMaterialPlugin(child.getNumJoints(), child.getMaxBoneWeightsPerVertex());
child.getMaterial().addPlugin(plugin);
}
obj.setAnimationSequences(skelAnims);
obj.setAnimationSequence(mActive);
if (mAutoPlay)
obj.play(true);
}
}
use of org.rajawali3d.animation.mesh.SkeletalAnimationChildObject3D in project Rajawali by Rajawali.
the class BlockTriangleGeometry method parseBlock.
public void parseBlock(AWDLittleEndianDataInputStream dis, BlockHeader blockHeader) throws Exception {
// Lookup name
mLookupName = dis.readVarString();
// Count of sub geometries
mSubGeometryCount = dis.readUnsignedShort();
// TODO Meshes need to be joined in some fashion. This might work. Need to test it I suppose.
// One object for each sub geometry
mBaseObjects = new Object3D[mSubGeometryCount];
// Debug
if (RajLog.isDebugEnabled()) {
RajLog.d(" Lookup Name: " + mLookupName);
RajLog.d(" Sub Geometry Count: " + mSubGeometryCount);
}
// Determine the precision for the block
final boolean geoAccuracy = (blockHeader.flags & BlockHeader.FLAG_ACCURACY_GEO) == BlockHeader.FLAG_ACCURACY_GEO;
final short geoNr = geoAccuracy ? AWDLittleEndianDataInputStream.TYPE_FLOAT64 : AWDLittleEndianDataInputStream.TYPE_FLOAT32;
// Read the properties
SparseArray<Short> properties = new SparseArray<Short>();
// Scale Texture U
properties.put(1, geoNr);
// Scale Texture V
properties.put(2, geoNr);
// TODO Apply texture scales, need example of this working.
dis.readProperties(properties);
// Calculate the sizes
final int geoPrecisionSize = blockHeader.globalPrecisionGeo ? 8 : 4;
// Read each sub mesh data
for (int parsedSub = 0; parsedSub < mSubGeometryCount; ++parsedSub) {
long subMeshEnd = dis.getPosition() + dis.readUnsignedInt();
// Geometry
float[] vertices = null;
int[] indices = null;
float[] uvs = null;
float[] normals = null;
int[] joints = null;
float[] weights = null;
// Skip reading of mesh properties for now (per AWD implementation)
dis.readProperties();
// Read each data type from the mesh
while (dis.getPosition() < subMeshEnd) {
int idx = 0;
int type = dis.readUnsignedByte();
int typeF = dis.readUnsignedByte();
long subLength = dis.readUnsignedInt();
long subEnd = dis.getPosition() + subLength;
if (RajLog.isDebugEnabled())
RajLog.d(" Mesh Data: t:" + type + " tf:" + typeF + " l:" + subLength + " ls:" + dis.getPosition() + " le:" + subEnd);
// Process the mesh data by type
switch((int) type) {
case // Vertex positions
1:
vertices = new float[(int) (subLength / geoPrecisionSize)];
while (idx < vertices.length) {
// X, Y, Z
vertices[idx++] = (float) dis.readPrecisionNumber(blockHeader.globalPrecisionGeo);
vertices[idx++] = (float) dis.readPrecisionNumber(blockHeader.globalPrecisionGeo);
vertices[idx++] = (float) -dis.readPrecisionNumber(blockHeader.globalPrecisionGeo);
}
break;
case // Face indices
2:
indices = new int[(int) (subLength / 2)];
while (idx < indices.length) {
indices[idx + 2] = dis.readUnsignedShort();
indices[idx + 1] = dis.readUnsignedShort();
indices[idx] = dis.readUnsignedShort();
idx += 3;
}
break;
case // UV coordinates
3:
uvs = new float[(int) (subLength / geoPrecisionSize)];
while (idx < uvs.length) uvs[idx++] = (float) dis.readPrecisionNumber(blockHeader.globalPrecisionGeo);
break;
case // Vertex normals
4:
normals = new float[(int) (subLength / geoPrecisionSize)];
while (idx < normals.length) {
normals[idx++] = (float) dis.readPrecisionNumber(blockHeader.globalPrecisionGeo);
normals[idx++] = (float) dis.readPrecisionNumber(blockHeader.globalPrecisionGeo);
normals[idx++] = (float) dis.readPrecisionNumber(blockHeader.globalPrecisionGeo);
}
break;
case // Joint index
6:
joints = new int[(int) (subLength / 2)];
while (idx < joints.length) joints[idx++] = dis.readUnsignedShort();
break;
case // Joint weight
7:
weights = new float[(int) (subLength / geoPrecisionSize)];
while (idx < weights.length) weights[idx++] = (float) dis.readPrecisionNumber(blockHeader.globalPrecisionGeo);
break;
// Vertex tangents
case 5:
default:
// Unknown mesh data, skipping
dis.skip(subLength);
}
// Validate each mesh data ending. This is a sanity check against precision flags.
if (dis.getPosition() != subEnd)
throw new ParsingException("Unexpected ending. Expected " + subEnd + ". Got " + dis.getPosition());
}
dis.readUserAttributes(null);
// Verify the arrays
if (vertices == null)
vertices = new float[0];
if (normals == null)
normals = new float[0];
if (uvs == null)
uvs = new float[0];
if (indices == null)
indices = new int[0];
// FIXME This should be combining sub geometry not creating objects
if (joints != null && joints.length > 0) {
/*
* Prepares skeletal animation object as far as possible; setting mesh
* and skeletal weight data. The object will not yet have an actual
* skeleton applied to it.
*/
SkeletalAnimationChildObject3D obj = new SkeletalAnimationChildObject3D();
obj.setData(vertices, normals, uvs, null, indices, false);
int numVertices = vertices.length / 3;
// AWD stipulates all vertices have same # bindings, possibly 0 weighted
int weightsPerVertex = weights.length / numVertices;
// true WPV may be out of range, so clamp
int clampWeightsPerVertex = Math.min(weightsPerVertex, SkeletalAnimationChildObject3D.MAX_WEIGHTS_PER_VERTEX);
// one BoneVertex per actual vertex, maps to N weights & joint indices
BoneVertex[] bvertices = new BoneVertex[numVertices];
ArrayList<BoneWeight> bweights = new ArrayList<BoneWeight>();
int maxWeightsPerVertex = 0;
int vertexWeightIndex = 0;
for (int vert = 0; vert < numVertices; vert++) {
BoneVertex bone = new BoneVertex();
bvertices[vert] = bone;
// we may ignore weights, so map to our custom list
bone.weightIndex = bweights.size();
// true position in raw weight array
vertexWeightIndex = vert * weightsPerVertex;
// only add first [clamp] non-zero weights
for (int wgt = 0; wgt < clampWeightsPerVertex; wgt++) {
if (weights[vertexWeightIndex + wgt] == 0)
continue;
BoneWeight weight = new BoneWeight();
// joints and weights are indexed together
weight.jointIndex = joints[vertexWeightIndex + wgt];
weight.weightValue = weights[vertexWeightIndex + wgt];
bone.numWeights++;
bweights.add(weight);
}
maxWeightsPerVertex = Math.max(maxWeightsPerVertex, bone.numWeights);
}
// extract the clean BoneWeight array
BoneWeight[] boneweights = bweights.toArray(new BoneWeight[bweights.size()]);
obj.setMaxBoneWeightsPerVertex(maxWeightsPerVertex);
obj.setSkeletonMeshData(bvertices, boneweights);
//obj.setInverseZScale(true);
mBaseObjects[parsedSub] = obj;
} else {
mBaseObjects[parsedSub] = new Object3D();
mBaseObjects[parsedSub].setData(vertices, normals, uvs, null, indices, false);
}
}
dis.readUserAttributes(null);
}
use of org.rajawali3d.animation.mesh.SkeletalAnimationChildObject3D in project Rajawali by Rajawali.
the class BlockTriangleGeometry method getBaseObject3D.
@Override
public Object3D getBaseObject3D() {
if (finalObject != null)
return finalObject;
if (mBaseObjects[0] instanceof SkeletalAnimationChildObject3D) {
SkeletalAnimationObject3D container = new SkeletalAnimationObject3D();
for (int i = 0; i < mBaseObjects.length; i++) {
SkeletalAnimationChildObject3D child = (SkeletalAnimationChildObject3D) mBaseObjects[i];
child.setSkeleton(container);
container.addChild(child);
}
finalObject = container;
} else if (mBaseObjects.length == 1)
finalObject = mBaseObjects[0];
else {
final Object3D container = new Object3D(mLookupName);
container.isContainer(true);
for (int i = 0; i < mBaseObjects.length; i++) container.addChild(mBaseObjects[i]);
finalObject = container;
}
return finalObject;
}
use of org.rajawali3d.animation.mesh.SkeletalAnimationChildObject3D in project Rajawali by Rajawali.
the class LoaderMD5Mesh method createObjects.
private void createObjects() throws TextureException, ParsingException, SkeletalAnimationException {
SkeletalAnimationObject3D root = new SkeletalAnimationObject3D();
root.uBoneMatrix = mBindPoseMatrix;
root.mInverseBindPoseMatrix = mInverseBindPoseMatrix;
root.setJoints(mJoints);
mRootObject = root;
for (int i = 0; i < mNumMeshes; ++i) {
SkeletonMeshData mesh = mMeshes[i];
SkeletalAnimationChildObject3D o = new SkeletalAnimationChildObject3D();
o.setData(mesh.vertices, GLES20.GL_STREAM_DRAW, mesh.normals, GLES20.GL_STREAM_DRAW, mesh.textureCoordinates, GLES20.GL_STATIC_DRAW, null, GLES20.GL_STATIC_DRAW, mesh.indices, GLES20.GL_STATIC_DRAW, false);
o.setMaxBoneWeightsPerVertex(mesh.maxBoneWeightsPerVertex);
o.setSkeletonMeshData(mesh.numVertices, mesh.boneVertices, mesh.numWeights, mesh.boneWeights);
o.setName("MD5Mesh_" + i);
o.setSkeleton(mRootObject);
o.setInverseZScale(true);
boolean hasTexture = mesh.textureName != null && mesh.textureName.length() > 0;
Material mat = new Material();
mat.addPlugin(new SkeletalAnimationMaterialPlugin(mNumJoints, mesh.maxBoneWeightsPerVertex));
mat.enableLighting(true);
mat.setDiffuseMethod(new DiffuseMethod.Lambert());
o.setMaterial(mat);
if (!hasTexture) {
o.setColor(0xff000000 + (int) (Math.random() * 0xffffff));
} else {
int identifier = mResources.getIdentifier(mesh.textureName, "drawable", mResources.getResourcePackageName(mResourceId));
if (identifier == 0) {
throw new ParsingException("Couldn't find texture " + mesh.textureName);
}
mat.setColorInfluence(0);
mat.addTexture(new Texture("md5tex" + i, identifier));
}
mRootObject.addChild(o);
mesh.destroy();
mesh = null;
}
}
Aggregations