【OpenGL】蓝宝书第七章——纹理高级知识
发布日期:2021-05-10 02:21:03 浏览次数:10 分类:精选文章

本文共 6697 字,大约阅读时间需要 22 分钟。

OpenGL纹理技术指南

矩形纹理

矩形纹理在OpenGL中提供了一种高效的纹理渲染方式。与标准纹理(GL_TEXTURE_2D)不同,矩形纹理(GL_TEXTURE_RECTANGLE)具有以下特点:

  • 纹理坐标范围:矩形纹理的纹理坐标不像普通纹理那样在[0,1]范围内,而是基于像素坐标进行计算,例如纹理坐标(5,19)代表从左数第六列,从上数第20行的像素。

  • 倍数贴图支持:矩形纹理不支持倍数贴图(Mip贴图),因此需要手动生成倍数层次。

  • 环绕模式:支持标准的环绕模式(GL_texture_wrap_mode),包括Repeat、Clamp到边缘和Mirror等。

  • 纹理压缩:不支持纹理压缩,必须使用原始图片数据。

  • 加载矩形纹理

    以下是加载矩形纹理(GL_TEXTURE_RECTANGLE)的代码示例:

    bool LoadTGATexture(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) {        return false;    }    // 设置纹理参数    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapMode);    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapMode);    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter);    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter);    // 设置像素存储属性    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);    // 创建纹理    glTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB, nWidth, nHeight, 0,                  eFormat, GL_UNSIGNED_BYTE, pBits);    free(pBits);    // 如果启用倍数贴图生成    if (minFilter == GL_LINEAR_MIPMAP_LINEAR ||         minFilter == GL_LINEAR_MIPMAP_NEAREST ||         minFilter == GL_NEAREST_MIPMAP_LINEAR ||         minFilter == GL_NEAREST_MIPMAP_NEAREST) {        glGenerateMipmap(GL_TEXTURE_2D);    }    return true;}

    使用矩形纹理

    将矩形纹理加载到uiTextures[3]纹理对象中:

    // 加载Logo纹理// glBindTexture(GL_TEXTURE_RECTANGLE, uiTextures[3]);LoadTGATexture("OpenGL-Logo.tga", GL_NEAREST, GL_NEAREST, GL_CLAMP_TO_EDGE);

    渲染设置

    准备好正交投影矩阵,并创建一个GLBatch批次对象。纹理坐标的设置方式如下:

    // 定义纹理坐标int x = 500; int y = 155; int width = 300; int height = 155;// 创建批次对象logoBatch.Begin(GL_TRIANGLE_FAN, 4, 1);// 上左角位置logoBatch.MultiTexCoord2f(0, 0.0f, height);logoBatch.Vertex3f(x, y, 0.0f);// 下左角位置logoBatch.MultiTexCoord2f(0, 0.0f, 0.0f);logoBatch.Vertex3f(x, y - height, 0.0f);// 下右角位置logoBatch.MultiTexCoord2f(0, width, 0.0f);logoBatch.Vertex3f(x + width, y - height, 0.0f);// 上右角位置logoBatch.MultiTexCoord2f(0, width, height);logoBatch.Vertex3f(x + width, y, 0.0f);// 结束批次绘制logoBatch.End();

    片段着色器和顶点着色器

    // 矩形纹理片段着色器Shader代码如下:#version 140out vec4 vFragColor;uniform sampler2DRect rectangleImage;smooth in vec2 vVaryingTexCoord;void main() {    vFragColor = texture(rectangleImage, vVaryingTexCoord);}
    // 矩形纹理顶点着色器Shader代码如下:#version 140in vec4 vVertex;in vec2 vTexCoord;uniform mat4 mvpMatrix;smooth out vec2 vVaryingTexCoord;void main() {    vVaryingTexCoord = vTexCoord;    gl_Position = mvpMatrix * vVertex;}

    立方体贴图

    立方体贴图(Cubemap)由六个面组成,每个面是一个正方形的2D图像。立方体贴图用于模拟真实环境中的反射和遮挡。

    加载立方体贴图

    立方体贴图的标量类型包括:

    • 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方向的贴图:

    GLubyte *pBits = gltReadTGABits("positive_x.tga", &nWidth, &nHeight, &nComponents, &eFormat);glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL_RGBA, nWidth, nHeight, 0, eFormat, GL_UNSIGNED_BYTE, pBits);free(pBits);

    设置纹理参数时,需要将目标类型设置为GL_TEXTURE_CUBE_MAP。例如:

    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    生成倍数贴图

    立方体贴图支持生成倍数贴图(Mip贴图):

    glGenerateMipmap(GL_TEXTURE_CUBE_MAP);

    立方体贴图的纹理坐标是三维的,环绕模式需要同时设置三个方向:

    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);

    多重纹理

    OpenGL支持多个纹理单元的绑定,使得可以将多个纹理应用于同一个几何对象。使用多重纹理可以创造更复杂的视觉效果。

    检查纹理单元数量

    获取支持的纹理单元数量:

    GLint iUnits;glGetIntegerv(GL_MAX_TEXTURE_UNITS, &iUnits);

    �rys 使用多重纹理

    切换到第2个纹理单元并绑定纹理对象:

    glActiveTexture(GL_TEXTURE1);glBindTexture(GL_TEXTURE_2D, textureID);

    在渲染时,需要注意当前活动的纹理单元。

    多纹理坐标

    GLBatch批次对象支持设置多个纹理坐标:

    GLBatch::Begin(GLフェ lienprimitive, GLuint nVerts, GLuint nTextureUnits = 0);

    可以使用以下方法设置纹理坐标:

  • 一次复制纹理坐标

    void GLBatch::CopyTexCoordData2f(M3DVector2f *vTexCoords, GLuint uiTextureLayer);
  • 逐个设置纹理坐标

    void GLBatch::MultiTexCoord2f(GLuint texture, GLclampf s, GLclampf t);void GLBatch::MultiTexCoord2fv(GLuint texture, M3DVector2f vTexCoord);
  • 多重纹理示例

    // 初始化多重纹理GLuint texture1, texture2;glGenTextures(2, &texture1, &texture2);glBindTexture(GL_TEXTURE_2D, texture1);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);glActiveTexture(GL_TEXTURE1);glBindTexture(GL_TEXTURE_2D, texture2);// 渲染使用多重纹理的几何对象

    点精灵(Point Sprite)

    点精灵是一个特殊的纹理类型,每个顶点都会生成一个小的点形象。点精灵的纹理坐标使用gl_PointCoord内置变量。

    定义点精灵大小

    设置点精灵大小:

    glPointSize(5.0);

    启用顶点着色器定义点大小:

    glEnable(GL_PROGRAM_POINT_SIZE);

    在片段着色器中设定点大小:

    uniform float gl_PointSize;out vec4 vFragColor;void main() {    vFragColor = vec4(1.0, 1.0, 1.0, 1.0);}

    点精灵旋转

    为了实现点精灵的旋转,可以在顶点着色器中计算旋转矩阵并将其传递到片段着色器。

    uniform float angle;uniform mat2 rotationMatrix;void main() {    vVertex.x = (rotationMatrix[0] * vVertex.x) + (rotationMatrix[1] * vVertex.y);    vVertex.y = (rotationMatrix[2] * vVertex.x) + (rotationMatrix[3] * vVertex.y);    gl_Position = MVPMatrix * vVertex;}

    纹理数组

    纹理数组(GL_TEXTURE_2D_ARRAY)允许将多张纹理切换到同一个纹理对象中,特别适用于动态图像。

    加载纹理数组

    生成纹理数组:

    GLuint moonTexture;glGenTextures(1, &moonTexture);glBindTexture(GL_TEXTURE_2D_ARRAY, moonTexture);

    设置纹理参数:

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

    加载纹理数组数据:

    void glTexImage3D(GLenum target, GLint level, GLint internalformat,                   GLsizei width, GLsizei height, GLsizei depth,                   GLint border, GLenum format, GLenum type, const void *data);glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA, 64, 64, 29, 0,              GL_BGRA, GL_UNSIGNED_BYTE, NULL);for (int i = 0; i < 29; i++) {    char cFile[32];    sprintf_s(cFile, "moon%02d.tga", i);    GLbyte *pBits = gltReadTGABits(cFile, &nWidth, &nHeight, &nComponents, &eFormat);    glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, i, nWidth, nHeight, 1,                    GL_BGRA, GL_UNSIGNED_BYTE, pBits);    free(pBits);}

    访问纹理数组

    在片段着色器中使用纹理数组:

    uniform sampler2DArray moonImage;smooth in vec3 vMoonCoords;void main() {    vec2 st = vMoonCoords.st;    float index = vMoonCoords.p;    vec3 color = texture2DArray(moonImage, st, index);    vFragColor = color;}

    纹理代理

    纹理代理(GL_PROXY_TEXTURE)用于检查硬件支持的纹理格式和参数。

    创建纹理代理

    glTexImage2D(GL_PROXY_TEXTURE_2D, 0, GL_RGB, 2048, 4096, 0,              GL_BGRA, GL_UNSIGNED_BYTE, NULL);

    检查硬件支持

    int height;glGetTexLevelParameter(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height);

    如果height返回0,说明不支持该纹理尺寸。

    上一篇:【OpenGL】7-1矩形纹理案例
    下一篇:【OpenGL】卡通着色(Cell Shading)——将纹理单元作为光线

    发表评论

    最新留言

    初次前来,多多关照!
    [***.217.46.12]2025年04月16日 03时16分43秒