예제 #1
0
            public void Push(SkinnedMeshRenderer renderer)
            {
                var mesh = renderer.sharedMesh;

                if (mesh == null)
                {
                    Debug.LogWarningFormat("{0} has no mesh", renderer.name);
                    return;
                }

                Renderers.Add(renderer);

                var indexOffset     = Positions.Count;
                var boneIndexOffset = Bones.Count;

                Positions.AddRange(mesh.vertices);
                Normals.AddRange(mesh.normals);
                UV.AddRange(mesh.uv);
                Tangents.AddRange(mesh.tangents);

                if (mesh.vertexCount == mesh.boneWeights.Length)
                {
                    BoneWeights.AddRange(mesh.boneWeights.Select(x => AddBoneIndexOffset(x, boneIndexOffset)).ToArray());
                }
                else
                {
                    BoneWeights.AddRange(Enumerable.Range(0, mesh.vertexCount).Select(x => new BoneWeight()).ToArray());
                }

                BindPoses.AddRange(mesh.bindposes);
                Bones.AddRange(renderer.bones);

                for (int i = 0; i < mesh.subMeshCount; ++i)
                {
                    var indices = mesh.GetIndices(i).Select(x => x + indexOffset);
                    var mat     = renderer.sharedMaterials[i];
                    var sameMaterialSubMeshIndex = SubMeshes.FindIndex(x => ReferenceEquals(x.Material, mat));
                    if (sameMaterialSubMeshIndex >= 0)
                    {
                        SubMeshes[sameMaterialSubMeshIndex].Indices.AddRange(indices);
                    }
                    else
                    {
                        SubMeshes.Add(new SubMesh
                        {
                            Indices  = indices.ToList(),
                            Material = mat,
                        });
                    }
                }

                for (int i = 0; i < mesh.blendShapeCount; ++i)
                {
                    var positions = (Vector3[])mesh.vertices.Clone();
                    var normals   = (Vector3[])mesh.normals.Clone();
                    var tangents  = mesh.tangents.Select(x => (Vector3)x).ToArray();

                    mesh.GetBlendShapeFrameVertices(i, 0, positions, normals, tangents);
                    BlendShapes.Add(new BlendShape
                    {
                        VertexOffset = indexOffset,
                        FrameWeight  = mesh.GetBlendShapeFrameWeight(i, 0),
                        Name         = mesh.GetBlendShapeName(i),
                        Positions    = positions,
                        Normals      = normals,
                        Tangents     = tangents,
                    });
                }
            }
예제 #2
0
 public static Vector4 ToVector4(this BoneWeights boneWeights) => new Vector4(boneWeights.w0, boneWeights.w1, boneWeights.w2, boneWeights.w3);
예제 #3
0
    public static void ParseSkin(BinaryReader reader, M2Data m2Data)
    {
        string  magic        = reader.ReadFourCC();             // 'SKIN'
        M2Array vertices     = reader.ReadM2Array();
        M2Array indices      = reader.ReadM2Array();
        M2Array bones        = reader.ReadM2Array();
        M2Array submeshes    = reader.ReadM2Array();
        M2Array batches      = reader.ReadM2Array();            // nTexture_units
        int     boneCountMax = reader.ReadInt32();              // WoW takes this and divides it by the number of bones in each submesh, then stores the biggest one.
                                                                // Maximum number of bones per drawcall for each view. Related to (old) GPU numbers of registers.
                                                                // Values seen : 256, 64, 53, 21
        M2Array shadow_batches = reader.ReadM2Array();

        /// Read Batches ///
        reader.BaseStream.Seek(batches.Offset, SeekOrigin.Begin);
        for (var batch = 0; batch < batches.Size; batch++)
        {
            M2BatchIndices m2BatchIndices = new M2BatchIndices();

            m2BatchIndices.M2Batch_flags                      = reader.ReadByte();          // Usually 16 for static textures, and 0 for animated textures. &0x1: materials invert something; &0x2: transform &0x4: projected texture; &0x10: something batch compatible; &0x20: projected texture?; &0x40: use textureWeights
            m2BatchIndices.M2Batch_priorityPlane              = reader.ReadByte();
            m2BatchIndices.M2Batch_shader_id                  = reader.ReadUInt16();        // See below.
            m2BatchIndices.M2Batch_skinSectionIndex           = reader.ReadUInt16();        // A duplicate entry of a submesh from the list above.
            m2BatchIndices.M2Batch_geosetIndex                = reader.ReadUInt16();        // See below.
            m2BatchIndices.M2Batch_color_index                = reader.ReadUInt16();        // A Color out of the Colors-Block or -1 if none.
            m2BatchIndices.M2Batch_materialIndex              = reader.ReadUInt16();        // The renderflags used on this texture-unit.
            m2BatchIndices.M2Batch_materialLayer              = reader.ReadUInt16();        // Capped at 7 (see CM2Scene::BeginDraw)
            m2BatchIndices.M2Batch_textureCount               = reader.ReadUInt16();        // 1 to 4. See below. Also seems to be the number of textures to load, starting at the texture lookup in the next field (0x10).
            m2BatchIndices.M2Batch_textureComboIndex          = reader.ReadUInt16();        // Index into Texture lookup table
            m2BatchIndices.M2Batch_textureCoordComboIndex     = reader.ReadUInt16();        // Index into the texture unit lookup table.
            m2BatchIndices.M2Batch_textureWeightComboIndex    = reader.ReadUInt16();        // Index into transparency lookup table.
            m2BatchIndices.M2Batch_textureTransformComboIndex = reader.ReadUInt16();        // Index into uvanimation lookup table.

            m2Data.m2BatchIndices.Add(m2BatchIndices);
        }

        // Read SubMesh Data //
        int[] Indices   = new int[vertices.Size];                                 // Three indices which make up a triangle.
        int[] Triangles = new int[indices.Size];                                  // Bone indices (Index into BoneLookupTable)

        int[] skinSectionId         = new int[submeshes.Size];                    // Mesh part ID, see below.
        int[] submesh_StartVertex   = new int[submeshes.Size];                    // Starting vertex number.
        int[] submesh_NbrVerts      = new int[submeshes.Size];                    // Number of vertices.
        int[] submesh_StartTriangle = new int[submeshes.Size];                    // Starting triangle index (that's 3* the number of triangles drawn so far).
        int[] submesh_NbrTris       = new int[submeshes.Size];                    // Number of triangle indices.

        int[] submesh_boneCount      = new int[submeshes.Size];                   // Number of elements in the bone lookup table. Max seems to be 256 in Wrath. Shall be ≠ 0.
        int[] submesh_boneComboIndex = new int[submeshes.Size];                   // Starting index in the bone lookup table.
        int[] submesh_boneInfluences = new int[submeshes.Size];                   // <= 4
                                                                                  // from <=BC documentation: Highest number of bones needed at one time in this Submesh --Tinyn (wowdev.org)
                                                                                  // In 2.x this is the amount of of bones up the parent-chain affecting the submesh --NaK
                                                                                  // Highest number of bones referenced by a vertex of this submesh. 3.3.5a and suspectedly all other client revisions. -- Skarn
        int[]     submesh_centerBoneIndex    = new int[submeshes.Size];
        Vector3[] submesh_centerPosition     = new Vector3[submeshes.Size];       // Average position of all the vertices in the sub mesh.
        Vector3[] submesh_sortCenterPosition = new Vector3[submeshes.Size];       // The center of the box when an axis aligned box is built around the vertices in the submesh.
        float[]   submesh_sortRadius         = new float[submeshes.Size];         // Distance of the vertex farthest from CenterBoundingBox.

        /// Indices ///
        reader.BaseStream.Seek(vertices.Offset, SeekOrigin.Begin);
        for (var ind = 0; ind < vertices.Size; ind++)
        {
            Indices[ind] = reader.ReadUInt16();
        }

        /// triangles ///
        reader.BaseStream.Seek(indices.Offset, SeekOrigin.Begin);
        for (var tri = 0; tri < indices.Size; tri++)
        {
            Triangles[tri] = reader.ReadUInt16();
        }

        /// submeshes ///
        reader.BaseStream.Seek(submeshes.Offset, SeekOrigin.Begin);
        for (var sub = 0; sub < submeshes.Size; sub++)
        {
            skinSectionId[sub] = reader.ReadUInt16();
            int Level = reader.ReadUInt16();                                    // (level << 16) is added (|ed) to startTriangle and alike to avoid having to increase those fields to uint32s.
            submesh_StartVertex[sub]   = reader.ReadUInt16() + (Level << 16);
            submesh_NbrVerts[sub]      = reader.ReadUInt16();
            submesh_StartTriangle[sub] = reader.ReadUInt16() + (Level << 16);
            submesh_NbrTris[sub]       = reader.ReadUInt16();

            submesh_boneCount[sub]       = reader.ReadUInt16();
            submesh_boneComboIndex[sub]  = reader.ReadUInt16();
            submesh_boneInfluences[sub]  = reader.ReadUInt16();
            submesh_centerBoneIndex[sub] = reader.ReadUInt16();

            Vector3 canterPosition = new Vector3(reader.ReadSingle() / Settings.WORLD_SCALE, reader.ReadSingle() / Settings.WORLD_SCALE, reader.ReadSingle() / Settings.WORLD_SCALE);
            submesh_centerPosition[sub] = new Vector3(-canterPosition.x, canterPosition.z, -canterPosition.y);
            Vector3 sortCenterPosition = new Vector3(reader.ReadSingle() / Settings.WORLD_SCALE, reader.ReadSingle() / Settings.WORLD_SCALE, reader.ReadSingle() / Settings.WORLD_SCALE);
            submesh_sortCenterPosition[sub] = new Vector3(-sortCenterPosition.x, sortCenterPosition.z, -sortCenterPosition.y);

            submesh_sortRadius[sub] = reader.ReadSingle();
        }

        /// Assemble Submeshes ///
        m2Data.submeshData = new List <SubmeshData>();
        for (int sm = 0; sm < submeshes.Size; sm++)
        {
            Vector3[] vertList  = new Vector3[submesh_NbrVerts[sm]];
            Vector3[] normsList = new Vector3[submesh_NbrVerts[sm]];
            Vector2[] uvsList   = new Vector2[submesh_NbrVerts[sm]];
            Vector2[] uvs2List  = new Vector2[submesh_NbrVerts[sm]];

            BoneWeights[] boneWeights = new BoneWeights[submesh_NbrVerts[sm]];

            for (int vn = 0; vn < submesh_NbrVerts[sm]; vn++)
            {
                vertList[vn]  = m2Data.meshData.pos[vn + submesh_StartVertex[sm]];
                normsList[vn] = m2Data.meshData.normal[vn + submesh_StartVertex[sm]];
                uvsList[vn]   = m2Data.meshData.tex_coords[vn + submesh_StartVertex[sm]];
                uvs2List[vn]  = m2Data.meshData.tex_coords2[vn + submesh_StartVertex[sm]];

                BoneWeights boneWeightVert = new BoneWeights();
                int[]       boneIndex      = new int[4];
                float[]     boneWeight     = new float[4];

                for (int bn = 0; bn < 4; bn++)
                {
                    boneIndex[bn]  = m2Data.meshData.bone_indices[vn + submesh_boneComboIndex[sm]][bn];
                    boneWeight[bn] = m2Data.meshData.bone_weights[vn + submesh_boneComboIndex[sm]][bn];
                }
                boneWeightVert.boneIndex  = boneIndex;
                boneWeightVert.boneWeight = boneWeight;
                boneWeights[vn]           = boneWeightVert;
            }

            int[] triList = new int[submesh_NbrTris[sm]];
            for (var t = 0; t < submesh_NbrTris[sm]; t++)
            {
                //triList[t] = Triangles[t + submesh_StartTriangle[sm]] - submesh_StartVertex[sm];  // using Separate Meshes, reset first triangle to index 0;
                triList[t] = Triangles[t + submesh_StartTriangle[sm]];                              // using Unity Submeshes, don't reset first triangle to index 0;
            }


            SubmeshData submeshData = new SubmeshData();

            submeshData.ID        = skinSectionId[sm];
            submeshData.vertList  = vertList;
            submeshData.normsList = normsList;
            submeshData.uvsList   = uvsList;
            submeshData.uvs2List  = uvs2List;
            Array.Reverse(triList);
            submeshData.triList                = triList;
            submeshData.submesh_StartVertex    = submesh_StartVertex[sm];
            submeshData.boneWeights            = boneWeights;
            submeshData.submesh_boneCount      = submesh_boneCount[sm];
            submeshData.submesh_boneInfluences = submesh_boneInfluences[sm];
            m2Data.submeshData.Add(submeshData);
        }

        /// Read Bone Data ///
        // byte[] Properties = new byte[bones.Size];
        // reader.BaseStream.Seek(bones.Offset, SeekOrigin.Current);
        // for (var bone = 0; bone < bones.Size; bone++)
        // {
        //     Properties[bone] = reader.ReadByte();
        // }
    }
예제 #4
0
        public Geoset1300(BinaryReader br)
        {
            TotalSize = br.ReadUInt32();
            long end = TotalSize + br.BaseStream.Position;

            //Vertices
            if (br.HasTag("VRTX"))
            {
                NrOfVertices = br.ReadUInt32();
                for (int i = 0; i < NrOfVertices; i++)
                {
                    Vertices.Add(new CVector3(br));
                }
            }

            //Normals
            if (br.HasTag("NRMS"))
            {
                NrOfNormals = br.ReadUInt32();
                for (int i = 0; i < NrOfNormals; i++)
                {
                    Normals.Add(new CVector3(br));
                }
            }

            //TexCoords
            if (br.HasTag("UVAS"))
            {
                NrOfTexCoords = br.ReadUInt32();                 //Amount of groups
                for (int i = 0; i < NrOfNormals * NrOfTexCoords; i++)
                {
                    TexCoords.Add(new CVector2(br));
                }
            }

            //Face Group Type
            if (br.HasTag("PTYP"))
            {
                NrOfFaceTypeGroups = br.ReadUInt32();
                FaceTypes.AddRange(br.ReadBytes((int)NrOfFaceTypeGroups));
            }

            //Face Groups
            if (br.HasTag("PCNT"))
            {
                NrOfFaceGroups = br.ReadUInt32();
                for (int i = 0; i < NrOfFaceGroups; i++)
                {
                    FaceGroups.Add(br.ReadUInt32());
                }
            }

            //Indexes
            if (br.HasTag("PVTX"))
            {
                NrOfFaceVertices = br.ReadUInt32();
                for (int i = 0; i < NrOfFaceVertices / 3; i++)
                {
                    FaceVertices.Add(new CVertex(br));
                }
            }

            //Vertex Groups
            if (br.HasTag("GNDX"))
            {
                NrOfVertexGroupIndices = br.ReadUInt32();
                VertexGroupIndices.AddRange(br.ReadBytes((int)NrOfVertexGroupIndices));
            }

            //Matrix Groups
            if (br.HasTag("MTGC"))
            {
                NrOfMatrixGroups = br.ReadUInt32();
                for (int i = 0; i < NrOfMatrixGroups; i++)
                {
                    MatrixGroups.Add(br.ReadUInt32());
                }
            }

            //Matrix Indexes
            if (br.HasTag("MATS"))
            {
                NrOfMatrixIndexes = br.ReadUInt32();
                for (int i = 0; i < NrOfMatrixIndexes; i++)
                {
                    MatrixIndexes.Add(br.ReadUInt32());
                }
            }

            //Bone Indexes
            if (br.HasTag("BIDX"))
            {
                NrOfBoneIndexes = br.ReadUInt32();
                for (int i = 0; i < NrOfBoneIndexes; i++)
                {
                    BoneIndexes.Add(br.ReadUInt32());
                }
            }

            //Bone Weights
            if (br.HasTag("BWGT"))
            {
                NrOfBoneWeights = br.ReadUInt32();
                for (int i = 0; i < NrOfBoneWeights; i++)
                {
                    BoneWeights.Add(br.ReadUInt32());
                }
            }

            MaterialId     = br.ReadUInt32();
            SelectionGroup = br.ReadUInt32();
            Unselectable   = br.ReadUInt32() == 1;
            Bounds         = new CExtent(br);

            //Extents
            NrOfExtents = br.ReadUInt32();
            for (int i = 0; i < NrOfExtents; i++)
            {
                Extents.Add(new CExtent(br));
            }

            //Grouped Vertices
            for (int i = 0; i < NrOfVertices; i++)
            {
                if (!GroupedVertices.ContainsKey(VertexGroupIndices[i]))
                {
                    GroupedVertices.Add(VertexGroupIndices[i], new List <CVector3>());
                }

                GroupedVertices[VertexGroupIndices[i]].Add(Vertices[i]);
            }
        }
예제 #5
0
        public MeshIntegrationResult Integrate(MeshEnumerateOption onlyBlendShapeRenderers)
        {
            var mesh = new Mesh();

            if (Positions.Count > ushort.MaxValue)
            {
                Debug.LogFormat("exceed 65535 vertices: {0}", Positions.Count);
                mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;
            }

            mesh.vertices     = Positions.ToArray();
            mesh.normals      = Normals.ToArray();
            mesh.uv           = UV.ToArray();
            mesh.tangents     = Tangents.ToArray();
            mesh.boneWeights  = BoneWeights.ToArray();
            mesh.subMeshCount = SubMeshes.Count;
            for (var i = 0; i < SubMeshes.Count; ++i)
            {
                mesh.SetIndices(SubMeshes[i].Indices.ToArray(), MeshTopology.Triangles, i);
            }
            mesh.bindposes = BindPoses.ToArray();

            // blendshape
            switch (onlyBlendShapeRenderers)
            {
            case MeshEnumerateOption.OnlyWithBlendShape:
            {
                AddBlendShapesToMesh(mesh);
                mesh.name = INTEGRATED_MESH_WITH_BLENDSHAPE_NAME;
                break;
            }

            case MeshEnumerateOption.All:
            {
                AddBlendShapesToMesh(mesh);
                mesh.name = INTEGRATED_MESH_ALL_NAME;
                break;
            }

            case MeshEnumerateOption.OnlyWithoutBlendShape:
            {
                mesh.name = INTEGRATED_MESH_WITHOUT_BLENDSHAPE_NAME;
                break;
            }
            }

            // meshName
            var meshNode = new GameObject();

            switch (onlyBlendShapeRenderers)
            {
            case MeshEnumerateOption.OnlyWithBlendShape:
            {
                meshNode.name = INTEGRATED_MESH_WITH_BLENDSHAPE_NAME;
                break;
            }

            case MeshEnumerateOption.OnlyWithoutBlendShape:
            {
                meshNode.name = INTEGRATED_MESH_WITHOUT_BLENDSHAPE_NAME;
                break;
            }

            case MeshEnumerateOption.All:
            {
                meshNode.name = INTEGRATED_MESH_ALL_NAME;
                break;
            }
            }

            var integrated = meshNode.AddComponent <SkinnedMeshRenderer>();

            integrated.sharedMesh      = mesh;
            integrated.sharedMaterials = SubMeshes.Select(x => x.Material).ToArray();
            integrated.bones           = Bones.ToArray();
            Result.IntegratedRenderer  = integrated;
            Result.MeshMap.Integrated  = mesh;
            return(Result);
        }
예제 #6
0
        public void Push(MeshRenderer renderer)
        {
            var meshFilter = renderer.GetComponent <MeshFilter>();

            if (meshFilter == null)
            {
                Debug.LogWarningFormat("{0} has no mesh filter", renderer.name);
                return;
            }
            var mesh = meshFilter.sharedMesh;

            if (mesh == null)
            {
                Debug.LogWarningFormat("{0} has no mesh", renderer.name);
                return;
            }
            Result.SourceMeshRenderers.Add(renderer);
            Result.MeshMap.Sources.Add(mesh);

            var indexOffset     = Positions.Count;
            var boneIndexOffset = Bones.Count;

            Positions.AddRange(mesh.vertices
                               .Select(x => renderer.transform.TransformPoint(x))
                               );
            Normals.AddRange(mesh.normals
                             .Select(x => renderer.transform.TransformVector(x))
                             );
            UV.AddRange(mesh.uv);
            Tangents.AddRange(mesh.tangents
                              .Select(t =>
            {
                var v = renderer.transform.TransformVector(t.x, t.y, t.z);
                return(new Vector4(v.x, v.y, v.z, t.w));
            })
                              );

            var self = renderer.transform;
            var bone = self.parent;

            if (bone == null)
            {
                Debug.LogWarningFormat("{0} is root gameobject.", self.name);
                return;
            }
            var bindpose = bone.worldToLocalMatrix;

            BoneWeights.AddRange(Enumerable.Range(0, mesh.vertices.Length)
                                 .Select(x => new BoneWeight()
            {
                boneIndex0 = Bones.Count,
                weight0    = 1,
            })
                                 );

            BindPoses.Add(bindpose);
            Bones.Add(bone);

            for (int i = 0; i < mesh.subMeshCount && i < renderer.sharedMaterials.Length; ++i)
            {
                var indices = mesh.GetIndices(i).Select(x => x + indexOffset);
                var mat     = renderer.sharedMaterials[i];
                var sameMaterialSubMeshIndex = SubMeshes.FindIndex(x => ReferenceEquals(x.Material, mat));
                if (sameMaterialSubMeshIndex >= 0)
                {
                    SubMeshes[sameMaterialSubMeshIndex].Indices.AddRange(indices);
                }
                else
                {
                    SubMeshes.Add(new SubMesh
                    {
                        Indices  = indices.ToList(),
                        Material = mat,
                    });
                }
            }
        }