目前尝试沿贝塞尔曲线实例化一些对象。这是有效的,除了网格沿曲线不均匀分布的事实。所以我需要做一些弧参数化。
我的信息来自此文档WarpingTextToSplines,因此以下代码是我对伪代码的解释。
首先,找到曲线的(近似)长度,并将其分成几个部分:
private void buildCurveTables()
{
int curveSegments = 100;
lengthTable = new float[curveSegments + 1];
Vector3 previousPoint = GetBezierPoint(0, curvePoints[0], curvePoints[1], curvePoints[2]);
float sum = 0;
lengthTable[0] = 0;
for (int i = 1; i < lengthTable.Length; i++)
{
Vector3 currentPoint = GetBezierPoint(i / (float) lengthTable.Length, curvePoints[0], curvePoints[1], curvePoints[2]);
sum += Vector3.Distance(previousPoint, currentPoint);
lengthTable[i] = sum;
previousPoint = currentPoint;
}
totalCurveLength = sum;
}
这将沿曲线存储100个长度值。稍后将使用这些来确定曲线上放置网格的正确位置。使用以下内容在表中找到该值:
private float findPositionOnCurve(float u)
{
float t; //Find t for the given u
float targetArcLength = u * lengthTable[lengthTable.Length-1];
//Debug.Log("u is: " + u);
int index = Array.BinarySearch(lengthTable, targetArcLength);
if (u >=1)
{
return 1;
}
if (index < 0)
{
index = ~index - 1;
//No exact match found
float lengthBefore = lengthTable[index];
return (index + (targetArcLength - lengthBefore) / (lengthTable[index + 1] - lengthBefore)) / lengthTable.Length;
}
else
{
//Exact match found
t = index / (float)lengthTable.Length - 1;
//Debug.Log("Exact match, returning " + t);
return t;
}
}
我尝试了许多不同的二次贝塞尔曲线算法,但这些算法似乎产生了正确的结果。
private Vector3 GetBezierPoint(float t, Vector3 start, Vector3 control, Vector3 end)
{
//float x = (((1 - t) * (1 - t)) * start.x) + (2 * t * (1 - t) * control.x) + ((t * t) * end.x);
//float y = (((1 - t) * (1 - t)) * start.y) + (2 * t * (1 - t) * control.y) + ((t * t) * end.y);
//float z = (((1 - t) * (1 - t)) * start.z) + (2 * t * (1 - t) * control.z) + ((t * t) * end.z);
//return new Vector3(x, y, z);
//http://answers.unity3d.com/questions/990171/curve-between-lerps.html
float rt = 1 - t;
return rt * rt * start + 2 * rt * t * control + t * t * end;
}
更新
我还会把我写的代码放到实例化曲线上的对象上,以防我在那里做一些蠢事......
//Only try to curve the objects once the control point has been put down.
if (curvedMode && createdCurveControlHandle)
{
Vector3 startOfCurve = getCurveStartPoint().transform.position;
curvePoints = new Vector3[3] { startOfCurve, currentCurveControlHandle.transform.position, currentMousePosition };
buildCurveTables();
//Lerp value is generated through a loop that generates 'n' number of
objects based on the distance between the start and current mouse position
float mappedLerp = findPositionOnCurve(lerpValue);
Vector3 pointTest = GetBezierPoint(mappedLerp, curvePoints[0], curvePoints[1], curvePoints[2]);
nextPlacementLocationTarget = pointTest;
nextPosition = Vector3.Lerp(startOfCurve, nextPlacementLocationTarget,mappedLerp);}
以下是一些lerp查找:
Lerp: 0.32 mappedLerp: 0.1659664
Lerp: 0.36 mappedLerp: 0.1896916
Lerp: 0.3999999 mappedLerp: 0.2143274
Lerp: 0.4399999 mappedLerp: 0.2399609
Lerp: 0.4799999 mappedLerp: 0.2667291
Lerp: 0.5199999 mappedLerp: 0.2948231
Lerp: 0.5599999 mappedLerp: 0.3244205
其他更新
经过一些调整和SO用户'MBo'的帮助后,我现在使用固定长度的十个对象得到了相当均匀的分布。然而,他们仍然在曲线的开头分配更多。
我更新了我的代码,使用第二个答案中提到的表格创建和二元搜索来解决这个问题How-to-achieve-uniform-speed-of-movement-on-a-bezier-curve
我经历了很多次检查,我开始睁大眼睛。我不确定我的数学是否已关闭,所以我误解了一些事情。
曲线上的大多数网格都在开始时分组,然后在一段时间后它们开始均匀。
如果有人有任何想法或建议,我将非常感激。
由于
答案 0 :(得分:2)
您的Bezier数学和表格构建看起来不错。但搜索是奇怪的。
首先 - 使用一种用于不精确搜索的二进制搜索算法 - 它返回数组/列表中的索引,我们可以在其中插入项目。 Delphi实现示例:
alow := 0;
ahigh := A.Count - 1;
while ahigh - alow > 1 do begin
j := (ahigh + alow) div 2;
if Value <= A[j] then
ahigh := j
else
alow := j;
end;
如果按顺序沿曲线放置对象(例如,文本字符),则线性搜索可能更有效 - 您总是向前移动,因此下一次搜索从当前索引开始:
i = 0 // or current index
while (A[i] < Value) && (i < A.Length)
i++
请注意,沿Bezier弧长的t参数分布可能非常不均匀。示例显示了两条曲线,均带有t步参数1/8。在第二种情况下,t = 0.5对应于全长的0.28。
现在甚至弧长点的范围为0.05..0.95(relativelength = 0.05 + i / 10.0
)。我使用过二维立方贝塞尔曲线,但没有主要区别。