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, }); } }
public static Vector4 ToVector4(this BoneWeights boneWeights) => new Vector4(boneWeights.w0, boneWeights.w1, boneWeights.w2, boneWeights.w3);
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(); // } }
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]); } }
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); }
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, }); } } }