Как нарисовать нормаль сегментов в unity3D - PullRequest
0 голосов
/ 25 сентября 2019

Я пытаюсь нарисовать нормаль сегментов на кривой в редакторе единиц.До сих пор я вычислял нормали, но когда я рисую его в редакторе единиц, его направление не является правильным.Я думаю, что мне чего-то не хватает в функции Draw.Вот краткая версия кода.

using System.Collections.Generic;
using UnityEngine;

public class Segments : MonoBehaviour
{
    [HideInInspector]
    public List<Vector3> ControlPoints;
    [HideInInspector]
    public List<Vector3> Normals;

    [HideInInspector]
    public bool initialized;

    public void Init()
    {
        ControlPoints = new List<Vector3>();

        ControlPoints.Add(new Vector3(40, 0, 0));
        ControlPoints.Add(new Vector3(30, 0, -30));
        ControlPoints.Add(new Vector3(0, 0, -40));
        ControlPoints.Add(new Vector3(-30, 0, -30));
        ControlPoints.Add(new Vector3(-40, 0, 0));
        ControlPoints.Add(new Vector3(-30, 0, 30));
        ControlPoints.Add(new Vector3(0, 0, 40));
        ControlPoints.Add(new Vector3(30, 0, 30));

        int points = ControlPoints.Count;
        Normals = new List<Vector3>();

        for (int i = 0; i < points; i++)
        {
            //if we define dx=x2-x1 and dy=y2-y1, then the normals are (-dy, dx) and (dy, -dx).
            Vector2 start = new Vector2(ControlPoints[i % points].x, ControlPoints[i % points].z);
            Vector2 end = new Vector2(ControlPoints[(i + 1) % points].x, ControlPoints[(i + 1) % points].z);
            Vector2 direction = (end - start).normalized;
            Normals.Add(new Vector3(-direction.y, direction.x, 0));
        }

        initialized = true;
    }
}



using UnityEditor;
using UnityEngine;

[CustomEditor(typeof(Segments))]
public class DrawSegments : Editor
{
    Segments segments;

    void OnSceneGUI()
    {
        Draw();
    }

    void OnEnable()
    {
        segments = (Segments)target;
        if (!segments.initialized)
        {
            segments.Init();
        }
    }

    void Draw()
    {
        int points = segments.ControlPoints.Count;
        Handles.color = Color.green;

        for (int i = 0; i < points; i++)
        {
            Handles.FreeMoveHandle(segments.ControlPoints[i], Quaternion.identity, 1f, Vector3.zero, Handles.RectangleHandleCap);
            Handles.DrawLine(segments.ControlPoints[i % points], segments.ControlPoints[(i + 1) % points]);

            if (points > 1)
            {
                Vector3 midPoint = (segments.ControlPoints[i % points] + segments.ControlPoints[(i + 1) % points]) / 2;
                Handles.DrawLine(midPoint, midPoint + segments.Normals[i] + Vector3.one * 10);
            }
        }
    }
}

Вот как это происходит в редакторе единства This how it is coming in the unity editor

1 Ответ

1 голос
/ 25 сентября 2019

В ящике должно быть

Handles.DrawLine(midPoint, midPoint + Normals[i] * 10);

. То, что вы сделали с помощью + Vector3.one * 10, всегда дополнительно смещает направление в направлении X и Y.


Тогда вы бывместо этого используйте Vector3.Cross, чтобы получить векторы, которые находятся под углом 90 ° к вашему вектору direction.

Поскольку вы заставляете вершины всегда быть копланарными в XZ в любом случае (в вашем коде вы использовали Vector2 для того, чтобы отрезать компонент Y), вы можете напрямую передать обе позиции на Vector3.Cross, чтобы выполучим нормаль треугольника, используя Vector3.zero в качестве одной вершины.

Для первой точки % points фактически всегда избыточен.

for (int i = 0; i < points; i++)
{
    Normals.Add(Vector3.Cross(ControlPoints[i], ControlPoints[(i + 1) % points]).normalized);
}

enter image description here

В зависимости от ваших потребностей вы должны быть осторожны, в каком порядке вы проходите в обоих пунктах.Поскольку применяется правило «левой руки», нормаль перевернет свое направление, если порядок обоих векторов будет перевернут в трехмерном пространстве.

Перекрестное произведение двух векторов приводит к третьему вектору, перпендикулярномуна два входных вектора.Величина результата равна амплитудам двух входов, умноженным вместе и затем умноженным на синус угла между входами.Вы можете определить направление вектора результата, используя «правило левой руки».

Однако - снова - сВы заставляете их быть всегда копланарными в XZ. Разве не ясно, что все нормальные значения всегда будут равны Vector3.up?Чтобы вы могли пропустить весь обычный расчет и просто сделать

Handles.DrawLine(midPoint, midPoint + Vector3.up * 10);

Кстати: вам не нужен CustomEditor для этого.Вы можете просто сделать это в OnDrawGizmos или OnDrawGizmosSelected (вызывается только когда объект или родительский объект выбран в иерархии)

#if UNITY_EDITOR
    private void OnDrawGizmosSelected()
    {
        if (!initialized)
        {
            Init();
        }

        var points = ControlPoints.Count;
        Handles.color = Color.green;

        for (var i = 0; i < points; i++)
        {
            Handles.FreeMoveHandle(ControlPoints[i], Quaternion.identity, 1f, Vector3.zero, Handles.RectangleHandleCap);
            Handles.DrawLine(ControlPoints[i], ControlPoints[(i + 1) % points]);

            if (points > 1)
            {
                var midPoint = (ControlPoints[i] + ControlPoints[(i + 1) % points]) / 2;
                Handles.DrawLine(midPoint, midPoint + Normals[i] * 10);
            }
        }
    }
#endif
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...