对之前画的矩形基础上贴上纹理。在片段着色器中,声明一个采样器,表示纹理位置,每个纹理位置叫做纹理单元,比如 0、1等,当只有一个纹理事时,纹理单元默认为0,当有一个以上的纹理时,则需要通过uniform从外部设置每个纹理单元的值。
需要注意的是,在一个以上的纹理绑定过程中,需要激活纹理单元的位置,然后进行绑定当前纹理。比如需要绑定第2个纹理时,需要先通过 glActiveTexture(GL_TEXTURE1),来激活位置为 1 的纹理单元,然后再通过 glBindTexture()来绑定纹理对象。(第1个纹理单元可以不用激活,因为会默认第一个激活,其纹理单元为 GL_TEXTURE0)。
代码:
#define STB_IMAGE_IMPLEMENTATION
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "std_image.h"
#include <iostream>
#include <vector>
int main()
{
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
GLFWwindow* window = glfwCreateWindow(1120, 1120, "Rectangle", nullptr, nullptr);
glfwMakeContextCurrent(window);
std::cout << glGetString(GL_VERSION) << std::endl;
glewInit();
std::vector<float> vertices = {
-0.8f, -0.8f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // 0 位置2个,颜色3个,纹理坐标2个
0.8f, -0.8f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, // 1
0.8f, 0.8f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, // 2
-0.8f, 0.8f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, // 3
};
unsigned int vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(float), &vertices[0], GL_STATIC_DRAW);
int width, height, nrChannels;
unsigned char* texture = stbi_load("./data/wall.jpg", &width, &height, &nrChannels, 0);
unsigned int tbo;
glGenTextures(1, &tbo);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tbo);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, texture);
glGenerateMipmap(GL_TEXTURE_2D); //经常会忘了这个函数,其功能是产生多级渐进纹理
stbi_image_free(texture);
unsigned char* texture1 = stbi_load("./data/container.jpg", &width, &height, &nrChannels, 0);
unsigned int tbo1;
glGenTextures(1, &tbo1);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, tbo1);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, texture1);
glGenerateMipmap(GL_TEXTURE_2D);
stbi_image_free(texture1);
unsigned int vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 7, 0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 7, (void*)(2 * sizeof(float)));
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 7, (void*)(5 * sizeof(float)));
std::vector<int> indices = {
0, 1, 2,
2, 3, 0
};
unsigned int ibo;
glGenBuffers(1, &ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6 * sizeof(unsigned int), &indices[0], GL_STATIC_DRAW);
const char* vertexShaderSource = "#version 330 core\n"
"layout(location = 0) in vec4 pos;\n"
"layout(location = 1) in vec4 color;\n"
"layout(location = 2) in vec2 text_pos;\n"
"out vec4 our_color;\n"
"out vec2 our_text_pos;\n"
"void main()\n"
"{\n"
" gl_Position = pos;\n"
" our_color = color;\n"
" our_text_pos = text_pos;\n"
"}\0";
unsigned int vs = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vs, 1, &vertexShaderSource, nullptr);
glCompileShader(vs);
const char* fragmentShaderSource = "#version 330 core\n"
"out vec4 color;\n"
"in vec4 our_color;\n"
"in vec2 our_text_pos;\n"
"uniform float r;\n"
"uniform sampler2D ourTexture;\n"
"uniform sampler2D ourTexture1;\n"
"void main()\n"
"{\n"
//" color = texture(ourTexture, our_text_pos) * vec4(r, our_color.y, our_color.z, our_color.w);\n"
" color = mix(texture(ourTexture, our_text_pos), texture(ourTexture1, our_text_pos), 0.5)* vec4(r, our_color.y, our_color.z, our_color.w);\n"
"}\0";
unsigned int fs = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fs, 1, &fragmentShaderSource, nullptr);
glCompileShader(fs);
int result;
glGetShaderiv(fs, GL_COMPILE_STATUS, &result);
if (!result)
{
char message[512];
glGetShaderInfoLog(fs, 512, 0, message);
std::cout << message << std::endl;
}
unsigned int program = glCreateProgram();
glAttachShader(program, vs);
glAttachShader(program, fs);
glLinkProgram(program);
glUseProgram(program);
int location = glGetUniformLocation(program, "r");
glUniform1i(glGetUniformLocation(program, "ourTexture"), 0);
glUniform1i(glGetUniformLocation(program, "ourTexture1"), 1);
glBindVertexArray(0);
float increment = 0.05f, r = 0.1f;
while (!glfwWindowShouldClose(window))
{
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glBindVertexArray(vao);
glUseProgram(program);
glUniform1f(location, r);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
glfwSwapBuffers(window);
glfwPollEvents();
if (r > 1) increment = -0.05f;
else if (r < 0) increment = 0.05f;
r += increment;
}
glDeleteProgram(program);
glfwTerminate();
return 0;
}
实验结果:
可以看到有两层纹理,一个是木箱,一个是砖墙,两个纹理分别如下:
最终渲染效果: