Search in sources :

Example 1 with BoneVertex

use of org.rajawali3d.animation.mesh.SkeletalAnimationChildObject3D.BoneVertex in project Rajawali by Rajawali.

the class LoaderMD5Mesh method calculateNormals.

private void calculateNormals() {
    for (int i = 0; i < mNumMeshes; ++i) {
        SkeletonMeshData mesh = mMeshes[i];
        int numTriangles = mesh.numTriangles;
        mesh.indices = new int[numTriangles * 3];
        int index = 0;
        for (int j = 0; j < numTriangles; ++j) {
            int[] triangle = mesh.triangles[j];
            int index0 = triangle[0];
            int index1 = triangle[2];
            int index2 = triangle[1];
            mesh.indices[index++] = index0;
            mesh.indices[index++] = index1;
            mesh.indices[index++] = index2;
            int index03 = index0 * 3;
            int index13 = index1 * 3;
            int index23 = index2 * 3;
            Vector3 v0 = new Vector3(mesh.vertices[index03], mesh.vertices[index03 + 1], mesh.vertices[index03 + 2]);
            Vector3 v1 = new Vector3(mesh.vertices[index13], mesh.vertices[index13 + 1], mesh.vertices[index13 + 2]);
            Vector3 v2 = new Vector3(mesh.vertices[index23], mesh.vertices[index23 + 1], mesh.vertices[index23 + 2]);
            Vector3 normal = Vector3.crossAndCreate(Vector3.subtractAndCreate(v2, v0), Vector3.subtractAndCreate(v1, v0));
            normal.inverse();
            mesh.boneVertices[index0].normal.add(normal);
            mesh.boneVertices[index1].normal.add(normal);
            mesh.boneVertices[index2].normal.add(normal);
        }
        int numVertices = mesh.numVertices;
        if (mesh.normals == null)
            mesh.normals = new float[numVertices * 3];
        for (int j = 0; j < numVertices; ++j) {
            BoneVertex vert = mesh.boneVertices[j];
            Vector3 normal = vert.normal.clone();
            vert.normal.normalize();
            normal.normalize();
            int normIndex = j * 3;
            mesh.normals[normIndex] = (float) normal.x;
            mesh.normals[normIndex + 1] = (float) normal.y;
            mesh.normals[normIndex + 2] = (float) normal.z;
            vert.normal.setAll(0, 0, 0);
            // so the animated normal can be computed faster
            for (int k = 0; k < vert.numWeights; ++k) {
                BoneWeight weight = mesh.boneWeights[vert.weightIndex + k];
                SkeletonJoint joint = mJoints[weight.jointIndex];
                //We don't clone here because nothing will be able to use the quaternion scratch before we do
                vert.normal.add(Vector3.scaleAndCreate(joint.getOrientation().multiply(normal), weight.weightValue));
            }
        }
    }
}
Also used : BoneWeight(org.rajawali3d.animation.mesh.SkeletalAnimationChildObject3D.BoneWeight) SkeletonJoint(org.rajawali3d.animation.mesh.SkeletalAnimationFrame.SkeletonJoint) Vector3(org.rajawali3d.math.vector.Vector3) SkeletonJoint(org.rajawali3d.animation.mesh.SkeletalAnimationFrame.SkeletonJoint) BoneVertex(org.rajawali3d.animation.mesh.SkeletalAnimationChildObject3D.BoneVertex)

Example 2 with BoneVertex

use of org.rajawali3d.animation.mesh.SkeletalAnimationChildObject3D.BoneVertex in project Rajawali by Rajawali.

the class LoaderMD5Mesh method parseMesh.

private void parseMesh(BufferedReader buffer) {
    try {
        String line;
        SkeletonMeshData mesh = new SkeletonMeshData();
        while ((line = buffer.readLine()) != null) {
            line = line.replace("\t", "");
            StringTokenizer parts = new StringTokenizer(line, " ");
            int numTokens = parts.countTokens();
            if (line.indexOf('}') > -1) {
                mMeshes[mMeshIndex++] = mesh;
                return;
            }
            if (numTokens == 0 || line.indexOf('}') > -1)
                continue;
            String type = parts.nextToken();
            if (type.equalsIgnoreCase(SHADER)) {
                String shader = parts.nextToken();
                shader = shader.replace("\"", "");
                mesh.textureName = shader;
                if (shader.length() == 0)
                    continue;
                int lastDelim = shader.lastIndexOf("/");
                if (lastDelim == -1)
                    lastDelim = shader.lastIndexOf("\\");
                if (lastDelim > -1)
                    mesh.textureName = shader.substring(lastDelim + 1, shader.length());
                int dot = shader.lastIndexOf(".");
                if (dot > -1)
                    mesh.textureName = shader.substring(0, dot);
            } else if (type.equalsIgnoreCase(NUM_VERTS)) {
                mesh.numVertices = Integer.parseInt(parts.nextToken());
                mesh.boneVertices = new BoneVertex[mesh.numVertices];
            } else if (type.equalsIgnoreCase(VERT)) {
                int index = Integer.parseInt(parts.nextToken());
                BoneVertex vert = new BoneVertex();
                // -- ignore '('
                parts.nextToken();
                vert.textureCoordinate.setAll(Float.parseFloat(parts.nextToken()), Float.parseFloat(parts.nextToken()));
                // -- ignore ')'
                parts.nextToken();
                vert.weightIndex = Integer.parseInt(parts.nextToken());
                vert.numWeights = Integer.parseInt(parts.nextToken());
                mesh.numWeights += vert.numWeights;
                mesh.maxBoneWeightsPerVertex = Math.max(mesh.maxBoneWeightsPerVertex, vert.numWeights);
                mesh.boneVertices[index] = vert;
            } else if (type.equalsIgnoreCase(NUM_TRIS)) {
                mesh.numTriangles = Integer.parseInt(parts.nextToken());
                mesh.triangles = new int[mesh.numTriangles][];
            } else if (type.equalsIgnoreCase(TRI)) {
                int index = Integer.parseInt(parts.nextToken());
                mesh.triangles[index] = new int[] { Integer.parseInt(parts.nextToken()), Integer.parseInt(parts.nextToken()), Integer.parseInt(parts.nextToken()) };
            } else if (type.equalsIgnoreCase(NUM_WEIGHTS)) {
                mesh.numWeights = Integer.parseInt(parts.nextToken());
                mesh.boneWeights = new BoneWeight[mesh.numWeights];
            } else if (type.equalsIgnoreCase(WEIGHT)) {
                int index = Integer.parseInt(parts.nextToken());
                BoneWeight weight = new BoneWeight();
                weight.jointIndex = Integer.parseInt(parts.nextToken());
                weight.weightValue = Float.parseFloat(parts.nextToken());
                mesh.boneWeights[index] = weight;
                // -- ignore '('
                parts.nextToken();
                float x = Float.parseFloat(parts.nextToken());
                float z = Float.parseFloat(parts.nextToken());
                float y = Float.parseFloat(parts.nextToken());
                weight.position.setAll(x, y, z);
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}
Also used : StringTokenizer(java.util.StringTokenizer) BoneWeight(org.rajawali3d.animation.mesh.SkeletalAnimationChildObject3D.BoneWeight) SkeletonJoint(org.rajawali3d.animation.mesh.SkeletalAnimationFrame.SkeletonJoint) TextureException(org.rajawali3d.materials.textures.ATexture.TextureException) ParsingException(org.rajawali3d.loader.ParsingException) FileNotFoundException(java.io.FileNotFoundException) SkeletalAnimationException(org.rajawali3d.animation.mesh.SkeletalAnimationObject3D.SkeletalAnimationException) BoneVertex(org.rajawali3d.animation.mesh.SkeletalAnimationChildObject3D.BoneVertex)

Example 3 with BoneVertex

use of org.rajawali3d.animation.mesh.SkeletalAnimationChildObject3D.BoneVertex 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);
}
Also used : SkeletalAnimationChildObject3D(org.rajawali3d.animation.mesh.SkeletalAnimationChildObject3D) ArrayList(java.util.ArrayList) Object3D(org.rajawali3d.Object3D) SkeletalAnimationObject3D(org.rajawali3d.animation.mesh.SkeletalAnimationObject3D) SkeletalAnimationChildObject3D(org.rajawali3d.animation.mesh.SkeletalAnimationChildObject3D) SparseArray(android.util.SparseArray) BoneWeight(org.rajawali3d.animation.mesh.SkeletalAnimationChildObject3D.BoneWeight) ParsingException(org.rajawali3d.loader.ParsingException) BoneVertex(org.rajawali3d.animation.mesh.SkeletalAnimationChildObject3D.BoneVertex)

Example 4 with BoneVertex

use of org.rajawali3d.animation.mesh.SkeletalAnimationChildObject3D.BoneVertex in project Rajawali by Rajawali.

the class LoaderMD5Mesh method buildMeshes.

private void buildMeshes() {
    for (int i = 0; i < mNumMeshes; ++i) {
        int boneIndex = 0;
        SkeletonMeshData mesh = mMeshes[i];
        mesh.vertices = new float[mesh.numVertices * 3];
        mesh.indices = new int[mesh.numWeights];
        mesh.weights = new float[mesh.numWeights];
        mesh.textureCoordinates = new float[mesh.numVertices * 2];
        int numVerts = mesh.numVertices;
        for (int j = 0; j < numVerts; ++j) {
            BoneVertex vert = mesh.boneVertices[j];
            Vector3 position = new Vector3();
            for (int k = 0; k < vert.numWeights; ++k) {
                BoneWeight weight = mesh.boneWeights[vert.weightIndex + k];
                SkeletonJoint joint = mJoints[weight.jointIndex];
                Vector3 rotPos = joint.getOrientation().multiply(weight.position);
                //We don't clone here because nothing will be able to use the quaternion scratch before we do
                Vector3 pos = Vector3.addAndCreate(joint.getPosition(), rotPos);
                pos.multiply(weight.weightValue);
                position.add(pos);
                mesh.indices[boneIndex] = weight.jointIndex;
                mesh.weights[boneIndex++] = weight.weightValue;
            }
            int vertIndex = j * 3;
            mesh.vertices[vertIndex] = (float) position.x;
            mesh.vertices[vertIndex + 1] = (float) position.y;
            mesh.vertices[vertIndex + 2] = (float) position.z;
            int uvIndex = j * 2;
            mesh.textureCoordinates[uvIndex] = (float) vert.textureCoordinate.getX();
            mesh.textureCoordinates[uvIndex + 1] = (float) vert.textureCoordinate.getY();
        }
    }
}
Also used : BoneWeight(org.rajawali3d.animation.mesh.SkeletalAnimationChildObject3D.BoneWeight) SkeletonJoint(org.rajawali3d.animation.mesh.SkeletalAnimationFrame.SkeletonJoint) Vector3(org.rajawali3d.math.vector.Vector3) SkeletonJoint(org.rajawali3d.animation.mesh.SkeletalAnimationFrame.SkeletonJoint) BoneVertex(org.rajawali3d.animation.mesh.SkeletalAnimationChildObject3D.BoneVertex)

Aggregations

BoneVertex (org.rajawali3d.animation.mesh.SkeletalAnimationChildObject3D.BoneVertex)4 BoneWeight (org.rajawali3d.animation.mesh.SkeletalAnimationChildObject3D.BoneWeight)4 SkeletonJoint (org.rajawali3d.animation.mesh.SkeletalAnimationFrame.SkeletonJoint)3 ParsingException (org.rajawali3d.loader.ParsingException)2 Vector3 (org.rajawali3d.math.vector.Vector3)2 SparseArray (android.util.SparseArray)1 FileNotFoundException (java.io.FileNotFoundException)1 ArrayList (java.util.ArrayList)1 StringTokenizer (java.util.StringTokenizer)1 Object3D (org.rajawali3d.Object3D)1 SkeletalAnimationChildObject3D (org.rajawali3d.animation.mesh.SkeletalAnimationChildObject3D)1 SkeletalAnimationObject3D (org.rajawali3d.animation.mesh.SkeletalAnimationObject3D)1 SkeletalAnimationException (org.rajawali3d.animation.mesh.SkeletalAnimationObject3D.SkeletalAnimationException)1 TextureException (org.rajawali3d.materials.textures.ATexture.TextureException)1