2016-05-05 79 views
1

我想在opengl中渲染3d激光束。我有兩個點(p1,p2)和一個由p1和p2之間的距離縮放的三面圓柱體。問題是我無法讓氣缸正確旋轉。我嘗試過使用atan2來計算三軸角度並將它們應用到矩陣中,到目前爲止沒有成功。圓柱體根本沒有遵循這些點。這就是我如何完成旋轉計算:Opengl 3d激光束

p3 = p2 - p1 
rotX = atan2(p3.y, p3.z) 
rotY = atan2(p3.x, p3.z) 
rotZ = atan2(p3.x, p3.y) 

matrix.rotate(rotX, rotY, rotZ) 
+1

使用四元數並將其轉換爲旋轉矩陣 –

+0

@willywonka_dailyblah:這沒有幫助。問題是角度的選擇。使用四元數是獲得相同答案的另一種技術。 –

回答

1

這是線性代數稍微長一點的情況之一。你根本不需要三角函數。三角函數全是關於角度的,你正在做的是將直角座標轉換成角度,然後再轉換成直角座標。這兩次轉換是不必要的。

我們來定義v = p2-p1。假設你的圓柱沿Z軸從(0,0,0)到(0,0,1)。我們正努力創造一個矩陣A爲我們提供瞭如下改造:

A * (0, 0, 1) = v 

那麼,一旦你寫出來這樣的,它看起來非常簡單,不是嗎!因爲通過基向量右乘矩陣給我們一個列向量。所以v必須是矩陣的其中一列。

A = [ ? ? v.x ] 
    [ ? ? v.y ] 
    [ ? ? v.z ] 

現在我們只選擇那些被歸一化和正交至v另外兩個列向量,所以我們保持激光器的橫截面形狀。這很簡單。下面是一些代碼,因爲它將用GLSL編寫(你可以在C++中使用glm或在JavaScript中使用gl-matrix來獲得類似的語法)。

mat3 create_laser_matrix(vec3 v) { 
    // Find a vector, ref, not parallel to v 
    vec3 vmag = abs(v); 
    vec3 ref; 
    if (vmag.x <= vmag.y && vmag.x <= vmag.z) { 
     ref = vec3(1.0, 0.0, 0.0); 
    } else if (vmag.y <= vmag.z) { 
     ref = vec3(0.0, 1.0, 0.0); 
    } else { 
     ref = vec3(0.0, 0.0, 1.0); 
    } 
    // Use ref to create two unit vectors, u1, u2, so {v, u1, u2} are orthogonal 
    vec3 utemp = cross(v, ref); 
    vec3 u1 = normalize(cross(v, utemp)); 
    vec3 u2 = normalize(cross(v, u1)); 
    return mat3(u1, u2, v); 
} 

爲了擴大對數學:三角允許我們的角度和直角座標和反之亦然之間進行轉換,但事實證明,我們並不需要這樣做的。一個「旋轉矩陣」只是一種正交矩陣(一個具有行列式1而不是-1),正交矩陣就是列向量正交的矩陣,這就意味着任意兩列的點積向量是零。沒有三角法需要。我們並不完全在正交矩陣之後,因爲我們需要「伸出」激光來連接兩個點,但大部分相同的數學運算也適用。