Unity3d 网格曲面上的线渲染器
目标:渲染基于网格的基本体(即球体、立方体等)曲面上两点之间的距离线 当前解决方案:迭代遍历两个端点之间的距离线,并通过该点反向光线投射。由于距离线通过网格直接连接两个顶点,因此需要网格曲面上的相应点 然后,使用Unity的LineRenderer绘制线,只要识别到上一个光线投射的法线发生更改,就会使用顶点位置填充LineRenderer 问题: 当端点移动时,100条射线被投射,表现非常糟糕 解决方案并不总是有效,并产生意外的锯齿线/点 问题:Unity3d 网格曲面上的线渲染器,unity3d,3d,mesh,Unity3d,3d,Mesh,目标:渲染基于网格的基本体(即球体、立方体等)曲面上两点之间的距离线 当前解决方案:迭代遍历两个端点之间的距离线,并通过该点反向光线投射。由于距离线通过网格直接连接两个顶点,因此需要网格曲面上的相应点 然后,使用Unity的LineRenderer绘制线,只要识别到上一个光线投射的法线发生更改,就会使用顶点位置填充LineRenderer 问题: 当端点移动时,100条射线被投射,表现非常糟糕 解决方案并不总是有效,并产生意外的锯齿线/点 问题: 有没有更好的方法来实现这一点?如果要优化解决方
有没有更好的方法来实现这一点?如果要优化解决方案,可能需要为每个原语编写一个脚本,并利用原语特定的数学 例如,您可以简单地获取网格的半径并将线顶点放置在半径*方向FromCenter处,而不是投射光线 下面是一个示例脚本:
[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变量。
[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);
}
}