繁体   English   中英

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

[英]Need rotation matrix for opengl 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;
}

运行上面的代码后,我得到了这个: 在此输入图像描述

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

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

嗯,有任意数量的旋转矩阵满足您的约束。 但任何人都会这样做。 我们不是试图找出特定的旋转,而是直接写下矩阵。 假设您的圆柱体在未应用变换时,其轴线沿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。

用具有其两端,我称之为一个单位长度的圆筒开始C1 ,在原点(请注意,您的图片表明了你的汽缸都有它的起源中心 ,但你可以很容易地变换一下我开头)。 另一端,我称之为C2 ,然后是(0,1,0)

我想打电话给你的两个点在世界坐标P1P2 ,我们要找到C1上的P1C2P2

首先将圆柱体转换为P1 ,然后将C1成功定位到P1

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

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

像这样的东西会这样做(伪代码):

Matrix getTransformation(Point P1, Point P2) {
    float length = distance(P1, P2);
    Point direction = normalize(P2 - P1);
    float pitch = acos(direction.y);
    float yaw = atan2(direction.z, direction.x);

    return translate(P1) * scaleY(length) * rotateX(pitch) * rotateY(yaw);
}

调用气缸A的轴。 第二次旋转(大约X )不能改变AX之间的角度,所以我们必须在第一次旋转(大约Z )时获得该角度。

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM