2011-10-11 94 views
5

我在OpenGL中的天空盒內製作過山車,並且沒有太多關於它的功能或計算機圖形的背景,它證明是非常困難的。我用Catmull-Rom樣條插值繪製了過山車,並用glVertex3f繪製了每個點。現在我想每50ms調用一次update()函數來移動攝像機在軌道上。 gluLookAt()正在產生奇怪的結果,無論是從屏幕上移除軌道,產生黑屏等。我想我需要移動一些矩陣函數,但我不確定在哪裏放置每一個。這是我到目前爲止的代碼:OpenGL gluLookAt()未按預期工作

int main(int argc, char** argc) 
{ 
    // ... load track, etc ... 

    // Init currpos, nextpos, iter, up 
    currpos = Vec3f(0, 0, 0); 
    nextpos = currpos; 
    iter = 0; 
    up = Vec3f(0, 1, 0); 

    deque<Vec3f> points; 
    Vec3f newpt; 

    // Loop through the points and interpolate 
    for (pointVectorIter pv = g_Track.points().begin(); pv != g_Track.points().end(); pv++) 
    { 
     Vec3f curr(*pv);   // Initialize the current point and a new point (to be drawn) 
     points.push_back(curr);  // Push the current point onto the stack 
     allpoints.push_back(curr); // Add current point to the total stack 

     if (points.size() == 4) // Check if there are 4 points in the stack, if so interpolate 
     { 
      for (float u = 0.0f; u < 1.0f; u += 0.01f) 
      { 
       newpt = interpolate(points[0], points[1], points[2], points[3], u); 
       glColor3f(1, 1, 1); 
       glVertex3f(newpt.x(), newpt.y(), newpt.z()); 

       allpoints.push_back(newpt); 
      } 

      points.pop_front(); 
     } 
    } 

    // glutInit, InitGL(), etc... 
} 

void InitGL(GLvoid) 
{ 
    glEnable(GL_DEPTH_TEST); 
    glDepthFunc(GL_LEQUAL); 
    glMatrixMode(GL_PROJECTION); 
    glLoadIdentity(); 
    gluPerspective(100.0, (GLfloat)WINDOW_WIDTH/(GLfloat)WINDOW_HEIGHT, .0001, 999999); 
    glMatrixMode(GL_MODELVIEW); 
    glClearColor(0.0f, 0.0f, 0.0f, 0.5f); 
} 

void display (void) 
{ 
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
    glMatrixMode(GL_MODELVIEW); 
    glLoadIdentity(); 
    gluLookAt(currpos.x(), currpos.y(), currpos.z(), nextpos.x(), nextpos.y(), nextpos.z(), up.x(), up.y(), up.z()); 

    glPushMatrix(); 
    glEnable(GL_TEXTURE_2D); // Enable texturing from now on 

    /* draw skybox, this was from previous assignment and renders correctly */ 

    glPopMatrix(); 

    // now draw rollercoaster ... 

    glPushMatrix(); 
    glBegin(GL_LINE_STRIP); 

    deque<Vec3f> points; 
    Vec3f newpt; 

    for each (Vec3f pt in allpoints) 
    { 
     glColor3f(1, 1, 1); 
     glVertex3f(pt.x(), pt.y(), pt.z()); 
    } 

    glutTimerFunc(50, update, 1); 
    glEnd(); 
    glPopMatrix(); 

    // Swap buffers, so one we just drew is displayed 
    glutSwapBuffers(); 
} 

void update(int a) 
{ 
    if (iter < allpoints.size()) 
    { 
     currpos = allpoints[iter]; 
     nextpos = allpoints[iter + 1]; 

     gaze = nextpos - currpos; 
     gaze.Normalize(); 

     Vec3f::Cross3(binorm, gaze, up); 
     binorm.Normalize(); 

     Vec3f::Cross3(up, binorm, gaze); 
     up.Normalize(); 

     glutPostRedisplay(); 
    } 

    iter++; 
} 

的想法是,我保持一個全球性的雙端隊列allpoints包括樣條曲線的控制點和插值點。一旦完成,我每隔50ms撥打update(),並沿着allpoints的每個點移動攝像機。在該項目的以前版本中,我可以看到過山車正在正確繪製。這是gluLookAt(),似乎並沒有工作,我想如何。使用上面的代碼,程序開始時攝像頭用一部分過山車看着天空盒的一側,然後當update()被調用時,過山車消失,但攝像機不動。我一直在搞亂OpenGL矩陣功能,根據它們的位置有時update()也會導致一個空白屏幕。

回答

5

除了沒有glPopMatrix(其中user971377已發現),你在你的繪圖程序,這當然會覆蓋您在update方法做了模型視圖矩陣的任何更改(使用gluLookAt)調用glLoadIdentity

始終牢記:gluLookAtglOrthogluPerspectiveglTranslateglRotate,和所有其他矩陣和轉換功能始終是當前選定的矩陣堆棧(由glMatrixMode改變)的頂級元素(由glPush/PopMatrix改變)上工作。它們總是乘以當前的矩陣,而不是替換它。對於gluPerspective,您應該致電glLoadIdentity,然後致電gluLookAt。整個相機的改變應該在渲染程序中完成,而不是更新程序。

而是在update做任何GL轉換的,你應該改變,而其上的攝像頭所依賴的變量和方法display設定相機(gluLookAt在模型視圖矩陣)。爲了證明標準的使用這些功能,你的代碼應該是這樣的:

void display() 
{ 
    <general state setup (glClear, ...)> 

    glMatrixMode(GL_MODELVIEW); 
    glLoadIdentity(); 
    glLookAt(camera);  //view transformation (camera) 

    //object 1 
    glPushMatrix();  //save modelview 
    glTranslate/glRotate/glScale;  //local model transformations 
    <draw object 1> 
    glPopMatrix(); 
    ... 
    //object n 
    glPushMatrix();  //save modelview 
    glTranslate/glRotate/glScale;  //local model transformations 
    <draw object n> 
    glPopMatrix(); 

    gluSwapBuffers(); 
} 

void update() 
{ 
    camera = ...; 
} 

}

+0

對不起,'glPopMatrix()'是在過山車之前的天空盒代碼的末尾(因爲我沒有包含天空盒代碼,所以我在問題中忘記了它) - 是它應該去的地方,還是應該在過山車之後? –

+0

@Logan儘管控制流在運行時可能是相同的,但是'glPopMatrix'應該與'glPushMatrix'處於相同的範圍,因爲兩者都代表一個整體,並且應該始終成對。 –

+0

我的意思是,如果'glPopMatrix()'在註釋過的天空盒代碼之後(在用'glVertex3f'繪製rc之前)之後,還是在循環之後用'glVertex3f'繪製rc? –

0

gluLookAt總是將其結果應用到當前矩陣,在你的情況下它是GL_MODEL_VIEW。但是當你渲染你的過山車時,你會在這個矩陣中加載身份,這會抹掉你使用gluLookAt的值。

在這種情況下,您不需要觸摸模型視圖。實際上,GL_MODEL_VIEW表示模型矩陣乘以視圖矩陣。在這種情況下,您可以glPushMatrix()後跟glMulMatrix(myModelMatrix)並在呈現glPopMatrix()後。有了這個,你可以將視圖矩陣保留在GL_MODEL_VIEW中,並且每個對象仍然使用不同的模型矩陣。我還建議你只改變投影矩陣一次而不是每幀。

0

它一直以來我感動OpenGL的很長一段時間,但這裏要考慮幾件事情:顯示

  • 每次調用(),您繪製有那麼當前矩陣加載身份天空盒矩陣繪製過山車。也許在push/pop內加載身份,以使天空盒保持不變,但是你在雲霄飛車上的流行變形被應用。
  • 您是否需要每次調用display()時調用gluPerspective和glMatrixMode?
  • 反覆從上往上計算binorm,然後從binorm開始,可能會給您帶來意想不到的結果,即相機在屏幕z軸周圍的旋轉。
  • 對gluLookAt的調用似乎有反向的nextpos和currpos,將相機指向相反的方向。
  • (僅限意見)使用完全靜止的天空盒可能仍會看起來很奇怪。在繪製天空盒和過山車時匹配相機旋轉(但不能平移)可能會更好看。
+0

謝謝,您的建議是工作好(我認爲),因爲本身現在與相機旋轉過山車。相機本身雖然行動起來,但它並未遵循軌道,最終失去控制並走出了天空盒。我確實切換了下一個位置和currpos,所以這可能是由於binorm/up向量計算?你知道如何計算這些,因爲我的代碼中有我們的TA所建議的。 –

+0

up的計算只應該影響相機的旋轉角度,這並不能解釋它在天空盒之外的轉換。你的控制點是否使用與OpenGL相同的xyz方向? – SlightNihilism

+0

同時,如果你的過山車從來沒有在步驟之間完全上下襬動,那麼你應該能夠保持「向上」穩定。我甚至會暫時調整軌道,以便我可以使用這種方法,直到我設法調試/測試相機的xyz位置。然後我擔心之後會有更安全的計算。不幸的是,我沒有推薦這種計算方法。 – SlightNihilism

3

在你的代碼glPushMatrix();注意到的是所謂的無glPopMatrix();

只是一個想法,這可能是與你的問題。