OpenGL显示图片

显示一个正方形位图文件pictest.bmp。
举例:
LoadT8("images/pictest.bmp", iTex);
glTranslatef(0,0,-10);
texture(iTex);
tPic(3.0f);

附:各个函数的源码:
//绘制正方形
void tPic(float e)
{
glBegin(GL_QUADS);
  glTexCoord2f(0.0f, 0.0f); glVertex3f(-e, -e,  0.0f);
  glTexCoord2f(1.0f, 0.0f); glVertex3f( e, -e,  0.0f);
  glTexCoord2f(1.0f, 1.0f); glVertex3f( e,  e,  0.0f);
  glTexCoord2f(0.0f, 1.0f); glVertex3f(-e,  e,  0.0f);
glEnd();
}
//加载位图
bool LoadT8(char *filename, GLuint &texture)
{
AUX_RGBImageRec *pImage = NULL;

//加载图片内容
pImage = auxDIBImageLoad(filename); 
if(pImage == NULL)
  return false;

//创建纹理
glGenTextures(1, &texture); 
glBindTexture    (GL_TEXTURE_2D,texture);
//生成2维映射
gluBuild2DMipmaps(GL_TEXTURE_2D,4, 
       pImage->sizeX,   
       pImage->sizeY, 
       GL_RGB, GL_UNSIGNED_BYTE,
       pImage->data   
      );
//释放内存
free(pImage->data);     
free(pImage);
return true;     
}
//绑定纹理
void texture(UINT textur)
{
//绑定纹理
glBindTexture  (GL_TEXTURE_2D, textur);
//指定贴图方式和滤波方式
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,

GL_LINEAR_MIPMAP_NEAREST);
}
(感谢《学OPENGL编3D游戏》课件 来自www.gameres.com

<think>我们使用OpenGL显示图片通常采用纹理贴图的方式,这是现代OpenGL的推荐做法。下面我将详细介绍从零开始实现显示图片的步骤,包括如何读取图片数据、创建纹理、设置纹理参数以及渲染纹理。 ### 核心步骤 1. **读取图片数据**:使用图像库(如GDAL、stb_image等)加载图片,获取像素数据 2. **创建纹理对象**:生成OpenGL纹理并绑定 3. **设置纹理参数**:配置纹理过滤方式和环绕方式 4. **上传纹理数据**:将图片像素数据传入OpenGL纹理 5. **渲染纹理**:绘制带有纹理的矩形 ### 详细实现步骤 #### 1. 读取图片数据 使用图像加载库读取图片文件,获取像素数据。这里以`stb_image`为例(跨平台,简单易用): ```cpp #include "stb_image.h" int width, height, channels; unsigned char *data = stbi_load("image.jpg", &width, &height, &channels, 0); if (!data) { // 错误处理 } ``` 注意:`channels`表示颜色通道数(如RGB为3,RGBA为4) #### 2. 创建纹理对象 ```cpp GLuint textureID; glGenTextures(1, &textureID); glBindTexture(GL_TEXTURE_2D, textureID); // 绑定纹理[^2] ``` #### 3. 设置纹理参数 ```cpp // 设置纹理环绕方式 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); // 设置纹理过滤方式 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); ``` #### 4. 上传纹理数据 ```cpp // 根据通道数选择格式 GLenum format = GL_RGB; if (channels == 4) format = GL_RGBA; glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data); glGenerateMipmap(GL_TEXTURE_2D); // 可选:生成Mipmap[^3] ``` #### 5. 释放图像内存 ```cpp stbi_image_free(data); ``` #### 6. 渲染纹理四边形 ```cpp // 顶点数据(位置 + 纹理坐标) float vertices[] = { // 位置 // 纹理坐标 -0.5f, -0.5f, 0.0f, 0.0f, // 左下 0.5f, -0.5f, 1.0f, 0.0f, // 右下 0.5f, 0.5f, 1.0f, 1.0f, // 右上 -0.5f, 0.5f, 0.0f, 1.0f // 左上 }; // 索引数据 unsigned int indices[] = { 0, 1, 2, // 第一个三角形 2, 3, 0 // 第二个三角形 }; // 创建VAO, VBO, EBO GLuint VAO, VBO, EBO; glGenVertexArrays(1, &VAO); glGenBuffers(1, &VBO); glGenBuffers(1, &EBO); // 绑定VAO glBindVertexArray(VAO); // 绑定VBO并填充数据 glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); // 绑定EBO并填充数据 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); // 设置顶点属性指针 // 位置属性 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0); glEnableVertexAttribArray(0); // 纹理坐标属性 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float))); glEnableVertexAttribArray(1); // 解绑 glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); ``` #### 7. 着色器程序 顶点着色器(`vertex_shader.glsl`): ```glsl #version 330 core layout (location = 0) in vec2 aPos; layout (location = 1) in vec2 aTexCoord; out vec2 TexCoord; void main() { gl_Position = vec4(aPos, 0.0, 1.0); TexCoord = aTexCoord; } ``` 片段着色器(`fragment_shader.glsl`): ```glsl #version 330 core in vec2 TexCoord; out vec4 FragColor; uniform sampler2D texture1; void main() { FragColor = texture(texture1, TexCoord); } ``` #### 8. 渲染循环中绘制 ```cpp glUseProgram(shaderProgram); glBindTexture(GL_TEXTURE_2D, textureID); glBindVertexArray(VAO); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); ``` ### 关键注意事项 1. **纹理单元管理**:多纹理时需要激活不同纹理单元 ```cpp glActiveTexture(GL_TEXTURE0); // 激活纹理单元0 glBindTexture(GL_TEXTURE_2D, textureID); ``` 在着色器中设置采样器: ```glsl uniform sampler2D texture1; ``` 然后设置采样器对应的纹理单元(默认为0): ```cpp glUniform1i(glGetUniformLocation(shaderProgram, "texture1"), 0); ``` 2. **纹理坐标系统**:OpenGL纹理坐标原点在左下角,而很多图像格式原点在左上角,可能需要翻转Y轴 - 方法1:翻转纹理坐标(修改顶点数据中的纹理坐标) - 方法2:加载时翻转图像 ```cpp stbi_set_flip_vertically_on_load(true); // 在加载图像前调用 ``` 3. **纹理格式支持**:确保OpenGL支持图像的像素格式(如RGBA8888) ### 不同平台适配 - **Android**:使用`GL_TEXTURE_EXTERNAL_OES`扩展处理相机流等特殊纹理[^3] - **Qt**:在`QOpenGLWidget`中重写`initializeGL`和`paintGL`方法[^2] - **WebGL**:需注意纹理尺寸限制和格式兼容性 ### 性能优化 - 使用纹理图集(Texture Atlas) - 压缩纹理格式(如ASTC、ETC2) - 异步纹理加载 ### 完整流程图 ```mermaid graph TD A[加载图像数据] --> B[创建纹理对象] B --> C[设置纹理参数] C --> D[上传纹理数据] D --> E[创建几何体] E --> F[编译着色器] F --> G[渲染循环] G --> H[绑定纹理] H --> I[绘制四边形] ``` ### 相关问题 1. 如何处理非2的幂次方纹理? 2. OpenGL纹理过滤模式如何选择? 3. 如何实现多图层的混合显示? 4. 纹理内存管理的最佳实践? 5. 跨平台开发中纹理加载的差异处理?</think>### 如何使用 OpenGL 显示图片(纹理贴图方法) 现代 OpenGL 推荐使用纹理贴图方式显示图片,以下是详细步骤: #### 1. 准备图片数据 ```cpp // 使用图像库加载图片(如stb_image.h) int width, height, channels; unsigned char *data = stbi_load("image.jpg", &width, &height, &channels, 0); // 检查是否成功加载 if (!data) { std::cerr << "Failed to load image" << std::endl; return; } ``` #### 2. 创建纹理对象 ```cpp GLuint textureID; glGenTextures(1, &textureID); // 生成纹理ID glBindTexture(GL_TEXTURE_2D, textureID); // 绑定到2D纹理目标[^2] ``` #### 3. 设置纹理参数 ```cpp // 设置纹理环绕方式 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); // 设置纹理过滤方式 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); ``` #### 4. 上传纹理数据 ```cpp // 根据通道数选择格式 GLenum format = (channels == 4) ? GL_RGBA : GL_RGB; glTexImage2D( GL_TEXTURE_2D, // 纹理目标 0, // Mipmap级别 format, // 纹理内部格式 width, // 宽度 height, // 高度 0, // 必须为0(历史遗留) format, // 源数据格式 GL_UNSIGNED_BYTE, // 数据类型 data // 图像数据 ); glGenerateMipmap(GL_TEXTURE_2D); // 生成Mipmap链[^3] ``` #### 5. 创建几何体(四边形) ```cpp // 顶点数据(位置 + 纹理坐标) float vertices[] = { // 位置 // 纹理坐标 -0.5f, -0.5f, 0.0f, 0.0f, // 左下 0.5f, -0.5f, 1.0f, 0.0f, // 右下 0.5f, 0.5f, 1.0f, 1.0f, // 右上 -0.5f, 0.5f, 0.0f, 1.0f // 左上 }; // 索引缓冲 unsigned int indices[] = { 0, 1, 2, // 第一个三角形 2, 3, 0 // 第二个三角形 }; ``` #### 6. 设置顶点属性 ```cpp // 创建VAO/VBO glGenVertexArrays(1, &VAO); glGenBuffers(1, &VBO); glGenBuffers(1, &EBO); // 绑定VAO glBindVertexArray(VAO); // 填充顶点数据 glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); // 填充索引数据 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); // 位置属性 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0); glEnableVertexAttribArray(0); // 纹理坐标属性 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float))); glEnableVertexAttribArray(1); ``` #### 7. 着色器程序 **顶点着色器** (`vertex.glsl`): ```glsl #version 330 core layout (location = 0) in vec2 aPos; layout (location = 1) in vec2 aTexCoord; out vec2 TexCoord; void main() { gl_Position = vec4(aPos, 0.0, 1.0); TexCoord = aTexCoord; } ``` **片段着色器** (`fragment.glsl`): ```glsl #version 330 core in vec2 TexCoord; out vec4 FragColor; uniform sampler2D texture1; void main() { FragColor = texture(texture1, TexCoord); } ``` #### 8. 渲染循环 ```cpp // 激活纹理单元0 glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, textureID); // 使用着色器程序 glUseProgram(shaderProgram); // 绑定VAO glBindVertexArray(VAO); // 绘制四边形 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); ``` ### 关键注意事项 1. **纹理坐标系统**:OpenGL 纹理坐标原点在左下角 $(0,0)$,右上角为 $(1,1)$ 2. **图像翻转处理**: ```cpp stbi_set_flip_vertically_on_load(true); // 加载前调用 ``` 3. **内存管理**: ```cpp stbi_image_free(data); // 释放图像内存 glDeleteTextures(1, &textureID); // 程序退出时删除纹理 ``` 4. **多平台适配**: - Android:使用 `GL_TEXTURE_EXTERNAL_OES` 处理相机流[^3] - Qt:在 `QOpenGLWidget` 中实现 `initializeGL()` 和 `paintGL()`[^2] ### 优化技巧 1. **纹理压缩**:使用 `glCompressedTexImage2D` 减少显存占用 2. **纹理图集**:合并多张小图提高渲染效率 3. **异步加载**:后台线程加载纹理,避免主线程卡顿 ### 工作流程总结 ```mermaid graph LR A[加载图像数据] --> B[创建纹理对象] B --> C[设置纹理参数] C --> D[上传纹理数据] D --> E[创建几何体] E --> F[设置顶点属性] F --> G[编译着色器] G --> H[渲染循环] ``` ### 相关问题 1. 如何处理非2的幂次方纹理? 2. OpenGL纹理过滤模式如何选择? 3. 如何实现多图层的混合显示? 4. 纹理内存管理的最佳实践? 5. 如何在Qt/Android平台优化OpenGL纹理加载?[^2][^3]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值