OpenGL 基础纹理

原始数据图像

图像存储空间 = 长 x 宽 x   每个像素的字节数

API

设置像素的存储格式 

 glPixelStorei(<#GLenum pname#>, GLint param)

glPixelStorei是OpenGL中的一个函数,用于设置像素的存储格式。常见的用法有:

  • glPixelStorei(GL_PACK_ALIGNMENT,1):在像素传输的场合中使用,尤其是在导入纹理(glTexImage2D)时。
  • glpixelStorei(GL_UNPACK_ALIGNMENT,1):改变某个状态量,然后再恢复回来。

这些用法通常会影响纹理映射的效果,例如控制所读取数据的对齐方式、防止读取越界等。在使用glPixelStorei函数时,需要根据具体的需求和场景来选择合适的参数。

恢复像素存储方式

    glPixelStoref(<#GLenum pname#>, <#GLfloat param#>)

在OpenGL中,glPixelStoref函数用于设置像素存储模式,其函数原型为void glPixelStoref(GLenum pname, GLfloat param);。其中,pname为指定的参数名称,param为指定的参数值。

这些模式会影响后续glReadPixels的操作以及纹理图案的解包,也会影响到glTexImage1DglTexImage2DglTexImage3DglTexSubImage1DglTexSubImage2DglTexSubImage3D等函数。

#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>

void textureMapping() {
    // 初始化 GLFW
    if (!glfwInit()) {
        std::cerr << "Failed to initialize GLFW" << std::endl;
        return;
    }

    // 创建窗口
    GLFWwindow* window = glfwCreateWindow(640, 480, "Texture Mapping", NULL, NULL);
    if (!window) {
        std::cerr << "Failed to create window" << std::endl;
        glfwTerminate();
        return;
    }

    // 绑定 OpenGL 上下文
    glfwMakeContextCurrent(window);

    // 加载纹理图像
    GLuint texture;
    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);
    // 设置纹理参数
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    // 加载并生成纹理
    int width, height, channels;
    unsigned char* image = stbi_load("texture.png", &width, &height, &channels, 0);
    if (image) {
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image);
        glGenerateMipmap(GL_TEXTURE_2D);
    } else {
        std::cerr << "Failed to load texture image" << std::endl;
    }
    stbi_image_free(image);

    // 渲染循环
    while (!glfwWindowShouldClose(window)) {
        // 清空颜色缓冲区
        glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        // 绘制一个矩形,使用纹理映射
        glBegin(GL_QUADS);
        glTexCoord2f(0.0f, 0.0f); glVertex2f(-0.5f, -0.5f);
        glTexCoord2f(1.0f, 0.0f); glVertex2f(0.5f, -0.5f);
        glTexCoord2f(1.0f, 1.0f); glVertex2f(0.5f, 0.5f);
        glTexCoord2f(0.0f, 1.0f); glVertex2f(-0.5f, 0.5f);
        glEnd();

        // 交换缓冲区
        glfwSwapBuffers(window);
        // 检查事件
        glfwPollEvents();
    }

    // 释放资源
    glfwTerminate();
}

int main() {
    textureMapping();
    return 0;
}
在OpenGL中,常见的纹理存储模式有哪些?
  • GL_CLAMP:该模式下,纹理坐标超出范围时,会被截取为边界值。
  • GL_REPEAT:该模式下,纹理坐标会重复使用,以使图像在物体表面上重复显示。
  • GL_MIRRORED_REPEAT:该模式下,纹理坐标会镜像重复使用,以使图像在物体表面上重复显示,但会进行镜像操作。
  • GL_NEAREST:该模式下,使用最近邻插值方法来进行纹理采样。
  • GL_LINEAR:该模式下,使用线性插值方法来进行纹理采样。

这些模式可以通过调用glPixelStoref函数并传入对应的参数来设置。具体的使用方法和参数含义可能会因OpenGL版本和扩展而有所不同,如果你想了解更多关于纹理存储模式的信息,可以查阅相关的OpenGL文档或参考书籍。

从颜色缓存区内容作为像素图直接读取
void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels);

glReadPixels是 Open Graphics Library(OpenGL)中的一个函数,用于从帧缓冲区中读取像素数据。它可以将屏幕上显示的图像内容读取到内存中,以便进行后续处理或保存为图像文件。

其中,xy表示要读取的像素区域的左上角坐标,widthheight表示要读取的像素区域的宽度和高度。format参数指定了读取像素数据的格式,常见的格式包括GL_RGBA(每个像素包含 R、G、B 和 A 四个分量)和GL_DEPTH_COMPONENT(每个像素包含深度信息)等。type参数指定了读取像素数据的类型,常见的类型包括GL_UNSIGNED_BYTE(无符号字节)和GL_FLOAT(浮点数)等。pixels是一个指向内存的指针,用于接收读取到的像素数据。

需要注意的是,在使用glReadPixels函数之前,需要确保已经完成了所有的绘图操作,并且帧缓冲区中的内容已经准备好被读取。此外,还需要注意内存的分配和释放,以及数据格式和类型的匹配。

glReaderBuffer可能指的是OpenGL中的glReadBuffer函数,该函数用于指定用于读取帧缓冲区数据的颜色缓冲区。它的函数原型如下:

void glReadBuffer(GLenum mode);

其中,参数mode指定要读取的颜色缓冲区,可以是以下几个常量之一:

  • GL_FRONT_LEFT :读取前缓冲区的左半部分。
  • GL_FRONT_RIGHT :读取前缓冲区的右半部分。
  • GL_BACK_LEFT :读取后缓冲区的左半部分。
  • GL_BACK_RIGHT :读取后缓冲区的右半部分。

通过调用glReadBuffer函数,可以指定要读取的颜色缓冲区,从而获取所需的帧缓冲区数据。

像素格式

像素数据数据类型

载入纹理

void glCopyTexImage1D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border)

其中,target表示目标纹理,通常为GL_TEXTURE_1D;level表示层级;internalformat表示内部格式;xy表示纹理图像的起始位置;width表示纹理图像的宽度;border表示边框宽度。

void glTexImage2D(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *data);

其中,参数target表示指定纹理单元的类型,必须指定为GL_TEXTURE_2DGL_PROXY_TEXTURE_2DGL_TEXTURE_CUBE_MAP_POSITIVE_XGL_TEXTURE_CUBE_MAP_NEGATIVE_XGL_TEXTURE_CUBE_MAP_POSITIVE_YGL_TEXTURE_CUBE_MAP_NEGATIVE_YGL_TEXTURE_CUBE_MAP_POSITIVE_ZGL_TEXTURE_CUBE_MAP_NEGATIVE_ZGL_PROXY_TEXTURE_CUBE_MAP中的一个;参数level指定纹理单元的层次,非mipmap纹理level设置为0,mipmap纹理设置为纹理的层级;参数internalFormat指定OpenGL是如何管理纹理单元中数据格式的;参数widthheight指定纹理单元的宽度和高度;参数border指定纹理单元的边框,如果包含边框取值为1,不包含边框取值为0;参数format指定data所指向的数据的格式。

glTexImage3D是OpenGL中的一个函数,用于创建和加载三维纹理图像。其函数原型如下

void glTexImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *data);

其中,参数target表示指定纹理单元的类型;参数level指定纹理单元的层次;参数internalformat指定OpenGL是如何管理纹理单元中数据格式的;参数widthheightdepth指定纹理单元的宽度、高度和深度;参数border指定纹理单元的边框;参数format指定data所指向的数据的格式;参数type指定数据的数据类型。

glCopyTexImage1D

glCopyTexImage1D函数的作用是将像素从帧缓冲区拷贝到一个单空间纹理图像中。该函数的语法格式如下:

void glCopyTexImage1D(glenum target, glint level, glenum internalformat, glint x, glint y, glsizei width, glint border);

其中,target参数表示目标图像数据将更改为的目标,必须具有值GL_TEXTURE_1Dlevel参数表示详细信息级别编号,级别0是基础映像,级别n是第n个mipmap缩减图像;x参数表示要复制的像素行左下角的窗口x平面坐标;y参数表示要复制的像素行左下角的窗口y平面坐标;width参数表示纹理图像的子图像的宽度;border参数表示允许为纹理贴图指定一个边界宽度。

glCopyTexImage2D
void glCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border)

其中,target表示目标纹理,通常设置为GL_TEXTURE_2Dlevel表示纹理图像的层次,0 表示基础层,n 表示第 n 层 mipmap 纹理;internalformat表示纹理的内部格式;xy表示纹理的左下角坐标;widthheight表示纹理的宽度和高度;border表示纹理的边框宽度。

使用glCopyTexImage2D函数可以将帧缓冲区中的像素数据复制到纹理图像中,以便在后续的渲染中使用。需要注意的是,该函数会阻塞图形管道,因此在使用时需要注意性能。

更新纹理

glTexSubImage1D
glTexSubImage1D(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels)

glTexSubImage1D 是一个用于在一维纹理中更新(替换或添加)一部分像素数据的函数。它是 Open Graphics Library (OpenGL) 图形库的一部分。

以下是对每个参数的解释:

  1. target:指定目标纹理,通常设置为 GL_TEXTURE_1D 表示一维纹理。
  2. level:指定要更新的 mipmap 层次,0 表示基础层,n 表示第 n 层 mipmap 纹理。
  3. xoffset:指定在纹理的 x 轴上的偏移量,用于确定要更新的纹理区域的起始位置。
  4. width:指定要更新的纹理区域的宽度。
  5. format:指定像素数据的格式,例如 GL_RGBA 表示每个像素包含红、绿、蓝和 alpha 通道。
  6. type:指定像素数据的类型,例如 GL_UNSIGNED_BYTE 表示无符号字节类型。
  7. pixels:指向包含要更新的像素数据的内存块的指针。
  8. 这个函数用于将像素数据上传到纹理,从而更新或替换纹理的一部分内容。它可以用于动态修改纹理,例如在实时渲染中更新场景的一部分。在调用该函数之前,通常需要确保已经生成了纹理对象并绑定到相应的纹理单元。

glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels)

glTexSubImage2D 是一个用于在二维纹理中更新(替换或添加)一部分像素数据的函数。它是 Open Graphics Library (OpenGL) 图形库的一部分。

以下是对每个参数的解释:

  1. target:指定目标纹理,通常设置为 GL_TEXTURE_2D 表示二维纹理。
  2. level:指定要更新的 mipmap 层次,0 表示基础层,n 表示第 n 层 mipmap 纹理。
  3. xoffset 和 yoffset:分别指定在纹理的 x 和 y 轴上的偏移量,用于确定要更新的纹理区域的起始位置。
  4. width 和 height:分别指定要更新的纹理区域的宽度和高度。
  5. format:指定像素数据的格式,例如 GL_RGBA 表示每个像素包含红、绿、蓝和 alpha 通道。
  6. type:指定像素数据的类型,例如 GL_UNSIGNED_BYTE 表示无符号字节类型。
  7. pixels:指向包含要更新的像素数据的内存块的指针。

这个函数用于将像素数据上传到纹理,从而更新或替换纹理的一部分内容。它可以用于动态修改纹理,例如在实时渲染中更新场景的一部分。在调用该函数之前,通常需要确保已经生成了纹理对象并绑定到相应的纹理单元。

插入替换纹理

 glCopyTexSubImage1D(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width)

glCopyTexSubImage1D 是 Open Graphics Library (OpenGL) 中的一个函数,用于将一维纹理图像的一部分从帧缓冲区复制到纹理图像中。

以下是对每个参数的解释:

  1. target:指定目标纹理,通常设置为 GL_TEXTURE_1D 表示一维纹理。
  2. level:指定要复制的 mipmap 层次,0 表示基础层,n 表示第 n 层 mipmap 纹理。
  3. xoffset:指定在纹理的 x 轴上的偏移量,用于确定要复制的纹理区域的起始位置。
  4. xy:指定纹理的左下角坐标。
  5. width:指定要复制的纹理区域的宽度。

这个函数用于将帧缓冲区中的像素数据复制到纹理中,从而更新或替换纹理的一部分内容。它可以用于动态生成或更新纹理,例如在实时渲染中从渲染结果中捕获图像并将其作为纹理使用。

在调用该函数之前,通常需要确保已经生成了纹理对象并绑定到相应的纹理单元。

 glCopyTexSubImage1D(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width)

glCopyTexSubImage1D是 Open Graphics Library (OpenGL) 中的一个函数,用于将一维纹理图像的一部分从帧缓冲区复制到纹理图像中。

以下是对每个参数的解释:

  1. target:指定目标纹理,通常设置为 GL_TEXTURE_1D 表示一维纹理。
  2. level:指定要复制的 mipmap 层次,0 表示基础层,n 表示第 n 层 mipmap 纹理。
  3. xoffset:指定在纹理的 x 轴上的偏移量,用于确定要复制的纹理区域的起始位置。
  4. xy:指定纹理的左下角坐标。
  5. width:指定要复制的纹理区域的宽度。

这个函数用于将帧缓冲区中的像素数据复制到纹理中,从而更新或替换纹理的一部分内容。它可以用于动态生成或更新纹理,例如在实时渲染中从渲染结果中捕获图像并将其作为纹理使用。

在调用该函数之前,通常需要确保已经生成了纹理对象并绑定到相应的纹理单元。

纹理对象

创建纹理对象
 glGenTextures(GLsizei n, GLuint *textures)

glGenTextures 是 Open Graphics Library (OpenGL) 中的一个函数,用于生成纹理对象的标识符。

以下是对每个参数的解释:

  1. GLsizei n:指定要生成的纹理对象数量。
  2. GLuint *textures:指向一个数组,用于存储生成的纹理对象的标识符。

这个函数用于创建纹理对象,这些对象用于在图形应用程序中存储和管理纹理数据。生成的纹理对象标识符可以用于后续的纹理操作,例如绑定纹理、设置纹理参数等。

在调用该函数之前,通常需要确保已经创建了纹理对象,并将纹理对象与相应的纹理单元进行绑定。

绑定纹理对象
glBindTexture(GLenum target, GLuint texture)

glBindTexture 是 Open Graphics Library (OpenGL) 中的一个函数,用于将纹理对象绑定到指定的纹理目标。

以下是对每个参数的解释:

  1. GLenum target:指定要绑定纹理的目标,通常设置为 GL_TEXTURE_2D 表示二维纹理。
  2. GLuint texture:指定要绑定的纹理对象的标识符。

这个函数用于将纹理对象与纹理目标相关联,以便在后续的绘图操作中使用该纹理。在调用该函数之前,通常需要先使用 glGenTextures 函数生成纹理对象,并使用 glTexImage2D 或其他函数加载或设置纹理数据。

通过调用 glBindTexture,可以将纹理对象绑定到指定的纹理目标,然后在绘图命令中使用相应的纹理坐标来引用纹理。

删除纹理对象
glDeleteTextures(GLsizei n, const GLuint *textures)

glDeleteTextures 是 Open Graphics Library (OpenGL) 中的一个函数,用于删除已生成的纹理对象。

以下是对每个参数的解释:

  1. GLsizei n:指定要删除的纹理对象数量。
  2. const GLuint *textures:指向一个包含要删除的纹理对象标识符的数组。

这个函数用于释放不再需要的纹理对象所占用的内存资源。通过调用该函数,可以将指定数量的纹理对象从系统中删除,释放其所占用的内存。

在调用该函数之前,确保已经解除了纹理对象与任何纹理单元的绑定,并且不再使用这些纹理对象进行绘图操作。

测试纹理对象是否有效
glIsTexture(GLuint texture)

glIsTexture是OpenGL中的一个函数,用于确定一个ID是否与纹理相对应。其函数原型为GLboolean glIsTexture(GLuint texture),参数texture指定一个可能是纹理ID的值。如果texture是一个纹理ID,那么glIsTexture将返回GL_TRUE;如果texture的值是0或者非0但是不是纹理ID,又或者有错误生成了glIsTexture,都会返回GL_FALSE。如果这个texture确实是由glGenTextures生成的,但是还没有调用glBindTexture来关联,那么我们也认为这个texture不是纹理ID。

设置纹理参数

参数1:target,指定这些参数将要应用在那个纹理模式上,比如GI TEXTURE 1D、GI TEXTURE 2D、GL TEXTURE 3D。
参数2:pname,指定需要设置那个纹理参数
参数3:param,设定特定的纹理参数的值

glTexParameterf 是 Open Graphics Library (OpenGL) 中的一个函数,用于设置纹理参数的值。

glTexParameterf(GLenum target, GLenum pname, GLfloat param)
  1. GLenum target:指定要设置参数的纹理目标,通常设置为 GL_TEXTURE_2D 表示二维纹理。
  2. GLenum pname:指定要设置的纹理参数的名称。
  3. GLfloat param:指定要设置的纹理参数的值。

这个函数用于设置纹理的各种参数,例如纹理的滤波方式、纹理环绕方式等。通过设置不同的 pname 参数,可以控制纹理的行为和效果。

glTexParameteri(GLenum target, GLenum pname, GLint param)
  1. GLenum target:指定要设置参数的纹理目标,通常设置为 GL_TEXTURE_2D 表示二维纹理。
  2. GLenum pname:指定要设置的纹理参数的名称。
  3. GLint param:指定要设置的纹理参数的值。

与 glTexParameterf 函数类似,这个函数用于设置纹理的各种参数,例如纹理的滤波方式、纹理环绕方式等。通过设置不同的 pname 参数,可以控制纹理的行为和效果。

在调用该函数之前,通常需要先使用 glBindTexture 函数将纹理对象绑定到指定的纹理目标。

glTexParameteriv(GLenum target, GLenum pname, const GLint *params)
  1. GLenum target:指定要设置参数的纹理目标,通常设置为 GL_TEXTURE_2D 表示二维纹理。
  2. GLenum pname:指定要设置的纹理参数的名称。
  3. const GLint *params:指向一个包含要设置的纹理参数值的整数数组。

这个函数与 glTexParameteri 函数类似,用于设置纹理的各种参数,例如纹理的滤波方式、纹理环绕方式等。通过设置不同的 pname 参数,可以控制纹理的行为和效果。

在调用该函数之前,通常需要先使用 glBindTexture 函数将纹理对象绑定到指定的纹理目标。

glTexParameterfv(GLenum target, GLenum pname, const GLfloat *params)
  1. GLenum target:指定要设置参数的纹理目标,通常设置为 GL_TEXTURE_2D 表示二维纹理。
  2. GLenum pname:指定要设置的纹理参数的名称。
  3. const GLfloat *params:指向一个包含要设置的纹理参数值的浮点数数组。

这个函数与 glTexParameteri 函数类似,用于设置纹理的各种参数,例如纹理的滤波方式、纹理环绕方式等。通过设置不同的 pname 参数,可以控制纹理的行为和效果。

在调用该函数之前,通常需要先使用 glBindTexture 函数将纹理对象绑定到指定的纹理目标。

过滤

临近过滤和线性过滤

临近过滤是一种用于图像处理和计算机图形学的技术,用于提高渲染速度和图像质量。它通过在内存中维护一个较小的“临近”数据结构,来加速对大量数据的访问。

在纹理过滤中,临近过滤通过使用临近像素的颜色来计算当前像素的颜色,从而减少对纹理数据的访问次数。这种方法可以在保证图像质量的同时,提高渲染速度。

临近过滤通常有以下几种实现方式:

  • 最近邻过滤:使用最近的像素颜色作为当前像素的颜色。
  • 双线性过滤:使用相邻的四个像素的颜色,通过加权平均来计算当前像素的颜色。
  • 三线性过滤:使用相邻的八个像素的颜色,通过加权平均来计算当前像素的颜色。

临近过滤可以在各种硬件平台上实现,并且可以根据需要进行调整,以适应不同的场景和需求。

线性过滤是一种用于图像处理和计算机图形学的技术,用于生成更平滑的图像或纹理。它通过对相邻像素的颜色值进行加权平均来计算当前像素的颜色值。

在线性过滤中,权重通常根据相邻像素与当前像素的距离来确定。离当前像素越近的像素会被赋予更高的权重,离当前像素越远的像素会被赋予较低的权重。这样可以在保持图像细节的同时,减少图像中的噪点和锯齿。

常见的线性过滤方法包括双线性过滤和三线性过滤。双线性过滤使用当前像素周围的四个像素进行加权平均,而三线性过滤则使用当前像素周围的八个像素进行加权平均。这些方法可以在不同的硬件平台上实现,并且可以根据需要进行调整,以适应不同的场景和需求。

线性过滤通常用于生成更平滑的纹理映射、抗锯齿处理和图像缩放等操作中。它可以提高图像的质量和视觉效果,但可能会导致一定程度的图像模糊。

    /// 纹理缩小时 使用临近过滤
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
    /// 纹理放大时 使用线性过滤
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
环绕方式
GL_TEXTURE_WRAP_S 

GL_TEXTURE_WRAP_S是OpenGL中的一个纹理参数,用于指定纹理在水平方向上的重复模式,取值范围为GL_REPEATGL_CLAMP_TO_EDGEGL_MIRRORED_REPEAT

通过调用glTexParameteri函数并传入GL_TEXTURE_WRAP_S和相应的参数值,可以控制纹理在水平方向上的重复方式。例如,将参数值设置为GL_REPEAT表示纹理在水平方向上循环重复,而设置为GL_CLAMP_TO_EDGE则表示纹理在水平方向上被约束在边缘处。

GL_TEXTURE_WRAP_T

GL_TEXTURE_WRAP_T是OpenGL中的一个纹理参数,用于指定纹理在垂直方向上的重复模式,取值范围为GL_REPEATGL_CLAMP_TO_EDGEGL_MIRRORED_REPEAT

通过调用glTexParameteri函数并传入GL_TEXTURE_WRAP_T和相应的参数值,可以控制纹理在垂直方向上的重复方式。例如,将参数值设置为GL_REPEAT表示纹理在垂直方向上循环重复,而设置为GL_CLAMP_TO_EDGE则表示纹理在垂直方向上被约束在边缘处。

GL_CLAMP_TO_EDGE

GL_CLAMP_TO_EDGE 是 Open Graphics Library (OpenGL) 中的一个纹理参数,用于指定纹理在坐标超出纹理边界时的行为。

当 GL_CLAMP_TO_EDGE 被设置为纹理参数时,纹理的采样将被限制在纹理的边界上。这意味着,如果纹理坐标超出了纹理的范围,将返回纹理边界上的颜色值,而不是进行插值或重复。

可以通过调用 glTexParameteri 函数并传入 GL_TEXTURE_WRAP_S 或 GL_TEXTURE_WRAP_T 以及 GL_CLAMP_TO_EDGE 来设置纹理的边界行为。

以下是一个示例代码,演示如何将纹理的边界行为设置为 GL_CLAMP_TO_EDGE

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

在这个示例中,将纹理的 S 和 T 方向的边界行为都设置为 GL_CLAMP_TO_EDGE,以确保纹理在超出边界时不会进行插值或重复。

请注意,GL_CLAMP_TO_EDGE 是一种常见的纹理边界处理方式,适用于许多情况。其他可选的纹理边界处理方式包括 GL_REPEAT(重复纹理)和 GL_MIRRORED_REPEAT(镜像重复纹理)。选择合适的边界处理方式取决于具体的需求和效果。

demo

#include "GLTools.h"
#include "GLBatch.h"
#include "GLMatrixStack.h"
#include "GLShaderManager.h"
#include "GLFrame.h"
#include "GLFrustum.h"
#include "StopWatch.h"
#include "GLGeometryTransform.h"
#ifdef __APPLE__
#include <GLUT/GLUT.h>
#else
#include <GL/glut.h>
#endif
static GLShaderManager shaderManager; // 着色器管理器
static GLMatrixStack modelViewMatrix; // 模型视图矩阵 视图变化需要放在模型视图矩阵里面
static GLMatrixStack projectionMatrix; // 投影矩阵
//角色帧 照相机角色帧
static GLFrame             cameraFrame;

static GLFrame             objectFrame;
static GLFrustum           viewFrustum;      // 视景体
static GLBatch            pyramidBatch;             // 地板批处理
static GLuint              textureID;
static GLGeometryTransform transformPipeline;
static M3DMatrix44f         shadowMatrix;

//**4、添加附加随机球
#define NUM_SPHERES 50
static GLFrame spheres[NUM_SPHERES];

static void SpecialFunc(int key, int x, int y) {
    float linear = 0.1f;
    float angular = float(m3dDegToRad(5.0f));
    
    if (key == GLUT_KEY_UP) {
       
        //MoveForward 平移
        objectFrame.RotateWorld(m3dDegToRad(-5.0f), 1.0f, 0.0f, 0.0f);
    }
    
    if (key == GLUT_KEY_DOWN) {
        objectFrame.RotateWorld(m3dDegToRad(5.0f), 1.0f, 0.0f, 0.0f);
    }
    
    if (key == GLUT_KEY_LEFT) {
        //RotateWorld 旋转
        objectFrame.RotateWorld(m3dDegToRad(-5.0f), 0.0f, 1.0f, 0.0f);
    }
    
    if (key == GLUT_KEY_RIGHT) {
        objectFrame.RotateWorld(m3dDegToRad(5.0f), 0.0f, 1.0f, 0.0f);
    }
    glutPostRedisplay();

}
static void glutKeyboardFunc(unsigned char key, int x, int y) {
    
    
}
static void glutShape(int w, int h) {
    if (h == 0) {
        h == 1.0f;
    }
    glViewport(0, 0, w, h);
    viewFrustum.SetPerspective(10.0f, (float)w/(float)h, 1.0, 50.f);
    projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
    transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
    
    
}
static bool LoadTGATexture(const char *szFileName,GLenum minFilter,GLenum magFilter,GLenum wrapMode) {
    GLbyte *pBits;
    int mWidth, mHeight, mComponents;
    GLenum eformat;
    //1. 读取像素
    /*
     pBits = gltReadTGABits(const char *szFileName, GLint *iWidth, GLint *iHeight, GLint *iComponents, GLenum *eFormat)
     const char *szFileName 纹理文件名称
     GLint *iWidth 纹理宽度
     GLint *iHeight 纹理高度
     GLint *iComponents 图片的组件地址
     GLenum *eForma 文件格式地址
     */
    pBits = gltReadTGABits(szFileName, &mWidth, &mHeight, &mComponents, &eformat);
    if(pBits == NULL) {
        return false;
    }
    /// 设置纹理参数
    
    //2、设置纹理参数
    //参数1:纹理维度
    //参数2:为S/T坐标设置模式
    //参数3:wrapMode,环绕模式
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapMode);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapMode);

    //参数1:纹理维度
    //参数2:线性过滤
    //参数3:wrapMode,环绕模式
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter);
    //3、精密包装像素数据
    //参数1:GL_UNPACK_ALIGNMENT,指定OpenGL如何从数据缓存区中解包图像数据
    //参数2:针对GL_UNPACK_ALIGNMENT 设置的值
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    //载入纹理
    glTexImage2D(GL_TEXTURE_2D, 0, mComponents, mWidth, mHeight, 0, eformat, GL_UNSIGNED_BYTE, pBits);
    free(pBits);
    
    //只有minFilter 等于以下四种模式,才可以生成Mip贴图
    //GL_NEAREST_MIPMAP_NEAREST具有非常好的性能,并且闪烁现象非常弱
    //GL_LINEAR_MIPMAP_NEAREST常常用于对游戏进行加速,它使用了高质量的线性过滤器
    //GL_LINEAR_MIPMAP_LINEAR 和GL_NEAREST_MIPMAP_LINEAR 过滤器在Mip层之间执行了一些额外的插值,以消除他们之间的过滤痕迹。
    //GL_LINEAR_MIPMAP_LINEAR 三线性Mip贴图。纹理过滤的黄金准则,具有最高的精度。
    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;
}
static void MakePyramid(GLBatch batch) {
    /*1、通过pyramidBatch组建三角形批次
      参数1:类型
      参数2:顶点数
      参数3:这个批次中将会应用1个纹理
      注意:如果不写这个参数,默认为0。
     */
    pyramidBatch.Begin(GL_TRIANGLES, 18, 1);
    
    //金字塔底部
    //底部的四边形 = 三角形X + 三角形Y
    //三角形X
    
    /*设置法线
     Normal3f:添加一个表面法线(法线坐标 与 Vertex顶点坐标中的Y轴一致)
     表面法线是有方向的向量,代表表面或者顶点面对的方向(相反的方向)。在多数的关照模式下是必须使用。后面的课程会详细来讲法线的应用
     */
    pyramidBatch.Normal3f(0.0f, -1.0f, 0.0f);
    /**设置纹理坐标
     MultiTexCoord2f(GLuint texture,GLclampf s,GLclamp t);
     参数1:texture,纹理层次,对于使用存储着色器来进行渲染,设置为0
     参数2:(s,t,r,q对应顶点坐标的x,y,z,w)s:对应顶点坐标中的x坐标
     参数3:t:对应顶点坐标中的y
     */
    pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
    //vBlackLeft点
    pyramidBatch.Vertex3f(-1.0f, -1.0f, -1.0f);
   
    
    pyramidBatch.Normal3f(0.0f, -1.0f, 0.0f);
    pyramidBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
    //vBlackRight点
    pyramidBatch.Vertex3f(1.0f, -1.0f, -1.0f);
    
    pyramidBatch.Normal3f(0.0f, -1.0f, 0.0f);
    pyramidBatch.MultiTexCoord2f(0, 1.0f, 1.0f);
    //vFrontRight点
    pyramidBatch.Vertex3f(1.0f, -1.0f, 1.0f);
    
    
    //三角形B
    pyramidBatch.Normal3f(0.0f, -1.0f, 0.0f);
    pyramidBatch.MultiTexCoord2f(0, 0.0f, 1.0f);
    pyramidBatch.Vertex3f(-1.0f, -1.0f, 1.0f);
    
    pyramidBatch.Normal3f(0.0f, -1.0f, 0.0f);
    pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
    pyramidBatch.Vertex3f(-1.0f, -1.0f, -1.0f);
    
    pyramidBatch.Normal3f(0.0f, -1.0f, 0.0f);
    pyramidBatch.MultiTexCoord2f(0, 1.0f, 1.0f);
    pyramidBatch.Vertex3f(1.0f, -1.0f, 1.0f);
    
    //塔顶
    M3DVector3f vApex = { 0.0f, 1.0f, 0.0f };
    M3DVector3f vFrontLeft = { -1.0f, -1.0f, 1.0f };
    M3DVector3f vFrontRight = { 1.0f, -1.0f, 1.0f };
    M3DVector3f vBackLeft = { -1.0f, -1.0f, -1.0f };
    M3DVector3f vBackRight = { 1.0f, -1.0f, -1.0f };
    M3DVector3f n;
    
    
    // 金字塔前面
    //三角形:(Apex,vFrontLeft,vFrontRight)
    //纹理坐标设置,参考PPT图6-4图
    /** 获取从三点找到一个法线坐标(三点确定一个面)
     void m3dFindNormal(result,point1, point2,point3);
     参数1:结果
     参数2-4:3个顶点数据
     */
    m3dFindNormal(n, vApex, vFrontLeft, vFrontRight);
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 0.5f, 1.0f);
    pyramidBatch.Vertex3fv(vApex);
    
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
    pyramidBatch.Vertex3fv(vFrontLeft);

    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
    pyramidBatch.Vertex3fv(vFrontRight);
    
    //金字塔左边
    //三角形:(vApex, vBackLeft, vFrontLeft)
    m3dFindNormal(n, vApex, vBackLeft, vFrontLeft);
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 0.5f, 1.0f);
    pyramidBatch.Vertex3fv(vApex);
    
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
    pyramidBatch.Vertex3fv(vBackLeft);
    
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
    pyramidBatch.Vertex3fv(vFrontLeft);
    
    //金字塔右边
    //三角形:(vApex, vFrontRight, vBackRight)
    m3dFindNormal(n, vApex, vFrontRight, vBackRight);
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 0.5f, 1.0f);
    pyramidBatch.Vertex3fv(vApex);
    
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
    pyramidBatch.Vertex3fv(vFrontRight);
    
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
    pyramidBatch.Vertex3fv(vBackRight);
    
    //金字塔后边
    //三角形:(vApex, vBackRight, vBackLeft)
    m3dFindNormal(n, vApex, vBackRight, vBackLeft);
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 0.5f, 1.0f);
    pyramidBatch.Vertex3fv(vApex);
    
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
    pyramidBatch.Vertex3fv(vBackRight);
    
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
    pyramidBatch.Vertex3fv(vBackLeft);
    
    //结束批次设置
    pyramidBatch.End();
}
static void loadData() {
    glClearColor(0.7f, 0.7f, 0.7f, 1.0f);
    shaderManager.InitializeStockShaders();
    glEnable(GL_DEPTH_TEST);
    //分配纹理对象 参数1:纹理对象个数,参数2:纹理对象指针
    glGenTextures(1, &textureID);
    //绑定纹理状态 参数1:纹理状态2D 参数2:纹理对象
    glBindTexture(GL_TEXTURE_2D, textureID);
    
    //将TGA文件加载为2D纹理。
    //参数1:纹理文件名称
    //参数2&参数3:需要缩小&放大的过滤器
    //参数4:纹理坐标环绕模式
    LoadTGATexture("brick.tga",GL_LINEAR_MIPMAP_NEAREST,GL_LINEAR,GL_CLAMP_TO_EDGE);
    
    //创造金字塔pyramidBatch
    MakePyramid(pyramidBatch);
    
    /**相机frame MoveForward(平移)
    参数1:Z,深度(屏幕到图形的Z轴距离)
     */
    cameraFrame.MoveForward(-20.0f);
    
}


static void RenderScene() {
    
    static float vLightPos[] = {1.0f,1.0f,0.0f};
    static float vWhite[] = {1.0f,1.0f,1.0f,1.0f};
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
    
    modelViewMatrix.PushMatrix();
    //添加观察者矩形
    M3DMatrix44f mCamera;
    //从camraFrame中获取一个4*4的矩阵
    cameraFrame.GetCameraMatrix(mCamera);
    //矩阵乘以矩阵堆栈顶部矩阵,相乘结果存储到堆栈的顶部 将照相机矩阵 与 当前模型矩阵相乘 压入栈顶
    modelViewMatrix.MultMatrix(mCamera);
    
     
    //添加mObjectFrame矩阵
    M3DMatrix44f mobjectFrame;
    //从objectFrame中获取矩阵,objectFrame保存的是特殊键位的变换矩阵
    objectFrame.GetMatrix(mobjectFrame);
    //矩阵乘以矩阵堆栈顶部矩阵,相乘结果存储到堆栈的顶部 将世界变换矩阵 与 当前模型矩阵相乘 压入栈顶
    modelViewMatrix.MultMatrix(mobjectFrame);
    //绑定纹理,因为我们的项目中只有一个纹理。如果有多个纹理。绑定纹理很重要
    glBindTexture(GL_TEXTURE_2D, textureID);
    /*
     参数1:GLT_SHADER_POINT_LIGHT_DIFF
     参数2:模型视图矩阵
     参数3: 投影矩阵
     参数4: 光源位置
     参数5: 漫反射颜色
     参数6:图形填充颜色(纹理 可以不需要设置颜色 设置为0)
     */
    shaderManager.UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF,transformPipeline.GetModelViewMatrix(),transformPipeline.GetProjectionMatrix(),vLightPos,vWhite,0);
    pyramidBatch.Draw();
    modelViewMatrix.PopMatrix();
    glutSwapBuffers();
    
}
static void freeSource() {
    glDeleteTextures(1, &textureID);
    
}
int main(int argc,char *argv[]) {
    
    gltSetWorkingDirectory(argv[0]);
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH);
    glutInitWindowSize(800, 600);
    glutCreateWindow("window");
    
    GLenum error = glewInit();
    
    if (error != GLEW_OK) {
        printf("===============error=\%s\n",glewGetErrorString(error));
        return 1;
    }
    glutSpecialFunc(SpecialFunc);
    
    glutKeyboardFunc(glutKeyboardFunc);
    
    glutReshapeFunc(glutShape);
    
    glutDisplayFunc(RenderScene);
    loadData();
    
    glutMainLoop();
    freeSource();
    return 0;
}

/*
 /// 纹理缩小时 使用临近过滤
 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
 /// 纹理放大时 使用线性过滤
 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)

 glTexParameteriv(GLenum target, GLenum pname, const GLint *params)
 glTexParameterfv(GLenum target, GLenum pname, const GLfloat *params)
 glTexParameteri(GLenum target, GLenum pname, GLint param)
 
 glIsTexture(GLuint texture)
 glDeleteTextures(GLsizei n, const GLuint *textures)
 glBindTexture(GLenum target, GLuint texture)
 
 glGenTextures(GLsizei n, GLuint *textures)
 
 glCopyTexSubImage1D(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width)
 glCopyTexSubImage1D(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width)
 glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels)
 glCopyTexImage1D(, <#GLint level#>, <#GLenum internalFormat#>, <#GLint x#>, <#GLint y#>, <#GLsizei width#>, <#GLint border#>)
 glTexImage2D(<#GLenum target#>, <#GLint level#>, <#GLint internalformat#>, <#GLsizei width#>, <#GLsizei height#>, <#GLint border#>, <#GLenum format#>, <#GLenum type#>, <#const GLvoid *pixels#>)
 glTexImage1D(<#GLenum target#>, <#GLint level#>, <#GLint internalformat#>, GLsizei width, <#GLint border#>, <#GLenum format#>, <#GLenum type#>, <#const GLvoid *pixels#>)

 
 
 
 */

  纹理加载小demo

#include "GLTools.h"
#include "GLBatch.h"
#include "GLMatrixStack.h"
#include "GLShaderManager.h"
#include "GLFrame.h"
#include "GLFrustum.h"
#include "StopWatch.h"
#include "GLGeometryTransform.h"
#ifdef __APPLE__
#include <GLUT/GLUT.h>
#else
#include <GL/glut.h>
#endif
static GLShaderManager shaderManager;    /// 着色器 管理器
static GLMatrixStack   modelViewMatrix;  // 模型视图矩阵
static GLMatrixStack   projectMatrix;    // 投影矩阵
static GLFrustum       viewFrustum;      // 视景体
static GLGeometryTransform transformPipeline; // 几何变换管线
// 4个批次容器类
static GLBatch     floorBatch; /// 地面
static GLBatch     ceilingBatch; // 天花板
static GLBatch     leftWallBatch;  ///左墙面
static GLBatch     rightWallBatch; /// 右墙面
/// 深度初始值 往屏幕里面
static GLfloat     viewZ = -65.0f;
#define TEXTURE_BRICK 0 //墙面
#define TEXTURE_FLOOR 1 //地板
#define TEXTURE_CEILING 2 //纹理天花板
#define TEXTURE_COUNT 3 //纹理个数
static GLuint textures[TEXTURE_COUNT]; // 纹理标记数组
/// 文件tag名字数组
static const char *szTextureFiles[TEXTURE_COUNT] = {"brick.tga","floor.tga","ceiling.tga"};

static void SpecialFunc(int key, int x, int y) {
    // 修改z值
    if (key == GLUT_KEY_UP) {

        viewZ += 0.5;
    }

    if (key == GLUT_KEY_DOWN) {
        viewZ -= 0.5;
    }
    glutPostRedisplay();

}
static void glutKeyboardFunc(unsigned char key, int x, int y) {
    
    
}
static void glutShape(int w, int h) {
    if (h == 0) {
        h == 1.0f;
    }
    glViewport(0, 0, w, h);
    /// 设置投影方式
    viewFrustum.SetPerspective(80.0f, float(w)/float(h), 1.0f, 35.0f);
    projectMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
    
    transformPipeline.SetMatrixStacks(modelViewMatrix, projectMatrix);
}
static bool LoadTGATexture(const char *szFileName,GLenum minFilter,GLenum magFilter,GLenum wrapMode) {
    return true;
}
static void loadData() {
    GLbyte *pBytes;
    GLint iWidth,iHeight,iComponets;
    GLenum eFormat;
    GLint iLoop;
    ///设置背景颜色
    glClearColor(0.0f, 0.0f, 0.0f,  1.0f);
    shaderManager.InitializeStockShaders();
    /// 加载纹理
    glGenTextures(TEXTURE_COUNT, textures);
    /// 循环加载纹理
    for (iLoop = 0; iLoop < TEXTURE_COUNT; iLoop++) {
        ///绑定纹理
        glBindTexture(GL_TEXTURE_2D, textures[iLoop]);
        /// 加载TGA文件
        pBytes = gltReadTGABits(szTextureFiles[iLoop], &iWidth, &iHeight, &iComponets, &eFormat);
        /// 过滤
        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, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        // 载入纹理
        glTexImage2D(GL_TEXTURE_2D, 0, iComponets, iWidth, iHeight, 0, eFormat, GL_UNSIGNED_BYTE,pBytes);
        glGenerateMipmap(GL_TEXTURE_2D);
        free(pBytes);
    }
    /// 建立几何图形
    floorBatch.Begin(GL_TRIANGLE_STRIP, 28,1);
    GLfloat z = 0;
    for (z = 60.f; z >= 0.0f; z -= 10.0f) {
        /// 纹理坐标
        floorBatch.MultiTexCoord2f(0, 0, 0);
        floorBatch.Vertex3f(-10.f, -10.f, z);
        
        floorBatch.MultiTexCoord2f(0, 1, 0);
        floorBatch.Vertex3f(10.f, -10.f, z);

        floorBatch.MultiTexCoord2f(0, 0, 1);
        floorBatch.Vertex3f(-10.f, -10.f, z - 10.f);
        
        floorBatch.MultiTexCoord2f(0, 1, 1);
        floorBatch.Vertex3f(10.f, -10.f, z - 10.f);


    }
    floorBatch.End();
    
    
    ceilingBatch.Begin(GL_TRIANGLE_STRIP, 28,1);
    for (z = 60.f; z >= 0.0f; z -= 10.0f) {
        /// 纹理坐标
        ceilingBatch.MultiTexCoord2f(0, 0, 1);
        ceilingBatch.Vertex3f(-10.f, 10.f, z - 10.f);
           
        ceilingBatch.MultiTexCoord2f(0, 1, 1);
        ceilingBatch.Vertex3f(10.f, 10.f, z - 10.f);

        
        ceilingBatch.MultiTexCoord2f(0, 0, 0);
        ceilingBatch.Vertex3f(-10.f, 10.f, z);
        
        ceilingBatch.MultiTexCoord2f(0, 1, 0);
        ceilingBatch.Vertex3f(10.f, 10.f, z);

    }
    ceilingBatch.End();

    leftWallBatch.Begin(GL_TRIANGLE_STRIP, 28,1);
    for (z = 60.f; z >= 0.0f; z -= 10.0f) {
        /// 纹理坐标
        leftWallBatch.MultiTexCoord2f(0, 0, 0);
        leftWallBatch.Vertex3f(-10.f, -10.f, z);

        leftWallBatch.MultiTexCoord2f(0, 0, 1);
        leftWallBatch.Vertex3f(-10.f, 10.f, z);
        
        leftWallBatch.MultiTexCoord2f(0, 1, 0);
        leftWallBatch.Vertex3f(-10.f, -10.f, z -10.f);

        
        leftWallBatch.MultiTexCoord2f(0, 1, 1);
        leftWallBatch.Vertex3f(-10.f, 10.f, z - 10.f);

    }
    leftWallBatch.End();

    rightWallBatch.Begin(GL_TRIANGLE_STRIP, 28,1);
    for (z = 60.f; z >= 0.0f; z -= 10.0f) {
        /// 纹理坐标
        rightWallBatch.MultiTexCoord2f(0, 0, 0);
        rightWallBatch.Vertex3f(10.f, -10.f, z);

        rightWallBatch.MultiTexCoord2f(0, 0, 1);
        rightWallBatch.Vertex3f(10.f, 10.f, z);
        
        rightWallBatch.MultiTexCoord2f(0, 1, 0);
        rightWallBatch.Vertex3f(10.f, -10.f, z -10.f);

        
        rightWallBatch.MultiTexCoord2f(0, 1, 1);
        rightWallBatch.Vertex3f(10.f, 10.f, z - 10.f);

    }
    rightWallBatch.End();


    
}
static  void RenderScene() {
    glClear(GL_COLOR_BUFFER_BIT);
    
    modelViewMatrix.PushMatrix();
    modelViewMatrix.Translate(0, 0, viewZ);
    shaderManager.UseStockShader(GLT_SHADER_TEXTURE_REPLACE,transformPipeline.GetModelViewProjectionMatrix(),0);
    glBindTexture(GL_TEXTURE_2D, textures[TEXTURE_FLOOR]);
    floorBatch.Draw();
    glBindTexture(GL_TEXTURE_2D, textures[TEXTURE_CEILING]);
    ceilingBatch.Draw();

    glBindTexture(GL_TEXTURE_2D, textures[TEXTURE_BRICK]);
    leftWallBatch.Draw();
    rightWallBatch.Draw();
    modelViewMatrix.PopMatrix();
    glutSwapBuffers();
}
static void freeSource() {
    glDeleteTextures(TEXTURE_COUNT, textures);
}
static void ProcessMenu(int value) {
    /// 4个纹理
    GLint iLoop;
    for (iLoop = 0; iLoop < TEXTURE_COUNT;iLoop++) {
        glBindTexture(GL_TEXTURE_2D,    textures[iLoop]);
        switch (value) {
            case 0:
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
                break;
            case 1:
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
                break;
            case 2:
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
                break;
            case 3:
                /*
                 GL_TEXTURE_MIN_FILTER(缩小过滤器)
                 GL_NEAREST_MIPMAP_LINEAR
                 */
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);
                break;
            case 4:
                /*
                 GL_TEXTURE_2D GL_TEXTURE_MIN_FILTER(缩小过滤器)
                 GL_NEAREST_MIPMAP_LINEAR (选择最邻近Mip层 并执行线性过滤)
                 */
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
                break;
            case 5:
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
                break;
            case 6:
                GLfloat fLargest;
                glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &fLargest);
                glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, fLargest);
                break;
            case 7:
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f);
                break;

            default:
                break;
        }
    }
    glutPostRedisplay();
}


int main(int argc,char *argv[]) {
    
    gltSetWorkingDirectory(argv[0]);
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH);
    glutInitWindowSize(800, 600);
    glutCreateWindow("window");
    
    GLenum error = glewInit();
    
    if (error != GLEW_OK) {
        printf("===============error=\%s\n",glewGetErrorString(error));
        return 1;
    }
    glutSpecialFunc(SpecialFunc);
    
    glutKeyboardFunc(glutKeyboardFunc);
    
    glutReshapeFunc(glutShape);
    
    glutDisplayFunc(RenderScene);
    
    glutCreateMenu(ProcessMenu);
    
    glutAddMenuEntry("GL_NEARST", 0);
    glutAddMenuEntry("GL_LINEAR", 1);
    glutAddMenuEntry("GL_NEARST_MIPMAP_NEARST", 2);
    glutAddMenuEntry("GL_NEARST_MIPMAP_LINEAR", 3);
    glutAddMenuEntry("GL_LINEAR_MIPMAP_NEAREST", 4);
    glutAddMenuEntry("GL_LINEAR_MIPMAP_LINEAR", 5);

    glutAddMenuEntry("Anisotropic Filter", 6);
    glutAddMenuEntry("Anisotropic off", 7);
    glutAttachMenu(GLUT_RIGHT_BUTTON);
    
    loadData();
    
    glutMainLoop();
    freeSource();
    return 0;
}

/*
 /// 纹理缩小时 使用临近过滤
 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
 /// 纹理放大时 使用线性过滤
 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)

 glTexParameteriv(GLenum target, GLenum pname, const GLint *params)
 glTexParameterfv(GLenum target, GLenum pname, const GLfloat *params)
 glTexParameteri(GLenum target, GLenum pname, GLint param)
 
 glIsTexture(GLuint texture)
 glDeleteTextures(GLsizei n, const GLuint *textures)
 glBindTexture(GLenum target, GLuint texture)
 
 glGenTextures(GLsizei n, GLuint *textures)
 
 glCopyTexSubImage1D(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width)
 glCopyTexSubImage1D(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width)
 glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels)
 glCopyTexImage1D(, <#GLint level#>, <#GLenum internalFormat#>, <#GLint x#>, <#GLint y#>, <#GLsizei width#>, <#GLint border#>)
 glTexImage2D(<#GLenum target#>, <#GLint level#>, <#GLint internalformat#>, <#GLsizei width#>, <#GLsizei height#>, <#GLint border#>, <#GLenum format#>, <#GLenum type#>, <#const GLvoid *pixels#>)
 glTexImage1D(<#GLenum target#>, <#GLint level#>, <#GLint internalformat#>, GLsizei width, <#GLint border#>, <#GLenum format#>, <#GLenum type#>, <#const GLvoid *pixels#>)

 
 
 
 */

  • 22
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值