天天看點

OpenGL--進階紋理知識

目錄(?)[+]

矩形紋理

紋理目标為GL_TEXTURE_RECTANGLE。 

首選,矩形紋理不能進行Mip貼圖; 

然後,矩形紋理不是标準化的(實際上是對像素尋址) 

最後,紋理坐标不能重複,并且不支援紋理壓縮

加載矩形紋理

bool LoadTGATextureRect(const char *szFileName, GLenum minFilter, GLenum magFilter, GLenum wrapMode)
    {
    GLbyte *pBits;
    int nWidth, nHeight, nComponents;
    GLenum eFormat;

    // 讀入紋理位
    pBits = gltReadTGABits(szFileName, &nWidth, &nHeight, &nComponents, &eFormat);
    if(pBits == NULL) 
        return false;

    glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_S, wrapMode);
    glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_T, wrapMode);

    glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MIN_FILTER, minFilter);
    glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MAG_FILTER, magFilter);

    glPixelStorei(GL_UNPACK_ALIGNMENT, );
    glTexImage2D(GL_TEXTURE_RECTANGLE, , nComponents, nWidth, nHeight, ,
                 eFormat, GL_UNSIGNED_BYTE, pBits);

    free(pBits);

    return true;
    }           
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

使用矩形紋理

加載矩形紋理:

glBindTexture(GL_TEXTURE_RECTANGLE, uiTextures[]);
    LoadTGATextureRect("OpenGL-Logo.tga", GL_NEAREST, GL_NEAREST, GL_CLAMP_TO_EDGE);           
  • 1
  • 2

對矩形紋理投影矩陣的設定:

M3DMatrix44f mScreenSpace;
m3dMakeOrthographicMatrix(mScreenSpace, , , , , -, );           
  • 1
  • 2

設定矩形紋理從0.0到标志寬度或者高度範圍内的紋理坐标:

int x = ;    int y = ;    int width = ;    int height = ;   logoBatch.Begin(GL_TRIANGLE_FAN, , );

        // Upper left hand corner
        logoBatch.MultiTexCoord2f(, , height);
        logoBatch.Vertex3f(x, y, );

        // Lower left hand corner
        logoBatch.MultiTexCoord2f(, , );
        logoBatch.Vertex3f(x, y - height, );

        // Lower right hand corner
        logoBatch.MultiTexCoord2f(, width, );
        logoBatch.Vertex3f(x + width, y - height, );

        // Upper righ hand corner
        logoBatch.MultiTexCoord2f(, width, height);
        logoBatch.Vertex3f(x + width, y, );

    logoBatch.End();           
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

矩形紋理的貼圖着色器需要将采樣器從sampler2D改變成samplerRect類型:

// Rectangle Texture (replace) Shader
// Fragment Shader
// Richard S. Wright Jr.
// OpenGL SuperBible
#version 140

out vec4 vFragColor;

uniform sampler2DRect  rectangleImage;

smooth in vec2 vVaryingTexCoord;

void main(void)
    { 
    vFragColor = texture(rectangleImage, vVaryingTexCoord);
}           
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

立方體貼圖

立方體貼圖是作為一個單獨的由組成立方體6個面的6個正方形的2D圖像組成的紋理對象看待。

加載立方體貼圖

立方體貼圖新增了以下6個值,這些值可以傳遞到glTexImage2D: 

GL_TEXTURE_CUBE_MAP_POSITIVE_X,GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 

GL_TEXTURE_CUBE_MAP_POSITIVE_Y,GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 

GL_TEXTURE_CUBE_MAP_POSITIVE_Z,GL_TEXTURE_CUBE_MAP_NEGATIVE_Z. 

例如,要加載x軸正方向的貼圖:

glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X,,GL_RGBA,iWidth,iHeight,,GL_RGBA,GL_UNSIGNED_BYTE,pImage);           
  • 1

建立天空盒

例如,我們建立一個在每個方向到原點距離都為20個機關長度的立方體:

gltMakeCube(cubeBatch,f);           
  • 1

然後使用如下着色器對從立方體的中心指向每個角的向量标準化: 

立方體貼圖頂點着色器

// Skybox Shader
// Vertex Shader
// Richard S. Wright Jr.
// OpenGL SuperBible
#version 130

// Incoming per vertex... just the position
in vec4 vVertex;

uniform mat4   mvpMatrix;  // Transformation matrix

// Texture Coordinate to fragment program
varying vec3 vVaryingTexCoord;


void main(void) 
    {
    // Pass on the texture coordinates 
    vVaryingTexCoord = normalize(vVertex.xyz);

    // Don't forget to transform the geometry!
    gl_Position = mvpMatrix * vVertex;
}           
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

立方體貼圖檔段着色器

// Skybox Shader
// Fragment Shader
// Richard S. Wright Jr.
// OpenGL SuperBible
#version 130

out vec4 vFragColor;

uniform samplerCube  cubeMap;

varying vec3 vVaryingTexCoord;

void main(void)
    { 
    vFragColor = texture(cubeMap, vVaryingTexCoord);
}           
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

最後消除立方體邊緣的縫隙:

glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);           
  • 1

建立反射

首先必須使用表面法線和指向頂點的向量在着色器中建立一個視覺坐标系中的反射向量。另外,為了獲得一個真實的反射,還要考慮照相機的方向。從GLFrame類中提取照相機的旋轉矩陣并進行轉置。然後将其作為統一值,與另一個變換矩陣(用來與前述的反射向量進行旋轉,這個反射實際上就是立方體貼圖紋理坐标)一起提供給着色器。

// Reflection Shader
// Vertex Shader
// Richard S. Wright Jr.
// OpenGL SuperBible
#version 130

// Incoming per vertex... position and normal
in vec4 vVertex;
in vec3 vNormal;

uniform mat4   mvpMatrix;
uniform mat4   mvMatrix;
uniform mat3   normalMatrix;
uniform mat4   mInverseCamera;

// Texture coordinate to fragment program
smooth out vec3 vVaryingTexCoord;

void main(void) 
    {
    // Normal in Eye Space
    vec3 vEyeNormal = normalMatrix * vNormal;

    // Vertex position in Eye Space
    vec4 vVert4 = mvMatrix * vVertex;
    vec3 vEyeVertex = normalize(vVert4.xyz / vVert4.w);

    // Get reflected vector
    vec4 vCoords = vec4(reflect(vEyeVertex, vEyeNormal), );

    // Rotate by flipped camera
    vCoords = mInverseCamera * vCoords;
    vVaryingTexCoord.xyz = normalize(vCoords.xyz);

    // Don't forget to transform the geometry!
    gl_Position = mvpMatrix * vVertex;
}           
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

多重紋理

片段着色器中的單個統一值是我們将要綁定到的紋理單元的索引,我們可以對實作進行查詢,來檢視支援的紋理單元數量:

Glint iUnits;
glGetIntegerv(GL_MAX_TEXTURE_UNITS,&iUnits);           
  • 1
  • 2

我們可以通過調用以紋理單元辨別符為變量的glActiveTexture來改變目前紋理單元:

glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D,textureID);           
  • 1
  • 2

多重紋理坐标

在調用以nTextureUnits為參數的Begin函數時,我們最多可以指定4組紋理坐标:

void GLBatch::Begin(GLenum primitive,GLuint nVerts,GLuint nTextureUnits=);           
  • 1

CopyTexCoordData2f會一次複制整個一組紋理坐标:

void GLBatch::CopyTexCoordData2f(M3DVector2f *vTexCoords,GLuint uiTextureLayer);           
  • 1

而下面的方法則會每次提供紋理一個頂點的接口,速度較慢:

void GLBatch::MultiTexCoord2f(GLuint texture,GLclampf s,GLclampf t);
void GLBatch::MultiTexCoord2fv(GLuint texture,M3DVector2f vTexCoord);           
  • 1
  • 2

點精靈(點塊紋理)

使用點精靈,我們可以通過繪制一個3D點将一個2D紋理圖像顯示在螢幕的任意位置上。 

店精靈允許我們通過發送單個3D頂點,渲染一個完美對其的紋理2D多邊形,他所需要的帶寬隻有為四邊形發送4個頂點所需帶寬的四分之一,并且不需要用戶端的矩陣邏輯來保持3D四邊形與照相機的對其。

使用點

在用戶端,我們需要做的訓示簡單地綁定一個2D紋理;

// SpaceFlight Shader
// Fragment Shader
// Richard S. Wright Jr.
// OpenGL SuperBible
#version 130

out vec4 vFragColor;

in vec4 vStarColor;

uniform sampler2D  starImage;

void main(void)
    { 
    vFragColor = texture(starImage, gl_PointCoord) * vStarColor;
}           
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

點大小

有兩種方式可以設定點大小。第一種方式是glPointSize函數:

void glPointSize(GLfloat size);           
  • 1

我們也可以在頂點着色器中用程式設定點大小。首先啟用點大小模式:

glEnable(GL_PROGRAM_POINT_SIZE);           
  • 1

然後,在我們的低昂點程式中,可以設定一個内建變量gl_PointSize,這個變量确定了點的最終光栅化大小。這通常用來根據點的距離來确定它的大小。

點參數

通過glPointParameter函數,我們可以對店精靈的幾個特性進行微調。将GL_POINT_SPRITE_COORD_ORIGIN參數設定為GL_LOWER_LEFT,可以将紋理坐标系的原點放置在點的左下角,點精靈的預設方向為GL_UPPER_LEFT

glPointParameteri(GL_POINT_SPRITE_COORD_ORGIN,GL_LOWER_LEFT);           
  • 1

異形點

我們可以在片段着色器中使用discard關鍵字來丢棄位域我們想要的點形狀範圍之外的片段,進而建立出非正方形的點。

vec2 p=gl_PointCoord*-vec2();
if(dot(p,p)>)
    discard;           
  • 1
  • 2
  • 3

點的旋轉

要讓點旋轉,我們隻需在片段着色器中建立一個2D旋轉矩陣,并用它乘以gl_PointCoord使它圍繞z軸進行旋轉。旋轉的角度可以從頂點着色器或者集合着色器中作為一個插值變量傳遞到片段着色器。

紋理數組

在紋理數組中,我們可以将整個數組的紋理圖縣綁定到一個紋理對象上,然後阻礙着色器中對它們進行檢索,這樣就大大增加了着色器可用的文禮書局的數量。

加載2D紋理數組

紋理數組添加了兩個新的紋理對象作為大多數文理管理函數的有效參數,他們是GL_TEXTURE_1D_ARRAY和GL_TEXTURE_2D_ARRAY。

GLuint  moonTexture;
……
    glGenTextures(, &moonTexture);
    glBindTexture(GL_TEXTURE_2D_ARRAY, moonTexture);           
  • 1
  • 2
  • 3
  • 4

紋理參數、環繞模式和過濾器的情況也是如此:

glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);           
  • 1
  • 2
  • 3
  • 4

對于2D紋理數組來說,我們使用管理TexImageD函數來加載紋理資料:

void glTexImage3D(GLenum target,Glint level,Glint internalformat,GLsizei width,GLsizei height,GLsizei depth,Glint border,GLenum format,GLenum type,void *data);           
  • 1

然後,我們使用glTexSubImageXD函數族來更新紋理。例如要保留29個64X64的RGBA圖像,代碼應如下所示:

glTexImage3D(GL_TEXTURE_2D_ARRAY,,GL_RGBA,,,,,GL_BGRA,GL_UNSIGNED_BYTE,NULL);           
  • 1

紋理數組索引

在進行渲染前,下面的代碼會在頂點着色器中設定恰當的統一值:

float fTime = timer.GetElapsedSeconds();
    fTime = fmod(fTime, );
    glUniform1f(locTimeStamp, fTime);

moonBatch.Draw();           
  • 1
  • 2
  • 3
  • 4
  • 5

在頂點着色器中,我們将包含經過實踐的統一值放在vec3的p變量中在随後的片段着色器中使用:

// MoonShader
// Vertex Shader
// Richard S. Wright Jr.
// OpenGL SuperBible
#version 130

in vec4 vVertex;
in vec4 vTexCoords;

uniform mat4 mvpMatrix;
uniform float fTime;

smooth out vec3 vMoonCoords;

void main(void) 
    { 
    vMoonCoords.st = vTexCoords.st;
    vMoonCoords.p = fTime;

    gl_Position = mvpMatrix * vVertex;
}           
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

通路紋理數組

// MoonShader
// Fragment Shader
// Richard S. Wright Jr.
// OpenGL SuperBible
#version 130

out vec4 vFragColor;

uniform sampler2DArray moonImage;

smooth in vec3 vMoonCoords;

void main(void)
   { 
   vFragColor = texture2DArray(moonImage, vMoonCoords);
   }           
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

紋理代理

下面方法可以獲得一個一維或二維紋理貼圖(或者也可以用特定紋理類型如GL_MAX_3D_TEXTURE_SIZE和GL_MAX_CUBE_MAP_TEXTURE_SIZE)最大寬度或者最大高度的下限:

Glint maxSize;
glGetIntegerv(GL_MAX_TEXTURE_SIZE,&maxSize);           
  • 1
  • 2

要弄清是否支援某種特定的紋理大小和格式,我們可以使用一個紋理代理。紋理代理不占用記憶體空間也無法應用到幾何圖形上,僅僅用來嘗試。 

例如,為了查明是否能夠整整加載一個2048X4096的BGRA紋理,我們可以建立類似下面這樣的代理:

glTexImage2D(GL_PROXY_TEXTURE_2D,,GL_RGBA,,,,GL_BGRA,GL_UNSIGNED_BYTE,NULL);           
  • 1

然後檢視是否支援相應的高度4096:

void glGetTexLevelParameter(GL_PROXY_TEXTURE_2D,,GL_TEXTURE_HEIGHT,&height);           
  • 1

轉載請注明出處:http://blog.csdn.net/ylbs110/article/details/51926110 

說明 

由于超級寶典版本太老了,決定本周開始改學習程式設計指南第8版。

繼續閱讀