01、纹理贴图
- 纹理贴图是在栅格化的模型表面上覆盖图像的技术。通过纹理贴图操作可以让渲染场景更具有真实感。将一张图像就像贴纸一样贴到(映射)一个几何图形的表面上去,也叫纹理映射。
- 纹理单元:计算机专门为实现纹理贴图提供了纹理单元的硬件支持,通过io加载的本地(网络)图像都是保存在纹理单元中,计算机显卡通常带有数个纹理单元,可同时加载显示多个纹理图像。
- 实现纹理贴图的步骤:
- 1、准备好映射到几何图形上的纹理图像
- 2、为几何图形配置映射方式,根据图形顶点,设置对应的纹理坐标
- 3、加载纹理图像,对其进行一些配置
- 4、在片元着色器中将相应的图像元素从纹理对象中抽取出来,并将元素的颜色赋值给片元着色器
02、加载纹理图像
- 为了使纹理图像用于OpenGL管线中的着色器,需要从图像中提取颜色并将他们放入纹理对象中。
- 本项目采用SOIL2库进行图像文件的加载实现,其他库的使用方式可查看网络资料
unsigned int SOIL_load_OGL_texture(const char *filename,int force_channels,unsigned int reuse_texture_ID,unsigned int flags)
- 加载纹理图像,项目中使用的纹理图像和代码如下,加载纹理对象,并返回纹理对象id
GLuint textureId = SOIL_load_OGL_texture(
"brick1.jpg",
SOIL_LOAD_AUTO,
SOIL_CREATE_NEW_ID,
SOIL_FLAG_INVERT_Y)

03、纹理坐标
- 纹理坐标多指的是2D纹理坐标,假设纹理图像为矩形,则左下角的位置坐标为原点(0,0),右上角的位置坐标为(1,1)

- 要将纹理图像应用到图形的渲染表面,需要通过为图形中的每个顶点指定纹理坐标来完成,纹理坐标是对纹理图像中像素的引用,用于将3D模型上的点映射到纹理中的位置。
- 一个顶点的数据除了具有标记其在3D空间的坐标(x,y,z)之外,每个点还具有纹理坐标(s,t),用来指定纹理图像中的那个像素为他提供颜色(纹理图像的像素也叫纹元)。
- 插值操作:为了确保渲染模型中的每个像素都使用纹理图像中的适当纹元进行绘制,顶点属性中包含顶点坐标数据和纹理坐标数据,他们以同样的方式,纹理图像和顶点一起被插值和填充。
- 纹理坐标数据也是通过vbo进行传值,切纹理坐标点的数量和顶点坐标数量相同。
float vPositions[72] = {
1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0,-1.0, 1.0, 1.0,-1.0, 1.0,
1.0, 1.0, 1.0, 1.0,-1.0, 1.0, 1.0,-1.0,-1.0, 1.0, 1.0,-1.0,
1.0, 1.0, 1.0, 1.0, 1.0,-1.0, -1.0, 1.0,-1.0, -1.0, 1.0, 1.0,
-1.0, 1.0, 1.0, -1.0, 1.0,-1.0, -1.0,-1.0,-1.0, -1.0,-1.0, 1.0,
-1.0,-1.0,-1.0, 1.0,-1.0,-1.0, 1.0,-1.0, 1.0, -1.0,-1.0, 1.0,
1.0,-1.0,-1.0, -1.0,-1.0,-1.0, -1.0, 1.0,-1.0, 1.0, 1.0,-1.0
};
float textureCoords[48] = {
1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0,
0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0,
1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0,
0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0
};
glBindBuffer(GL_ARRAY_BUFFER, vbo[2]);
glBufferData(GL_ARRAY_BUFFER,sizeof(textureCoords),textureCoords,GL_STATIC_DRAW);
04、在着色器中使用纹理
- 计算机为了提高图像渲染的性能,特地在硬件中处理纹理相关的操作,我们可以在片元着色器中进行纹理图像的加载。
- 纹理图像先是加载到纹理单元中,然后在片元着色器程序中,要将纹理单元的图像数据加载到着色器程序中,需要使用到着色器程序提供的纹理采样器sampler2D
- 经过光栅化处理后的纹理坐标和对应纹理对象进行采样,可得到最重要渲染的片元颜色,通过调用texture方法实现
"in vec2 v_TexCoord; \n"
"uniform sampler2D u_Sampler; \n"
" color = texture(u_Sampler, v_TexCoord); \n"
- 纹理单元和采样器可以对任何纹理对象进行采样,也可以在运行时更改,在每一帧画面绘制时,通过激活纹理单元并绑定到特定的纹理对象
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textureId);
const char *vertex_shader =
"#version 410 \n"
"layout(location=0) in vec3 a_Position; \n"
"layout(location=1) in vec3 a_Color; \n"
"layout(location=2) in vec2 a_TexCoord; \n"
"uniform mat4 u_ModelMatirx; \n"
"uniform mat4 u_ViewMatirx; \n"
"uniform mat4 u_ProjMatirx; \n"
"out vec4 v_colors; \n"
"out vec2 v_TexCoord; \n"
" void main() {"
" gl_Position = u_ProjMatirx * u_ViewMatirx * u_ModelMatirx * vec4(a_Position, 1.0); \n"
" v_colors = vec4(a_Color.x, a_Color.y, a_Color.z, 1.0); \n"
" v_TexCoord = a_TexCoord; \n"
"} \n";
const char *fragment_shader =
"#version 410 \n"
"in vec4 v_colors; \n"
"in vec2 v_TexCoord; \n"
"uniform sampler2D u_Sampler; \n"
"out vec4 color; \n"
"void main(void){ \n"
" color = texture(u_Sampler, v_TexCoord); \n"
"} \n";

05、项目源码