OpenGL:紋理基礎(chǔ)總結(jié)
當(dāng)前光柵位置:
? ? 當(dāng)前光柵位置就是開始繪制下一幅位圖/圖像的屏幕位置。 ?//左下角
glRasterPos2f(GLfloat x, GLfloat y);
glRasterPos3f(GLfloat x, GLfloat y, GLfloat z);
? ? 1、4版本中,glWindowsPos*()作為glRasterPos*()的替代品,它用窗口坐標(biāo)指定當(dāng)前光柵位置,不必把它的x和y坐標(biāo)通過
模型視圖和投影矩陣進(jìn)行變換,也不會(huì)被裁剪出視口區(qū)域。更容易混合使用2D文本和3D圖形,而不必再各種變換狀態(tài)之間反復(fù)切換。
glGetFloatv(GLenum pname, GLfloat *params);
//使用GL_CURRENT_RASTER_POSITION為pname獲取當(dāng)前光柵位置。
glGetBooleanv(GLenum pname, GLboolean *params);
//使用GL_CURRENT_RASTER_POSITION_VALUE為pname確定當(dāng)前光柵位置是否有效。
? ? 在設(shè)置了光柵位置之后,可以使用glBitmap()繪制位圖。
glBitmap(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove,
? ? ? ? ?GLfloat ymove, const GLubyte *bitmap); ?//xmove表示位圖光柵化之后光柵位置的x增加值
選擇位圖的顏色:
? ? glColor*()和glIndex*()設(shè)置當(dāng)前顏色或當(dāng)前顏色索引,還可以設(shè)置狀態(tài)變量GL_CURRENT_RASTER_COLOR和
GL_CURRENT_INDEX.光柵顏色狀態(tài)變量是在調(diào)用glRasterPos*()時(shí)根據(jù)當(dāng)前顏色設(shè)置的:
? ? glColor3f(1.0, 1.0, 1.0);
? ? glRasterPos3fv(position);
? ? glColor3f(1.0, 0.0, 0.0);
? ? glBitmap(...); ? //位圖顏色是白色的?。?!
OpenGL提供了3個(gè)基本的函數(shù)來操縱圖像數(shù)據(jù):
? ? glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format,
? ? ? ? ? ? ? ? ?GLenum type, GLvoid *pixels);
//從幀緩沖區(qū)讀取一個(gè)矩形像素?cái)?shù)組,并把數(shù)據(jù)保存在內(nèi)存中。
? ? glDrawPixels(GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);
//把內(nèi)存中保存的一個(gè)矩形像素?cái)?shù)組寫入到幀緩存區(qū)中由glRasterPos*()指定的當(dāng)前位置
? ? glCopyPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type);
//把一個(gè)矩形像素?cái)?shù)組從幀緩沖區(qū)的一個(gè)部分復(fù)制到另一部分,數(shù)據(jù)不會(huì)寫入內(nèi)存
OpenGL所支持的所有像素存儲(chǔ)模式都是由glPixelStore*()函數(shù)控制的,一般,可以連續(xù)幾次調(diào)用這個(gè)函數(shù),成批設(shè)置幾個(gè)參數(shù)值。
glPixelStorei(GLenum pname, GLint param);
pname參數(shù)值:
? ? GL_UNPACK_SWAP_BYTES: 若FALSE,內(nèi)存中的字符順序采用OpenGL客戶機(jī)自身的方案,否則反轉(zhuǎn)字節(jié)順序
? ? GL_UNPACK_LSB_FIRST:只適合在位圖上繪制或讀取1位圖像,若FALSE(默認(rèn)),數(shù)據(jù)位從字節(jié)的最高有效位開始提取。
? ? GL_UNPACK_ROW_LENGTH:
? ? GL_UNPACK_SKIP_ROWS
? ? GL_UNPACK_SKIP_ROWS
? ? GL_UNPACK_ALIGNMENT
? ? GL_UNPACK_IMAGE_HEIGHT
? ? GL_UNPACK_SKIP_IMAGES
? ? 像素傳輸操作:當(dāng)圖像從內(nèi)存?zhèn)鬏數(shù)綆彌_區(qū)或者從幀緩沖區(qū)傳輸?shù)絻?nèi)存時(shí),可以更改顏色成分的范圍(0.0-1.0),或執(zhí)行任意的顏色索引或
顏色成分的轉(zhuǎn)換,這種在像素傳輸期間所執(zhí)行的轉(zhuǎn)換成為像素傳輸操作,由glPixelTransfer*()和glPixelMap*()控制。
放大、縮小或翻轉(zhuǎn)圖像:
? glPixelZoom(GLfloat xfactor, GLfloat yfactor);
//設(shè)置像素寫入操作glDrawPixels()和glCopyPixels()中x和y方向的縮放因子,負(fù)的縮放因子根據(jù)當(dāng)前的光柵位置對圖像進(jìn)行翻轉(zhuǎn)。
顏色矩陣:
? ? 從RGB顏色空間轉(zhuǎn)換為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);
從幀緩沖區(qū)中讀取一塊像素矩形替換一個(gè)現(xiàn)有紋理數(shù)組的一部分:
glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y,
? ? ? ? ? ? ? ? ? ? GLsizei width, GLsizei height);
mipmap:
? ? 當(dāng)紋理對象迅速遠(yuǎn)離觀察點(diǎn)而去時(shí),在經(jīng)過一些過濾點(diǎn)時(shí),經(jīng)過過濾的紋理圖像可能出現(xiàn)突然的變化,為了避免這種人工痕跡,可以
指定一系列預(yù)先過濾的分辨率遞減的紋理圖像,稱為mipmap。如果不使用mipmap,當(dāng)紋理映射到更小的物體上時(shí),若物體移動(dòng),會(huì)閃爍或抖動(dòng)。
? ? 為了使用mipmap, 必須提供全系列的大小為2的整數(shù)次方的紋理對象,范圍從最大值到1×1紋理單元,例如如果最高分辨率的紋理圖像是64*16,
還必須提供大小分別是32*8,16*4,8*2,4*1,2*1,1*1的紋理圖像。
? ? 可以使用glGenerateMipmap(GLenum target);為與target相關(guān)聯(lián)的紋理圖像生成一組完整的mipmap。
? ? 若已創(chuàng)建了最高分辨率的mipmap,可使用glutBuild2DMipmaps()創(chuàng)建和定義一系列大小遞減的mipmap,直到1*1紋理單元。
? ? 計(jì)算和加載mipmap層的一個(gè)子集,可以調(diào)用glutBuild2DMipmapLevels()。
? ? 為了控制mipmap層,可以向glTexParameter*()傳遞GL_TEXTURE_BASE_LEVEL、GL_TEXTURE_MAX_LEVEL、GL_TEXTURE_MIN_LOD
和GL_TEXTURE_MAX_LOD。前兩個(gè)控制哪些mipmap層被使用,后兩個(gè)用于控制縮放因子λ的活動(dòng)范圍。
? ? 若紋理圖像大小64*32,多邊形大小8*16,ρ=8.0(取最大值),λ=3.0.
過濾:
? ? 使用glTexParameter*()函數(shù)指定放大和縮小過濾方法:
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);判斷一個(gè)紋理是否處于使用中,texture是由glGenTextures()函數(shù)返回的。
可以把紋理圖像的顏色與物體表面原先的顏色進(jìn)行組合:使用glTexEnv*()函數(shù)
? ? 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必須是浮點(diǎn)值,作為
mipmap細(xì)節(jié)層參數(shù)的偏移值。
? ? 如果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數(shù)組。
紋理坐標(biāo)映射:
? ? glTexCoord2f(GLfloat s, GLfloat t); glVertex3f(GLfloat x, GLfloat y, GLfloat z);
紋理坐標(biāo)自動(dòng)生成:
? ? 可以使用紋理貼圖生成模型的輪廓線,或者模擬具有光澤的模型對任意環(huán)境的反射,為了實(shí)現(xiàn)這些效果,可以讓OpenGL自動(dòng)生成紋理坐標(biāo):
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
球形紋理:
? ? 為了自動(dòng)生成紋理坐標(biāo),對環(huán)境紋理貼圖提供支持,可使用如下代碼:
? ? 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幅二維紋理圖像構(gòu)成一個(gè)以原點(diǎn)為中心的紋理立方體。立方體紋理非常適用于實(shí)現(xiàn)環(huán)境、反射和光照效果。立方體紋理還可把
紋理環(huán)繞到球體上,使紋理單元均勻地分布于各個(gè)面上。
? ? 可以調(diào)用glTexImage2D() 6次,分別使用target參數(shù)表示立方體的各個(gè)面(+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);
? ? 因?yàn)榱⒎綀D紋理所占的內(nèi)存時(shí)普通2D紋理的6倍,所以應(yīng)把立方圖紋理視為一個(gè)整體,為它指定紋理參數(shù)并創(chuàng)建紋理對象,
而不是為6個(gè)面分別指定紋理參數(shù):
? ? 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所使用的計(jì)算方式和GL_SPHERE_MAP相同,它非常適用于環(huán)境紋理貼圖,可替代GL_SPHERE_MAP.
GL_NORMAL_MAP適用于渲染無限遠(yuǎn)處光源及散射反射的場景
多重紋理的步驟:
? ? 1、對于每個(gè)紋理單位,建立相關(guān)的紋理狀態(tài),使用glActiveTexture()更改當(dāng)前的紋理單位,
調(diào)用glGetIntegerv(GL_MAX_TEXTURE_UNITS,...)查詢當(dāng)前OpenGL實(shí)現(xiàn)所支持的紋理單位的數(shù)量。
? ? 2、在指定頂點(diǎn)時(shí),使用glMultiTexCoord*()為每個(gè)頂點(diǎn)指定多個(gè)紋理坐標(biāo),分別用于不同的紋理單位。
1、glActiveTexture(GLenum texUnit);
//選擇可以由紋理函數(shù)進(jìn)行修改的當(dāng)前紋理單位.texUnit是一個(gè)符號常量,形式為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);
在第一個(gè)紋理單位渲染完成后, 這個(gè)經(jīng)過紋理處理的多邊形便發(fā)送到第二個(gè)紋理單位。
保存恢復(fù)紋理單位的紋理狀態(tài)(紋理矩陣狀態(tài)除外):
? ? glPushAttrib(GLbitfield mask); glPushClientAttrib(GLbitfield mask); //Pop
2、在多重紋理中,每個(gè)頂點(diǎn)只有一組紋理坐標(biāo)是不夠的,需要為每個(gè)頂點(diǎn)的每個(gè)紋理單位都指定一組紋理坐標(biāo),使用glMutiTexCoord*().
eg: ?//為多重紋理指定頂點(diǎn)
? ? 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();
? ? 使用多重紋理時(shí),指定紋理坐標(biāo)除了顯示調(diào)用glMultiTexCoord*(),還可以使用紋理坐標(biāo)自動(dòng)生成(glTexGenf();)和
頂點(diǎn)數(shù)組(glTexCoordPointer();)。