http://www.tuicool.com/articles/uiayYrIhtml
OpenGL學習腳印: 座標變換過程(vertex transformation) git
http://blog.csdn.net/wangdingqiaoit/article/details/51594408github
寫在前面
前面幾節分別介紹了模型變換,視變換,以及給出了投影矩陣和視口變換矩陣的推導,本節從全局把握一遍OpenGL座標轉換的過程,從總體上認識座標變換過程。相關矩陣的數學推導過程請參考前面幾節對應的內容。api
經過本節能夠了解到ruby
OpenGL中的座標處理過程包括模型變換、視變換、投影變換、視口變換等過程,以下圖所示:
less
在上面的圖中,注意,OpenGL只定義了裁剪座標系、規範化設備座標系和屏幕座標系,而局部座標系(模型座標系)、世界座標系和照相機座標系都是爲了方便用戶設計而自定義的座標系,它們的關係以下圖所示(來自Chapter 7. World in Motion):函數
圖中左邊的過程包括模型變換、視變換,投影變換,這些變換能夠由用戶根據須要自行指定,這些內容在頂點着色器中完成;而圖中右邊的兩個步驟,包括透視除法、視口變換,這兩個步驟是OpenGL自動執行的,在頂點着色器處理後的階段完成。學習
下面分別對每一個階段的變換作一個總結,以幫助理解。ui
局部座標系(模型座標系)是爲了方便構造模型而設立的座標系,創建模型時咱們無需關心最終對象顯示在屏幕哪一個位置。模型的原點定位也能夠有所不一樣,例以下面在模型座標系定義的模型:
atom
模型變換的主要目的是經過變換使得用頂點屬性定義或者3d建模軟件構造的模型,可以按照須要,經過縮小、平移等操做放置到場景中合適的位置。經過模型變換後,物體放置在一個全局的世界座標系中,世界座標系是全部物體交互的一個公共座標系。例以下面的圖中在模型座標系定義的茶壺模型(來自World, View and Projection Transformation Matrices):
茶壺經過模型變換,轉換到世界座標系中(來自World, View and Projection Transformation Matrices):
模型變換包括:旋轉、平移、縮放、錯切等內容。例如將物體從一個位置p=(x,y,z),移動到另外一個位置p′=(x′,y′,z′)的過程,用矩陣表示爲:
應用多個模型變換時,注意變換執行的順序影響變換的結果,通常按照縮放–》旋轉—》平移的順序執行;另外,注意旋轉和縮放變換的不動點問題。這些內容在模型變換一節已經介紹了,這裏再也不贅述。利用GLM數學庫實現模型變換,例如平移變換示例代碼爲:
glm::mat4 model; // 構造單位矩陣 model = glm::translate(model, glm::vec3(0.0f, 0.0f,-0.5f));
視變換是爲了方便觀察場景中物體而設立的座標系,在這個座標系中相機是個假想的概念,是爲了便於計算而引入的。相機座標系中的座標,就是從相機的角度來解釋世界座標系中位置。相機和場景的示意圖以下所示(來自World, View and Projection Transformation Matrices):
OpenGL中相機始終位於原點,指向-Z軸,而以相反的方式來調整場景中物體,從而達到相同的觀察效果。例如要觀察-z軸方向的一個立方體的右側面,能夠有兩種方式:
- 立方體不動,讓相機繞着+y軸,旋轉+90度,此時相機鏡頭朝向立方體的右側面,實現目的。完成這一旋轉的矩陣記做Ry(π2)
- 相機不動,讓立方體繞着+y軸,旋轉-90度,此時也能實現一樣的目的。注意這時相機沒有轉動。完成這一旋轉的矩陣記做Ry(−π2)
OpenGL中採用方式2的觀點來解釋視變換。再舉一個例子,好比,一個物體中心位於原點,照相機也位於初始位置原點,方向指向-Z軸。爲了對物體的+Z面成像,那麼必須將照相機從原點移走,若是照相機仍然指向-Z軸,須要將照相機沿着+Z軸方向後退。倘若照相機不移動,咱們能夠經過將物體沿着-Z軸後退d個單位,則變換矩陣爲:
經過在世界座標系中指定相機的位置,指向的目標位置,以及viewUp向量來構造一個相機座標系,經過視變換矩陣將物體座標由世界座標系轉換到相機座標系,視變換矩陣的推導已經在視變換一節介紹,感興趣地能夠去參考。利用GLM數學庫實現視變換的代碼爲:
glm::mat4 view = glm::lookAt(eyePos,
glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
投影方式決定以何種方式成像,投影方式有不少種,OpenGL中主要使用兩種方式,即透視投影(perspective projection)和正交投影( orthographic projection)。
1.正交投影是平行投影的一種特殊情形,正交投影的投影線垂直於觀察平面。平行投影的投影線相互平行,投影的結果與原物體的大小相等,所以普遍地應用於工程製圖等方面。
2.透視投影的投影線相交於一點,所以投影的結果與原物體的實際大小並不一致,而是會近大遠小。所以透視投影更接近於真實世界的投影方式。
二者的示意圖以下:
在OpenGL中成像時的效果以下所示(圖片來自Modern OpenGL):
上面的圖中,紅色和黃色球在視見體內,於是呈如今投影平面上,而綠色球在視見體外,沒有在投影平面上成像。指定視見體經過(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble nearVal, GLdouble farVal)6個參數來指定。注意在相機座標系下,相機指向-z軸,nearVal和farVal表示的剪裁平面分別爲:近裁剪平面z=−nearVal,以及遠裁剪平面z=−farVal。
使用
glOrtho(xleft, xright, ybottom, ytop, znear, zfar);
或者相似API指定正交投影,參數意義形象表示爲下圖所示(來自World, View and Projection Transformation Matrices):
使用
void glFrustum(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble nearVal, GLdouble farVal);
void gluPerspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar);
或者相似的API指定透視投影的視見體,其參數含義以下圖所示(來自World, View and Projection Transformation Matrices):
關於投影矩陣的推導,能夠參考前面的投影矩陣和視口變換矩陣一節。利用GLM數學庫實現視透視投影變換的代碼示例爲:
glm::mat4 projection = glm::perspective(glm::radians(45.0f), (GLfloat)(WINDOW_WIDTH)/ WINDOW_HEIGHT, 1.0f, 100.0f);
通過投影變換後,物體座標變換到了裁剪座標系,通過OpenGL自動執行的透視除法後,變換到規範化設備座標系中。透視除法就是將裁剪座標系中座標都除以wc成分的過程。
視變換是將規範化設備座標(NDC)轉換爲屏幕座標的過程,以下圖所示:
視口變化經過函數:
glViewport(GLint sx , GLint sy , GLsizei ws , GLsizei hs);
glDepthRangef(GLclampf ns , GLclampf fs );
兩個函數來指定。其中(sx,sy)表示窗口的左下角,ns和 fs指定遠近剪裁平面到屏幕座標的映射關係。視口變換矩陣的推導能夠參考前面的投影矩陣和視口變換矩陣一節。用上面的glViewport和glDepthRangef函數指定參數後,視口變換由OpenGL自動執行,不須要額外代碼。
上述過程從座標計算角度來看,以下圖所示:
在程序中,咱們須要在兩個部分作處理。
第一,編寫頂點着色器程序以下:
#version 330 layout(location = 0) in vec3 position; layout(location = 1) in vec3 color; layout(location = 2) in vec2 textCoord; out vec3 VertColor; out vec2 TextCoord; uniform mat4 projection; uniform mat4 view; uniform mat4 model; void main() { gl_Position = projection * view * model * vec4(position, 1.0); VertColor = color; TextCoord = textCoord; }
第二,在主程序中傳遞變換矩陣到頂點着色器,並繪製場景中物體,代碼以下:
// 投影矩陣 glm::mat4 projection = glm::perspective(glm::radians(45.0f), (GLfloat)(WINDOW_WIDTH)/ WINDOW_HEIGHT, 1.0f, 100.0f); // 視變換矩陣 glm::mat4 view = glm::lookAt(eyePos, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f)); // 模型變換矩陣 glm::mat4 model = glm::mat4(); model = glm::translate(model, glm::vec3(-0.25f, 0.0f, 0.0f)); // 使用uniform變量傳遞MVP矩陣 glUniformMatrix4fv( glGetUniformLocation(shader.programId, "projection"), 1, GL_FALSE, glm::value_ptr(projection)); // 傳遞投影矩陣 glUniformMatrix4fv( glGetUniformLocation(shader.programId, "view"), 1, GL_FALSE, glm::value_ptr(view));// 傳遞視變換矩陣 glUniformMatrix4fv( glGetUniformLocation(shader.programId, "model"), 1, GL_FALSE, glm::value_ptr(model)); // 傳遞模型變換矩陣 // 繪製物體 glDrawArrays(GL_TRIANGLES, 0, 36);
例如利用圓形座標系指定相機位置,繪製的立方體以下圖所示:
1.World, View and Projection Transformation Matrices
2.GLSL Programming/Vertex Transformations
1.OpenGL 101: Matrices - projection, view, model
2.songho OpenGL Transformation
3.The Perspective and Orthographic Projection Matrix
4.songho OpenGL Projection Matrix
5. glOrtho
6. glFrustum
7. gluPerspective
8. gluLookAt