LineRenderer на поверхности сетки - PullRequest
0 голосов
/ 01 марта 2019

Цель: Отображать линии расстояния между двумя точками на поверхности примитива на основе сетки (т. Е. Сферы, куба и т. Д.).

Lines drawn on surface of sphere Текущее решение: Итеративно пересекает линию расстояния между двумя конечными точками и как-то «переворачивает» лучевую передачу через эту точку. Так как линия расстояния напрямую соединяет обе вершины через сетку, требуются соответствующие точки на поверхности сетки.

Ray ray = new Ray();
RaycastHit raycastHit;
ray.origin = posOnDistanceLine;
ray.direction = raycastNormal.normalized;
// Reverse ray since we can't raycast from inside the mesh
ray.origin = ray.GetPoint(1);
ray.direction = -ray.direction;

Затем линии строятся с использованием Unity LineRenderer, который заполняетсяс позициями вершин всякий раз, когда идентифицируется изменение нормалей (к предыдущему радиопередаче).

Проблемы:

  • Ужасная производительность (так как 100 лучей подаются при движении конечных точек).

  • Решение не всегда работает и выдает неожиданные неровные линии / точки.

Вопрос: Есть ли лучший подход для реализации этого?

1 Ответ

0 голосов
/ 01 марта 2019

Если вы хотите оптимизировать решение, вам может потребоваться создать сценарий для каждого примитива и использовать математику, относящуюся к примитиву.

Например, вместо наведения лучей вы можете просто получить радиуссетка и поместите вершину линии в radius * directionFromCenter.

Вот пример сценария:

[RequireComponent(typeof(LineRenderer))]
public class SurfaceLine : MonoBehaviour, IPointerClickHandler
{
    [SerializeField] private float pointsPerUnit;
    [SerializeField] private MeshFilter mesh;

    private Vector3 start;
    private Vector3 end;
    private LineRenderer lineRenderer;

    void Awake()
    {
        this.lineRenderer = this.GetComponent<LineRenderer>();
    }

    public void OnPointerClick(PointerEventData eventData)
    {
        if(eventData.button == PointerEventData.InputButton.Left)
        {
            this.start = this.transform.InverseTransformPoint(eventData.pointerCurrentRaycast.worldPosition);
            this.Render();
            return;
        }

        if(eventData.button == PointerEventData.InputButton.Right)
        {
            this.end = this.transform.InverseTransformPoint(eventData.pointerCurrentRaycast.worldPosition);
            this.Render();
        }
    }

    private void Render()
    {
        var distance = Vector3.Distance(this.end, this.start);

        var direction = (this.end - this.start).normalized;

        var numPoints = Mathf.FloorToInt(distance * this.pointsPerUnit);

        numPoints = Mathf.Max(numPoints, 2);

        this.lineRenderer.positionCount = numPoints;

        var positions = new Vector3[numPoints];

        var stepInDir = direction * (distance / (float)numPoints);

        for(int i = 0; i < numPoints; i++)
        {
            positions[i] = this.start + i * stepInDir;

            var dirFromCenter = positions[i] - this.mesh.mesh.bounds.center;

            positions[i] = this.mesh.mesh.bounds.center + dirFromCenter.normalized * (this.mesh.mesh.bounds.size.x / 2.0f);
        }

        positions[positions.Length - 1] = this.end;

        this.lineRenderer.SetPositions(positions);
    }
}

Это, кажется, работает хорошо в цикле обновления.Недостатком является то, что решение не является общим.Вам понадобится стратегия для каждого примитива.

В качестве альтернативы вы можете по крайней мере использовать концепцию pointsPerUnit в скрипте, чтобы контролировать разрешение вашей линии и придерживаться приведения лучей.Я думаю, что странные артефакты, которые вы видите, являются результатом слишком высокой плотности точек.Согласование точек на единицу расстояния также может иметь лучшую производительность.

Вот результат для приведенного выше сценария: enter image description here

...