Repository: ray-cast/UnityVOXFileImport
Branch: master
Commit: 649b302719dd
Files: 12
Total size: 49.6 KB
Directory structure:
gitextract_tyd_gif7/
├── .gitattributes
├── .gitignore
├── LICENSE
├── README.md
└── VOXFileLoader/
├── Demo/
│ ├── 8x8x8.vox
│ └── chr_sword.vox
├── Editor/
│ └── VOXFileLoader.cs
└── Scripts/
├── ObjFileExport.cs
├── VOXCruncher.cs
├── VOXFileImport.cs
├── VOXHashMap.cs
└── VOXModel.cs
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitattributes
================================================
# git files
.gitattributes export-ignore
.gitignore export-ignore
# Folders/Files
Screenshots/ export-ignore
================================================
FILE: .gitignore
================================================
*.meta
Standard Assets
Materials
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2017 ~ 2018 Rui
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
MagicaVoxel for Unity 2017
========
### VOXFileLoader ###
The VOXFileLoader is a .vox reader to convert the .vox file from [MagicaVoxel](https://ephtracy.github.io/) to static GameObject and Prefab with optimized obj file.

How to use:
========
* Download a zip archive from the github page
* Un-zip the archive
* Copy the VOXFileLoader folder to Assets folder
* Open Window -> Tools -> Cubizer -> show VOXFileLoader inspector
* Select .vox file in the project view
* Click 'Create Prefab from .vox file' button, you'll get a prefab and obj file from project view
Features:
------------
* Voxel file import for [MagicalVoxel](http://voxel.codeplex.com/)
* Mesh Optimization
* Level of detail
Requirements:
========
* Unity 2017.2.0 or higher
Contact:
------------
* Reach me via Twitter: [@Rui](https://twitter.com/Rui_cg).
[License (MIT)](https://raw.githubusercontent.com/ray-cast/ray-mmd/developing/LICENSE.txt)
-------------------------------------------------------------------------------
Copyright (C) 2016-2017 Ray-MMD Developers. All rights reserved.
https://github.com/ray-cast/UnityVOXFileImport
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
References:
--------
* Meshing in a Minecraft Game \[[link](https://0fps.net/2012/07/07/meshing-minecraft-part-2/)\]
================================================
FILE: VOXFileLoader/Editor/VOXFileLoader.cs
================================================
using System;
using System.IO;
using UnityEngine;
using UnityEditor;
using Cubizer;
using Cubizer.Model;
public class VOXFileLoader : EditorWindow
{
public bool _isSelectCreatePrefab = true;
public bool _isSelectCreateAssetbundle = true;
[MenuItem("Tools/Cubizer/Show VOXFileLoader Inspector")]
public static void ShowWindow()
{
VOXFileLoader.CreateInstance<VOXFileLoader>().Show();
}
[MenuItem("Tools/Cubizer/Load .vox file as Prefab")]
public static void LoadVoxelFileAsPrefab()
{
var filepath = EditorUtility.OpenFilePanel("Load .vox file", "", "vox");
if (!String.IsNullOrEmpty(filepath))
{
if (!filepath.Contains(".vox"))
{
EditorUtility.DisplayDialog("Invalid File", "The end of the path wasn't \".vox\"", "Ok");
return;
}
VoxFileImport.LoadVoxelFileAsPrefab(filepath);
}
}
[MenuItem("Tools/Cubizer/Load .vox file as GameObject")]
public static void LoadVoxelFileAsGameObject()
{
var filepath = EditorUtility.OpenFilePanel("Load .vox file", "", "vox");
if (!String.IsNullOrEmpty(filepath))
{
if (!filepath.Contains(".vox"))
{
EditorUtility.DisplayDialog("Invalid File", "The end of the path wasn't \".vox\"", "Ok");
return;
}
VoxFileImport.LoadVoxelFileAsGameObject(filepath);
}
}
public void OnGUI()
{
GUILayout.Label("Selected Object:", EditorStyles.boldLabel);
this._isSelectCreatePrefab = EditorGUILayout.Foldout(this._isSelectCreatePrefab, "Create Model from .vox file");
if (this._isSelectCreatePrefab)
{
if (GUILayout.Button("Create Prefab from .vox file"))
CreateVoxelPrefabsFromSelection();
if (GUILayout.Button("Create Prefab LOD from .vox file"))
CreateVoxelPrefabsFromSelection(3);
if (GUILayout.Button("Create GameObject from .vox file"))
CreateVoxelGameObjectFromSelection();
if (GUILayout.Button("Create GameObject LOD from .vox file"))
CreateVoxelGameObjectFromSelection(3);
}
this._isSelectCreateAssetbundle = EditorGUILayout.Foldout(this._isSelectCreateAssetbundle, "Create AssetBundle");
if (this._isSelectCreateAssetbundle)
{
if (GUILayout.Button("Selection To StreamingAssets folder"))
CreateAssetBundlesFromSelectionToStreamingAssets();
if (GUILayout.Button("Selection To Selected Folder"))
CreateAssetBundlesWithFolderPanel();
}
}
private static bool CreateVoxelPrefabsFromSelection(int lodLevel = 0)
{
var SelectedAsset = Selection.GetFiltered(typeof(UnityEngine.Object), SelectionMode.DeepAssets);
if (SelectedAsset.Length == 0)
{
EditorUtility.DisplayDialog("No Object Selected", "Please select any .vox file to create to prefab", "Ok");
return false;
}
foreach (var asset in SelectedAsset)
{
var path = AssetDatabase.GetAssetPath(asset);
if (Path.GetExtension(path) != ".vox")
{
EditorUtility.DisplayDialog("Invalid File", "The end of the path wasn't \".vox\"", "Ok");
return false;
}
if (path.Remove(0, path.LastIndexOf('.')) == ".vox")
{
if (lodLevel == 0)
VoxFileImport.LoadVoxelFileAsPrefab(path);
else
VoxFileImport.LoadVoxelFileAsPrefab(path, "Assets/", lodLevel);
}
}
return true;
}
private static bool CreateVoxelGameObjectFromSelection(int lodLevel = 0)
{
var SelectedAsset = Selection.GetFiltered(typeof(UnityEngine.Object), SelectionMode.DeepAssets);
if (SelectedAsset.Length == 0)
{
EditorUtility.DisplayDialog("No Object Selected", "Please select any .vox file to create to prefab", "Ok");
return false;
}
foreach (var asset in SelectedAsset)
{
var path = AssetDatabase.GetAssetPath(asset);
if (Path.GetExtension(path) != ".vox")
{
EditorUtility.DisplayDialog("Invalid File", "The end of the path wasn't \".vox\"", "Ok");
return false;
}
if (path.Remove(0, path.LastIndexOf('.')) == ".vox")
{
if (lodLevel == 0)
VoxFileImport.LoadVoxelFileAsGameObject(path);
else
VoxFileImport.LoadVoxelFileAsGameObjectLOD(path, lodLevel);
}
}
return true;
}
private static void CreateAssetBundlesFromSelection(string targetPath, string bundleName = "Resource", string ext = "")
{
var SelectedAsset = Selection.GetFiltered(typeof(UnityEngine.Object), SelectionMode.DeepAssets);
if (SelectedAsset.Length > 0)
{
AssetBundleBuild[] buildMap = new AssetBundleBuild[2];
buildMap[0].assetBundleName = bundleName + ext;
buildMap[0].assetNames = new string[SelectedAsset.Length];
for (int i = 0; i < SelectedAsset.Length; i++)
buildMap[0].assetNames[i] = AssetDatabase.GetAssetPath(SelectedAsset[i]);
if (!BuildPipeline.BuildAssetBundles(targetPath, buildMap, BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows))
UnityEngine.Debug.Log(targetPath + ": failed to load");
AssetDatabase.Refresh();
}
}
private static void CreateAssetBundlesWithFolderPanel(string bundleName = "Resource", string ext = "")
{
var SelectedPath = EditorUtility.SaveFolderPanel("Save Resource", "", "New Resource");
if (SelectedPath.Length == 0)
return;
CreateAssetBundlesFromSelection(SelectedPath + "/", bundleName, ext);
}
private static void CreateAssetBundlesFromSelectionToStreamingAssets(string bundleName = "Resource", string ext = "")
{
CreateAssetBundlesFromSelection(Application.dataPath + "/StreamingAssets/", bundleName, ext);
}
}
================================================
FILE: VOXFileLoader/Scripts/ObjFileExport.cs
================================================
using System;
using System.IO;
using System.Diagnostics;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Linq.Expressions;
using UnityEngine;
namespace Cubizer
{
namespace Model
{
public class ObjFileExport
{
public static string MeshToString(MeshFilter mf, Vector3 scale)
{
Mesh mesh = mf.sharedMesh;
Dictionary<int, int> dictionary = new Dictionary<int, int>();
if (mesh.subMeshCount > 1)
{
int[] triangles = mesh.GetTriangles(1);
for (int j = 0; j < triangles.Length; j += 3)
{
if (!dictionary.ContainsKey(triangles[j]))
dictionary.Add(triangles[j], 1);
if (!dictionary.ContainsKey(triangles[j + 1]))
dictionary.Add(triangles[j + 1], 1);
if (!dictionary.ContainsKey(triangles[j + 2]))
dictionary.Add(triangles[j + 2], 1);
}
}
StringBuilder stringBuilder = new StringBuilder().Append("mtllib design.mtl").Append("\n").Append("g ").Append(mf.name).Append("\n");
Vector3[] vertices = mesh.vertices;
foreach (Vector3 v in mesh.vertices)
{
stringBuilder.Append(string.Format("v {0} {1} {2}\n", v.x * scale.x, v.y * scale.y, v.z * scale.z));
}
stringBuilder.Append("\n");
foreach (Vector3 n in mesh.normals)
stringBuilder.Append(string.Format("vn {0} {1} {2}\n", -n.x, -n.y, n.z));
for (int num = 0; num != mesh.uv.Length; num++)
{
Vector2 uv = mesh.uv[num];
if (dictionary.ContainsKey(num))
stringBuilder.Append(string.Format("vt {0} {1}\n", mesh.uv[num].x, mesh.uv[num].y));
else
stringBuilder.Append(string.Format("vt {0} {1}\n", uv.x, uv.y));
}
for (int k = 0; k < mesh.subMeshCount; k++)
{
stringBuilder.Append("\n");
if (k == 0)
stringBuilder.Append("usemtl ").Append("Material_design").Append("\n");
if (k == 1)
stringBuilder.Append("usemtl ").Append("Material_logo").Append("\n");
int[] triangles2 = mesh.GetTriangles(k);
for (int l = 0; l < triangles2.Length; l += 3)
stringBuilder.Append(string.Format("f {0}/{0} {1}/{1} {2}/{2}\n", triangles2[l] + 1, triangles2[l + 2] + 1, triangles2[l + 1] + 1));
}
return stringBuilder.ToString();
}
public static void WriteToFile(string path, MeshFilter mf, Vector3 scale)
{
using (var sw = new StreamWriter(path))
{
sw.Write(MeshToString(mf, new Vector3(-1f, 1f, 1f)));
sw.Close();
}
}
}
}
}
================================================
FILE: VOXFileLoader/Scripts/VOXCruncher.cs
================================================
using System;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
namespace Cubizer
{
namespace Model
{
using VOXMaterial = System.Int32;
public enum VOXCruncherMode
{
Stupid,
Culled,
Greedy,
}
public struct VOXVisiableFaces
{
public bool left;
public bool right;
public bool bottom;
public bool top;
public bool back;
public bool front;
public VOXVisiableFaces(bool _left, bool _right, bool _bottom, bool _top, bool _back, bool _front)
{
left = _left;
right = _right;
bottom = _bottom;
top = _top;
back = _back;
front = _front;
}
}
public class VOXCruncher
{
public struct Vector3
{
public int x;
public int y;
public int z;
}
public Vector3 begin;
public Vector3 end;
public VOXMaterial material;
public VOXVisiableFaces faces;
public VOXCruncher(Vector3 begin, Vector3 end, VOXMaterial _material)
{
this.begin = begin;
this.end = end;
material = _material;
faces.left = true;
faces.right = true;
faces.top = true;
faces.bottom = true;
faces.front = true;
faces.back = true;
}
public VOXCruncher(int begin_x, int end_x, int begin_y, int end_y, int begin_z, int end_z, VOXMaterial _material)
{
begin.x = begin_x;
begin.y = begin_y;
begin.z = begin_z;
end.x = end_x;
end.y = end_y;
end.z = end_z;
material = _material;
faces.left = true;
faces.right = true;
faces.top = true;
faces.bottom = true;
faces.front = true;
faces.back = true;
}
public VOXCruncher(int begin_x, int end_x, int begin_y, int end_y, int begin_z, int end_z, VOXVisiableFaces _faces, VOXMaterial _material)
{
begin.x = begin_x;
begin.y = begin_y;
begin.z = begin_z;
end.x = end_x;
end.y = end_y;
end.z = end_z;
material = _material;
faces = _faces;
}
}
public interface IVOXCruncherStrategy
{
VOXModel CalcVoxelCruncher(VoxData chunk, Color32[] palette);
}
public class VOXCruncherStupid : IVOXCruncherStrategy
{
public VOXModel CalcVoxelCruncher(VoxData chunk, Color32[] palette)
{
var crunchers = new VOXCruncher[chunk.count];
var faces = new VOXVisiableFaces(true, true, true, true, true, true);
int n = 0;
for (int i = 0; i < chunk.x; ++i)
{
for (int j = 0; j < chunk.y; ++j)
{
for (int k = 0; k < chunk.z; ++k)
{
var m = chunk.voxels[i, j, k];
if (m != int.MaxValue)
crunchers[n++] = new VOXCruncher(i, i, j, j, k, k, faces, m);
}
}
}
return new VOXModel(crunchers);
}
}
public class VOXCruncherCulled : IVOXCruncherStrategy
{
public static bool GetVisiableFaces(VOXMaterial[,,] map, Vector3Int bound, int x, int y, int z, VOXMaterial material, Color32[] palette, out VOXVisiableFaces faces)
{
VOXMaterial[] instanceID = new VOXMaterial[6] { VOXMaterial.MaxValue, VOXMaterial.MaxValue, VOXMaterial.MaxValue, VOXMaterial.MaxValue, VOXMaterial.MaxValue, VOXMaterial.MaxValue };
if (x >= 1) instanceID[0] = map[(byte)(x - 1), y, z];
if (y >= 1) instanceID[2] = map[x, (byte)(y - 1), z];
if (z >= 1) instanceID[4] = map[x, y, (byte)(z - 1)];
if (x <= bound.x) instanceID[1] = map[(byte)(x + 1), y, z];
if (y <= bound.y) instanceID[3] = map[x, (byte)(y + 1), z];
if (z <= bound.z) instanceID[5] = map[x, y, (byte)(z + 1)];
var alpha = palette[material].a;
if (alpha < 255)
{
bool f1 = (instanceID[0] == VOXMaterial.MaxValue) ? true : palette[instanceID[0]].a != alpha ? true : false;
bool f2 = (instanceID[1] == VOXMaterial.MaxValue) ? true : palette[instanceID[1]].a != alpha ? true : false;
bool f3 = (instanceID[2] == VOXMaterial.MaxValue) ? true : palette[instanceID[2]].a != alpha ? true : false;
bool f4 = (instanceID[3] == VOXMaterial.MaxValue) ? true : palette[instanceID[3]].a != alpha ? true : false;
bool f5 = (instanceID[4] == VOXMaterial.MaxValue) ? true : palette[instanceID[4]].a != alpha ? true : false;
bool f6 = (instanceID[5] == VOXMaterial.MaxValue) ? true : palette[instanceID[5]].a != alpha ? true : false;
faces.left = f1;
faces.right = f2;
faces.bottom = f3;
faces.top = f4;
faces.front = f5;
faces.back = f6;
}
else
{
bool f1 = (instanceID[0] == VOXMaterial.MaxValue) ? true : palette[instanceID[0]].a < 255 ? true : false;
bool f2 = (instanceID[1] == VOXMaterial.MaxValue) ? true : palette[instanceID[1]].a < 255 ? true : false;
bool f3 = (instanceID[2] == VOXMaterial.MaxValue) ? true : palette[instanceID[2]].a < 255 ? true : false;
bool f4 = (instanceID[3] == VOXMaterial.MaxValue) ? true : palette[instanceID[3]].a < 255 ? true : false;
bool f5 = (instanceID[4] == VOXMaterial.MaxValue) ? true : palette[instanceID[4]].a < 255 ? true : false;
bool f6 = (instanceID[5] == VOXMaterial.MaxValue) ? true : palette[instanceID[5]].a < 255 ? true : false;
faces.left = f1;
faces.right = f2;
faces.bottom = f3;
faces.top = f4;
faces.front = f5;
faces.back = f6;
}
return faces.left | faces.right | faces.bottom | faces.top | faces.front | faces.back;
}
public VOXModel CalcVoxelCruncher(VoxData chunk, Color32[] palette)
{
var crunchers = new List<VOXCruncher>();
var bound = new Vector3Int(chunk.x, chunk.y, chunk.z);
for (int i = 0; i < chunk.x; ++i)
{
for (int j = 0; j < chunk.y; ++j)
{
for (int k = 0; k < chunk.z; ++k)
{
var c = chunk.voxels[i, j, k];
if (c != int.MaxValue)
{
VOXVisiableFaces faces;
if (!GetVisiableFaces(chunk.voxels, bound, i, j, k, c, palette, out faces))
continue;
crunchers.Add(new VOXCruncher((byte)i, (byte)i, (byte)j, (byte)j, (byte)k, (byte)k, faces, c));
}
}
}
}
var array = new VOXCruncher[crunchers.Count];
int numbers = 0;
foreach (var it in crunchers)
array[numbers++] = it;
return new VOXModel(array);
}
}
public class VOXCruncherGreedy : IVOXCruncherStrategy
{
public VOXModel CalcVoxelCruncher(VoxData chunk, Color32[] palette)
{
var crunchers = new List<VOXCruncher>();
var dims = new int[] { chunk.x, chunk.y, chunk.z };
var alloc = System.Math.Max(dims[0], System.Math.Max(dims[1], dims[2]));
var mask = new int[alloc * alloc];
var map = chunk.voxels;
for (var d = 0; d < 3; ++d)
{
var u = (d + 1) % 3;
var v = (d + 2) % 3;
var x = new int[3] { 0, 0, 0 };
var q = new int[3] { 0, 0, 0 };
q[d] = 1;
var faces = new VOXVisiableFaces(false, false, false, false, false, false);
for (x[d] = -1; x[d] < dims[d];)
{
var n = 0;
for (x[v] = 0; x[v] < dims[v]; ++x[v])
{
for (x[u] = 0; x[u] < dims[u]; ++x[u])
{
var a = x[d] >= 0 ? map[x[0], x[1], x[2]] : VOXMaterial.MaxValue;
var b = x[d] < dims[d] - 1 ? map[x[0] + q[0], x[1] + q[1], x[2] + q[2]] : VOXMaterial.MaxValue;
if (a != b)
{
if (a == VOXMaterial.MaxValue)
mask[n++] = b;
else if (b == VOXMaterial.MaxValue)
mask[n++] = -a;
else
mask[n++] = -b;
}
else
{
mask[n++] = VOXMaterial.MaxValue;
}
}
}
++x[d];
n = 0;
for (var j = 0; j < dims[v]; ++j)
{
for (var i = 0; i < dims[u];)
{
var c = mask[n];
if (c == VOXMaterial.MaxValue)
{
++i; ++n;
continue;
}
var w = 1;
var h = 1;
var k = 0;
for (; (i + w) < dims[u] && c == mask[n + w]; ++w) { }
var done = false;
for (; (j + h) < dims[v]; ++h)
{
for (k = 0; k < w; ++k)
{
if (c != mask[n + k + h * dims[u]])
{
done = true;
break;
}
}
if (done)
break;
}
x[u] = i; x[v] = j;
var du = new int[3] { 0, 0, 0 };
var dv = new int[3] { 0, 0, 0 };
du[u] = w;
dv[v] = h;
var v1 = new Vector3(x[0], x[1], x[2]);
var v2 = new Vector3(x[0] + du[0] + dv[0], x[1] + du[1] + dv[1], x[2] + du[2] + dv[2]);
v2.x = System.Math.Max(v2.x - 1, 0);
v2.y = System.Math.Max(v2.y - 1, 0);
v2.z = System.Math.Max(v2.z - 1, 0);
if (c > 0)
{
faces.front = d == 2;
faces.back = false;
faces.left = d == 0;
faces.right = false;
faces.top = false;
faces.bottom = d == 1;
}
else
{
c = -c;
faces.front = false;
faces.back = d == 2;
faces.left = false;
faces.right = d == 0;
faces.top = d == 1;
faces.bottom = false;
}
crunchers.Add(new VOXCruncher((byte)v1.x, (byte)(v2.x), (byte)(v1.y), (byte)(v2.y), (byte)(v1.z), (byte)(v2.z), faces, c));
for (var l = 0; l < h; ++l)
{
for (k = 0; k < w; ++k)
mask[n + k + l * dims[u]] = VOXMaterial.MaxValue;
}
i += w; n += w;
}
}
}
}
var array = new VOXCruncher[crunchers.Count];
int numbers = 0;
foreach (var it in crunchers)
array[numbers++] = it;
return new VOXModel(array);
}
}
public class VOXPolygonCruncher
{
public static VOXModel CalcVoxelCruncher(VoxData chunk, Color32[] palette, VOXCruncherMode mode)
{
switch (mode)
{
case VOXCruncherMode.Stupid:
return new VOXCruncherStupid().CalcVoxelCruncher(chunk, palette);
case VOXCruncherMode.Culled:
return new VOXCruncherCulled().CalcVoxelCruncher(chunk, palette);
case VOXCruncherMode.Greedy:
return new VOXCruncherGreedy().CalcVoxelCruncher(chunk, palette);
default:
return null;
}
}
}
}
}
================================================
FILE: VOXFileLoader/Scripts/VOXFileImport.cs
================================================
using System;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace Cubizer
{
namespace Model
{
public struct VoxFileHeader
{
public byte[] header;
public Int32 version;
}
public struct VoxFilePack
{
public byte[] name;
public Int32 chunkContent;
public Int32 chunkNums;
public Int32 modelNums;
}
public struct VoxFileSize
{
public byte[] name;
public Int32 chunkContent;
public Int32 chunkNums;
public Int32 x;
public Int32 y;
public Int32 z;
}
public struct VoxFileXYZI
{
public byte[] name;
public Int32 chunkContent;
public Int32 chunkNums;
public VoxData voxels;
}
public struct VoxFileRGBA
{
public byte[] name;
public Int32 chunkContent;
public Int32 chunkNums;
public uint[] values;
}
public struct VoxFileChunkChild
{
public VoxFileSize size;
public VoxFileXYZI xyzi;
}
public struct VoxFileChunk
{
public byte[] name;
public Int32 chunkContent;
public Int32 chunkNums;
}
public struct VoxFileMaterial
{
public int id;
public int type;
public float weight;
public int propertyBits;
public float[] propertyValue;
}
public class VoxFileData
{
public VoxFileHeader hdr;
public VoxFileChunk main;
public VoxFilePack pack;
public VoxFileChunkChild[] chunkChild;
public VoxFileRGBA palette;
}
public class VoxData
{
public int x, y, z;
public int[,,] voxels;
public int count
{
get
{
int _count = 0;
for (int i = 0; i < x; ++i)
{
for (int j = 0; j < y; ++j)
for (int k = 0; k < z; ++k)
if (voxels[i, j, k] != int.MaxValue)
_count++;
}
return _count;
}
}
public VoxData()
{
x = 0; y = 0; z = 0;
}
public VoxData(byte[] _voxels, int xx, int yy, int zz)
{
x = xx;
y = zz;
z = yy;
voxels = new int[x, y, z];
for (int i = 0; i < x; ++i)
{
for (int j = 0; j < y; ++j)
for (int k = 0; k < z; ++k)
voxels[i, j, k] = int.MaxValue;
}
for (int j = 0; j < _voxels.Length; j += 4)
{
var x = _voxels[j];
var y = _voxels[j + 1];
var z = _voxels[j + 2];
var c = _voxels[j + 3];
voxels[x, z, y] = c;
}
}
public int GetMajorityColorIndex(int xx, int yy, int zz, int lodLevel)
{
xx = Mathf.Min(xx, x - 2);
yy = Mathf.Min(yy, y - 2);
zz = Mathf.Min(zz, z - 2);
int[] samples = new int[lodLevel * lodLevel * lodLevel];
for (int i = 0; i < lodLevel; i++)
{
for (int j = 0; j < lodLevel; j++)
{
for (int k = 0; k < lodLevel; k++)
{
if (xx + i > x - 1 || yy + j > y - 1 || zz + k > z - 1)
samples[i * lodLevel * lodLevel + j * lodLevel + k] = int.MaxValue;
else
samples[i * lodLevel * lodLevel + j * lodLevel + k] = voxels[xx + i, yy + j, zz + k];
}
}
}
int maxNum = 1;
int maxNumIndex = 0;
int[] numIndex = new int[samples.Length];
for (int i = 0; i < samples.Length; i++)
numIndex[i] = samples[i] == int.MaxValue ? 0 : 1;
for (int i = 0; i < samples.Length; i++)
{
for (int j = 0; j < samples.Length; j++)
{
if (i != j && samples[i] != int.MaxValue && samples[i] == samples[j])
{
numIndex[i]++;
if (numIndex[i] > maxNum)
{
maxNum = numIndex[i];
maxNumIndex = i;
}
}
}
}
return samples[maxNumIndex];
}
public VoxData GetVoxelDataLOD(int level)
{
if (x <= 1 || y <= 1 || z <= 1)
return null;
level = Mathf.Clamp(level, 0, 16);
if (level <= 1)
return this;
if (x <= level && y <= level && z <= level)
return this;
VoxData data = new VoxData();
data.x = Mathf.CeilToInt((float)x / level);
data.y = Mathf.CeilToInt((float)y / level);
data.z = Mathf.CeilToInt((float)z / level);
data.voxels = new int[data.x, data.y, data.z];
for (int x = 0; x < data.x; x++)
{
for (int y = 0; y < data.y; y++)
{
for (int z = 0; z < data.z; z++)
{
data.voxels[x, y, z] = this.GetMajorityColorIndex(x * level, y * level, z * level, level);
}
}
}
return data;
}
}
public class VoxFileImport
{
private static uint[] _paletteDefault = new uint[256]
{
0x00000000, 0xffffffff, 0xffccffff, 0xff99ffff, 0xff66ffff, 0xff33ffff, 0xff00ffff, 0xffffccff, 0xffccccff, 0xff99ccff, 0xff66ccff, 0xff33ccff, 0xff00ccff, 0xffff99ff, 0xffcc99ff, 0xff9999ff,
0xff6699ff, 0xff3399ff, 0xff0099ff, 0xffff66ff, 0xffcc66ff, 0xff9966ff, 0xff6666ff, 0xff3366ff, 0xff0066ff, 0xffff33ff, 0xffcc33ff, 0xff9933ff, 0xff6633ff, 0xff3333ff, 0xff0033ff, 0xffff00ff,
0xffcc00ff, 0xff9900ff, 0xff6600ff, 0xff3300ff, 0xff0000ff, 0xffffffcc, 0xffccffcc, 0xff99ffcc, 0xff66ffcc, 0xff33ffcc, 0xff00ffcc, 0xffffcccc, 0xffcccccc, 0xff99cccc, 0xff66cccc, 0xff33cccc,
0xff00cccc, 0xffff99cc, 0xffcc99cc, 0xff9999cc, 0xff6699cc, 0xff3399cc, 0xff0099cc, 0xffff66cc, 0xffcc66cc, 0xff9966cc, 0xff6666cc, 0xff3366cc, 0xff0066cc, 0xffff33cc, 0xffcc33cc, 0xff9933cc,
0xff6633cc, 0xff3333cc, 0xff0033cc, 0xffff00cc, 0xffcc00cc, 0xff9900cc, 0xff6600cc, 0xff3300cc, 0xff0000cc, 0xffffff99, 0xffccff99, 0xff99ff99, 0xff66ff99, 0xff33ff99, 0xff00ff99, 0xffffcc99,
0xffcccc99, 0xff99cc99, 0xff66cc99, 0xff33cc99, 0xff00cc99, 0xffff9999, 0xffcc9999, 0xff999999, 0xff669999, 0xff339999, 0xff009999, 0xffff6699, 0xffcc6699, 0xff996699, 0xff666699, 0xff336699,
0xff006699, 0xffff3399, 0xffcc3399, 0xff993399, 0xff663399, 0xff333399, 0xff003399, 0xffff0099, 0xffcc0099, 0xff990099, 0xff660099, 0xff330099, 0xff000099, 0xffffff66, 0xffccff66, 0xff99ff66,
0xff66ff66, 0xff33ff66, 0xff00ff66, 0xffffcc66, 0xffcccc66, 0xff99cc66, 0xff66cc66, 0xff33cc66, 0xff00cc66, 0xffff9966, 0xffcc9966, 0xff999966, 0xff669966, 0xff339966, 0xff009966, 0xffff6666,
0xffcc6666, 0xff996666, 0xff666666, 0xff336666, 0xff006666, 0xffff3366, 0xffcc3366, 0xff993366, 0xff663366, 0xff333366, 0xff003366, 0xffff0066, 0xffcc0066, 0xff990066, 0xff660066, 0xff330066,
0xff000066, 0xffffff33, 0xffccff33, 0xff99ff33, 0xff66ff33, 0xff33ff33, 0xff00ff33, 0xffffcc33, 0xffcccc33, 0xff99cc33, 0xff66cc33, 0xff33cc33, 0xff00cc33, 0xffff9933, 0xffcc9933, 0xff999933,
0xff669933, 0xff339933, 0xff009933, 0xffff6633, 0xffcc6633, 0xff996633, 0xff666633, 0xff336633, 0xff006633, 0xffff3333, 0xffcc3333, 0xff993333, 0xff663333, 0xff333333, 0xff003333, 0xffff0033,
0xffcc0033, 0xff990033, 0xff660033, 0xff330033, 0xff000033, 0xffffff00, 0xffccff00, 0xff99ff00, 0xff66ff00, 0xff33ff00, 0xff00ff00, 0xffffcc00, 0xffcccc00, 0xff99cc00, 0xff66cc00, 0xff33cc00,
0xff00cc00, 0xffff9900, 0xffcc9900, 0xff999900, 0xff669900, 0xff339900, 0xff009900, 0xffff6600, 0xffcc6600, 0xff996600, 0xff666600, 0xff336600, 0xff006600, 0xffff3300, 0xffcc3300, 0xff993300,
0xff663300, 0xff333300, 0xff003300, 0xffff0000, 0xffcc0000, 0xff990000, 0xff660000, 0xff330000, 0xff0000ee, 0xff0000dd, 0xff0000bb, 0xff0000aa, 0xff000088, 0xff000077, 0xff000055, 0xff000044,
0xff000022, 0xff000011, 0xff00ee00, 0xff00dd00, 0xff00bb00, 0xff00aa00, 0xff008800, 0xff007700, 0xff005500, 0xff004400, 0xff002200, 0xff001100, 0xffee0000, 0xffdd0000, 0xffbb0000, 0xffaa0000,
0xff880000, 0xff770000, 0xff550000, 0xff440000, 0xff220000, 0xff110000, 0xffeeeeee, 0xffdddddd, 0xffbbbbbb, 0xffaaaaaa, 0xff888888, 0xff777777, 0xff555555, 0xff444444, 0xff222222, 0xff111111
};
private static UnityEngine.Object _assetPrefab;
public static VoxFileData Load(string path)
{
using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read))
{
if (stream == null)
throw new System.Exception("Failed to open file for FileStream.");
using (var reader = new BinaryReader(stream))
{
VoxFileData voxel = new VoxFileData();
voxel.hdr.header = reader.ReadBytes(4);
voxel.hdr.version = reader.ReadInt32();
if (voxel.hdr.header[0] != 'V' || voxel.hdr.header[1] != 'O' || voxel.hdr.header[2] != 'X' || voxel.hdr.header[3] != ' ')
throw new System.Exception("Bad Token: token is not VOX.");
if (voxel.hdr.version != 150)
throw new System.Exception("The version of file isn't 150 that version of vox, tihs version of file is " + voxel.hdr.version + ".");
voxel.main.name = reader.ReadBytes(4);
voxel.main.chunkContent = reader.ReadInt32();
voxel.main.chunkNums = reader.ReadInt32();
if (voxel.main.name[0] != 'M' || voxel.main.name[1] != 'A' || voxel.main.name[2] != 'I' || voxel.main.name[3] != 'N')
throw new System.Exception("Bad Token: token is not MAIN.");
if (voxel.main.chunkContent != 0)
throw new System.Exception("Bad Token: chunk content is " + voxel.main.chunkContent + ", it should be 0.");
if (reader.PeekChar() == 'P')
{
voxel.pack.name = reader.ReadBytes(4);
if (voxel.pack.name[0] != 'P' || voxel.pack.name[1] != 'A' || voxel.pack.name[2] != 'C' || voxel.pack.name[3] != 'K')
throw new System.Exception("Bad Token: token is not PACK");
voxel.pack.chunkContent = reader.ReadInt32();
voxel.pack.chunkNums = reader.ReadInt32();
voxel.pack.modelNums = reader.ReadInt32();
if (voxel.pack.modelNums == 0)
throw new System.Exception("Bad Token: model nums must be greater than zero.");
}
else
{
voxel.pack.chunkContent = 0;
voxel.pack.chunkNums = 0;
voxel.pack.modelNums = 1;
}
voxel.chunkChild = new VoxFileChunkChild[voxel.pack.modelNums];
for (int i = 0; i < voxel.pack.modelNums; i++)
{
var chunk = new VoxFileChunkChild();
chunk.size.name = reader.ReadBytes(4);
chunk.size.chunkContent = reader.ReadInt32();
chunk.size.chunkNums = reader.ReadInt32();
chunk.size.x = reader.ReadInt32();
chunk.size.y = reader.ReadInt32();
chunk.size.z = reader.ReadInt32();
if (chunk.size.name[0] != 'S' || chunk.size.name[1] != 'I' || chunk.size.name[2] != 'Z' || chunk.size.name[3] != 'E')
throw new System.Exception("Bad Token: token is not SIZE");
if (chunk.size.chunkContent != 12)
throw new System.Exception("Bad Token: chunk content is " + chunk.size.chunkContent + ", it should be 12.");
chunk.xyzi.name = reader.ReadBytes(4);
if (chunk.xyzi.name[0] != 'X' || chunk.xyzi.name[1] != 'Y' || chunk.xyzi.name[2] != 'Z' || chunk.xyzi.name[3] != 'I')
throw new System.Exception("Bad Token: token is not XYZI");
chunk.xyzi.chunkContent = reader.ReadInt32();
chunk.xyzi.chunkNums = reader.ReadInt32();
if (chunk.xyzi.chunkNums != 0)
throw new System.Exception("Bad Token: chunk nums is " + chunk.xyzi.chunkNums + ",i t should be 0.");
var voxelNums = reader.ReadInt32();
var voxels = new byte[voxelNums * 4];
if (reader.Read(voxels, 0, voxels.Length) != voxels.Length)
throw new System.Exception("Failed to read voxels");
chunk.xyzi.voxels = new VoxData(voxels, chunk.size.x, chunk.size.y, chunk.size.z);
voxel.chunkChild[i] = chunk;
}
if (reader.BaseStream.Position < reader.BaseStream.Length)
{
byte[] palette = reader.ReadBytes(4);
if (palette[0] != 'R' || palette[1] != 'G' || palette[2] != 'B' || palette[3] != 'A')
throw new System.Exception("Bad Token: token is not RGBA");
voxel.palette.chunkContent = reader.ReadInt32();
voxel.palette.chunkNums = reader.ReadInt32();
var bytePalette = new byte[voxel.palette.chunkContent];
reader.Read(bytePalette, 0, voxel.palette.chunkContent);
voxel.palette.values = new uint[voxel.palette.chunkContent / 4];
for (int i = 4; i < bytePalette.Length; i += 4)
voxel.palette.values[i / 4] = BitConverter.ToUInt32(bytePalette, i - 4);
}
else
{
voxel.palette.values = new uint[256];
_paletteDefault.CopyTo(voxel.palette.values, 0);
}
return voxel;
}
}
}
public static Color32[] CreateColor32FromPelatte(uint[] palette)
{
Debug.Assert(palette.Length == 256);
Color32[] colors = new Color32[256];
for (uint j = 0; j < 256; j++)
{
uint rgba = palette[j];
Color32 color = new Color32();
color.r = (byte)((rgba >> 0) & 0xFF);
color.g = (byte)((rgba >> 8) & 0xFF);
color.b = (byte)((rgba >> 16) & 0xFF);
color.a = (byte)((rgba >> 24) & 0xFF);
colors[j] = color;
}
return colors;
}
public static Texture2D CreateTextureFromColor16x16(Color32[] colors)
{
Debug.Assert(colors.Length == 256);
Texture2D texture = new Texture2D(16, 16, TextureFormat.ARGB32, false, false);
texture.name = "texture";
texture.SetPixels32(colors);
texture.Apply();
return texture;
}
public static Texture2D CreateTextureFromColor256(Color32[] colors)
{
Debug.Assert(colors.Length == 256);
Texture2D texture = new Texture2D(256, 1, TextureFormat.ARGB32, false, false);
texture.name = "texture";
texture.SetPixels32(colors);
texture.Apply();
return texture;
}
public static Texture2D CreateTextureFromPelatte16x16(uint[] palette)
{
Debug.Assert(palette.Length == 256);
return CreateTextureFromColor16x16(CreateColor32FromPelatte(palette));
}
public static int CalcFaceCountAsAllocate(VOXModel model, Color32[] palette, ref Dictionary<string, int> entities)
{
entities.Add("opaque", 0);
foreach (var it in model.voxels)
{
bool[] visiable = new bool[] { it.faces.left, it.faces.right, it.faces.top, it.faces.bottom, it.faces.front, it.faces.back };
int facesCount = 0;
for (int j = 0; j < 6; j++)
{
if (visiable[j])
facesCount++;
}
entities["opaque"] += facesCount;
}
return entities.Count;
}
public static GameObject CreateGameObject(string name, VoxData data, Texture2D texture, Color32[] colors, float scale)
{
var cruncher = VOXPolygonCruncher.CalcVoxelCruncher(data, colors, VOXCruncherMode.Greedy);
var entities = new Dictionary<string, int>();
if (CalcFaceCountAsAllocate(cruncher, colors, ref entities) == 0)
throw new System.Exception(name + ": There is no voxel for this file");
var model = new GameObject(name);
foreach (var entity in entities)
{
if (entity.Value == 0)
continue;
var index = 0;
var allocSize = entity.Value;
var vertices = new Vector3[allocSize * 4];
var normals = new Vector3[allocSize * 4];
var uv = new Vector2[allocSize * 4];
var triangles = new int[allocSize * 6];
bool isTransparent = false;
foreach (var it in cruncher.voxels)
{
VOXModel.CreateCubeMesh16x16(it, ref vertices, ref normals, ref uv, ref triangles, ref index, scale);
isTransparent |= (colors[it.material].a < 255) ? true : false;
}
if (triangles.Length > 0)
{
Mesh mesh = new Mesh();
mesh.name = "mesh";
mesh.vertices = vertices;
mesh.normals = normals;
mesh.uv = uv;
mesh.triangles = triangles;
var meshFilter = model.AddComponent<MeshFilter>();
var meshRenderer = model.AddComponent<MeshRenderer>();
#if UNITY_EDITOR
MeshUtility.Optimize(mesh);
meshFilter.sharedMesh = mesh;
meshRenderer.sharedMaterial = new Material(Shader.Find("Mobile/Diffuse"));
meshRenderer.sharedMaterial.name = "material";
meshRenderer.sharedMaterial.mainTexture = texture;
#else
meshFilter.mesh = mesh;
meshRenderer.material = new Material(Shader.Find("Mobile/Diffuse"));
meshRenderer.material.mainTexture = texture;
#endif
}
}
return model;
}
public static GameObject LoadVoxelFileAsGameObject(string name, VoxFileData voxel, int lodLevel)
{
Debug.Assert(!String.IsNullOrEmpty(name));
GameObject gameObject = new GameObject();
gameObject.name = name;
gameObject.isStatic = true;
try
{
var colors = CreateColor32FromPelatte(voxel.palette.values);
var texture = CreateTextureFromColor16x16(colors);
if (lodLevel <= 1)
{
foreach (var chunk in voxel.chunkChild)
{
var submesh = CreateGameObject("model", chunk.xyzi.voxels, texture, colors, 1);
submesh.transform.parent = gameObject.transform;
}
}
else
{
foreach (var chunk in voxel.chunkChild)
{
for (int lod = 1; lod < lodLevel + 1; lod++)
{
var submesh = CreateGameObject("lod" + (lod - 1), chunk.xyzi.voxels.GetVoxelDataLOD(lod), texture, colors, lod);
submesh.transform.parent = gameObject.transform;
}
var lodgroup = gameObject.AddComponent<LODGroup>();
var lods = lodgroup.GetLODs();
for (int i = 0; i < gameObject.transform.childCount; i++)
lods[i].renderers = new Renderer[] { gameObject.transform.GetChild(i).GetComponent<MeshRenderer>() };
lodgroup.SetLODs(lods);
}
}
}
catch (SystemException e)
{
GameObject.DestroyImmediate(gameObject);
throw e;
}
return gameObject;
}
public static GameObject LoadVoxelFileAsGameObject(string path)
{
var voxel = VoxFileImport.Load(path);
return LoadVoxelFileAsGameObject(Path.GetFileNameWithoutExtension(path), voxel, 0);
}
public static GameObject LoadVoxelFileAsGameObjectLOD(string path, int lodLevel)
{
var voxel = VoxFileImport.Load(path);
return LoadVoxelFileAsGameObject(Path.GetFileNameWithoutExtension(path), voxel, lodLevel);
}
#if UNITY_EDITOR
public static GameObject LoadVoxelFileAsPrefab(VoxFileData voxel, string name, string path = "Assets/", int lodLevel = 0)
{
Debug.Assert(!String.IsNullOrEmpty(name));
GameObject gameObject = null;
try
{
gameObject = LoadVoxelFileAsGameObject(name, voxel, lodLevel);
var prefabPath = path + name + ".prefab";
var prefab = PrefabUtility.CreateEmptyPrefab(prefabPath);
var prefabTextures = new Dictionary<string, int>();
for (int i = 0; i < gameObject.transform.childCount; i++)
{
var subObject = gameObject.transform.GetChild(i);
var meshFilter = subObject.GetComponent<MeshFilter>();
if (meshFilter != null)
{
AssetDatabase.AddObjectToAsset(meshFilter.sharedMesh, prefabPath);
}
var renderer = subObject.GetComponent<MeshRenderer>();
if (renderer != null)
{
if (renderer.sharedMaterial != null)
{
AssetDatabase.AddObjectToAsset(renderer.sharedMaterial, prefabPath);
var textureName = renderer.sharedMaterial.mainTexture.name;
if (!prefabTextures.ContainsKey(textureName))
{
prefabTextures.Add(textureName, 1);
AssetDatabase.AddObjectToAsset(renderer.sharedMaterial.mainTexture, prefabPath);
}
}
}
}
return PrefabUtility.ReplacePrefab(gameObject, prefab, ReplacePrefabOptions.ReplaceNameBased);
}
finally
{
GameObject.DestroyImmediate(gameObject);
}
}
public static GameObject LoadVoxelFileAsPrefab(string path, string outpath = "Assets/", int lodLevel = 0)
{
var voxel = VoxFileImport.Load(path);
return LoadVoxelFileAsPrefab(voxel, Path.GetFileNameWithoutExtension(path), outpath, lodLevel);
}
#endif
}
}
}
================================================
FILE: VOXFileLoader/Scripts/VOXHashMap.cs
================================================
using System;
using System.Diagnostics;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using UnityEngine;
namespace Cubizer
{
using VOXMaterial = System.Int32;
namespace Model
{
[Serializable]
public class VOXHashMapNode<_Tx>
where _Tx : struct
{
public _Tx x;
public _Tx y;
public _Tx z;
public VOXMaterial element;
public VOXHashMapNode()
{
element = int.MaxValue;
}
public VOXHashMapNode(_Tx xx, _Tx yy, _Tx zz, VOXMaterial value)
{
x = xx;
y = yy;
z = zz;
element = value;
}
public bool is_empty()
{
return element == int.MaxValue;
}
}
public class VOXHashMapNodeEnumerable<_Tx> : IEnumerable
where _Tx : struct
{
private VOXHashMapNode<_Tx>[] _array;
public VOXHashMapNodeEnumerable(VOXHashMapNode<_Tx>[] array)
{
_array = array;
}
IEnumerator IEnumerable.GetEnumerator()
{
return (IEnumerator)GetEnumerator();
}
public VOXHashMapNodeEnum<_Tx> GetEnumerator()
{
return new VOXHashMapNodeEnum<_Tx>(_array);
}
}
public class VOXHashMapNodeEnum<_Tx> : IEnumerator
where _Tx : struct
{
private int position = -1;
private VOXHashMapNode<_Tx>[] _array;
public VOXHashMapNodeEnum(VOXHashMapNode<_Tx>[] list)
{
_array = list;
}
public bool MoveNext()
{
var length = _array.Length;
for (position++; position < length; position++)
{
if (_array[position] == null)
continue;
if (_array[position].is_empty())
continue;
break;
}
return position < _array.Length;
}
public void Reset()
{
position = -1;
}
object IEnumerator.Current
{
get
{
return Current;
}
}
public VOXHashMapNode<_Tx> Current
{
get
{
return _array[position];
}
}
}
[Serializable]
public class VOXHashMap
{
protected int _count;
protected int _allocSize;
protected Vector3Int _bound;
protected VOXHashMapNode<System.Byte>[] _data;
public int Count { get { return _count; } }
public Vector3Int bound { get { return _bound; } }
public VOXHashMap(Vector3Int bound)
{
_count = 0;
_bound = bound;
_allocSize = 0;
}
public VOXHashMap(Vector3Int bound, int count)
{
_count = 0;
_bound = bound;
_allocSize = 0;
this.Create(count);
}
public VOXHashMap(int bound_x, int bound_y, int bound_z, int count)
{
_count = 0;
_bound = new Vector3Int(bound_x, bound_y, bound_z);
_allocSize = 0;
this.Create(count);
}
public void Create(int count)
{
int usage = 1;
while (usage < count) usage = usage << 1 | 1;
_count = 0;
_allocSize = usage;
_data = new VOXHashMapNode<System.Byte>[usage + 1];
}
public bool Set(System.Byte x, System.Byte y, System.Byte z, VOXMaterial value, bool replace = true)
{
if (_allocSize == 0)
this.Create(0xFF);
var index = HashInt(x, y, z) & _allocSize;
var entry = _data[index];
while (entry != null)
{
if (entry.x == x && entry.y == y && entry.z == z)
{
if (replace)
{
_data[index].element = value;
return true;
}
return false;
}
index = (index + 1) & _allocSize;
entry = _data[index];
}
if (value != VOXMaterial.MaxValue)
{
_data[index] = new VOXHashMapNode<System.Byte>(x, y, z, value);
_count++;
if (_count >= _allocSize)
this.Grow();
return true;
}
return false;
}
public bool Get(System.Byte x, System.Byte y, System.Byte z, ref VOXMaterial instanceID)
{
if (_allocSize == 0)
return false;
var index = HashInt(x, y, z) & _allocSize;
var entry = _data[index];
while (entry != null)
{
if (entry.x == x && entry.y == y && entry.z == z)
{
instanceID = entry.element;
return instanceID != VOXMaterial.MaxValue;
}
index = (index + 1) & _allocSize;
entry = _data[index];
}
instanceID = VOXMaterial.MaxValue;
return false;
}
public bool Exists(System.Byte x, System.Byte y, System.Byte z)
{
VOXMaterial instanceID = VOXMaterial.MaxValue;
return this.Get(x, y, z, ref instanceID);
}
public bool Empty()
{
return _count == 0;
}
public VOXHashMapNodeEnumerable<System.Byte> GetEnumerator()
{
if (_data == null)
throw new System.ApplicationException("GetEnumerator: Empty data");
return new VOXHashMapNodeEnumerable<System.Byte>(_data);
}
public static bool Save(string path, VOXHashMap map)
{
UnityEngine.Debug.Assert(map != null);
var stream = new FileStream(path, FileMode.Create, FileAccess.Write);
var serializer = new BinaryFormatter();
serializer.Serialize(stream, map);
stream.Close();
return true;
}
public static VOXHashMap Load(string path)
{
var serializer = new BinaryFormatter();
var loadFile = new FileStream(path, FileMode.Open, FileAccess.Read);
return serializer.Deserialize(loadFile) as VOXHashMap;
}
private bool Grow(VOXHashMapNode<System.Byte> data)
{
var index = HashInt(data.x, data.y, data.z) & _allocSize;
var entry = _data[index];
while (entry != null)
{
index = (index + 1) & _allocSize;
entry = _data[index];
}
if (data.element != VOXMaterial.MaxValue)
{
_data[index] = data;
_count++;
return true;
}
return false;
}
private void Grow()
{
var map = new VOXHashMap(_bound, _allocSize << 1 | 1);
foreach (var it in GetEnumerator())
map.Grow(it);
_count = map._count;
_allocSize = map._allocSize;
_data = map._data;
}
private static int _hash_int(int key)
{
key = ~key + (key << 15);
key = key ^ (key >> 12);
key = key + (key << 2);
key = key ^ (key >> 4);
key = key * 2057;
key = key ^ (key >> 16);
return key;
}
public static int HashInt(int x, int y, int z)
{
return _hash_int(x) ^ _hash_int(y) ^ _hash_int(z);
}
}
}
}
================================================
FILE: VOXFileLoader/Scripts/VOXModel.cs
================================================
using UnityEngine;
namespace Cubizer
{
namespace Model
{
public class VOXModel
{
private static Vector3[,] _positions = new Vector3[6, 4]
{
{ new Vector3(-1, -1, -1), new Vector3(-1, -1, +1), new Vector3(-1, +1, -1), new Vector3(-1, +1, +1) },
{ new Vector3(+1, -1, -1), new Vector3(+1, -1, +1), new Vector3(+1, +1, -1), new Vector3(+1, +1, +1) },
{ new Vector3(-1, +1, -1), new Vector3(-1, +1, +1), new Vector3(+1, +1, -1), new Vector3(+1, +1, +1) },
{ new Vector3(-1, -1, -1), new Vector3(-1, -1, +1), new Vector3(+1, -1, -1), new Vector3(+1, -1, +1) },
{ new Vector3(-1, -1, -1), new Vector3(-1, +1, -1), new Vector3(+1, -1, -1), new Vector3(+1, +1, -1) },
{ new Vector3(-1, -1, +1), new Vector3(-1, +1, +1), new Vector3(+1, -1, +1), new Vector3(+1, +1, +1) }
};
private static Vector3[] _normals = new Vector3[6]
{
new Vector3(-1, 0, 0),
new Vector3(+1, 0, 0),
new Vector3(0, +1, 0),
new Vector3(0, -1, 0),
new Vector3(0, 0, -1),
new Vector3(0, 0, +1)
};
private static Vector2[,] _uvs = new Vector2[6, 4]
{
{ new Vector2(0, 0), new Vector2(1, 0), new Vector2(0, 1), new Vector2(1, 1) },
{ new Vector2(1, 0), new Vector2(0, 0), new Vector2(1, 1), new Vector2(0, 1) },
{ new Vector2(0, 1), new Vector2(0, 0), new Vector2(1, 1), new Vector2(1, 0) },
{ new Vector2(0, 0), new Vector2(0, 1), new Vector2(1, 0), new Vector2(1, 1) },
{ new Vector2(0, 0), new Vector2(0, 1), new Vector2(1, 0), new Vector2(1, 1) },
{ new Vector2(1, 0), new Vector2(1, 1), new Vector2(0, 0), new Vector2(0, 1) }
};
private static int[,] _indices = new int[6, 6]
{
{ 0, 3, 2, 0, 1, 3 },
{ 0, 3, 1, 0, 2, 3 },
{ 0, 3, 2, 0, 1, 3 },
{ 0, 3, 1, 0, 2, 3 },
{ 0, 3, 2, 0, 1, 3 },
{ 0, 3, 1, 0, 2, 3 }
};
public VOXCruncher[] voxels;
public VOXModel(VOXCruncher[] array)
{
voxels = array;
}
public static void CreateCubeMesh16x16(ref Vector3[] vertices, ref Vector3[] normals, ref Vector2[] uv, ref int[] triangles, ref int index, VOXVisiableFaces faces, Vector3 translate, Vector3 scale, uint palette)
{
bool[] visiable = new bool[] { faces.left, faces.right, faces.top, faces.bottom, faces.front, faces.back };
float s = 1.0f / 16.0f;
float a = 0 + 1.0f / 32.0f;
float b = s - 1.0f / 32.0f;
for (int i = 0; i < 6; i++)
{
if (!visiable[i])
continue;
for (int n = index * 4, k = 0; k < 4; k++, n++)
{
Vector3 v = _positions[i, k] * 0.5f;
v.x *= scale.x;
v.y *= scale.y;
v.z *= scale.z;
v += translate;
float du = (palette % 16) * s;
float dv = (palette / 16) * s;
Vector2 coord;
coord.x = du + (_uvs[i, k].x > 0 ? b : a);
coord.y = dv + (_uvs[i, k].y > 0 ? b : a);
vertices[n] = v;
normals[n] = _normals[i];
uv[n] = coord;
}
for (int j = index * 6, k = 0; k < 6; k++, j++)
triangles[j] = index * 4 + _indices[i, k];
index++;
}
}
public static void CreateCubeMesh16x16(VOXCruncher it, ref Vector3[] vertices, ref Vector3[] normals, ref Vector2[] uv, ref int[] triangles, ref int index, float scaling)
{
Vector3 pos;
pos.x = (it.begin.x + it.end.x + 1) * 0.5f * scaling;
pos.y = (it.begin.y + it.end.y + 1) * 0.5f * scaling;
pos.z = (it.begin.z + it.end.z + 1) * 0.5f * scaling;
Vector3 scale;
scale.x = (it.end.x + 1 - it.begin.x) * scaling;
scale.y = (it.end.y + 1 - it.begin.y) * scaling;
scale.z = (it.end.z + 1 - it.begin.z) * scaling;
VOXModel.CreateCubeMesh16x16(ref vertices, ref normals, ref uv, ref triangles, ref index, it.faces, pos, scale, (uint)it.material);
}
}
}
}
gitextract_tyd_gif7/
├── .gitattributes
├── .gitignore
├── LICENSE
├── README.md
└── VOXFileLoader/
├── Demo/
│ ├── 8x8x8.vox
│ └── chr_sword.vox
├── Editor/
│ └── VOXFileLoader.cs
└── Scripts/
├── ObjFileExport.cs
├── VOXCruncher.cs
├── VOXFileImport.cs
├── VOXHashMap.cs
└── VOXModel.cs
SYMBOL INDEX (91 symbols across 6 files)
FILE: VOXFileLoader/Editor/VOXFileLoader.cs
class VOXFileLoader (line 10) | public class VOXFileLoader : EditorWindow
method ShowWindow (line 15) | [MenuItem("Tools/Cubizer/Show VOXFileLoader Inspector")]
method LoadVoxelFileAsPrefab (line 21) | [MenuItem("Tools/Cubizer/Load .vox file as Prefab")]
method LoadVoxelFileAsGameObject (line 37) | [MenuItem("Tools/Cubizer/Load .vox file as GameObject")]
method OnGUI (line 53) | public void OnGUI()
method CreateVoxelPrefabsFromSelection (line 84) | private static bool CreateVoxelPrefabsFromSelection(int lodLevel = 0)
method CreateVoxelGameObjectFromSelection (line 114) | private static bool CreateVoxelGameObjectFromSelection(int lodLevel = 0)
method CreateAssetBundlesFromSelection (line 144) | private static void CreateAssetBundlesFromSelection(string targetPath,...
method CreateAssetBundlesWithFolderPanel (line 164) | private static void CreateAssetBundlesWithFolderPanel(string bundleNam...
method CreateAssetBundlesFromSelectionToStreamingAssets (line 173) | private static void CreateAssetBundlesFromSelectionToStreamingAssets(s...
FILE: VOXFileLoader/Scripts/ObjFileExport.cs
class ObjFileExport (line 16) | public class ObjFileExport
method MeshToString (line 18) | public static string MeshToString(MeshFilter mf, Vector3 scale)
method WriteToFile (line 83) | public static void WriteToFile(string path, MeshFilter mf, Vector3 scale)
FILE: VOXFileLoader/Scripts/VOXCruncher.cs
type VOXCruncherMode (line 13) | public enum VOXCruncherMode
type VOXVisiableFaces (line 20) | public struct VOXVisiableFaces
method VOXVisiableFaces (line 29) | public VOXVisiableFaces(bool _left, bool _right, bool _bottom, bool _t...
class VOXCruncher (line 40) | public class VOXCruncher
type Vector3 (line 42) | public struct Vector3
method VOXCruncher (line 55) | public VOXCruncher(Vector3 begin, Vector3 end, VOXMaterial _material)
method VOXCruncher (line 70) | public VOXCruncher(int begin_x, int end_x, int begin_y, int end_y, int...
method VOXCruncher (line 90) | public VOXCruncher(int begin_x, int end_x, int begin_y, int end_y, int...
type IVOXCruncherStrategy (line 105) | public interface IVOXCruncherStrategy
method CalcVoxelCruncher (line 107) | VOXModel CalcVoxelCruncher(VoxData chunk, Color32[] palette);
class VOXCruncherStupid (line 110) | public class VOXCruncherStupid : IVOXCruncherStrategy
method CalcVoxelCruncher (line 112) | public VOXModel CalcVoxelCruncher(VoxData chunk, Color32[] palette)
class VOXCruncherCulled (line 136) | public class VOXCruncherCulled : IVOXCruncherStrategy
method GetVisiableFaces (line 138) | public static bool GetVisiableFaces(VOXMaterial[,,] map, Vector3Int bo...
method CalcVoxelCruncher (line 186) | public VOXModel CalcVoxelCruncher(VoxData chunk, Color32[] palette)
class VOXCruncherGreedy (line 220) | public class VOXCruncherGreedy : IVOXCruncherStrategy
method CalcVoxelCruncher (line 222) | public VOXModel CalcVoxelCruncher(VoxData chunk, Color32[] palette)
class VOXPolygonCruncher (line 365) | public class VOXPolygonCruncher
method CalcVoxelCruncher (line 367) | public static VOXModel CalcVoxelCruncher(VoxData chunk, Color32[] pale...
FILE: VOXFileLoader/Scripts/VOXFileImport.cs
type VoxFileHeader (line 17) | public struct VoxFileHeader
type VoxFilePack (line 23) | public struct VoxFilePack
type VoxFileSize (line 31) | public struct VoxFileSize
type VoxFileXYZI (line 41) | public struct VoxFileXYZI
type VoxFileRGBA (line 49) | public struct VoxFileRGBA
type VoxFileChunkChild (line 57) | public struct VoxFileChunkChild
type VoxFileChunk (line 63) | public struct VoxFileChunk
type VoxFileMaterial (line 70) | public struct VoxFileMaterial
class VoxFileData (line 79) | public class VoxFileData
class VoxData (line 88) | public class VoxData
method VoxData (line 111) | public VoxData()
method VoxData (line 116) | public VoxData(byte[] _voxels, int xx, int yy, int zz)
method GetMajorityColorIndex (line 141) | public int GetMajorityColorIndex(int xx, int yy, int zz, int lodLevel)
method GetVoxelDataLOD (line 190) | public VoxData GetVoxelDataLOD(int level)
class VoxFileImport (line 224) | public class VoxFileImport
method Load (line 248) | public static VoxFileData Load(string path)
method CreateColor32FromPelatte (line 363) | public static Color32[] CreateColor32FromPelatte(uint[] palette)
method CreateTextureFromColor16x16 (line 385) | public static Texture2D CreateTextureFromColor16x16(Color32[] colors)
method CreateTextureFromColor256 (line 397) | public static Texture2D CreateTextureFromColor256(Color32[] colors)
method CreateTextureFromPelatte16x16 (line 409) | public static Texture2D CreateTextureFromPelatte16x16(uint[] palette)
method CalcFaceCountAsAllocate (line 415) | public static int CalcFaceCountAsAllocate(VOXModel model, Color32[] pa...
method CreateGameObject (line 437) | public static GameObject CreateGameObject(string name, VoxData data, T...
method LoadVoxelFileAsGameObject (line 498) | public static GameObject LoadVoxelFileAsGameObject(string name, VoxFil...
method LoadVoxelFileAsGameObject (line 548) | public static GameObject LoadVoxelFileAsGameObject(string path)
method LoadVoxelFileAsGameObjectLOD (line 554) | public static GameObject LoadVoxelFileAsGameObjectLOD(string path, int...
method LoadVoxelFileAsPrefab (line 562) | public static GameObject LoadVoxelFileAsPrefab(VoxFileData voxel, stri...
method LoadVoxelFileAsPrefab (line 612) | public static GameObject LoadVoxelFileAsPrefab(string path, string out...
FILE: VOXFileLoader/Scripts/VOXHashMap.cs
class VOXHashMapNode (line 16) | [Serializable]
method VOXHashMapNode (line 25) | public VOXHashMapNode()
method VOXHashMapNode (line 30) | public VOXHashMapNode(_Tx xx, _Tx yy, _Tx zz, VOXMaterial value)
method is_empty (line 38) | public bool is_empty()
class VOXHashMapNodeEnumerable (line 44) | public class VOXHashMapNodeEnumerable<_Tx> : IEnumerable
method VOXHashMapNodeEnumerable (line 49) | public VOXHashMapNodeEnumerable(VOXHashMapNode<_Tx>[] array)
method GetEnumerator (line 54) | IEnumerator IEnumerable.GetEnumerator()
method GetEnumerator (line 59) | public VOXHashMapNodeEnum<_Tx> GetEnumerator()
class VOXHashMapNodeEnum (line 65) | public class VOXHashMapNodeEnum<_Tx> : IEnumerator
method VOXHashMapNodeEnum (line 72) | public VOXHashMapNodeEnum(VOXHashMapNode<_Tx>[] list)
method MoveNext (line 77) | public bool MoveNext()
method Reset (line 92) | public void Reset()
class VOXHashMap (line 114) | [Serializable]
method VOXHashMap (line 126) | public VOXHashMap(Vector3Int bound)
method VOXHashMap (line 133) | public VOXHashMap(Vector3Int bound, int count)
method VOXHashMap (line 141) | public VOXHashMap(int bound_x, int bound_y, int bound_z, int count)
method Create (line 149) | public void Create(int count)
method Set (line 159) | public bool Set(System.Byte x, System.Byte y, System.Byte z, VOXMateri...
method Get (line 198) | public bool Get(System.Byte x, System.Byte y, System.Byte z, ref VOXMa...
method Exists (line 222) | public bool Exists(System.Byte x, System.Byte y, System.Byte z)
method Empty (line 228) | public bool Empty()
method GetEnumerator (line 233) | public VOXHashMapNodeEnumerable<System.Byte> GetEnumerator()
method Save (line 241) | public static bool Save(string path, VOXHashMap map)
method Load (line 254) | public static VOXHashMap Load(string path)
method Grow (line 261) | private bool Grow(VOXHashMapNode<System.Byte> data)
method Grow (line 283) | private void Grow()
method _hash_int (line 295) | private static int _hash_int(int key)
method HashInt (line 306) | public static int HashInt(int x, int y, int z)
FILE: VOXFileLoader/Scripts/VOXModel.cs
class VOXModel (line 7) | public class VOXModel
method VOXModel (line 51) | public VOXModel(VOXCruncher[] array)
method CreateCubeMesh16x16 (line 56) | public static void CreateCubeMesh16x16(ref Vector3[] vertices, ref Vec...
method CreateCubeMesh16x16 (line 96) | public static void CreateCubeMesh16x16(VOXCruncher it, ref Vector3[] v...
Condensed preview — 12 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (59K chars).
[
{
"path": ".gitattributes",
"chars": 108,
"preview": "# git files\n.gitattributes export-ignore\n.gitignore export-ignore\n# Folders/Files\nScreenshots/ export-ignore"
},
{
"path": ".gitignore",
"chars": 32,
"preview": "*.meta\nStandard Assets\nMaterials"
},
{
"path": "LICENSE",
"chars": 1067,
"preview": "MIT License\n\nCopyright (c) 2017 ~ 2018 Rui\n\nPermission is hereby granted, free of charge, to any person obtaining a copy"
},
{
"path": "README.md",
"chars": 2338,
"preview": "MagicaVoxel for Unity 2017\n========\n### VOXFileLoader ###\n The VOXFileLoader is a .vox reader to convert the .vox file "
},
{
"path": "VOXFileLoader/Editor/VOXFileLoader.cs",
"chars": 5313,
"preview": "using System;\nusing System.IO;\n\nusing UnityEngine;\nusing UnityEditor;\n\nusing Cubizer;\nusing Cubizer.Model;\n\npublic clas"
},
{
"path": "VOXFileLoader/Scripts/ObjFileExport.cs",
"chars": 2520,
"preview": "using System;\nusing System.IO;\nusing System.Diagnostics;\nusing System.Collections;\nusing System.Collections.Generic;\nus"
},
{
"path": "VOXFileLoader/Scripts/VOXCruncher.cs",
"chars": 10001,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.IO;\n\nusing UnityEngine;\n\nnamespace Cubizer\n{\n\tnamespace Mo"
},
{
"path": "VOXFileLoader/Scripts/VOXFileImport.cs",
"chars": 19514,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.IO;\n\nusing UnityEngine;\n\n#if UNITY_EDITOR\n\nusing UnityEdit"
},
{
"path": "VOXFileLoader/Scripts/VOXHashMap.cs",
"chars": 6141,
"preview": "using System;\nusing System.Diagnostics;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.IO;\nus"
},
{
"path": "VOXFileLoader/Scripts/VOXModel.cs",
"chars": 3728,
"preview": "using UnityEngine;\n\nnamespace Cubizer\n{\n\tnamespace Model\n\t{\n\t\tpublic class VOXModel\n\t\t{\n\t\t\tprivate static Vector3[,] _p"
}
]
// ... and 2 more files (download for full content)
About this extraction
This page contains the full source code of the ray-cast/UnityVOXFileImport GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 12 files (49.6 KB), approximately 16.2k tokens, and a symbol index with 91 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.