【问题标题】:LineRenderer on Mesh surface网格表面上的 LineRenderer
【发布时间】:2019-02-28 23:41:17
【问题描述】:

目标:在基于网格的图元(即球体、立方体等)表面上的两点之间渲染距离线。

当前解决方案: 迭代遍历两个端点之间的距离线,并以某种方式通过该点“反向”射线投射。 由于距离线通过网格直接连接两个顶点,因此需要网格表面上的对应点。

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 条光线)。

  • 解决方案并不总是有效,会产生意想不到的锯齿状线条/点。

问题: 有没有更好的方法来实现这一点?

【问题讨论】:

    标签: unity3d 3d mesh


    【解决方案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 概念来控制线条的分辨率并坚持使用光线投射。我认为您看到的奇怪人工制品是点密度过高的结果。使每单位距离的点数保持一致也可能具有更好的性能。

    这是上面脚本的结果:

    【讨论】:

    • 感谢您的洞察力!正如您自己注意到的那样,不幸的是,这仅适用于单个基元,但如上所述,我至少会尝试利用 pointsPerUnit 变量。
    猜你喜欢
    • 2014-06-14
    • 2016-04-07
    • 1970-01-01
    • 1970-01-01
    • 2018-08-09
    • 2019-09-15
    • 1970-01-01
    • 1970-01-01
    • 2012-01-17
    相关资源
    最近更新 更多