I have to create a path with Bezier curves. The problem is that I can only get the results on the first 3 waypoints. How can I implement the algorithm to use multiple points?
public void DrawLine()
{
for (int point = 0; point < path.Length; point++)
{
if (point == 0)
{
positions[point] = Bezier(0, path[point].position, path[point + 1].position, path[point + 2].position, path[point + 3].position);
}
for (int i = 1; i <= 80; i++)
{
tt = (i / (float)numPoinr);
positions[i] = Bezier(node, path[point].position, path[point + 1].position, path[point + 2].position, path[point + 3].position);
inst = Instantiate(node, positions[i], Quaternion.identity) as GameObject;
}
}
}
private Vector3 Bezier(float t, Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3)
{
float u = 1 - t;
float tt = t * t;
float uu = u * u;
float uuu = uu + u;
float ttt = tt * t;
Vector3 p = uuu * p0;
p += 3 * uu * t * p1;
p += 3 * u * tt * p2;
p += ttt * p3;
return p;
}
in that case you need to step your loop by 3 each time, because p1 and p2 are just control points, and you dont want to actually visit them in the loop
also i just notcies you are instantiating your node in the sub loop, 80 times per point, this is probably wrong depending on how you are drawing the line
if you are using linerenderer you should only need one gameobject, and you assign the calculated bezier positions to it
I’m not using the line renderer I’m using small spheres. This is a trial file after I will use Bezier only for the movements. I was interested in seeing the various instances
I was able to trace Bezier curves, the problem is that if I wanted to use it to make a path does not work well. The player skips the first loop. Can you tell me why? Written so does not seem good to me but is the only solution I have found
private void Update()
{
//don't work
for (int point = 0; point < path.Length - 2; point +=2)
{
curr += Time.deltaTime;
perc = curr / 50f;
tr.transform.position = Bezier(perc, path[point].position, path[point + 1].position, path[point + 2].position);
Debug.Log(point);
}
}
Because of the mathematical complexity it takes to calculate the binomial coefficients for an increasing number of points. its usually cheaper if you subdivide a long bezier into a group of 3-5 point beziers and stitch them together. but if you really want a high point count…
public int BinomialCoefficient(int size, int choose)
{
int result = 1;
// use symmetry to reduce calculations
if (choose > size - 1 - choose)
{
choose = size - 1 - choose;
}
for (int i = 1; i <= choose; i++,size--)
{
if (result / i > Int16.MaxValue)
return 0; //result overflowed, so we lost the value
result = result / i * (size-1) + result % i; // divide before multiply to better avoid reaching overflow
}
return result;
}
public Vector3 Bezier(Vector3[] points, float lerp)
{
Vector3 point = Vector3.zero;
if (points == null)
{
return point;
}
lerp = Mathf.Clamp01(lerp);
float inverseLerp = 1 - lerp;
for (int i = 0; i < points.Length; i++)
{
//this is were the function can get expensive
float coef = BinomialCoefficient (points.Length, i);
float power = Mathf.Pow (lerp, i);
float inversePower = Mathf.Pow (inverseLerp, points.Length - i-1);
if(power < float.Epsilon) power = 0;
if(inversePower< float.Epsilon) inversePower = 0;
Vector3 weightedPosition = points [i] * coef * power * inversePower;
point += weightedPosition;
}
return point;
}
however if you do subdivide them, to ensure a smooth transition you simply need to make the last 2 points of bezier A be Colinear with the 1st two points of bezier B (meaning all four of those points run along the same line and in order), and then have the last point of Bezier A and the 1st point of Bezier B have the same position
You’re looping incorrectly and also incrementing the curr value by the deltaTime several times per frame. actually I’m not quite certain what you’re trying to do there as its all redundant in the end.
if you’re trying to animate something flying along the path you need to perform it differently (this is using the code I provided)
This code will make tr.transform visit all points on the curve at the same time in a single frame.
You need to spread out the movement across multiple frames.
Either use a coroutine and yield in the loop, or don’t use a loop at all, stepping the value only once per frame
Thanks for your answer. I had also thought of using the coroutiner but wanted to avoid it if I had to implement the algorithm in another graphical engine