OpenGL是乙個狀態機

2021-05-22 00:19:30 字數 3722 閱讀 4202

顏色、紋理座標、源因子和目標因子、光源的各種引數,等等,這些都是狀態,所以這一句話就包含了上面敘述的所有內容。

此外,「是否啟用了光照」、「是否啟用了紋理」、「是否啟用了混合」、「是否啟用了深度測試」等等,這些也都是狀態,也符合上面的描述: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...