沿路径的OpenGL管

时间:2011-02-23 07:52:49

标签: c opengl

所以我正在玩OpenGL并试图弄清楚如何绘制一些有趣的形状。

现在,我正在做一个管子。我可以直接用直管绘制:

void tube(GLfloat radius, GLfloat segment_length) {
    glPolygonMode(GL_BACK, GL_NONE);
    glPolygonMode(GL_FRONT, GL_FILL);

    glPushMatrix(); {
        GLfloat z1 = 0.0;
        GLfloat z2 = segment_length;

        GLfloat y_offset = 0.0;
        GLfloat y_change = 0.00;

        int i = 0;
        int j = 0;
        for (j = 0; j < 20; j++) {
            glPushMatrix(); {
                glBegin(GL_TRIANGLE_STRIP); {
                    for (i = 360; i >= 0; i--) {
                        GLfloat theta = i * pi/180;
                        GLfloat x = radius * cos(theta);
                        GLfloat y = radius * sin(theta) + y_offset;

                        glVertex3f(x, y, z1);
                        glVertex3f(x, y, z2);
                    }
                } glEnd();
            } glPopMatrix();

            // attach the front of the next segment to the back of the previous
            z1 = z2;
            z2 += segment_length;

            // make some other adjustments
            y_offset += y_change;
        }
    } glPopMatrix();
}

但是,我还没弄清楚如何使管子遵循任何预定义的路径,如螺旋线,甚至是简单的线。如果将y_change更改为0.01,则会在y方向上将每个管段偏移另外0.01。那太棒了,但我怎样才能让每个细分都指向那个方向呢?换句话说,现在,绘制每个线段使它们都面向相同的方向,方向不是管的方向(因为y_change = 0.01,方向略微“向上”)。

我不知道该怎么办。我通过获取前一段和当前段之间的向量来玩向量,但我不确定过去该怎么做。

4 个答案:

答案 0 :(得分:19)

这个想法被称为路径控制挤压,即你有一个基本的n维形状,并沿着n + 1维曲线挤出它。我可以看到你的脸:“嗯,他说的是什么?”

所以这是一个粗略的轮廓。首先,您需要一个将值(通常称为t)映射到空间中连续,平滑曲线的函数。例如螺丝:

path(t): R → R³, t ↦ ( a·sin(k·t), b·cos(k·t), c·t )

想法是找到一个局部坐标基础来定义与该路径相关的顶点位置 - 有意义的是,其中一个坐标与路径平行对齐,因此您希望找到它的切线。这是通过找到它的梯度来完成的:

tangent(t): R → R³, t ↦ ( k·a·cos(k·t), -k·b·sin(k·t), c ) = d/dt path(t)

因此,这是指向曲线的局部基矢量,局部坐标系的原点位于曲线的t点。

但我们需要另外两个向量,以形成一个完整的3d基础。将第二个基点垂直于曲率通常是一个不错的选择,通过找到切线的卷曲可以得到:

normal(t): R → R³, t ↦ ( -k²·a·sin(k·t), -k²·b·cos(k·t), 0 ) = d/dt tangent(t) = d²/dt² path(t)

这称为正常。

可以获得第三个基本向量,取正态和正切的交叉乘积,得到二次正规。我会让你把这个想象成一个练习。

现在要沿着曲线挤出一个形状,你只需要在选择的范围内迭代t,就可以将路径分割成段,从而为你提供本地原点。挤压形状的点相对于此原点路径(t)。假设你的形状由x-y平面中的点P_n组成:

for t in [k..l]:
    for p in P_n:
        yield_vertex( path(t).x + binormal(t).x * p.x, 
                      path(t).y + normal(t).y * p.y, 
                      path(t).z )

我会把它留给你,弄清楚如何使它适应OpenGL,毕竟你应该通过思考来学习一些东西。如果明天之前你无法解决问题,我很乐意为你提供解决方案,但通常你自己解决这些问题会更有趣。

答案 1 :(得分:1)

将其减少到previously-solved problem

答案 2 :(得分:1)

答案 3 :(得分:0)

物理 解释对您的挤压问题很好(从代数矢量的角度来看):

https://cobalt.rocky.edu/~ulrich.hoensch/FS_2016/MAT275/Lecture%20Notes/Lecture%2013_5%20The%20Binormal%20Vector%20and%20Torsion.pdf

https://physics.stackexchange.com/questions/368634/direction-of-velocity-vector-in-3d-space

https://math.libretexts.org/Bookshelves/Calculus/Map%3A_University_Calculus_(Hass_et_al)/12%3A_Vector-Valued_Functions_and_Motion_in_Space/12.5%3A_Tangential_and_Normal_Components_of_Acceleration

https://web.mit.edu/hyperbook/Patrikalakis-Maekawa-Cho/node24.html

其实可以看出:

1)path(t) 是 r(alpha(t)) 其中 alpha(t)=kt with k=2PI/w r(t) - 具有 3d(欧几里德空间)坐标的位置向量:x(t),y(t),z(t) alpha - 中心角度 w - 标量角速度 = 2PI/k = (r x v)/||r^2||这里 x 是向量积

  1. tangent(t) 是 v(t) 切向速度 = dr / dt(梯度)

  2. normal(t) 是 a(t) 法向加速度 = dv/dt

  3. binormal(b) 是向量乘积 b(t) = a(t) x v (t) 的结果

副法线(b)、法线(a) 和切线(v) 向量定义了沿空间曲线(r) 的坐标正交局部系统——参见图2.6来自 node24.html 文章。

所以,如果已经记住了 b(= axv)、n(= a = dv/dt) 和 v(= dr/dt) 的计算局部值,我可以使用从 BNV 系统到 XYZ 的一种转换(从一个坐标系转换为其他;两者都是正交系统)以获得 x,y,z 坐标; 综上所述,XYZ 中的任意点(x,y,z) 都将被写成其在 BNV 系统中的投影点的线性组合。

在物理学中参见运动方程:https://en.wikipedia.org/wiki/Equations_of_motion

您可以在此数学文档(幻灯片 3 和 5)中看到这一点: https://www.robots.ox.ac.uk/~sjrob/Teaching/Vectors/

备注

-不要忘记一些 n 可导函数可以分解为函数的线性组合,如 sin 和 cos(参见傅立叶https://en.wikipedia.org/wiki/Fourier_series

-In plus 不要忘记这个组合函数(需要区分时有用的规则):http://mathsfirst.massey.ac.nz/Calculus/ChainRule/decompose.html#vma

结论

-如果找到一个 3D - 参数函数(=算法)用于一个 3d 体(= 3d 模型 = 3d 对象)然后可以在 3d 空间中绘制它;

-参数化不是绘制 3D 物体(3D 对象)的单一方法... 例如可以使用二维函数的旋转来获得它!

或者,查看另一种方法而不是参数化来获得 3D 物体:管(沿路径挤压)图像作为 http://www.songho.ca/opengl/gl_cylinder.html 中两个棱镜的交集结果 并将 P'(投影点 P 到两个棱镜的相交平面)计算为从 P(从初始面/轮廓的点)到 https://www.cs.princeton.edu/courses/archive/fall00/cs426/lectures/raycast/sld017.htm

(这种挤压方法的输入是一组profie=初始面和路径的点,可以改进以获得平滑的路径或轮廓:https://en.wikipedia.org/wiki/Centripetal_Catmull%E2%80%93Rom_spline

https://jiharu.github.io/intm3d/week03.html,

https://www.ee.ucl.ac.uk/~mflanaga/java/Interpolation.html

或者,参见另一个更平滑的 Kockanek-Bartel(KB),名为 Tension-Continuity-Bias-spline(别名 TCB): https://download.java.net/media/java3d/javadoc/1.5.0/com/sun/j3d/utils/behaviors/interpolators/package-summary.html)

-但不要忘记,使用这些方法可以获得的只是一团近似 3D 曲线的点(不是整个 3d 模型)。

如果知道面的点云、边云和法线,则一个模型是完全定义的(参见基于 https://doc.cgal.org/latest/Poisson_surface_reconstruction_3/index.html 点云的泊松重建)。

请注意algebra vector3D(或3D-vectorial algebra)的力量!!!