我个人不喜欢"纹理"这个翻译, 所以之后使用 Texture 来替代.
一个几何图案的 Texture 即为与它相绑定的图片, 从上一篇博客可以知道, Fragment Shader 负责计算一个图形的颜色, 而一个图片实际上就是一个颜色复杂的方形, 所以 OpenGL 中 Texture 是由 Fragment Shader 来完成的. 具体的流程是:
如果读过上一篇博客应该能够对 OpenGL 的使用进行自己的简单封装, 所以从本篇博客开始, 只贴部分代码.
.vs 后缀表示这是一个 Vertex Shader
.fs 后缀表示这是一个 Fragment Shader
#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec2 texCoord;
out vec2 _texCoord;
void main() {
_texCoord = texCoord;
gl_Position = vec4(position, 1.0);
}
其中 texCoord 表示该顶点对应的 Texture 坐标.
Texture 坐标定义为: 左下角为 ( 0, 0 ), 右上角为 ( 1, 1 )
#version 330 core
out vec4 outColor;
in vec2 _texCoord;
uniform sampler2D tex;
void main() {
outColor = texture(tex, _texCoord);
}
其中 tex 变量表示的是该 Texture 的图片数据, texture(tex, _texCoord) 表示取该图片的该坐标的像素值.
float vertices[20] = {
-0.5f, -0.5f, 0.f, 0.f, 0.f,
-0.5f, 0.5f, 0.f, 0.f, 1.f,
0.5f, -0.5f, 0.f, 1.f, 0.f,
0.5f, 0.5f, 0.f, 1.f, 1.f
};
Shader *shader = new Shader("texture.vs", "texture.fs");
int width, height, nChannels;
unsigned char* data = stbi_load("aragaki_yui.jpg", &width, &height, &nChannels, 0);
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
// 加载 Vertex Array...
shader->use();
glBindTexture(GL_TEXTURE_2D, texture);
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 5, (void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 5, (void*)(sizeof(float) * 3)); // 最后一个参数是偏移量, 即跳过前面3个float
glEnableVertexAttribArray(1);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
为什么如果不调用 glGenerateMipmap() 则不会绘制图像? 这一点我还没搞懂
当图片的面积小于其多边形的面积时, 多余部分该如何填充?
API 为:
glTexParameteri(GL_TEXTURE_2D, [WRAP_DIMENSION], [WRAP_MODE]);
其中 WRAP_DIMENSION 取值为
其中 WRAP_MODE 取值为下面这 4 个宏:
float borderColor[] = {0.8f, 0.2f, 0.5f, 1.f};
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
Fragment Shader 可以混合多种 Texture 和颜色:
#version 330 core
out vec4 outColor;
in vec2 _texCoord;
uniform sampler2D tex1;
uniform sampler2D tex2;
void main() {
outColor = mix(texture(tex1, _texCoord), texture(tex2, _texCoord), 0.2) * vec4(1.0, 0.8, 0.95, 1.0);
}
其中 mix 函数表示将两个 Texture 的像素混合, 它的第三个参数表示前者取 0.8, 后者取 0.2.
OpenGL 里颜色混合一般用乘法
// 绑定两次 GL_TEXTURE_2D
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, bg);
int tex1Loc = shader->getUniformLocation("tex1");
int tex2Loc = shader->getUniformLocation("tex2");
glUniform1i(tex1Loc, 0);
glUniform1i(tex2Loc, 1);
// glBindVertexArray(VAO)...
Texture Filter 适用于当一个图片的分辨率太低时, 应如何填充"空隙", API为
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, [FILTER_MODE]);
其中 FILTER_MODE有两个取值:
Texture 绘制是计算机图形学中十分常用的功能, OpenGL巧妙地将图片数据和 Shader 相联系, 尤其是用 Fragment Shader 来计算图片的像素, 让我对图片的绘制有了新的理解!