У меня есть код для динамической генерации сегмента тора в зависимости от угла (который я в основном взял из ProceduralPrimitives и внес некоторые изменения, чтобы использовать входной угол вместо создания полного тора):
public class DynamicTorusSegment : MonoBehaviour
{
[Range(0, 360)] public float CurrentAngle;
[SerializeField] private int _maxSegments = 20;
[SerializeField] private float _radius1 = 1f;
[SerializeField] private float _radius2 = 0.3f;
[SerializeField] private int _nbSides = 5;
// For checking if the Angle was changed since the last frame
private float _lastAngle;
private const float TwoPi = Mathf.PI * 2f;
// Update is called once per frame
private void Update()
{
if (Mathf.Approximately(CurrentAngle, _lastAngle)) return;
_lastAngle = CurrentAngle;
GenerateTorus(CurrentAngle);
}
private void GenerateTorus(float angle)
{
var meshFilter = GetComponent<MeshFilter>();
var mesh = meshFilter.mesh;
mesh.Clear();
var segmentsCount = (int)(_maxSegments * angle / 360);
if (!Mathf.Approximately(angle, 0))
{
segmentsCount = Mathf.Clamp(segmentsCount, 2, _maxSegments);
}
#region Vertices
var vertices = new Vector3[(segmentsCount + 1) * (_nbSides + 1)];
for (var segment = 0; segment < segmentsCount; segment++)
{
var currentSegment = segment == segmentsCount ? 0 : segment;
var t1 = (float)currentSegment / segmentsCount * TwoPi / 360 * angle;
var r1 = new Vector3(Mathf.Cos(t1) * _radius1, 0f, Mathf.Sin(t1) * _radius1);
for (var side = 0; side <= _nbSides; side++)
{
var currentSide = side == _nbSides ? 0 : side;
var t2 = (float)currentSide / _nbSides * TwoPi;
var r2 = Quaternion.AngleAxis(-t1 * Mathf.Rad2Deg, Vector3.up) * new Vector3(Mathf.Sin(t2) * _radius2, Mathf.Cos(t2) * _radius2);
vertices[side + segment * (_nbSides + 1)] = r1 + r2;
}
}
#endregion
#region Normales
var normals = new Vector3[vertices.Length];
for (var segment = 0; segment < segmentsCount; segment++)
{
var currentSegment = segment == segmentsCount ? 0 : segment;
var t1 = (float)currentSegment / segmentsCount * TwoPi / 360 * angle;
var r1 = new Vector3(Mathf.Cos(t1) * _radius1, 0f, Mathf.Sin(t1) * _radius1);
for (var side = 0; side <= _nbSides; side++)
{
normals[side + segment * (_nbSides + 1)] = (vertices[side + segment * (_nbSides + 1)] - r1).normalized;
}
}
#endregion
#region UVs
var uvs = new Vector2[vertices.Length];
for (var segment = 0; segment < segmentsCount; segment++)
{
for (var side = 0; side <= _nbSides; side++)
{
uvs[side + segment * (_nbSides + 1)] = new Vector2((float)segment / segmentsCount, (float)side / _nbSides);
}
}
#endregion
#region Triangles
var faceCount = vertices.Length;
var triangleCount = faceCount * 2;
var indexesCount = triangleCount * 3;
var triangles = new int[indexesCount];
var i = 0;
for (var segment = 0; segment < segmentsCount - 1; segment++)
{
for (var side = 0; side <= _nbSides - 1; side++)
{
var current = side + segment * (_nbSides + 1);
var next = side + (segment < (segmentsCount) ? (segment + 1) * (_nbSides + 1) : 0);
if (i >= triangles.Length - 6) continue;
triangles[i++] = current;
triangles[i++] = next;
triangles[i++] = next + 1;
triangles[i++] = current;
triangles[i++] = next + 1;
triangles[i++] = current + 1;
}
}
#endregion
mesh.vertices = vertices;
mesh.normals = normals;
mesh.uv = uvs;
mesh.triangles = triangles;
mesh.RecalculateBounds();
}
}
Это в основном работает нормально и создает сегмент Torus в зависимости от CurrentAngle
Но, как вы могли заметить, что-то не так с моим кодом / математикой.
Основная проблема: торус не завершен на 360 °.
Но когда я проверил это дальше, я заметил, что на самом деле уже раньше, например. Неправильно и угол 90 °:
Так что в настоящее время для получения замкнутого тора мне нужно использовать угол где-то между 378 ° и 379 °. Так что кажется, что пропущенное смещение в 19 ° всегда есть ... но откуда это? (Это также работает для небольших углов, поэтому у меня есть сегмент также для angle < 19°
)
Кто-нибудь видит, что я здесь не так делаю?
Обновление
Это число 19°
на самом деле, кажется, зависит от (360° / _maxSegments ) = 18,5°
(в моем примере _maxSegments
было 20) и фактически становится меньше или больше в зависимости от этого значения _maxSegments
.