public static void FromImage(Texture2D image, GameObject root, float voxelSize, int depth, bool centerPivot, Color cutoutColor) { if (root != null && image != null && image.width > 0 && image.height > 0 && depth > 0) { Volume voxelVolume = root.GetComponent <Volume>(); voxelVolume.XSize = image.width; voxelVolume.YSize = image.height; voxelVolume.ZSize = depth; voxelVolume.Frames[0].XSize = voxelVolume.XSize; voxelVolume.Frames[0].YSize = voxelVolume.YSize; voxelVolume.Frames[0].ZSize = voxelVolume.ZSize; voxelVolume.Frames[0].Voxels = new Voxel[voxelVolume.XSize * voxelVolume.YSize * voxelVolume.ZSize]; voxelVolume.VoxelSize = voxelSize; if (centerPivot) { voxelVolume.Pivot = (new Vector3(voxelVolume.XSize, voxelVolume.YSize, voxelVolume.ZSize) * voxelVolume.VoxelSize) / 2f; voxelVolume.UpdatePivot(); } for (int x = 0; x < image.width; x++) { for (int y = 0; y < image.height; y++) { Color col = image.GetPixel(x, y); for (int z = 0; z < depth; z++) { voxelVolume.Frames[0].Voxels[x + voxelVolume.XSize * (y + voxelVolume.YSize * z)] = new Voxel() { State = (col != cutoutColor && col.a > 0f)?VoxelState.Active : VoxelState.Inactive, Color = col, Value = 128 }; } } } voxelVolume.CreateChunks(); voxelVolume.SaveForSerialize(); } }
public static void LoadCompound(BinaryReader stream, GameObject root, float voxelSize, bool first, Color32[] palette) { var nameLength = stream.ReadInt32(); var name = new string(stream.ReadChars(nameLength)); var px = stream.ReadInt32(); var py = stream.ReadInt32(); var pz = stream.ReadInt32(); px = -px; // PicaVoxel doesn't support scaling of volumes, sorry! stream.ReadInt32(); stream.ReadInt32(); stream.ReadInt32(); var pivx = stream.ReadSingle(); var pivy = stream.ReadSingle(); var pivz = stream.ReadSingle(); var sizeX = (int)stream.ReadUInt32(); var sizeY = (int)stream.ReadUInt32(); var sizeZ = (int)stream.ReadUInt32(); pivx = sizeX - pivx; var child = Editor.Instantiate(EditorUtility.VoxelVolumePrefab, Vector3.zero, Quaternion.identity) as GameObject; child.transform.SetParent(root.transform); child.name = name; child.GetComponent <Volume>().Material = EditorUtility.PicaVoxelDiffuseMaterial; child.GetComponent <Volume>().GenerateBasic(FillMode.None); Volume voxelVolume = child.GetComponent <Volume>(); voxelVolume.XSize = Convert.ToInt32(sizeX); voxelVolume.YSize = Convert.ToInt32(sizeY); voxelVolume.ZSize = Convert.ToInt32(sizeZ); voxelVolume.Frames[0].XSize = Convert.ToInt32(sizeX); voxelVolume.Frames[0].YSize = Convert.ToInt32(sizeY); voxelVolume.Frames[0].ZSize = Convert.ToInt32(sizeZ); voxelVolume.Frames[0].Voxels = new Voxel[sizeX * sizeY * sizeZ]; voxelVolume.VoxelSize = voxelSize; var dataSize = (int)stream.ReadUInt32(); var compressedData = stream.ReadBytes(dataSize); using (var ms = new MemoryStream(compressedData)) { using (var gzs = new ZlibStream(ms, CompressionMode.Decompress, true)) { for (var x = 0; x < sizeX; x++) { for (var z = 0; z < sizeZ; z++) { for (var y = 0; y < sizeY; y++) { var r = (byte)gzs.ReadByte(); var g = (byte)gzs.ReadByte(); var b = (byte)gzs.ReadByte(); var m = (byte)gzs.ReadByte(); if (m > 0) { voxelVolume.Frames[0].Voxels[(sizeX - 1 - x) + sizeX * (y + sizeY * z)] = new Voxel() { Color = palette == null ? new Color32(r, g, b, 255) : palette[r], Value = 128, State = VoxelState.Active } } ; } } } } } voxelVolume.CreateChunks(); voxelVolume.SaveForSerialize(); var pivot = new Vector3(pivx, pivy, pivz) * voxelSize; voxelVolume.Pivot = pivot; voxelVolume.UpdatePivot(); voxelVolume.transform.localPosition = (new Vector3(-sizeX + px, py, pz) * voxelSize) + pivot; var childCount = stream.ReadUInt32(); for (var i = 0; i < childCount; i++) { LoadNode(stream, child, voxelSize, first, palette); } }
private static void FromQubicleQB(BinaryReader stream, GameObject root, float voxelSize) { //const int MAX_VOLUME_DIMENSION = 64; uint sizex = 0; uint sizey = 0; uint sizez = 0; // uint version; uint colorFormat; uint zAxisOrientation; uint compressed; // uint visibilityMaskEncoded; uint numMatrices; uint i; uint j; uint x; uint y; uint z; int posX; int posY; int posZ; uint[,,] matrix; List <uint[, , ]> matrixList = new List <uint[, , ]>(); uint index; uint data; uint count; const uint CODEFLAG = 2; const uint NEXTSLICEFLAG = 6; //version = stream.ReadUInt32(); stream.ReadUInt32(); colorFormat = stream.ReadUInt32(); zAxisOrientation = stream.ReadUInt32(); compressed = stream.ReadUInt32(); //visibilityMaskEncoded = stream.ReadUInt32(); stream.ReadUInt32(); numMatrices = stream.ReadUInt32(); string volumeName = root.name; string path = Helper.GetMeshStorePath(); for (int d = root.transform.childCount - 1; d >= 0; d--) { Volume vol = root.transform.GetChild(d).GetComponent <Volume>(); if (vol != null) { if (Directory.Exists(path)) { DirectoryInfo di = new DirectoryInfo(path); DirectoryInfo[] dirs = di.GetDirectories(); for (int dir = 0; dir < dirs.Length; dir++) { if (dirs[dir].Name.ToLower() == vol.AssetGuid.ToLower()) { dirs[dir].Delete(true); break; } } } GameObject.DestroyImmediate(root.transform.GetChild(d).gameObject); } } for (i = 0; i < numMatrices; i++) // for each matrix stored in file { // read matrix name byte nameLength = stream.ReadByte(); string name = new string(stream.ReadChars(nameLength)); // read matrix size sizex = stream.ReadUInt32(); sizey = stream.ReadUInt32(); sizez = stream.ReadUInt32(); // read matrix position (in this example the position is irrelevant) posX = stream.ReadInt32(); posY = stream.ReadInt32(); posZ = stream.ReadInt32(); // create matrix and add to matrix list matrix = new uint[sizex, sizey, sizez]; matrixList.Add(matrix); if (compressed == 0) // if uncompressd { for (z = 0; z < sizez; z++) { for (y = 0; y < sizey; y++) { for (x = 0; x < sizex; x++) { matrix[x, y, z] = stream.ReadUInt32(); } } } } else // if compressed { z = 0; while (z < sizez) { index = 0; while (true) { data = stream.ReadUInt32(); if (data == NEXTSLICEFLAG) { break; } else if (data == CODEFLAG) { count = stream.ReadUInt32(); data = stream.ReadUInt32(); for (j = 0; j < count; j++) { x = index % sizex; // mod = modulo e.g. 12 mod 8 = 4 y = index / sizex; // div = integer division e.g. 12 div 8 = 1 index++; matrix[x, y, z] = data; } } else { x = index % sizex; y = index / sizex; index++; matrix[x, y, z] = data; } } z++; } } var newObject = Editor.Instantiate(EditorUtility.VoxelVolumePrefab, Vector3.zero, Quaternion.identity) as GameObject; if (newObject != null) { newObject.name = name != ""?name:volumeName; newObject.GetComponent <Volume>().Material = EditorUtility.PicaVoxelDiffuseMaterial; newObject.GetComponent <Volume>().GenerateBasic(FillMode.None); Volume voxelVolume = newObject.GetComponent <Volume>(); voxelVolume.XSize = Convert.ToInt32(sizex); voxelVolume.YSize = Convert.ToInt32(sizey); voxelVolume.ZSize = Convert.ToInt32(sizez); voxelVolume.Frames[0].XSize = Convert.ToInt32(sizex); voxelVolume.Frames[0].YSize = Convert.ToInt32(sizey); voxelVolume.Frames[0].ZSize = Convert.ToInt32(sizez); voxelVolume.Frames[0].Voxels = new Voxel[sizex * sizey * sizez]; for (int v = 0; v < voxelVolume.Frames[0].Voxels.Length; v++) { voxelVolume.Frames[0].Voxels[v].Value = 128; } voxelVolume.VoxelSize = voxelSize; if (zAxisOrientation == 0) { voxelVolume.Pivot = new Vector3(sizex, 0, 0) * voxelSize; voxelVolume.UpdatePivot(); } for (z = 0; z < sizez; z++) { for (y = 0; y < sizey; y++) { for (x = 0; x < sizex; x++) { Color col = UIntToColor(matrix[x, y, z], colorFormat); if (matrix[x, y, z] != 0) { voxelVolume.Frames[0].Voxels[(zAxisOrientation == 0 ? sizex - 1 - x : x) + sizex * (y + sizey * z)] = new Voxel() { State = VoxelState.Active, Color = col, Value = 128 } } ; } } } voxelVolume.CreateChunks(); voxelVolume.SaveForSerialize(); newObject.transform.position = (new Vector3((zAxisOrientation == 0 ? -posX : posX), posY, posZ) * voxelSize); newObject.transform.parent = root.transform; } // } } }
private void OnEnable() { voxelObject = (Volume) target; Undo.undoRedoPerformed += () => voxelObject.OnUndoRedo(); voxelSizeProperty = serializedObject.FindProperty("VoxelSize"); overlapAmountProperty = serializedObject.FindProperty("OverlapAmount"); collisionMode = serializedObject.FindProperty("CollisionMode"); meshingMode = serializedObject.FindProperty("MeshingMode"); meshCompression = serializedObject.FindProperty("MeshCompression"); colliderMeshingMode = serializedObject.FindProperty("MeshColliderMeshingMode"); separateColliderMesh = serializedObject.FindProperty("GenerateMeshColliderSeparately"); pivotProperty = serializedObject.FindProperty("Pivot"); voxelSize = voxelSizeProperty.floatValue; overlapAmount = overlapAmountProperty.floatValue; pivot = pivotProperty.vector3Value; selfShadeInt = serializedObject.FindProperty("SelfShadingIntensity"); drawGrid = voxelObject.DrawGrid; drawMesh = voxelObject.DrawMesh; runtimeOnlyMesh = serializedObject.FindProperty("RuntimOnlyMesh"); material = serializedObject.FindProperty("Material"); physicMaterial = serializedObject.FindProperty("PhysicMaterial"); castShadows = serializedObject.FindProperty("CastShadows"); receiveShadows = serializedObject.FindProperty("ReceiveShadows"); chunkLayer = serializedObject.FindProperty("ChunkLayer"); collisionTrigger = serializedObject.FindProperty("CollisionTrigger"); if (voxelObject != null && !Application.isPlaying && PrefabUtility.GetPrefabType(voxelObject) != PrefabType.Prefab && PrefabUtility.GetPrefabType(voxelObject) != PrefabType.PrefabInstance) { string path = Path.Combine(Helper.GetMeshStorePath(), voxelObject.AssetGuid); if (!Directory.Exists(path)) voxelObject.CreateChunks(); } if (!Application.isPlaying && voxelObject.gameObject.activeSelf && PrefabUtility.GetPrefabType(voxelObject) != PrefabType.Prefab && !voxelObject.RuntimOnlyMesh) foreach (var frame in voxelObject.Frames) { if (frame.HasDeserialized) frame.UpdateChunks(true); frame.HasDeserialized = false; } paintMode = voxelObject.PaintMode; if (EditorPersistence.SelectBox.BottomLeftFront.X > voxelObject.XSize - 1 || EditorPersistence.SelectBox.BottomLeftFront.Y > voxelObject.YSize - 1 || EditorPersistence.SelectBox.BottomLeftFront.Z > voxelObject.ZSize - 1 || EditorPersistence.SelectBox.TopRightBack.X > voxelObject.XSize - 1 || EditorPersistence.SelectBox.TopRightBack.Y > voxelObject.YSize - 1 || EditorPersistence.SelectBox.TopRightBack.Z > voxelObject.ZSize - 1) EditorPersistence.SelectBox = new PicaVoxelBox(0, 0, 0, voxelObject.XSize - 1, voxelObject.YSize - 1, voxelObject.ZSize - 1); }
public static void Scan(GameObject meshObject, float voxelSize) { Transform meshTransform = meshObject.transform; Mesh mesh = null; MeshFilter mF = meshObject.GetComponent <MeshFilter>(); if (mF != null) { mesh = mF.sharedMesh; } else { SkinnedMeshRenderer sMR = meshObject.GetComponent <SkinnedMeshRenderer>(); if (sMR != null) { mesh = sMR.sharedMesh; } } if (mesh == null) { return; } // bool addedCollider = false; GameObject mcContainer = new GameObject("PVMCC"); mcContainer.transform.SetParent(meshObject.transform, false); MeshCollider mc = mcContainer.AddComponent <MeshCollider>(); mc.sharedMesh = mesh; GameObject mcContainerRev = new GameObject("PVMCCR"); mcContainerRev.transform.SetParent(meshObject.transform, false); Mesh reverseMesh = (Mesh)UnityEngine.Object.Instantiate(mesh); reverseMesh.triangles = mesh.triangles.Reverse().ToArray(); MeshCollider mcr = mcContainerRev.AddComponent <MeshCollider>(); mcr.sharedMesh = reverseMesh; Vector3[] vertices = mesh.vertices; if (vertices.Length <= 0) { return; } Texture2D renderTex = null; Color materialColor = Color.white; Renderer rend = meshObject.GetComponent <Renderer>(); if (rend != null && rend.sharedMaterial != null && rend.sharedMaterial.mainTexture != null) { renderTex = (Texture2D)rend.sharedMaterial.mainTexture; try { renderTex.GetPixel(0, 0); } catch (Exception) { string path = AssetDatabase.GetAssetPath(rend.sharedMaterial.mainTexture); TextureImporter ti = (TextureImporter)TextureImporter.GetAtPath(path); ti.isReadable = true; AssetDatabase.ImportAsset(path); ti.isReadable = false; try { renderTex.GetPixel(0, 0); } catch (Exception) { renderTex = null; } } } else if (rend != null && rend.sharedMaterial != null) { materialColor = rend.sharedMaterial.color; } Vector3 min, max; min = max = meshTransform.TransformPoint(vertices[0]); for (int i = 1; i < vertices.Length; i++) { Vector3 V = meshTransform.TransformPoint(vertices[i]); for (int n = 0; n < 3; n++) { if (V[n] > max[n]) { max[n] = V[n]; } if (V[n] < min[n]) { min[n] = V[n]; } } vertices[i] = V; } vertices[0] = meshTransform.TransformPoint(vertices[0]); Bounds bounds = new Bounds(); bounds.SetMinMax(min, max); if (bounds.size.x <= 0f || bounds.size.y <= 0f || bounds.size.z <= 0f) { return; } var newObject = Editor.Instantiate(EditorUtility.VoxelVolumePrefab, Vector3.zero, Quaternion.identity) as GameObject; newObject.name = meshObject.name + " (Voxels)"; newObject.GetComponent <Volume>().Material = EditorUtility.PicaVoxelDiffuseMaterial; newObject.GetComponent <Volume>().GenerateBasic(FillMode.None); Volume voxelVolume = newObject.GetComponent <Volume>(); voxelVolume.XSize = (int)(bounds.size.x / voxelSize) + 1; voxelVolume.YSize = (int)(bounds.size.y / voxelSize) + 1; voxelVolume.ZSize = (int)(bounds.size.z / voxelSize) + 1; voxelVolume.Frames[0].XSize = voxelVolume.XSize; voxelVolume.Frames[0].YSize = voxelVolume.YSize; voxelVolume.Frames[0].ZSize = voxelVolume.ZSize; voxelVolume.Frames[0].Voxels = new Voxel[voxelVolume.XSize * voxelVolume.YSize * voxelVolume.ZSize]; for (int i = 0; i < voxelVolume.Frames[0].Voxels.Length; i++) { voxelVolume.Frames[0].Voxels[i].Value = 128; } voxelVolume.VoxelSize = voxelSize; Vector3[] testDirs = { Vector3.forward, Vector3.back, Vector3.left, Vector3.right, Vector3.up, Vector3.down }; float stepScale = 0.5f; int size = (int)((bounds.size.x) / (voxelSize * stepScale)) * (int)((bounds.size.y) / (voxelSize * stepScale)) * (int)((bounds.size.z) / (voxelSize * stepScale)); int progress = 0; // Outside for (float x = bounds.min.x; x < bounds.max.x + voxelSize; x += voxelSize * stepScale) { for (float y = bounds.min.y; y < bounds.max.y + voxelSize; y += voxelSize * stepScale) { for (float z = bounds.min.z; z < bounds.max.z + voxelSize; z += voxelSize * stepScale) { Vector3 test = new Vector3(x, y, z); for (int d = 0; d < 6; d++) { Vector3 hit; Color col; if (TestRay(mc, mcContainer, renderTex, materialColor, mesh, test, testDirs[d].normalized, out hit, out col)) { int vX = (voxelVolume.XSize - 1) - (int)((bounds.max.x - hit.x) / voxelSize); int vY = (voxelVolume.YSize - 1) - (int)((bounds.max.y - hit.y) / voxelSize); int vZ = (voxelVolume.ZSize - 1) - (int)((bounds.max.z - hit.z) / voxelSize); if (!(vX < voxelVolume.XSize && vY < voxelVolume.YSize && vZ < voxelVolume.ZSize)) { continue; } voxelVolume.Frames[0].Voxels[vX + voxelVolume.XSize * (vY + voxelVolume.YSize * vZ)] = new Voxel() { State = VoxelState.Active, Color = col, Value = 128 }; } } progress++; } } if (UnityEditor.EditorUtility.DisplayCancelableProgressBar("Scanning Mesh", "Scanning Outside", (1f / (float)size) * (float)progress)) { UnityEditor.EditorUtility.ClearProgressBar(); GameObject.DestroyImmediate(voxelVolume.gameObject); UnityEngine.Object.DestroyImmediate(mcContainer); UnityEngine.Object.DestroyImmediate(mcContainerRev); return; } } progress = 0; //Inside for (float x = bounds.min.x; x < bounds.max.x + voxelSize; x += voxelSize * stepScale) { for (float y = bounds.min.y; y < bounds.max.y + voxelSize; y += voxelSize * stepScale) { for (float z = bounds.min.z; z < bounds.max.z + voxelSize; z += voxelSize * stepScale) { Vector3 test = new Vector3(x, y, z); Vector3 hit; Color col; float closestHit = Mathf.Infinity; Color closestCol = Color.white; int hitCount = 0; for (int d = 0; d < 6; d++) { if (TestRay(mcr, mcContainerRev, renderTex, materialColor, reverseMesh, test, testDirs[d].normalized, out hit, out col)) { if (Vector3.Distance(hit, test) < closestHit) { closestHit = Vector3.Distance(hit, test); closestCol = col; } hitCount++; } } if (hitCount == 6) { int vX = (voxelVolume.XSize - 1) - (int)((bounds.max.x - test.x) / voxelSize); int vY = (voxelVolume.YSize - 1) - (int)((bounds.max.y - test.y) / voxelSize); int vZ = (voxelVolume.ZSize - 1) - (int)((bounds.max.z - test.z) / voxelSize); if (!(vX < voxelVolume.XSize && vY < voxelVolume.YSize && vZ < voxelVolume.ZSize)) { continue; } voxelVolume.Frames[0].Voxels[vX + voxelVolume.XSize * (vY + voxelVolume.YSize * vZ)] = new Voxel() { State = VoxelState.Active, Color = closestCol, Value = 128 }; } progress++; } } if (UnityEditor.EditorUtility.DisplayCancelableProgressBar("Scanning Mesh", "Attempting to fill inside", (1f / (float)size) * (float)progress)) { UnityEditor.EditorUtility.ClearProgressBar(); GameObject.DestroyImmediate(voxelVolume.gameObject); UnityEngine.Object.DestroyImmediate(mcContainer); UnityEngine.Object.DestroyImmediate(mcContainerRev); return; } } UnityEditor.EditorUtility.ClearProgressBar(); voxelVolume.CreateChunks(); voxelVolume.SaveForSerialize(); voxelVolume.Frames[0].OnAfterDeserialize(); voxelVolume.transform.position = meshObject.transform.position; voxelVolume.Pivot = (new Vector3(voxelVolume.XSize, voxelVolume.YSize, voxelVolume.ZSize) * voxelVolume.VoxelSize) / 2f; voxelVolume.UpdatePivot(); UnityEngine.Object.DestroyImmediate(mcContainer); UnityEngine.Object.DestroyImmediate(mcContainerRev); voxelVolume.UpdateAllChunks(); }
public static void Generate(int xSize, int ySize, int zSize, float smoothness, float voxelSize) { var newObject = Editor.Instantiate(EditorUtility.VoxelVolumePrefab, Vector3.zero, Quaternion.identity) as GameObject; newObject.name = "Terrain"; newObject.GetComponent <Volume>().Material = EditorUtility.PicaVoxelDiffuseMaterial; newObject.GetComponent <Volume>().GenerateBasic(FillMode.None); Volume voxelVolume = newObject.GetComponent <Volume>(); voxelVolume.XSize = xSize; voxelVolume.YSize = ySize; voxelVolume.ZSize = zSize; voxelVolume.Frames[0].XSize = voxelVolume.XSize; voxelVolume.Frames[0].YSize = voxelVolume.YSize; voxelVolume.Frames[0].ZSize = voxelVolume.ZSize; voxelVolume.Frames[0].Voxels = new Voxel[voxelVolume.XSize * voxelVolume.YSize * voxelVolume.ZSize]; // Could remove this if we use Value as block type for (int i = 0; i < voxelVolume.Frames[0].Voxels.Length; i++) { voxelVolume.Frames[0].Voxels[i].Value = 128; } voxelVolume.VoxelSize = voxelSize; int progress = 0; // float progressSize = xSize*zSize; float[][] noise = PerlinNoise.GeneratePerlinNoise(xSize, zSize, 2 + (int)(smoothness * 6f)); for (int x = 0; x < xSize; x++) { for (int z = 0; z < zSize; z++) { //if (UnityEditor.EditorUtility.DisplayCancelableProgressBar("Terrain Generator", "Generating Terrain", // (1f/(float) progressSize)*(float) progress)) //{ // UnityEditor.EditorUtility.ClearProgressBar(); // GameObject.DestroyImmediate(voxelVolume.gameObject); // return; //} for (int y = 0; y < ySize; y++) { voxelVolume.Frames[0].Voxels[x + xSize * (y + ySize * z)] = new Voxel() { State = (noise[x][z] >= (1f / (float)ySize) * (float)y)?VoxelState.Active : VoxelState.Inactive, Color = (y == ySize - 1 || noise[x][z] < (1f / (float)ySize) * (float)(y + 1))? new Color32(0, 128, 0, 255) : new Color32(128, 64, 0, 255), }; } progress++; } } voxelVolume.CreateChunks(); voxelVolume.SaveForSerialize(); voxelVolume.Frames[0].OnAfterDeserialize(); voxelVolume.Pivot = (new Vector3(voxelVolume.XSize, 0, voxelVolume.ZSize) * voxelVolume.VoxelSize) / 2f; voxelVolume.UpdatePivot(); voxelVolume.UpdateAllChunks(); }
public void OnGUI() { EditorGUILayout.Space(); EditorUtility.SkinnedLabel("Volume Size: " + voxelObject.name + " (" + voxelObject.XSize + "," + voxelObject.YSize + "," + voxelObject.ZSize + ")"); EditorGUILayout.Space(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("X:", new[] { GUILayout.Width(30) }); xSize = EditorGUILayout.IntField(xSize); EditorGUILayout.LabelField("Y:", new[] { GUILayout.Width(30) }); ySize = EditorGUILayout.IntField(ySize); EditorGUILayout.LabelField("Z:", new[] { GUILayout.Width(30) }); zSize = EditorGUILayout.IntField(zSize); EditorGUILayout.EndHorizontal(); EditorGUILayout.Space(); anchorX = (AnchorX)EditorGUILayout.EnumPopup("X Anchor: ", anchorX); anchorY = (AnchorY)EditorGUILayout.EnumPopup("Y Anchor: ", anchorY); anchorZ = (AnchorZ)EditorGUILayout.EnumPopup("Z Anchor: ", anchorZ); EditorGUILayout.Space(); fillVoxels = EditorGUILayout.ToggleLeft(" Fill any added space", fillVoxels); EditorGUILayout.Space(); EditorUtility.SkinnedLabel( "Chunk Size: " + voxelObject.name + " (" + voxelObject.XChunkSize + "," + voxelObject.YChunkSize + "," + voxelObject.ZChunkSize + ")"); EditorGUILayout.Space(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("X:", new[] { GUILayout.Width(30) }); xChunkSize = EditorGUILayout.IntField(xChunkSize); EditorGUILayout.LabelField("Y:", new[] { GUILayout.Width(30) }); yChunkSize = EditorGUILayout.IntField(yChunkSize); EditorGUILayout.LabelField("Z:", new[] { GUILayout.Width(30) }); zChunkSize = EditorGUILayout.IntField(zChunkSize); EditorGUILayout.EndHorizontal(); EditorGUILayout.Space(); EditorGUILayout.BeginHorizontal(); if (GUILayout.Button("Resize") && (xSize != voxelObject.XSize || ySize != voxelObject.YSize || zSize != voxelObject.ZSize || xChunkSize != voxelObject.XChunkSize || yChunkSize != voxelObject.YChunkSize || zChunkSize != voxelObject.ZChunkSize)) { if (xSize < 1) { xSize = 1; } if (ySize < 1) { ySize = 1; } if (zSize < 1) { zSize = 1; } if (xChunkSize < 1) { xChunkSize = 1; } if (yChunkSize < 1) { yChunkSize = 1; } if (zChunkSize < 1) { zChunkSize = 1; } int totalChunkSize = xChunkSize * yChunkSize * zChunkSize; if (totalChunkSize > 16 * 16 * 16) { UnityEditor.EditorUtility.DisplayDialog("PicaVoxel", "The largest chunk size is 16*16*16 voxels TOTAL. Decrease size in one axis to increase the other two.", "OK"); } else { voxelObject.XChunkSize = xChunkSize; voxelObject.YChunkSize = yChunkSize; voxelObject.ZChunkSize = zChunkSize; if (xSize != voxelObject.XSize || ySize != voxelObject.YSize || zSize != voxelObject.ZSize) { List <Object> undoObjects = new List <Object>(); foreach (Frame frame in voxelObject.Frames) { undoObjects.Add(frame); } undoObjects.Add(voxelObject); Undo.RecordObjects(undoObjects.ToArray(), "Resize Voxel Object"); foreach (Frame frame in voxelObject.Frames) { UnityEditor.EditorUtility.SetDirty(frame); } UnityEditor.EditorUtility.SetDirty(voxelObject); PicaVoxelBox copyDestBox = new PicaVoxelBox( anchorX == AnchorX.Left ? 0 : anchorX == AnchorX.Center ? (xSize / 2) - (voxelObject.XSize / 2) : xSize - voxelObject.XSize, anchorY == AnchorY.Bottom ? 0 : anchorY == AnchorY.Center ? (ySize / 2) - (voxelObject.YSize / 2) : ySize - voxelObject.YSize, anchorZ == AnchorZ.Front ? 0 : anchorZ == AnchorZ.Center ? (zSize / 2) - (voxelObject.ZSize / 2) : zSize - voxelObject.ZSize, (anchorX == AnchorX.Left ? 0 : anchorX == AnchorX.Center ? (xSize / 2) - (voxelObject.XSize / 2) : xSize - voxelObject.XSize) + (voxelObject.XSize - 1), (anchorY == AnchorY.Bottom ? 0 : anchorY == AnchorY.Center ? (ySize / 2) - (voxelObject.YSize / 2) : ySize - voxelObject.YSize) + (voxelObject.YSize - 1), (anchorZ == AnchorZ.Front ? 0 : anchorZ == AnchorZ.Center ? (zSize / 2) - (voxelObject.ZSize / 2) : zSize - voxelObject.ZSize) + (voxelObject.ZSize - 1)); foreach (Frame frame in voxelObject.Frames) { Voxel[] newVox = new Voxel[xSize * ySize * zSize]; if (fillVoxels) { for (int x = 0; x < xSize; x++) { for (int y = 0; y < ySize; y++) { for (int z = 0; z < zSize; z++) { newVox[x + xSize * (y + ySize * z)] = new Voxel() { State = VoxelState.Active, Color = voxelObject.PaletteColors[0], Value = 128 } } } } ; } int destX = copyDestBox.BottomLeftFront.X; int destY = copyDestBox.BottomLeftFront.Y; int destZ = copyDestBox.BottomLeftFront.Z; for (int x = 0; x < voxelObject.XSize; x++) { for (int y = 0; y < voxelObject.YSize; y++) { for (int z = 0; z < voxelObject.ZSize; z++) { if (destX < 0 || destY < 0 || destZ < 0 || destX >= xSize || destY >= ySize || destZ >= zSize) { destZ++; continue; } newVox[destX + xSize * (destY + ySize * destZ)] = frame.Voxels[x + frame.XSize * (y + frame.YSize * z)]; destZ++; } destZ = copyDestBox.BottomLeftFront.Z; destY++; } destY = copyDestBox.BottomLeftFront.Y; destX++; } frame.XSize = xSize; frame.YSize = ySize; frame.ZSize = zSize; frame.EditingVoxels = null; frame.Voxels = newVox; } voxelObject.XSize = xSize; voxelObject.YSize = ySize; voxelObject.ZSize = zSize; } voxelObject.CreateChunks(); voxelObject.SaveForSerialize(); //EditorUtility.SetDirty(voxelObject); Close(); } } // } if (GUILayout.Button("Cancel")) { Close(); } EditorGUILayout.EndHorizontal(); }
public static void FromMagica(BinaryReader stream, GameObject root, float voxelSize, bool centerPivot) { // check out http://voxel.codeplex.com/wikipage?title=VOX%20Format&referringTitle=Home for the file format used below // we're going to return a voxel chunk worth of data Color32[] colors = new Color32[256]; for (int i = 1; i < 256; i++) { uint hexval = defaultColors[i]; byte cb = (byte)((hexval >> 16) & 0xFF); byte cg = (byte)((hexval >> 8) & 0xFF); byte cr = (byte)((hexval >> 0) & 0xFF); colors[i - 1] = new Color32(cr, cg, cb, 255); } MagicaVoxelData[] voxelData = null; List <MagicaVoxelData[]> frames = new List <MagicaVoxelData[]>(); //int numFrames = 1; string magic = new string(stream.ReadChars(4)); //int version = stream.ReadInt32(); // a MagicaVoxel .vox file starts with a 'magic' 4 character 'VOX ' identifier if (magic == "VOX ") { int sizex = 0, sizey = 0, sizez = 0; bool subsample = false; while (stream.BaseStream.Position < stream.BaseStream.Length) { // each chunk has an ID, size and child chunks char[] chunkId = stream.ReadChars(4); int chunkSize = stream.ReadInt32(); //int childChunks = stream.ReadInt32(); string chunkName = new string(chunkId); if (chunkName == "PACK") { stream.ReadInt32(); } else if (chunkName == "SIZE") { sizex = stream.ReadInt32(); sizez = stream.ReadInt32(); sizey = stream.ReadInt32(); //if (sizex > 32 || sizey > 32) subsample = true; stream.ReadBytes(chunkSize - 4 * 3); } else if (chunkName == "XYZI") { // XYZI contains n voxels int numVoxels = stream.ReadInt32(); // int div = (subsample ? 2 : 1); // each voxel has x, y, z and color index values voxelData = new MagicaVoxelData[numVoxels]; for (int i = 0; i < voxelData.Length; i++) { voxelData[i] = new MagicaVoxelData(stream, subsample); } frames.Add(voxelData); } else if (chunkName == "RGBA") { for (int i = 0; i < 256; i++) { byte r = stream.ReadByte(); byte g = stream.ReadByte(); byte b = stream.ReadByte(); byte a = stream.ReadByte(); // convert RGBA to our custom voxel format (16 bits, 0RRR RRGG GGGB BBBB) colors[i] = new Color32(r, g, b, a); } } else { stream.ReadBytes(chunkSize); // read any excess bytes } } if (voxelData.Length == 0) { return; // failed to read any valid voxel data } if (root != null) { Volume voxelVolume = root.GetComponent <Volume>(); voxelVolume.XSize = sizex; voxelVolume.YSize = sizey; voxelVolume.ZSize = sizez; voxelVolume.Frames[voxelVolume.CurrentFrame].XSize = sizex; voxelVolume.Frames[voxelVolume.CurrentFrame].YSize = sizey; voxelVolume.Frames[voxelVolume.CurrentFrame].ZSize = sizez; voxelVolume.Frames[voxelVolume.CurrentFrame].Voxels = new Voxel[sizex * sizey * sizez]; for (int i = 0; i < voxelVolume.Frames[voxelVolume.CurrentFrame].Voxels.Length; i++) { voxelVolume.Frames[voxelVolume.CurrentFrame].Voxels[i].Value = 128; } voxelVolume.VoxelSize = voxelSize; if (centerPivot) { voxelVolume.Pivot = (new Vector3(voxelVolume.XSize, voxelVolume.YSize, voxelVolume.ZSize) * voxelVolume.VoxelSize) / 2f; voxelVolume.UpdatePivot(); } foreach (MagicaVoxelData[] d in frames) { foreach (MagicaVoxelData v in d) { try { voxelVolume.Frames[voxelVolume.CurrentFrame].Voxels[v.x + sizex * (v.z + sizey * v.y)] = new Voxel() { State = VoxelState.Active, Color = colors[v.color - 1], Value = 128 }; } catch (Exception) { Debug.Log(v.x + " " + v.y + " " + v.z); } } if (frames.IndexOf(d) < frames.Count - 1) { voxelVolume.AddFrame(voxelVolume.CurrentFrame + 1); voxelVolume.Frames[voxelVolume.CurrentFrame].Voxels = new Voxel[sizex * sizey * sizez]; } } voxelVolume.SetFrame(0); voxelVolume.CreateChunks(); voxelVolume.SaveForSerialize(); } } }
public override void OnInspectorGUI() { serializedObject.Update(); EditorGUILayout.Space(); EditorGUILayout.LabelField("Editor", new GUIStyle() { fontStyle = FontStyle.Bold }); if (!allRuntimeOnlyMesh) { if (GUILayout.Button(allEditorsEnabled ? "Stop Editing All" : "Start Editing All")) { foreach (Volume v in mpvObject.Volumes) { v.IsEnabledForEditing = !allEditorsEnabled; v.PaintMode = EditorPaintMode.Color; v.UpdateAllChunks(); } SceneView.RepaintAll(); allEditorsEnabled = AllEditorsEnabled(); } } rtomCheckBox = EditorGUILayout.ToggleLeft(new GUIContent(" Runtime-Only Mesh"), rtomCheckBox); if (rtomCheckBox != allRuntimeOnlyMesh) { foreach (Volume v in mpvObject.Volumes) { v.IsEnabledForEditing = false; v.RuntimOnlyMesh = !allRuntimeOnlyMesh; v.CreateChunks(); v.UpdateAllChunks(); } allRuntimeOnlyMesh = AllRuntimeOnlyMesh(); allEditorsEnabled = AllEditorsEnabled(); } EditorGUILayout.Space(); EditorGUILayout.LabelField("Size", new GUIStyle() { fontStyle = FontStyle.Bold }); float size = EditorGUILayout.FloatField("Voxel Size:", voxelSizeProperty.floatValue); if (size != voxelSizeProperty.floatValue && size > 0f) { voxelSizeProperty.floatValue = size; voxelSize = voxelSizeProperty.floatValue; foreach (Volume v in mpvObject.Volumes) { v.VoxelSize = voxelSize; v.CreateChunks(); } mpvObject.RepositionParts(); } EditorGUILayout.Space(); EditorGUILayout.LabelField("Pivot", new GUIStyle() { fontStyle = FontStyle.Bold }); pivotProperty.vector3Value = EditorGUILayout.Vector3Field("", pivotProperty.vector3Value, null); if (pivotProperty.vector3Value != mpvObject.Pivot) { pivot = pivotProperty.vector3Value; mpvObject.Pivot = pivot; mpvObject.RepositionParts(); } if (GUILayout.Button("Set to Center")) { mpvObject.SetPivotToCenter(); } EditorGUILayout.Space(); EditorGUILayout.LabelField("Individual Pivots", new GUIStyle() { fontStyle = FontStyle.Bold }); EditorGUILayout.BeginHorizontal(); if (GUILayout.Button("Set all to Center")) { foreach (Volume v in mpvObject.Volumes) { Vector3 piv = (new Vector3(v.XSize, v.YSize, v.ZSize) * v.VoxelSize) / 2f; v.Pivot = piv; v.UpdatePivot(); } } if (GUILayout.Button("Set all to Zero")) { foreach (Volume v in mpvObject.Volumes) { v.Pivot = Vector3.zero; v.UpdatePivot(); } } EditorGUILayout.EndHorizontal(); EditorGUILayout.Space(); EditorGUILayout.LabelField("Collision Mode", new GUIStyle() { fontStyle = FontStyle.Bold }); collisionMode.enumValueIndex = Convert.ToInt16(EditorGUILayout.EnumPopup((CollisionMode)collisionMode.enumValueIndex)); if (collisionMode.enumValueIndex != Convert.ToInt16(mpvObject.CollisionMode)) { foreach (Volume v in mpvObject.Volumes) { v.ChangeCollisionMode((CollisionMode)collisionMode.enumValueIndex); } } if (collisionMode.enumValueIndex > 0) { separateColliderMesh.boolValue = EditorGUILayout.ToggleLeft(new GUIContent(" Generate collider mesh separately (Edit-time only)"), separateColliderMesh.boolValue); if (separateColliderMesh.boolValue != mpvObject.GenerateMeshColliderSeparately) { foreach (Volume v in mpvObject.Volumes) { v.GenerateMeshColliderSeparately = separateColliderMesh.boolValue; v.UpdateAllChunks(); } } if (separateColliderMesh.boolValue) { EditorGUILayout.LabelField("Collider Meshing Mode", new GUIStyle() { fontStyle = FontStyle.Bold }); colliderMeshingMode.enumValueIndex = Convert.ToInt16(EditorGUILayout.EnumPopup((MeshingMode)colliderMeshingMode.enumValueIndex)); if (colliderMeshingMode.enumValueIndex != Convert.ToInt16(mpvObject.MeshColliderMeshingMode)) { foreach (Volume v in mpvObject.Volumes) { v.MeshColliderMeshingMode = (MeshingMode)colliderMeshingMode.enumValueIndex; v.UpdateAllChunks(); } } } } EditorGUILayout.Space(); EditorGUILayout.LabelField("Rendering", new GUIStyle() { fontStyle = FontStyle.Bold }); EditorGUILayout.LabelField("Meshing Mode", new GUIStyle() { fontStyle = FontStyle.Bold }); meshingMode.enumValueIndex = Convert.ToInt16(EditorGUILayout.EnumPopup((MeshingMode)meshingMode.enumValueIndex)); if (meshingMode.enumValueIndex != Convert.ToInt16(mpvObject.MeshingMode)) { foreach (Volume v in mpvObject.Volumes) { v.MeshingMode = (MeshingMode)meshingMode.enumValueIndex; v.UpdateAllChunks(); } } selfShadeInt.floatValue = EditorGUILayout.Slider("Self-Shading Intensity", selfShadeInt.floatValue, 0, 1); if (selfShadeInt.floatValue != mpvObject.SelfShadingIntensity) { foreach (Volume v in mpvObject.Volumes) { v.SelfShadingIntensity = selfShadeInt.floatValue; v.UpdateAllChunks(); } } material.objectReferenceValue = EditorGUILayout.ObjectField("Material: ", material.objectReferenceValue, typeof(Material), false); if (material.objectReferenceValue != mpvObject.Material) { foreach (Volume v in mpvObject.Volumes) { v.Material = (Material)material.objectReferenceValue; v.UpdateAllChunks(); } } EditorGUILayout.Space(); if (GUILayout.Button(new GUIContent("Mesh-Only Copy", "Create a copy of this Volume with mesh(es) only"))) { GameObject newMPV = new GameObject(target.name + " (Copy)"); foreach (Volume vol in mpvObject.Volumes) { GameObject bake = Instantiate(EditorUtility.VoxelVolumePrefab, Vector3.zero, Quaternion.identity) as GameObject; Volume v = bake.GetComponent <Volume>(); v.XSize = vol.XSize; v.YSize = vol.YSize; v.ZSize = vol.ZSize; v.MeshingMode = vol.MeshingMode; v.MeshColliderMeshingMode = vol.MeshColliderMeshingMode; v.GenerateMeshColliderSeparately = vol.GenerateMeshColliderSeparately; v.Material = vol.Material; for (int f = 0; f < vol.Frames.Count; f++) { v.AddFrame(f); v.Frames[f].Voxels = vol.Frames[f].Voxels; } v.CreateChunks(); v.ChangeCollisionMode(vol.CollisionMode); v.UpdateAllChunks(); bake.tag = "Untagged"; bake.name = vol.name; DestroyImmediate(bake.GetComponent <Volume>()); DestroyImmediate(bake.transform.FindChild("Hitbox").gameObject); for (int i = 0; i < bake.transform.childCount; i++) { GameObject o = bake.transform.GetChild(i).gameObject; if (o.GetComponent <Frame>() != null) { DestroyImmediate(o.GetComponent <Frame>()); for (int c = 0; c < o.transform.FindChild("Chunks").childCount; c++) { GameObject chunk = o.transform.FindChild("Chunks").GetChild(c).gameObject; if (chunk.GetComponent <Chunk>() != null) { DestroyImmediate(chunk.GetComponent <Chunk>()); } } } } bake.transform.parent = newMPV.transform; bake.transform.localPosition = vol.transform.localPosition; } } serializedObject.ApplyModifiedProperties(); }