namespace MagicaVoxelToolbox { using System.Collections; using System.Collections.Generic; using UnityEngine; public enum Direction { Up = 0, Down = 1, Left = 2, Right = 3, Front = 4, Back = 5, } public class VoxelData { #region --- SUB --- [System.Serializable] public class MaterialData { public const int SHADER_NUM = 5; public const int SHADER_PROPERTY_NUM = 13; public static readonly Vector2[] SHADER_VALUE_REMAP_SOURCE = new Vector2[SHADER_PROPERTY_NUM] { new Vector2(0, 1), new Vector2(0, 1), new Vector2(0, 1), new Vector2(0, 1), new Vector2(0, 1), new Vector2(0, 1), new Vector2(0, 1), new Vector2(0, 1), new Vector2(0, 1), new Vector2(0, 1), new Vector2(0, 1), new Vector2(0, 4), new Vector2(0, 1), }; public enum MaterialType { Diffuse = 0, Metal = 1, Glass = 2, Emit = 3, } public MaterialType Type; public int Index; public float Weight; public float Rough; public float Spec; public float Ior; public float Att; public float Flux; public float LDR; public int Plastic; public static MaterialType GetTypeFromString (string voxStr) { switch (voxStr) { default: case "_diffuse": return MaterialType.Diffuse; case "_metal": return MaterialType.Metal; case "_glass": return MaterialType.Glass; case "_emit": return MaterialType.Emit; } } public static string GetStringFromType (MaterialType type) { switch (type) { default: case MaterialType.Diffuse: return "_diffuse"; case MaterialType.Metal: return "_metal"; case MaterialType.Glass: return "_glass"; case MaterialType.Emit: return "_emit"; } } public bool IsSameWith (MaterialData other) { if (Type != other.Type) { return false; } switch (Type) { default: case MaterialType.Diffuse: return true; case MaterialType.Metal: return Weight == other.Weight && Rough == other.Rough && Spec == other.Spec && Plastic == other.Plastic; case MaterialType.Glass: return Weight == other.Weight && Rough == other.Rough && Ior == other.Ior && Att == other.Att; case MaterialType.Emit: return Weight == other.Weight && Flux == other.Flux && LDR == other.LDR; } } } [System.Serializable] public class TransformData { [System.Serializable] public class FrameData { public Vector3 Rotation; public Vector3 Position; public Vector3 Scale; } public int ChildID; public int LayerID; public string Name; public bool Hidden; public int Reserved; public FrameData[] Frames; } public class GroupData { public Dictionary Attributes; public int[] ChildNodeId; } public class ShapeData { public Dictionary Attributes; public KeyValuePair>[] ModelData; } [System.Serializable] public class RigData { [System.Serializable] public class Bone { [System.NonSerialized] public Bone Parent = null; [System.NonSerialized] public int ChildCount = 0; public int ParentIndex;// root >> -1 public string Name; public int PositionX; public int PositionY; public int PositionZ; public static implicit operator bool (Bone bone) { return bone != null; } } [System.Serializable] public class Weight { public int X; public int Y; public int Z; public int BoneIndexA = -1; public int BoneIndexB = -1; public Weight () { X = 0; Y = 0; Z = 0; BoneIndexA = -1; BoneIndexB = -1; } public Weight (int indexA, int indexB) { X = 0; Y = 0; Z = 0; BoneIndexA = indexA; BoneIndexB = indexB; } public float GetWeight (int boneIndex) { float weight = 0f; if (boneIndex == BoneIndexA || boneIndex == BoneIndexB) { weight = 0.5f; if (BoneIndexA == -1 || BoneIndexB == -1) { weight = 1f; } } return weight; } public void SetWeight (int boneIndex) { if (BoneIndexA == boneIndex || BoneIndexB == boneIndex) { return; } else if (BoneIndexA == -1) { BoneIndexA = boneIndex; } else if (BoneIndexB == -1) { BoneIndexB = boneIndex; } else { BoneIndexB = BoneIndexA; BoneIndexA = boneIndex; } } public bool IndexEqualsTo (Weight other) { return (BoneIndexA == other.BoneIndexA && BoneIndexB == other.BoneIndexB) || (BoneIndexA == other.BoneIndexB && BoneIndexB == other.BoneIndexA); } } public const int CURRENT_VERSION = 1; public List Bones; public List Weights; public int Version = 0; public void FixVersion () { if (Version == 0) { if (Bones != null) { for (int i = 0; i < Bones.Count; i++) { var bone = Bones[i]; bone.PositionX *= 2; bone.PositionY *= 2; bone.PositionZ *= 2; } } } Version = CURRENT_VERSION; } public static List GetHumanBones (Vector3 size, bool fullSize) { var bones = new List(); // Body var hip = GetNewBone("Hips", null, 0.5f - 1f / size.x, 0.5f - 1f / size.y, 0.5f - 1f / size.z, size); var spine = GetNewBone("Spine", hip, 0, 0.05f, 0, size); var chest = GetNewBone("Chest", spine, 0, 0.05f, 0, size); var _upperChest = GetNewBone("UpperChest", chest, 0, 0.05f, 0, size); var neck = GetNewBone("Neck", fullSize ? _upperChest : chest, 0, 0.15f, 0, size); var head = GetNewBone("Head", neck, 0, 0.05f, 0, size); // Head var _eyeL = GetNewBone("LeftEye", head, -0.1f, 0.1f, 0, size); var _eyeR = GetNewBone("RightEye", head, 0.1f, 0.1f, 0, size); var _jaw = GetNewBone("Jaw", head, 0, 0.05f, 0, size); // Arm var _leftShoulder = GetNewBone("LeftShoulder", _upperChest, -0.05f, 0, 0, size); var _rightShoulder = GetNewBone("RightShoulder", _upperChest, 0.05f, 0, 0, size); var armUL = GetNewBone("LeftUpperArm", fullSize ? _leftShoulder : chest, -0.1f, 0.05f, 0, size); var armUR = GetNewBone("RightUpperArm", fullSize ? _rightShoulder : chest, 0.1f, 0.05f, 0, size); var armDL = GetNewBone("LeftLowerArm", armUL, -0.2f, 0, 0, size); var armDR = GetNewBone("RightLowerArm", armUR, 0.2f, 0, 0, size); var handL = GetNewBone("LeftHand", armDL, -0.2f, 0, 0, size); var handR = GetNewBone("RightHand", armDR, 0.2f, 0, 0, size); // Leg var legUL = GetNewBone("LeftUpperLeg", hip, -0.05f, 0, 0, size); var legUR = GetNewBone("RightUpperLeg", hip, 0.05f, 0, 0, size); var legDL = GetNewBone("LeftLowerLeg", legUL, 0, -0.25f, 0, size); var legDR = GetNewBone("RightLowerLeg", legUR, 0, -0.25f, 0, size); var footL = GetNewBone("LeftFoot", legDL, 0, -0.25f, 0, size); var footR = GetNewBone("RightFoot", legDR, 0, -0.25f, 0, size); var _toeL = GetNewBone("LeftToes", footL, 0, 0, -0.05f, size); var _toeR = GetNewBone("RightToes", footR, 0, 0, -0.05f, size); // Hand // Proximal > Intermediate > Distal // Thumb Index Middle Ring Little var _thumbProximalL = GetNewBone("Left Thumb Proximal", handL, -0.05f, 0, 0, size); var _thumbProximalR = GetNewBone("Right Thumb Proximal", handR, 0.05f, 0, 0, size); var _thumbIntermediateL = GetNewBone("Left Thumb Intermediate", _thumbProximalL, -0.05f, 0, 0, size); var _thumbIntermediateR = GetNewBone("Right Thumb Intermediate", _thumbProximalR, 0.05f, 0, 0, size); var _thumbDistalL = GetNewBone("Left Thumb Distal", _thumbIntermediateL, -0.05f, 0, 0, size); var _thumbDistalR = GetNewBone("Right Thumb Distal", _thumbIntermediateR, 0.05f, 0, 0, size); var _indexProximalL = GetNewBone("Left Index Proximal", handL, -0.05f, 0, 0, size); var _indexProximalR = GetNewBone("Right Index Proximal", handR, 0.05f, 0, 0, size); var _indexIntermediateL = GetNewBone("Left Index Intermediate", _indexProximalL, -0.05f, 0, 0, size); var _indexIntermediateR = GetNewBone("Right Index Intermediate", _indexProximalR, 0.05f, 0, 0, size); var _indexDistalL = GetNewBone("Left Index Distal", _indexIntermediateL, -0.05f, 0, 0, size); var _indexDistalR = GetNewBone("Right Index Distal", _indexIntermediateR, 0.05f, 0, 0, size); var _middleProximalL = GetNewBone("Left Middle Proximal", handL, -0.05f, 0, 0, size); var _middleProximalR = GetNewBone("Right Middle Proximal", handR, 0.05f, 0, 0, size); var _middleIntermediateL = GetNewBone("Left Middle Intermediate", _middleProximalL, -0.05f, 0, 0, size); var _middleIntermediateR = GetNewBone("Right Middle Intermediate", _middleProximalR, 0.05f, 0, 0, size); var _middleDistalL = GetNewBone("Left Middle Distal", _middleIntermediateL, -0.05f, 0, 0, size); var _middleDistalR = GetNewBone("Right Middle Distal", _middleIntermediateR, -0.05f, 0, 0, size); var _ringProximalL = GetNewBone("Left Ring Proximal", handL, -0.05f, 0, 0, size); var _ringProximalR = GetNewBone("Right Ring Proximal", handR, 0.05f, 0, 0, size); var _ringIntermediateL = GetNewBone("Left Ring Intermediate", _ringProximalL, -0.05f, 0, 0, size); var _ringIntermediateR = GetNewBone("Right Ring Intermediate", _ringProximalR, 0.05f, 0, 0, size); var _ringDistalL = GetNewBone("Left Ring Distal", _ringIntermediateL, -0.05f, 0, 0, size); var _ringDistalR = GetNewBone("Right Ring Distal", _ringIntermediateR, -0.05f, 0, 0, size); var _littleProximalL = GetNewBone("Left Little Proximal", handL, -0.05f, 0, 0, size); var _littleProximalR = GetNewBone("Right Little Proximal", handR, 0.05f, 0, 0, size); var _littleIntermediateL = GetNewBone("Left Little Intermediate", _littleProximalL, -0.05f, 0, 0, size); var _littleIntermediateR = GetNewBone("Right Little Intermediate", _littleProximalR, 0.05f, 0, 0, size); var _littleDistalL = GetNewBone("Left Little Distal", _littleIntermediateL, -0.05f, 0, 0, size); var _littleDistalR = GetNewBone("Right Little Distal", _littleIntermediateR, -0.05f, 0, 0, size); bones.Add(hip); bones.Add(spine); bones.Add(chest); bones.Add(neck); bones.Add(head); bones.Add(legUL); bones.Add(legUR); bones.Add(legDL); bones.Add(legDR); bones.Add(footL); bones.Add(footR); bones.Add(armUL); bones.Add(armUR); bones.Add(armDL); bones.Add(armDR); bones.Add(handL); bones.Add(handR); if (fullSize) { bones.Add(_upperChest); bones.Add(_eyeL); bones.Add(_eyeR); bones.Add(_jaw); bones.Add(_leftShoulder); bones.Add(_rightShoulder); bones.Add(_toeL); bones.Add(_toeR); bones.Add(_thumbProximalL); bones.Add(_thumbProximalR); bones.Add(_thumbIntermediateL); bones.Add(_thumbIntermediateR); bones.Add(_thumbDistalL); bones.Add(_thumbDistalR); bones.Add(_indexProximalL); bones.Add(_indexProximalR); bones.Add(_indexIntermediateL); bones.Add(_indexIntermediateR); bones.Add(_indexDistalL); bones.Add(_indexDistalR); bones.Add(_middleProximalL); bones.Add(_middleProximalR); bones.Add(_middleIntermediateL); bones.Add(_middleIntermediateR); bones.Add(_middleDistalL); bones.Add(_middleDistalR); bones.Add(_ringProximalL); bones.Add(_ringProximalR); bones.Add(_ringIntermediateL); bones.Add(_ringIntermediateR); bones.Add(_ringDistalL); bones.Add(_ringDistalR); bones.Add(_littleProximalL); bones.Add(_littleProximalR); bones.Add(_littleIntermediateL); bones.Add(_littleIntermediateR); bones.Add(_littleDistalL); bones.Add(_littleDistalR); } return bones; } public static Bone GetNewBone (string name, Bone parent, float x = 0, float y = 0, float z = 0, Vector3 size = default(Vector3)) { x *= 2f; y *= 2f; z *= 2f; return new Bone() { Name = name, Parent = parent, PositionX = x > 0 ? Mathf.CeilToInt(x * size.x) : Mathf.FloorToInt(x * size.x), PositionY = y > 0 ? Mathf.CeilToInt(y * size.y) : Mathf.FloorToInt(y * size.y), PositionZ = z > 0 ? Mathf.CeilToInt(z * size.z) : Mathf.FloorToInt(z * size.z), }; } } #endregion #region --- VAR --- public int Version = -1; public List Voxels = new List(); public List Palette = new List(); public List Materials = new List(); public Dictionary Transforms = new Dictionary(); public Dictionary Groups = new Dictionary(); public Dictionary Shapes = new Dictionary(); public Dictionary Rigs = new Dictionary(); #endregion #region --- API --- public Color GetColorFromPalette (int index) { index--; return index >= 0 && index < Palette.Count ? Palette[index] : Color.clear; } public Vector3 GetModelSize (int index) { return new Vector3( Voxels[index].GetLength(0), Voxels[index].GetLength(1), Voxels[index].GetLength(2) ); } public Vector3 GetFootPoint (int index) { var voxels = Voxels[index]; int sizeX = voxels.GetLength(0); int sizeY = voxels.GetLength(1); int sizeZ = voxels.GetLength(2); for (int y = 0; y < sizeY; y++) { Vector3 foot = Vector3.zero; int footCount = 0; for (int x = 0; x < sizeX; x++) { for (int z = 0; z < sizeZ; z++) { var voxel = voxels[x, y, z]; if (voxel != 0) { foot += new Vector3(x, y, z); footCount++; } } } if (footCount > 0) { return foot / footCount; } } return Vector3.zero; } public Vector3 GetBounds () { Vector3 bounds = Vector3.zero; for (int i = 0; i < Voxels.Count; i++) { var size = GetModelSize(i); bounds = Vector3.Max(bounds, size); } return bounds; } public VoxelData GetCopy () { return new VoxelData() { Version = Version, Voxels = new List(Voxels), Palette = new List(Palette), Transforms = new Dictionary(Transforms), Groups = new Dictionary(Groups), Shapes = new Dictionary(Shapes), Materials = new List(Materials), Rigs = new Dictionary(Rigs), }; } public void GetModelTransform (int index, out Vector3 pos, out Vector3 rot, out Vector3 scale) { pos = Vector3.zero; rot = Vector3.zero; scale = Vector3.one; foreach (var tf in Transforms) { bool success = false; int id = tf.Value.ChildID; if (Shapes.ContainsKey(id)) { var shape = Shapes[id]; for (int i = 0; i < shape.ModelData.Length; i++) { if (shape.ModelData[i].Key == index) { if (tf.Value.Frames.Length > 0) { var frame = tf.Value.Frames[0]; pos = frame.Position; rot = frame.Rotation; scale = frame.Scale; } success = true; break; } } } if (success) { break; } } } public Texture2D GetThumbnail (int index, bool positiveZ = true) { if (Voxels == null || index >= Voxels.Count || index < 0) { return null; } var voxels = Voxels[index]; int sizeX = voxels.GetLength(0); int sizeY = voxels.GetLength(1); int sizeZ = voxels.GetLength(2); Texture2D texture = new Texture2D(sizeX, sizeY, TextureFormat.ARGB32, false); var colors = new Color[sizeX * sizeY]; for (int x = 0; x < sizeX; x++) { for (int y = 0; y < sizeY; y++) { Color c = Color.clear; for (int z = positiveZ ? 0 : sizeZ - 1; positiveZ ? z < sizeZ : z >= 0; z += positiveZ ? 1 : -1) { if (voxels[x, y, z] != 0) { c = GetColorFromPalette(voxels[x, y, z]); break; } } colors[y * sizeX + (positiveZ ? x : sizeX - 1 - x)] = c; } } texture.filterMode = FilterMode.Point; texture.SetPixels(colors); texture.Apply(); return texture; } public bool IsExposed (int index, int x, int y, int z, int sizeX, int sizeY, int sizeZ, Direction dir, List materials = null) { return IsExposed(Voxels[index], x, y, z, sizeX, sizeY, sizeZ, dir, materials); } public void ResetToDefaultNode () { Transforms.Clear(); Groups.Clear(); Shapes.Clear(); Transforms.Add(0, new TransformData() { ChildID = 1, Hidden = false, LayerID = -1, Name = "Root", Reserved = -1, Frames = new TransformData.FrameData[1] { new TransformData.FrameData() { Position = Vector3.zero, Rotation = Vector3.zero, Scale = Vector3.one, }, }, }); Groups.Add(1, new GroupData() { Attributes = new Dictionary(), ChildNodeId = new int[1] { 2 }, }); Transforms.Add(2, new TransformData() { ChildID = 3, Hidden = false, LayerID = -1, Name = "Root", Reserved = -1, Frames = new TransformData.FrameData[1] { new TransformData.FrameData() { Position = Vector3.zero, Rotation = Vector3.zero, Scale = Vector3.one, }, }, }); Shapes.Add(3, new ShapeData() { Attributes = new Dictionary(), ModelData = new KeyValuePair>[1] { new KeyValuePair>(0, new Dictionary()) }, }); } public void Rotate180InY () { if (Shapes.Count == 1) { for (int i = 0; i < Voxels.Count; i++) { var source = Voxels[i]; int sizeX = source.GetLength(0); int sizeY = source.GetLength(1); int sizeZ = source.GetLength(2); var voxels = new int[sizeX, sizeY, sizeZ]; for (int x = 0; x < sizeX; x++) { for (int y = 0; y < sizeY; y++) { for (int z = 0; z < sizeZ; z++) { voxels[x, y, z] = source[sizeX - x - 1, y, sizeZ - z - 1]; } } } Voxels[i] = voxels; } } else if (Transforms.ContainsKey(0) && Transforms[0].Frames.Length > 0) { Transforms[0].Frames[0].Rotation.y += 180; } } // Global API public static VoxelData CreateNewData () { var data = new VoxelData() { Version = 150, Materials = new List(), Palette = new List() { Color.white }, Rigs = new Dictionary(), Voxels = new List() { new int[1,1,1]{ { { 1 } } }, }, }; data.ResetToDefaultNode(); return data; } public static bool IsExposed (int[,,] voxels, int x, int y, int z, int sizeX, int sizeY, int sizeZ, Direction dir, List materials = null) { bool exposed = false; if (voxels[x, y, z] != 0) { switch (dir) { case Direction.Up: exposed = y == sizeY - 1 || voxels[x, y + 1, z] == 0; break; case Direction.Down: exposed = y == 0 || voxels[x, y - 1, z] == 0; break; case Direction.Left: exposed = x == 0 || voxels[x - 1, y, z] == 0; break; case Direction.Right: exposed = x == sizeX - 1 || voxels[x + 1, y, z] == 0; break; case Direction.Front: exposed = z == sizeZ - 1 || voxels[x, y, z + 1] == 0; break; case Direction.Back: exposed = z == 0 || voxels[x, y, z - 1] == 0; break; } if (materials != null && !exposed) { int voxel = voxels[x, y, z]; var material = voxel >= 0 && voxel < materials.Count ? materials[voxel] : null; if (material != null && material.Type != MaterialData.MaterialType.Glass) { int blockingVoxel = 0; switch (dir) { case Direction.Up: blockingVoxel = y == sizeY - 1 ? -1 : voxels[x, y + 1, z]; break; case Direction.Down: blockingVoxel = y == 0 ? -1 : voxels[x, y - 1, z]; break; case Direction.Left: blockingVoxel = x == 0 ? -1 : voxels[x - 1, y, z]; break; case Direction.Right: blockingVoxel = x == sizeX - 1 ? -1 : voxels[x + 1, y, z]; break; case Direction.Front: blockingVoxel = z == sizeZ - 1 ? -1 : voxels[x, y, z + 1]; break; case Direction.Back: blockingVoxel = z == 0 ? -1 : voxels[x, y, z - 1]; break; } var blockingMaterial = blockingVoxel >= 0 && blockingVoxel < materials.Count ? materials[blockingVoxel] : null; if (blockingMaterial != null && blockingMaterial.Type == MaterialData.MaterialType.Glass) { exposed = true; } } } } return exposed; } public static Material GetMaterialFrom (MaterialData mat, Texture2D texture, Shader[] shaders, string[] keywords, Vector2[] remaps, string mainTexKeyword) { if (mat == null || shaders == null || keywords == null || remaps == null) { return new Material(shaders != null && shaders.Length > 0 ? shaders[0] : Shader.Find("Mobile/Diffuse")) { mainTexture = texture }; } Material material; if (shaders.Length < 5) { var shader = shaders.Length > 0 ? shaders[0] : Shader.Find("Mobile/Diffuse"); shaders = new Shader[5] { shader, shader, shader, shader, shader }; } switch (mat.Type) { default: case MaterialData.MaterialType.Diffuse: material = new Material(shaders[0]); break; case MaterialData.MaterialType.Metal: if (mat.Plastic == 0) { material = new Material(shaders[1]); Util.SetMaterialFloatOrColor(material, keywords[0], Util.Remap(MaterialData.SHADER_VALUE_REMAP_SOURCE[0].x, MaterialData.SHADER_VALUE_REMAP_SOURCE[0].y, remaps[0].x, remaps[0].y, mat.Weight));// Weight Util.SetMaterialFloatOrColor(material, keywords[1], Util.Remap(MaterialData.SHADER_VALUE_REMAP_SOURCE[1].x, MaterialData.SHADER_VALUE_REMAP_SOURCE[1].y, remaps[1].x, remaps[1].y, mat.Rough));// Rough Util.SetMaterialFloatOrColor(material, keywords[2], Util.Remap(MaterialData.SHADER_VALUE_REMAP_SOURCE[2].x, MaterialData.SHADER_VALUE_REMAP_SOURCE[2].y, remaps[2].x, remaps[2].y, mat.Spec));// Specular } else { material = new Material(shaders[2]); Util.SetMaterialFloatOrColor(material, keywords[3], Util.Remap(MaterialData.SHADER_VALUE_REMAP_SOURCE[3].x, MaterialData.SHADER_VALUE_REMAP_SOURCE[3].y, remaps[3].x, remaps[3].y, mat.Weight));// Weight Util.SetMaterialFloatOrColor(material, keywords[4], Util.Remap(MaterialData.SHADER_VALUE_REMAP_SOURCE[4].x, MaterialData.SHADER_VALUE_REMAP_SOURCE[4].y, remaps[4].x, remaps[4].y, mat.Rough));// Rough Util.SetMaterialFloatOrColor(material, keywords[5], Util.Remap(MaterialData.SHADER_VALUE_REMAP_SOURCE[5].x, MaterialData.SHADER_VALUE_REMAP_SOURCE[5].y, remaps[5].x, remaps[5].y, mat.Spec));// Specular } break; case MaterialData.MaterialType.Glass: material = new Material(shaders[3]); Util.SetMaterialFloatOrColor(material, keywords[6], Util.Remap(MaterialData.SHADER_VALUE_REMAP_SOURCE[6].x, MaterialData.SHADER_VALUE_REMAP_SOURCE[6].y, remaps[6].x, remaps[6].y, mat.Weight));// Weight Util.SetMaterialFloatOrColor(material, keywords[7], Util.Remap(MaterialData.SHADER_VALUE_REMAP_SOURCE[7].x, MaterialData.SHADER_VALUE_REMAP_SOURCE[7].y, remaps[7].x, remaps[7].y, mat.Rough));// Rough Util.SetMaterialFloatOrColor(material, keywords[8], Util.Remap(MaterialData.SHADER_VALUE_REMAP_SOURCE[8].x, MaterialData.SHADER_VALUE_REMAP_SOURCE[8].y, remaps[8].x, remaps[8].y, mat.Ior));// Refract Util.SetMaterialFloatOrColor(material, keywords[9], Util.Remap(MaterialData.SHADER_VALUE_REMAP_SOURCE[9].x, MaterialData.SHADER_VALUE_REMAP_SOURCE[9].y, remaps[9].x, remaps[9].y, mat.Att));// Att break; case MaterialData.MaterialType.Emit: material = new Material(shaders[4]); Util.SetMaterialFloatOrColor(material, keywords[10], Util.Remap(MaterialData.SHADER_VALUE_REMAP_SOURCE[10].x, MaterialData.SHADER_VALUE_REMAP_SOURCE[10].y, remaps[10].x, remaps[10].y, mat.Weight));// Weight Util.SetMaterialFloatOrColor(material, keywords[11], Util.Remap(MaterialData.SHADER_VALUE_REMAP_SOURCE[11].x, MaterialData.SHADER_VALUE_REMAP_SOURCE[11].y, remaps[11].x, remaps[11].y, mat.Flux));// Power Util.SetMaterialFloatOrColor(material, keywords[12], Util.Remap(MaterialData.SHADER_VALUE_REMAP_SOURCE[12].x, MaterialData.SHADER_VALUE_REMAP_SOURCE[12].y, remaps[12].x, remaps[12].y, mat.LDR));// ldr break; } material.SetTexture(mainTexKeyword, texture); return material; } public static implicit operator bool (VoxelData data) { return data != null; } public static VoxelData GetSplitedData (VoxelData source) { const int SPLIT_SIZE = 126; if (source.Voxels.Count == 0) { return source; } var size = source.GetModelSize(0); int sizeX = Mathf.RoundToInt(size.x); int sizeY = Mathf.RoundToInt(size.y); int sizeZ = Mathf.RoundToInt(size.z); if (sizeX <= SPLIT_SIZE && sizeY <= SPLIT_SIZE && sizeZ <= SPLIT_SIZE) { return source; } int splitCountX = (sizeX / SPLIT_SIZE) + 1; int splitCountY = (sizeY / SPLIT_SIZE) + 1; int splitCountZ = (sizeZ / SPLIT_SIZE) + 1; var data = new VoxelData(); // Nodes var childNodeId = new int[splitCountX * splitCountY * splitCountZ]; for (int i = 0; i < childNodeId.Length; i++) { childNodeId[i] = i * 2 + 2; } data.Voxels = new List(); data.Transforms = new Dictionary() { { 0, new TransformData(){ Name = "", ChildID = 1, Hidden = false, LayerID = 0, Reserved = 0, Frames = new TransformData.FrameData[1]{ new TransformData.FrameData(){ Position = Vector3.zero, Rotation = Vector3.zero, Scale = Vector3.one, }, }, }}, }; data.Groups = new Dictionary() { {1, new GroupData(){ Attributes = new Dictionary(), ChildNodeId = childNodeId, }}, }; data.Shapes = new Dictionary(); data.Palette = new List(source.Palette); data.Version = source.Version; int _i = 0; for (int x = 0; x < splitCountX; x++) { for (int y = 0; y < splitCountY; y++) { for (int z = 0; z < splitCountZ; z++) { int splitSizeX = x < splitCountX - 1 ? SPLIT_SIZE : (sizeX - x * SPLIT_SIZE) % SPLIT_SIZE; int splitSizeY = y < splitCountY - 1 ? SPLIT_SIZE : (sizeY - y * SPLIT_SIZE) % SPLIT_SIZE; int splitSizeZ = z < splitCountZ - 1 ? SPLIT_SIZE : (sizeZ - z * SPLIT_SIZE) % SPLIT_SIZE; int childID = childNodeId[_i]; data.Transforms.Add(childID, new TransformData() { Name = "Splited_Model_" + _i, Reserved = 0, LayerID = 0, Hidden = false, ChildID = childID + 1, Frames = new TransformData.FrameData[1] { new TransformData.FrameData(){ Position = new Vector3( x * SPLIT_SIZE + splitSizeX / 2, y * SPLIT_SIZE + splitSizeY / 2, z * SPLIT_SIZE + splitSizeZ / 2 ), Rotation = Vector3.zero, Scale = Vector3.one, }, }, }); data.Shapes.Add(childID + 1, new ShapeData() { Attributes = new Dictionary(), ModelData = new KeyValuePair>[] { new KeyValuePair>(_i, new Dictionary()), }, }); _i++; } } } // Split var sourceVoxels = source.Voxels[0]; for (int x = 0; x < splitCountX; x++) { for (int y = 0; y < splitCountY; y++) { for (int z = 0; z < splitCountZ; z++) { int splitSizeX = x < splitCountX - 1 ? SPLIT_SIZE : (sizeX - x * SPLIT_SIZE) % SPLIT_SIZE; int splitSizeY = y < splitCountY - 1 ? SPLIT_SIZE : (sizeY - y * SPLIT_SIZE) % SPLIT_SIZE; int splitSizeZ = z < splitCountZ - 1 ? SPLIT_SIZE : (sizeZ - z * SPLIT_SIZE) % SPLIT_SIZE; var voxels = new int[splitSizeX, splitSizeY, splitSizeZ]; for (int i = 0; i < splitSizeX; i++) { for (int j = 0; j < splitSizeY; j++) { for (int k = 0; k < splitSizeZ; k++) { voxels[i, j, k] = sourceVoxels[ x * SPLIT_SIZE + i, y * SPLIT_SIZE + j, z * SPLIT_SIZE + k ]; } } } data.Voxels.Add(voxels); } } } return data; } #endregion #region --- LOD --- public void LodIteration (int lodLevel) { Rigs.Clear(); for (int index = 0; index < Voxels.Count; index++) { var size = GetModelSize(index); int sizeX = (int)size.x; int sizeY = (int)size.y; int sizeZ = (int)size.z; int range = lodLevel + Mathf.Max(1, (sizeX + sizeY + sizeZ) / 42); bool allZero = true; int[,,] voxels = new int[sizeX, sizeY, sizeZ]; int[,,] sourceVoxels = Voxels[index]; for (int x = 0; x < sizeX - range; x++) { for (int y = 0; y < sizeY - range; y++) { for (int z = 0; z < sizeZ - range; z++) { if (sourceVoxels[x, y, z] == 0) { continue; } if (allZero) { allZero = false; } SetRange( ref voxels, sourceVoxels[x, y, z], Mathf.Max(0, x - range), Mathf.Min(sizeX - 1, x + range), Mathf.Max(0, y - range), Mathf.Min(sizeY - 1, y + range), Mathf.Max(0, z - range), Mathf.Min(sizeZ - 1, z + range) ); } } } if (allZero) { voxels[0, 0, 0] = 1; } Voxels[index] = voxels; } } private void SetRange (ref int[,,] voxels, int v, int l, int r, int d, int u, int b, int f) { for (int x = l; x < r; x++) { for (int y = d; y < u; y++) { for (int z = b; z < f; z++) { voxels[x, y, z] = v; } } } } #endregion } public class QbData { public struct QbMatrix { public string Name; public int SizeX, SizeY, SizeZ; public int PosX, PosY, PosZ; public int[,,] Voxels; } public uint Version; public uint ColorFormat; // 0->RGBA 1->BGRA public uint ZAxisOrientation; // 0->Left Handed 1->Right Handed public uint Compressed; // 0->Normal 1->WithNumbers public uint NumMatrixes; public uint VisibleMask; public List MatrixList; public VoxelData GetVoxelData () { var data = new VoxelData { Version = 150, Palette = new List(), Transforms = new Dictionary() { { 0, new VoxelData.TransformData(){ ChildID = 1, Hidden = false, LayerID = -1, Name = "", Reserved = -1, Frames = new VoxelData.TransformData.FrameData[1] {new VoxelData.TransformData.FrameData() { Position = Vector3.zero, Rotation = Vector3.zero, Scale = Vector3.one, }}, }}, }, Shapes = new Dictionary(), Groups = new Dictionary() { {1, new VoxelData.GroupData(){ Attributes = new Dictionary(), ChildNodeId = new int[MatrixList.Count], }} }, Materials = new List(), Voxels = new List(), }; bool leftHanded = ZAxisOrientation == 0; var palette = new Dictionary(); for (int index = 0; index < MatrixList.Count; index++) { var m = MatrixList[index]; int[,,] voxels = new int[m.SizeX, m.SizeY, m.SizeZ]; for (int x = 0; x < m.SizeX; x++) { for (int y = 0; y < m.SizeY; y++) { for (int z = 0; z < m.SizeZ; z++) { int colorInt = m.Voxels[x, y, z]; if (colorInt == 0) { if (leftHanded) { voxels[x, y, m.SizeZ - z - 1] = 0; } else { voxels[x, y, z] = 0; } } else { var color = GetColor(colorInt); int cIndex; if (palette.ContainsKey(color)) { cIndex = palette[color]; } else { cIndex = palette.Count; palette.Add(color, cIndex); data.Palette.Add(color); } if (leftHanded) { voxels[x, y, m.SizeZ - z - 1] = cIndex + 1; } else { voxels[x, y, z] = cIndex + 1; } } } } } data.Voxels.Add(voxels); data.Groups[1].ChildNodeId[index] = index * 2 + 2; data.Transforms.Add(index * 2 + 2, new VoxelData.TransformData() { ChildID = index * 2 + 3, Hidden = false, LayerID = 0, Reserved = 0, Name = "", Frames = new VoxelData.TransformData.FrameData[1] {new VoxelData.TransformData.FrameData() { Position = leftHanded ? new Vector3(m.PosX + m.SizeX / 2, m.PosY + m.SizeY / 2, -(m.PosZ + Mathf.CeilToInt(m.SizeZ / 2f))) : new Vector3(m.PosX + m.SizeX / 2, m.PosY + m.SizeY / 2, m.PosZ + m.SizeZ / 2), Rotation = Vector3.zero, Scale = Vector3.one, }}, }); data.Shapes.Add(index * 2 + 3, new VoxelData.ShapeData() { Attributes = new Dictionary(), ModelData = new KeyValuePair>[1] { new KeyValuePair>(index, new Dictionary()) }, }); } return data; } private Color GetColor (int color) { if (ColorFormat == 0) { int r = 0xFF & color; int g = 0xFF00 & color; g >>= 8; int b = 0xFF0000 & color; b >>= 16; return new Color(r / 255f, g / 255f, b / 255f, 1f); } else { int b = 0xFF & color; int g = 0xFF00 & color; g >>= 8; int r = 0xFF0000 & color; r >>= 16; return new Color(r / 255f, g / 255f, b / 255f, 1f); } } } [System.Serializable] public class VoxelJsonData { [System.Serializable] public class IntArray3 { public int[] Value; public int SizeX; public int SizeY; public int SizeZ; public IntArray3 (int sizeX, int sizeY, int sizeZ) { SizeX = sizeX; SizeY = sizeY; SizeZ = sizeZ; Value = new int[sizeX * sizeY * sizeZ]; } public void Set (int x, int y, int z, int value) { Value[z * SizeX * SizeY + y * SizeX + x] = value; } public int Get (int x, int y, int z) { return Value[z * SizeX * SizeY + y * SizeX + x]; } } [System.Serializable] public class SerGroupData { public int Index; public string[] AttKeys; public string[] Attributes; public int[] ChildNodeId; } [System.Serializable] public class SerShapeData { [System.Serializable] public class ModelMap { public string[] Key; public string[] Value; } public int Index; public string[] AttKeys; public string[] Attributes; public int[] ModelDataIndexs; public ModelMap[] ModelDatas; } public int Version; public IntArray3[] Voxels; public Color[] Palette; public VoxelData.MaterialData[] Materials; public int[] TransformIndexs; public VoxelData.TransformData[] Transforms; public SerGroupData[] Groups; public SerShapeData[] Shapes; public int[] RigIndexs; public VoxelData.RigData[] Rigs; public VoxelJsonData (VoxelData source) { // Version Version = source.Version; // Voxels Voxels = new IntArray3[source.Voxels.Count]; for (int i = 0; i < Voxels.Length; i++) { int sizeX = source.Voxels[i].GetLength(0); int sizeY = source.Voxels[i].GetLength(1); int sizeZ = source.Voxels[i].GetLength(2); var voxels = new IntArray3(sizeX, sizeY, sizeZ); var sourceVoxels = source.Voxels[i]; for (int x = 0; x < sizeX; x++) { for (int y = 0; y < sizeY; y++) { for (int z = 0; z < sizeZ; z++) { voxels.Set(x, y, z, sourceVoxels[x, y, z]); } } } Voxels[i] = voxels; } // Palette Palette = source.Palette.ToArray(); // Materials Materials = source.Materials.ToArray(); // Transforms var tfMap = source.Transforms; TransformIndexs = new int[tfMap.Count]; Transforms = new VoxelData.TransformData[tfMap.Count]; int index = 0; foreach (var tf in tfMap) { TransformIndexs[index] = tf.Key; Transforms[index] = tf.Value; index++; } // Groups var gpMap = source.Groups; Groups = new SerGroupData[gpMap.Count]; index = 0; foreach (var gp in gpMap) { Groups[index] = new SerGroupData() { Index = gp.Key, ChildNodeId = gp.Value.ChildNodeId, AttKeys = new string[gp.Value.Attributes.Count], Attributes = new string[gp.Value.Attributes.Count], }; var attMap = gp.Value.Attributes; int i = 0; foreach (var att in attMap) { Groups[index].AttKeys[i] = att.Key; Groups[index].Attributes[i] = att.Value; i++; } index++; } // Shapes var shMap = source.Shapes; Shapes = new SerShapeData[shMap.Count]; index = 0; foreach (var sh in shMap) { Shapes[index] = new SerShapeData { Index = sh.Key, ModelDataIndexs = new int[sh.Value.ModelData.Length], ModelDatas = new SerShapeData.ModelMap[sh.Value.ModelData.Length], AttKeys = new string[sh.Value.Attributes.Count], Attributes = new string[sh.Value.Attributes.Count], }; var attMap = sh.Value.Attributes; int i = 0; foreach (var att in attMap) { Shapes[index].AttKeys[i] = att.Key; Shapes[index].Attributes[i] = att.Value; i++; } for (i = 0; i < sh.Value.ModelData.Length; i++) { Shapes[index].ModelDataIndexs[i] = sh.Value.ModelData[i].Key; Shapes[index].ModelDatas[i] = new SerShapeData.ModelMap() { Key = new string[sh.Value.ModelData[i].Value.Count], Value = new string[sh.Value.ModelData[i].Value.Count], }; int j = 0; var map = sh.Value.ModelData[i].Value; foreach (var aj in map) { Shapes[index].ModelDatas[i].Key[j] = aj.Key; Shapes[index].ModelDatas[i].Value[j] = aj.Value; j++; } } index++; } // Rigs var rigMap = source.Rigs; RigIndexs = new int[rigMap.Count]; Rigs = new VoxelData.RigData[rigMap.Count]; index = 0; foreach (var rig in rigMap) { RigIndexs[index] = rig.Key; Rigs[index] = rig.Value; var bones = Rigs[index].Bones; for (int i = 0; i < bones.Count; i++) { bones[i].ParentIndex = bones.IndexOf(bones[i].Parent); } index++; } } public VoxelData GetVoxelData () { var data = new VoxelData() { Version = Version, Voxels = new List(), Palette = new List(Palette), Materials = new List(Materials), Transforms = new Dictionary(), Groups = new Dictionary(), Shapes = new Dictionary(), Rigs = new Dictionary(), }; // Voxels for (int i = 0; i < Voxels.Length; i++) { var sourceV = Voxels[i]; int[,,] vs = new int[sourceV.SizeX, sourceV.SizeY, sourceV.SizeZ]; for (int x = 0; x < sourceV.SizeX; x++) { for (int y = 0; y < sourceV.SizeY; y++) { for (int z = 0; z < sourceV.SizeZ; z++) { vs[x, y, z] = sourceV.Get(x, y, z); } } } data.Voxels.Add(vs); } // Transforms for (int i = 0; i < Transforms.Length; i++) { data.Transforms.Add(TransformIndexs[i], Transforms[i]); } // Groups for (int i = 0; i < Groups.Length; i++) { var groupData = new VoxelData.GroupData() { ChildNodeId = Groups[i].ChildNodeId, Attributes = new Dictionary(), }; for (int j = 0; j < Groups[i].AttKeys.Length; j++) { groupData.Attributes.Add(Groups[i].AttKeys[j], Groups[i].Attributes[j]); } data.Groups.Add(Groups[i].Index, groupData); } // Shapes for (int i = 0; i < Shapes.Length; i++) { var sourceShape = Shapes[i]; var shapeData = new VoxelData.ShapeData() { Attributes = new Dictionary(), ModelData = new KeyValuePair>[sourceShape.ModelDatas.Length], }; for (int j = 0; j < sourceShape.Attributes.Length; j++) { shapeData.Attributes.Add(sourceShape.AttKeys[j], sourceShape.Attributes[j]); } for (int j = 0; j < sourceShape.ModelDatas.Length; j++) { shapeData.ModelData[j] = new KeyValuePair>( sourceShape.ModelDataIndexs[j], new Dictionary() ); var sourceData = sourceShape.ModelDatas[j]; for (int k = 0; k < sourceData.Value.Length; k++) { shapeData.ModelData[j].Value.Add(sourceData.Key[k], sourceData.Value[k]); } } data.Shapes.Add(sourceShape.Index, shapeData); } // Rig for (int i = 0; i < Rigs.Length; i++) { var bones = Rigs[i].Bones; for (int j = 0; j < bones.Count; j++) { bones[j].Parent = null; int pIndex = bones[j].ParentIndex; if (pIndex >= 0 && pIndex < bones.Count) { bones[j].Parent = bones[pIndex]; } } data.Rigs.Add(RigIndexs[i], Rigs[i]); } return data; } } }