Win32 OpenGL編程(9) 投影變換
write by 九天雁翎(JTianLing) -- blog.csdn.net/vagrxie
討論新聞群組及檔案
提要
在前文(系列文章(7),以下簡稱XO7,系列其他文章類似)中的照相機比喻中提到了4種3D變換,如下:
1.確定照相機的位置的過程對應於“視圖變換”(Viewing Transformations)
2.確定物體位置的過程對應於“模型變換”(Modeling Transformations)
3.確定照相機放大倍數的過程對應於“投影變換”(Projection Transformations)
4.確定照片大小的過程對應於“視口變換”(Viewport Transformations)
XO7中我們講的是第一種變換視圖變換,即改變觀察者本身的位置,視角等的變換效果,XO8中講的是第二種變換模型變換,本文開始繼續按順序講解下一個3D變換過程,投影變換。
正投影
投影變換的過程就像是照相機選鏡頭的過程,目的是確定視野,其實說起來投影一詞,我在學習工程製圖的時候就接觸過了,不知道大家是否學過這門課程,工程製圖就是一種將三維空間的事物設想投影在二維空間中,然後畫下來,工程中應用非常廣泛,那時候學的那些剖面圖什麼的,也是累死我了-_-!OpenGL就可以類比這樣的過程,並且名字和工程製圖中的名字是一樣的,叫正投影。
OpenGL以glOrtho來指定一個正交平行的矩形,螢幕上顯示的就是此物體在此矩形的正面的投影。在XO2中用過的gluOrtho2D實際上是此函數的一個去掉Z軸座標的簡化版,而glOrtho包括的參數nearVal,farVal表示此矩形的前,後兩面,超出此矩形範圍的圖形將會被裁掉。
《OpenGL Programming Guide
》:
glOrtho — multiply the current matrix with an orthographic matrix
C Specification
void glOrtho( GLdouble left,
GLdouble right,
GLdouble bottom,
GLdouble top,
GLdouble nearVal,
GLdouble farVal);
Parameters
left, right
Specify the coordinates for the left and right vertical clipping planes.
bottom, top
Specify the coordinates for the bottom and top horizontal clipping planes.
nearVal, farVal
Specify the distances to the nearer and farther depth clipping planes.
These values are negative if the plane is to be behind the viewer.
用此函數,通過調整nearVal與farVal我們可以實作類別似工程製圖中的剖面的效果,見下例:
GLfloat gfNear = 1.0;
//這裡進行所有的繪圖工作
void SceneShow(GLvoid)
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0, 0.0, 0.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-1.0, 1.0, -1.0, 1.0, gfNear, -1.0);
glPushMatrix();
DrawSmoothColorPyramid(0.5);
glPopMatrix();
glFlush();
}
///////////////////////////////////////////////////////////
int Game_Main(void *parms = NULL, int num_parms = 0)
{
DWORD dwStartTime;
dwStartTime = GetTickCount();
// this is the main loop of the game, do all your processing
// here
// for now test if user is hitting ESC and send WM_CLOSE
if (KEYDOWN(VK_ESCAPE))
SendMessage(ghWnd,WM_CLOSE,0,0);
if (KEYDOWN(VK_UP))
{
gfNear -= 0.01;
}
if (KEYDOWN(VK_DOWN))
{
gfNear += 0.01;
}
SceneShow();
// 控制幀率
while(GetTickCount() - dwStartTime < TIME_IN_FRAME)
{
Sleep(1);
}
// return success or failure or your own return code here
return(1);
} // end Game_Main
以下就是當nearVal為0.8時的效果,也就是說,Z軸座標大於0.8的,一律被截掉了,在工程製圖中,我們老師常將,此時假設在此用一刀將物體切掉。上面的原始碼中還出現了一個新函數,glMatrixmode,用於指定以下的變換是針對哪個變換的,
glMatrixMode(GL_PROJECTION);
用於指定以下的變換是針對投影變換的,而用glMatrixMode(GL_MODELVIEW);方式調用時,(預設值)表示針對模型變換。為節省篇幅僅貼出關鍵片段,完整原始碼見我部落格原始碼的2008-10-28/glOrthoSample 目錄,擷取方式見文章最後關於擷取部落格完整原始碼的說明。 透視投影
上述的正投影僅僅存在於想象之中,主要是工程製圖(或者CAD)中能夠正確反映物體的真實尺寸,現實中我們看東西,越遠的越小,越近的越大,並且所有物體最終會消失在遠方(地平線),OpenGL常用於VR(虛擬現實),這樣程度的視覺模擬效果自然是有的,在OpenGL中,這樣投影叫做透視投影。OpenGL提供了兩個函數用於指定透視投影,兩個函數僅僅是參數表示的方式不同,事實上效果是一樣的。
《OpenGL Programming Guide
》:
glFrustum — multiply the current matrix by a perspective matrix
C Specification
void glFrustum( GLdouble left,
GLdouble right,
GLdouble bottom,
GLdouble top,
GLdouble nearVal,
GLdouble farVal);
Parameters
left, right
Specify the coordinates for the left and right vertical clipping planes.
bottom, top
Specify the coordinates for the bottom and top horizontal clipping planes.
nearVal, farVal
Specify the distances to the near and far depth clipping planes.
Both distances must be positive.
gluPerspective — set up a perspective projection matrix
C Specification
void gluPerspective( GLdouble fovy,
GLdouble aspect,
GLdouble zNear,
GLdouble zFar);
Parameters
fovy
Specifies the field of view angle, in degrees, in the y direction.
aspect
Specifies the aspect ratio that determines
the field of view in the x direction.
The aspect ratio is the ratio of x (width) to y (height).
zNear
Specifies the distance from the viewer to the near clipping plane
(always positive).
zFar
Specifies the distance from the viewer to the far clipping plane
(always positive).
事實上,glFrustum指定的方式與glOrtho很像,參數意義也一致,僅僅是使用後OpenGL使用的投影方式不同,gluPerspective函數指定的方式是類比觀察者(照相機)的視角,用fovy指定觀察者的上下視角(及在y-z平面上觀察的角度),aspect指定觀察寬度與高度的比,然後用zNear指定離觀察者較近的截面,用zFar指定離觀察者較遠的截面(都指離觀察者的距離),下例展示了原來那個三角錐從遠方的一個小點然後到放大到原來大小的過程:
GLfloat gfDis = 5.0;
//這裡進行所有的繪圖工作
void SceneShow(GLvoid)
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(-1.0, 1.0, -1.0, 1.0, 1.0, 5.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0.0, 0.0, gfDis, 0.0, 0.0, -1.0, 0.0, 1.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0, 0.0, 0.0);
glPushMatrix();
DrawSmoothColorPyramid(0.5);
glPopMatrix();
glFlush();
}
int Game_Main(void *parms = NULL, int num_parms = 0)
{
DWORD dwStartTime;
dwStartTime = GetTickCount();
// this is the main loop of the game, do all your processing
// here
// for now test if user is hitting ESC and send WM_CLOSE
if (KEYDOWN(VK_ESCAPE))
SendMessage(ghWnd,WM_CLOSE,0,0);
if (KEYDOWN(VK_UP))
{
gfDis -= 0.01f;
}
if (KEYDOWN(VK_DOWN))
{
gfDis += 0.01f;
}
SceneShow();
// 控制幀率
while(GetTickCount() - dwStartTime < TIME_IN_FRAME)
{
Sleep(1);
}
// return success or failure or your own return code here
return(1);
} // end Game_Main
上面例子中靠
gluLookAt(0.0, 0.0, gfDis, 0.0, 0.0, -1.0, 0.0, 1.0, 0.0);
來調整觀察者的位置,通過上下鍵調節,會類比出一種慢慢走近三角錐的過程,三角錐也是隨著走近由小慢慢變大。
實際上最重要的還是
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(-1.0, 1.0, -1.0, 1.0, 1.0, 5.0);
三句確定的透視投影方式。
為節省篇幅僅貼出關鍵片段,完整原始碼見我部落格原始碼的2008-10-28/glPerspective 目錄,擷取方式見文章最後關於擷取部落格完整原始碼的說明。
小結:
相對來說,個人認為投影變換是屬於OpenGL中重要但是確較難理解的一部分,動態變化上述函數的參數,準確理解上述函數中每個參數的意義是種不錯的學習途徑,其中Nate Robin的OpenGL教程有個很形象的教學程式,推薦給大家(實際上為《OpenGL Programming Guide
》中推薦的),http://www.xmission.com/~nate/tutors.html
中有下載的。對應投影變換的教程為projection一例。
參考資料
1. 《OpenGL Reference Manual
》,OpenGL參考手冊
2. 《OpenGL
編程指南》(《OpenGL Programming Guide
》),Dave Shreiner,Mason Woo,Jackie Neider,Tom Davis
著,徐波譯,機械工業出版社
3. 《Nehe OpenGL Tutorials》,Nehe著,在http://nehe.gamedev.net/
上可以找到教程及相關的代碼下載,(有PDF版本教程下載)Nehe自己還做了一個物件導向的架構,作為示範程式來說,這樣的架構非常合適。也有中文版
,各取所需吧。
4. 《OpenGL入門學習》 ,eastcowboy著,這是我在網上找到的一個比較好的教程,較為完善,而且非常通俗。這是第一篇的地址:http://bbs.pfan.cn/post-184355.html
本OpenGL系列其他文章
1.
《 Win32 OpenGL 編程(1)Win32下的OpenGL編程必須步驟
》
2. 《Win32 OpenGL編程(2) 尋找缺失的OpenGL函數
》
3. 《Win32 OpenGL編程(3) 基本圖元(點,直線,多邊形)的繪製
》
4. 《Win32 OpenGL編程(4) 2D圖形基礎(顏色及座標體系進階知識)
》
5. 《Win32 OpenGL編程(5)頂點數組詳細介紹
》
6.《Win32 OpenGL編程(6) 踏入3D世界
》
7.《Win32 OpenGL編程(7) 3D視圖變換——真3D的關鍵
》
8.《Win32 OpenGL編程(8) 3D模型變換及其組合應用
》
應用舉例:《Win32 OpenGL編程系列 2D例子 -- 七巧板圖形繪製
》
完整原始碼擷取說明
由於篇幅限制,本文一般僅貼出代碼的主要關心的部分,代碼帶工程(或者makefile)完整版(如果有的話)都能用Mercurial在Google Code中下載。文章以博文發表的日期分目錄存放,請直接使用Mercurial複製下庫:
https://blog-sample-code.jtianling.googlecode.com/hg/
Mercurial使用方法見《分布式的,新一代版本控制系統Mercurial的介紹及簡要入門
》
要是僅僅想瀏覽全部代碼也可以直接到google code上去看,在下面的地址:
http://code.google.com/p/jtianling/source/browse?repo=blog-sample-code
原創文章作者保留著作權 轉載請註明原作者 並給出連結
write by 九天雁翎(JTianLing) -- blog.csdn.net/vagrxie