void GenerateModelAsset() { ColorBasedModelDefinition baseModel = BinaryToColorBasedModelDefinition(); if (baseModel.colors == null) { return; } ModelDefinition newModel = VoxelPlayFormatTools.GetModelDefinition(null, baseModel, importIgnoreOffset); if (!string.IsNullOrEmpty(baseModel.name)) { newModel.name = baseModel.name; } newModel.name = Path.GetFileNameWithoutExtension(importFilename); // Create a suitable file path string path = GetPathForNewModel(); string modelName = GetFilenameForNewModel(newModel.name); AssetDatabase.CreateAsset(newModel, path + "/" + modelName + ".asset"); if (shouldMakeColorToVoxMap) { var map = CreateColorToVoxDefMap(newModel); AssetDatabase.CreateAsset(map, path + "/" + modelName + ".CTVMAP.asset"); } AssetDatabase.SaveAssets(); EditorUtility.FocusProjectWindow(); Selection.activeObject = newModel; }
public static ColorBasedModelDefinition ImportBinary(Stream stream, Encoding encoding) { var br = new BinaryReader(stream, encoding); Vector3Int size; var data = FromMagica(br, out size); ColorBasedModelDefinition result = new ColorBasedModelDefinition(); result.sizeX = size.x; result.sizeY = size.y; result.sizeZ = size.z; Debug.Log("size: " + size.ToString() + " data len: " + data.Length); result.colors = data; VoxelPlayFormatTools.DBUGCheckNonAlphaZeroColors(result.colors); return(result); }
private ColorBasedModelDefinition MagicaVoxelBinaryToColorBasedModelDefinition() { ColorBasedModelDefinition baseModel = ColorBasedModelDefinition.Null; Stream file = System.IO.File.Open(importFilename, FileMode.Open); try { baseModel = VE.Importers.MagicaVoxelImporter.ImportBinary(file, System.Text.Encoding.UTF8); } catch (Exception e) { Debug.Log("excp in Magica to Bin: " + e.ToString()); } finally { file.Close(); } return(baseModel); }
void GeneratePrefab() { ColorBasedModelDefinition baseModel = BinaryToColorBasedModelDefinition(); if (baseModel.colors == null) { return; } // Generate a cuboid per visible voxel int index; int sizeX = baseModel.sizeX; int sizeY = baseModel.sizeY; int sizeZ = baseModel.sizeZ; int ONE_Y_ROW = sizeX * sizeZ; int ONE_Z_ROW = sizeX; float offsetX = 0, offsetY = 0, offsetZ = 0; if (!importIgnoreOffset) { offsetX += baseModel.offsetX; offsetY += baseModel.offsetY; offsetZ += baseModel.offsetZ; } Color32[] colors = baseModel.colors; List <Cuboid> cuboidsPick = new List <Cuboid>(); for (int y = 0; y < sizeY; y++) { int posy = y * ONE_Y_ROW; for (int z = 0; z < sizeZ; z++) { int posz = z * ONE_Z_ROW; for (int x = 0; x < sizeX; x++) { index = posy + posz + x; Color32 color = colors[index]; if (color.a > 0) { Cuboid cuboid = new Cuboid(); Vector3 center = new Vector3(x - sizeX / 2 - 0.5f + offsetX, y + 0.5f + offsetY, z - sizeZ / 2 - 0.5f + offsetZ); cuboid.bounds = new Bounds(center, Misc.vector3one); cuboid.color = color; cuboidsPick.Add(cuboid); } } } } Cuboid[] cuboids = cuboidsPick.ToArray(); // Optimization 1: Fusion same color cuboids bool repeat = true; while (repeat) { repeat = false; for (int k = 0; k < cuboids.Length; k++) { if (cuboids[k].color.a == 0) { continue; } for (int j = k + 1; j < cuboids.Length; j++) { if (cuboids[j].color.a == 0) { continue; } if (cuboids[k].color.r == cuboids[j].color.r && cuboids[k].color.b == cuboids[j].color.b && cuboids[k].color.g == cuboids[j].color.g) { bool touching = false; Bounds f1 = cuboids[k].bounds; Bounds f2 = cuboids[j].bounds; // Touching back or forward faces? if (f1.min.x == f2.min.x && f1.max.x == f2.max.x && f1.min.y == f2.min.y && f1.max.y == f2.max.y) { touching = f1.min.z == f2.max.z || f1.max.z == f2.min.z; // ... left or right faces? } else if (f1.min.z == f2.min.z && f1.max.z == f2.max.z && f1.min.y == f2.min.y && f1.max.y == f2.max.y) { touching = f1.min.x == f2.max.x || f1.max.x == f2.min.x; // ... top or bottom faces? } else if (f1.min.x == f2.min.x && f1.max.x == f2.max.x && f1.min.z == f2.min.z && f1.max.z == f2.max.z) { touching = f1.min.y == f2.max.y || f1.max.y == f2.min.y; } if (touching) { cuboids[k].bounds.Encapsulate(cuboids[j].bounds); cuboids[j].color.a = 0; // mark as deleted repeat = true; } } } } } // Optimization 2: Remove hidden cuboids for (int k = 0; k < cuboids.Length; k++) { if (cuboids[k].color.a == 0) { continue; } for (int j = k + 1; j < cuboids.Length; j++) { if (cuboids[j].color.a == 0) { continue; } int occlusion = 0; Bounds f1 = cuboids[k].bounds; Bounds f2 = cuboids[j].bounds; // Touching back or forward faces? if (f1.min.x >= f2.min.x && f1.max.x <= f2.max.x && f1.min.y >= f2.min.y && f1.max.y <= f2.max.y) { if (f1.min.z == f2.max.z) { occlusion++; } if (f1.max.z == f2.min.z) { occlusion++; } // ... left or right faces? } else if (f1.min.z >= f2.min.z && f1.max.z <= f2.max.z && f1.min.y >= f2.min.y && f1.max.y <= f2.max.y) { if (f1.min.x == f2.max.x) { occlusion++; } if (f1.max.x == f2.min.x) { occlusion++; } // ... top or bottom faces? } else if (f1.min.x >= f2.min.x && f1.max.x <= f2.max.x && f1.min.z >= f2.min.z && f1.max.z <= f2.max.z) { if (f1.min.y == f2.max.y) { occlusion++; } if (f1.max.y == f2.min.y) { occlusion++; } } if (occlusion == 6) { cuboids[k].color.a = 0; break; } } } // Optimization 3: Fragment cuboids into faces and remove duplicates List <Face> faces = new List <Face>(); for (int k = 0; k < cuboids.Length; k++) { if (cuboids[k].color.a == 0) { continue; } Vector3 min = cuboids[k].bounds.min; Vector3 max = cuboids[k].bounds.max; Vector3 size = cuboids[k].bounds.size; Face top = new Face(new Vector3((min.x + max.x) * 0.5f, max.y, (min.z + max.z) * 0.5f), new Vector3(size.x, 0, size.z), faceVerticesTop, normalsUp, cuboids[k].color); RemoveDuplicateOrAddFace(faces, top); Face bottom = new Face(new Vector3((min.x + max.x) * 0.5f, min.y, (min.z + max.z) * 0.5f), new Vector3(size.x, 0, size.z), faceVerticesBottom, normalsDown, cuboids[k].color); RemoveDuplicateOrAddFace(faces, bottom); Face left = new Face(new Vector3(min.x, (min.y + max.y) * 0.5f, (min.z + max.z) * 0.5f), new Vector3(0, size.y, size.z), faceVerticesLeft, normalsLeft, cuboids[k].color); RemoveDuplicateOrAddFace(faces, left); Face right = new Face(new Vector3(max.x, (min.y + max.y) * 0.5f, (min.z + max.z) * 0.5f), new Vector3(0, size.y, size.z), faceVerticesRight, normalsRight, cuboids[k].color); RemoveDuplicateOrAddFace(faces, right); Face back = new Face(new Vector3((min.x + max.x) * 0.5f, (min.y + max.y) * 0.5f, min.z), new Vector3(size.x, size.y, 0), faceVerticesBack, normalsBack, cuboids[k].color); RemoveDuplicateOrAddFace(faces, back); Face forward = new Face(new Vector3((min.x + max.x) * 0.5f, (min.y + max.y) * 0.5f, max.z), new Vector3(size.x, size.y, 0), faceVerticesForward, normalsForward, cuboids[k].color); RemoveDuplicateOrAddFace(faces, forward); } // Create geometry & uv mapping int facesCount = faces.Count; List <Vector3> vertices = new List <Vector3>(facesCount * 4); List <int> indices = new List <int>(facesCount * 6); List <Vector3> normals = new List <Vector3>(facesCount * 4); List <Color32> meshColors = new List <Color32>(facesCount * 4); index = 0; for (int k = 0; k < facesCount; k++, index += 4) { Face face = faces[k]; Vector3 faceVertex; for (int j = 0; j < 4; j++) { faceVertex.x = (face.center.x + face.vertices[j].x * face.size.x) * scale.x; faceVertex.y = (face.center.y + face.vertices[j].y * face.size.y) * scale.y; faceVertex.z = (face.center.z + face.vertices[j].z * face.size.z) * scale.z; vertices.Add(faceVertex); meshColors.Add(face.color); } normals.AddRange(face.normals); indices.Add(index); indices.Add(index + 1); indices.Add(index + 2); indices.Add(index + 3); indices.Add(index + 2); indices.Add(index + 1); } Mesh mesh = new Mesh(); mesh.SetVertices(vertices); mesh.SetNormals(normals); mesh.SetTriangles(indices, 0); mesh.SetColors(meshColors); mesh.RecalculateBounds(); GameObject obj = new GameObject("Model", typeof(VoxelPlayBehaviour)); MeshFilter mf = obj.AddComponent <MeshFilter>(); mf.mesh = mesh; MeshRenderer mr = obj.AddComponent <MeshRenderer>(); mr.sharedMaterial = Resources.Load <Material>("VoxelPlay/Materials/VP Model VertexLit"); string path = GetPathForNewModel(); path += "/" + GetFilenameForNewModel(baseModel.name) + ".prefab"; GameObject prefab = PrefabUtility.CreatePrefab(path, obj); // Store the mesh inside the prefab AssetDatabase.AddObjectToAsset(mesh, prefab); prefab.GetComponent <MeshFilter>().sharedMesh = mesh; MeshCollider mc = prefab.AddComponent <MeshCollider>(); mc.sharedMesh = mesh; mc.convex = true; Rigidbody rb = prefab.AddComponent <Rigidbody>(); rb.constraints = RigidbodyConstraints.FreezeRotationX | RigidbodyConstraints.FreezeRotationZ; AssetDatabase.SaveAssets(); DestroyImmediate(obj); EditorUtility.FocusProjectWindow(); Selection.activeObject = prefab; }