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

211 lines
7.9 KiB
C#

using System.Collections.Generic;
using UnityEditor;
namespace UnityEngine.ProBuilder.Shapes
{
/// <summary>
/// Represents a basic [pipe](../manual/Pipe.html) shape.
/// </summary>
[Shape("Pipe")]
public class Pipe : Shape
{
/// <summary>
/// Sets the thickness of the walls of the pipe in meters. The thicker the value, the smaller the hole becomes.
/// The default value is 0.25. The minimum value is 0.01.
/// </summary>
[Min(0.01f)]
[SerializeField]
float m_Thickness = .25f;
/// <summary>
/// Sets the number of sides for the pipe. The more sides you use, the smoother the sides of the pipe become.
/// The default value is 6. Valid values range from 3 to 64.
/// </summary>
[Range(3, 64)]
[SerializeField]
int m_NumberOfSides = 6;
/// <summary>
/// Sets the number of divisions to use for the height of the pipe.
/// The default value is 0. Valid values range from 0 to 31.
/// </summary>
[Range(0, 31)]
[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 Pipe)
{
Pipe pipe = (Pipe) shape;
m_Thickness = pipe.m_Thickness;
m_NumberOfSides = pipe.m_NumberOfSides;
m_HeightCuts = pipe.m_HeightCuts;
m_Smooth = pipe.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;
// template is outer ring - radius refers to outer ring always
Vector2[] templateOut = new Vector2[m_NumberOfSides];
Vector2[] templateIn = new Vector2[m_NumberOfSides];
Vector2 tangent;
for (int i = 0; i < m_NumberOfSides; i++)
{
float angle = i * ( 360f / m_NumberOfSides );
templateOut[i] = Math.PointInEllipseCircumference(xRadius, zRadius, angle, Vector2.zero, out tangent);
Vector2 tangentOrtho = new Vector2(-tangent.y, tangent.x);
templateIn[i] = templateOut[i] + (m_Thickness * tangentOrtho);
}
List<Vector3> v = new List<Vector3>();
var baseY = height / 2f;
// build out sides
Vector2 tmp, tmp2, tmp3, tmp4;
var heightSegments = m_HeightCuts + 1;
for (int i = 0; i < heightSegments; i++)
{
// height subdivisions
float y = i * (height / heightSegments) - baseY;
float y2 = (i + 1) * (height / heightSegments) - baseY;
for (int n = 0; n < m_NumberOfSides; n++)
{
tmp = templateOut[n];
tmp2 = n < (m_NumberOfSides - 1) ? templateOut[n + 1] : templateOut[0];
// outside quads
Vector3[] qvo = new Vector3[4]
{
new Vector3(tmp2.x, y, tmp2.y),
new Vector3(tmp.x, y, tmp.y),
new Vector3(tmp2.x, y2, tmp2.y),
new Vector3(tmp.x, y2, tmp.y)
};
// inside quad
tmp = templateIn[n];
tmp2 = n < (m_NumberOfSides - 1) ? templateIn[n + 1] : templateIn[0];
Vector3[] qvi = new Vector3[4]
{
new Vector3(tmp.x, y, tmp.y),
new Vector3(tmp2.x, y, tmp2.y),
new Vector3(tmp.x, y2, tmp.y),
new Vector3(tmp2.x, y2, tmp2.y)
};
v.AddRange(qvo);
v.AddRange(qvi);
}
}
// build top and bottom
for (int i = 0; i < m_NumberOfSides; i++)
{
tmp = templateOut[i];
tmp2 = (i < m_NumberOfSides - 1) ? templateOut[i + 1] : templateOut[0];
tmp3 = templateIn[i];
tmp4 = (i < m_NumberOfSides - 1) ? templateIn[i + 1] : templateIn[0];
// top
Vector3[] tpt = new Vector3[4]
{
new Vector3(tmp2.x, height-baseY, tmp2.y),
new Vector3(tmp.x, height-baseY, tmp.y),
new Vector3(tmp4.x, height-baseY, tmp4.y),
new Vector3(tmp3.x, height-baseY, tmp3.y)
};
// bottom
Vector3[] tpb = new Vector3[4]
{
new Vector3(tmp.x, -baseY, tmp.y),
new Vector3(tmp2.x, -baseY, tmp2.y),
new Vector3(tmp3.x, -baseY, tmp3.y),
new Vector3(tmp4.x, -baseY, tmp4.y),
};
v.AddRange(tpb);
v.AddRange(tpt);
}
for(int i = 0; i < v.Count; i++)
v[i] = rotation * v[i];
mesh.GeometryWithPoints(v.ToArray());
//Smooth internal and external faces
if(m_Smooth)
{
int smoothCount = 2 * heightSegments * m_NumberOfSides;
for(int i = 0; i < smoothCount; i++)
mesh.facesInternal[i].smoothingGroup = 1;
}
return UpdateBounds(mesh, size, rotation, new Bounds());
}
}
#if UNITY_EDITOR
[CustomPropertyDrawer(typeof(Pipe))]
public class PipeDrawer : PropertyDrawer
{
static bool s_foldoutEnabled = true;
const bool k_ToggleOnLabelClick = true;
static readonly GUIContent k_ThicknessContent = new GUIContent("Thickness", L10n.Tr("Thickness of the pipe borders. Larger value creates a smaller hole."));
static readonly GUIContent k_SidesContent = new GUIContent("Sides Count", L10n.Tr("Number of sides of the pipe."));
static readonly GUIContent k_HeightCutsContent = new GUIContent("Height Cuts", L10n.Tr("Number of divisions in the pipe height."));
static readonly GUIContent k_SmoothContent = new GUIContent("Smooth", L10n.Tr("Whether to smooth the edges of the pipe."));
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
EditorGUI.BeginProperty(position, label, property);
s_foldoutEnabled = EditorGUI.Foldout(position, s_foldoutEnabled, "Pipe Settings", k_ToggleOnLabelClick);
EditorGUI.indentLevel++;
if(s_foldoutEnabled)
{
EditorGUILayout.PropertyField(property.FindPropertyRelative("m_Thickness"), k_ThicknessContent);
EditorGUILayout.PropertyField(property.FindPropertyRelative("m_NumberOfSides"), k_SidesContent);
EditorGUILayout.PropertyField(property.FindPropertyRelative("m_HeightCuts"), k_HeightCutsContent);
EditorGUILayout.PropertyField(property.FindPropertyRelative("m_Smooth"), k_SmoothContent);
}
EditorGUI.indentLevel--;
EditorGUI.EndProperty();
}
}
#endif
}