TurnBasedStrategyCourse/Library/PackageCache/com.unity.probuilder@5.1.0/Runtime/Shapes/Sphere.cs

248 lines
8.1 KiB
C#

using UnityEditor;
namespace UnityEngine.ProBuilder.Shapes
{
/// <summary>
/// Represents a basic [sphere](../manual/Sphere.html) shape.
/// </summary>
[Shape("Sphere")]
public class Sphere : Shape
{
static readonly Vector3[] k_IcosphereVertices = new Vector3[12]
{
new Vector3(-1f, Math.phi, 0f),
new Vector3(1f, Math.phi, 0f),
new Vector3(-1f, -Math.phi, 0f),
new Vector3(1f, -Math.phi, 0f),
new Vector3(0f, -1f, Math.phi),
new Vector3(0f, 1f, Math.phi),
new Vector3(0f, -1f, -Math.phi),
new Vector3(0f, 1f, -Math.phi),
new Vector3(Math.phi, 0f, -1f),
new Vector3(Math.phi, 0f, 1f),
new Vector3(-Math.phi, 0f, -1f),
new Vector3(-Math.phi, 0f, 1f)
};
static readonly int[] k_IcosphereTriangles = new int[60]
{
0, 11, 5,
0, 5, 1,
0, 1, 7,
0, 7, 10,
0, 10, 11,
1, 5, 9,
5, 11, 4,
11, 10, 2,
10, 7, 6,
7, 1, 8,
3, 9, 4,
3, 4, 2,
3, 2, 6,
3, 6, 8,
3, 8, 9,
4, 9, 5,
2, 4, 11,
6, 2, 10,
8, 6, 7,
9, 8, 1
};
/// <summary>
/// Sets the number of times to subdivide each triangle. The more subdivisions you create, the smoother the sphere appears.
/// However, remember that each subdivision increases the number of triangles exponentially, which means that it uses a lot
/// more resources to render.
///
/// The default value is 3. Valid values range from 1 to 5.
/// </summary>
[Range(1, 5)]
[SerializeField]
int m_Subdivisions = 3;
int m_BottomMostVertexIndex = 0;
/// <summary>
/// Determines whether to smooth the edges of the polygons.
/// This property is enabled by default.
/// </summary>
[SerializeField]
bool m_Smooth = true;
/// <inheritdoc/>
public override void CopyShape(Shape shape)
{
if(shape is Sphere)
{
Sphere sphere = ( (Sphere) shape );
m_Subdivisions = sphere.m_Subdivisions;
m_BottomMostVertexIndex = sphere.m_BottomMostVertexIndex;
m_Smooth = sphere.m_Smooth;
}
}
/// <inheritdoc/>
public override Bounds UpdateBounds(ProBuilderMesh mesh, Vector3 size, Quaternion rotation, Bounds bounds)
{
bounds = mesh.mesh.bounds;
return bounds;
}
/// <inheritdoc/>
public override Bounds RebuildMesh(ProBuilderMesh mesh, Vector3 size, Quaternion rotation)
{
var radius = .5f;
// http://blog.andreaskahler.com/2009/06/creating-icosphere-mesh-in-code.html
Vector3[] v = new Vector3[k_IcosphereTriangles.Length];
// Regular Icosahedron - 12 vertices, 20 faces.
for (int i = 0; i < k_IcosphereTriangles.Length; i += 3)
{
v[i + 0] = k_IcosphereVertices[k_IcosphereTriangles[i + 0]].normalized * radius;
v[i + 1] = k_IcosphereVertices[k_IcosphereTriangles[i + 1]].normalized * radius;
v[i + 2] = k_IcosphereVertices[k_IcosphereTriangles[i + 2]].normalized * radius;
}
for (int i = 0; i < m_Subdivisions; i++)
{
v = SubdivideIcosahedron(v, radius);
}
Face[] f = new Face[v.Length / 3];
Vector3 bottomMostVertexPosition = Vector3.positiveInfinity;
for (int i = 0; i < v.Length; i += 3)
{
f[i / 3] = new Face(new int[3] { i, i + 1, i + 2 });
f[i / 3].smoothingGroup = m_Smooth ? 1 : 0;
f[i / 3].manualUV = false;
// Get the bottom most vertex of the whole shape. We'll use it as a pivot point.
for (int j = 0; j < f[i / 3].indexes.Count; ++j)
{
int index = f[i / 3].indexes[j];
if (v[index].y < bottomMostVertexPosition.y)
{
bottomMostVertexPosition = v[index];
m_BottomMostVertexIndex = index;
}
}
}
for (int i = 0; i < f.Length; i++)
{
var nrm = Math.Normal(v[f[i].indexesInternal[0]], v[f[i].indexesInternal[1]], v[f[i].indexesInternal[2]]);
var axis = Projection.VectorToProjectionAxis(nrm);
if (axis == ProjectionAxis.X)
f[i].textureGroup = 2;
else if (axis == ProjectionAxis.Y)
f[i].textureGroup = 3;
else if (axis == ProjectionAxis.Z)
f[i].textureGroup = 4;
else if (axis == ProjectionAxis.XNegative)
f[i].textureGroup = 5;
else if (axis == ProjectionAxis.YNegative)
f[i].textureGroup = 6;
else if (axis == ProjectionAxis.ZNegative)
f[i].textureGroup = 7;
}
mesh.unwrapParameters = new UnwrapParameters()
{
packMargin = 30f
};
mesh.RebuildWithPositionsAndFaces(v, f);
return UpdateBounds(mesh, size, rotation, new Bounds());
}
// Subdivides a set of vertices (wound as individual triangles) on an icosphere.
//
// /\ /\
// / \ -> /--\
// /____\ /_\/_\
//
static Vector3[] SubdivideIcosahedron(Vector3[] vertices, float radius)
{
Vector3[] v = new Vector3[vertices.Length * 4];
int index = 0;
Vector3 p0 = Vector3.zero, // 5
p1 = Vector3.zero, // 3 4
p2 = Vector3.zero, // 0, 1, 2
p3 = Vector3.zero,
p4 = Vector3.zero,
p5 = Vector3.zero;
for (int i = 0; i < vertices.Length; i += 3)
{
p0 = vertices[i + 0];
p2 = vertices[i + 1];
p5 = vertices[i + 2];
p1 = ((p0 + p2) * .5f).normalized * radius;
p3 = ((p0 + p5) * .5f).normalized * radius;
p4 = ((p2 + p5) * .5f).normalized * radius;
v[index++] = p0;
v[index++] = p1;
v[index++] = p3;
v[index++] = p1;
v[index++] = p2;
v[index++] = p4;
v[index++] = p1;
v[index++] = p4;
v[index++] = p3;
v[index++] = p3;
v[index++] = p4;
v[index++] = p5;
}
return v;
}
}
#if UNITY_EDITOR
[CustomPropertyDrawer(typeof(Sphere))]
public class SphereDrawer : PropertyDrawer
{
static bool s_foldoutEnabled = true;
const bool k_ToggleOnLabelClick = true;
static readonly GUIContent k_SubdivisionsContent = new GUIContent("Subdivisions", L10n.Tr("Number of time each triangle of the basic sphere is divided."));
static readonly GUIContent k_SmoothContent = new GUIContent("Smooth", L10n.Tr("Whether to smooth the edges of the sphere."));
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
EditorGUI.BeginProperty(position, label, property);
s_foldoutEnabled = EditorGUI.Foldout(position, s_foldoutEnabled, "Sphere Settings", k_ToggleOnLabelClick);
EditorGUI.indentLevel++;
if(s_foldoutEnabled)
{
EditorGUILayout.PropertyField(property.FindPropertyRelative("m_Subdivisions"), k_SubdivisionsContent);
EditorGUILayout.PropertyField(property.FindPropertyRelative("m_Smooth"), k_SmoothContent);
}
EditorGUI.indentLevel--;
EditorGUI.EndProperty();
}
}
#endif
}