public static Lib3dsFile Export(List <Group> groups, List <Lib3dsVertex> vertices, List <ushort[]> allFaces, short[] faceGroupIds) { var file = LIB3DS.lib3ds_file_new(); var textureGroups = new Dictionary <int, List <Group> >(); foreach (var group in groups) { var groupId = (int)group[ModelField.TextureGroup]; if (groupId == -1 || !textureGroups.TryGetValue(groupId, out var textureGroup)) { textureGroup = new List <Group>(); if (groupId != -1) { textureGroups.Add(groupId, textureGroup); } } textureGroup.Add(group); group.TextureGroup = textureGroup; // TODO: Hierarchy of object var node = LIB3DS.lib3ds_node_new(Lib3dsNodeType.LIB3DS_NODE_MESH_INSTANCE); node.name = group[ModelField.GroupName].ToString(); node.node_id = (ushort)file.nodes.Count; file.nodes.Add(node); } var objectIndices = (faceGroupIds == null ? Enumerable.Range(0, groups.Count) : faceGroupIds.Distinct().Select(b => (int)b)).ToArray(); MaterialExporter.Export(groups, file); var facesByObject = TriangleExporter.Export(allFaces, faceGroupIds, objectIndices); foreach (var i in objectIndices) { var group = groups[i]; var faces = facesByObject[i]; var mesh = LIB3DS.lib3ds_mesh_new(group[ModelField.GroupName].ToString()); mesh.vertices = vertices; mesh.nvertices = (ushort)vertices.Count; mesh.texcos = new List <Lib3dsTexturecoordinate>(); file.meshes.Add(mesh); if (faces.Count != 0) { var usedVertices = group.TextureGroup .Select(g => groups.IndexOf(g)) .SelectMany(g => facesByObject[g]) .SelectMany(f => f.index) .Distinct() .Select(v => vertices[v]) .ToArray(); var minX = usedVertices.Min(v => v.x); var minY = usedVertices.Min(v => v.y); var minZ = usedVertices.Min(v => v.z); var maxX = usedVertices.Max(v => v.x); var maxY = usedVertices.Max(v => v.y); var maxZ = usedVertices.Max(v => v.z); var objectMin = new Vector3(minX, minY, minZ); var objectScale = new Vector3(maxX - minX, maxY - minY, maxZ - minZ); if (objectScale.X < 0.001f) { objectScale.X = 1; } if (objectScale.Y < 0.001f) { objectScale.Y = 1; } if (objectScale.Z < 0.001f) { objectScale.Z = 1; } var quaternionX = Quaternion.CreateFromYawPitchRoll(0, -(float)group[ModelField.TextureRotateX], 0); var quaternionY = Quaternion.CreateFromYawPitchRoll(-(float)group[ModelField.TextureRotateY], 0, 0); var quaternionZ = Quaternion.CreateFromYawPitchRoll(0, 0, -(float)group[ModelField.TextureRotateZ]); var quaternion = Quaternion.Multiply(quaternionX, quaternionY); var rotation = Matrix4x4.CreateFromQuaternion(Quaternion.Multiply(quaternion, quaternionZ)); for (int v = 0; v < vertices.Count; v++) { var vector = new Vector3(vertices[v].x, vertices[v].y, vertices[v].z); vector -= objectMin; vector /= objectScale; vector = Vector3.Transform(vector, rotation); mesh.texcos.Add(new Lib3dsTexturecoordinate(vector.X, vector.Y)); } foreach (var face in faces) { face.material = i; } mesh.faces = faces; mesh.nfaces = (ushort)faces.Count; } } return(file); }