Example #1
0
        private void OptimizeData(
            Vector3[] vertices, Vector3[] normals, Vector2[] texCoord, Color[] colors,
            short[] matIds,
            ref byte[][] boneIndices, ref float[][] boneWeights)
        {
            // Hack for meshes without skin
            if (boneIndices.Length == 0)
                boneIndices = null;

            if (boneWeights.Length == 0)
                boneWeights = null;

            // These lists will be used to store the new vertex data
            List<Vector3> newPositions = new List<Vector3>();
            List<Vector3> newNormals = new List<Vector3>();
            List<Vector2> newTexCoords = new List<Vector2>();
            List<Color> newColors = new List<Color>();
            List<byte[]> newBoneIndices = new List<byte[]>();
            List<float[]> newBoneWeights = new List<float[]>();

            // This list will be used to compare between vertices to check their equality
            List<ProceduralVertex> uniqueVertList = new List<ProceduralVertex>();

            // This list will store the new optimized triangles generated from the new vertex data
            List<RWTriangle> newTriangles = new List<RWTriangle>();

            int triIdx = -1;

            Console.WriteLine("Optimizing mesh with {0} vertices", vertices.Length);

            for (int vtxIndex = 0; vtxIndex < vertices.Length; vtxIndex += 3)
            {
                // Increment the triangle index each iteration for the material id list
                triIdx++;

                // Create a new empty triangle
                RWTriangle tri = new RWTriangle { MatID = matIds[triIdx] };

                // Loop 3 times, covering A, B and C of the triangle
                for (int triVtxOffset = 0; triVtxOffset < 3; triVtxOffset++)
                {
                    ProceduralVertex curVertex = new ProceduralVertex();

                    curVertex.position = vertices[vtxIndex + triVtxOffset];
                    curVertex.normal = normals[vtxIndex + triVtxOffset];

                    if (texCoord != null)
                        curVertex.texCoord = texCoord[vtxIndex + triVtxOffset];

                    if (colors != null)
                        curVertex.color = colors[vtxIndex + triVtxOffset];

                    if (boneIndices != null)
                    {
                        curVertex.boneIndices = boneIndices[vtxIndex + triVtxOffset].ToArray();
                        curVertex.boneWeights = boneWeights[vtxIndex + triVtxOffset].ToArray();
                    }

                    bool isMatch = false;
                    int uniqueVtxIndex = -1;
                    foreach (ProceduralVertex uniqueVertex in uniqueVertList)
                    {
                        uniqueVtxIndex++;

                        if (uniqueVertex.position == curVertex.position)
                        {
                            isMatch = true;
                        }
                        else
                        {
                            isMatch = false; // in case everything breaks, remove this line
                            continue;
                        }

                        if (uniqueVertex.normal == curVertex.normal)
                        {
                            isMatch = true;
                        }
                        else
                        {
                            isMatch = false;
                            continue;
                        }

                        if (texCoord != null)
                        {
                            if (uniqueVertex.texCoord == curVertex.texCoord)
                            {
                                isMatch = true;
                            }
                            else
                            {
                                isMatch = false;
                                continue;
                            }
                        }

                        if (colors != null)
                        {
                            if (uniqueVertex.color == curVertex.color)
                            {
                                isMatch = true;
                            }
                            else
                            {
                                isMatch = false;
                                continue;
                            }
                        }
                       
                        if (boneIndices != null)
                        {
                            for (int i = 0; i < 4; i++)
                            {
                                if (uniqueVertex.boneIndices[i] != curVertex.boneIndices[i] ||
                                    uniqueVertex.boneWeights[i] != curVertex.boneWeights[i])
                                {
                                    isMatch = false;
                                    break;
                                }
                            }
                        }                     

                        if (isMatch)
                            break;
                    }

                    // We have a match
                    // The new triangle vertex index is the index of the matched vertex
                    if (isMatch)
                    {
                        tri[triVtxOffset] = (ushort)uniqueVtxIndex;
                    }
                    else
                    {
                        // We did not find a match in the unique vertex list
                        // So we add the current vertex to the list
                        uniqueVertList.Add(curVertex);

                        // Add the other attributes to their lists
                        newPositions.Add(curVertex.position);
                        newNormals.Add(curVertex.normal);

                        if (texCoord != null)
                            newTexCoords.Add(curVertex.texCoord);

                        if (colors != null)
                            newColors.Add(curVertex.color);

                        if (boneIndices != null)
                        {
                            newBoneIndices.Add(curVertex.boneIndices);
                            newBoneWeights.Add(curVertex.boneWeights);
                        }

                        // And set the triangle index to the last checked vertex + 1
                        tri[triVtxOffset] = (ushort)(uniqueVtxIndex + 1);
                    }
                }

                newTriangles.Add(tri);

                if (vtxIndex % 256 == 0)
                    Console.WriteLine("{0} out of {1} vertices optimized", vtxIndex, vertices.Length);
            }

            Console.WriteLine("{0} out of {1} vertices optimized", vertices.Length, vertices.Length);
            Console.WriteLine("Done! Optimized vertex count = {0}, {1}% less vertices", 
				uniqueVertList.Count, ((float)(vertices.Length - uniqueVertList.Count) / vertices.Length) * 100);

            if (texCoord != null)
            {
                _texCoordSets = new Vector2[1][];
                _texCoordSets[0] = newTexCoords.ToArray();
            }

            if (colors != null)
                _clrArray = newColors.ToArray();

            if (boneIndices != null)
            {
                boneIndices = newBoneIndices.ToArray();
                boneWeights = newBoneWeights.ToArray();
            }

            _triArray = newTriangles.ToArray();
            _posArray = newPositions.ToArray();
            _nrmArray = newNormals.ToArray();
        }
Example #2
0
        internal RWMeshStruct(RWNodeFactory.RWNodeInfo header, BinaryReader reader)
        : base(header)
        {
            _geoFlags = (RWGeometryFlags)reader.ReadUInt16();
            byte numTexCoord = reader.ReadByte();
            _nativeFlag = (RWGeometryNativeFlag)reader.ReadByte();
            int numTris = reader.ReadInt32();
            int numVerts = reader.ReadInt32();
            int numMorphTargets = reader.ReadInt32();

            if (numMorphTargets != SUPPORTED_MORPH_COUNT)
            {
                throw new NotImplementedException("More than 1 morph target are not implemented");
            }

            if (_geoFlags.HasFlagUnchecked(RWGeometryFlags.HasColors))
            {
                _clrArray = reader.ReadColorArray(numVerts);
            }

            if (_geoFlags.HasFlagUnchecked(RWGeometryFlags.HasTexCoord1) ||
               (_geoFlags.HasFlagUnchecked(RWGeometryFlags.HasTexCoord2)))
            {
                _texCoordSets = new Vector2[numTexCoord][];

                for (int i = 0; i < numTexCoord; i++)
                {
                    _texCoordSets[i] = reader.ReadVector2Array(numVerts);
                }
            }

            _triArray = new RWTriangle[numTris];
            for (int i = 0; i < numTris; i++)
            {
                _triArray[i] = new RWTriangle(reader);
            }

            _bSphere = new RWBoundingSphere(reader);

            if (_geoFlags.HasFlagUnchecked(RWGeometryFlags.HasVertices))
            {
                _posArray = reader.ReadVector3Array(numVerts);
            }

            if (_geoFlags.HasFlagUnchecked(RWGeometryFlags.HasNormals))
            {
                _nrmArray = reader.ReadVector3Array(numVerts);
            }
        }