网格表面上的LineRenderer

时间:2019-02-28 23:41:17

标签: unity3d 3d mesh

目标:在基于网格的图元表面(例如球体,立方体等)的两点之间绘制距离线。

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 :(得分:1)

如果您想优化解决方案,则可能需要为每个原始语言编写一个脚本并利用特定于原始语言的数学。

例如,您可以简单地获取网格的半径并将线顶点放在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