2012年6月21日 星期四

PyOpenGL全解析 3


資料來源:http://eyehere.net/2011/learn-opengl-3d-by-pyopengl-3/

用PyOpenGL叩開3D的心扉——OpenGL全解析(3)

星期四, 20. 十月2011

第一個PyOpenGL程序

說實話我們OpenGL的基礎還遠遠沒有學完,不過我在說下去大概就不會有人看了,所以,雖然稍稍有些早,開始我們的第一個程序吧。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
def drawFunc():
    glClear(GL_COLOR_BUFFER_BIT)
    #glRotatef(1, 0, 1, 0)
    glutWireTeapot( 0.5 )
    glFlush()
glutInit()
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA)
glutInitWindowSize( 400 , 400 )
glutCreateWindow( "First" )
glutDisplayFunc(drawFunc)
#glutIdleFunc(drawFunc)
glutMainLoop()
結果如上圖,雖然很短,相信這裡面很多函數大家會覺得陌生,不要緊,這些代碼是每個程序中都需要的,基本看兩個就OK了,下面來詳細說明一下。
先把註釋的兩個函數給無視了,看看一開始三行的導入,OpenGL一開始是以C寫成的,所以OpenGL的程序中繪圖的代碼也是一大堆的函數,沒有什麼對像類的,所以我們把相關函數全部倒入,雖然這有些污染環境的感覺和Python的設計機理有些不符,不過這麼多年都過來了:),而且OpenGL中的函數都是有前綴的,問題也不大。

OpenGL函數的命名規則

一般的函數命名如下:
<前綴><根函數><參數數目><參數類型>
前綴有gl、glu、aux、glut、wgl、glx、agl等等,分別表示該函數屬於OpenGL那個開發庫等。所謂開發庫,要知道原生的OpenGL是跨平台的,跨平台意味著很多功能是無法實現的,比如說Windows和X-Window的窗口實現機制是不同的,OpenGL並不關心這些東西,只管畫圖。所以,OpenGL並沒有窗口函數,比如無法創建窗口,無法獲得輸入……這些東西都需要其他的函數庫來實現。我們可以用我之前講述的Pygame來創建窗口,然後用PyOpenGL來繪圖,不過咱不能要求每個看PyOpenGL教程的朋友都先看一遍Pygame教程(這樣就是強買強賣了不是),所以這裡就用OpenGL常用的工具函數庫來實現。
我們主要使用兩種,一個是GLU庫,它提供了比較基礎的命令的封裝,可以很簡單的實現比較多的複雜功能;而另外一個就是GLUT,glut是不依賴於窗口平台的OpenGL工具包,目的是隱藏不同窗口平台API的複雜度,提供更為複雜的繪製功能,我們會大量的使用它。
參數數和參數函數就很好理解了,有點像匈牙利命名法,f說明是個float,i說明是int等等。對Python來說可能不是很重要,不過還是要說明一下,OpenGL函數有d(double)的版本,C/C++語言一般默認浮點數就是double,使用d版本函數可能會顯得比較簡單,但是我們不推薦。因為OpenGL內部數據都是以float的形式存放的,如果使用double會對性能有一定的影響。
舉個例子,glColor3f()表示了該函數屬於gl庫,參數是三個float型參數指針。類似的函數還有glColor3i,glColor4f等,我們用glColor*()來表示這一類函數。

初始化窗口

11~17行基本也是固定的,
glutInit()是用glut來初始化OpenGL的,所有的問題都交給這個函數吧,基本不用管,雖說可以接受參數的,基本無用。
glutInitDisplayMode(MODE)非常重要,這裡告訴系統我們需要一個怎樣顯示模式。至於其參數GLUT_RGBA就是使用(red, green, blue)的顏色系統。有沒有寫錯?這裡有個A啊,不應該是(red, green, blue, alpha)麼?大概是歷史原因,GLUT_RGBA和GLUT_RGB是其實是等價的(坑爹啊),要想實現Alpha還得用其他的參數。而GLUT_SINGLE意味著所有的繪圖操作都直接在顯示的窗口執行,相對的,我們還有一個雙緩衝的窗口,對於動畫來說非常合適。看看用Python和Pygame寫遊戲-從入門到精通(3)有些說明。
glutInitWindowSize(400, 400)這個函數很容易理解,設置出現的窗口的大小。實際上還有個glutInitWindowPosition()也很常用,用來設置窗口出現的位置。
glutCreateWindow(“First”),一旦調用了,就出現一個窗口了,參數就是窗口的標題。
glutDisplayFunc(func)是glut非常討人喜歡的一個功能,它註冊了一個函數,用來繪製OpenGL窗口,這個函數里就寫著很多OpenGL的繪圖操作等命令,也就是我們主要要學習的東西。
glutMainLoop(),主循環,一旦調用了,我們的OpenGL就一直運行下去了。和很多程序中的主循環一樣,不停的運行,畫出即時的圖像,處理輸入等。

繪圖

看看drawFunc裡的幾句話,這裡是實際繪圖的函數。
glClear(GL_COLOR_BUFFER_BIT)是把先前的畫面給清除,這基本是定律,每次重繪之前都要把原來的畫面擦除,否則疊加起來什麼都看不出了。glClear一看就知道是OpenGL原生的命令,而參數就是指明要清除的buffer。大家一定會有疑問,我們清除,不就是清除屏幕上的畫面麼,為什麼還要指定?OpenGL的博大精深這裡就體現出來了,buffer不僅僅有我們看到的那個GL_COLOR_BUFFER_BIT,OpenGL中還有其他的buffer類型,我們會在後面的章節講到。
glutWireTeapot(0.5)是glut提供的繪製猶他茶壺的工具函數,茶壺還是相當複雜的一個幾何體,用這個函數一下子就畫出來了,不過基本也就演示用用。這裡是用的線模型,因為沒有說光照和材質,如果glutSolidTeapot()畫出來就成紙片兒了。
glFlush()似乎不用多說,畫了那麼多,自然要刷新一下顯示。不過,這裡的刷新不僅僅是屏幕上的更新,實際上,它是處理OpenGL的渲染流水線,讓所有排隊中的命令得到執行。OpenGL的渲染流水線是一個很重要的概念,不過這裡暫時還不打算多說明,否則對初學者來說,未免有些麻煩了。但是這並不意味著可以無視這些基礎,知道怎麼做只能讓你優秀,知道為什麼這麼做才能讓你卓越

小驚喜

現在你可以把註釋的兩個語句打開了,執行以下看到什麼?旋轉的茶壺!不得不說帥多了~
glutIdleFunc(Func)又是一個激動人心的函數,可以讓OpenGL在閒暇之餘,調用一下註冊的函數,這是是產生動畫的絕好方法。
glRotatef(1, 0, 1, 0)是一個我們以後會詳細講的函數,簡單來說四個參數第一個是角度,後三個是一個向量,意義就是繞著這個向量旋轉,這裡是繞著Y軸旋轉1°。這一度一度的累加,最後使得茶壺圍繞Y軸不停的旋轉。從這裡我們也能看出來,我們指定了一個旋轉的角度後,重新繪製並不會復位,而是在上一次旋轉的結果上繼續旋轉。這是一個非常重要的概念,OpenGL是一個狀態機,一旦你指定了某種狀態,知道再指定位置,它會保持那種狀態。不僅僅是旋轉,包括以後的光照貼圖等等,都遵循這樣的規律。
好了,我們有了第一個PyOpenGL程序了,雖然離我們詳細中的五光十色的立體世界還有些差距,不過畢竟畫了點東西出來了(要知道,猶他茶壺在3D技術發展之初,是里程碑一般的作品)。慢慢的,我們會充實自己的知識,繪製出更靚麗的畫面。

沒有留言:

張貼留言