1,目的
本文只是為了初步了解一下Python的OpenGL使用方法(整合前輩的技術(shù)Blog),至于繪圖方面的博大精深,我們尚不知一二,有待于作者以后深入學習和實踐,不在本文的講述范圍。不過,計算機繪圖方面的技術(shù)深度和商業(yè)使用,是值得深入學習研究的。但是,是否是Python所長,就看以后的技術(shù)演化了。
2,安裝
- 執(zhí)行Linux命令安裝
pip install PyOpenGL PyOpenGL_accelerate
- Windows下,Pycharm安裝
** PyOpenGL
** PyOpenGL_accelerate
3,初級Demo
下面的代碼,可以直接執(zhí)行,詳細的函數(shù)介紹,請查看:
用PyOpenGL叩開3D的心扉——OpenGL全解析(3)
http://eyehere.net/2011/learn-opengl-3d-by-pyopengl-3/
先上圖:

再看代碼:
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()
最后,代碼介紹:
初始化窗口
11~17行基本也是固定的,
glutInit()是用glut來初始化OpenGL的,所有的問題都交給這個函數(shù)吧,基本不用管,雖說可以接受參數(shù)的,基本無用。
glutInitDisplayMode(MODE)非常重要,這里告訴系統(tǒng)我們需要一個怎樣顯示模式。至于其參數(shù)GLUT_RGBA就是使用(red,
green, blue)的顏色系統(tǒng)。有沒有寫錯?這里有個A啊,不應(yīng)該是(red, green, blue,
alpha)么?大概是歷史原因,GLUT_RGBA和GLUT_RGB是其實是等價的(坑爹?。雽崿F(xiàn)Alpha還得用其他的參數(shù)。而GLUT_SINGLE意味著所有的繪圖操作都直接在顯示的窗口執(zhí)行,相對的,我們還有一個雙緩沖的窗口,對于動畫來說非常合適??纯从肞ython和Pygame寫游戲-從入門到精通(3)有些說明。glutInitWindowSize(400,
400)這個函數(shù)很容易理解,設(shè)置出現(xiàn)的窗口的大小。實際上還有個glutInitWindowPosition()也很常用,用來設(shè)置窗口出現(xiàn)的位置。glutCreateWindow(“First”),一旦調(diào)用了,就出現(xiàn)一個窗口了,參數(shù)就是窗口的標題。
glutDisplayFunc(func)是glut非常討人喜歡的一個功能,它注冊了一個函數(shù),用來繪制OpenGL窗口,這個函數(shù)里就寫著很多OpenGL的繪圖操作等命令,也就是我們主要要學習的東西。
glutMainLoop(),主循環(huán),一旦調(diào)用了,我們的OpenGL就一直運行下去了。和很多程序中的主循環(huán)一樣,不停的運行,畫出即時的圖像,處理輸入等。
繪圖
看看drawFunc里的幾句話,這里是實際繪圖的函數(shù)。
glClear(GL_COLOR_BUFFER_BIT)是把先前的畫面給清除,這基本是定律,每次重繪之前都要把原來的畫面擦除,否則疊加起來什么都看不出了。glClear一看就知道是OpenGL原生的命令,而參數(shù)就是指明要清除的buffer。大家一定會有疑問,我們清除,不就是清除屏幕上的畫面么,為什么還要指定?OpenGL的博大精深這里就體現(xiàn)出來了,buffer不僅僅有我們看到的那個GL_COLOR_BUFFER_BIT,OpenGL中還有其他的buffer類型,我們會在后面的章節(jié)講到。
glutWireTeapot(0.5)是glut提供的繪制猶他茶壺的工具函數(shù),茶壺還是相當復雜的一個幾何體,用這個函數(shù)一下子就畫出來了,不過基本也就演示用用。這里是用的線模型,因為沒有說光照和材質(zhì),如果glutSolidTeapot()畫出來就成紙片兒了。
glFlush()似乎不用多說,畫了那么多,自然要刷新一下顯示。不過,這里的刷新不僅僅是屏幕上的更新,實際上,它是處理OpenGL的渲染流水線,讓所有排隊中的命令得到執(zhí)行。OpenGL的渲染流水線是一個很重要的概念,不過這里暫時還不打算多說明,否則對初學者來說,未免有些麻煩了。但是這并不意味著可以無視這些基礎(chǔ),知道怎么做只能讓你優(yōu)秀,知道為什么這么做才能讓你卓越。
小驚喜
現(xiàn)在你可以把注釋的兩個語句打開了,執(zhí)行以下看到什么?旋轉(zhuǎn)的茶壺!不得不說帥多了~
glutIdleFunc(Func)又是一個激動人心的函數(shù),可以讓OpenGL在閑暇之余,調(diào)用一下注冊的函數(shù),這是是產(chǎn)生動畫的絕好方法。
glRotatef(1, 0, 1,
0)是一個我們以后會詳細講的函數(shù),簡單來說四個參數(shù)第一個是角度,后三個是一個向量,意義就是繞著這個向量旋轉(zhuǎn),這里是繞著Y軸旋轉(zhuǎn)1°。這一度一度的累加,最后使得茶壺圍繞Y軸不停的旋轉(zhuǎn)。從這里我們也能看出來,我們指定了一個旋轉(zhuǎn)的角度后,重新繪制并不會復位,而是在上一次旋轉(zhuǎn)的結(jié)果上繼續(xù)旋轉(zhuǎn)。這是一個非常重要的概念,OpenGL是一個狀態(tài)機,一旦你指定了某種狀態(tài),知道再指定位置,它會保持那種狀態(tài)。不僅僅是旋轉(zhuǎn),包括以后的光照貼圖等等,都遵循這樣的規(guī)律。好了,我們有了第一個PyOpenGL程序了,雖然離我們詳細中的五光十色的立體世界還有些差距,不過畢竟畫了點東西出來了(要知道,猶他茶壺在3D技術(shù)發(fā)展之初,是里程碑一般的作品)。慢慢的,我們會充實自己的知識,繪制出更靚麗的畫面。
4,入門Demo
下面的代碼可以直接執(zhí)行,詳細的代碼請查看:
用PyOpenGL叩開3D的心扉——OpenGL全解析(5)
http://eyehere.net/2013/learn-opengl-3d-by-pyopengl-5/
先上圖:

再看代碼:
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
from numpy import *
import sys
global W, H, R
(W, H, R) = (500, 500, 10.0)
def init():
glClearColor(1.0, 1.0, 1.0, 1.0)
def drawfunc():
glClear(GL_COLOR_BUFFER_BIT)
glColor3f(0.0, 0.0, 0.0)
glBegin(GL_POINTS)
for x in arange(-R, R, 0.04):
print '%.1f%%r' % ((R + x) / (R + R) * 100),
for y in arange(-R, R, 0.04):
r = cos(x) + sin(y)
glColor3f(cos(y * r), cos(x * y * r), sin(x * r))
glVertex2f(x, y)
print '100%!!'
glEnd()
glFlush()
def reshape(w, h):
if h <= 0: h = 1;
glViewport(0, 0, w, h)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
if w <= h:
gluOrtho2D(-R, R, -R * h / w, R * h / w)
else:
gluOrtho2D(-R * w / h, R * w / h, -R, R)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
def keyboard(key, x, y):
if key == chr(27) or key == "q": # Esc is 27
sys.exit()
def main():
glutInit(sys.argv)
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB)
glutInitWindowPosition(20, 20)
glutInitWindowSize(W, H)
glutCreateWindow("Artist Drawer")
glutReshapeFunc(reshape)
glutDisplayFunc(drawfunc)
glutKeyboardFunc(keyboard)
init()
glutMainLoop()
main()
最后,代碼介紹:
glViewport:指定了視口程序顯示的范圍,也就是OpenGL繪制的范圍,這里使用(0, 0, w,
h)便是說明整個窗口,一般情況下總是如此,但是我們也是可以指定小于這個范圍的ViewPort的。事實上我隱瞞了很多細節(jié),這個函數(shù)必須和下面要講的gluOrtho2D函數(shù)一起用才能出現(xiàn)正確的結(jié)果。
gluOrtho2D:這個函數(shù)派生于OpenGL的glOrtho,它創(chuàng)建了一個正交的視景體(View
Volume),我們所看到的物體,都處在這個體中,四個參數(shù)分別代表了(left, right, bottom,
top),也就是豎直的左右邊界和水平的下上邊界;而近遠則是默認的(-1,
1),glOrtho有六個參數(shù)可以設(shè)定。這個體越大,我們看到的東西就越?。环粗吹降臇|西就越大。我知道這樣很難理解,打個比方就是一個六邊形的魚缸,這個函數(shù)定出了一個魚缸的大小,我們所看的東西呢,都在這個魚缸里面。
上面說glViewport要和gluOrtho2D一起用才能正確顯示是個什么意思呢?gluOrtho2D只管創(chuàng)建一個視體,而glViewport只管繪圖的范圍,如果視體是個正方體,而窗口是個長方體,直接繪制的結(jié)果會是什么呢?很明顯,整個視體里的東西都被拉長了,而一般我們viewport都是指明了窗口大小,自然只能修改視體來適應(yīng)各種不同的比例了。
修改代碼,拉伸窗口,查看最終的結(jié)果會是怎樣的。glMatrixMode:這個函數(shù)非常難以理解,但是又極其重要!這關(guān)系到了OpenGL中的“矩陣”的概念。矩陣……你是說黑客帝國么?好像很有趣誒~~
嗯嗯沒錯,矩陣是個偉大的東西,通過它,3D世界的所有維度都蜷曲到內(nèi)存中的一維數(shù)據(jù)里去了。這是一個有點兒抽象的概念但其實也沒什么特別的,OpenGL里有如下幾種矩陣:GL_MODELVIEW:模型觀察矩陣,表示物體的位置變化和觀察點的改變;
GL_PROJECTION:投影矩陣,描述如何將一個物體投影到平面上; GL_TEXTURE:紋理矩陣,描述紋理坐標的動態(tài)變化 …
我不想搬出一堆數(shù)字和大括號來說明矩陣的基本運算和應(yīng)用(好吧其實真實原因是我也不會:),也不會告訴你最后的ModelView矩陣是View矩陣與Model矩陣的乘積,更不會告訴你有g(shù)lRotate和glTranslate之流的函數(shù)來改變矩陣!暫時這么理解就好了,矩陣就是我們走路的方向,我們現(xiàn)在朝南走,看到的南邊的風景,然后說“向右拐”,現(xiàn)在看到西邊的風景了,再說“向后轉(zhuǎn)”,現(xiàn)在看到東邊的風景了。就是通過這樣可以累積的變換,我們把我們最初的一些數(shù)據(jù)變成了更復雜的東西表達了出來,轉(zhuǎn)了幾圈后也許有點糊涂了,用glLoadIdentity將當前指定的矩陣還原為最初的狀態(tài)。
5,參考頁面
PyOpenGL安裝
http://pyopengl.sourceforge.net/
用PyOpenGL叩開3D的心扉——OpenGL全解析(3)
http://eyehere.net/2011/learn-opengl-3d-by-pyopengl-3/
用PyOpenGL叩開3D的心扉——OpenGL全解析(5)
http://eyehere.net/2013/learn-opengl-3d-by-pyopengl-5/