很遗憾,我认为没有任何一种方法可以实现这种不怪异且不影响性能的效果。
当然,你可以像下面这样计算(假设LineRenderer
的起始位置数量为0):
public LineRenderer line;
private int positionCount;
private float totalLengthOld;
private void AddPoint(Vector3 position, float width)
{
positionCount++;
line.positionCount = positionCount;
line.SetPosition(positionCount - 1, position);
var curve = line.widthCurve;
if (positionCount == 1)
{
curve.MoveKey(0, new Keyframe(0f, width));
}
else
{
var positions = new Vector3[positionCount];
line.GetPositions(positions);
var totalLengthNew = 0f;
for (var i = 1; i < positionCount; i++)
{
totalLengthNew += Vector3.Distance(positions[i - 1], positions[i]);
}
var factor = totalLengthOld / totalLengthNew;
totalLengthOld = totalLengthNew;
var keys = curve.keys;
for (var i = 1; i < keys.Length; i++)
{
var key = keys[i];
key.time *= factor;
curve.MoveKey(i, key);
}
curve.AddKey(1f, width);
}
line.widthCurve = curve;
}
仅用作示范
public class Example : MonoBehaviour
{
public LineRenderer line;
public Transform pen;
[Range(0.01f, 0.5f)] public float width;
public float drawThreshold = 0.1f;
private int positionCount;
private float totalLengthOld;
private Vector3 lastPenPosition;
private void Awake()
{
line = GetComponent<LineRenderer>();
line.useWorldSpace = true;
line.positionCount = 0;
lastPenPosition = pen.position;
}
private void Update()
{
width = Mathf.Lerp(0.01f, 0.8f, Mathf.PingPong(Time.time, 1f));
var currentPenPosition = pen.position;
if (Vector3.Distance(lastPenPosition, currentPenPosition) >= drawThreshold)
{
lastPenPosition = currentPenPosition;
AddPoint(currentPenPosition, width);
}
}
private void AddPoint(Vector3 position, float width)
{
positionCount++;
line.positionCount = positionCount;
line.SetPosition(positionCount - 1, position);
var curve = line.widthCurve;
if (positionCount == 1)
{
curve.MoveKey(0, new Keyframe(0f, width));
}
else
{
var positions = new Vector3[positionCount];
line.GetPositions(positions);
var totalLengthNew = 0f;
for (var i = 1; i < positionCount; i++)
{
totalLengthNew += Vector3.Distance(positions[i - 1], positions[i]);
}
var factor = totalLengthOld / totalLengthNew;
totalLengthOld = totalLengthNew;
var keys = curve.keys;
for (var i = 1; i < keys.Length; i++)
{
var key = keys[i];
key.time *= factor;
curve.MoveKey(i, key);
}
curve.AddKey(1f, width);
}
line.widthCurve = curve;
}
}
![在此输入图片描述](https://istack.dev59.com/QdTtB.gif)
当然,使用LineRenderer
绘制一定数量的点后,性能会受到限制。但我认为目前来说这已经是你可以做到的最好了。否则,LineRenderer
可能不是绘图的正确工具。
当然,你可以采取巧妙的方法,在绘制一定数量的点之后,使用LineRenderer.BakeMesh
将现有的线路烘焙成单独的固定网格,并以最后一个点作为起点开始绘制新的线路。
这样,只有尚未烘焙的部分才会受到宽度曲线关键帧移动的影响。
类似于:
public int meshBakeThreshold = 50;
private void AddPoint(Vector3 position, float width)
{
......
if (positionCount >= meshBakeThreshold)
{
CreateSnapShotAndStartOver(position, width);
}
}
private void CreateSnapShotAndStartOver(Vector3 position, float width)
{
var snapshotObject = new GameObject("LineSnapshot", typeof(MeshRenderer), typeof(MeshFilter));
var renderer = snapshotObject.GetComponent<Renderer>();
renderer.material = line.material;
var meshFilter = snapshotObject.GetComponent<MeshFilter>();
var mesh = new Mesh();
line.BakeMesh(mesh, Camera.main, true);
meshFilter.mesh = mesh;
positionCount = 0;
AddPoint(position, width);
}
您需要稍微调整一下阈值,50
可能有点低,只是为了演示而使用。您需要在迭代所有关键帧和烘焙网格的性能成本之间找到一个平衡;)
![输入图像描述](https://istack.dev59.com/Jp6xH.gif)
totalLengthOld
最初为0
;) 稍后在线路至少有 2 个点后,您始终会在totalLengthOld = totalLengthNew;
中更新它 ;) - derHugo