簡體   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