using UnityEngine;
|
|
using System.Collections;
|
|
using System.Linq;
|
|
using System.Collections.Generic;
|
|
|
|
namespace Utility.Meshes
|
|
{
|
|
|
|
public static class Subdivion
|
|
{
|
|
static List<Vector3> vertices;
|
|
static List<Vector3> normals;
|
|
static List<Color> colors;
|
|
static List<Vector2> uv;
|
|
static List<Vector2> uv1;
|
|
static List<Vector2> uv2;
|
|
|
|
static List<List<int>> allIndices;
|
|
static Dictionary<uint, int> newVectices;
|
|
|
|
static void InitArrays(Mesh mesh)
|
|
{
|
|
vertices = new List<Vector3>(mesh.vertices);
|
|
normals = new List<Vector3>(mesh.normals);
|
|
colors = new List<Color>(mesh.colors);
|
|
uv = new List<Vector2>(mesh.uv);
|
|
uv1 = new List<Vector2>(mesh.uv2);
|
|
uv2 = new List<Vector2>(mesh.uv2);
|
|
allIndices = new List<List<int>>();
|
|
}
|
|
static void CleanUp()
|
|
{
|
|
vertices = null;
|
|
normals = null;
|
|
colors = null;
|
|
uv = null;
|
|
uv1 = null;
|
|
uv2 = null;
|
|
allIndices = null;
|
|
}
|
|
|
|
#region Subdivide4 (2x2)
|
|
static int GetNewVertex4(int i1, int i2)
|
|
{
|
|
int newIndex = vertices.Count;
|
|
uint t1 = ((uint)i1 << 16) | (uint)i2;
|
|
uint t2 = ((uint)i2 << 16) | (uint)i1;
|
|
if (newVectices.ContainsKey(t2))
|
|
return newVectices[t2];
|
|
if (newVectices.ContainsKey(t1))
|
|
return newVectices[t1];
|
|
|
|
newVectices.Add(t1, newIndex);
|
|
|
|
vertices.Add((vertices[i1] + vertices[i2]) * 0.5f);
|
|
if (normals.Count > 0)
|
|
normals.Add((normals[i1] + normals[i2]).normalized);
|
|
if (colors.Count > 0)
|
|
colors.Add((colors[i1] + colors[i2]) * 0.5f);
|
|
if (uv.Count > 0)
|
|
uv.Add((uv[i1] + uv[i2]) * 0.5f);
|
|
if (uv1.Count > 0)
|
|
uv1.Add((uv1[i1] + uv1[i2]) * 0.5f);
|
|
if (uv2.Count > 0)
|
|
uv2.Add((uv2[i1] + uv2[i2]) * 0.5f);
|
|
|
|
return newIndex;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Devides each triangles into 4. A quad(2 tris) will be splitted into 2x2 quads( 8 tris )
|
|
/// </summary>
|
|
/// <param name="mesh"></param>
|
|
public static void Subdivide4(Mesh mesh)
|
|
{
|
|
newVectices = new Dictionary<uint, int>();
|
|
|
|
InitArrays(mesh);
|
|
|
|
int[] triangles = mesh.triangles;
|
|
|
|
Debug.Log(mesh.subMeshCount);
|
|
for (int j = 0; j < mesh.subMeshCount; j++)
|
|
{
|
|
var subMesh = mesh.GetSubMesh(j);
|
|
|
|
allIndices.Add(new List<int>());
|
|
List<int> subIndices = allIndices[j];
|
|
|
|
for (int i = subMesh.indexStart; i < subMesh.indexStart + subMesh.indexCount; i += 3)
|
|
{
|
|
int i1 = triangles[i + 0];
|
|
int i2 = triangles[i + 1];
|
|
int i3 = triangles[i + 2];
|
|
|
|
int a = GetNewVertex4(i1, i2);
|
|
int b = GetNewVertex4(i2, i3);
|
|
int c = GetNewVertex4(i3, i1);
|
|
subIndices.Add(i1); subIndices.Add(a); subIndices.Add(c);
|
|
subIndices.Add(i2); subIndices.Add(b); subIndices.Add(a);
|
|
subIndices.Add(i3); subIndices.Add(c); subIndices.Add(b);
|
|
subIndices.Add(a); subIndices.Add(b); subIndices.Add(c); // center triangle
|
|
}
|
|
}
|
|
|
|
mesh.vertices = vertices.ToArray();
|
|
|
|
if (normals.Count > 0)
|
|
mesh.normals = normals.ToArray();
|
|
if (colors.Count > 0)
|
|
mesh.colors = colors.ToArray();
|
|
if (uv.Count > 0)
|
|
mesh.uv = uv.ToArray();
|
|
if (uv1.Count > 0)
|
|
mesh.uv2 = uv1.ToArray();
|
|
if (uv2.Count > 0)
|
|
mesh.uv2 = uv2.ToArray();
|
|
|
|
|
|
mesh.triangles = allIndices.SelectMany(x => x).ToArray();
|
|
mesh.subMeshCount = allIndices.Count;
|
|
for (int i = 0; i < allIndices.Count; i++)
|
|
mesh.SetTriangles(allIndices[i], i);
|
|
|
|
|
|
CleanUp();
|
|
}
|
|
#endregion Subdivide4 (2x2)
|
|
|
|
#region Subdivide9 (3x3)
|
|
static int GetNewVertex9(int i1, int i2, int i3)
|
|
{
|
|
int newIndex = vertices.Count;
|
|
|
|
// center points don't go into the edge list
|
|
if (i3 == i1 || i3 == i2)
|
|
{
|
|
uint t1 = ((uint)i1 << 16) | (uint)i2;
|
|
if (newVectices.ContainsKey(t1))
|
|
return newVectices[t1];
|
|
newVectices.Add(t1, newIndex);
|
|
}
|
|
|
|
// calculate new vertex
|
|
vertices.Add((vertices[i1] + vertices[i2] + vertices[i3]) / 3.0f);
|
|
if (normals.Count > 0)
|
|
normals.Add((normals[i1] + normals[i2] + normals[i3]).normalized);
|
|
if (colors.Count > 0)
|
|
colors.Add((colors[i1] + colors[i2] + colors[i3]) / 3.0f);
|
|
if (uv.Count > 0)
|
|
uv.Add((uv[i1] + uv[i2] + uv[i3]) / 3.0f);
|
|
if (uv1.Count > 0)
|
|
uv1.Add((uv1[i1] + uv1[i2] + uv1[i3]) / 3.0f);
|
|
if (uv2.Count > 0)
|
|
uv2.Add((uv2[i1] + uv2[i2] + uv2[i3]) / 3.0f);
|
|
return newIndex;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Devides each triangles into 9. A quad(2 tris) will be splitted into 3x3 quads( 18 tris )
|
|
/// </summary>
|
|
/// <param name="mesh"></param>
|
|
public static void Subdivide9(Mesh mesh)
|
|
{
|
|
newVectices = new Dictionary<uint, int>();
|
|
|
|
InitArrays(mesh);
|
|
|
|
int[] triangles = mesh.triangles;
|
|
|
|
Debug.Log(mesh.subMeshCount);
|
|
for (int j = 0; j < mesh.subMeshCount; j++)
|
|
{
|
|
var subMesh = mesh.GetSubMesh(j);
|
|
|
|
allIndices.Add(new List<int>());
|
|
List<int> subIndices = allIndices[j];
|
|
for (int i = subMesh.indexStart; i < subMesh.indexStart + subMesh.indexCount; i += 3)
|
|
{
|
|
int i1 = triangles[i + 0];
|
|
int i2 = triangles[i + 1];
|
|
int i3 = triangles[i + 2];
|
|
|
|
int a1 = GetNewVertex9(i1, i2, i1);
|
|
int a2 = GetNewVertex9(i2, i1, i2);
|
|
int b1 = GetNewVertex9(i2, i3, i2);
|
|
int b2 = GetNewVertex9(i3, i2, i3);
|
|
int c1 = GetNewVertex9(i3, i1, i3);
|
|
int c2 = GetNewVertex9(i1, i3, i1);
|
|
|
|
int d = GetNewVertex9(i1, i2, i3);
|
|
|
|
subIndices.Add(i1); subIndices.Add(a1); subIndices.Add(c2);
|
|
subIndices.Add(i2); subIndices.Add(b1); subIndices.Add(a2);
|
|
subIndices.Add(i3); subIndices.Add(c1); subIndices.Add(b2);
|
|
subIndices.Add(d); subIndices.Add(a1); subIndices.Add(a2);
|
|
subIndices.Add(d); subIndices.Add(b1); subIndices.Add(b2);
|
|
subIndices.Add(d); subIndices.Add(c1); subIndices.Add(c2);
|
|
subIndices.Add(d); subIndices.Add(c2); subIndices.Add(a1);
|
|
subIndices.Add(d); subIndices.Add(a2); subIndices.Add(b1);
|
|
subIndices.Add(d); subIndices.Add(b2); subIndices.Add(c1);
|
|
}
|
|
}
|
|
|
|
mesh.vertices = vertices.ToArray();
|
|
if (normals.Count > 0)
|
|
mesh.normals = normals.ToArray();
|
|
if (colors.Count > 0)
|
|
mesh.colors = colors.ToArray();
|
|
if (uv.Count > 0)
|
|
mesh.uv = uv.ToArray();
|
|
if (uv1.Count > 0)
|
|
mesh.uv2 = uv1.ToArray();
|
|
if (uv2.Count > 0)
|
|
mesh.uv2 = uv2.ToArray();
|
|
|
|
mesh.triangles = allIndices.SelectMany(x => x).ToArray();
|
|
mesh.subMeshCount = allIndices.Count;
|
|
for (int i = 0; i < allIndices.Count; i++)
|
|
mesh.SetTriangles(allIndices[i], i);
|
|
|
|
CleanUp();
|
|
}
|
|
#endregion Subdivide9 (3x3)
|
|
|
|
|
|
#region Subdivide
|
|
/// <summary>
|
|
/// This functions subdivides the mesh based on the level parameter
|
|
/// Note that only the 4 and 9 subdivides are supported so only those divides
|
|
/// are possible. [2,3,4,6,8,9,12,16,18,24,27,32,36,48,64, ...]
|
|
/// The function tried to approximate the desired level
|
|
/// </summary>
|
|
/// <param name="mesh"></param>
|
|
/// <param name="level">Should be a number made up of (2^x * 3^y)
|
|
/// [2,3,4,6,8,9,12,16,18,24,27,32,36,48,64, ...]
|
|
/// </param>
|
|
public static void Subdivide(Mesh mesh, int level)
|
|
{
|
|
if (level < 2)
|
|
return;
|
|
while (level > 1)
|
|
{
|
|
// remove prime factor 3
|
|
while (level % 3 == 0)
|
|
{
|
|
Subdivide9(mesh);
|
|
level /= 3;
|
|
}
|
|
// remove prime factor 2
|
|
while (level % 2 == 0)
|
|
{
|
|
Subdivide4(mesh);
|
|
level /= 2;
|
|
}
|
|
// try to approximate. All other primes are increased by one
|
|
// so they can be processed
|
|
if (level > 3)
|
|
level++;
|
|
}
|
|
}
|
|
#endregion Subdivide
|
|
|
|
public static Mesh DuplicateMesh(Mesh mesh)
|
|
{
|
|
Mesh newMesh = (Mesh)UnityEngine.Object.Instantiate(mesh);
|
|
|
|
newMesh.uv = mesh.uv;
|
|
|
|
return newMesh;
|
|
}
|
|
}
|
|
}
|