贝塞尔曲线的 OpenGL 坐标
基本上,我需要获取从 OpenGL 中的贝塞尔曲线实现绘制的所有坐标。具体来说,我需要坐标来沿着弯曲的轨迹路径移动场景中的球体对象(棒球)。这就是我用来绘制曲线的方法:
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();
有人知道如何从这个实现中得到要点吗?
Basically, I need to get all the coordinates drawn from a Bezier curve implementation in OpenGL. Specifically, I need the coordinates to move a sphere object (baseball) in my scene along a curved trajectory path. This is what I use to draw my curve:
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();
Does any one have any idea how to get the points out of this implementation?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
贝塞尔曲线很容易计算。首先是可分离的,这意味着您可以一次计算一个坐标(首先是 x,然后是 y,然后是 z...)。对于给定坐标,以下是使用定义的函数:
请注意,在上述函数中,参数
t
不是曲线的弧长参数,而是来自的通用参数t=0
(该点位于曲线的起点)到t=1
(该点位于曲线的终点)。上图的交互式版本,您可以在其中拖动 A、B、C、 D 点和 AB 点可在此处获取。它是用 html/js/canvas 实现的,并且仅在 Chrome、Firefox、Safari 上进行了测试。
如果您需要在 XYZ 中以受控的特定速度移动对象,一种简单的方法是计算一条近似折线(例如,通过对 100 个
t
值对曲线进行采样),然后以恒定速度行走生成的折线。贝塞尔三次曲线的真实弧长参数化(即使用沿曲线测量的长度的参数)计算起来相当烦人(IIRC,积分没有封闭形式的解)。
A Bezier curve is quite easy to compute. First of all is separable, that means that you can compute it one coordinate at a time (first x, then y, then z...). For a given coordinate the following is a function that uses the definition:
Note that in the above function the parameter
t
is not the arc-length parameter for the curve but a generic parameter that goes fromt=0
(where the point is at the beginning of the curve) tot=1
(where the point is at the end of the curve).An interactive version of the above picture where you can drag A, B, C, D and AB points is available here. It's implemented with html/js/canvas and tested only on Chrome, Firefox, Safari.
If you need to move your objects at a controlled specific speed in XYZ an easy way is to compute an approximated polyline (for example by sampling the curve for 100 values of
t
) and then walk at constant speed on the resulting polyline.The true arc-length parametrization for a Bezier cubic (i.e. using a parameter that is the length measured along the curve) is rather annoying to compute (IIRC there is no closed form solution for the integral).
我认为 bezier() 中的以下行应为
double ABC = AB*s + CD*t;
而不是
双 ABC = BC*s + CD*t;
使用 .c 程序进行快速测试可以得出这些结果。请注意,对于上述未修改的函数,曲线坐标从 10.00 开始,而不是从 20.00 开始。
测试程序oglBezier.c:
I think the following line in bezier() should read
double ABC = AB*s + CD*t;
instead of
double ABC = BC*s + CD*t;
A quick test with a .c program gives these results. Note, the curve coordinates start at 10.00 instead of at 20.00 with the above unmodified function.
Test program oglBezier.c:
如果有人感兴趣,这就是我最终如何使用贝塞尔曲线绘制的轨迹在场景中实现棒球球的投球。我使用 6502 非常有启发性的函数来计算球在每一帧的 xyz 坐标。起始值是绘制框架时球位于曲线上的任何位置。绘制整条曲线的结束值和控制点完全相同。我花了一段时间才弄清楚给参数 t 提供什么参数。
我最终发现它是从0(曲线的起点)到1(曲线的终点)的值。因此,从投手丘投出的棒球在距本垒 60.5 英尺处为 t=0,在距本垒 0 英尺处为 t=1。因此 t 的计算方式可能就像
我首先将整个曲线绘制为 GL_LINE_STRIP 一样简单,然后计算每一帧的球的坐标。当我运行程序时,球完全遵循曲线轨迹。感谢所有给出答案和提出意见的人。
In case anyone's interested, this is how I finally implemented pitching a baseball sphere in my scene using a trajectory drawn with a bezier curve. I used 6502's very illuminating function to compute xyz coordinates for the ball at each frame. The starting value is wherever the ball is on the curve as the frame is being drawn. The ending value and the control points are the exact same for drawing the entire curve. The thing that took me a while to figure out was what arguments to give the parameter t.
I finally figured out that it was the values from 0, the START of the curve, to 1, the END of the curve. So, a baseball pitched from the pitchers mound will be t=0 at 60.5 feet from home plate, and t=1 at 0 feet from home plate. So t might be computed as simply as
I drew the whole curve first as a GL_LINE_STRIP, and then I computed the coordinates for the ball at each frame. When I ran my program, the ball exactly followed the curving line trajectory. Thanks to all who gave answers and made comments.
我采用了公式,对其进行了更正,并在 github 上创建了一个测试应用程序,网址为 git://github.com/rmd6502/BezierLicious.git 。我强烈建议不要在生产应用程序中使用我在那里所做的任何事情 - 仅考虑将其用于研究目的!
I took the formula, corrected it, and created a test app on github at git://github.com/rmd6502/BezierLicious.git . I strongly recommend against using anything I did there in a production app - consider it for research purposes only!!
您应该看看De Casteljau 算法。它允许您递归地细化曲线。只需在几步后中止并使用生成的顶点即可。您还可以直接沿着参数化位置评估控制点并使用它们。直接评估 Bézier-Splines 并不难(例如,您可以在顶点着色器中执行此操作!)De Casteljau 算法的优点是您永远不必计算(高)幂,尽管对于您的情况来说,两者都应该没问题(并且直接评估肯定更容易实现/测试.)
You should take a look at De Casteljau's algorithm. It allows you to recursively refine your curve. Just abort after a few steps and use the resulting vertices. You could also evaluate the control points directly along the parametric position and use those. It's not that hard to evaluate Bézier-Splines directly (you could do it in the vertex shader for instance!) The advantage of De Casteljau's algorithm is that you never have to compute (high) powers, though for your case both should be fine (and the direct evaluation is definitely easier to implement/test.)