简体   繁体   English

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

[英]Need rotation matrix for opengl 3D transformation

The problem is I have two points in 3D space where y+ is up, x+ is to the right, and z+ is towards you. 问题是我在3D空间中有两个点,其中y +是向上的,x +是向右的,而z +是朝向你的。 I want to orientate a cylinder between them that is the length of of the distance between both points, so that both its center ends touch the two points. 我想在它们之间定位一个圆柱体,它是两个点之间距离的长度,因此它的两个中心端都接触这两个点。 I got the cylinder to translate to the location at the center of the two points, and I need help coming up with a rotation matrix to apply to the cylinder, so that it is orientated the correct way. 我将气缸转换到两点中心的位置,我需要帮助提出一个旋转矩阵应用于气缸,以便它以正确的方式定向。 My transformation matrix for the entire thing looks like this: 我对整个事物的转换矩阵如下所示:

translate(center point) * rotateX(some X degrees) * rotateZ(some Z degrees) 平移(中心点)* rotateX(有些X度)* rotateZ(有些Z度)

The translation is applied last, that way I can get it to the correct orientation before I translate it. 翻译最后应用,这样我可以在翻译之前将其转换为正确的方向。

Here is what I have so far for this: 以下是我迄今为止所做的事情:

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

I tried a solution given down below, but it did not seem to work at all 我尝试了下面给出的解决方案,但它似乎根本不起作用

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

After running the above code I get this: 运行上面的代码后,我得到了这个: 在此输入图像描述

Every black point is a point with its parent being the point that spawned it (the one before it) I want the branches to fit into the points. 每个黑点都是一个点,其父级是产生它的点(前面的那个)我希望分支适合点。 Basically I am trying to implement the space colonization algorithm for random tree generation. 基本上我正在尝试为随机树生成实现空间定殖算法。 I got most of it, but I want to map the branches to it so it looks good. 我得到了大部分,但我想将树枝映射到它,所以看起来不错。 I can use GL_LINES just to make a generic connection, but if I get this working it will look so much prettier. 我可以使用GL_LINES来建立一个通用的连接,但如果我得到这个工作,它看起来会更漂亮。 The algorithm is explained here . 这里解释算法。

Here is an image of what I am trying to do (pardon my paint skills) 这是我想要做的事情的图像(原谅我的绘画技巧)

Well, there's an arbitrary number of rotation matrices satisfying your constraints. 嗯,有任意数量的旋转矩阵满足您的约束。 But any will do. 但任何人都会这样做。 Instead of trying to figure out a specific rotation, we're just going to write down the matrix directly. 我们不是试图找出特定的旋转,而是直接写下矩阵。 Say your cylinder, when no transformation is applied, has its axis along the Z axis. 假设您的圆柱体在未应用变换时,其轴线沿Z轴。 So you have to transform the local space Z axis toward the direction between those two points. 因此,您必须将局部空间Z轴转换为这两个点之间的方向。 Ie z_t = normalize(p_1 - p_2) , where normalize(a) = a / length(a) . z_t = normalize(p_1 - p_2) ,其中normalize(a) = a / length(a)

Now we just need to make this a full 3 dimensional coordinate base. 现在我们只需要使它成为一个完整的三维坐标基础。 We start with an arbitrary vector that's not parallel to z_t. 我们从一个与z_t不平行的任意向量开始。 Say, one of (1,0,0) or (0,1,0) or (0,0,1); 比如,(1,0,0)或(0,1,0)或(0,0,1)之一; use the scalar product · (also called inner, or dot product) with z_t and use the vector for which the absolute value is the smallest, let's call this vector u . 用标产品· (也称为内部,或内积)与z_t并使用其绝对值最小的向量,我们称之为载体u In pseudocode: 在伪代码中:

# 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_

Then you orthogonalize that vector yielding a local y transformation y_t = normalize(u - z_t · u) . 然后,您正交化该向量,产生局部y变换y_t = normalize(u - z_t · u)

Finally create the x transformation by taking the cross product x_t = z_t × y_t 最后通过乘以叉积x_t = z_t × y_t创建x变换

To move the cylinder into place you combine that with a matching translation matrix. 要将圆柱体移动到位,请将其与匹配的平移矩阵组合。

Transformation matrices are effectively just the axes of the space you're "coming from" written down as if seen from the other space. 转换矩阵实际上只是你从“来自”空间的轴,就像从另一个空间看到的那样。 So the resulting matrix, which is the rotation matrix you're looking for is simply the vectors x_t, y_t and z_t side by side as a matrix. 因此,得到的矩阵,即您正在寻找的旋转矩阵,只是矢量x_t,y_t和z_t并排作为矩阵。 OpenGL uses so called homogenuous matrices, so you have to pad it to a 4×4 form using a 0,0,0,1 bottommost row and rightmost column. OpenGL使用所谓的均匀矩阵,因此您必须使用0,0,0,1最底行和最右列将其填充为4×4形式。

That you can load then into OpenGL; 你可以加载到OpenGL; if using fixed functio using glMultMatrix to apply the rotation, or if using shader to multiply onto the matrix you're eventually pass to glUniform. 如果使用固定功能使用glMultMatrix来应用旋转,或者如果使用着色器乘以矩阵,则最终会传递给glUniform。

Begin with a unit length cylinder which has one of its ends, which I call C1 , at the origin (note that your image indicates that your cylinder has its center at the origin, but you can easily transform that to what I begin with). 用具有其两端,我称之为一个单位长度的圆筒开始C1 ,在原点(请注意,您的图片表明了你的汽缸都有它的起源中心 ,但你可以很容易地变换一下我开头)。 The other end, which I call C2 , is then at (0,1,0) . 另一端,我称之为C2 ,然后是(0,1,0)

I'd like to call your two points in world coordinates P1 and P2 and we want to locate C1 on P1 and C2 to P2 . 我想打电话给你的两个点在世界坐标P1P2 ,我们要找到C1上的P1C2P2

Start with translating the cylinder by P1 , which successfully locates C1 to P1 . 首先将圆柱体转换为P1 ,然后将C1成功定位到P1

Then scale the cylinder by distance(P1, P2) , since it originally had length 1 . 然后按distance(P1, P2)缩放圆柱体,因为它最初的长度为1

The remaining rotation can be computed using spherical coordinates. 可以使用球面坐标计算剩余旋转。 If you're not familiar with this type of coordinate system: it's like GPS coordinates: two angles; 如果您不熟悉这种类型的坐标系:它就像GPS坐标:两个角度; one around the pole axis (in your case the world's Y-axis) which we typically call yaw , the other one is a pitch angle (in your case the X axis in model space). 一个围绕极轴(在你的情况下是世界的Y轴),我们通常称之为偏航 ,另一个是俯仰角(在你的情况下是模型空间中的X轴)。 These two angles can be computed by converting P2-P1 (ie the local offset of P2 with respect to P1 ) into spherical coordinates. 可以通过将P2-P1 (即, P2的局部偏移相对于P1 )转换为球面坐标来计算这两个角度。 First rotate the object with the pitch angle around X, then with yaw around Y. 首先以俯仰角围绕X旋转物体,然后绕Y偏航。

Something like this will do it (pseudo-code): 像这样的东西会这样做(伪代码):

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

Call the axis of the cylinder A . 调用气缸A的轴。 The second rotation (about X ) can't change the angle between A and X , so we have to get that angle right with the first rotation (about Z ). 第二次旋转(大约X )不能改变AX之间的角度,所以我们必须在第一次旋转(大约Z )时获得该角度。

Call the destination vector (the one between the two points) B . 调用目标矢量(两点之间的矢量) B Take -acos(B X /B Y ), and that's the angle of the first rotation. 拿-acos(B X / B Y ),这是第一次旋转的角度。

Take B again, ignore the X component, and look at its projection in the (Y, Z) plane. 再次取B ,忽略X分量,并查看其在(Y,Z)平面中的投影。 Take acos(B Z /B Y ), and that's the angle of the second rotation. 取acos(B Z / B Y ),这就是第二次旋转的角度。

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

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