public byte[] ToBytes() { List <byte> outList = new List <byte>(); using (System.IO.MemoryStream mem = new System.IO.MemoryStream()) { EndianBinaryWriter writer = new EndianBinaryWriter(mem, Endian.Big); writer.Write(m_MatrixType); writer.Write(m_UnknownIndex); writer.Write((sbyte)-1); ushort[] compressRot = J3DUtility.CompressRotation(m_Rotation.ToEulerAngles()); writer.Write(m_Scale); writer.Write(compressRot[0]); writer.Write(compressRot[1]); writer.Write(compressRot[2]); writer.Write((short)-1); writer.Write(m_Translation); Bounds.Write(writer); outList.AddRange(mem.ToArray()); } return(outList.ToArray()); }
static GMX_Parser.MESH CreateMesh(Model model, Shape curShape) { var attributes = model.VertexData.Attributes; var mesh = new GMX_Parser.MESH(); mesh.IndexGroup = new GMX_Parser.INDX(); mesh.VertexGroup = new GMX_Parser.VERT(); mesh.VMapGroup = new GMX_Parser.VMAP(); List <GMX_Parser.Vertex> vertices = new List <GMX_Parser.Vertex>(); List <ushort> indices = new List <ushort>(); List <ushort> boneindices = new List <ushort>(); List <ushort> vmapindices = new List <ushort>(); ushort vertexID = 0; uint vertexStride = 0; if (curShape.Descriptor.CheckAttribute(GXVertexAttribute.PositionMatrixIdx)) { vertexStride += 4; } if (curShape.Descriptor.CheckAttribute(GXVertexAttribute.Position)) { vertexStride += 12; } if (curShape.Descriptor.CheckAttribute(GXVertexAttribute.Normal)) { vertexStride += 12; } if (curShape.Descriptor.CheckAttribute(GXVertexAttribute.Color0)) { vertexStride += 4; } if (curShape.Descriptor.CheckAttribute(GXVertexAttribute.Color1)) { vertexStride += 4; } if (curShape.Descriptor.CheckAttribute(GXVertexAttribute.Tex0)) { vertexStride += 8; } if (curShape.Descriptor.CheckAttribute(GXVertexAttribute.Tex1)) { vertexStride += 8; } uint[] matrices = new uint[10]; uint matrixStart = 0; foreach (Packet pack in curShape.Packets) { for (int i = 0; i < pack.MatrixIndices.Count; i++) { if (pack.MatrixIndices[i] != -1) { matrices[i] = (uint)pack.MatrixIndices[i]; } } foreach (Primitive prim in pack.Primitives) { List <Vertex> triVertices = J3DUtility.PrimitiveToTriangles(prim); for (int triIndex = 0; triIndex < triVertices.Count; triIndex += 3) { indices.AddRange(new ushort[] { (ushort)(vertexID + 2), (ushort)(vertexID + 1), vertexID }); for (int triVertIndex = 0; triVertIndex < 3; triVertIndex++) { var gmxVertex = new GMX_Parser.Vertex(); Vertex vert = triVertices[triIndex + triVertIndex]; var position = attributes.Positions[(int)vert.GetAttributeIndex(GXVertexAttribute.Position)]; if (curShape.Descriptor.CheckAttribute(GXVertexAttribute.Normal)) { gmxVertex.Normal = attributes.Normals[(int)vert.GetAttributeIndex(GXVertexAttribute.Normal)]; } if (curShape.Descriptor.CheckAttribute(GXVertexAttribute.Color0)) { var color = attributes.Color_0[(int)vert.GetAttributeIndex(GXVertexAttribute.Color0)]; gmxVertex.Color = new OpenTK.Vector4(color.R, color.G, color.B, color.A); } if (curShape.Descriptor.CheckAttribute(GXVertexAttribute.Tex0)) { gmxVertex.TexCoord0 = attributes.TexCoord_0[(int)vert.GetAttributeIndex(GXVertexAttribute.Tex0)]; } if (curShape.Descriptor.CheckAttribute(GXVertexAttribute.Tex1)) { gmxVertex.TexCoord1 = attributes.TexCoord_1[(int)vert.GetAttributeIndex(GXVertexAttribute.Tex1)]; } if (curShape.Descriptor.CheckAttribute(GXVertexAttribute.PositionMatrixIdx)) { gmxVertex.MatrixID = (uint)(matrixStart + vert.PositionMatrixIDxIndex); } gmxVertex.Position = position; vertices.Add(gmxVertex); } } } matrixStart += 10; } indices.Clear(); //Now optmize the indices Dictionary <GMX_Parser.Vertex, int> verticesNew = new Dictionary <GMX_Parser.Vertex, int>(); foreach (var v in vertices) { if (!verticesNew.ContainsKey(v)) { verticesNew.Add(v, verticesNew.Count); } if (verticesNew.ContainsKey(v)) { indices.Add((ushort)verticesNew[v]); } } vertices = verticesNew.Keys.ToList(); foreach (var v in vertices) { vmapindices.Add(0); vmapindices.Add(0); } mesh.VMapGroup.Indices = vmapindices.ToArray(); mesh.VertexSize = (ushort)vertexStride; mesh.VertexCount = (ushort)vertices.Count; mesh.VertexGroup.Vertices = vertices; mesh.FaceCount = (uint)indices.Count; mesh.IndexGroup.Indices = indices.ToArray(); mesh.SkinningFlags = 0; if (curShape.Descriptor.CheckAttribute(GXVertexAttribute.PositionMatrixIdx)) { mesh.SkinningFlags = 20; } return(mesh); }
private SHP1(EndianBinaryReader reader, int offset) { Shapes = new List <Shape>(); RemapTable = new List <int>(); reader.BaseStream.Seek(offset, System.IO.SeekOrigin.Begin); reader.SkipInt32(); int shp1Size = reader.ReadInt32(); int entryCount = reader.ReadInt16(); reader.SkipInt16(); int shapeHeaderDataOffset = reader.ReadInt32(); int shapeRemapTableOffset = reader.ReadInt32(); int unusedOffset = reader.ReadInt32(); int attributeDataOffset = reader.ReadInt32(); int matrixIndexDataOffset = reader.ReadInt32(); int primitiveDataOffset = reader.ReadInt32(); int matrixDataOffset = reader.ReadInt32(); int PacketInfoDataOffset = reader.ReadInt32(); reader.BaseStream.Seek(offset + shapeRemapTableOffset, System.IO.SeekOrigin.Begin); // Remap table for (int i = 0; i < entryCount; i++) { RemapTable.Add(reader.ReadInt16()); } int highestIndex = J3DUtility.GetHighestValue(RemapTable); // Packet data List <Tuple <int, int> > packetData = new List <Tuple <int, int> >(); // <packet size, packet offset> int packetDataCount = (shp1Size - PacketInfoDataOffset) / 8; reader.BaseStream.Seek(PacketInfoDataOffset + offset, System.IO.SeekOrigin.Begin); for (int i = 0; i < packetDataCount; i++) { packetData.Add(new Tuple <int, int>(reader.ReadInt32(), reader.ReadInt32())); } // Matrix data List <Tuple <int, int> > matrixData = new List <Tuple <int, int> >(); // <index count, start index> List <int[]> matrixIndices = new List <int[]>(); int matrixDataCount = (PacketInfoDataOffset - matrixDataOffset) / 8; reader.BaseStream.Seek(matrixDataOffset + offset, System.IO.SeekOrigin.Begin); for (int i = 0; i < matrixDataCount; i++) { reader.SkipInt16(); matrixData.Add(new Tuple <int, int>(reader.ReadInt16(), reader.ReadInt32())); } for (int i = 0; i < matrixDataCount; i++) { reader.BaseStream.Seek(offset + matrixIndexDataOffset + (matrixData[i].Item2 * 2), System.IO.SeekOrigin.Begin); int[] indices = new int[matrixData[i].Item1]; for (int j = 0; j < matrixData[i].Item1; j++) { indices[j] = reader.ReadInt16(); } matrixIndices.Add(indices); } // Shape data List <Shape> tempShapeList = new List <Shape>(); reader.BaseStream.Seek(offset + shapeHeaderDataOffset, System.IO.SeekOrigin.Begin); for (int i = 0; i < highestIndex + 1; i++) { byte matrixType = reader.ReadByte(); reader.SkipByte(); int packetCount = reader.ReadInt16(); int shapeAttributeOffset = reader.ReadInt16(); int shapeMatrixDataIndex = reader.ReadInt16(); int firstPacketIndex = reader.ReadInt16(); reader.SkipInt16(); BoundingVolume shapeVol = new BoundingVolume(reader); long curOffset = reader.BaseStream.Position; ShapeVertexDescriptor descriptor = new ShapeVertexDescriptor(reader, offset + attributeDataOffset + shapeAttributeOffset); List <Packet> shapePackets = new List <Packet>(); for (int j = 0; j < packetCount; j++) { int packetSize = packetData[j + firstPacketIndex].Item1; int packetOffset = packetData[j + firstPacketIndex].Item2; Packet pack = new Packet(packetSize, packetOffset + primitiveDataOffset + offset, matrixIndices[j + firstPacketIndex]); pack.ReadPrimitives(reader, descriptor); shapePackets.Add(pack); } tempShapeList.Add(new Shape(descriptor, shapeVol, shapePackets, matrixType)); reader.BaseStream.Seek(curOffset, System.IO.SeekOrigin.Begin); } for (int i = 0; i < entryCount; i++) { Shapes.Add(tempShapeList[RemapTable[i]]); } reader.BaseStream.Seek(offset + shp1Size, System.IO.SeekOrigin.Begin); }
public void FillScene(Scene scene, VertexData vertData, List <Rigging.Bone> flatSkeleton, List <Matrix4> inverseBindMatrices) { for (int i = 0; i < Shapes.Count; i++) { Mesh mesh = new Mesh($"mesh_{ i }", PrimitiveType.Triangle); mesh.MaterialIndex = i; int vertexID = 0; Shape curShape = Shapes[i]; foreach (Packet pack in curShape.Packets) { foreach (Primitive prim in pack.Primitives) { List <Vertex> triVertices = J3DUtility.PrimitiveToTriangles(prim); for (int triIndex = 0; triIndex < triVertices.Count; triIndex += 3) { Face newFace = new Face(new int[] { vertexID + 2, vertexID + 1, vertexID }); mesh.Faces.Add(newFace); for (int triVertIndex = 0; triVertIndex < 3; triVertIndex++) { Vertex vert = triVertices[triIndex + triVertIndex]; for (int j = 0; j < vert.VertexWeight.WeightCount; j++) { Rigging.Bone curWeightBone = flatSkeleton[vert.VertexWeight.BoneIndices[j]]; int assBoneIndex = mesh.Bones.FindIndex(x => x.Name == curWeightBone.Name); if (assBoneIndex == -1) { Assimp.Bone newBone = new Assimp.Bone(); newBone.Name = curWeightBone.Name; newBone.OffsetMatrix = curWeightBone.InverseBindMatrix.ToMatrix4x4(); mesh.Bones.Add(newBone); assBoneIndex = mesh.Bones.IndexOf(newBone); } mesh.Bones[assBoneIndex].VertexWeights.Add(new VertexWeight(vertexID, vert.VertexWeight.Weights[j])); } OpenTK.Vector3 posVec = vertData.Positions[(int)vert.GetAttributeIndex(GXVertexAttribute.Position)]; OpenTK.Vector4 openTKVec = new Vector4(posVec.X, posVec.Y, posVec.Z, 1); Vector3D vertVec = new Vector3D(openTKVec.X, openTKVec.Y, openTKVec.Z); if (vert.VertexWeight.WeightCount == 1) { if (inverseBindMatrices.Count > vert.VertexWeight.BoneIndices[0]) { Matrix4 test = inverseBindMatrices[vert.VertexWeight.BoneIndices[0]].Inverted(); test.Transpose(); Vector4 trans = OpenTK.Vector4.Transform(openTKVec, test); vertVec = new Vector3D(trans.X, trans.Y, trans.Z); } else { Vector4 trans = OpenTK.Vector4.Transform(openTKVec, flatSkeleton[vert.VertexWeight.BoneIndices[0]].TransformationMatrix); vertVec = new Vector3D(trans.X, trans.Y, trans.Z); } } /*else * { * Matrix4 finalMatrix = Matrix4.Zero; * * for (int m = 0; m < vert.VertexWeight.WeightCount; m++) * { * Matrix4 sm1 = inverseBindMatrices[vert.VertexWeight.BoneIndices[m]]; * //sm1.Transpose(); * Matrix4 sm2 = flatSkeleton[vert.VertexWeight.BoneIndices[m]].TransformationMatrix; * //sm2.Transpose(); * * finalMatrix += Matrix4.Mult(sm1, vert.VertexWeight.Weights[m]); * } * * Vector4 final = Vector4.Transform(openTKVec, finalMatrix); * * vertVec = new Vector3D(final.X, final.Y, final.Z); * }*/ mesh.Vertices.Add(vertVec); if (curShape.Descriptor.CheckAttribute(GXVertexAttribute.Normal)) { mesh.Normals.Add(vertData.Normals[(int)vert.NormalIndex].ToVector3D()); } if (curShape.Descriptor.CheckAttribute(GXVertexAttribute.Color0)) { mesh.VertexColorChannels[0].Add(vertData.Color_0[(int)vert.Color0Index].ToColor4D()); } if (curShape.Descriptor.CheckAttribute(GXVertexAttribute.Color1)) { mesh.VertexColorChannels[1].Add(vertData.Color_1[(int)vert.Color1Index].ToColor4D()); } for (int texCoordNum = 0; texCoordNum < 8; texCoordNum++) { if (curShape.Descriptor.CheckAttribute(GXVertexAttribute.Tex0 + texCoordNum)) { Vector3D texCoord = new Vector3D(); switch (texCoordNum) { case 0: texCoord = vertData.TexCoord_0[(int)vert.TexCoord0Index].ToVector2D(); break; case 1: texCoord = vertData.TexCoord_1[(int)vert.TexCoord1Index].ToVector2D(); break; case 2: texCoord = vertData.TexCoord_2[(int)vert.TexCoord2Index].ToVector2D(); break; case 3: texCoord = vertData.TexCoord_3[(int)vert.TexCoord3Index].ToVector2D(); break; case 4: texCoord = vertData.TexCoord_4[(int)vert.TexCoord4Index].ToVector2D(); break; case 5: texCoord = vertData.TexCoord_5[(int)vert.TexCoord5Index].ToVector2D(); break; case 6: texCoord = vertData.TexCoord_6[(int)vert.TexCoord6Index].ToVector2D(); break; case 7: texCoord = vertData.TexCoord_7[(int)vert.TexCoord7Index].ToVector2D(); break; } mesh.TextureCoordinateChannels[texCoordNum].Add(texCoord); } } vertexID++; } } } } scene.Meshes.Add(mesh); } }
private void LoadBMD(Model model) { Nodes.Clear(); ShapeFolder = new TreeNode("Shapes"); SkeletonFolder = new TreeNode("Skeleton"); MaterialFolder = new TreeNode("Materials"); TextureFolder = new BMDTextureFolder("Textures"); Nodes.Add(ShapeFolder); Nodes.Add(MaterialFolder); Nodes.Add(SkeletonFolder); Nodes.Add(TextureFolder); BMDFile = model; FillSkeleton(BMDFile.Scenegraph, Skeleton, BMDFile.Joints.FlatSkeleton); foreach (var bone in Skeleton.bones) { if (bone.Parent == null) { SkeletonFolder.Nodes.Add(bone); } } for (int i = 0; i < BMDFile.Shapes.Shapes.Count; i++) { var curShape = BMDFile.Shapes.Shapes[i]; var mat = new BMDMaterialWrapper(BMDFile.Materials.GetMaterial(i), BMDFile); MaterialFolder.Nodes.Add(mat); var shpWrapper = new BMDShapeWrapper(curShape, BMDFile, mat); shpWrapper.Text = $"Shape {i}"; ShapeFolder.Nodes.Add(shpWrapper); Renderer.Meshes.Add(shpWrapper); var polyGroup = new STGenericPolygonGroup(); shpWrapper.PolygonGroups.Add(polyGroup); var VertexAttributes = BMDFile.VertexData.Attributes; int vertexID = 0; int packetID = 0; foreach (var att in curShape.Descriptor.Attributes) { shpWrapper.Nodes.Add($"Attribute {att.Key} {att.Value.Item1}"); } foreach (SuperBMDLib.Geometry.Packet pack in curShape.Packets) { int primID = 0; foreach (SuperBMDLib.Geometry.Primitive prim in pack.Primitives) { List <SuperBMDLib.Geometry.Vertex> triVertices = J3DUtility.PrimitiveToTriangles(prim); for (int triIndex = 0; triIndex < triVertices.Count; triIndex += 3) { polyGroup.faces.AddRange(new int[] { vertexID + 2, vertexID + 1, vertexID }); for (int triVertIndex = 0; triVertIndex < 3; triVertIndex++) { SuperBMDLib.Geometry.Vertex vert = triVertices[triIndex + triVertIndex]; Vertex vertex = new Vertex(); vertex.pos = VertexAttributes.Positions[(int)vert.GetAttributeIndex(GXVertexAttribute.Position)]; shpWrapper.vertices.Add(vertex); if (curShape.Descriptor.CheckAttribute(GXVertexAttribute.Normal)) { vertex.nrm = VertexAttributes.Normals[(int)vert.NormalIndex]; } if (curShape.Descriptor.CheckAttribute(GXVertexAttribute.Color0)) { var color0 = VertexAttributes.Color_0[(int)vert.Color0Index]; vertex.col = new OpenTK.Vector4(color0.R, color0.G, color0.B, color0.A); } for (int j = 0; j < vert.VertexWeight.WeightCount; j++) { vertex.boneWeights.Add(vert.VertexWeight.Weights[j]); vertex.boneIds.Add(vert.VertexWeight.BoneIndices[j]); } if (vert.VertexWeight.WeightCount == 1) { if (BMDFile.SkinningEnvelopes.InverseBindMatrices.Count > vert.VertexWeight.BoneIndices[0]) { Matrix4 test = BMDFile.SkinningEnvelopes.InverseBindMatrices[vert.VertexWeight.BoneIndices[0]].Inverted(); test.Transpose(); vertex.pos = OpenTK.Vector3.TransformPosition(vertex.pos, test); vertex.nrm = OpenTK.Vector3.TransformNormal(vertex.nrm, test); } else { vertex.pos = OpenTK.Vector3.TransformPosition(vertex.pos, BMDFile.Joints.FlatSkeleton[vert.VertexWeight.BoneIndices[0]].TransformationMatrix); vertex.nrm = OpenTK.Vector3.TransformNormal(vertex.nrm, BMDFile.Joints.FlatSkeleton[vert.VertexWeight.BoneIndices[0]].TransformationMatrix); } } for (int texCoordNum = 0; texCoordNum < 8; texCoordNum++) { if (curShape.Descriptor.CheckAttribute(GXVertexAttribute.Tex0 + texCoordNum)) { switch (texCoordNum) { case 0: vertex.uv0 = VertexAttributes.TexCoord_0[(int)vert.TexCoord0Index]; break; case 1: vertex.uv1 = VertexAttributes.TexCoord_0[(int)vert.TexCoord0Index]; break; case 2: vertex.uv2 = VertexAttributes.TexCoord_0[(int)vert.TexCoord0Index]; break; } } } vertexID++; } } primID++; } packetID++; } } CorrectMaterialIndices(Renderer.Meshes, BMDFile.Scenegraph, BMDFile.Materials); for (int i = 0; i < BMDFile.Textures.Textures.Count; i++) { var texWrapper = new BMDTextureWrapper(BMDFile.Textures.Textures[i]); TextureFolder.Nodes.Add(texWrapper); Renderer.TextureList.Add(texWrapper); } }
public void FillScene(Scene scene, VertexData vertData, List <Rigging.Bone> flatSkeleton, List <Matrix4> inverseBindMatrices) { for (int i = 0; i < Shapes.Count; i++) { int vertexID = 0; Shape curShape = Shapes[i]; Console.Write("Mesh " + i + ": "); string meshname = $"mesh_{ i }"; switch (curShape.MatrixType) { case MatrixType.BillboardX: meshname += "_BillX"; Console.Write("Billboarding Detected! "); break; case MatrixType.BillboardXY: meshname += "_BillXY"; Console.Write("Billboarding Detected! "); break; default: break; } Mesh mesh = new Mesh($"mesh_{ i }", PrimitiveType.Triangle); mesh.MaterialIndex = i; foreach (Packet pack in curShape.Packets) { foreach (Primitive prim in pack.Primitives) { List <Vertex> triVertices = J3DUtility.PrimitiveToTriangles(prim); for (int triIndex = 0; triIndex < triVertices.Count; triIndex += 3) { Face newFace = new Face(new int[] { vertexID + 2, vertexID + 1, vertexID }); mesh.Faces.Add(newFace); for (int triVertIndex = 0; triVertIndex < 3; triVertIndex++) { Vertex vert = triVertices[triIndex + triVertIndex]; for (int j = 0; j < vert.VertexWeight.WeightCount; j++) { Rigging.Bone curWeightBone = flatSkeleton[vert.VertexWeight.BoneIndices[j]]; int assBoneIndex = mesh.Bones.FindIndex(x => x.Name == curWeightBone.Name); if (assBoneIndex == -1) { Assimp.Bone newBone = new Assimp.Bone(); newBone.Name = curWeightBone.Name; newBone.OffsetMatrix = curWeightBone.InverseBindMatrix.ToMatrix4x4(); mesh.Bones.Add(newBone); assBoneIndex = mesh.Bones.IndexOf(newBone); } mesh.Bones[assBoneIndex].VertexWeights.Add(new VertexWeight(vertexID, vert.VertexWeight.Weights[j])); } OpenTK.Vector3 posVec = vertData.Positions[(int)vert.GetAttributeIndex(GXVertexAttribute.Position)]; OpenTK.Vector4 openTKVec = new Vector4(posVec.X, posVec.Y, posVec.Z, 1); Vector3D vertVec = new Vector3D(openTKVec.X, openTKVec.Y, openTKVec.Z); if (vert.VertexWeight.WeightCount == 1) { if (inverseBindMatrices.Count > vert.VertexWeight.BoneIndices[0]) { Matrix4 test = inverseBindMatrices[vert.VertexWeight.BoneIndices[0]].Inverted(); test.Transpose(); Vector4 trans = OpenTK.Vector4.Transform(openTKVec, test); vertVec = new Vector3D(trans.X, trans.Y, trans.Z); } else { Vector4 trans = OpenTK.Vector4.Transform(openTKVec, flatSkeleton[vert.VertexWeight.BoneIndices[0]].TransformationMatrix); vertVec = new Vector3D(trans.X, trans.Y, trans.Z); } } mesh.Vertices.Add(vertVec); if (curShape.Descriptor.CheckAttribute(GXVertexAttribute.Normal)) { OpenTK.Vector3 nrmVec = vertData.Normals[(int)vert.NormalIndex]; OpenTK.Vector4 openTKNrm = new Vector4(nrmVec.X, nrmVec.Y, nrmVec.Z, 1); Vector3D vertNrm = new Vector3D(nrmVec.X, nrmVec.Y, nrmVec.Z); if (vert.VertexWeight.WeightCount == 1) { if (inverseBindMatrices.Count > vert.VertexWeight.BoneIndices[0]) { Matrix4 test = inverseBindMatrices[vert.VertexWeight.BoneIndices[0]].Inverted(); vertNrm = Vector3.TransformNormalInverse(nrmVec, test).ToVector3D(); } else { Vector4 trans = OpenTK.Vector4.Transform(openTKNrm, flatSkeleton[vert.VertexWeight.BoneIndices[0]].TransformationMatrix); vertNrm = new Vector3D(trans.X, trans.Y, trans.Z); } } mesh.Normals.Add(vertNrm); } if (curShape.Descriptor.CheckAttribute(GXVertexAttribute.Color0)) { mesh.VertexColorChannels[0].Add(vertData.Color_0[(int)vert.Color0Index].ToColor4D()); } if (curShape.Descriptor.CheckAttribute(GXVertexAttribute.Color1)) { mesh.VertexColorChannels[1].Add(vertData.Color_1[(int)vert.Color1Index].ToColor4D()); } for (int texCoordNum = 0; texCoordNum < 8; texCoordNum++) { if (curShape.Descriptor.CheckAttribute(GXVertexAttribute.Tex0 + texCoordNum)) { Vector3D texCoord = new Vector3D(); switch (texCoordNum) { case 0: texCoord = vertData.TexCoord_0[(int)vert.TexCoord0Index].ToVector2D(); break; case 1: texCoord = vertData.TexCoord_1[(int)vert.TexCoord1Index].ToVector2D(); break; case 2: texCoord = vertData.TexCoord_2[(int)vert.TexCoord2Index].ToVector2D(); break; case 3: texCoord = vertData.TexCoord_3[(int)vert.TexCoord3Index].ToVector2D(); break; case 4: texCoord = vertData.TexCoord_4[(int)vert.TexCoord4Index].ToVector2D(); break; case 5: texCoord = vertData.TexCoord_5[(int)vert.TexCoord5Index].ToVector2D(); break; case 6: texCoord = vertData.TexCoord_6[(int)vert.TexCoord6Index].ToVector2D(); break; case 7: texCoord = vertData.TexCoord_7[(int)vert.TexCoord7Index].ToVector2D(); break; } mesh.TextureCoordinateChannels[texCoordNum].Add(texCoord); } } vertexID++; } } } Console.Write("..."); } scene.Meshes.Add(mesh); Console.Write("✓"); Console.WriteLine(); } }