贝塞尔曲线的 OpenGL 坐标

发布于 2024-10-27 01:05:30 字数 996 浏览 0 评论 0原文

基本上,我需要获取从 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

空名 2024-11-03 01:05:30

贝塞尔曲线很容易计算。首先是可分离的,这意味着您可以一次计算一个坐标(首先是 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(该点位于曲线的终点)。

Evaluation of a Beziercube for t=0.35

上图的交互式版本,您可以在其中拖动 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:

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;
}

Note that in the above function the parameter t is not the arc-length parameter for the curve but a generic parameter that goes from t=0 (where the point is at the beginning of the curve) to t=1 (where the point is at the end of the curve).

Evaluation of a Bezier cubic for t=0.35

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).

陌路黄昏 2024-11-03 01:05:30

我认为 bezier() 中的以下行应为

double 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;
}

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.

~/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

Test program 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;
}
和我恋爱吧 2024-11-03 01:05:30

如果有人感兴趣,这就是我最终如何使用贝塞尔曲线绘制的轨迹在场景中实现棒球球的投球。我使用 6502 非常有启发性的函数来计算球在每一帧的 xyz 坐标。起始值是绘制框架时球位于曲线上的任何位置。绘制整条曲线的结束值和控制点完全相同。我花了一段时间才弄清楚给参数 t 提供什么参数。

我最终发现它是从0(曲线的起点)到1(曲线的终点)的值。因此,从投手丘投出的棒球在距本垒 60.5 英尺处为 t=0,在距本垒 0 英尺处为 t=1。因此 t 的计算方式可能就像

t += 1.0 / 60.5;

我首先将整个曲线绘制为 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

t += 1.0 / 60.5;

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.

许仙没带伞 2024-11-03 01:05:30

我采用了公式,对其进行了更正,并在 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!!

回忆那么伤 2024-11-03 01:05:30

您应该看看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.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文