顏色、紋理座標、源因子和目標因子、光源的各種引數,等等,這些都是狀態,所以這一句話就包含了上面敘述的所有內容。
此外,「是否啟用了光照」、「是否啟用了紋理」、「是否啟用了混合」、「是否啟用了深度測試」等等,這些也都是狀態,也符合上面的描述:opengl會保持狀態,除非我們呼叫opengl函式來改變它。
取得opengl的當前狀態
opengl儲存了自己的狀態,我們可以通過一些函式來取得這些狀態。
首先來說一些啟用/禁用的狀態。
我們通過glenable來啟用狀態,通過gldisable來禁用它們。例如:
glenable(gl_depth_test);
glenable(gl_blend);
glenable(gl_cull_face);
glenable(gl_lighting);
glenable(gl_texture_2d);
可以用glisenabled函式來檢測這些狀態是否被開啟。例如:
glisenabled(gl_depth_test);
glisenabled(gl_blend);
glisenabled(gl_cull_face);
glisenabled(gl_lighting);
glisenabled(gl_texture_2d);
如果狀態是開啟的,則glisenabled函式返回gl_true(這是乙個不為零的常量,一般被定義為1);否則返回gl_false(這是乙個常量,其值為零)
我們可以在程式裡面寫:
if( glisenabled(gl_blend) )
else
再看其它型別的狀態。
比如當前顏色,其值是四個浮點數,當前設定的直線寬度,其值是乙個浮點數,當前的視口(viewport,參見第五課),其值是四個整數。
為了取得整數型別、浮點數型別的狀態,opengl提供了glgetbooleanv, glgetintegerv, glgetfloatv, glgetdoublev這四個函式。呼叫函式時,指定需要得到的狀態的名稱,以及需要將狀態值存放到的位置(乙個指標),則這四個函式可以把狀態值存放到指標所值位置。例如:
// 取得當前的直線寬度
glfloat lw;
glgetfloatv(gl_line_width, &lw);
// 取得當前的顏色
glfloat cc[4];
glgetfloatv(gl_current_color, cc);
// 取得當前的視口
glint viewport[4];
glgetintegerv(gl_viewport, viewport);
說明:1. 注意元素的個數。比如gl_line_width狀態只有乙個值,而gl_current_color有四個值。應該小心的定義變數或者陣列,避免下標越界。
2. 使用四個不同的函式,同一種狀態也可以返回為不同型別的值。比如要得到當前的顏色,一般可以返回glfloat型別或者gldouble型別。**如下:
glfloat cc[4];
gldouble dcc[4];
glgetfloatv(gl_current_color, cc);
glgetdoublev(gl_current_color, dcc);
glgetbooleanv, glgetintegerv, glgetfloatv, glgetdoublev這四個函式可以得到opengl中多數的狀態,但是還有一些狀態不便用這四個函式來取得。比如光源的狀態,因為可能有多個光源,所以不可能使用類似glgetfloatv(gl_light_position, pos);這樣的方法來得到光源位置。為了解決這個問題,opengl專門提供了glgetlight*系列函式,來取得光源的狀態。
類似的,還有glgetmaterial*, glgettexparameter*等,每個函式都有自己的適用範圍。
設定opengl狀態
呵呵,讀者可能會有疑問。既然有get***這樣的函式來取得opengl的狀態,那麼為什麼沒有set***這樣的函式來設定opengl狀態呢?
答案很簡單,因為opengl已經提供了大量的函式來設定狀態了:glcolor*, glmaterial*, glenable, gldisable, 等等,大多數opengl函式都是用來設定opengl狀態的,因此不需要再設計乙個set***函式來設定opengl狀態。
從「狀態機」的角度來看。狀態機根據輸入來修改自己的狀態,而不是由外界直接修改自己的狀態。所以不設定set***這樣的函式,也是很合理的。
opengl工作流程
教程都放到第十三課了,但是我一直沒有對「工作流程」這種東西做過說明。opengl是按照什麼樣的流程來進行工作的呢?下面的可以簡要的說明一下:
宣告:該來自www.opengl.org,該是《opengl程式設計指南》一書的附圖,由於該書的舊版(第一版,2023年)已經流傳於網路,我希望沒有觸及到版權問題。
因為中的文字是英語,這裡還翻譯一下。說明文字也夾雜在翻譯之中了。
1. vertex data: 頂點資料。比如我們指定的顏色、紋理座標、法線向量、頂點座標等,都屬於頂點資料。
2. pixel data: 畫素資料。我們在繪製畫素、指定紋理時都會用到畫素資料。
3. display list: 顯示列表。可以把呼叫的opengl函式儲存起來。(參見第八課)
4. evaluators: 求值器。這個我們在前面的課程中沒有提到,以後估計也不太會提到。利用求值器可以指定貝賽爾曲線或者貝賽爾曲面,但是實際上還是可以理解為指定頂點、指定紋理座標、指定法線向量等。
5. per-vertex operations and primitive assembly: 單一的頂點操作以及圖元裝配。首先對單一的頂點進行操作,比如變換(參見第五課)。然後把頂點裝配為圖元(圖元就是opengl所能繪製的最簡單的圖形,比如點、線段、三角形、四邊形、多邊形等,參見第二課)
6. pixel operations: 畫素操作。例如把記憶體中的畫素資料格式轉化為圖形硬體所支援的資料格式。對於紋理,可以替換其中的一部分畫素,這也屬於畫素操作。
7. rasterization: 光柵化。頂點資料和畫素資料在這裡交匯(可以想像成:頂點和紋理,一起組合成了具有紋理的三角形),形成完整的、可以顯示的一整塊(可能是點、線段、三角形、四邊形,或者其它不規則圖形),裡面包含若干個畫素。這一整塊被稱為fragment(片段)。
8. per-fragment operations: 片段操作。包括各種片段測試(參見第十二課)。
9. framebuffer: 幀緩衝。這是一塊儲存空間,顯示裝置從這裡讀取資料,然後顯示到螢幕。
10. texture assembly: 紋理裝配,這裡我也沒怎麼弄清楚:(,大概是說紋理的操作和畫素操作是相關的吧。
說明:中實線表示正常的處理流程,虛線表示資料可以反方向讀取,比如可以用glreadpixels從幀緩衝中讀取畫素資料(實際上是從幀緩衝讀取資料,經過畫素操作,把顯示裝置中的畫素資料格式轉化為記憶體中的畫素資料格式,最終成為記憶體中的畫素資料)。
小結本課是枯燥的理論知識。
opengl是乙個狀態機,它維持自己的狀態,並根據使用者呼叫的函式來改變自己的狀態。根據狀態的不同,呼叫同樣的函式也可能產生不同的效果。
可以通過一些函式來獲取opengl當前的狀態。常用的函式有:glisenabled, glgetbooleanv, glgetintegerv, glgetfloatv, glgetdoublev。
opengl的工作流程,輸入畫素資料和頂點資料,兩種資料分別操作後,通過光柵化,得到片段,再經過片段處理,最後繪製到幀緩衝區。繪製的結果也可以逆方向傳送,最終轉化為畫素資料。
OpenGL 學習2 OpenGL 狀態機
1 狀態變數型別是一些c資料型別的 typedef,有 glfloat,glboolean,glint,gluint 等等。2 狀態變數 狀態變數 讀取設定 兩種狀態變數 glisenabled gldisable 其他狀態變數 glget 大部分函式 3gl fill faceglpushattr...
人生就是乙個狀態機
從出生到死亡人生走的是乙個過程。從巨集觀來看,人分為幼年 青年 中年和老年 從微觀來看,人每天吃飯 睡覺 學習 工作和娛樂。古語有云 良田千傾不過一日三餐,廣廈萬間只睡臥榻三尺 沒必要我一己私利而貪得無厭。而我看來人生就如同乙個大型狀態機。人生的狀態機從大的方面看,它的輸入為時間,輸出為做出的成果,...
乙個簡單的狀態機總結
工作中乙個簡單的狀態機實現,總結如下。定義狀態 public enum qstate public int getcode public enum vstate public int getcode public enum state public int getcode public int ge...