文章目录
纹理
纹理是一种结构化的存储形式,可供着色器读写。
纹理通常用于存储图形数据,并有多种形式和布局。
创建并且初始化纹理
纹理的创建和vbo的创建差不多
先创建纹理对象,然后分配内存,绑定到OpenGL,将数据添加到缓存。
GLuint texture;
//1、创建纹理对象
glCreateTextures(GL_TEXTURE_2D, 1, &texture);
//2、分配纹理缓存空间
glTextureStorage2D(texture, //纹理对象
1, //mipmap层数,这个只是分配的内存!!!
GL_RGB8, //数据格式
width, //纹素的宽
height); //纹素的长
//3、绑定纹理对象到OpenGL上下文,告诉OpenGL纹理的类型
glBindTexture(GL_TEXTURE_2D, texture);
更新纹理数据
//4、更新纹理数据
glTextureSubImage2D(texture, //纹理对象
0, //mipmap层数,这是纹理的!!!别和上面的弄混乱
0, 0, //开始坐标
width, height, //纹理宽和长
GL_RGB, //纹理数据格式
GL_UNSIGNED_BYTE, //数据类型
image_data); //数据
从着色器中读取数据
着色器中的纹理以采样器变量形式存在,通过sampler类型的统一变量与外界进行连接。
glsl中二维纹理的采样器类型为sampler2D
#version 450 core
out vec4 color;
uniform sampler2D s;
in vec2 txcoord;
void main()
{
color = texture(s, txcoord);
}
采样器类型
控制纹理数据的读取方式
通常,纹理坐标都是标准化坐标,即坐标的范围为0.0~1.0。
通过OpenGL可以控制当提供的纹理坐标超出此范围时的情况,这称为采样器的包装模式(wrapping mode)。
同时,我们可以决定如何计算实际采样器之间的值,这称为采样器的过滤模式(filering mode)。
控制采样器包装和过滤模式的参数存储在采样器对象(sampler object)中。
创建采样器对象和绑定到纹理单元
//5.1、创建采样器对象
glCreateSamplers(1, &s);
//绑定到纹理单元,使用多个纹理的时候用,一个纹理不需要用!
//glBindSampler(0, s);
纹理过滤
纹理图中的纹素和屏幕上的像素之间几乎从来不存在一一对应的关系
因此,纹理图像在进行纹理贴图的时候总是被拉伸或收缩。
glsl中有一个函数texture(),可以通过从拉伸或收缩的纹理图中计算颜色片段来对贴图进行调节。这个函数有几种重载:
vec4 texture(sampler1D s, float P);
vec4 texture(sampler2D s, vec2 P);
ivec4 texture(isampler2D s, vec2 P);
uvec4 texture(usampler3D s, vec3 P);
从拉伸或收缩的纹理图中计算颜色片段的过程称为纹理过滤(texture filering)。
拉伸纹理也叫作放大(magnification)
,收缩纹理也叫作缩小(minification)
。
利用采样器的参数,OpenGL支持分别在放大和缩小情况下分别设置构造纹素值的方法。这些条件称为
过滤器(filter)
。
这两个过滤器的名称分别为
GL_TEXTURE_MAG_FILTER
和GL_TEXTURE_MIN_FILTER,分别对应放大
和缩小
过滤器
我们可以从GL_NEAREST和GL_LINEAR这两个基本纹理过滤器中进行选择,分别对应最近邻
和线性
过滤
设置过滤器
//5.2、设置纹理过滤方式,多个纹理的时候用这个
/*glSamplerParameterf(s, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glSamplerParameterf(s, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glSamplerParameterf(s, GL_TEXTURE_WRAP_S, GL_REPEAT);
glSamplerParameterf(s, GL_TEXTURE_WRAP_T, GL_REPEAT);*/
//采用纹理嵌入的采样器对象,只有一个纹理的时候使用这个
glTextureParameterf(texture, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTextureParameterf(texture, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTextureParameterf(texture, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTextureParameterf(texture, GL_TEXTURE_WRAP_T, GL_REPEAT);
加载纹理
这里我使用的加载纹理方式是使用stb_image库进行加载
可以通过此链接下载
https://github.com/nothings/stb/blob/master/stb_image.h
完整代码展示
shader
vertex shader
#version 450 core
layout(location = 0) in vec3 position;
layout(location = 1) in vec2 tex_coord;
out vec2 txcoord;
uniform mat4 mvp;
void main()
{
txcoord = tex_coord;
gl_Position = vec4(position, 1.0);
}
fragment shader
#version 450 core
out vec4 color;
uniform sampler2D s;
in vec2 txcoord;
void main()
{
color = texture(s, txcoord);
}
Shader
和上篇文章的一样
源代码
#define STB_IMAGE_IMPLEMENTATION
#include "sb7.h"
#include "Shader.h"
#include "stb_image.h"
#include "sb7ktx.h"
#include <iostream>
using std::cout;
using std::endl;
class my_applicaiton : public sb7::application
{
public:
void startup()
{
//加载纹理
unsigned char* image_data = stbi_load("wall.jpg", &width, &height, &nrChannel, 0);
if (!image_data)
{
cout << "load image fail" << endl;
}
cout << "channel: " << nrChannel << endl;
cout << "width: " << width << endl;
cout << "height: " << height << endl;
float data[] =
{
//vertex_coord uv_coord
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
0.5f, -0.5f, -0.5f, 1.0f, 1.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f
};
//create shader instance
shader = new Shader("vs.vert", "fs.frag");
//create shader object;
glCreateVertexArrays(1, &vao);
//bind vao to content
glBindVertexArray(vao);
//create vbo object
glCreateBuffers(1, &vbo);
//bind vbo to content
glBindBuffer(GL_ARRAY_BUFFER, vbo);
//分配内存
glNamedBufferStorage(vbo, //缓存目标
sizeof(data), //缓存大小
nullptr, //无数据
GL_DYNAMIC_STORAGE_BIT);//模式
glNamedBufferSubData(vbo, //缓存
0, //偏移量
sizeof(data), //数据大小
data); //数据
//绑定缓存到vao
glVertexArrayVertexBuffer(vao, //绑定的vao
0, //顶点属性
vbo, //绑定的vbo
0, //绑定点
sizeof(float) * 5); //每个顶点之间的距离
//绑定到vao
glVertexArrayAttribBinding(vao, //vao
0, //顶点属性
0); //绑定点
glVertexArrayAttribFormat(vao, //vao
0, //顶点属性
3, //顶点分量
GL_FLOAT, //数据类型
GL_FALSE, //是否标准化
0); //顶点属性的顶点与起始顶点的距离你
glVertexArrayAttribBinding(vao, 1, 0);
glVertexArrayAttribFormat(vao, 1, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 3);
//启用顶点属性
glEnableVertexArrayAttrib(vao, 0);
glEnableVertexArrayAttrib(vao, 1);
//1、创建纹理对象
glCreateTextures(GL_TEXTURE_2D, 1, &texture);
//2、分配纹理缓存空间
glTextureStorage2D(texture, //纹理对象
1, //mipmap层数,这个只是分配的内存!!!
GL_RGB8, //数据格式
width, //纹素的宽
height); //纹素的长
//3、绑定纹理对象到OpenGL上下文,告诉OpenGL纹理的类型
glBindTexture(GL_TEXTURE_2D, texture);
//4、更新纹理数据
glTextureSubImage2D(texture, //纹理对象
0, //mipmap层数,这是纹理的!!!别和上面的弄混乱
0, 0, //开始坐标
width, height, //纹理宽和长
GL_RGB, //纹理数据格式
GL_UNSIGNED_BYTE, //数据类型
image_data); //数据
//5、控制纹理数据的读取方式
//5.1、创建采样器对象
glCreateSamplers(1, &s);
//绑定到纹理单元,使用多个纹理的时候用
glBindSampler(0, s);
//5.2、设置纹理过滤方式
/*glSamplerParameterf(s, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glSamplerParameterf(s, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glSamplerParameterf(s, GL_TEXTURE_WRAP_S, GL_REPEAT);
glSamplerParameterf(s, GL_TEXTURE_WRAP_T, GL_REPEAT);*/
//采用纹理嵌入的采样器对象
glTextureParameterf(texture, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTextureParameterf(texture, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTextureParameterf(texture, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTextureParameterf(texture, GL_TEXTURE_WRAP_T, GL_REPEAT);
}
void render(double currentTime)
{
GLfloat colors[] = { 0.0, 0.5, 0.0, 1.0 };
glClearBufferfv(GL_COLOR, 0, colors);
shader->use();
glDrawArrays(GL_TRIANGLES, 0, 36);
//delete[] data;
}
void shutdown()
{
}
private:
//vao object and vbo object
GLuint vao;
GLuint vbo;
//shader object
Shader* shader;
//texture object
GLuint texture;
//sampler
GLuint s;
int width, height, nrChannel;
private:
};
DECLARE_MAIN(my_applicaiton);
效果
总结
- 创建纹理对象
- 分配纹理缓存空间
- 绑定纹理对象到OpenGL上下文,告诉OpenGL纹理的类型
- 更新纹理数据
- 控制纹理数据的读取方式
5.1 创建采样器对象
5.2 设置纹理过滤方式