2014-07-11 104 views
1

這應該很容易,但我一直試圖找到一個簡單的解釋,我可以把握。我有一個對象,我想在OpenGL中表示爲一個圓錐體。該物體具有x,y,z座標和速度矢量vx,vy和vz。錐應指向速度矢量的方向。OpenGL從速度矢量旋轉

所以,我覺得我的PyOpenGL代碼應該是這個樣子:

glPushMatrix() 
glTranslate(x, y, z) 
glPushMatrix() 

# do some sort of rotation here # 

glutSolidCone(base, height, slices, stacks) 
glPopMatrix() 
glPopMatrix() 

那麼,是正確的(迄今爲止)?我用什麼來代替「#在這裏做某種旋轉#」?

在我的世界裏,Z軸指向(0,0,1),沒有任何旋轉,我的錐體也是如此。


好吧,雷託Koradi的答案似乎是,我應該採取的辦法,但我不知道的一些實施細則和我的代碼是行不通的。

如果我理解正確,旋轉矩陣應該是4x4。 Reto向我展示瞭如何獲得3x3,所以我假定3x3應該是4x4單位矩陣的左上角。這裏是我的代碼:

import numpy as np 

def normalize(v): 
    norm = np.linalg.norm(v) 
    if norm > 1.0e-8: # arbitrarily small 
     return v/norm 
    else: 
     return v 

def transform(v): 
    bz = normalize(v) 
    if (abs(v[2]) < abs(v[0])) and (abs(v[2]) < abs(v[1])): 
     by = normalize(np.array([v[1], -v[0], 0])) 
    else: 
     by = normalize(np.array([v[2], 0, -v[0]])) 
     #~ by = normalize(np.array([0, v[2], -v[1]])) 

    bx = np.cross(by, bz) 
    R = np.array([[bx[0], by[0], bz[0], 0], 
        [bx[1], by[1], bz[1], 0], 
        [bx[2], by[2], bz[2], 0], 
        [0,  0,  0,  1]], dtype=np.float32) 

    return R 

,這裏是它被插入渲染代碼的方式:

glPushMatrix() 
glTranslate(x, y, z) 
glPushMatrix() 

v = np.array([vx, vy, vz]) 
glMultMatrixf(transform(v)) 

glutSolidCone(base, height, slices, stacks) 
glPopMatrix() 
glPopMatrix() 

不幸的是,這是行不通的。我的測試案例錐體只是沒有正確指出,我無法識別失敗模式。如果沒有「glutMultMatrixf(變換(V)」行,錐沿z軸對齊,符合市場預期。


它的工作。雷託Koradi正確地確定了需要旋轉矩陣,以便匹配移調。的OpenGL列順序的代碼應該是這樣的(優化前):

def transform(v): 
    bz = normalize(v) 
    if (abs(v[2]) < abs(v[0])) and (abs(v[2]) < abs(v[1])): 
     by = normalize(np.array([v[1], -v[0], 0])) 
    else: 
     by = normalize(np.array([v[2], 0, -v[0]])) 
     #~ by = normalize(np.array([0, v[2], -v[1]])) 

    bx = np.cross(by, bz) 
    R = np.array([[bx[0], by[0], bz[0], 0], 
        [bx[1], by[1], bz[1], 0], 
        [bx[2], by[2], bz[2], 0], 
        [0,  0,  0,  1]], dtype=np.float32) 

    return R.T 

回答

0

一個有用的概念,這裏要記住的是,線性變換也可以被解釋爲座標系的變化。換句話說,而不是描繪點在座標系統內轉換,你可以很好地描繪點的位置,但它們的位置座標以新的座標系表示。當查看錶達變換的矩陣時,這個新座標系的基向量是矩陣的列向量。

在下面,新座標系的基矢量被命名爲bx,bybz。由於旋轉矩陣的列需要是正交的,所以bx,bybz需要形成正交的向量集合。

在這種情況下,原始錐體沿着z軸取向。由於您希望錐體沿着(vx, vy, vz)取向,所以我們使用此矢量作爲新座標系的z軸。因爲我們希望有一個標準正交座標系中,唯一剩下要做獲得bz是歸這個載體:

   [vx] 
bz = normalize([vy]) 
       [vz] 

由於錐體是旋轉對稱的,它並沒有真正無論怎麼剩餘的兩個基向量被選擇,只要它們都與bz正交,並且彼此正交。找到給定矢量的任意正交矢量的簡單方法是保持一個座標0,交換其他兩個座標,並更改這兩個座標之一的符號。同樣,矢量需要進行歸一化。我們可以用這種方法選擇的載體包括:

   [ vy]     [ vz]     [ 0 ] 
by = normalize([-vx]) by = normalize([ 0 ]) by = normalize([ vz]) 
       [ 0 ]     [-vx]     [-vy] 

每個向量與(vx, vy, vz)的點積爲零,這意味着向量是正交的。

雖然這些(或其他變體)之間的選擇大多是任意的,但必須注意不要以退化矢量結束。例如,如果vxvy都爲零,則使用這些向量中的第一個將是不好的。爲避免選擇(近)簡併向量,一個簡單的策略是使用這三個向量中的第一個,如果vz小於vxvy,並且另外兩個之一。

有了兩個新的基矢量,第三是其它兩個的叉積:

bx = by x bz 

所有剩下的是填充具有列向量bxbybz旋轉矩陣,並且旋轉矩陣已完成:

[ bx.x by.x bz.x ] 
R = [ bx.y by.y bz.y ] 
    [ bx.z by.z bz.z ] 

如果您需要4x4矩陣,例如因爲你使用的是傳統的固定功能的OpenGL管道,您可以將此擴展到4x4矩陣:

[ bx.x by.x bz.x 0 ] 
R = [ bx.y by.y bz.y 0 ] 
    [ bx.z by.z bz.z 0 ] 
    [ 0 0 0 1 ] 
+0

不旋轉矩陣需要一個4x4矩陣(我假設我應該使用glMultMatrixf呼叫)?速度矢量爲[0,0,0]時的情況如何?我需要特殊情況下的那種情況嗎? – user2483736

+0

是的,如果您使用的是固定管道,則必須將其擴展到4x4。如果您使用着色器(在Core Profile中需要),則可以將3x3矩陣傳遞到着色器中。 –

+0

您在上面添加的代碼看起來很合理。根據OpenGL綁定處理矩陣的方式,您可能需要按轉置順序編寫元素。至少在本地接口中,OpenGL期望矩陣按列主要順序傳入。爲了調試,我將從非常簡單的案例開始,並查看結果矩陣中的值。例如。用一個指向'z'方向的矢量,你應該能夠通過查看矩陣來判斷它是否正確。 –