536 lines
18 KiB
C#
536 lines
18 KiB
C#
|
namespace UnityEngine.Rendering
|
||
|
{
|
||
|
/// <summary>Debug class containing several debug shapes for debugging</summary>
|
||
|
public partial class DebugShapes
|
||
|
{
|
||
|
// Singleton
|
||
|
static DebugShapes s_Instance = null;
|
||
|
|
||
|
/// <summary>Singleton instance</summary>
|
||
|
static public DebugShapes instance
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
if (s_Instance == null)
|
||
|
{
|
||
|
s_Instance = new DebugShapes();
|
||
|
}
|
||
|
|
||
|
return s_Instance;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Mesh m_sphereMesh = null;
|
||
|
Mesh m_boxMesh = null;
|
||
|
Mesh m_coneMesh = null;
|
||
|
Mesh m_pyramidMesh = null;
|
||
|
|
||
|
// This code has been grabbed from http://wiki.unity3d.com/index.php/ProceduralPrimitives
|
||
|
void BuildSphere(ref Mesh outputMesh, float radius, uint longSubdiv, uint latSubdiv)
|
||
|
{
|
||
|
// Make sure it is empty before pushing anything to it
|
||
|
outputMesh.Clear();
|
||
|
|
||
|
// Build the vertices array
|
||
|
Vector3[] vertices = new Vector3[(longSubdiv + 1) * latSubdiv + 2];
|
||
|
float _pi = Mathf.PI;
|
||
|
float _2pi = _pi * 2f;
|
||
|
|
||
|
vertices[0] = Vector3.up * radius;
|
||
|
for (int lat = 0; lat < latSubdiv; lat++)
|
||
|
{
|
||
|
float a1 = _pi * (float)(lat + 1) / (latSubdiv + 1);
|
||
|
float sin1 = Mathf.Sin(a1);
|
||
|
float cos1 = Mathf.Cos(a1);
|
||
|
|
||
|
for (int lon = 0; lon <= longSubdiv; lon++)
|
||
|
{
|
||
|
float a2 = _2pi * (float)(lon == longSubdiv ? 0 : lon) / longSubdiv;
|
||
|
float sin2 = Mathf.Sin(a2);
|
||
|
float cos2 = Mathf.Cos(a2);
|
||
|
|
||
|
vertices[lon + lat * (longSubdiv + 1) + 1] = new Vector3(sin1 * cos2, cos1, sin1 * sin2) * radius;
|
||
|
}
|
||
|
}
|
||
|
vertices[vertices.Length - 1] = Vector3.up * -radius;
|
||
|
|
||
|
// Build the normals array
|
||
|
Vector3[] normals = new Vector3[vertices.Length];
|
||
|
for (int n = 0; n < vertices.Length; n++)
|
||
|
{
|
||
|
normals[n] = vertices[n].normalized;
|
||
|
}
|
||
|
|
||
|
// Build the UV array
|
||
|
Vector2[] uvs = new Vector2[vertices.Length];
|
||
|
uvs[0] = Vector2.up;
|
||
|
uvs[uvs.Length - 1] = Vector2.zero;
|
||
|
for (int lat = 0; lat < latSubdiv; lat++)
|
||
|
{
|
||
|
for (int lon = 0; lon <= longSubdiv; lon++)
|
||
|
{
|
||
|
uvs[lon + lat * (longSubdiv + 1) + 1] = new Vector2((float)lon / longSubdiv, 1f - (float)(lat + 1) / (latSubdiv + 1));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Build the index array
|
||
|
uint nbTriangles = longSubdiv * 2 + // Top and bottom cap
|
||
|
(latSubdiv - 1) * longSubdiv * 2; // Middle part
|
||
|
uint nbIndexes = nbTriangles * 3;
|
||
|
int[] triangles = new int[nbIndexes];
|
||
|
|
||
|
// Top Cap
|
||
|
int i = 0;
|
||
|
for (int lon = 0; lon < longSubdiv; lon++)
|
||
|
{
|
||
|
triangles[i++] = lon + 2;
|
||
|
triangles[i++] = lon + 1;
|
||
|
triangles[i++] = 0;
|
||
|
}
|
||
|
|
||
|
//Middle
|
||
|
for (uint lat = 0; lat < latSubdiv - 1; lat++)
|
||
|
{
|
||
|
for (uint lon = 0; lon < longSubdiv; lon++)
|
||
|
{
|
||
|
uint current = lon + lat * (longSubdiv + 1) + 1;
|
||
|
uint next = current + longSubdiv + 1;
|
||
|
|
||
|
triangles[i++] = (int)current;
|
||
|
triangles[i++] = (int)current + 1;
|
||
|
triangles[i++] = (int)next + 1;
|
||
|
|
||
|
triangles[i++] = (int)current;
|
||
|
triangles[i++] = (int)next + 1;
|
||
|
triangles[i++] = (int)next;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Bottom Cap
|
||
|
for (int lon = 0; lon < longSubdiv; lon++)
|
||
|
{
|
||
|
triangles[i++] = vertices.Length - 1;
|
||
|
triangles[i++] = vertices.Length - (lon + 2) - 1;
|
||
|
triangles[i++] = vertices.Length - (lon + 1) - 1;
|
||
|
}
|
||
|
|
||
|
// Assign them to
|
||
|
outputMesh.vertices = vertices;
|
||
|
outputMesh.normals = normals;
|
||
|
outputMesh.uv = uvs;
|
||
|
outputMesh.triangles = triangles;
|
||
|
|
||
|
outputMesh.RecalculateBounds();
|
||
|
}
|
||
|
|
||
|
void BuildBox(ref Mesh outputMesh, float length, float width, float height)
|
||
|
{
|
||
|
outputMesh.Clear();
|
||
|
|
||
|
Vector3 p0 = new Vector3(-length * .5f, -width * .5f, height * .5f);
|
||
|
Vector3 p1 = new Vector3(length * .5f, -width * .5f, height * .5f);
|
||
|
Vector3 p2 = new Vector3(length * .5f, -width * .5f, -height * .5f);
|
||
|
Vector3 p3 = new Vector3(-length * .5f, -width * .5f, -height * .5f);
|
||
|
|
||
|
Vector3 p4 = new Vector3(-length * .5f, width * .5f, height * .5f);
|
||
|
Vector3 p5 = new Vector3(length * .5f, width * .5f, height * .5f);
|
||
|
Vector3 p6 = new Vector3(length * .5f, width * .5f, -height * .5f);
|
||
|
Vector3 p7 = new Vector3(-length * .5f, width * .5f, -height * .5f);
|
||
|
|
||
|
Vector3[] vertices = new Vector3[]
|
||
|
{
|
||
|
// Bottom
|
||
|
p0, p1, p2, p3,
|
||
|
// Left
|
||
|
p7, p4, p0, p3,
|
||
|
// Front
|
||
|
p4, p5, p1, p0,
|
||
|
// Back
|
||
|
p6, p7, p3, p2,
|
||
|
// Right
|
||
|
p5, p6, p2, p1,
|
||
|
// Top
|
||
|
p7, p6, p5, p4
|
||
|
};
|
||
|
|
||
|
Vector3 up = Vector3.up;
|
||
|
Vector3 down = Vector3.down;
|
||
|
Vector3 front = Vector3.forward;
|
||
|
Vector3 back = Vector3.back;
|
||
|
Vector3 left = Vector3.left;
|
||
|
Vector3 right = Vector3.right;
|
||
|
|
||
|
Vector3[] normales = new Vector3[]
|
||
|
{
|
||
|
// Bottom
|
||
|
down, down, down, down,
|
||
|
// Left
|
||
|
left, left, left, left,
|
||
|
// Front
|
||
|
front, front, front, front,
|
||
|
// Back
|
||
|
back, back, back, back,
|
||
|
// Right
|
||
|
right, right, right, right,
|
||
|
// Top
|
||
|
up, up, up, up
|
||
|
};
|
||
|
|
||
|
Vector2 _00 = new Vector2(0f, 0f);
|
||
|
Vector2 _10 = new Vector2(1f, 0f);
|
||
|
Vector2 _01 = new Vector2(0f, 1f);
|
||
|
Vector2 _11 = new Vector2(1f, 1f);
|
||
|
|
||
|
Vector2[] uvs = new Vector2[]
|
||
|
{
|
||
|
// Bottom
|
||
|
_11, _01, _00, _10,
|
||
|
// Left
|
||
|
_11, _01, _00, _10,
|
||
|
// Front
|
||
|
_11, _01, _00, _10,
|
||
|
// Back
|
||
|
_11, _01, _00, _10,
|
||
|
// Right
|
||
|
_11, _01, _00, _10,
|
||
|
// Top
|
||
|
_11, _01, _00, _10,
|
||
|
};
|
||
|
|
||
|
int[] triangles = new int[]
|
||
|
{
|
||
|
// Bottom
|
||
|
3, 1, 0,
|
||
|
3, 2, 1,
|
||
|
// Left
|
||
|
3 + 4 * 1, 1 + 4 * 1, 0 + 4 * 1,
|
||
|
3 + 4 * 1, 2 + 4 * 1, 1 + 4 * 1,
|
||
|
// Front
|
||
|
3 + 4 * 2, 1 + 4 * 2, 0 + 4 * 2,
|
||
|
3 + 4 * 2, 2 + 4 * 2, 1 + 4 * 2,
|
||
|
// Back
|
||
|
3 + 4 * 3, 1 + 4 * 3, 0 + 4 * 3,
|
||
|
3 + 4 * 3, 2 + 4 * 3, 1 + 4 * 3,
|
||
|
// Right
|
||
|
3 + 4 * 4, 1 + 4 * 4, 0 + 4 * 4,
|
||
|
3 + 4 * 4, 2 + 4 * 4, 1 + 4 * 4,
|
||
|
// Top
|
||
|
3 + 4 * 5, 1 + 4 * 5, 0 + 4 * 5,
|
||
|
3 + 4 * 5, 2 + 4 * 5, 1 + 4 * 5,
|
||
|
};
|
||
|
|
||
|
outputMesh.vertices = vertices;
|
||
|
outputMesh.normals = normales;
|
||
|
outputMesh.uv = uvs;
|
||
|
outputMesh.triangles = triangles;
|
||
|
|
||
|
outputMesh.RecalculateBounds();
|
||
|
}
|
||
|
|
||
|
void BuildCone(ref Mesh outputMesh, float height, float topRadius, float bottomRadius, int nbSides)
|
||
|
{
|
||
|
outputMesh.Clear();
|
||
|
|
||
|
int nbVerticesCap = nbSides + 1;
|
||
|
|
||
|
// bottom + top + sides
|
||
|
Vector3[] vertices = new Vector3[nbVerticesCap + nbVerticesCap + nbSides * 2 + 2];
|
||
|
int vert = 0;
|
||
|
float _2pi = Mathf.PI * 2f;
|
||
|
|
||
|
// Bottom cap
|
||
|
vertices[vert++] = new Vector3(0f, 0f, 0f);
|
||
|
while (vert <= nbSides)
|
||
|
{
|
||
|
float rad = (float)vert / nbSides * _2pi;
|
||
|
vertices[vert] = new Vector3(Mathf.Sin(rad) * bottomRadius, Mathf.Cos(rad) * bottomRadius, 0f);
|
||
|
vert++;
|
||
|
}
|
||
|
|
||
|
// Top cap
|
||
|
vertices[vert++] = new Vector3(0f, 0f, height);
|
||
|
while (vert <= nbSides * 2 + 1)
|
||
|
{
|
||
|
float rad = (float)(vert - nbSides - 1) / nbSides * _2pi;
|
||
|
vertices[vert] = new Vector3(Mathf.Sin(rad) * topRadius, Mathf.Cos(rad) * topRadius, height);
|
||
|
vert++;
|
||
|
}
|
||
|
|
||
|
// Sides
|
||
|
int v = 0;
|
||
|
while (vert <= vertices.Length - 4)
|
||
|
{
|
||
|
float rad = (float)v / nbSides * _2pi;
|
||
|
vertices[vert] = new Vector3(Mathf.Sin(rad) * topRadius, Mathf.Cos(rad) * topRadius, height);
|
||
|
vertices[vert + 1] = new Vector3(Mathf.Sin(rad) * bottomRadius, Mathf.Cos(rad) * bottomRadius, 0);
|
||
|
vert += 2;
|
||
|
v++;
|
||
|
}
|
||
|
vertices[vert] = vertices[nbSides * 2 + 2];
|
||
|
vertices[vert + 1] = vertices[nbSides * 2 + 3];
|
||
|
|
||
|
// bottom + top + sides
|
||
|
Vector3[] normales = new Vector3[vertices.Length];
|
||
|
vert = 0;
|
||
|
|
||
|
// Bottom cap
|
||
|
while (vert <= nbSides)
|
||
|
{
|
||
|
normales[vert++] = new Vector3(0, 0, -1);
|
||
|
}
|
||
|
|
||
|
// Top cap
|
||
|
while (vert <= nbSides * 2 + 1)
|
||
|
{
|
||
|
normales[vert++] = new Vector3(0, 0, 1);
|
||
|
}
|
||
|
|
||
|
// Sides
|
||
|
v = 0;
|
||
|
while (vert <= vertices.Length - 4)
|
||
|
{
|
||
|
float rad = (float)v / nbSides * _2pi;
|
||
|
float cos = Mathf.Cos(rad);
|
||
|
float sin = Mathf.Sin(rad);
|
||
|
|
||
|
normales[vert] = new Vector3(sin, cos, 0f);
|
||
|
normales[vert + 1] = normales[vert];
|
||
|
|
||
|
vert += 2;
|
||
|
v++;
|
||
|
}
|
||
|
normales[vert] = normales[nbSides * 2 + 2];
|
||
|
normales[vert + 1] = normales[nbSides * 2 + 3];
|
||
|
|
||
|
Vector2[] uvs = new Vector2[vertices.Length];
|
||
|
|
||
|
// Bottom cap
|
||
|
int u = 0;
|
||
|
uvs[u++] = new Vector2(0.5f, 0.5f);
|
||
|
while (u <= nbSides)
|
||
|
{
|
||
|
float rad = (float)u / nbSides * _2pi;
|
||
|
uvs[u] = new Vector2(Mathf.Cos(rad) * .5f + .5f, Mathf.Sin(rad) * .5f + .5f);
|
||
|
u++;
|
||
|
}
|
||
|
|
||
|
// Top cap
|
||
|
uvs[u++] = new Vector2(0.5f, 0.5f);
|
||
|
while (u <= nbSides * 2 + 1)
|
||
|
{
|
||
|
float rad = (float)u / nbSides * _2pi;
|
||
|
uvs[u] = new Vector2(Mathf.Cos(rad) * .5f + .5f, Mathf.Sin(rad) * .5f + .5f);
|
||
|
u++;
|
||
|
}
|
||
|
|
||
|
// Sides
|
||
|
int u_sides = 0;
|
||
|
while (u <= uvs.Length - 4)
|
||
|
{
|
||
|
float t = (float)u_sides / nbSides;
|
||
|
uvs[u] = new Vector3(t, 1f);
|
||
|
uvs[u + 1] = new Vector3(t, 0f);
|
||
|
u += 2;
|
||
|
u_sides++;
|
||
|
}
|
||
|
uvs[u] = new Vector2(1f, 1f);
|
||
|
uvs[u + 1] = new Vector2(1f, 0f);
|
||
|
|
||
|
int nbTriangles = nbSides + nbSides + nbSides * 2;
|
||
|
int[] triangles = new int[nbTriangles * 3 + 3];
|
||
|
|
||
|
// Bottom cap
|
||
|
int tri = 0;
|
||
|
int i = 0;
|
||
|
while (tri < nbSides - 1)
|
||
|
{
|
||
|
triangles[i] = 0;
|
||
|
triangles[i + 1] = tri + 1;
|
||
|
triangles[i + 2] = tri + 2;
|
||
|
tri++;
|
||
|
i += 3;
|
||
|
}
|
||
|
triangles[i] = 0;
|
||
|
triangles[i + 1] = tri + 1;
|
||
|
triangles[i + 2] = 1;
|
||
|
tri++;
|
||
|
i += 3;
|
||
|
|
||
|
// Top cap
|
||
|
//tri++;
|
||
|
while (tri < nbSides * 2)
|
||
|
{
|
||
|
triangles[i] = tri + 2;
|
||
|
triangles[i + 1] = tri + 1;
|
||
|
triangles[i + 2] = nbVerticesCap;
|
||
|
tri++;
|
||
|
i += 3;
|
||
|
}
|
||
|
|
||
|
triangles[i] = nbVerticesCap + 1;
|
||
|
triangles[i + 1] = tri + 1;
|
||
|
triangles[i + 2] = nbVerticesCap;
|
||
|
tri++;
|
||
|
i += 3;
|
||
|
tri++;
|
||
|
|
||
|
// Sides
|
||
|
while (tri <= nbTriangles)
|
||
|
{
|
||
|
triangles[i] = tri + 2;
|
||
|
triangles[i + 1] = tri + 1;
|
||
|
triangles[i + 2] = tri + 0;
|
||
|
tri++;
|
||
|
i += 3;
|
||
|
|
||
|
triangles[i] = tri + 1;
|
||
|
triangles[i + 1] = tri + 2;
|
||
|
triangles[i + 2] = tri + 0;
|
||
|
tri++;
|
||
|
i += 3;
|
||
|
}
|
||
|
|
||
|
outputMesh.vertices = vertices;
|
||
|
outputMesh.normals = normales;
|
||
|
outputMesh.uv = uvs;
|
||
|
outputMesh.triangles = triangles;
|
||
|
|
||
|
outputMesh.RecalculateBounds();
|
||
|
}
|
||
|
|
||
|
void BuildPyramid(ref Mesh outputMesh, float width, float height, float depth)
|
||
|
{
|
||
|
outputMesh.Clear();
|
||
|
|
||
|
// Allocate the buffer
|
||
|
Vector3[] vertices = new Vector3[16];
|
||
|
|
||
|
// Top Face
|
||
|
vertices[0] = new Vector3(0f, 0f, 0f);
|
||
|
vertices[1] = new Vector3(-width / 2.0f, height / 2.0f, depth);
|
||
|
vertices[2] = new Vector3(width / 2.0f, height / 2.0f, depth);
|
||
|
|
||
|
// Left Face
|
||
|
vertices[3] = new Vector3(0f, 0f, 0f);
|
||
|
vertices[4] = new Vector3(width / 2.0f, height / 2.0f, depth);
|
||
|
vertices[5] = new Vector3(width / 2.0f, -height / 2.0f, depth);
|
||
|
|
||
|
// Bottom Face
|
||
|
vertices[6] = new Vector3(0f, 0f, 0f);
|
||
|
vertices[7] = new Vector3(width / 2.0f, -height / 2.0f, depth);
|
||
|
vertices[8] = new Vector3(-width / 2.0f, -height / 2.0f, depth);
|
||
|
|
||
|
// Right Face
|
||
|
vertices[9] = new Vector3(0f, 0f, 0f);
|
||
|
vertices[10] = new Vector3(-width / 2.0f, -height / 2.0f, depth);
|
||
|
vertices[11] = new Vector3(-width / 2.0f, height / 2.0f, depth);
|
||
|
|
||
|
// Cap
|
||
|
vertices[12] = new Vector3(-width / 2.0f, height / 2.0f, depth);
|
||
|
vertices[13] = new Vector3(-width / 2.0f, -height / 2.0f, depth);
|
||
|
vertices[14] = new Vector3(width / 2.0f, -height / 2.0f, depth);
|
||
|
vertices[15] = new Vector3(width / 2.0f, height / 2.0f, depth);
|
||
|
|
||
|
// TODO: support the uv/normals
|
||
|
Vector3[] normals = new Vector3[vertices.Length];
|
||
|
Vector2[] uvs = new Vector2[vertices.Length];
|
||
|
|
||
|
// The indexes for the side part is simple
|
||
|
int[] triangles = new int[18];
|
||
|
for (int idx = 0; idx < 12; ++idx)
|
||
|
{
|
||
|
triangles[idx] = idx;
|
||
|
}
|
||
|
|
||
|
// Cap indexes
|
||
|
triangles[12] = 12;
|
||
|
triangles[13] = 13;
|
||
|
triangles[14] = 14;
|
||
|
triangles[15] = 12;
|
||
|
triangles[16] = 14;
|
||
|
triangles[17] = 15;
|
||
|
|
||
|
outputMesh.vertices = vertices;
|
||
|
outputMesh.normals = normals;
|
||
|
outputMesh.uv = uvs;
|
||
|
outputMesh.triangles = triangles;
|
||
|
|
||
|
outputMesh.RecalculateBounds();
|
||
|
}
|
||
|
|
||
|
void BuildShapes()
|
||
|
{
|
||
|
m_sphereMesh = new Mesh();
|
||
|
BuildSphere(ref m_sphereMesh, 1.0f, 24, 16);
|
||
|
|
||
|
m_boxMesh = new Mesh();
|
||
|
BuildBox(ref m_boxMesh, 1.0f, 1.0f, 1.0f);
|
||
|
|
||
|
m_coneMesh = new Mesh();
|
||
|
BuildCone(ref m_coneMesh, 1.0f, 1.0f, 0.0f, 16);
|
||
|
|
||
|
m_pyramidMesh = new Mesh();
|
||
|
BuildPyramid(ref m_pyramidMesh, 1.0f, 1.0f, 1.0f);
|
||
|
}
|
||
|
|
||
|
void RebuildResources()
|
||
|
{
|
||
|
if (m_sphereMesh == null || m_boxMesh == null || m_coneMesh == null || m_pyramidMesh == null)
|
||
|
{
|
||
|
BuildShapes();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>Get a Sphere Mesh</summary>
|
||
|
/// <returns>A Sphere Mesh</returns>
|
||
|
public Mesh RequestSphereMesh()
|
||
|
{
|
||
|
RebuildResources();
|
||
|
return m_sphereMesh;
|
||
|
}
|
||
|
|
||
|
/// <summary>Builds a custom Sphere Mesh</summary>
|
||
|
/// <param name="radius">The radius of the generated sphere.</param>
|
||
|
/// <param name="longSubdiv">The number of subdivisions along the equator of the sphere. Must be at least 3 to give a relevant shape.</param>
|
||
|
/// <param name="latSubdiv">The number of subdivisions from north to south. Must be at least 1 to give a relevant shape.</param>
|
||
|
/// <returns>A Sphere Mesh</returns>
|
||
|
/// <example>
|
||
|
/// <code>
|
||
|
/// <![CDATA[
|
||
|
/// Mesh lowPolyDebugMesh = DebugShapes.instance.BuildCustomSphereMesh(0.5f, 9, 8); // Generates a 82 vert sphere
|
||
|
/// ]]>
|
||
|
///</code>
|
||
|
/// </example>
|
||
|
public Mesh BuildCustomSphereMesh(float radius, uint longSubdiv, uint latSubdiv)
|
||
|
{
|
||
|
Mesh sphereMesh = new Mesh();
|
||
|
BuildSphere(ref sphereMesh, radius, longSubdiv, latSubdiv);
|
||
|
return sphereMesh;
|
||
|
}
|
||
|
|
||
|
/// <summary>Get a Box Mesh</summary>
|
||
|
/// <returns>A Box Mesh</returns>
|
||
|
public Mesh RequestBoxMesh()
|
||
|
{
|
||
|
RebuildResources();
|
||
|
return m_boxMesh;
|
||
|
}
|
||
|
|
||
|
/// <summary>Get a Cone Mesh</summary>
|
||
|
/// <returns>A Cone Mesh</returns>
|
||
|
public Mesh RequestConeMesh()
|
||
|
{
|
||
|
RebuildResources();
|
||
|
return m_coneMesh;
|
||
|
}
|
||
|
|
||
|
/// <summary>Get a Pyramid Mesh</summary>
|
||
|
/// <returns>A Pyramid Mesh</returns>
|
||
|
public Mesh RequestPyramidMesh()
|
||
|
{
|
||
|
RebuildResources();
|
||
|
return m_pyramidMesh;
|
||
|
}
|
||
|
}
|
||
|
}
|