需要用于opengl 3D变换的旋转矩阵

时间:2013-12-15 23:57:14

标签: c++ opengl graphics 3d transformation

问题是我在3D空间中有两个点,其中y +是向上的,x +是向右的,而z +是朝向你的。我想在它们之间定位一个圆柱体,它是两个点之间距离的长度,因此它的两个中心端都接触这两个点。我将气缸转换到两点中心的位置,我需要帮助提出一个旋转矩阵应用于气缸,以便它以正确的方式定向。我对整个事物的转换矩阵如下所示:

平移(中心点)* rotateX(某些X度)* rotateZ(某些Z度)

最后应用翻译,这样我才能在翻译之前将其转换到正确的方向。

这是我到目前为止所做的:

mat4 getTransformation(vec3 point, vec3 parent)
{
    float deltaX = point.x - parent.x;
    float deltaY = point.y - parent.y;
    float deltaZ = point.z - parent.z;

    float yRotation = atan2f(deltaZ, deltaX) * (180.0 / M_PI);
    float xRotation = atan2f(deltaZ, deltaY) * (180.0 / M_PI);
    float zRotation = atan2f(deltaX, deltaY) * (-180.0 / M_PI);
    if(point.y < parent.y)
    {
        zRotation = atan2f(deltaX, deltaY) * (180.0 / M_PI);
    }

    vec3 center = vec3((point.x + parent.x)/2.0, (point.y + parent.y)/2.0, (point.z + parent.z)/2.0);
    mat4 translation = Translate(center);
    return translation * RotateX(xRotation) * RotateZ(zRotation) * Scale(radius, 1, radius) * Scale(0.1, 0.1, 0.1);
}

我尝试了下面给出的解决方案,但它似乎根本不起作用

mat4 getTransformation(vec3 parent, vec3 point)
{
    // moves base of cylinder to origin and gives it unit scaling
    mat4 scaleFactor = Translate(0, 0.5, 0) * Scale(radius/2.0, 1/2.0, radius/2.0) * cylinderModel;

    float length = sqrtf(pow((point.x - parent.x), 2) + pow((point.y - parent.y), 2) + pow((point.z - parent.z), 2));
    vec3 direction = normalize(point - parent);
    float pitch = acos(direction.y);
    float yaw = atan2(direction.z, direction.x);

    return Translate(parent) * Scale(length, length, length) * RotateX(pitch) * RotateY(yaw) * scaleFactor;
}

运行上面的代码后,我得到了这个: enter image description here

每个黑点都是一个点,其父级是产生它的点(前面的那个)我希望分支适合点。基本上我正在尝试为随机树生成实现空间定殖算法。我得到了大部分,但我想将树枝映射到它,所以看起来不错。我可以使用GL_LINES来建立一个通用的连接,但如果我得到这个工作,它看起来会更漂亮。该算法解释为here

这是我想要做的事情的图像(原谅我的绘画技巧)

3 个答案:

答案 0 :(得分:2)

嗯,有任意数量的旋转矩阵满足你的约束。但任何人都会这样做。我们不是试图找出特定的旋转,而是直接写下矩阵。假设您的圆柱体在未应用变换时,其轴线沿Z轴。因此,您必须将局部空间Z轴转换为这两个点之间的方向。即z_t = normalize(p_1 - p_2),其中normalize(a) = a / length(a)

现在我们只需要使它成为一个完整的三维坐标基础。我们从一个与z_t不平行的任意向量开始。比如,(1,0,0)或(0,1,0)或(0,0,1)之一;使用带有z_t的标量积·(也称为内积或点积)并使用绝对值最小的向量,让我们调用此向量u。 在伪代码中:

# Start with (1,0,0)
mindotabs = abs( z_t · (1,0,0) )
minvec = (1,0,0)
for u_ in (0,1,0), (0,0,1):
    dotabs = z_t · u_
    if dotabs < mindotabs:
        mindotabs = dotabs
        minvec = u_

u = minvec_

然后正交化该矢量产生局部y变换y_t = normalize(u - z_t · u)

最后通过交叉乘积x_t = z_t × y_t

创建x转换

要将圆柱体移动到位,请将其与匹配的平移矩阵组合。

转换矩阵实际上只是你从“来自”空间的轴,就像从另一个空间看到的那样。因此,得到的矩阵,即您正在寻找的旋转矩阵,只是矢量x_t,y_t和z_t并排作为矩阵。 OpenGL使用所谓的均匀矩阵,因此您必须使用0,0,0,1最底行和最右列将其填充为4×4形式。

你可以加载到OpenGL;如果使用固定功能使用glMultMatrix来应用旋转,或者如果使用着色器乘以矩阵,则最终会传递给glUniform。

答案 1 :(得分:0)

从一个单位长度的圆柱开始,它的一端(我称之为C1)位于原点(注意你的图像表明你的圆柱体的原点是 center ,但你可以轻松地将其转换为我的开头)。我称之为C2的另一端是(0,1,0)

我想在世界坐标P1P2中拨打您的两个点,我们希望在C1P1上找到C2到{ {1}}。

首先将P2翻译成圆柱,然后成功找到P1C1

然后按P1缩放柱面,因为它最初的长度为distance(P1, P2)

可以使用球面坐标计算剩余旋转。如果您不熟悉这种类型的坐标系:它就像GPS坐标:两个角度;一个围绕极轴(在你的情况下是世界的Y轴),我们通常称之为偏航,另一个是 pitch 角度(在你的情况下是X轴in模型空间)。可以通过将1(即P2-P1相对于P2的局部偏移)转换为球面坐标来计算这两个角度。首先以俯仰角围绕X旋转物体,然后绕Y偏航。

这样的事情会做到这一点(伪代码):

P1

答案 2 :(得分:0)

调用圆柱轴 A 。第二次旋转(约 X )无法改变 A X 之间的角度,因此我们必须使用< em>第一次轮换(约 Z )。

调用目标矢量(两点之间的矢量) B 。拿-acos(B X / B Y ),这就是第一次旋转的角度。

再次 B ,忽略 X 组件,并查看其在(Y,Z)平面中的投影。取acos(B Z / B Y ),这就是第二次旋转的角度。