天天看點

OpenGL:紋理基礎總結

目前光栅位置:

    目前光栅位置就是開始繪制下一幅位圖/圖像的螢幕位置。  //左下角

glRasterPos2f(GLfloat x, GLfloat y);

glRasterPos3f(GLfloat x, GLfloat y, GLfloat z);

    1、4版本中,glWindowsPos*()作為glRasterPos*()的替代品,它用視窗坐标指定目前光栅位置,不必把它的x和y坐标通過

模型視圖和投影矩陣進行變換,也不會被裁剪出視口區域。更容易混合使用2D文本和3D圖形,而不必再各種變換狀态之間反複切換。

glGetFloatv(GLenum pname, GLfloat *params);

//使用GL_CURRENT_RASTER_POSITION為pname擷取目前光栅位置。

glGetBooleanv(GLenum pname, GLboolean *params);

//使用GL_CURRENT_RASTER_POSITION_VALUE為pname确定目前光栅位置是否有效。

    在設定了光栅位置之後,可以使用glBitmap()繪制位圖。

glBitmap(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove,

         GLfloat ymove, const GLubyte *bitmap);  //xmove表示位圖光栅化之後光栅位置的x增加值

選擇位圖的顔色:

    glColor*()和glIndex*()設定目前顔色或目前顔色索引,還可以設定狀态變量GL_CURRENT_RASTER_COLOR和

GL_CURRENT_INDEX.光栅顔色狀态變量是在調用glRasterPos*()時根據目前顔色設定的:

    glColor3f(1.0, 1.0, 1.0);

    glRasterPos3fv(position);

    glColor3f(1.0, 0.0, 0.0);

    glBitmap(...);   //位圖顔色是白色的!!!

OpenGL提供了3個基本的函數來操縱圖像資料:

    glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format,

                 GLenum type, GLvoid *pixels);

//從幀緩沖區讀取一個矩形像素數組,并把資料儲存在記憶體中。

    glDrawPixels(GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);

//把記憶體中儲存的一個矩形像素數組寫入到幀緩存區中由glRasterPos*()指定的目前位置

    glCopyPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type);

//把一個矩形像素數組從幀緩沖區的一個部分複制到另一部分,資料不會寫入記憶體

OpenGL所支援的所有像素存儲模式都是由glPixelStore*()函數控制的,一般,可以連續幾次調用這個函數,成批設定幾個參數值。

glPixelStorei(GLenum pname, GLint param);

pname參數值:

    GL_UNPACK_SWAP_BYTES: 若FALSE,記憶體中的字元順序采用OpenGL客戶機自身的方案,否則反轉位元組順序

    GL_UNPACK_LSB_FIRST:隻适合在位圖上繪制或讀取1位圖像,若FALSE(預設),資料位從位元組的最高有效位開始提取。

    GL_UNPACK_ROW_LENGTH:

    GL_UNPACK_SKIP_ROWS

    GL_UNPACK_SKIP_ROWS

    GL_UNPACK_ALIGNMENT

    GL_UNPACK_IMAGE_HEIGHT

    GL_UNPACK_SKIP_IMAGES

    像素傳輸操作:當圖像從記憶體傳輸到幀緩沖區或者從幀緩沖區傳輸到記憶體時,可以更改顔色成分的範圍(0.0-1.0),或執行任意的顔色索引或

顔色成分的轉換,這種在像素傳輸期間所執行的轉換成為像素傳輸操作,由glPixelTransfer*()和glPixelMap*()控制。

放大、縮小或翻轉圖像:

  glPixelZoom(GLfloat xfactor, GLfloat yfactor);

//設定像素寫入操作glDrawPixels()和glCopyPixels()中x和y方向的縮放因子,負的縮放因子根據目前的光栅位置對圖像進行翻轉。

顔色矩陣:

    從RGB顔色空間轉換為CMY顔色空間:

    GLfloat rgb2cmy[16] = {

        -1,  0,  0,  0,

         0, -1,  0,  0,

         0,  0, -1,  0,

         1,  1,  1,  1

    };

    glMatrixMode(GL_COLOR);

    glLoadMatrixf(rgb2cmy);

    glMatrixMode(GL_MODELVIEW);

紋理貼圖:

glEnable(GL_TEXTURE_2D); // 1D, 2D, 3D, GL_TEXTURE_CUBE_MAP立方圖紋理

glGenTextures(GLsizei n, GLuint *textures);

glBindTexture(GLenum target, GLuint texture);

glTexParameteri(GLenum target, GLenum pname, GLint param);

glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height,

             GLint border, GLenum format,GLenum type, const GLvoid *pixels);

gluScaleImage(GLenum format, GLint widthin, GLint heightin, GLenum typein, const void *datain,

              GLint widthout, GLint heightout, GLenum typeout, void *dataout);

glCopyTexImage2D(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width,

                 GLsizei height, GLint border);

替換紋理:

glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,

                GLenum format, GLenum type, const GLvoid *pixels);

從幀緩沖區中讀取一塊像素矩形替換一個現有紋理數組的一部分:

glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y,

                    GLsizei width, GLsizei height);

mipmap:

    當紋理對象迅速遠離觀察點而去時,在經過一些過濾點時,經過過濾的紋理圖像可能出現突然的變化,為了避免這種人工痕迹,可以

指定一系列預先過濾的分辨率遞減的紋理圖像,稱為mipmap。如果不使用mipmap,當紋理映射到更小的物體上時,若物體移動,會閃爍或抖動。

    為了使用mipmap, 必須提供全系列的大小為2的整數次方的紋理對象,範圍從最大值到1×1紋理單元,例如如果最高分辨率的紋理圖像是64*16,

還必須提供大小分别是32*8,16*4,8*2,4*1,2*1,1*1的紋理圖像。

    可以使用glGenerateMipmap(GLenum target);為與target相關聯的紋理圖像生成一組完整的mipmap。

    若已建立了最高分辨率的mipmap,可使用glutBuild2DMipmaps()建立和定義一系列大小遞減的mipmap,直到1*1紋理單元。

    計算和加載mipmap層的一個子集,可以調用glutBuild2DMipmapLevels()。

    為了控制mipmap層,可以向glTexParameter*()傳遞GL_TEXTURE_BASE_LEVEL、GL_TEXTURE_MAX_LEVEL、GL_TEXTURE_MIN_LOD

和GL_TEXTURE_MAX_LOD。前兩個控制哪些mipmap層被使用,後兩個用于控制縮放因子λ的活動範圍。

    若紋理圖像大小64*32,多邊形大小8*16,ρ=8.0(取最大值),λ=3.0.

過濾:

    使用glTexParameter*()函數指定放大和縮小過濾方法:

glTexParameteri(GLenum target, GLenum pname, GLint param);

eg: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

glIsTexture(GLuint texture);判斷一個紋理是否處于使用中,texture是由glGenTextures()函數傳回的。

可以把紋理圖像的顔色與物體表面原先的顔色進行組合:使用glTexEnv*()函數

    glTexEnvf(GLenum target, GLenum pname, GLfloat param);

    //target必須是GL_TEXTURE_FILTER_CONTROL或GL_TEXTURE_ENV

    如果target是GL_TEXTURE_FILTER_CONTROL,pname必須是GL_TEXTURE_LOD_BIAS,param必須是浮點值,作為

mipmap細節層參數的偏移值。

    如果target是GL_TEXTURE_ENV,且pname是GL_TEXTURE_ENV_MODE,那麼param必須是如下值之一:GL_DECAL,

GL_REPLACE, GL_MODULATE, GL_BLEND, GL_ADD, GL_COMBINE;如果pname是GL_TEXTURE_ENV_COLOR,param就是顔色RGBA數組。

紋理坐标映射:

    glTexCoord2f(GLfloat s, GLfloat t); glVertex3f(GLfloat x, GLfloat y, GLfloat z);

紋理坐标自動生成:

    可以使用紋理貼圖生成模型的輪廓線,或者模拟具有光澤的模型對任意環境的反射,為了實作這些效果,可以讓OpenGL自動生成紋理坐标:

glTexGeni(GLenum coord, GLenum pname, GLint param);

//coord必須是GL_S, GL_T, GL_R, GL_Q; pname取值GL_TEXTURE_GEN_MODE, GL_OBJECT_PLANE, GL_EYE_PLANE

球形紋理:

    為了自動生成紋理坐标,對環境紋理貼圖提供支援,可使用如下代碼:

    glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);

    glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);

    glEnable(GL_TEXTURE_GEN_S);

    glEnable(GL_TEXTURE_GEN_T);

立方圖紋理:

    立方圖紋理使用6幅二維紋理圖像構成一個以原點為中心的紋理立方體。立方體紋理非常适用于實作環境、反射和光照效果。立方體紋理還可把

紋理環繞到球體上,使紋理單元均勻地分布于各個面上。

    可以調用glTexImage2D() 6次,分别使用target參數表示立方體的各個面(+X, -X, +Y, -Y, +Z, -Z):

    glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL_RGBA, imageSize, imageSize, 0, GL_RGBA,

                 GL_UNSIGNED_BYTE, image1);

    glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, GL_RGBA, imageSize, imageSize, 0, GL_RGBA,

                 GL_UNSIGNED_BYTE, image4);

    glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, GL_RGBA, imageSize, imageSize, 0, GL_RGBA,

                 GL_UNSIGNED_BYTE, image2);

    glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GL_RGBA, imageSize, imageSize, 0, GL_RGBA,

                 GL_UNSIGNED_BYTE, image5);

    glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, GL_RGBA, imageSize, imageSize, 0, GL_RGBA,

                 GL_UNSIGNED_BYTE, image3);

    glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, GL_RGBA, imageSize, imageSize, 0, GL_RGBA,

                 GL_UNSIGNED_BYTE, image6);

    因為立方圖紋理所占的記憶體時普通2D紋理的6倍,是以應把立方圖紋理視為一個整體,為它指定紋理參數并建立紋理對象,

而不是為6個面分别指定紋理參數:

    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_REPEAT);

    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_REPEAT);

    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_REPEAT);

    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

啟用立方圖紋理:

    glEnable(GL_TEXTURE_GEN_S);

    glEnable(GL_TEXTURE_GEN_T);

    glEnable(GL_TEXTURE_GEN_R);

GL_REFLECTION_MAP所使用的計算方式和GL_SPHERE_MAP相同,它非常适用于環境紋理貼圖,可替代GL_SPHERE_MAP.

GL_NORMAL_MAP适用于渲染無限遠處光源及散射反射的場景

多重紋理的步驟:

    1、對于每個紋理機關,建立相關的紋理狀态,使用glActiveTexture()更改目前的紋理機關,

調用glGetIntegerv(GL_MAX_TEXTURE_UNITS,...)查詢目前OpenGL實作所支援的紋理機關的數量。

    2、在指定頂點時,使用glMultiTexCoord*()為每個頂點指定多個紋理坐标,分别用于不同的紋理機關。

1、glActiveTexture(GLenum texUnit);

//選擇可以由紋理函數進行修改的目前紋理機關.texUnit是一個符号常量,形式為GL_TEXTUREi

eg:

GLuint texNames[2];
    glGenTextures(2, texNames);
    glBindTexture(GL_TEXTURE_2D, texNames[0]);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, texels0);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, REPEAT);
    glBindTexture(GL_TEXTURE_2D, texNames[1]);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, texels1);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);


    glActiveTexture(GL_TEXTURE0);
    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, texNames[0]);
    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
    glMatrixMode(GL_TEXTURE);
    glLoadIdentity();
    glTranslatef(0.5f, 0.5f, 0.0f);
    glRotatef(45.0f, 0.0f, 0.0f, 1.0f);
    glTranslatef(-0.5f, -0.5f, 0.0f);
    glMatrixMode(GL_MODELVIEW);
    glActiveTexture(GL_TEXTURE1);
    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, texNames[1]);
    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
           

在第一個紋理機關渲染完成後, 這個經過紋理處理的多邊形便發送到第二個紋理機關。

儲存恢複紋理機關的紋理狀态(紋理矩陣狀态除外):

    glPushAttrib(GLbitfield mask); glPushClientAttrib(GLbitfield mask); //Pop

2、在多重紋理中,每個頂點隻有一組紋理坐标是不夠的,需要為每個頂點的每個紋理機關都指定一組紋理坐标,使用glMutiTexCoord*().

eg:  //為多重紋理指定頂點

glBegin(GL_TRIANGLES);
    glMultiTexCoord2f(GL_TEXTURE0, 0.0, 0.0);
    glMultiTexCoord2f(GL_TEXTURE1, 1.0, 0.0);
    glVertex2f(0.0, 0.0);
    glMultiTexCoord2f(GL_TEXTURE0, 0.5, 1.0);
    glMultiTexCoord2f(GL_TEXTURE1, 0.5, 1.0);
    glVertex2f(50.0, 100.0);
    glMultiTexCoord2f(GL_TEXTURE0, 1.0, 0.0);
    glMultiTexCoord2f(GL_TEXTURE1, 1.0, 1.0);
    glVertex2f(100.0, 0.0);
    glEnd();
           

    使用多重紋理時,指定紋理坐标除了顯示調用glMultiTexCoord*(),還可以使用紋理坐标自動生成(glTexGenf();)和

頂點數組(glTexCoordPointer();)。

繼續閱讀