C ++ / openGL:使用四元数将QUAD旋转到一个点

Posted

技术标签:

【中文标题】C ++ / openGL:使用四元数将QUAD旋转到一个点【英文标题】:C++ / openGL: Rotating a QUAD toward a point using quaternions 【发布时间】:2011-03-13 08:26:53 【问题描述】:

当我在某个位置有一个 QUAD 时,如何旋转它以使其法线指向给定点?想象一下彩色块只是矩形四边形,那么这张图片就有点我的意思了。四边形都以指向球体中心的方式定向。

alt text http://emrahgunduz.com/wp-content/uploads/2009/01/material_id_gui-600x364.jpg

也许这第二张图片显示了我正在尝试做的更多事情: alt text http://img689.imageshack.us/img689/3130/screenshot20100708at555.png

我正在使用 openGL / C++(和 Eigen 库)。我有这个代码来绘制一个简单的四边形:

#include "ofMain.h"
#include "Quad.h"
Quad::Quad(Vector3f oPosition):position(oPosition) 


void Quad::update() 


void Quad::draw() 
    float size = 1.3;
    glColor3f(1.0f, 0.0f, 0.6f);
    glPushMatrix();
        glTranslatef(position.x(), position.y(), position.z());
        glScalef(size, size,size);
        glBegin(GL_QUADS);
            glVertex3f(0,0,0);
            glVertex3f(1,0,0);
            glVertex3f(1,1,0);
            glVertex3f(0,1,0);
        glEnd();
    glPopMatrix();

17-07 更新 亲爱的读者,

刚刚通过旋转四边形获得了一些进一步的信息。我随机放置了几个四边形,然后使用以下回复中的描述使用此代码将它们旋转到look_atvector3f:

void Quad::draw() 
    float size = 0.5;
    glColor3f(1.0f, 0.0f, 0.6f);
    glPushMatrix();
        Vector3f center = look_at - position;
        Vector3f center_norm = center.normalized();
        float r_angle   = acos(center_norm.dot(normal));
        Vector3f axis = normal.normalized().cross(center_norm);

        glPointSize(8);
        glLineWidth(4.0f);

        // draw the center point
        glColor3f(1.0f, 0.0f, 0.0f);
        glBegin(GL_POINTS); 
            glVertex3fv(look_at.data());
        glEnd();

        // draw the quad
        glColor4f(0.0f, 0.0f, 0.0f, 0.85f); 
        glTranslatef(position.x(), position.y(), position.z());
        glRotatef(r_angle * RAD_TO_DEG, axis.x(), axis.y(), axis.z());
        glScalef(size, size,size);
        glBegin(GL_QUADS);
            glVertex3f(-0.5,-0.5,0);
            glVertex3f(0.5,-0.5,0);
            glVertex3f(0.5,0.5,0);
            glVertex3f(-0.5,0.5,0);
        glEnd();

    glPopMatrix();

结果如下所示:

正如你所见,我快到了,尽管四边形的旋转仍然有点“奇怪”。我看到下面带有彩色四边形的图像,您可以清楚地看到旋转的差异。如何旋转四边形以得到与下面的彩色球体相同的结果?

【问题讨论】:

+1:因为我喜欢 3D 图片 :) 这些图片链接都失效了。 【参考方案1】:

旋转轴 = normalize(crossproduct(currentNormal, desiredNormal))

旋转角度 = acos(dotproduct(normalize(currentNormal), normalize(desiredNormal)).

您可以从轴和角度构建旋转矩阵或四元数。可以在任何有关四元数的资源中找到确切的公式。

您可能需要翻转角度或轴,具体取决于您是围绕其底部还是围绕其尖端正常旋转。

另外,THIS 资源似乎有足够的关于四元数、旋转和一般 3d 空间的信息。

【讨论】:

对于四边形 abcd 法线可以使用叉积 = normalize(cross(c-a, d-b)) 或 normalize(Crossproduct(b-a, c-a)) 找到。来自 quad 的任何两个非平行向量都可以用来做垂直。在您的示例中,法线是 (0, 0, 1) 或 (0, 0, -1)。 (取决于四边形是否使用相同的绕组顺序,单面或双面等)。 @pollux:如果我有一个黑板,几分钟的时间并且你在房间里,我可以解释一切。在纯文本中它有点困难。现在你得到了你的行为,因为你尝试只使用一次旋转来对齐四边形。这是可能的,但使用两次旋转要容易得多 - 首先旋转四边形,使其法线平行(或相反,取决于您想要什么)与指向球体中心的矢量。如果我正确理解了您的屏幕截图,那么您已经这样做了。其次,围绕法线旋转四边形,使其“向上”矢量正确对齐。 @pollux:第 2 步:在四边形中,您需要找到“局部向上”向量。 IE。从四边形的中心指向四边形的“顶部”的方向。你需要一个“全局向上”向量,它指向世界。要为四边形找到“正确”,您需要制作两个叉积 - 第一个“vec3 side = normalize(cross(global_up, direction_to_center))” - 这将获得指向“侧面”的向量。然后你可以得到“proper_up = normalize(cross(direction_to_center, side))”。这将为您提供四边形所需的“向上”向量。现在您可以计算旋转角度 (acos(dot(local_up, proper_up)),并使用 ... @pollux:问题可以通过不同的方式解决。在这种情况下,quad 的位置/旋转可以是偏航、俯仰和距离。 IE。两个旋转角度和距球心的距离。您可以只制作一个四边形,然后使用一个 glTranslate 和两个 glRotate 调用来绘制它。距离可以计算为长度(quad_center-sphere_center)。 pitch - acos(dot3(global_up, normalize(quad_center - sphere_center))) 等。不难。 @pollux:无论如何,如果您遇到困难,我建议您购买三角学书籍,将所有内容都画在纸上,然后看看您将如何自己旋转四边形,以及如何计算旋转。或者你可能会向某种几何老师/导师寻求帮助。我有点直观地使用和理解这样的3d东西,但我不是老师,我不擅长在没有笔/纸或黑板的情况下远程解释它。我可能无法进一步帮助您。【参考方案2】:

您可能已经找到了这个 - http://gpwiki.org/index.php/OpenGL:Tutorials:Using_Quaternions_to_represent_rotation - 但我在上次研究这个主题时发现它很有用。

【讨论】:

【参考方案3】:

如果“在某个位置”意味着你知道你目前的正常情况,那么事情就是这样:

    新旧法线的点积是它们之间夹角的余弦值。 它们的叉积是一个轴,您应该围绕该轴执行所需的旋转 根据给定的轴和角度构造旋转四元数已得到很好的证明和基本特征。 旋转四边形本身很棘手,具体取决于您希望它的旋转方式。

【讨论】:

以上是关于C ++ / openGL:使用四元数将QUAD旋转到一个点的主要内容,如果未能解决你的问题,请参考以下文章

从四元数到 OpenGL 旋转

c++ 四元数澄清

四元数旋转导致场景伸展

3D图形:矩阵、欧拉角、四元数与方位的故事

四元数(转自知乎)

四元数到达万向节锁