Угол выключен в динамическом поколении Torus Mesh - PullRequest
0 голосов
/ 31 октября 2018

У меня есть код для динамической генерации сегмента тора в зависимости от угла (который я в основном взял из 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

enter image description here

Но, как вы могли заметить, что-то не так с моим кодом / математикой.

Основная проблема: торус не завершен на 360 °.

enter image description here

Но когда я проверил это дальше, я заметил, что на самом деле уже раньше, например. Неправильно и угол 90 °:

enter image description here

Так что в настоящее время для получения замкнутого тора мне нужно использовать угол где-то между 378 ° и 379 °. Так что кажется, что пропущенное смещение в 19 ° всегда есть ... но откуда это? (Это также работает для небольших углов, поэтому у меня есть сегмент также для angle < 19°)

Кто-нибудь видит, что я здесь не так делаю?


Обновление

Это число 19° на самом деле, кажется, зависит от (360° / _maxSegments ) = 18,5° (в моем примере _maxSegments было 20) и фактически становится меньше или больше в зависимости от этого значения _maxSegments.

1 Ответ

0 голосов
/ 31 октября 2018

Извлечение двух строк из исходного кода:

Vector3[] vertices = new Vector3[(nbRadSeg+1) * (nbSides+1)];

for( int seg = 0; seg <= nbRadSeg; seg++ )
                      ^^

... и соответствующие строки из вашего собственного кода:

var vertices = new Vector3[(segmentsCount + 1) * (_nbSides + 1)];

for (var segment = 0; segment < segmentsCount; segment++)
                              ^

Обратите внимание, что второе условие цикла - < вместо <=, как и должно быть. Это означает, что вы пропускаете последний сегмент.

А поскольку в вашем примере угловой интервал сегмента составляет ~ 18,5 °, наблюдаемое вами систематическое несоответствие ~ 19 ° не является совпадением.

Обратите внимание, что такая же проблема возникает и для нормального цикла, цикла УФ и треугольника.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...