2009-11-04 67 views
1

我正在進行一個正在進行的項目,我想要對齊鏈條的鏈接,以便它遵循貝塞爾曲線的輪廓。我目前正在執行以下步驟。如何在OpenGL中圍繞本地軸旋轉對象?

  1. 繪製曲線。
  2. 使用顯示列表創建鏈中的一個鏈接。
  3. 使用FOR循環重複調用計算曲線上兩個點之間角度的函數,返回應該旋轉鏈接的角度和軸。
  4. 旋轉角度「a」並翻譯到新的位置,將鏈接放置在新的位置。

編輯:我也應該說,兩個半圓環的中心必須位於貝塞爾曲線上。 另外我知道我用來繪製圓環的方法很乏味,以後我會用TRIANGLE_FAN或QUAD_STRIP以更高效的方式繪製圓環。

雖然乍一看這個邏輯看起來好像會正確地呈現鏈條,但最終的結果並不是我想象的那樣。這是一張關於鏈條的圖片。

gold_chain

,我讀了你翻譯的對象旋轉之前的由來?我只需要調用glTranslate(0,0,0),然後從上面的第4步開始?

我已經包括了迄今爲止所做的相關代碼,我將不勝感激任何建議讓我的代碼正常工作。

/* this function calculates the angle between two vectors oldPoint and new point contain the x,y,z coordinates of the two points,axisOfRot is used to return the x,y,z coordinates of the rotation axis*/ 
double getAxisAngle(pointType oldPoint[], 
pointType newPoint[],pointType axisOfRot[]){ 

float tmpPoint[3]; 

float normA = 0.0,normB = 0.0,AB = 0.0,angle=0.0; 
int i; 

axisOfRot->x= oldPoint->y * newPoint->z - oldPoint->z * newPoint->y; 
axisOfRot->y= oldPoint->z * newPoint->x - oldPoint->x * newPoint->z; 
axisOfRot->z= oldPoint->x * newPoint->y - oldPoint->y * newPoint->x; 


normA=sqrt(oldPoint->x * oldPoint->x + oldPoint->y * oldPoint->y + oldPoint->z * 
oldPoint->z); 
normB=sqrt(newPoint->x * newPoint->x + newPoint->y * newPoint->y + newPoint->z *  
newPoint->z); 

tmpPoint[0] = oldPoint->x * newPoint->x; 
tmpPoint[1] = oldPoint->y * newPoint->y; 
tmpPoint[2] = oldPoint->z * newPoint->z; 

for(i=0;i<=2;i++) 
AB+=tmpPoint[i]; 

AB /= (normA * normB); 


    return angle = (180/PI)*acos(AB); 
} 

/* this function calculates and returns the next point on the curve give the 4 initial points for the curve, t is the tension of the curve */ 
    void bezierInterpolation(float t,pointType cPoints[], 
    pointType newPoint[]){ 

newPoint->x = pow(1 - t, 3) * cPoints[0].x +3 * pow(1 - t , 2) * t * cPoints[1].x + 3 
* pow(1 - t, 1) * pow(t, 2) * cPoints[2].x + pow(t, 3) * cPoints[3].x; 

newPoint->y = pow(1 - t, 3) * cPoints[0].y +3 * pow(1 - t , 2) * t * cPoints[1].y + 3 
* pow(1 - t, 1) * pow(t, 2) * cPoints[2].y + pow(t, 3) * cPoints[3].y; 

newPoint->z = pow(1 - t, 3) * cPoints[0].z +3 * pow(1 - t , 2) * t * cPoints[1].z + 3 
* pow(1 - t, 1) * pow(t, 2) * cPoints[2].z + pow(t, 3) * cPoints[3].z; 

} 

/* the two lists below are used to create a single link in a chain, I realize that creating a half torus using cylinders is a bad idea, I will use GL_STRIP or TRIANGLE_FAN once I get the alignment right 
*/ 
torusList=glGenLists(1); 

glNewList(torusList,GL_COMPILE); 
for (i=0; i<=180; i++) 
{ 
    degInRad = i*DEG2RAD; 
    glPushMatrix(); 
    glTranslatef(cos(degInRad)*radius,sin(degInRad)*radius,0); 
    glRotated(90,1,0,0); 
    gluCylinder(quadric,Diameter/2,Diameter/2,Height/5,10,10); 
    glPopMatrix();  
} 

glEndList(); 

    /*! create a list for the link , 2 half torus and 2 columns */ 

linkList = glGenLists(1); 

glNewList(linkList, GL_COMPILE); 
glPushMatrix(); 
glCallList(torusList); 
glRotatef(90,1,0,0); 
glTranslatef(radius,0,0); 
gluCylinder(quadric, Diameter/2, Diameter/2, Height,10,10); 
glTranslatef(-(radius*2),0,0); 
gluCylinder(quadric, Diameter/2, Diameter/2, Height,10,10); 
glTranslatef(radius,0, Height); 
glRotatef(90,1,0,0); 
glCallList(torusList); 
glPopMatrix(); 
glEndList(); 

最後這裏是鏈

t=0.031; 
bezierInterpolation(t,cPoints,newPoint); 
a=getAxisAngle(oldPoint,newPoint,axisOfRot); 
glTranslatef(newPoint->x,newPoint->y,newPoint->z); 
    glRotatef(a,axisOfRot->x,axisOfRot->y,axisOfRot->z);  
    glCallList(DLid); 
    glRotatef(-a,axisOfRot->x,axisOfRot->y,axisOfRot->z); 
glTranslatef(-newPoint->x,-newPoint->y,-newPoint->z); 

oldPoint[0]=newPoint[0]; 
bezierInterpolation(t+=GAP,cPoints,newPoint); 
a=getAxisAngle(oldPoint,newPoint,axisOfRot); 
glTranslatef(newPoint->x,newPoint->y,newPoint->z); 
    glRotatef(90,0,1,0); 
    glRotatef(a,axisOfRot->x,axisOfRot->y,axisOfRot->z);  
    glCallList(DLid); 
    glRotatef(-a,axisOfRot->x,axisOfRot->y,axisOfRot->z); 
    glRotatef(90,0,1,0); 
glTranslatef(-newPoint->x,-newPoint->y,-newPoint->z); 

oldPoint[0]=newPoint[0]; 
bezierInterpolation(t+=GAP,cPoints,newPoint);  
    a=getAxisAngle(oldPoint,newPoint,axisOfRot); 
    glTranslatef(newPoint->x,newPoint->y,newPoint->z);  
    glRotatef(-a,axisOfRot->x,axisOfRot->y,axisOfRot->z); 
    glCallList(DLid); 
    glRotatef(a,axisOfRot->x,axisOfRot->y,axisOfRot->z); 
    glTranslatef(-newPoint->x,-newPoint->y,newPoint->z); 

回答

3

有一點需要注意的是,glTranslate函數建立在以前的翻譯上。 I.E.一個glTranslatef(0.0,0.0,0.0);不會到達原點,它只會將「筆」移動到任何地方。幸運的是,「筆」始於原點。如果你翻譯爲1.0,1.0,1.0,然後嘗試glTranslatef(0.0,0.0,0.0);你仍然在繪製1.0,1.0,1.0;

另外,您似乎已經掌握了openGL擴展matricies的事實。爲此,你在抽籤後正確地「撤銷」你的矩陣運算。我只看到一個地方,你可能會離開這裏,這是在此聲明:

glRotatef(90,0,1,0); 
    glRotatef(a,axisOfRot->x,axisOfRot->y,axisOfRot->z);  
    glCallList(DLid); 
    glRotatef(-a,axisOfRot->x,axisOfRot->y,axisOfRot->z); 
    glRotatef(90,0,1,0); 

在這裏你正確地撤消第二旋轉,但第一個你似乎更繞Y軸旋轉。最後一個glRotatef需要讀取glRotatef(-90,0,1,0);如果你想要撤消那個輪換。

1

我看着你的代碼中創建的三個環節和假設進行bezierInterp代碼和軸角度是正確的代碼。根據代碼,我有以下建議:

  1. 您創建單個鏈接的方式看起來非常昂貴。正如你使用gluCylinder 180次。這將爲小鏈接生成很多頂點。您可以創建單個環面並應用比例,使其看起來像鏈接!

  2. 無論何時進行任何矩陣運算,最好先設置模式。在做推動和流行之前,這很重要。在您的顯示列表中,您可以在不設置任何模式的情況下按下並彈出,也不會在呼叫者中設置。這不是很好的做法,會導致很多錯誤/問題。您可以從呼叫列表中刪除推送和彈出窗口,並只保留幾何圖形。

  3. 您已聽到建議在旋轉之前將翻譯原點翻譯爲翻譯*旋轉! =旋轉*翻譯。所以,這樣你會寫你的渲染循環是:

    // Set matrix mode 
    glMatrixMode(GL_MODELVIEW); 
    
    for(number of links) { 
    
    glLoadIdentity();  // makes model view matrix identity - default location` 
    glTranslatef(x,y,z); // Translate to a point on beizer curve 
    glRotatef(..);  // Rotate link 
    glCallList(link);  // can be simple torus, only geometry centered at origin 
    } 
    

以上代碼呈現在指定位置重複的鏈接。閱讀OpenGL紅皮書chapter 3 - 示例3.6(行星系統)示例,瞭解如何將每個鏈接正確放置在不同的位置。

+0

我的程序已經包含在main()函數中設置的MODELVIEW語句,正如我在該顯示列表中注意到的列表 「我意識到使用圓柱創建半圓環是一個壞主意,我將使用GL_STRIP或TRIANGLE_FAN一旦我得到對齊的權利「。僅使用圓環不會使鏈條變得逼真,這就是爲什麼選擇使用兩個半圓環和兩個圓柱來創建鏈條的原因。爲簡化起見,我在這篇文章中簡化了取消for循環和大部分main()函數的程序。 感謝您的幫助。 – NeatRobot 2009-11-04 15:38:03

+0

那麼你是否找到了正確的方法來獲得翻譯和輪換工作? – Ketan 2009-11-04 20:39:58

+0

不,我嘗試使用glTranslatef(0,0,0)將初始鏈接移動到原點。然後調用glRotate();然後glTranslate()到原來的位置,然後渲染鏈接,但我仍然有兩個不在曲線上的圓環中心的問題。 – NeatRobot 2009-11-05 13:41:51