閱讀727 返回首頁    go 技術社區[雲棲]


opengl編程學習筆記(四)(紋理映射)(結合nvdia OpenglSDk 的nvimage類)

Opengl中的紋理映射(texture mapping)是它的精華部分,在opengl的書中這一章也是所有章節中最為多的,在所有的opengl技術中,關於紋理映射的技術也是最多最豐富的,同時也是被開發人員使用各種trick最多的,因為紋理映射可以做很多的工作。在opengl的書中關於紋理映射有著很多的高級話題,而在這裏,我隻記錄關於紋理映射的基礎。

 

在紋理矩陣中的一個元素被稱為texel,紋理矩陣可是是一維、二維、三維,texel也可以有rgba分量。紋理映射不能工作在索引顏色模式下

紋理映射的一般步驟:

產生紋理物體的名字glgentexture

綁定這個紋理物體glbind

glTexParameter設定紋理的各種參數

為紋理物體指定紋理gltextureimage

打開各種開關

在繪製時為繪製物體產生紋理坐標

 

1.       產生紋理物體:在opengl中,紋理映射是一個狀態,同一時刻隻能有一種紋理活動,但是我們的程序中通常需要定義大量的不同的紋理,在這些紋理間需要隨時的切換,紋理物體就好比一個存儲一種紋理狀態的變量,當程序中一個紋理物體被綁定後,所有對紋理的參數的設定都是改變當前這個紋理物體代表的紋理映射的。需要先用glgentexture來產生一個紋理物體的名字。然後用glbind來綁定這個紋理後,就激活了這個紋理,這是程序中的活躍紋理是當前這個紋理,對紋理各種屬性的修改也是對這個紋理,直到再綁定另外一個紋理。

2.       glTexParameteri()指定紋理的各種屬性:這些屬性包括:

GL_TEXTURE_MIN/MAG_FILTER 當紋理貼圖需要被放大或縮小時的插值方式

                               此屬性通常必須要指定,否則可能看不到貼圖

GL_TEXTURE_MIN/MAG_LOD  設定紋理的最小和最大LOD級別(可為正負)

GL_TEXTURE_MAX_LOD 設定最小的那個mipmap的序號

GL_TEXTURE_MAX_LEVE設定最大的那個mipmap的序號

GL_TEXTURE_WRAP_S/T/R 設定紋理坐標的擴展方式,在這個參數下,可以使用的擴展方式有:GL_CLAMP(夾緊), GL_CLAMP_TO_BORDER, GL_CLAMP_TO_EDGE, GL_MIRRORED_REPEAT, or GL_REPEAT(重複),各種鋪陳方式的效果如圖:

 

GL_TEXTURE_BORDER_COLOR 設置紋理的邊界(BORDER)顏色

GL_TEXTURE_PRIORITY 設置紋理在GPU緩存中的優先級,通常為了性能考慮,紋理會被放在GPU的緩存中,但是存放的數量是有限的,這個參數可以設定在GPU中的存放優先級

GL_GENERATE_MIPMAP 設定當base mipmap改變後是否更新所有的mipmap

 

GL_TEXTURE_COMPARE_MODE GL_TEXTURE_COMPARE_FUNCGL_DEPTH_TEXTURE_MODE屬性是專門為陰影貼圖(shadow map)使用的,將在後麵講解

3使用glTexEnv (   GLenum       target, GLenum    pname, GLfloat    param);來設定紋理值是怎麼樣起作用的:

glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,)來指定紋理的顏色與物體的原來顏色的混合方式,有GL_ADD, GL_MODULATE, GL_DECAL, GL_BLEND, GL_REPLACE, or GL_COMBINE.

4產生紋理:

  前麵設定好紋理及生成方式的各種屬性後,就該實際的產生紋理了,產生紋理在opengl中有一下幾種方式:

  從內存數據產生紋理:這是最直接的生成紋理的方式,就是用void glTexImage2D(         GLenum          target,

        GLint      level,

        GLint      internalFormat,

        GLsizei  width,

        GLsizei  height,

        GLint      border,

        GLenum          format,

        GLenum          type,

          const GLvoid *     data)函數,從內存大數據構建紋理,通常你可以讀入一個圖像然後得到這個圖像的數據作為data

  直接產生LOD紋理:用gluBuild2DMipmaps可以從一片內存數據構建一個LOD的紋理

  從幀緩存產生紋理:glCopyTexImage2D可以將當前的一塊幀緩存作為紋理,使用它時glPixelStore是起作用的。

5為繪製物體產生紋理坐標

產生紋理坐標有兩種方式:

glTexCoord指定當前的紋理坐標,它時一個狀態函數,設定後如果不改變,所有之後的繪製的頂點的紋理坐標都是它

自動生成紋理:opengl有著強大的自動為物體生成紋理的機製,生成方式是依靠glTexGeni函數:自動生成紋理的過程是:

  glTexGeni(GL_S,GL_TEXTURE_GEN_MODE)設定生成紋理的平麵參考方式

它可以是GL_EYE_LINEAR或者GL_OBJECT_LINEAR,即用視平麵或者物體平麵做參考。

  glTexGenfv(GL_S,GL_EYE_PLANE,param)來設定這個平麵,param{p1,p2,p3,p4},最後生成紋理坐標為p1x0 + p2y0 + p3z0 + p4w0,這個param其實就是平麵方程的參數

  視平麵與物體平麵的區別就是視平麵中紋理坐標是相對於視坐標係的,視角變了紋理坐標也就隨著變了

兩種方式產生的紋理的區別如圖:

 

6紋理矩陣:紋理也是一個矩陣,也可以用opengl中的各種矩陣操作來改變它,隻不過在修改紋理矩陣的時候要先使用glmatrixmode(GL_TEXTURE)來切換到紋理矩陣

7需要打開的開關

在做紋理映射的時候,需要打開這些開關

最開始要打開

glEnable(GL_TEXTURE_1D/2D/CUBE_MAP);

如果使用了自動產生紋理坐標就還要打開

glEnable(GL_TEXTURE_GEN_S);

glEnable(GL_TEXTURE_GEN_T);

glEnable(GL_TEXTURE_GEN_R);

 

 

高級話題:

Cube map:cubemap是假想在繪製物體是可以反光的,它四周(六個麵)有一個空間,然後將這六個麵的圖像映射到這個物體上,最後會產生這個物體反射空間景物的效果,常常可以提高繪製的真實感,CUBE MAP的步驟為:

glBindTexture(GL_TEXTURE_CUBE_MAP,cubMapTextureName)將一個紋理物體綁定到CUBE MAP紋理上;

glTexGeni(GL_S/T/R,GL_TEXTURE_GEN_MODE,…)為紋理物體產生紋理坐標,這裏的產生方式隻能是GL_REFLECTION_MAP或者GL_NORMAL_MAP,這兩種的效果區別為:

reflection

normal

glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X,0,GL_RGB…)為每一個麵選擇那個麵的圖像數據,一共要貼6個麵

注意:在opengl中默認的用這種方式為物體產生坐標是在視坐標係中的,也就是說如果視角轉動,紋理不會改變,如果想更加的真是,就應該讓這個坐標在世界坐標係下,應該將這個紋理矩陣乘上視矩陣的逆矩陣。

 

Shadow map:

為了增強真實感,在繪製中產生陰影是及其重要的,其中一個重要的生成陰影的方法就是使用陰影貼圖。陰影貼圖的技術思想為:

首先將視角定位到光源的位置,視角的朝向為光源的朝向,在這個位置截取當前幀緩存中的深度值作為後麵的紋理貼圖。

然後為物體產生紋理坐標,產生的方式是按照模型為參考,參考麵的參數就是這是modelview矩陣的逆矩陣,這時產生的紋理坐標的R就是該點的深度值。

最後設定glTexParameteriGL_DEPTH_TEXTURE_MODEGL_LUMINANCE),它將最後用一個灰度值來繪製點的紋理顏色

設定glTexParameteriGL_TEXTURE_COMPARE_MODE)為GL_COMPARE_R_TO_TEXTURE,也就是比較該店的R坐標,它此時已經代表了該點的Z

設定glTexParameteriGL_TEXTURE_COMPARE_FUNC)為LEQUAL,也就是用該店的R坐標與此時深度圖的Z值比較,如果比Z深,則用1來繪製,就是陰影了。

最後將視角切換回來

 

 

使用nvdia openg sdk nvimage類做輔助:

NVdia OpenGl SDK中的nvImage類封裝了一個圖片類,它專門用來做opengl中的貼圖,這個類作用很大,因為我們在處理紋理映射時,通常要用一些圖片文件來做貼圖,而讀取保存這些圖片的數據通常很費力氣,這個類為我們提供了一些輔助的功能。它的幾個主要功能接口如下:

1.       它可以直接讀取解析的圖片格式為png hdr(這是一種高動態範圍圖片,圖片質量相當高,顏色級範圍很高,非常適用高真實感的cubemap或者天空盒等) dds(D3D的一種壓縮圖片)

2.       它可以得到當前圖像的尺寸、深度、mipmaplevelfacesFormatInternalFormat這些屬性

3.       他可以知道當前圖片是否可以做一個大的cubemap

4.       他可以將一個cubemap的交叉圖像(就是將6麵繪製在一張圖片上的圖像)轉變為6faceCUBEMAP,然後可以單獨得到各個麵,注意:這個類隻可以支持寬高比為34的交叉圖像,並且寬高為2的冪的3倍和4倍。

5.       他可以將當前數據寫入PNG圖片文件。

最後更新:2017-04-02 00:06:46

  上一篇:go 關於百度與GOOLE優化
  下一篇:go 不要重複發明輪子:C++重用的5重境界(5)——消息通信(完結篇)