基本上,我需要从OpenGL中的Bezier曲线实现中获取所有坐标。具体来说,我需要坐标沿着弯曲的轨迹路径在我的场景中移动球体对象(棒球)。这就是我用来绘制曲线的方法:
GL2 gl = drawable.getGL().getGL2();
float ctrlpoints[][] = new float[][]{
{0.0f, 0.0f, 60f},
{0.0f, 3.0f, 45.0f},
{0.0f, 2.0f, 15.0f},
{0.0f, 1.0f, 0f}};
FloatBuffer ctrlpointBuf = FloatBuffer.allocate(ctrlpoints[0].length * ctrlpoints.length);
for (int i = 0; i < ctrlpoints.length; i++) {
for (int j = 0; j < 3; j++) {
ctrlpointBuf.put(ctrlpoints[i][j]);
}
}
ctrlpointBuf.rewind();
gl.glMap1f(GL2.GL_MAP1_VERTEX_3, 0.0f, 1.0f, 3, numControlPoints, ctrlpointBuf);
gl.glEnable(GL2.GL_MAP1_VERTEX_3);
gl.glColor3f(1.0f, 1.0f, 1.0f);
gl.glBegin(GL2.GL_LINE_STRIP);
for (int i = 0; i <= 30; i++) {
gl.glEvalCoord1f((float) i / (float) 30.0);
}
gl.glEnd();
有没有人知道如何从这个实现中获得积分?
答案 0 :(得分:21)
Bezier曲线非常容易计算。首先是可分离的,这意味着你可以一次计算一个坐标(先是x,然后是y,然后是z ......)。对于给定坐标,以下是使用定义的函数:
double bezier(double A, // Start value
double B, // First control value
double C, // Second control value
double D, // Ending value
double t) // Parameter 0 <= t <= 1
{
double s = 1 - t;
double AB = A*s + B*t;
double BC = B*s + C*t;
double CD = C*s + D*t;
double ABC = AB*s + BC*t;
double BCD = BC*s + CD*t;
return ABC*s + BCD*t;
}
请注意,在上面的函数中,参数t
不是曲线的弧长参数,而是来自t=0
的通用参数(其中点位于曲线的开头)到t=1
(点在曲线的末尾)。
上图的交互式版本,您可以拖动A,B,C,D和AB点is available here。它使用html / js / canvas实现,仅在Chrome,Firefox,Safari上进行测试。
如果您需要在XYZ中以受控的特定速度移动对象,则可以轻松计算近似折线(例如,通过对100个t
值的曲线进行采样),然后以恒定速度行走生成的折线。
Bezier三次方的真正弧长参数化(即使用沿曲线测量的长度参数)计算起来相当烦人(IIRC没有关于积分的闭合形式解)。
答案 1 :(得分:3)
我认为bezier()中的以下行应该是
双ABC = AB * s + CD * t;
而不是
双ABC = BC * s + CD * t;
使用.c程序进行快速测试可得出这些结果。注意,曲线坐标从10.00而不是20.00开始,具有上述未修改的函数。
~/sujith/cc > gcc oglBezier.c
~/sujith/cc > ./a.out
Start. A=10.000000, B=20.000000, C=40.000000, D=5.000000, t=0.000000
Bezier pt= 10.000000
Bezier pt= 10.495490
Bezier pt= 10.981920
Bezier pt= 11.459230
Bezier pt= 11.927360
Bezier pt= 12.386250
Bezier pt= 12.835840
Bezier pt= 13.276070
Bezier pt= 13.706880
Bezier pt= 14.128210
Bezier pt= 14.540000
Bezier pt= 14.942190
Bezier pt= 15.334720
Bezier pt= 15.717530
Bezier pt= 16.090560
Bezier pt= 16.453750
Bezier pt= 16.807040
Bezier pt= 17.150370
Bezier pt= 17.483680
Bezier pt= 17.806910
Bezier pt= 18.120000
Bezier pt= 18.422890
Bezier pt= 18.715520
Bezier pt= 18.997830
Bezier pt= 19.269760
Bezier pt= 19.531250
Bezier pt= 19.782240
Bezier pt= 20.022670
Bezier pt= 20.252480
Bezier pt= 20.471610
Bezier pt= 20.680000
Bezier pt= 20.877590
Bezier pt= 21.064320
Bezier pt= 21.240130
Bezier pt= 21.404960
Bezier pt= 21.558750
Bezier pt= 21.701440
Bezier pt= 21.832970
Bezier pt= 21.953280
Bezier pt= 22.062310
Bezier pt= 22.160000
Bezier pt= 22.246290
Bezier pt= 22.321120
Bezier pt= 22.384430
Bezier pt= 22.436160
Bezier pt= 22.476250
Bezier pt= 22.504640
Bezier pt= 22.521270
Bezier pt= 22.526080
Bezier pt= 22.519010
Bezier pt= 22.500000
Bezier pt= 22.468990
Bezier pt= 22.425920
Bezier pt= 22.370730
Bezier pt= 22.303360
Bezier pt= 22.223750
Bezier pt= 22.131840
Bezier pt= 22.027570
Bezier pt= 21.910880
Bezier pt= 21.781710
Bezier pt= 21.640000
Bezier pt= 21.485690
Bezier pt= 21.318720
Bezier pt= 21.139030
Bezier pt= 20.946560
Bezier pt= 20.741250
Bezier pt= 20.523040
Bezier pt= 20.291870
Bezier pt= 20.047680
Bezier pt= 19.790410
Bezier pt= 19.520000
Bezier pt= 19.236390
Bezier pt= 18.939520
Bezier pt= 18.629331
Bezier pt= 18.305761
Bezier pt= 17.968751
Bezier pt= 17.618241
Bezier pt= 17.254171
Bezier pt= 16.876481
Bezier pt= 16.485111
Bezier pt= 16.080001
Bezier pt= 15.661091
Bezier pt= 15.228321
Bezier pt= 14.781631
Bezier pt= 14.320961
Bezier pt= 13.846251
Bezier pt= 13.357441
Bezier pt= 12.854471
Bezier pt= 12.337281
Bezier pt= 11.805811
Bezier pt= 11.260001
Bezier pt= 10.699791
Bezier pt= 10.125121
Bezier pt= 9.535931
Bezier pt= 8.932161
Bezier pt= 8.313751
Bezier pt= 7.680641
Bezier pt= 7.032771
Bezier pt= 6.370081
Bezier pt= 5.692512
Bezier pt= 5.000002
测试程序oglBezier.c:
#include <stdio.h>
double bezier(double A, // Start value
double B, // First control value
double C, // Second control value
double D, // Ending value
double t) // Parameter 0 <= t <= 1
{
double s = 1 - t;
double AB = A*s + B*t;
double BC = B*s + C*t;
double CD = C*s + D*t;
double ABC = AB*s + CD*t;
double BCD = BC*s + CD*t;
return ABC*s + BCD*t;
}
main()
{
double a,b,c,d,t;
a = 10.0f;
b = 20.0f;
c = 40.0f;
d = 5.0f;
t = 0.0f;
printf("Start. A=%f, B=%f, C=%f, D=%f, t=%f\n", a,b,c,d,t);
while(1)
{
if(t>1.0f)
break;
printf("Bezier pt= %f\n", bezier(a,b,c,d,t));
t += 0.01f;
}
return 1;
}
答案 2 :(得分:2)
如果有人感兴趣,这就是我最终使用用贝塞尔曲线绘制的轨迹在我的场景中投射棒球球的方法。我使用6502非常有启发性的功能来计算每帧球的xyz坐标。起始值是在绘制框架时球在曲线上的任何位置。绘制整条曲线的结束值和控制点完全相同。我花了一段时间才弄明白的是给出参数t的参数。
我终于弄清楚它是从曲线的起点0开始到1的曲线END的值。因此,从投手土墩投掷的棒球将在离本垒板60.5英尺处t = 0,并且距离本垒板0英尺处t = 1。所以t可以简单地计算为
t += 1.0 / 60.5;
我首先绘制了整条曲线作为GL_LINE_STRIP,然后我计算了每帧的球的坐标。当我运行我的程序时,球完全遵循弯曲线轨迹。感谢所有给出答案并发表评论的人。
答案 3 :(得分:1)
我接受了公式,更正了它,并在github上创建了一个测试应用程序:gg://github.com/rmd6502/BezierLicious.git。我强烈建议不要在生产应用程序中使用我在那里做的任何事情 - 仅考虑用于研究目的!!
答案 4 :(得分:0)
你应该看看De Casteljau's algorithm。它允许您递归地细化曲线。只需在几个步骤后中止并使用生成的顶点。您还可以直接沿参数位置评估控制点并使用它们。直接评估Bézier-Splines并不难(例如,您可以在顶点着色器中执行此操作!)De Casteljau算法的优势在于您永远不必计算(高)幂,但对于您的情况,两者都应该是很好(直接评估肯定更容易实现/测试。)