第3章 計算機圖形軟件
圖形軟件分爲兩大類:
- 專用軟件包:CAD、建築等
- 通用軟件包:GL(Graphics Libray)、OpenGL、VRML(Virtual Reality Modeling Language)、Java2D和Java3D等。
座標使用
通常,在構造和顯示一個場景的過程中會使用幾個不同的笛卡爾座標參照系。首先在各自的參考系中構造每一對象的形狀。這些座標系稱爲建模座標系(modeling coordinate),有時也稱爲局部座標系(local coordinate)或主座標系(master coordinate)。一旦指定了單個物體的形狀,將對象放到稱爲世界座標系(world coordinate)的場景參照系的適當位置。
在描述好場景的所有部分之後,要將該場景的世界座標描述經各種處理變換到一個或多個輸出設備參照系來顯示,這個過程稱爲觀察流水線(viewing pipeline)。世界座標系的位置首先轉換到我們要對場景進行觀察所對應的觀察座標系(viewing coordinate),該轉換依據假想照相機的位置和方向來進行。然後,對象位置變換到該場景的一個二維投影,該投影對應我們在輸出屏幕上看到的結果,然後將該場景存入規範化座標系(normalized coordinate),其座標範圍從-1到1或者從0到1。
圖形經掃描轉換到光柵系統的刷新緩存中進行顯示。顯示設備的座標系稱爲設備座標系(device coordinate),或對視頻監視器而言爲屏幕座標系(screen coordinate)。
圖形功能
通用圖形軟件包爲用戶提供建立和管理圖形的各種功能,這些子程序可以按照它們是否處理輸出、輸入、屬性、變換、觀察、圖形分隔或一般的控制而進行分類。
圖形的基本構造塊稱爲圖形輸出單元(graphics output primitive)。它們包括字符串和幾何成分,如點、直線、曲線、填充區域(通常爲多邊形)以及由彩色陣列定義的形狀。此外,有些圖形軟件包提供對複雜形體(如球體、錐體和柱體)的顯示函數。生成輸出單元的函數提供了構造圖形的基本工具。
屬性(attribute)是輸出圖元的特性,也就是說,屬性描述了一個特定圖元是怎樣顯示出來的。包括顏色設定、線型或文件格式及區域填充圖案等。
利用對象形狀及其屬性的描述函數構建場景之後,圖形軟件包將選定視圖投影到輸出設備。**觀察變換(viewing transformation)**用來指定將要顯示的視圖、使用的投影類型及在輸出顯示區域出現的範圍。
輸入函數(input function)用於控制和處理來自這些交互設備的數據流。
圖形軟件包常常包含很多事務性認爲,如將顯示屏變成指定顏色及對參數進行初始化。我們可以將這類處理事務性任務的功能歸入控制操作(control operation)類。
軟件標準
標準化圖形軟件的最主要的目標是可移植性。
圖形函數定義爲獨立於任何程序設計語言的一組規範。語言綁定(language binding)則是爲特定的高級語言而定義的。給出該語言訪問各種圖形函數的語法。
其他圖形軟件包
OpenGL簡介
OpenGL基本函數庫用來描述圖元、屬性、幾何變換、觀察變換和進行很多其他的操作。
基本的OpenGL語法
OpenGL基本庫(OpenGL核心庫)的函數名要以gl爲前綴,並且函數名中每一個組成詞的第一個字母要大寫。
例如
glBegin, glClear, glCopyPixele, glPolygonMode
有些函數要求一個(或多個)變量用符號常量賦值,如參數名、參數的值或特定的模式。所以這些常量均以大寫字母GL開頭。單詞之間用下劃線分隔。
GL_2D GL_RGB GL_CCW GL_POLYGON GL_AMBIENT_AND_DIFFUSE
OpenGL函數也要求專門的數據類型。例如OpenGL函數的參數可以要求一個32位整數類型的值,OpenGL採用專門的內置數據類型名來描述數據類型:
GLbyte GLshort GLitn GLfloat GLdouble GLboolean
相關庫
除了OpenGL基本(核心)庫之外,還有一些用於處理專門操作的附加庫。OpenGL實用函數(OpenGL Utility,GLU)提供了一些例程,可以設置觀察和投影矩陣,利用線條和多邊形近似法來描述複雜對象,使用線性近似法顯示二次曲線和樣條曲線,處理表面繪製操作,已經完成其他的複雜任務。每一個OpenGL實現中都包括GLU庫,所有GLU函數名均爲前綴glu開頭。
OpenGL的X窗口系統擴充(OpenGL Extension to the X Window System, GLX)提供了一組以glx爲前綴的函數。Apple系統可使用Apple GL(AGL)接口進行窗口管理操作,該庫的函數名爲agl爲前綴,對於Microsoft的Windows系統,WGL系統提供了Windows到OpenGL的接口,這些函數以wgl爲前綴。Presentation Manager to OpenGL(PGL)是一個用於IBM OS/2的接口,使用pgl作爲庫函數的前綴。OpenGL實用函數工具包(OpenGL Utility Toolkit,GLUT)提供了與任意屏幕窗口系統進行交互的函數系統。GLUT庫函數以glut爲前綴。
使用GLUT進行顯示窗口管理
OepnGL使用庫的第一步就是初始化GLUT,該初始函數能處理命令行變量,但不需要在一個示例程序中使用參數。
glutInit(&argc, argv)
緊接着創建顯示窗口的標題
glutCreateWindow("An Example OpenGL Program");
顯示函數
glutDisplayFunc()
在函數的最後一個是
glutMainLoop()
它顯示初始圖並使用程序進入檢查鼠標或鍵盤等設備輸入的無窮循環中。
glutInitWindowPosition
可用來給出顯示窗口左上角初始位置,該位置使用以屏幕左上角爲原點的整數座標來表示。glutInitWindowSize(400,300)
表示設置窗口的大小爲
還可以使用glutInitDispalyMode
函數來設定顯示窗口的緩存和顏色模型等選項。該函數的變量使用符號化GLUT常量來賦值。例如glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB)
表示顯示窗口使用單個緩存且使用由紅、綠、藍(RGB)三元素組成的顏色模型來選擇顏色值。傳遞個該函數的常量可以利用邏輯或操作組合起來。
一個完整的OpenGL程序
本次學習使用Python來進行OpenGL的操作(C++配置太麻煩,而且只是學習,沒有必要難爲自己)。
如果直接使用conda進行安裝,運行程序的時候出現
OpenGL.error.NullFunctionError: Attempt to call an undefined function glutInit, check for bool(glutInit) before calling
後來直接在https://www.lfd.uci.edu/~gohlke/pythonlibs/#pyopengl
中下載相應的版本的pyopengl,然後使用pip安裝就可以使用了(注意64位電腦一定要安裝64位的包)。
pip install packagename.whl
from OpenGL.GL import *
from OpenGL.GLUT import *
from OpenGL.GLU import *
def init():
glClearColor(1.0, 1.0, 1.0, 0.0)
glMatrixMode(GL_PROJECTION)
gluOrtho2D(0.0, 200.0, 0.0, 150.0)
def lineSegment():
glClear(GL_COLOR_BUFFER_BIT)
glColor3f(0.0, 0.4, 0.2)
glBegin(GL_LINES)
glVertex2i(180, 15)
glVertex2i(10, 145)
glEnd()
glFlush()
if __name__ == "__main__":
glutInit()
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB)
glutInitWindowPosition(50, 100)
glutInitWindowSize(400, 300)
glutCreateWindow("An Example OpenGL Program")
init()
glutDisplayFunc(lineSegment)
glutMainLoop()
在上面是程序中,glClearColor(1.0, 1.0, 1.0, 0.0)
表示使用RGB顏色值將顯示窗口設定爲白色。這個函數的前面三個變量是紅、綠、藍三個顏色的分量設定爲1,得到了白色。第4個參數稱爲分顏色的值,表示作爲調和參數。用來爲兩個重疊對象確定結果顏色,如果爲表示完全透明的對象,如果爲1.0表示完全不透明的對象。
儘管glClearColor
命令將某個顏色賦給顯示窗口,但它不能讓顯示窗口在屏幕上出現。要使賦值的窗口得到顯示,必須引入下面的OpenGL函數:
glClear(GL_COLOR_BUFFER_BIT)
變量GL_COLOR_BUFFER_BIT是一個OpenGL符號變量,用來指定它是顏色緩存(刷新緩存)中的位置,giant緩存將使用glClearColor函數中指定的值來設定。
glColor3f(0.0, 0.4, 0.2)
glColor函數的後綴3f表示我們在指定三個RGB顏色分量時使用浮點數。這些值範圍爲
我們要顯示一條簡單的二維線段,需要告訴OpenGL怎樣將圖形投影到顯示窗口中,因爲在OpenGL中把生成二維線段看成生成三維線段的特例。儘管我們只要生成很簡單的二維線段,OpenGL還是完整的三維觀察操作來處理該圖形。
glMatrixMode(GL_PROJECTION)
gluOrtho2D(0.0, 200.0, 0.0, 150.0)
這表示使用正投影將世界座標系二維區域的內容映射到屏幕上,區域的座標值從0.0到200.0,座標值從0.0到150.0,只要在該矩形內定義的對象,都會出現在顯示窗口中。任何在座標範圍外的內容都不會顯示出來。
最後,要調用合適的函數來建立線段。
glBegin(GL_LINES)
glVertex2i(180, 15)
glVertex2i(10, 145)
glEnd()
程序定義一個從整數笛卡爾端點座標到的二維直線段(Python不要隨意縮進哦,會出現語法錯誤)。
glFlush()
強制執行由計算機系統存放在緩存中不同位置的OpenGL函數,其位置依賴於OpenGL的實現。
描述圖形的函lineSegment稱爲一個顯示回調函數(display callback function)。該函數由glutDisplayFunc
作爲在顯示窗口需要重新顯示時引入的函數來註冊。
同樣如果你想設置你的標題爲中文,那就可以直接將字符進行編碼爲gbk就可以了
glutCreateWindow("樣例".encode('gbk'))
OpenGL的出錯處理
OpenGL和GLU記錄錯誤的方法比較的簡單,當OpenGL發生在對基本庫子程序或GLU子程序的一次調用中有錯誤的,就在內部距離一個出錯編碼,而造成出錯的子程序被忽略(因此該錯誤不影響OpenGL的內部狀態,也不影響幀緩存的內容),但是OpenGL每次只記錄一個錯誤編碼,一旦出現一個出錯編碼,在你的程序明確查詢OpenGL出錯轉態之前不會再記錄另外的出錯碼。
code = glGetError()
如果返回的值等於OpenGL符號常數GL_NO_ERROR
,則表示沒有出現任何錯誤。
OpenGL基本庫定義了一些代表各種出錯編碼的符號常數。GLU庫也定義了一些出錯編碼,但其中多數使用沒有什麼意義的名字,比如GLU_NURBS_ERROR
等。
符號常數 | 含義 |
---|---|
GL_INVALID_ENUM | GLenum的參數超出範圍 |
GL_INVALID_VALUE | 數值參數超出範圍 |
GL_INCALID_OPERATION | 當前OpenGL狀態中有一個操作非法 |
GL_STACK_OVERFLOW | 該命令將引起棧向上溢出 |
GL_STACK_UNDERFLOW | 該命令將引起棧向下溢出 |
GL_OUt_OF_MEMORY | 沒有足夠的存儲空間可以用於執行命令 |
ode = glGetError()
code = gluErrorString(code)
print(code.decode('gbk'))
glutErrorString
返回的值指向位於GLU庫內部的一個字符串,這不是動態分配的字符串,所以不能由我們的程序重新分配。