OpenGL藍寶書源碼學習(九)第五章——紋理基礎篇

前言:

在學習超級寶典的源碼之前,很有必要先把整個章節通讀一遍,梳理一下知識點,理解一些概念的介紹和函數的用法,這樣在後面源碼學習的示例中才會得心應手。當然在學習第五章的每一個源碼示例還要與基礎知識串聯起來,鞏固學習,加強理解

一、原始圖像數據

前四章的學習,已經對點、線和三角形組合的圖形進行了渲染,也瞭解瞭如何能夠通過計算顏色值對它們的表面進行着色,以及在它們之間進行插值來模擬光照效果。但是爲了達到更加顯示的效果,還有一種非常棒的捷徑,就是紋理貼圖。紋理只是一種能夠應用到場景中的三角形的圖像數據,它通過經過過濾的紋理單元填充到實心區域。當然,紋理遠遠不止是圖像數據那麼簡單,它是大多數現代3D渲染算法的一個關鍵因素。

1、像素包裝

一幅圖像的每一行都應該從一種特定的字節對齊地址開始。OpenGL採用4個字節的對齊方式,這種方式適合於很多目前正在使用的系統。內存分配意圖對OpenGL來說非常重要,因爲在想OpenGL提交圖像數據或從OpenGL獲取圖像數據時,OpenGL需要知道我們想要在內存中對數據進行進行怎樣的包裝或解包裝。

使用下列函數改變或者恢復像素的存儲方式。

void glPixelStorei(GLenum pname,GLint param);

void glPixelStoref(GLenum pname,GLint param);

2、像素圖

在OpenGL核心版本中,我們無法直接講一個像素圖繪製到顏色緩衝區,但是可以使用下面的函數將顏色緩衝區的內容作爲像素圖直接讀取。

void glReadPixels(GLint x,GLint y,GLSizei width,GLSizei height,GLenum format,GLenum type,const void *pixels)

x和y值指定爲矩形左下角的窗口座標,然後再指定矩形的width和height值(像素值)

format指定pixel指向的數據元素的顏色佈局,如下表5-2格式:


type解釋參數*pixels指向的數據,他告訴OpenGL使用緩衝區中的什麼數據類型來存儲顏色分量,如下表5-3類型格式



*pixels是指向圖像數據的指針,它必須是合法的,並且必須包含足夠的存儲空間來存儲轉換後的圖像數據,否則會遇到嚴重的內存運行時異常。

3、包裝的像素格式

包裝的像素格式將顏色數據壓縮到了儘可能少的存儲位中,每個顏色通道的位置顯示在常數中。例如,格式爲第一個分量提供3位存儲空間,爲第二個分量也提供3位存儲空間,而爲第三個分量則提供了兩位存儲空間。請記住,指定的分量(紅、綠、藍和Alpha)的排列順序仍然是根據format參數確定的。這些分量從高位到低位進行排列。

帶有REV標誌的類型的是按照相反的排序方式。

對於glReadPixel函數來說,讀取操作在雙緩衝區渲染環境下將在後臺緩衝區進行,而在單緩衝區渲染環境在前臺緩衝區進行,可以使用下面的函數改變這些像素操作的源:

void glReadBuffer(GLenum mode);

模式參數可以取GL_FRONT,GL_BACK,GL_LEFT,GL_FRONT_LEFT,GL_FRONT_RIGHT,GL_BACK_LEFT,GL_BACK_RIGHT或是GL_NONE中的任意一個。

4、保存像素

GLTools庫中的gltWriteTGA函數從前臺顏色緩衝區中讀取顏色數據,並將這些數據存儲到一個Targa文件格式的圖像文件

5、讀取像素

GLbyte *gltReadTGABits(const char *szFileName,GLint *Width,GLint *iHeight,GLint *iComponents,GLenum *eFormat)

第一個參數是將要載入的Targa文件的文件名。Targa圖像格式是得到廣泛支持的通用圖像文件格式,與JPEG文件不同,JPEG文件(通常)以未經壓縮的格式存儲圖像。

此函數用來打開文件,然後讀入文件頭並進行語法分析,以確定文件的寬度、高度和數據格式。分量的數量可以是1個、3個或4個,分別爲亮度、RGB、或RGBA圖像。最後的參數是一個指向GLenum的指針,它接受圖像相應的GLenum圖像格式。如果函數條用成功,它會返回一個新定位到直接從文件中讀取的圖像數據的指針。如果沒找到文件,或者出現他去錯誤,函數則會返回NULL。

6、載入紋理

二、載入紋理

在幾何圖形中應用紋理貼圖時,第一個必要步驟就是將紋理載入內存。一旦被載入,這些紋理就會成爲當前紋理狀態。有三個OpenGL函數最經常用來從存儲器緩衝區中載入(比如說,從一個磁盤文件中讀取)紋理數據。

這些函數實際上有同一個函數glTextImage派生出來的,支持一維、二維和三維。

注意:OpenGL會在調用這些函數中的一個時從data中複製紋理信息。這種數據複製會有很大的開銷,後面學習如何減輕。

target變量分別爲GL_TEXTURE_1D、GL_TEXTURE_2D、GL_TEXTURE_3D。也可以使用代理紋理,方法是指定GL_PROXY_TEXTURE_1D、GL_PROXY_TEXTURE_2D、GL__PROXY_TEXTURE_3D,並使用glTexParameter函數提取代理查詢的結果。後面學習。

level參數指定了這些函數所加載的mip貼圖層次。後面學習。對於非mip貼圖的紋理,總是把這個參數設置爲0。

internalformat參數告訴OpenGL在每個紋理單元中存儲多少顏色成分,並在可能的情況下說明這些成分的存儲大小,以及是否希望對紋理進行壓縮。

常用的紋理內部格式

width、height、depth參數指定了被加載紋理的寬度、高度和深度。注意,這些值必須是2的整數次方,這一點非常重要。

border參數允許爲紋理貼圖指定一個邊界寬度。紋理邊界允許對邊界處的紋理單元進行額外的設置,來對它的寬度、高度和深度進行擴展。

最後三個參數format、type和data和用於把圖像數據放入顏色緩衝區的glDrawPixels函數的對應參數相同。format和type與上面表5-2和表5-3對應。

1、使用顏色緩衝區

一維和二維紋理也可以從顏色緩衝區加載數據。可以從顏色緩衝區讀取一幅圖像,並通過下面的這兩個函數將它作爲一個新的紋理使用。



這兩個函數的操作類似於glTextImage,但在這裏x和y在顏色緩衝區中指定了開始讀取紋理數據的位置。源緩衝區時通過glReadBuffer函數設置的。請注意,並不存在glCopyTexImage3D,因爲我們無法從2D顏色緩衝區獲取體積數據。顏色緩衝區是2D的,不存在一種對應方法將一幅2D彩色圖像作爲一個3D紋理的來源。

2、更新紋理

重新加載新紋理可能會成爲性能瓶頸,替換一個紋理圖像常常要比直接使用glTexImage重新加載一個新紋理快得多,函數glTexSubImage用於替換


絕大部分參數鬥魚glTexImage函數所使用的參數準確對應。xOffset、yOffset個zOffset參數指定了在原來的紋理貼圖中開始替換紋理數據的偏移量。width、height和depth參數指定了“插入”到原來那個紋理中的新紋理的寬度、高度和深度。

最後一組函數允許從顏色緩衝區讀取紋理,並插入或替換原來紋理的一部分。下面的函數是glCopyTexSubImage函數的變型:



這裏,我們可以使用glCopyTexSubImage3D函數,在一個三維紋理中使用顏色緩衝區的數據來設置它的一個紋理單元平面。

3、紋理對象

紋理圖像本身就是所謂的紋理狀態的一部分。紋理狀態包含了紋理圖像本身和一組紋理參數,這些參數控制過濾和紋理座標的行爲。像glTexImage和glTexSubImage這樣的函數調用所耗費的內存特別多。在紋理之間進行切換或者重新加載不同的紋理圖像可能會是開銷很大的操作。紋理對象允許我們一次加載一個以上的紋理狀態(包括紋理圖像),以及在他們之間進行快速切換。紋理狀態是由當前綁定的紋理對象維護的,而紋理對象是由一個無符號整數標識的。

1)分配紋理

void glGenTextures(GLSizei n,GLuint *textures);

指定紋理對象的數量和一個指針,指針指向一個無符號整型數組(由紋理對象標識符填充)。

2)綁定紋理

void glBindTextures(GLenum target,GLuint texture);

target必須是GL_TEXTURE_1D、GL_TEXTURE_2D或GL_TEXTURE_3D,texture參數則是需要綁定的特定紋理對象。此後,所有的紋理加載和紋理參數設置只是影響當前綁定的紋理對象。

3)刪除紋理對象

void glDeleteTextures(GLSizei n ,GLuint *textures);

參數和glGenTextures函數的參數具有相同的意義。多次調用glDeleteTexture可能會造成一些延遲。

4)紋理對象測試

GLboolean glIsTexture(GLuint texture);

如果texture參數是一個以前已經分配的紋理對象名,那麼這個函數會返回GLTRUE,否則它就返回GL_FALSE。

三、小結

加載紋理只是在幾何圖形上應用紋理的第一步。最低限度我們必須同時提供紋理座標,並設置紋理座標環繞模式和紋理過濾。最後,可以選擇對紋理進行Mip貼圖,以提高紋理貼圖性能和視覺質量。在後面的學習中,通過源碼的學習來掌握紋理的應用。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章