public static Texture2D FromModel(VOX.Model model, int tileSizePx = 1, bool enableGrid = false) { Texture2D texture = new Texture2D(16, 16); texture.SetPixels(model.materials.Select(mat => mat.color).ToArray()); TextureScale.Point(texture, tileSizePx * 16, tileSizePx * 16); texture.filterMode = FilterMode.Point; texture.wrapMode = TextureWrapMode.Clamp; return(texture); }
private static MeshDraft CreateMesh(VOX.Model model, Dictionary <ColorPlanePos, ColorPlane> planes, float scale = 1.0f, float halfTexelShift = 0.0f) { MeshDraft mesh = new MeshDraft(); foreach (KeyValuePair <ColorPlanePos, ColorPlane> plane in planes) { mesh.Add(CreateOptimizedFaces(model, plane.Key, plane.Value, halfTexelShift)); } mesh.Scale(scale); return(mesh); }
private static MeshDraft CreateOptimizedFaces(VOX.Model model, ColorPlanePos pos, ColorPlane plane, float halfTexelShift) { plane.vertices = new List <Vector3>(); plane.triangles = new List <int>(); int count = 0; bool[,] matrix = new bool[plane.sizeX, plane.sizeY]; foreach (Vector2Int dot in plane.dots) { matrix[dot.x - plane.minX, dot.y - plane.minY] = true; count++; } return(SplitToRects(model, matrix, pos, plane, count, halfTexelShift)); }
public static void SetModel(UnityEngine.GameObject obj, VOX.Model model, Texture2D customTexture = null, bool enableGrid = false) { var mr = obj.GetComponent <MeshRenderer>(); if (mr == null) { mr = obj.AddComponent <MeshRenderer>(); } var mf = obj.GetComponent <MeshFilter>(); if (mf == null) { mf = obj.AddComponent <MeshFilter>(); } var texture = customTexture != null ? customTexture : VOX.Texture.FromModel(model, 1, true); MeshDraft mesh = VOX.Mesh.FromModel(model); mr.sharedMaterial = new UnityEngine.Material(Shader.Find("Standard")); mr.sharedMaterial.SetTexture("_MainTex", texture); if (enableGrid) { var hlines = Resources.Load("hlines_tr") as UnityEngine.Texture; mr.sharedMaterial.SetTexture("_DetailAlbedoMap", hlines); mr.sharedMaterial.SetTextureScale("_DetailAlbedoMap", new Vector2(16f, 16f)); mr.sharedMaterial.EnableKeyword("_DETAIL_MULX2"); mr.sharedMaterial.SetColor("_Color", new Color(0.5f, 0.5f, 0.5f)); // To lower brightness of additional hlines texture } else { mr.sharedMaterial.DisableKeyword("_DETAIL_MULX2"); mr.sharedMaterial.SetTexture("_DetailAlbedoMap", null); mr.sharedMaterial.SetColor("_Color", Color.white); } mr.sharedMaterial.EnableKeyword("_SPECULARHIGHLIGHTS_OFF"); mr.sharedMaterial.SetFloat("_SpecularHighlights", 0f); mf.sharedMesh = mesh.ToMesh(); mf.sharedMesh.RecalculateNormals(); }
private static Dictionary <ColorPlanePos, ColorPlane> CreateColorPlanes(VOX.Model model, bool withoutEdge) { var planes = new Dictionary <ColorPlanePos, ColorPlane>(); ColorPlane plane; for (int x = 0; x < model.sizeX; x++) { for (int y = 0; y < model.sizeY; y++) { for (int z = 0; z < model.sizeZ; z++) { if (model.VoxelAt(x, y, z) == null) { continue; } byte i = model.MaterialIDAt(x, y, z); if (i == 0) { continue; } // top plane = GetColorPlaneFor(planes, y, i, new Vector3(0, -1f, 0)); if (model.VoxelAt(x, y + 1, z) == null) { plane.AddDot(x, z); } // bottom plane = GetColorPlaneFor(planes, y, i, new Vector3(0, 1f, 0)); if (model.VoxelAt(x, y - 1, z) == null) { plane.AddDot(x, z); } if (z > 0 || !withoutEdge) { // front plane = GetColorPlaneFor(planes, z, i, new Vector3(0, 0, -1f)); if (model.VoxelAt(x, y, z - 1) == null) { plane.AddDot(x, y); } } if (z < model.sizeZ - 1 || !withoutEdge) { // back plane = GetColorPlaneFor(planes, z, i, new Vector3(0, 0, 1f)); if (model.VoxelAt(x, y, z + 1) == null) { plane.AddDot(x, y); } } if (x > 0 || !withoutEdge) { // left plane = GetColorPlaneFor(planes, x, i, new Vector3(-1f, 0, 0)); if (model.VoxelAt(x - 1, y, z) == null) { plane.AddDot(z, y); } } if (x < model.sizeX - 1 || !withoutEdge) { // right plane = GetColorPlaneFor(planes, x, i, new Vector3(1f, 0, 0)); if (model.VoxelAt(x + 1, y, z) == null) { plane.AddDot(z, y); } } } } } return(planes); }
private static MeshDraft SplitToRects(VOX.Model model, bool[,] matrix, ColorPlanePos pos, ColorPlane plane, int count, float halfTexelShift) { MeshDraft mesh = new MeshDraft(); int matIdX = plane.matID % 16; int matIdY = plane.matID / 16; Vector2 uvStart = new Vector2(matIdX / 16.0f, matIdY / 16.0f); int[,] h, w; h = new int[plane.sizeX, plane.sizeY]; w = new int[plane.sizeX, plane.sizeY]; while (count > 0) { int minw = 0, area = 0; int maxArea = 0; int[] maxFace = new int[4] { 0, 0, 0, 0 }; for (int j = 0; j < plane.sizeX; j++) { for (int i = 0; i < plane.sizeY; i++) { if (!matrix[j, i]) { continue; } if (j == 0) { h[j, i] = 1; } else { h[j, i] = h[j - 1, i] + 1; } if (i == 0) { w[j, i] = 1; } else { w[j, i] = w[j, i - 1] + 1; } minw = w[j, i]; for (int dh = 0; dh < h[j, i]; dh++) { if (w[j - dh, i] < minw) { minw = w[j - dh, i]; } area = (dh + 1) * minw; if (area > maxArea) { maxArea = area; maxFace[0] = i - minw + 1; maxFace[1] = j - dh; maxFace[2] = i; maxFace[3] = j; } } } } int vi = mesh.vertices.Count; bool order = true; float x1 = maxFace[1]; float y1 = maxFace[0]; float x2 = maxFace[3] + 1; float y2 = maxFace[2] + 1; if (pos.normal.y == -1) { mesh.vertices.Add(new Vector3(maxFace[1], pos.pos + 1, maxFace[0])); mesh.vertices.Add(new Vector3(maxFace[3] + 1, pos.pos + 1, maxFace[0])); mesh.vertices.Add(new Vector3(maxFace[3] + 1, pos.pos + 1, maxFace[2] + 1)); mesh.vertices.Add(new Vector3(maxFace[1], pos.pos + 1, maxFace[2] + 1)); x1 *= 1.0f / model.sizeX / 16.0f; y1 *= 1.0f / model.sizeZ / 16.0f; x2 *= 1.0f / model.sizeX / 16.0f; y2 *= 1.0f / model.sizeZ / 16.0f; } else if (pos.normal.y == 1) { mesh.vertices.Add(new Vector3(maxFace[1], pos.pos, maxFace[0])); mesh.vertices.Add(new Vector3(maxFace[3] + 1, pos.pos, maxFace[0])); mesh.vertices.Add(new Vector3(maxFace[3] + 1, pos.pos, maxFace[2] + 1)); mesh.vertices.Add(new Vector3(maxFace[1], pos.pos, maxFace[2] + 1)); order = false; x1 *= 1.0f / model.sizeX / 16.0f; y1 *= 1.0f / model.sizeZ / 16.0f; x2 *= 1.0f / model.sizeX / 16.0f; y2 *= 1.0f / model.sizeZ / 16.0f; } else if (pos.normal.z == -1) { mesh.vertices.Add(new Vector3(maxFace[1], maxFace[0], pos.pos)); mesh.vertices.Add(new Vector3(maxFace[3] + 1, maxFace[0], pos.pos)); mesh.vertices.Add(new Vector3(maxFace[3] + 1, maxFace[2] + 1, pos.pos)); mesh.vertices.Add(new Vector3(maxFace[1], maxFace[2] + 1, pos.pos)); x1 *= 1.0f / model.sizeX / 16.0f; y1 *= 1.0f / model.sizeY / 16.0f; x2 *= 1.0f / model.sizeX / 16.0f; y2 *= 1.0f / model.sizeY / 16.0f; } else if (pos.normal.z == 1) { mesh.vertices.Add(new Vector3(maxFace[1], maxFace[0], pos.pos + 1)); mesh.vertices.Add(new Vector3(maxFace[3] + 1, maxFace[0], pos.pos + 1)); mesh.vertices.Add(new Vector3(maxFace[3] + 1, maxFace[2] + 1, pos.pos + 1)); mesh.vertices.Add(new Vector3(maxFace[1], maxFace[2] + 1, pos.pos + 1)); order = false; x1 *= 1.0f / model.sizeX / 16.0f; y1 *= 1.0f / model.sizeY / 16.0f; x2 *= 1.0f / model.sizeX / 16.0f; y2 *= 1.0f / model.sizeY / 16.0f; } else if (pos.normal.x == -1) { mesh.vertices.Add(new Vector3(pos.pos, maxFace[0], maxFace[1])); mesh.vertices.Add(new Vector3(pos.pos, maxFace[0], maxFace[3] + 1)); mesh.vertices.Add(new Vector3(pos.pos, maxFace[2] + 1, maxFace[3] + 1)); mesh.vertices.Add(new Vector3(pos.pos, maxFace[2] + 1, maxFace[1])); order = false; x1 *= 1.0f / model.sizeY / 16.0f; y1 *= 1.0f / model.sizeY / 16.0f; x2 *= 1.0f / model.sizeY / 16.0f; y2 *= 1.0f / model.sizeY / 16.0f; } else if (pos.normal.x == 1) { mesh.vertices.Add(new Vector3(pos.pos + 1, maxFace[0], maxFace[1])); mesh.vertices.Add(new Vector3(pos.pos + 1, maxFace[0], maxFace[3] + 1)); mesh.vertices.Add(new Vector3(pos.pos + 1, maxFace[2] + 1, maxFace[3] + 1)); mesh.vertices.Add(new Vector3(pos.pos + 1, maxFace[2] + 1, maxFace[1])); x1 *= 1.0f / model.sizeY / 16.0f; y1 *= 1.0f / model.sizeY / 16.0f; x2 *= 1.0f / model.sizeY / 16.0f; y2 *= 1.0f / model.sizeY / 16.0f; } x1 += uvStart.x + halfTexelShift; y1 += uvStart.y + halfTexelShift; x2 += uvStart.x - halfTexelShift; y2 += uvStart.y - halfTexelShift; mesh.uv.Add(new Vector2(x1, y1)); mesh.uv.Add(new Vector2(x2, y1)); mesh.uv.Add(new Vector2(x2, y2)); mesh.uv.Add(new Vector2(x1, y2)); if (order) { mesh.triangles.Add(vi); mesh.triangles.Add(vi + 2); mesh.triangles.Add(vi + 1); mesh.triangles.Add(vi + 2); mesh.triangles.Add(vi); mesh.triangles.Add(vi + 3); } else { mesh.triangles.Add(vi); mesh.triangles.Add(vi + 1); mesh.triangles.Add(vi + 2); mesh.triangles.Add(vi + 2); mesh.triangles.Add(vi + 3); mesh.triangles.Add(vi); } for (int j = maxFace[1]; j <= maxFace[3]; j++) { for (int i = maxFace[0]; i <= maxFace[2]; i++) { matrix[j, i] = false; count--; } } for (int j = 0; j < plane.sizeX; j++) { for (int i = 0; i < plane.sizeY; i++) { w[j, i] = 0; h[j, i] = 0; } } } return(mesh); }
// halfTextShift - for better uv mapping public static MeshDraft FromModel(VOX.Model model, float scale = 1.0f, bool withoutEdge = false, float halfTexelShift = 0.0f) { var planes = CreateColorPlanes(model, withoutEdge); return(CreateMesh(model, planes, scale, halfTexelShift)); }