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

206 lines
7.8 KiB
C#

using UnityEditor;
namespace UnityEngine.ProBuilder.Shapes
{
/// <summary>
/// Represents a basic [cylinder](../manual/Cylinder.html) shape.
/// </summary>
[Shape("Cylinder")]
public class Cylinder : Shape
{
/// <summary>
/// Sets the number of sides for the cylinder. The more sides you use, the smoother the sides of the cylinder become.
/// The default value is 6. Valid values range from 4 to 64.
/// </summary>
[SerializeField]
[Range(3, 64)]
int m_AxisDivisions = 6;
/// <summary>
/// Sets the number of divisions to use for the height of the cylinder.
/// The default value is 0.
/// </summary>
[Min(0)]
[SerializeField]
int m_HeightCuts = 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 Cylinder)
{
m_AxisDivisions = ((Cylinder)shape).m_AxisDivisions;
m_HeightCuts = ((Cylinder)shape).m_HeightCuts;
m_Smooth = ((Cylinder)shape).m_Smooth;
}
}
/// <inheritdoc/>
public override Bounds UpdateBounds(ProBuilderMesh mesh, Vector3 size, Quaternion rotation, Bounds bounds)
{
bounds.size = size;
return bounds;
}
/// <inheritdoc/>
public override Bounds RebuildMesh(ProBuilderMesh mesh, Vector3 size, Quaternion rotation)
{
var upDir = Vector3.Scale(rotation * Vector3.up, size) ;
var rightDir = Vector3.Scale(rotation * Vector3.right, size) ;
var forwardDir = Vector3.Scale(rotation * Vector3.forward, size) ;
var height = upDir.magnitude;
var xRadius = rightDir.magnitude / 2f;
var zRadius = forwardDir.magnitude / 2f;
float heightStep = height / (m_HeightCuts + 1);
Vector2[] circle = new Vector2[m_AxisDivisions];
// get a circle
for (int i = 0; i < m_AxisDivisions; i++)
{
float angle = i * 360f / m_AxisDivisions;
circle[i] = Math.PointInEllipseCircumference(xRadius, zRadius, angle, Vector2.zero, out _);
}
// add two because end caps
Vector3[] vertices = new Vector3[(m_AxisDivisions * (m_HeightCuts + 1) * 4) + (m_AxisDivisions * 6)];
Face[] faces = new Face[m_AxisDivisions * (m_HeightCuts + 1) + (m_AxisDivisions * 2)];
// build vertex array
int it = 0;
// +1 to account for 0 height cuts
for (int i = 0; i < m_HeightCuts + 1; i++)
{
float Y = i * heightStep - height * .5f;
float Y2 = (i + 1) * heightStep - height * .5f;
for (int n = 0; n < m_AxisDivisions; n++)
{
vertices[it + 0] = new Vector3(circle[n + 0].x, Y, circle[n + 0].y);
vertices[it + 1] = new Vector3(circle[n + 0].x, Y2, circle[n + 0].y);
if (n != m_AxisDivisions - 1)
{
vertices[it + 2] = new Vector3(circle[n + 1].x, Y, circle[n + 1].y);
vertices[it + 3] = new Vector3(circle[n + 1].x, Y2, circle[n + 1].y);
}
else
{
vertices[it + 2] = new Vector3(circle[0].x, Y, circle[0].y);
vertices[it + 3] = new Vector3(circle[0].x, Y2, circle[0].y);
}
it += 4;
}
}
// wind side faces
int f = 0;
for (int i = 0; i < m_HeightCuts + 1; i++)
{
for (int n = 0; n < m_AxisDivisions * 4; n += 4)
{
int index = (i * (m_AxisDivisions * 4)) + n;
int zero = index;
int one = index + 1;
int two = index + 2;
int three = index + 3;
faces[f++] = new Face(
new int[6] { zero, one, two, one, three, two },
0,
AutoUnwrapSettings.tile,
m_Smooth ? 1 : -1,
-1,
-1,
false);
}
}
// construct caps separately, cause they aren't wound the same way
int ind = (m_AxisDivisions * (m_HeightCuts + 1) * 4);
int f_ind = m_AxisDivisions * (m_HeightCuts + 1);
for (int n = 0; n < m_AxisDivisions; n++)
{
// bottom faces
var bottomCapHeight = -height * .5f;
vertices[ind + 0] = new Vector3(circle[n].x, bottomCapHeight, circle[n].y);
vertices[ind + 1] = new Vector3(0f, bottomCapHeight, 0f);
if (n != m_AxisDivisions - 1)
vertices[ind + 2] = new Vector3(circle[n + 1].x, bottomCapHeight, circle[n + 1].y);
else
vertices[ind + 2] = new Vector3(circle[000].x, bottomCapHeight, circle[000].y);
faces[f_ind + n] = new Face(new int[3] { ind + 2, ind + 1, ind + 0 });
ind += 3;
// top faces
var topCapHeight = height * .5f;
vertices[ind + 0] = new Vector3(circle[n].x, topCapHeight, circle[n].y);
vertices[ind + 1] = new Vector3(0f, topCapHeight, 0f);
if (n != m_AxisDivisions - 1)
vertices[ind + 2] = new Vector3(circle[n + 1].x, topCapHeight, circle[n + 1].y);
else
vertices[ind + 2] = new Vector3(circle[000].x, topCapHeight, circle[000].y);
faces[f_ind + (n + m_AxisDivisions)] = new Face(new int[3] { ind + 0, ind + 1, ind + 2 });
ind += 3;
}
for(int i = 0; i < vertices.Length; i++)
vertices[i] = rotation * vertices[i];
mesh.RebuildWithPositionsAndFaces(vertices, faces);
return UpdateBounds(mesh, size, rotation, new Bounds());
}
}
#if UNITY_EDITOR
[CustomPropertyDrawer(typeof(Cylinder))]
public class CylinderDrawer : PropertyDrawer
{
static bool s_foldoutEnabled = true;
const bool k_ToggleOnLabelClick = true;
static readonly GUIContent k_SidesContent = new GUIContent("Sides Count", L10n.Tr("Number of sides of the cylinder."));
static readonly GUIContent k_HeightCutsContent = new GUIContent("Height Cuts", L10n.Tr("Number of divisions in the cylinder height."));
static readonly GUIContent k_SmoothContent = new GUIContent("Smooth", L10n.Tr("Whether to smooth the edges of the cylinder."));
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
EditorGUI.BeginProperty(position, label, property);
s_foldoutEnabled = EditorGUI.Foldout(position, s_foldoutEnabled, "Cylinder Settings", k_ToggleOnLabelClick);
EditorGUI.indentLevel++;
if(s_foldoutEnabled)
{
EditorGUILayout.PropertyField(property.FindPropertyRelative("m_AxisDivisions"), k_SidesContent);
EditorGUILayout.PropertyField(property.FindPropertyRelative("m_HeightCuts"), k_HeightCutsContent);
EditorGUILayout.PropertyField(property.FindPropertyRelative("m_Smooth"), k_SmoothContent);
}
EditorGUI.indentLevel--;
EditorGUI.EndProperty();
}
}
#endif
}