Exemplo n.º 1
0
		public bool Equals(VertexWeight other)
		{
			if (!other.Weight.Equals(this.Weight))
			{
				return false;
			}
			if (this.Weight == 0)
			{
				return true;
			}
			return other.BoneIndex == this.BoneIndex;
		}
Exemplo n.º 2
0
        /// <summary>
        /// Creates controllers to skin each geometry in the collada file
        /// </summary>
        void CreateControllerList()
        {
            H1.Tags.gbxmodel_group definition = tagManager.TagDefinition as H1.Tags.gbxmodel_group;

            // if there are no nodes then no skinning is possible
            if (definition.Nodes.Count == 0)
            {
                return;
            }

            // create a controller for each geometry
            for (int i = 0; i < modelInfo.GetGeometryCount(); i++)
            {
                List <VertexWeight> vertex_weights = new List <VertexWeight>();

                //  create a list of vertex weights from all of the geometry parts
                foreach (var part in definition.Geometries[modelInfo.GetGeometryIndex(i)].Parts)
                {
                    foreach (var vertex in part.UncompressedVertices)
                    {
                        VertexWeight vertex_weight = new VertexWeight();

                        int node1 = vertex.NodeIndex1;
                        int node2 = vertex.NodeIndex2;

                        // if the bone index count is 0 then the index references the main node list,
                        // otherwise it references a local node map for this part
                        if (part.NodeMapCount != 0)
                        {
                            node1 = part.NodeMap[node1];
                            node2 = (node2 != -1 ? part.NodeMap[node2].Value : node2);
                        }

                        vertex_weight.AddWeight(node1, vertex.NodeWeight1);

                        // if the first weight is 1 the vertex is weighted to one bone only so the second weight is not needed
                        if (vertex.NodeWeight1 != 1)
                        {
                            vertex_weight.AddWeight(node2, vertex.NodeWeight2);
                        }

                        vertex_weights.Add(vertex_weight);
                    }
                }

                // create the controller element
                CreateSkinController(listGeometry[i].ID, vertex_weights);
            }
        }
Exemplo n.º 3
0
        /// <summary>
        /// Load the bone information for each vertex
        /// </summary>
        /// <param name="assimpMesh"> mesh that contains the information to be processed </param>
        /// <param name="mesh"> customized mesh that stores information for later use </param>
        protected void LoadBoneWeights(Mesh assimpMesh, ClientMesh mesh)
        {
            // create a new data structures to store the bones
            mesh.VertexBoneDatas = new List <VertexBoneData>(mesh.CountVertices);
            for (int i = 0; i < mesh.CountVertices; i++)
            {
                mesh.VertexBoneDatas.Add(new VertexBoneData());
            }

            // copy bone weights from the meshes for each vertex
            for (int boneIndex = 0; boneIndex < assimpMesh.BoneCount; boneIndex++)
            {
                Bone currBone = assimpMesh.Bones[boneIndex];

                for (int weighti = 0; weighti < currBone.VertexWeightCount; weighti++)
                {
                    VertexWeight vertexWeight = currBone.VertexWeights[weighti];
                    mesh.VertexBoneDatas[vertexWeight.VertexID].AddBoneData(_allBoneMappings[currBone.Name], vertexWeight.Weight);
                }
            }

            // create new datastream so that we can stream them to the VBOs
            mesh.boneIDSize     = sizeof(int) * VertexBoneData.MAX_BONES_PER_VERTEX * mesh.CountVertices;
            mesh.boneWeightSize = sizeof(float) * VertexBoneData.MAX_BONES_PER_VERTEX * mesh.CountVertices;
            mesh.DSBoneIDs      = new DataStream(mesh.boneIDSize, true, true);
            mesh.DSBoneWeights  = new DataStream(mesh.boneWeightSize, true, true);

            // for each vertex, write the vertex buffer datastreams
            for (int i = 0; i < mesh.CountVertices; i++)
            {
                // normalize bone weights
                //mesh.VertexBoneDatas[i].NormalizeBoneData();

                // write the data into datastreams
                for (int bonei = 0; bonei < VertexBoneData.MAX_BONES_PER_VERTEX; bonei++)
                {
                    mesh.DSBoneIDs.Write(mesh.VertexBoneDatas[i].BoneIndices[bonei]);
                    mesh.DSBoneWeights.Write(mesh.VertexBoneDatas[i].BoneWeights[bonei]);
                }
            }

            mesh.DSBoneWeights.Position = 0;
            mesh.DSBoneIDs.Position     = 0;

            // create the datastreams
            mesh.VBOBoneIDs     = new Buffer(GraphicsRenderer.Device, mesh.DSBoneIDs, mesh.boneIDSize, ResourceUsage.Default, BindFlags.VertexBuffer, CpuAccessFlags.None, ResourceOptionFlags.None, 0);
            mesh.VBOBoneWeights = new Buffer(GraphicsRenderer.Device, mesh.DSBoneWeights, mesh.boneWeightSize, ResourceUsage.Default, BindFlags.VertexBuffer, CpuAccessFlags.None, ResourceOptionFlags.None, 0);
        }
        /// <summary>
        /// Creates a controller to skin each geometry in the file
        /// </summary>
        void CreateControllerList()
        {
            H2.Tags.render_model_group definition = tagManager.TagDefinition as H2.Tags.render_model_group;

            // if there are no bones then skinning isnt necessary
            if (definition.Nodes.Count == 0)
            {
                return;
            }

            // create a controller for each geometry in modelInfo
            for (int i = 0; i < modelInfo.GetGeometryCount(); i++)
            {
                H2.Tags.render_model_section_block.render_model_section_data_block section_block =
                    definition.Sections[modelInfo.GetGeometryIndex(i)].SectionData[0];

                // the node map contains a list of bone indices that the section is rigged to
                List <int> node_map = new List <int>();
                foreach (var node in section_block.NodeMap)
                {
                    node_map.Add(node.NodeIndex.Value);
                }

                List <VertexWeight> vertex_weights = new List <VertexWeight>();
                // create a generic list of vertex weights
                foreach (var vertex in section_block.Section.Value.RawVertices)
                {
                    VertexWeight common_weight = new VertexWeight();

                    // only add the weights with valid nodes
                    for (int weight_index = 0; (weight_index < vertex.Point.NodeIndex.Length) && (vertex.Point.NodeIndex[weight_index] != -1); weight_index++)
                    {
                        common_weight.AddWeight(node_map[vertex.Point.NodeIndex[weight_index]], vertex.Point.NodeWeight[weight_index]);
                    }

                    vertex_weights.Add(common_weight);
                }

                // create the controller element
                CreateSkinController(listGeometry[i].ID, vertex_weights);
            }
        }
        // This method use original assimp bone structure where many VertexWeights (with VertexId and Weight)
        // structs are assigned to each bone. This data structure is optimized for CPU updates.
        // The UpdateVertexPositions below requires that each vertex has its array of bones and weights - optimized for GPU updates.
        //
        // This method is based on sample code from: https://sourceforge.net/p/assimp/discussion/817654/thread/5462cbf5/

        /// <summary>
        /// UpdateVertexPositions updates the positions in the MeshGeometry3D
        /// </summary>
        public void UpdateVertexPositions()
        {
            if (SkeletonNodes == null)
            {
                return;
            }

            var originalPositions = _wpfOriginalPositions;

            var transformedPositions = new Point3D[originalPositions.Count];

            foreach (var skeletonNode in SkeletonNodes)
            {
                var assimpBone = skeletonNode.AssimpBone;
                if (assimpBone == null)
                {
                    continue;
                }

                var finalBoneMatrix = skeletonNode.FinalMatrix; // = skeletonNode.BoneOffsetMatrix * skeletonNode.CurrentWorldMatrix;

                for (int i = 0; i < assimpBone.VertexWeightCount; i++)
                {
                    VertexWeight boneWeight = assimpBone.VertexWeights[i];

                    int    vertexId     = boneWeight.VertexID;
                    double weightFactor = boneWeight.Weight;

                    var sourcePosition      = originalPositions[vertexId];
                    var transformedPosition = finalBoneMatrix.Transform(sourcePosition);

                    transformedPositions[vertexId] += new System.Windows.Media.Media3D.Vector3D(transformedPosition.X * weightFactor,
                                                                                                transformedPosition.Y * weightFactor,
                                                                                                transformedPosition.Z * weightFactor);
                }
            }

            MeshGeometry3D.Positions = new Point3DCollection(transformedPositions);
        }
Exemplo n.º 6
0
        public static List <Chunk> ReadVerts(ILogger log, byte[] fileData, int offset, int endOffset)
        {
            var   chunks        = new List <Chunk>();
            var   currentChunk  = new Chunk();
            Chunk previousChunk = null;

            while (offset < endOffset)
            {
                var vifCommand = fileData[offset + 3] & 0x7f;
                var numCommand = fileData[offset + 2] & 0xff;
                int immCommand = DataUtil.getLEShort(fileData, offset);
                switch (vifCommand)
                {
                case NOP_CMD:
                    DebugWrite(HexUtil.formatHex(offset) + " ");
                    DebugWriteLine("NOP");
                    offset += 4;
                    break;

                case STCYCL_CMD:
                    DebugWrite(HexUtil.formatHex(offset) + " ");
                    DebugWriteLine("STCYCL: WL: " + (immCommand >> 8) + " CL: " + (immCommand & 0xFF));
                    offset += 4;
                    break;

                case ITOP_CMD:
                    DebugWrite(HexUtil.formatHex(offset) + " ");
                    DebugWriteLine("ITOP: " + immCommand);
                    offset += 4;
                    break;

                case STMOD_CMD:
                    DebugWrite(HexUtil.formatHex(offset) + " ");
                    DebugWriteLine("STMOD: " + immCommand);
                    offset += 4;
                    break;

                case MSCAL_CMD:
                    DebugWrite(HexUtil.formatHex(offset) + " ");
                    DebugWriteLine("MSCAL: " + immCommand);
                    if (immCommand != 66 && immCommand != 68 && immCommand != 70)
                    {
                        DebugWriteLine("**** Microcode " + immCommand + " not supported");
                    }
                    currentChunk.mscalID = immCommand;
                    chunks.Add(currentChunk);
                    previousChunk = currentChunk;
                    currentChunk  = new Chunk();

                    offset += 4;
                    break;

                case STMASK_CMD:
                    DebugWrite(HexUtil.formatHex(offset) + " ");
                    offset += 4;
                    var stmask = DataUtil.getLEInt(fileData, offset);
                    DebugWriteLine("STMASK: " + stmask);
                    offset += 4;
                    break;

                case FLUSH_CMD:
                    DebugWrite(HexUtil.formatHex(offset) + " ");
                    DebugWriteLine("FLUSH");
                    offset += 4;
                    break;

                case DIRECT_CMD:
                    DebugWrite(HexUtil.formatHex(offset) + " ");
                    DebugWriteLine("DIRECT, " + immCommand * 16 + " bytes");

                    var tags = new GIFTag[immCommand];

                    for (var i = 0; i < immCommand; i++)
                    {
                        tags[i] = new GIFTag();
                        tags[i].parse(fileData, offset + 4 + i * 16);
                    }
                    currentChunk.DIRECTGifTags.AddRange(tags);

                    offset += 4;
                    offset += immCommand * 16;
                    break;

                default:
                    if ((vifCommand & 0x60) == 0x60)
                    {
                        // unpack command
                        var mask = ((vifCommand & 0x10) == 0x10);
                        var vn   = (vifCommand >> 2) & 3;
                        var vl   = vifCommand & 3;
                        var addr = immCommand & 0x1ff;
                        var flag = (immCommand & 0x8000) == 0x8000;
                        var usn  = (immCommand & 0x4000) == 0x4000;

                        DebugWrite(HexUtil.formatHex(offset) + " ");
                        var debugMsg = "UNPACK: vn: " + vn + ", vl: " + vl + ", Addr: " + addr + ", num: " + numCommand;

                        if (flag)
                        {
                            debugMsg += ", Flag";
                        }
                        if (usn)
                        {
                            debugMsg += ", Unsigned";
                        }
                        if (mask)
                        {
                            debugMsg += ", Mask";
                        }
                        DebugWriteLine(debugMsg);
                        offset += 4;
                        if (vn == 1 && vl == 1)
                        {
                            // v2-16
                            // I don't know why but the UVs come after the MSCAL instruction.
                            if (previousChunk != null)
                            {
                                for (var uvnum = 0; uvnum < numCommand; ++uvnum)
                                {
                                    var u = DataUtil.getLEShort(fileData, offset);
                                    var v = DataUtil.getLEShort(fileData, offset + 2);
                                    previousChunk.uvs.Add(new UV(u, v));
                                    offset += 4;
                                }
                            }
                            else
                            {
                                var numBytes = numCommand * 4;
                                offset += numBytes;
                            }
                        }
                        else if (vn == 2 && vl == 1)
                        {
                            // v3-16
                            // each vertex is 128 bits, so num is the number of vertices
                            for (var vnum = 0; vnum < numCommand; ++vnum)
                            {
                                if (!usn)
                                {
                                    var x = DataUtil.getLEShort(fileData, offset);
                                    var y = DataUtil.getLEShort(fileData, offset + 2);
                                    var z = DataUtil.getLEShort(fileData, offset + 4);
                                    offset += 6;

                                    var vertex = new Vertex
                                    {
                                        x = x,
                                        y = y,
                                        z = z
                                    };
                                    currentChunk.vertices.Add(vertex);
                                }
                                else
                                {
                                    int x = DataUtil.getLEUShort(fileData, offset);
                                    int y = DataUtil.getLEUShort(fileData, offset + 2);
                                    int z = DataUtil.getLEUShort(fileData, offset + 4);
                                    offset += 6;

                                    var vloc = new VLoc
                                    {
                                        v1 = x,
                                        v2 = y,
                                        v3 = z
                                    };
                                    currentChunk.vlocs.Add(vloc);
                                }
                            }
                            offset = (offset + 3) & ~3;
                        }
                        else if (vn == 2 && vl == 2)
                        {
                            // v3-8
                            var idx = offset;
                            for (var vnum = 0; vnum < numCommand; ++vnum)
                            {
                                var vec = new SByteVector
                                {
                                    x = (sbyte)fileData[idx++],
                                    y = (sbyte)fileData[idx++],
                                    z = (sbyte)fileData[idx++]
                                };
                                currentChunk.normals.Add(vec);
                            }
                            var numBytes = ((numCommand * 3) + 3) & ~3;
                            offset += numBytes;
                        }
                        else if (vn == 3 && vl == 0)
                        {
                            // v4-32
                            log.LogLine("v4-32 data, " + numCommand + (numCommand == 1 ? " entry" : " entries") + ", addr=" + addr);
                            if (1 == numCommand)
                            {
                                currentChunk.gifTag0 = new GIFTag();
                                currentChunk.gifTag0.parse(fileData, offset);
                                DebugWrite(HexUtil.formatHex(offset) + " ");
                                DebugWriteLine("GifTag: " + currentChunk.gifTag0.ToString());
                            }
                            else if (2 == numCommand)
                            {
                                currentChunk.gifTag0 = new GIFTag();
                                currentChunk.gifTag0.parse(fileData, offset);
                                currentChunk.gifTag1 = new GIFTag();
                                currentChunk.gifTag1.parse(fileData, offset + 16);

                                DebugWrite(HexUtil.formatHex(offset) + " ");
                                DebugWriteLine("GifTag0: " + currentChunk.gifTag0.ToString());
                                DebugWrite(HexUtil.formatHex(offset) + " ");
                                DebugWriteLine("GifTag1: " + currentChunk.gifTag1.ToString());
                            }
                            else
                            {
                                log.LogLine("unknown number of gif commands.");
                            }
                            var numBytes = numCommand * 16;
                            offset += numBytes;
                        }
                        else if (vn == 3 && vl == 1)
                        {
                            // v4-16
                            log.LogLine("v4-16 data, " + numCommand + (numCommand == 1 ? " entry" : " entries") + ", addr=" + addr);
                            var numShorts = numCommand * 4;
                            if (usn)
                            {
                                currentChunk.extraVlocs = new ushort[numShorts];
                                for (var i = 0; i < numCommand; ++i)
                                {
                                    currentChunk.extraVlocs[i * 4]     = DataUtil.getLEUShort(fileData, offset + i * 8);
                                    currentChunk.extraVlocs[i * 4 + 1] = DataUtil.getLEUShort(fileData, offset + i * 8 + 2);
                                    currentChunk.extraVlocs[i * 4 + 2] = DataUtil.getLEUShort(fileData, offset + i * 8 + 4);
                                    currentChunk.extraVlocs[i * 4 + 3] = DataUtil.getLEUShort(fileData, offset + i * 8 + 6);
                                }
                            }
                            else
                            {
                                log.LogLine("Unsupported tag");
                            }
                            offset += numShorts * 2;
                        }
                        else if (vn == 3 && vl == 2)
                        {
                            // v4-8
                            var numBytes = numCommand * 4;
                            currentChunk.vertexWeights = new List <VertexWeight>();
                            var curVertex = 0;
                            for (var i = 0; i < numCommand; ++i)
                            {
                                var vw = new VertexWeight
                                {
                                    startVertex = curVertex,
                                    bone1       = fileData[offset++] / 4,
                                    boneWeight1 = fileData[offset++],
                                    bone2       = fileData[offset++]
                                };
                                if (vw.bone2 == 0xFF)
                                {
                                    // Single bone
                                    vw.boneWeight2 = 0;
                                    int count = fileData[offset++];
                                    curVertex += count;
                                }
                                else
                                {
                                    vw.bone2      /= 4;
                                    vw.boneWeight2 = fileData[offset++];
                                    ++curVertex;

                                    if (vw.boneWeight1 + vw.boneWeight2 < 255)
                                    {
                                        ++i;
                                        vw.bone3       = fileData[offset++] / 4;
                                        vw.boneWeight3 = fileData[offset++];
                                        vw.bone4       = fileData[offset++];
                                        int bw4 = fileData[offset++];
                                        if (vw.bone4 != 255)
                                        {
                                            vw.bone4      /= 4;
                                            vw.boneWeight4 = bw4;
                                        }
                                    }
                                }
                                vw.endVertex = curVertex - 1;
                                currentChunk.vertexWeights.Add(vw);
                            }
                        }
                        else
                        {
                            DebugWriteLine("Unknown vnvl combination: vn=" + vn + ", vl=" + vl);
                            offset = endOffset;
                        }
                    }
                    else
                    {
                        DebugWriteLine("Unknown command: " + vifCommand);
                        offset = endOffset;
                    }
                    break;
                }
            }
            return(chunks);
        }
Exemplo n.º 7
0
        public void ParseMesh(Lexer parser, int numJoints, JointMat[] joints)
        {
            int num, jointnum, i, j; int[] tris, firstWeightForVertex, numWeightsForVertex; VertexWeight[] tempWeights;

            parser.ExpectTokenString("{");

            // parse name
            if (parser.CheckTokenString("name"))
            {
                parser.ReadToken(out var name);
            }

            // parse shader
            parser.ExpectTokenString("shader"); parser.ReadToken(out var token);
            var shaderName = token;

            shader = declManager.FindMaterial(shaderName);

            // parse texture coordinates
            parser.ExpectTokenString("numverts"); var count = parser.ParseInt();
            if (count < 0)
            {
                parser.Error($"Invalid size: {token}");
            }

            texCoords            = new Vector2[count];
            firstWeightForVertex = new int[count];
            numWeightsForVertex  = new int[count];

            numWeights = 0;
            var maxweight = 0;

            for (i = 0; i < texCoords.Length; i++)
            {
                parser.ExpectTokenString("vert"); parser.ParseInt();

                fixed(float *textCoordsF = &texCoords[i].x) parser.Parse1DMatrix(2, textCoordsF);

                firstWeightForVertex[i] = parser.ParseInt();
                numWeightsForVertex[i]  = parser.ParseInt();
                if (numWeightsForVertex[i] == 0)
                {
                    parser.Error("Vertex without any joint weights.");
                }

                numWeights += numWeightsForVertex[i];
                if (numWeightsForVertex[i] + firstWeightForVertex[i] > maxweight)
                {
                    maxweight = numWeightsForVertex[i] + firstWeightForVertex[i];
                }
            }

            // parse tris
            parser.ExpectTokenString("numtris");
            count = parser.ParseInt();
            if (count < 0)
            {
                parser.Error($"Invalid size: {count}");
            }

            tris    = new int[count * 3];
            numTris = count;
            for (i = 0; i < count; i++)
            {
                parser.ExpectTokenString("tri"); parser.ParseInt();
                tris[i * 3 + 0] = parser.ParseInt();
                tris[i * 3 + 1] = parser.ParseInt();
                tris[i * 3 + 2] = parser.ParseInt();
            }

            // parse weights
            parser.ExpectTokenString("numweights"); count = parser.ParseInt();
            if (count < 0)
            {
                parser.Error($"Invalid size: {count}");
            }

            if (maxweight > count)
            {
                parser.Warning($"Vertices reference out of range weights in model ({maxweight} of {count} weights).");
            }

            tempWeights = new VertexWeight[count];
            for (i = 0; i < count; i++)
            {
                parser.ExpectTokenString("weight"); parser.ParseInt();

                jointnum = parser.ParseInt();
                if ((jointnum < 0) || (jointnum >= numJoints))
                {
                    parser.Error($"Joint Index out of range({numJoints}): {jointnum}");
                }
                tempWeights[i].joint       = jointnum;
                tempWeights[i].jointWeight = parser.ParseFloat();

                fixed(float *offsetF = &tempWeights[i].offset.x) parser.Parse1DMatrix(3, offsetF);
            }

            // create pre-scaled weights and an index for the vertex/joint lookup
            scaledWeights = new Vector4[numWeights];
            weightIndex   = new int[numWeights * 2];

            count = 0;
            for (i = 0; i < texCoords.Length; i++)
            {
                num = firstWeightForVertex[i];
                for (j = 0; j < numWeightsForVertex[i]; j++, num++, count++)
                {
                    scaledWeights[count].ToVec3() = tempWeights[num].offset * tempWeights[num].jointWeight;
                    scaledWeights[count].w        = tempWeights[num].jointWeight;
                    weightIndex[count * 2 + 0]    = tempWeights[num].joint * sizeof(JointMat);
                }
                weightIndex[count * 2 - 1] = 1;
            }

            tempWeights          = null;
            numWeightsForVertex  = null;
            firstWeightForVertex = null;

            parser.ExpectTokenString("}");

            // update counters
            c_numVerts   += texCoords.Length;
            c_numWeights += numWeights;
            c_numWeightJoints++;
            for (i = 0; i < numWeights; i++)
            {
                c_numWeightJoints += weightIndex[i * 2 + 1];
            }

            // build the information that will be common to all animations of this mesh: silhouette edge connectivity and normal / tangent generation information
            //
            //DG: windows only has a 1MB stack and it could happen that we try to allocate >1MB here (in lost mission mod, game/le_hell map), causing a stack overflow to prevent that, use heap allocation if it's >600KB
            var verts = texCoords.Length * sizeof(DrawVert) < 600000
                ? stackalloc DrawVert[texCoords.Length + DrawVert.ALLOC16]
                : new DrawVert[texCoords.Length + DrawVert.ALLOC16];

            verts = Platform._alloca16(verts);

            for (i = 0; i < texCoords.Length; i++)
            {
                verts[i].Clear(); verts[i].st = texCoords[i];
            }
            fixed(DrawVert *vertsD = verts)
            fixed(JointMat * jointsJ = joints)
            TransformVerts(vertsD, jointsJ);

            deformInfo = R_BuildDeformInfo(texCoords.Length, verts, tris.Length, tris, shader.UseUnsmoothedTangents);
        }
Exemplo n.º 8
0
        public static void WritePosedObj(string savePath, Model model, WriteableBitmap texture, AnimData pose, int frame, double scale)
        {
            var dir  = Path.GetDirectoryName(savePath) ?? "";
            var name = Path.GetFileNameWithoutExtension(savePath);

            // Save the texture to a .png file
            using (var stream = new FileStream(Path.Combine(dir, name + ".png"), FileMode.Create))
            {
                var encoder = new PngBitmapEncoder();
                encoder.Frames.Add(BitmapFrame.Create(texture));
                encoder.Save(stream);

                stream.Flush();
                stream.Close();
            }

            WriteMtlFile(Path.Combine(dir, name + ".mtl"), name);

            var objFile = File.Open(Path.Combine(dir, name + ".obj"), FileMode.Create);
            var writer  = new StreamWriter(objFile);

            writer.WriteLine("mtllib " + name + ".mtl");
            writer.WriteLine("");

            var vStart    = 0;
            var meshCount = 1;

            foreach (var mesh in model.meshList)
            {
                writer.WriteLine("g Mesh_" + meshCount);
                writer.WriteLine("usemtl " + name);

                var hasVertexWeights = mesh.vertexWeights.Count > 0;
                var vwNum            = 0;
                var vw = new VertexWeight();
                if (mesh.vertexWeights.Count > 0)
                {
                    vw = mesh.vertexWeights[vwNum];
                }
                var vnum = 0;
                foreach (var vertex in mesh.Positions)
                {
                    var point = vertex;
                    if (frame >= 0 && pose != null)
                    {
                        if (vw.endVertex < vnum)
                        {
                            ++vwNum;
                            vw = mesh.vertexWeights[vwNum];
                            if (vnum < vw.startVertex || vnum > vw.endVertex)
                            {
                                Debug.Fail("Vertex " + vnum + " out of range of bone weights " + vw.startVertex + " -> " + vw.endVertex);
                            }
                        }
                        var bone1No     = vw.bone1;
                        var bindingPos1 = pose.bindingPose[bone1No];
                        var bone1Pose   = pose.perFrameFKPoses[frame, bone1No];
                        var joint1Pos   = bone1Pose.Position;
                        if (vw.bone2 == 0xFF)
                        {
                            if (bone1No == 1)
                            {
                                bone1No = 1;
                            }
                            var m = Matrix3D.Identity;
                            m.Translate(new Vector3D(-bindingPos1.X, -bindingPos1.Y, -bindingPos1.Z));   // Inverse binding matrix
                            m.Rotate(bone1Pose.Rotation);
                            m.Translate(new Vector3D(bone1Pose.Position.X, bone1Pose.Position.Y, bone1Pose.Position.Z));
                            point = m.Transform(point);
                        }
                        else
                        {
                            // multi-bone
                            var    bone2No     = vw.bone2;
                            var    bindingPos2 = pose.bindingPose[bone2No];
                            var    bone2Pose   = pose.perFrameFKPoses[frame, bone2No];
                            double boneSum     = vw.boneWeight1 + vw.boneWeight2;
                            var    bone1Coeff  = vw.boneWeight1 / boneSum;
                            var    bone2Coeff  = vw.boneWeight2 / boneSum;

                            var m = Matrix3D.Identity;
                            m.Translate(new Vector3D(-bindingPos1.X, -bindingPos1.Y, -bindingPos1.Z));   // Inverse binding matrix
                            m.Rotate(bone1Pose.Rotation);
                            m.Translate(new Vector3D(bone1Pose.Position.X, bone1Pose.Position.Y, bone1Pose.Position.Z));
                            var point1 = m.Transform(point);

                            // Now rotate
                            var m2 = Matrix3D.Identity;
                            m2.Translate(new Vector3D(-bindingPos2.X, -bindingPos2.Y, -bindingPos2.Z));   // Inverse binding matrix
                            m2.Rotate(bone2Pose.Rotation);
                            m2.Translate(new Vector3D(bone2Pose.Position.X, bone2Pose.Position.Y, bone2Pose.Position.Z));
                            var point2 = m2.Transform(point);

                            point = new Point3D(point1.X * bone1Coeff + point2.X * bone2Coeff, point1.Y * bone1Coeff + point2.Y * bone2Coeff, point1.Z * bone1Coeff + point2.Z * bone2Coeff);
                        }
                    }
                    ++vnum;
                    writer.WriteLine("v {0} {1} {2}",
                                     FormatDouble(point.X / scale),
                                     FormatDouble(point.Y / scale),
                                     FormatDouble(point.Z / scale));
                }
                writer.WriteLine("");

                foreach (var uv in mesh.TextureCoordinates)
                {
                    writer.WriteLine("vt {0} {1}",
                                     FormatDouble(uv.X),
                                     FormatDouble(1 - uv.Y)); // Flip uv's vertically
                }
                writer.WriteLine("");

                foreach (var vec in mesh.Normals)
                {
                    // TODO: If the mesh is posed, the normals needs modifying too.
                    writer.WriteLine("vn {0} {1} {2}",
                                     FormatDouble(vec.X),
                                     FormatDouble(vec.Y),
                                     FormatDouble(vec.Z));
                }
                writer.WriteLine("");

                for (var i = 0; i < mesh.TriangleIndices.Count - 3; i += 6)
                {
                    writer.WriteLine("f {0}/{1}/{2} {3}/{4}/{5} {6}/{7}/{8}",
                                     mesh.TriangleIndices[i] + 1 + vStart,
                                     mesh.TriangleIndices[i] + 1 + vStart,
                                     mesh.TriangleIndices[i] + 1 + vStart,

                                     mesh.TriangleIndices[i + 1] + 1 + vStart,
                                     mesh.TriangleIndices[i + 1] + 1 + vStart,
                                     mesh.TriangleIndices[i + 1] + 1 + vStart,

                                     mesh.TriangleIndices[i + 2] + 1 + vStart,
                                     mesh.TriangleIndices[i + 2] + 1 + vStart,
                                     mesh.TriangleIndices[i + 2] + 1 + vStart);
                }
                writer.WriteLine("");

                vStart += mesh.Positions.Count;
                meshCount++;
            }

            writer.Flush();
            writer.Close();
        }
Exemplo n.º 9
0
        private static Assimp.Scene GetPMOScene(Pmo pmo)
        {
            Assimp.Scene scene = new Assimp.Scene();
            scene.RootNode = new Assimp.Node("root");

            // Add materials.
            List <Material> matList = new List <Material>();

            for (int t = 0; t < pmo.header.TextureCount; t++)
            {
                Material mat = new Material();
                mat.Clear();
                mat.Name = pmo.textureInfo[t].TextureName;
                scene.Materials.Add(mat);
            }

            // Add skeleton.
            List <Node> Skeleton = new List <Node>();

            for (int b = 0; b < pmo.skeletonHeader.BoneCount; b++)
            {
                Pmo.BoneData bn = pmo.boneList[b];

                Assimp.Matrix4x4 mtx = new Assimp.Matrix4x4();
                mtx.A1 = bn.Transform.M11;
                mtx.A2 = bn.Transform.M12;
                mtx.A3 = bn.Transform.M13;
                mtx.A4 = bn.Transform.M14;
                mtx.B1 = bn.Transform.M21;
                mtx.B2 = bn.Transform.M22;
                mtx.B3 = bn.Transform.M23;
                mtx.B4 = bn.Transform.M24;
                mtx.C1 = bn.Transform.M31;
                mtx.C2 = bn.Transform.M32;
                mtx.C3 = bn.Transform.M33;
                mtx.C4 = bn.Transform.M34;
                mtx.D1 = bn.Transform.M41;
                mtx.D2 = bn.Transform.M42;
                mtx.D3 = bn.Transform.M43;
                mtx.D4 = bn.Transform.M44;

                Assimp.Matrix4x4 nd_mtx = mtx;
                nd_mtx.Transpose();
                if (bn.ParentBoneIndex == 0xFFFF)
                {
                    Node curNode = new Node(bn.JointName);
                    curNode.Transform = nd_mtx;
                    scene.RootNode.Children.Add(curNode);
                    Skeleton.Add(curNode);
                }
                else
                {
                    Node curNode = new Node(bn.JointName, Skeleton[bn.ParentBoneIndex]);

                    nd_mtx.A4 *= 100.0f;
                    nd_mtx.B4 *= 100.0f;
                    nd_mtx.C4 *= 100.0f;

                    curNode.Transform = nd_mtx;
                    Skeleton.Add(curNode);
                    scene.RootNode.FindNode(Skeleton[bn.ParentBoneIndex].Name).Children.Add(curNode);
                }
            }

            // Add meshes.
            for (int i = 0; i < pmo.Meshes.Count; i++)
            {
                Assimp.Mesh    mesh  = new Assimp.Mesh($"Mesh{i}", Assimp.PrimitiveType.Triangle);
                Pmo.MeshChunks chunk = pmo.Meshes[i];

                // Add vertices, vertex color and normals.
                for (int j = 0; j < chunk.vertices.Count; j++)
                {
                    mesh.Vertices.Add(new Assimp.Vector3D(
                                          chunk.vertices[j].X * pmo.header.ModelScale * 100.0f,
                                          chunk.vertices[j].Y * pmo.header.ModelScale * 100.0f,
                                          chunk.vertices[j].Z * pmo.header.ModelScale * 100.0f));

                    mesh.VertexColorChannels[0].Add(new Color4D(1.0f, 1.0f, 1.0f, 1.0f));
                    mesh.Normals.Add(new Vector3D());
                }
                mesh.SetIndices(chunk.Indices.ToArray(), 3);
                mesh.MaterialIndex = chunk.SectionInfo.TextureID;
                scene.Meshes.Add(mesh);

                for (int v = 0; v < chunk.vertices.Count; v++)
                {
                    // Build bone influences.
                    for (int z = 0; z < chunk.SectionInfo_opt1.SectionBoneIndices.Length; z++)
                    {
                        if (chunk.SectionInfo_opt1.SectionBoneIndices[z] != 0xFF)
                        {
                            Pmo.BoneData currentBone = new Pmo.BoneData();

                            int currentIndex = chunk.SectionInfo_opt1.SectionBoneIndices[z];
                            currentBone = pmo.boneList[currentIndex];

                            string           boneName = currentBone.JointName;
                            Assimp.Matrix4x4 mtx      = new Assimp.Matrix4x4();
                            mtx.A1 = currentBone.Transform.M11;
                            mtx.A2 = currentBone.Transform.M12;
                            mtx.A3 = currentBone.Transform.M13;
                            mtx.A4 = currentBone.Transform.M14;
                            mtx.B1 = currentBone.Transform.M21;
                            mtx.B2 = currentBone.Transform.M22;
                            mtx.B3 = currentBone.Transform.M23;
                            mtx.B4 = currentBone.Transform.M24;
                            mtx.C1 = currentBone.Transform.M31;
                            mtx.C2 = currentBone.Transform.M32;
                            mtx.C3 = currentBone.Transform.M33;
                            mtx.C4 = currentBone.Transform.M34;
                            mtx.D1 = currentBone.Transform.M41;
                            mtx.D2 = currentBone.Transform.M42;
                            mtx.D3 = currentBone.Transform.M43;
                            mtx.D4 = currentBone.Transform.M44;
                            Matrix3x3 mtx3 = new Matrix3x3(mtx);

                            mtx.Transpose();

                            mtx.A4 *= 100.0f;
                            mtx.B4 *= 100.0f;
                            mtx.C4 *= 100.0f;


                            mtx3.Transpose();

                            List <VertexWeight> weight = new List <VertexWeight>();

                            VertexWeight vW = new VertexWeight();
                            vW.VertexID = v;

                            float currentWeight = chunk.jointWeights[v].weights[z];

                            switch (chunk.jointWeights[v].coordFormart)
                            {
                            case Pmo.CoordinateFormat.NO_VERTEX:
                                break;

                            case Pmo.CoordinateFormat.NORMALIZED_8_BITS:
                                currentWeight *= 127.0f;
                                currentWeight /= 128.0f;
                                break;

                            case Pmo.CoordinateFormat.NORMALIZED_16_BITS:
                                currentWeight *= 32767.0f;
                                currentWeight /= 32768.0f;
                                break;

                            case Pmo.CoordinateFormat.FLOAT_32_BITS:
                                break;
                            }

                            vW.Weight = currentWeight;
                            weight.Add(vW);

                            Bone tempBone = scene.Meshes[i].Bones.Find(x => x.Name == boneName);
                            int  boneInd  = scene.Meshes[i].Bones.FindIndex(0, x => x.Name == boneName);

                            if (tempBone == null)
                            {
                                Bone bone = new Bone(boneName, mtx3, weight.ToArray());
                                scene.Meshes[i].Bones.Add(bone);
                            }
                            else
                            {
                                scene.Meshes[i].Bones[boneInd].VertexWeights.Add(vW);
                            }
                        }
                    }
                }
            }

            scene.RootNode.MeshIndices.AddRange(Enumerable.Range(0, scene.MeshCount));

            return(scene);
        }
Exemplo n.º 10
0
        protected void ProcessMesh(Assimp.Mesh m)
        {
            var newMesh = new Mesh
            {
                Name     = m.Name,
                Material = _materials[m.MaterialIndex]
            };

            _meshes.Add(newMesh);

            uint[] indices        = m.GetUnsignedIndices();
            var    emotionIndices = new ushort[indices.Length];

            for (var i = 0; i < indices.Length; i++)
            {
                emotionIndices[i] = (ushort)indices[i];
            }

            newMesh.Indices = emotionIndices;

            var vertices = new VertexDataWithBones[m.VertexCount];

            for (var i = 0; i < m.VertexCount; i++)
            {
                // todo: check if uvs exist, vert colors, normals
                Vector3D vertex = m.Vertices[i];
                Vector3D uv     = m.TextureCoordinateChannels[0][i];
                vertices[i] = new VertexDataWithBones
                {
                    Vertex = new Vector3(vertex.X, vertex.Y, vertex.Z),
                    UV     = new Vector2(uv.X, uv.Y),

                    BoneIds     = new Vector4(0),
                    BoneWeights = new Vector4(1, 0, 0, 0)
                };
            }

            newMesh.VerticesWithBones = vertices;

            if (!m.HasBones)
            {
                return;
            }

            _boneToIndex ??= new Dictionary <string, int>();
            var bones = new MeshBone[m.BoneCount];

            newMesh.Bones = bones;
            for (var i = 0; i < m.Bones.Count; i++)
            {
                Bone bone   = m.Bones[i];
                var  emBone = new MeshBone
                {
                    Name         = bone.Name,
                    OffsetMatrix = AssMatrixToEmoMatrix(bone.OffsetMatrix)
                };
                bones[i] = emBone;

                // Check if this bone has an id assigned.
                if (!_boneToIndex.TryGetValue(bone.Name, out int boneIndex))
                {
                    boneIndex = _boneToIndex.Count + 1;
                    _boneToIndex.Add(bone.Name, boneIndex);
                }

                emBone.BoneIndex = boneIndex;

                for (var j = 0; j < bone.VertexWeightCount; j++)
                {
                    VertexWeight            boneDef = bone.VertexWeights[j];
                    ref VertexDataWithBones vertex  = ref vertices[boneDef.VertexID];

                    // Todo: better way of doing this
                    if (vertex.BoneIds.X == 0)
                    {
                        vertex.BoneIds.X     = boneIndex;
                        vertex.BoneWeights.X = boneDef.Weight;
                    }
                    else if (vertex.BoneIds.Y == 0)
                    {
                        vertex.BoneIds.Y     = boneIndex;
                        vertex.BoneWeights.Y = boneDef.Weight;
                    }
                    else if (vertex.BoneIds.Z == 0)
                    {
                        vertex.BoneIds.Z     = boneIndex;
                        vertex.BoneWeights.Z = boneDef.Weight;
                    }
                    else if (vertex.BoneIds.W == 0)
                    {
                        vertex.BoneIds.W     = boneIndex;
                        vertex.BoneWeights.W = boneDef.Weight;
                    }
                    else
                    {
                        Engine.Log.Warning($"Bone {bone.Name} affects more than 4 vertices in mesh {m.Name}.", "Assimp", true);
                    }
                }
            }
Exemplo n.º 11
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="pobj"></param>
        private Mesh ProcessPOBJ(HSD_POBJ pobj, HSD_JOBJ parent, HSD_JOBJ singleBind)
        {
            Mesh m = new Mesh();

            m.Name          = "pobj";
            m.PrimitiveType = PrimitiveType.Triangle;

            m.MaterialIndex = 0;

            var dl        = pobj.ToDisplayList();
            var envelopes = pobj.EnvelopeWeights;

            var parentTransform = Matrix4.Identity;

            if (parent != null)
            {
                parentTransform = WorldTransforms[jobjToIndex[parent]];
            }

            var singleBindTransform = Matrix4.Identity;

            if (singleBind != null)
            {
                singleBindTransform = WorldTransforms[jobjToIndex[singleBind]];
            }

            Dictionary <HSD_JOBJ, Bone> jobjToBone = new Dictionary <HSD_JOBJ, Bone>();

            if (envelopes != null)
            {
                foreach (var jobj in Jobjs)
                {
                    var bone = new Bone();
                    bone.Name         = JobjNodes[jobjToIndex[jobj]].Name;
                    bone.OffsetMatrix = Matrix4ToMatrix4x4(WorldTransforms[jobjToIndex[jobj]].Inverted());
                    m.Bones.Add(bone);
                    jobjToBone.Add(jobj, bone);
                }
            }

            /*foreach (var en in envelopes)
             * {
             *  foreach (var jobj in en.JOBJs)
             *  {
             *      if (!jobjToBone.ContainsKey(jobj))
             *      {
             *          var bone = new Bone();
             *          bone.Name = JobjNodes[jobjToIndex[jobj]].Name;
             *          bone.OffsetMatrix = Matrix4ToMatrix4x4(WorldTransforms[jobjToIndex[jobj]].Inverted());
             *          m.Bones.Add(bone);
             *          jobjToBone.Add(jobj, bone);
             *      }
             *  }
             * }*/


            if (singleBind != null && !jobjToBone.ContainsKey(singleBind))
            {
                var bone = new Bone();
                bone.Name         = JobjNodes[jobjToIndex[singleBind]].Name;
                bone.OffsetMatrix = Matrix4ToMatrix4x4(WorldTransforms[jobjToIndex[singleBind]].Inverted());
                m.Bones.Add(bone);
                jobjToBone.Add(singleBind, bone);
            }

            int offset = 0;
            var vIndex = -1;

            foreach (var prim in dl.Primitives)
            {
                var verts = dl.Vertices.GetRange(offset, prim.Count);
                offset += prim.Count;

                switch (prim.PrimitiveType)
                {
                case GXPrimitiveType.Quads:
                    verts = TriangleConverter.QuadToList(verts);
                    break;

                case GXPrimitiveType.TriangleStrip:
                    verts = TriangleConverter.StripToList(verts);
                    break;

                case GXPrimitiveType.Triangles:
                    break;

                default:
                    Console.WriteLine(prim.PrimitiveType);
                    break;
                }

                for (int i = m.VertexCount; i < m.VertexCount + verts.Count; i += 3)
                {
                    var f = new Face();
                    f.Indices.Add(i);
                    f.Indices.Add(i + 1);
                    f.Indices.Add(i + 2);
                    m.Faces.Add(f);
                }

                foreach (var v in verts)
                {
                    vIndex++;
                    if (singleBind != null)
                    {
                        var vertexWeight = new VertexWeight();
                        vertexWeight.VertexID = vIndex;
                        vertexWeight.Weight   = 1;
                        jobjToBone[singleBind].VertexWeights.Add(vertexWeight);
                    }
                    Matrix4 weight = Matrix4.Identity;
                    foreach (var a in pobj.Attributes)
                    {
                        switch (a.AttributeName)
                        {
                        case GXAttribName.GX_VA_PNMTXIDX:

                            var en = envelopes[v.PNMTXIDX / 3];
                            for (int w = 0; w < en.EnvelopeCount; w++)
                            {
                                var vertexWeight = new VertexWeight();
                                vertexWeight.VertexID = vIndex;
                                vertexWeight.Weight   = en.Weights[w];
                                jobjToBone[en.JOBJs[w]].VertexWeights.Add(vertexWeight);
                            }

                            if (en.EnvelopeCount == 1 && jobjToIndex[parent] == 0)
                            {
                                weight = WorldTransforms[jobjToIndex[en.JOBJs[0]]];
                            }

                            break;

                        case GXAttribName.GX_VA_POS:
                            var vert = Vector3.TransformPosition(GXTranslator.toVector3(v.POS), parentTransform);
                            vert = Vector3.TransformPosition(vert, weight);
                            vert = Vector3.TransformPosition(vert, singleBindTransform);
                            m.Vertices.Add(new Vector3D(vert.X, vert.Y, vert.Z));
                            break;

                        case GXAttribName.GX_VA_NRM:
                            var nrm = Vector3.TransformNormal(GXTranslator.toVector3(v.NRM), parentTransform);
                            nrm = Vector3.TransformNormal(nrm, weight);
                            nrm = Vector3.TransformNormal(nrm, singleBindTransform);
                            m.Normals.Add(new Vector3D(nrm.X, nrm.Y, nrm.Z));
                            break;

                        case GXAttribName.GX_VA_CLR0:
                            m.VertexColorChannels[0].Add(new Color4D(v.CLR0.R, v.CLR0.G, v.CLR0.B, v.CLR0.A));
                            break;

                        case GXAttribName.GX_VA_CLR1:
                            m.VertexColorChannels[1].Add(new Color4D(v.CLR1.R, v.CLR1.G, v.CLR1.B, v.CLR1.A));
                            break;

                        case GXAttribName.GX_VA_TEX0:
                            m.TextureCoordinateChannels[0].Add(new Vector3D(v.TEX0.X, v.TEX0.Y, 1));
                            break;

                        case GXAttribName.GX_VA_TEX1:
                            m.TextureCoordinateChannels[1].Add(new Vector3D(v.TEX1.X, v.TEX1.Y, 1));
                            break;

                        case GXAttribName.GX_VA_TEX2:
                            m.TextureCoordinateChannels[2].Add(new Vector3D(v.TEX2.X, v.TEX2.Y, 1));
                            break;

                        case GXAttribName.GX_VA_TEX3:
                            m.TextureCoordinateChannels[3].Add(new Vector3D(v.TEX3.X, v.TEX3.Y, 1));
                            break;

                        case GXAttribName.GX_VA_TEX4:
                            m.TextureCoordinateChannels[4].Add(new Vector3D(v.TEX4.X, v.TEX4.Y, 1));
                            break;

                        case GXAttribName.GX_VA_TEX5:
                            m.TextureCoordinateChannels[5].Add(new Vector3D(v.TEX5.X, v.TEX5.Y, 1));
                            break;

                        case GXAttribName.GX_VA_TEX6:
                            m.TextureCoordinateChannels[6].Add(new Vector3D(v.TEX6.X, v.TEX6.Y, 1));
                            break;

                        case GXAttribName.GX_VA_TEX7:
                            m.TextureCoordinateChannels[7].Add(new Vector3D(v.TEX7.X, v.TEX7.Y, 1));
                            break;
                        }
                    }
                }
            }

            return(m);
        }
Exemplo n.º 12
0
		/// <summary>
		/// Creates controllers to skin each geometry in the collada file
		/// </summary>
		void CreateControllerList()
		{
			H1.Tags.gbxmodel_group definition = tagManager.TagDefinition as H1.Tags.gbxmodel_group;

			// if there are no nodes then no skinning is possible
			if (definition.Nodes.Count == 0)
				return;

			// create a controller for each geometry
			for (int i = 0; i < modelInfo.GetGeometryCount(); i++)
			{
				List<VertexWeight> vertex_weights = new List<VertexWeight>();

				//  create a list of vertex weights from all of the geometry parts
				foreach (var part in definition.Geometries[modelInfo.GetGeometryIndex(i)].Parts)
				{
					foreach (var vertex in part.UncompressedVertices)
					{
						VertexWeight vertex_weight = new VertexWeight();

						int node1 = vertex.NodeIndex1;
						int node2 = vertex.NodeIndex2;

						// if the bone index count is 0 then the index references the main node list,
						// otherwise it references a local node map for this part
						if (part.NodeMapCount != 0)
						{
							node1 = part.NodeMap[node1];
							node2 = (node2 != -1 ? part.NodeMap[node2].Value : node2);
						}

						vertex_weight.AddWeight(node1, vertex.NodeWeight1);

						// if the first weight is 1 the vertex is weighted to one bone only so the second weight is not needed
						if(vertex.NodeWeight1 != 1)
							vertex_weight.AddWeight(node2, vertex.NodeWeight2);

						vertex_weights.Add(vertex_weight);
					}
				}

				// create the controller element
				CreateSkinController(listGeometry[i].ID, vertex_weights);
			}
		}
Exemplo n.º 13
0
        public static Model3D CreateModel3D(List <Mesh> meshGroups, BitmapSource texture, AnimData pose, int frame)
        {
            var model  = new GeometryModel3D();
            var mesh3D = new MeshGeometry3D();

            var numVertices = 0;

            foreach (var meshGroup in meshGroups)
            {
                numVertices += meshGroup.Positions.Count;
            }
            var triangleIndices = new Int32Collection();
            var positions       = new Point3DCollection(numVertices);
            var normals         = new Vector3DCollection(numVertices);
            var uvCoords        = new PointCollection(numVertices);
            var vstart          = 0;

            foreach (var meshGroup in meshGroups)
            {
                var hasVertexWeights = meshGroup.vertexWeights.Count > 0;
                var vwNum            = 0;
                var vw = new VertexWeight();
                if (meshGroup.vertexWeights.Count > 0)
                {
                    vw = meshGroup.vertexWeights[vwNum];
                }
                var vnum = 0;
                foreach (var vertex in meshGroup.Positions)
                {
                    var point = vertex;
                    if (frame >= 0 && pose != null)
                    {
                        if (vw.endVertex < vnum)
                        {
                            ++vwNum;
                            vw = meshGroup.vertexWeights[vwNum];
                            if (vnum < vw.startVertex || vnum > vw.endVertex)
                            {
                                Debug.Fail("Vertex " + vnum + " out of range of bone weights " + vw.startVertex + " -> " + vw.endVertex);
                            }
                        }
                        var bone1No     = vw.bone1;
                        var bindingPos1 = pose.bindingPose[bone1No];
                        var bone1Pose   = pose.perFrameFKPoses[frame, bone1No];
                        var joint1Pos   = bone1Pose.Position;
                        if (vw.bone2 == 0xFF)
                        {
                            if (bone1No == 1)
                            {
                                bone1No = 1;
                            }
                            var m = Matrix3D.Identity;
                            m.Translate(new Vector3D(-bindingPos1.X, -bindingPos1.Y, -bindingPos1.Z));   // Inverse binding matrix
                            m.Rotate(bone1Pose.Rotation);
                            m.Translate(new Vector3D(bone1Pose.Position.X, bone1Pose.Position.Y, bone1Pose.Position.Z));
                            point = m.Transform(point);
                        }
                        else
                        {
                            // multi-bone
                            var    bone2No     = vw.bone2;
                            var    bindingPos2 = pose.bindingPose[bone2No];
                            var    bone2Pose   = pose.perFrameFKPoses[frame, bone2No];
                            double boneSum     = vw.boneWeight1 + vw.boneWeight2;
                            var    bone1Coeff  = vw.boneWeight1 / boneSum;
                            var    bone2Coeff  = vw.boneWeight2 / boneSum;

                            var m = Matrix3D.Identity;
                            m.Translate(new Vector3D(-bindingPos1.X, -bindingPos1.Y, -bindingPos1.Z));   // Inverse binding matrix
                            m.Rotate(bone1Pose.Rotation);
                            m.Translate(new Vector3D(bone1Pose.Position.X, bone1Pose.Position.Y, bone1Pose.Position.Z));
                            var point1 = m.Transform(point);

                            // Now rotate
                            var m2 = Matrix3D.Identity;
                            m2.Translate(new Vector3D(-bindingPos2.X, -bindingPos2.Y, -bindingPos2.Z));   // Inverse binding matrix
                            m2.Rotate(bone2Pose.Rotation);
                            m2.Translate(new Vector3D(bone2Pose.Position.X, bone2Pose.Position.Y, bone2Pose.Position.Z));
                            var point2 = m2.Transform(point);

                            point = new Point3D(point1.X * bone1Coeff + point2.X * bone2Coeff, point1.Y * bone1Coeff + point2.Y * bone2Coeff, point1.Z * bone1Coeff + point2.Z * bone2Coeff);
                        }
                    }
                    positions.Add(point);
                    ++vnum;
                }
                foreach (var normal in meshGroup.Normals)
                {
                    normals.Add(normal);
                }
                foreach (var ti in meshGroup.TriangleIndices)
                {
                    triangleIndices.Add(ti + vstart);
                }
                foreach (var uv in meshGroup.TextureCoordinates)
                {
                    uvCoords.Add(uv);
                }
                vstart += meshGroup.Positions.Count;
            }
            mesh3D.TriangleIndices    = triangleIndices;
            mesh3D.Positions          = positions;
            mesh3D.TextureCoordinates = uvCoords;
            mesh3D.Normals            = normals;
            model.Geometry            = mesh3D;
            var dm = new DiffuseMaterial();

            if (texture != null && texture.Width > 0 && texture.Height > 0)
            {
                var ib = new ImageBrush(texture)
                {
                    ViewportUnits = BrushMappingMode.Absolute
                };
                // May be needed at a later point
                //ib.TileMode = TileMode.Tile;
                dm.Brush = ib;
            }
            else
            {
                var dg = new DrawingGroup();
                // Background
                dg.Children.Add(new GeometryDrawing()
                {
                    Brush    = new SolidColorBrush(Colors.Black),
                    Geometry = new RectangleGeometry(new Rect(0, 0, 2, 2))
                });

                // Tiles
                dg.Children.Add(new GeometryDrawing()
                {
                    Brush    = new SolidColorBrush(Colors.Violet),
                    Geometry = new RectangleGeometry(new Rect(0, 0, 1, 1))
                });
                dg.Children.Add(new GeometryDrawing()
                {
                    Brush    = new SolidColorBrush(Colors.Violet),
                    Geometry = new RectangleGeometry(new Rect(1, 1, 1, 1))
                });

                dm.Brush = new DrawingBrush(dg)
                {
                    TileMode = TileMode.Tile, Transform = new ScaleTransform(0.1, 0.1)
                };
            }
            model.Material = dm;
            return(model);
        }
Exemplo n.º 14
0
        public static Mesh ChunksToMesh(ILogger log, List <Chunk> chunks, int texturePixelWidth, int texturePixelHeight)
        {
            Mesh mesh        = new Mesh();
            int  numVertices = 0;

            foreach (Chunk chunk in chunks)
            {
                numVertices += chunk.vertices.Count;
            }
            mesh.TriangleIndices = new Int32Collection();
            mesh.Positions       = new Point3DCollection(numVertices);
            mesh.Normals         = new Vector3DCollection(numVertices);
            mesh.vertexWeights   = new List <VertexWeight>();
            var   uvCoords    = new Point[numVertices];
            Point uninitPoint = new Point(-10000, -10000);

            for (int uv = 0; uv < uvCoords.Length; ++uv)
            {
                uvCoords[uv] = uninitPoint;
            }
            int vstart = 0;

            foreach (var chunk in chunks)
            {
                if ((chunk.gifTag0.prim & 0x07) != 4)
                {
                    Debug.Fail("Can only deal with tri strips");
                }

                foreach (var vertex in chunk.vertices)
                {
                    var point = new Point3D(vertex.x / 16.0, vertex.y / 16.0, vertex.z / 16.0);
                    mesh.Positions.Add(point);
                }
                foreach (var normal in chunk.normals)
                {
                    mesh.Normals.Add(new Vector3D(normal.x / 127.0, normal.y / 127.0, normal.z / 127.0));
                }
                foreach (VertexWeight vw in chunk.vertexWeights)
                {
                    VertexWeight vwAdjusted = vw;
                    vwAdjusted.startVertex += vstart;
                    if (vwAdjusted.endVertex >= chunk.vertices.Count)
                    {
                        vwAdjusted.endVertex = chunk.vertices.Count - 1;
                    }
                    vwAdjusted.endVertex += vstart;
                    if (vw.startVertex <= (chunk.vertices.Count - 1))
                    {
                        mesh.vertexWeights.Add(vwAdjusted);
                    }
                }
                int[] vstrip          = new int[chunk.gifTag0.nloop];
                int   regsPerVertex   = chunk.gifTag0.nreg;
                int   numVlocs        = chunk.vlocs.Count;
                int   numVertsInChunk = chunk.vertices.Count;
                for (int vlocIndx = 2; vlocIndx < numVlocs; ++vlocIndx)
                {
                    int v         = vlocIndx - 2;
                    int stripIdx2 = (chunk.vlocs[vlocIndx].v2 & 0x1FF) / regsPerVertex;
                    int stripIdx3 = (chunk.vlocs[vlocIndx].v3 & 0x1FF) / regsPerVertex;
                    if (stripIdx3 < vstrip.Length && stripIdx2 < vstrip.Length)
                    {
                        vstrip[stripIdx3] = vstrip[stripIdx2] & 0x1FF;

                        bool skip2 = (chunk.vlocs[vlocIndx].v3 & 0x8000) == 0x8000;
                        if (skip2)
                        {
                            vstrip[stripIdx3] |= 0x8000;
                        }
                    }
                    int  stripIdx = (chunk.vlocs[vlocIndx].v1 & 0x1FF) / regsPerVertex;
                    bool skip     = (chunk.vlocs[vlocIndx].v1 & 0x8000) == 0x8000;

                    if (v < numVertsInChunk && stripIdx < vstrip.Length)
                    {
                        vstrip[stripIdx] = skip ? (v | 0x8000) : v;
                    }
                }
                int numExtraVlocs = chunk.extraVlocs[0];
                for (int extraVloc = 0; extraVloc < numExtraVlocs; ++extraVloc)
                {
                    int idx           = extraVloc * 4 + 4;
                    int stripIndxSrc  = (chunk.extraVlocs[idx] & 0x1FF) / regsPerVertex;
                    int stripIndxDest = (chunk.extraVlocs[idx + 1] & 0x1FF) / regsPerVertex;;
                    vstrip[stripIndxDest] = (chunk.extraVlocs[idx + 1] & 0x8000) | (vstrip[stripIndxSrc] & 0x1FF);

                    stripIndxSrc          = (chunk.extraVlocs[idx + 2] & 0x1FF) / regsPerVertex;
                    stripIndxDest         = (chunk.extraVlocs[idx + 3] & 0x1FF) / regsPerVertex;;
                    vstrip[stripIndxDest] = (chunk.extraVlocs[idx + 3] & 0x8000) | (vstrip[stripIndxSrc] & 0x1FF);
                }
                int triIdx = 0;
                for (int i = 2; i < vstrip.Length; ++i)
                {
                    int vidx1 = vstart + (vstrip[i - 2] & 0xFF);
                    int vidx2 = vstart + (vstrip[i - 1] & 0xFF);
                    int vidx3 = vstart + (vstrip[i] & 0xFF);

                    int uv1 = i - 2;
                    int uv2 = i - 1;
                    int uv3 = i;

                    // Flip the faces (indices 1 and 2) to keep the winding rule consistent.
                    if ((triIdx & 1) == 1)
                    {
                        int temp = uv1;
                        uv1 = uv2;
                        uv2 = temp;

                        temp  = vidx1;
                        vidx1 = vidx2;
                        vidx2 = temp;
                    }

                    if ((vstrip[i] & 0x8000) == 0)
                    {
                        // WPF really has S,T coords rather than u,v
                        double udiv = texturePixelWidth * 16.0;
                        double vdiv = texturePixelHeight * 16.0;

                        var p1 = new Point(chunk.uvs[uv1].u / udiv, chunk.uvs[uv1].v / vdiv);
                        var p2 = new Point(chunk.uvs[uv2].u / udiv, chunk.uvs[uv2].v / vdiv);
                        var p3 = new Point(chunk.uvs[uv3].u / udiv, chunk.uvs[uv3].v / vdiv);

                        p1 = TileST(p1);
                        p2 = TileST(p2);
                        p3 = TileST(p3);

                        if (!uninitPoint.Equals(uvCoords[vidx1]) && !p1.Equals(uvCoords[vidx1]))
                        {
                            // There is more than 1 uv assigment to this vertex, so we need to duplicate it.
                            int originalVIdx = vidx1;
                            vidx1 = vstart + numVertsInChunk;
                            numVertsInChunk++;
                            mesh.Positions.Add(mesh.Positions.ElementAt(originalVIdx));
                            mesh.Normals.Add(mesh.Normals.ElementAt(originalVIdx));
                            Array.Resize(ref uvCoords, uvCoords.Length + 1);
                            uvCoords[uvCoords.Length - 1] = uninitPoint;
                            var weight = FindVertexWeight(chunk.vertexWeights, originalVIdx - vstart);
                            if (weight.boneWeight1 > 0)
                            {
                                var vw = weight;
                                vw.startVertex = vidx1;
                                vw.endVertex   = vidx1;
                                mesh.vertexWeights.Add(vw);
                            }
                        }
                        if (!uninitPoint.Equals(uvCoords[vidx2]) && !p2.Equals(uvCoords[vidx2]))
                        {
                            // There is more than 1 uv assigment to this vertex, so we need to duplicate it.
                            int originalVIdx = vidx2;
                            vidx2 = vstart + numVertsInChunk;
                            numVertsInChunk++;
                            mesh.Positions.Add(mesh.Positions.ElementAt(originalVIdx));
                            mesh.Normals.Add(mesh.Normals.ElementAt(originalVIdx));
                            Array.Resize(ref uvCoords, uvCoords.Length + 1);
                            uvCoords[uvCoords.Length - 1] = uninitPoint;
                            var weight = FindVertexWeight(chunk.vertexWeights, originalVIdx - vstart);
                            if (weight.boneWeight1 > 0)
                            {
                                var vw = weight;
                                vw.startVertex = vidx2;
                                vw.endVertex   = vidx2;
                                mesh.vertexWeights.Add(vw);
                            }
                        }
                        if (!uninitPoint.Equals(uvCoords[vidx3]) && !p3.Equals(uvCoords[vidx3]))
                        {
                            // There is more than 1 uv assigment to this vertex, so we need to duplicate it.
                            int originalVIdx = vidx3;
                            vidx3 = vstart + numVertsInChunk;
                            numVertsInChunk++;
                            mesh.Positions.Add(mesh.Positions.ElementAt(originalVIdx));
                            mesh.Normals.Add(mesh.Normals.ElementAt(originalVIdx));
                            Array.Resize(ref uvCoords, uvCoords.Length + 1);
                            uvCoords[uvCoords.Length - 1] = uninitPoint;
                            var weight = FindVertexWeight(chunk.vertexWeights, originalVIdx - vstart);
                            if (weight.boneWeight1 > 0)
                            {
                                var vw = weight;
                                vw.startVertex = vidx3;
                                vw.endVertex   = vidx3;
                                mesh.vertexWeights.Add(vw);
                            }
                        }

                        uvCoords[vidx1] = p1;
                        uvCoords[vidx2] = p2;
                        uvCoords[vidx3] = p3;

                        // Double sided hack. Should fix this with normals really
                        mesh.TriangleIndices.Add(vidx1);
                        mesh.TriangleIndices.Add(vidx2);
                        mesh.TriangleIndices.Add(vidx3);

                        mesh.TriangleIndices.Add(vidx2);
                        mesh.TriangleIndices.Add(vidx1);
                        mesh.TriangleIndices.Add(vidx3);
                    }
                    ++triIdx;
                }
                vstart += numVertsInChunk;
            }
            mesh.TextureCoordinates = new PointCollection(uvCoords);
            return(mesh);
        }
Exemplo n.º 15
0
        public Model FromScene(Scene scene, string name, AnimationEngine engine)
        {
            if (!scene.HasMeshes)
            {
                throw new Exception("Scene has no meshes!");
            }
            Model model = new Model(name);

            model.OriginalModel = scene;
            model.Root          = convert(scene.RootNode.Transform);
            foreach (Mesh mesh in scene.Meshes)
            {
                if (mesh.Name.ToLower().Contains("collision"))
                {
                    continue;
                }
                ModelMesh modmesh = new ModelMesh(mesh.Name, mesh);
                modmesh.Base = scene;
                modmesh.vbo.Prepare();
                bool hastc = mesh.HasTextureCoords(0);
                bool hasn  = mesh.HasNormals;
                if (!hasn)
                {
                    SysConsole.Output(OutputType.WARNING, "Mesh has no normals!");
                }
                if (!hastc)
                {
                    SysConsole.Output(OutputType.WARNING, "Mesh has no texcoords!");
                }
                for (int i = 0; i < mesh.Vertices.Count; i++)
                {
                    Vector3D vertex = mesh.Vertices[i];
                    modmesh.vbo.Vertices.Add(new Vector3(vertex.X, vertex.Y, vertex.Z));
                    if (!hastc)
                    {
                        modmesh.vbo.TexCoords.Add(new Vector3(0, 0, 0));
                    }
                    else
                    {
                        Vector3D texCoord = mesh.TextureCoordinateChannels[0][i];
                        modmesh.vbo.TexCoords.Add(new Vector3(texCoord.X, 1 - texCoord.Y, texCoord.Z));
                    }
                    if (!hasn)
                    {
                        modmesh.vbo.Normals.Add(new Vector3(0, 0, 1));
                    }
                    else
                    {
                        modmesh.vbo.Normals.Add(new Vector3(mesh.Normals[i].X, mesh.Normals[i].Y, mesh.Normals[i].Z));
                    }
                    modmesh.vbo.Colors.Add(new Vector4(1, 1, 1, 1)); // TODO: From the mesh?
                }
                foreach (Face face in mesh.Faces)
                {
                    if (face.Indices.Count == 3)
                    {
                        for (int i = 2; i >= 0; i--)
                        {
                            modmesh.vbo.Indices.Add((uint)face.Indices[i]);
                        }
                    }
                    else
                    {
                        SysConsole.Output(OutputType.WARNING, "Mesh has face with " + face.Indices.Count + " vertices!");
                    }
                }
                int bc = mesh.Bones.Count;
                if (bc > 70)
                {
                    SysConsole.Output(OutputType.WARNING, "Mesh has " + bc + " bones!");
                    bc = 70;
                }
                modmesh.vbo.BoneIDs     = new Vector4[modmesh.vbo.Vertices.Count].ToList();
                modmesh.vbo.BoneWeights = new Vector4[modmesh.vbo.Vertices.Count].ToList();
                int[] pos = new int[modmesh.vbo.Vertices.Count];
                for (int i = 0; i < bc; i++)
                {
                    for (int x = 0; x < mesh.Bones[i].VertexWeights.Count; x++)
                    {
                        VertexWeight vw   = mesh.Bones[i].VertexWeights[x];
                        int          spot = pos[vw.VertexID]++;
                        if (spot > 3)
                        {
                            //SysConsole.Output(OutputType.WARNING, "Too many bones influencing " + vw.VertexID + "!");
                            ForceSet(modmesh.vbo.BoneWeights, vw.VertexID, 3, modmesh.vbo.BoneWeights[vw.VertexID][3] + vw.Weight);
                        }
                        else
                        {
                            ForceSet(modmesh.vbo.BoneIDs, vw.VertexID, spot, i);
                            ForceSet(modmesh.vbo.BoneWeights, vw.VertexID, spot, vw.Weight);
                        }
                    }
                }
                model.Meshes.Add(modmesh);
                modmesh.GenerateVBO();
            }
            model.RootNode = new ModelNode()
            {
                Internal = scene.RootNode, Parent = null, Name = scene.RootNode.Name.ToLower()
            };
            List <ModelNode> allNodes = new List <ModelNode>();

            PopulateChildren(model.RootNode, scene, model, engine, allNodes);
            for (int i = 0; i < model.Meshes.Count; i++)
            {
                for (int x = 0; x < model.Meshes[i].Original.Bones.Count; x++)
                {
                    ModelNode nodet = null;
                    string    nl    = model.Meshes[i].Original.Bones[x].Name.ToLower();
                    for (int n = 0; n < allNodes.Count; n++)
                    {
                        if (allNodes[n].Name == nl)
                        {
                            nodet = allNodes[n];
                            break;
                        }
                    }
                    ModelBone mb = new ModelBone()
                    {
                        Internal = model.Meshes[i].Original.Bones[x], Offset = convert(model.Meshes[i].Original.Bones[x].OffsetMatrix)
                    };
                    nodet.Bones.Add(mb);
                    model.Meshes[i].Bones.Add(mb);
                }
            }
            return(model);
        }
Exemplo n.º 16
0
        private void RemoveDuplicateVertices(Mesh mesh)
        {
            // Calculate which vertices are duplicates (based on their position, texture coordinates, and normals).
            List <Tuple <Vector3D, Vector3D?, List <Vector3D> > > uniqueVertInfos = new List <Tuple <Vector3D, Vector3D?, List <Vector3D> > >();

            int[]  replaceVertexIDs = new int[mesh.Vertices.Count];
            bool[] vertexIsUnique   = new bool[mesh.Vertices.Count];
            for (var origVertexID = 0; origVertexID < mesh.Vertices.Count; origVertexID++)
            {
                var coordsForVert = new List <Vector3D>();
                for (var i = 0; i < mesh.TextureCoordinateChannelCount; i++)
                {
                    coordsForVert.Add(mesh.TextureCoordinateChannels[i][origVertexID]);
                }

                Vector3D?normal;
                if (origVertexID < mesh.Normals.Count)
                {
                    normal = mesh.Normals[origVertexID];
                }
                else
                {
                    normal = null;
                }

                var vertInfo = new Tuple <Vector3D, Vector3D?, List <Vector3D> >(mesh.Vertices[origVertexID], normal, coordsForVert);

                // Determine if this vertex is a duplicate of a previously encountered vertex or not and if it is keep track of the new index
                var duplicateVertexIndex = -1;
                for (var i = 0; i < uniqueVertInfos.Count; i++)
                {
                    Tuple <Vector3D, Vector3D?, List <Vector3D> > otherVertInfo = uniqueVertInfos[i];
                    if (CheckVertInfosAreDuplicates(vertInfo.Item1, vertInfo.Item2, vertInfo.Item3, otherVertInfo.Item1, otherVertInfo.Item2, otherVertInfo.Item3))
                    {
                        duplicateVertexIndex = i;
                        break;
                    }
                }

                if (duplicateVertexIndex == -1)
                {
                    vertexIsUnique[origVertexID] = true;
                    uniqueVertInfos.Add(vertInfo);
                    replaceVertexIDs[origVertexID] = uniqueVertInfos.Count - 1;
                }
                else
                {
                    vertexIsUnique[origVertexID]   = false;
                    replaceVertexIDs[origVertexID] = duplicateVertexIndex;
                }
            }

            // Remove duplicate vertices, normals, and texture coordinates.
            mesh.Vertices.Clear();
            mesh.Normals.Clear();
            // Need to preserve the channel count since it gets set to 0 when clearing all the channels
            int origTexCoordChannelCount = mesh.TextureCoordinateChannelCount;

            for (var i = 0; i < origTexCoordChannelCount; i++)
            {
                mesh.TextureCoordinateChannels[i].Clear();
            }
            foreach (Tuple <Vector3D, Vector3D?, List <Vector3D> > vertInfo in uniqueVertInfos)
            {
                mesh.Vertices.Add(vertInfo.Item1);
                if (vertInfo.Item2 != null)
                {
                    mesh.Normals.Add(vertInfo.Item2.Value);
                }
                for (var i = 0; i < origTexCoordChannelCount; i++)
                {
                    var coord = vertInfo.Item3[i];
                    mesh.TextureCoordinateChannels[i].Add(coord);
                }
            }

            // Update vertex indices for the faces.
            foreach (Face face in mesh.Faces)
            {
                for (var i = 0; i < face.IndexCount; i++)
                {
                    face.Indices[i] = replaceVertexIDs[face.Indices[i]];
                }
            }

            // Update vertex indices for the bone vertex weights.
            foreach (Bone bone in mesh.Bones)
            {
                List <VertexWeight> origVertexWeights = new List <VertexWeight>(bone.VertexWeights);
                bone.VertexWeights.Clear();
                for (var i = 0; i < origVertexWeights.Count; i++)
                {
                    VertexWeight origWeight   = origVertexWeights[i];
                    int          origVertexID = origWeight.VertexID;
                    if (!vertexIsUnique[origVertexID])
                    {
                        continue;
                    }

                    int          newVertexID = replaceVertexIDs[origVertexID];
                    VertexWeight newWeight   = new VertexWeight(newVertexID, origWeight.Weight);
                    bone.VertexWeights.Add(newWeight);
                }
            }
        }
Exemplo n.º 17
0
		public void SortBones()
		{
			VertexWeight tmp;
			if (this.Bone0.Weight < this.Bone1.Weight)
			{
				tmp = this.Bone0;
				this.Bone0 = this.Bone1;
				this.Bone1 = tmp;
			}
			if (this.Bone2.Weight < this.Bone3.Weight)
			{
				tmp = this.Bone2;
				this.Bone2 = this.Bone3;
				this.Bone3 = tmp;
			}
			if (this.Bone0.Weight < this.Bone2.Weight)
			{
				tmp = this.Bone0;
				this.Bone0 = this.Bone2;
				this.Bone2 = tmp;
			}
			if (this.Bone1.Weight < this.Bone2.Weight)
			{
				tmp = this.Bone1;
				this.Bone1 = this.Bone2;
				this.Bone2 = tmp;
			}
			if (this.Bone2.Weight < this.Bone3.Weight)
			{
				tmp = this.Bone2;
				this.Bone2 = this.Bone3;
				this.Bone3 = tmp;
			}
		}
Exemplo n.º 18
0
		/// <summary>
		/// Creates a controller to skin each geometry in the file
		/// </summary>
		void CreateControllerList()
		{
			H2.Tags.render_model_group definition = tagManager.TagDefinition as H2.Tags.render_model_group;

			// if there are no bones then skinning isnt necessary
			if (definition.Nodes.Count == 0)
				return;

			// create a controller for each geometry in modelInfo
			for (int i = 0; i < modelInfo.GetGeometryCount(); i++)
			{
				H2.Tags.render_model_section_block.render_model_section_data_block section_block = 
					definition.Sections[modelInfo.GetGeometryIndex(i)].SectionData[0];

				// the node map contains a list of bone indices that the section is rigged to
				List<int> node_map = new List<int>();
				foreach (var node in section_block.NodeMap)
					node_map.Add(node.NodeIndex.Value);

				List<VertexWeight> vertex_weights = new List<VertexWeight>();
				// create a generic list of vertex weights
				foreach(var vertex in section_block.Section.Value.RawVertices)
				{
					VertexWeight common_weight = new VertexWeight();

					// only add the weights with valid nodes
					for(int weight_index = 0; (weight_index < vertex.Point.NodeIndex.Length) && (vertex.Point.NodeIndex[weight_index] != -1); weight_index++)
						common_weight.AddWeight(node_map[vertex.Point.NodeIndex[weight_index]], vertex.Point.NodeWeight[weight_index]);

					vertex_weights.Add(common_weight);
				}

				// create the controller element
				CreateSkinController(listGeometry[i].ID, vertex_weights);
			}
		}