首页 > 代码库 > OpenGL:纹理基础总结

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();)。





















OpenGL:纹理基础总结