OpenGL纹理贴图


My Github Link

方案一:利用opencv库将图片读取为unsigned char

1、用到Opencv将png图片读取到内存,然后转换为GLubyte–unsigned char数据
2、将影像贴图到OpenGL纹理上

#include <stdlib.h>
#include "GL/glut.h"
#include <opencv.hpp>
using namespace cv;
//OpenCV读取图像
Mat I = imread("C://Users//XXX//Desktop//3.png");
//设置长宽  
int width = I.cols;
int height = I.rows;
//设置图像指针
GLubyte* pixels;

GLuint load_texture()
{
   
   
	//OpenGL纹理用整型数表示
	GLuint texture_ID;

	//获取图像指针
	int pixellength = width * height * 3;
	pixels = new GLubyte[pixellength];
	memcpy(pixels, I.data, pixellength * sizeof(char));
	//imshow("OpenCV", I);

	//将texture_ID设置为2D纹理信息
	glGenTextures(2, &texture_ID);
	glBindTexture(GL_TEXTURE_2D, 1);
	//纹理放大缩小使用线性插值
	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_REPEAT);
	//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
	//纹理水平竖直方向外扩使用边缘像素贴图(与重复贴图二选一)
	//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
	//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);

	//将图像内存用作纹理信息
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_BGR_EXT, GL_UNSIGNED_BYTE, pixels);

	free(pixels);
	return texture_ID;
}

void display()
{
   
   
	// 清除屏幕
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	//获取纹理对象
	GLuint image = load_texture();
	std::cout << image << std::endl;

	//重新设置OpenGL窗口:原点位置为左上角,x轴从左到右,y轴从上到下,坐标值与像素坐标值相同
	glViewport(0, 0, (GLsizei)width, (GLsizei)height);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity
<think> 我们被要求回答关于OpenGL纹理贴图的使用方法和原理。根据提供的引用内容,我们可以总结出以下关键点: 1. **贴图模式**:OpenGL提供三种贴图模式:GL_MODULATE(默认,考虑光照)、GL_DECAL(仅纹理,忽略光照)和GL_BLEND(混合纹理和颜色)。通过`glTexEnvi`函数设置。 2. **纹理内存**:OpenGL有一块纹理内存(可能在显存中),用于存储纹理纹理需要从应用程序内存传输到纹理内存,并可能进行格式换。 3. **纹理对象**:使用纹理对象(通过`glGenTextures`生成纹理名称)来管理纹理,可以绑定多个纹理并在需要时切换。 4. **纹理坐标映射**:在着色器中定义纹理坐标(如`vTexture`),通过`glVertexAttribPointer`将纹理坐标传递到着色器。 5. **法线贴图**:在像素着色器中从法线贴图纹理中读取法线,并将其换到[-1,1]范围,然后用于光照计算。 下面我们将结合这些信息,系统性地介绍OpenGL纹理贴图的使用方法和原理。 ### 纹理贴图原理 纹理贴图是将一张图像(纹理)映射到三维物体表面的过程。其核心原理是: - **纹理坐标**:每个顶点除了位置、颜色等属性外,还有一个纹理坐标(通常为二维坐标(s,t)或(u,v)),表示该顶点在纹理图像上的位置。纹理坐标范围通常是[0,1]。 - **纹理采样**:在光栅化过程中,根据片元(像素)在三角形内的位置,通过插值得到纹理坐标,然后根据该坐标从纹理图像中获取颜色值(称为纹理采样)。 ### 纹理贴图使用方法 以下是使用OpenGL纹理贴图的基本步骤: 1. **生成纹理对象**:使用`glGenTextures`生成一个或多个纹理名称(ID)。 ```c GLuint texture; glGenTextures(1, &texture); ``` 2. **绑定纹理**:使用`glBindTexture`将生成的纹理绑定到指定的纹理目标(如GL_TEXTURE_2D)。 ```c glBindTexture(GL_TEXTURE_2D, texture); ``` 3. **设置纹理参数**:包括纹理过滤方式(放大和缩小)和纹理环绕方式。 ```c 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. **加载纹理图像数据**:将图像数据从应用程序内存传输到纹理内存。需要指定图像数据的格式和纹理的内部格式。 ```c // 假设image_data是加载好的图像数据,width和height是图像的宽高 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image_data); ``` 5. **生成多级渐远纹理(可选)**:用于提高渲染效率和减少锯齿。 ```c glGenerateMipmap(GL_TEXTURE_2D); ``` 6. **在着色器中使用纹理**: - 顶点着色器:接收顶点的纹理坐标,并传递给片元着色器。 ```glsl layout (location = 2) in vec2 aTexCoord; out vec2 TexCoord; void main() { // ... 其他处理 TexCoord = aTexCoord; } ``` - 片元着色器:使用插值后的纹理坐标采样纹理。 ```glsl in vec2 TexCoord; uniform sampler2D ourTexture; void main() { FragColor = texture(ourTexture, TexCoord); } ``` 7. **设置贴图模式(可选)**:使用`glTexEnvi`设置纹理环境模式(如GL_MODULATE、GL_DECAL或GL_BLEND)。注意:在可编程管线中,这些固定功能可能被着色器替代。 ```c glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); ``` 8. **渲染时激活纹理单元并绑定纹理**:在绘制之前,激活一个纹理单元并将纹理绑定到该单元,然后将纹理单元赋值给着色器中的采样器。 ```c glActiveTexture(GL_TEXTURE0); // 激活纹理单元0 glBindTexture(GL_TEXTURE_2D, texture); // 在着色器程序中使用之前,需要设置ourTexture为0(对应GL_TEXTURE0) ``` ### 纹理内存管理 纹理从系统内存传输到OpenGL纹理内存(可能在显存中)需要时间。因此,应尽量减少纹理的重复加载。使用纹理对象(通过`glGenTextures`创建)可以方便地管理多个纹理,并在需要时通过绑定快速切换。 ### 特殊纹理应用 - **法线贴图**:纹理中存储的是法线向量而不是颜色。在片元着色器中,将纹理采样的法线值从[0,1]换到[-1,1],然后用于光照计算(如引用[5]所示)。 - **混合纹理**:使用GL_BLEND模式可以将纹理与颜色混合,或者通过着色器实现更复杂的混合效果。 ### 注意事项 - 纹理坐标需要正确映射到模型的顶点。 - 纹理尺寸最好是2的幂(如64x64, 128x128等),以兼容旧硬件。 - 使用多级渐远纹理(mipmap)可以提高渲染效率和质量。 通过以上步骤,我们可以实现基本的纹理贴图效果。对于更高级的应用,如多重纹理、立方体贴图等,原理类似,但需要额外的设置。 [^1]: 引用[1] [^2]: 引用[2] [^3]: 引用[3] [^4]: 引用[4] [^5]: 引用[5] §§相关问题§§ 1. OpenGL纹理贴图的三种模式(GL_MODULATE, GL_DECAL, GL_BLEND)有什么区别? 2. 如何在OpenGL中加载和绑定多个纹理? 3. 什么是法线贴图?它在OpenGL中如何实现? 4. 如何优化OpenGL纹理贴图的性能? </think> ### OpenGL纹理贴图的使用方法与原理 #### 一、核心原理 1. **纹理内存管理** OpenGL拥有独立的纹理内存(通常在显存中),纹理数据需从应用内存传输至此区域。传输过程涉及格式换(如RGB到压缩格式),由OpenGL自动处理[^2]。现代显卡支持纹理对象技术(`glGenTextures`),可同时管理多个纹理并通过数字标识快速切换[^3]。 2. **坐标映射机制** 纹理坐标(UV坐标)范围是$[0,1]^2$,通过顶点属性(如`glVertexAttribPointer`)绑定到模型顶点。光栅化时对UV坐标插值,每个片元根据插值结果采样纹理[^4]。映射公式为: $$ \text{颜色} = \text{texture2D}(\text{texSampler}, \text{uv}) $$ 3. **纹理采样流程** ```mermaid graph LR A[应用加载图像数据] --> B(glTexImage2D传输到GPU) B --> C[绑定纹理对象] C --> D[顶点着色器传递UV坐标] D --> E[片元着色器采样纹理] ``` #### 二、使用方法 1. **基础步骤** ```c // 1. 生成纹理对象 GLuint textureID; glGenTextures(1, &textureID); // 2. 绑定纹理 glBindTexture(GL_TEXTURE_2D, textureID); // 3. 设置参数 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // 4. 加载图像数据 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data); // 5. 着色器中使用 // 顶点着色器:传递uv坐标 // 片元着色器:vec4 color = texture(texSampler, uv); ``` 2. **贴图模式设置** 通过`glTexEnvi`选择模式: - `GL_MODULATE`:默认模式,纹理颜色与光照混合 $C_{\text{final}} = C_{\text{light}} \otimes C_{\text{texture}}$[^1] - `GL_DECAL`:忽略光照,直接使用纹理颜色 - `GL_BLEND`:纹理与指定颜色混合 $C_{\text{final}} = \alpha C_{\text{texture}} + (1-\alpha)C_{\color{red}}$[^1] 3. **高级应用示例(法线贴图)** ```glsl // 片元着色器 uniform sampler2D normalMap; void main() { vec3 normal = texture(normalMap, uv).rgb; normal = normalize(normal * 2.0 - 1.0); // 换到[-1,1] float diffuse = max(dot(normal, lightDir), 0.0); // ... } ``` 法线贴图将表面细节编码在RGB通道中,每个像素存储扰动后的法线向量[^5]。 #### 三、性能优化 1. **纹理对象复用** 使用`glGenTextures`创建纹理对象池,避免重复加载[^3]。 2. **压缩纹理** 采用GPU支持的压缩格式(如ASTC),减少内存占用和带宽消耗[^2]。 3. **Mipmap链** 生成多级渐远纹理: ```c glGenerateMipmap(GL_TEXTURE_2D); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); ``` #### 四、常见问题 1. **纹理扭曲**:UV坐标未正确映射到模型顶点 2. **边缘撕裂**:未设置环绕模式(`GL_CLAMP_TO_EDGE`) 3. **模糊/锯齿**:未启用Mipmap或过滤参数错误 [^1]: OpenGL提供了3种不同的贴图模式 [^2]: 纹理像素从应用程序内存传到纹理内存需要进行格式换 [^3]: OpenGL从1.2开始提供了纹理对象技术 [^4]: 纹理坐标的映射 [^5]: OpenGL法线贴图
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值