上一章,我们没有给 uniform sampler2D texData 在main.cpp中赋值。这里就来解释为啥。
实际上 texData 存储的是一个地址,texture对象的地址,我们一般管这个地址叫做 texture unit。而一些会给sampler类型的变量附一个默认值:0号地址。而每个texture对象的默认 texture unit都是0 。所以我们刚刚没有对texData进行赋值。
然而并不是所有显卡都会这么做,所以上一章的东西,可能出不来结果…………。
我们实际上可以同时绑定很多个texture对象,前提是,只要他们的texture unit不同。也由此,我们可以将多个texture对象传入shader。所以在绑定之前我们可以人为的激活不同的texture unit:
glActiveTexture(GL_TEXTURE0); // activate the texture unit first before binding texture
glBindTexture(GL_TEXTURE_2D, texture);
OpenGL保证了,至少有16个texture unit,并且他们的值是连续的(如:GL_TEXTURE8 == GL_TEXTURE3 + 5)
用下面的方法(与一般的 整型uniform 是一样的)为shader里的 sampler2D texData 进行赋值:
glUniform1i(glGetUniformLocation(myShaderProg.ID, "texData"), 0);
然后就可以用了。
大概步骤如下:
- 建立两个texture对象,并赋予不同的贴图
- 激活不同的texture unit,并为其绑定对应的texture对象。
- 写shader
- 激活shaderpProgram,并为uniform sampler类型的变量赋值。
- 绘制
有下面几点要注意:
- 在读取图片的时候,读出来是反的,可以在读取之前对其进行设置:stbi_set_flip_vertically_on_load(true);
- shader内置了一个函数:mix(vec4 col1,vec4 col2,float k)这个函数返回:col1*(1-k)+col2*k。用这个函数可以快捷的测试两个texture在一个物体上的效果。
- alpha通道有问题,我也不会解决,所以有alpha通道的图片,看着差不多就行了(能看出样子,有的地方可能是色块,但绝对不是乱码……)
我的代码如下:
main.cpp:
// 1.头文件:
#include <iostream>
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>
#include "Shader.h"
// 5.OpenGL与窗口(main之前):
void CBK_framebuffer_size(GLFWwindow* window, int w, int h)
{
glViewport(0, 0, w, h);
}
void processInput(GLFWwindow* window)
{
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
}
int main()
{
// 2.在创建窗口之前……:
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// 3.创建窗口:
GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL);
if (window == NULL)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
// 4.在OpenGL之前……:
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
// 5.OpenGL与窗口:
glViewport(0, 0, 800, 600);
glfwSetFramebufferSizeCallback(window, CBK_framebuffer_size);
// OpenGL的配置:
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);//设置背景色
// 绘图需要用的数据:
float vertices[] = {
// positions // colors // texture coords
0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top right
0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // bottom right
-0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom left
-0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f // top left
};
GLuint indeces[] = {
1,2,3,
3,0,1
};
int imageW, imageH, imageCH,imageW2,imageH2,imageCH2;
stbi_set_flip_vertically_on_load(true);
unsigned char *imageData = stbi_load("..\\my_OtherFiles\\container.jpg", &imageW, &imageH, &imageCH, 0);
unsigned char *imageData2 = stbi_load("..\\my_OtherFiles\\a.png", &imageW2, &imageH2, &imageCH2, 0);
// Texture 贴图
GLuint tex[2];
glGenTextures(2, tex);
glBindTexture(GL_TEXTURE_2D, tex[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, imageW, imageH, 0, GL_RGB, GL_UNSIGNED_BYTE, imageData);
glGenerateMipmap(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, tex[1]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, imageW2, imageH2, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData2);
glGenerateMipmap(GL_TEXTURE_2D);
stbi_image_free(imageData);
stbi_image_free(imageData2);
// 顶点相关的配置
GLuint VBO;
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
GLuint EBO;
glGenBuffers(1, &EBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indeces), indeces, GL_STATIC_DRAW);
GLuint VAO;
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
glEnableVertexAttribArray(2);
glBindVertexArray(0);
// ShaderProgram
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex[0]);//VAO不能存储texture对象,我试了
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, tex[1]);
Shader myShaderProg("vtx.vs", "frag.fs");
glUseProgram(myShaderProg.ID);
glUniform1i(glGetUniformLocation(myShaderProg.ID, "texData"), 0);
glUniform1i(glGetUniformLocation(myShaderProg.ID, "texData2"), 1);
glUseProgram(0);
// 6.Render Loop:
while (!glfwWindowShouldClose(window))
{
processInput(window);
glClear(GL_COLOR_BUFFER_BIT);//绘制背景色
// 这下面就可以写绘图的代码了
glUseProgram(myShaderProg.ID);
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES,6,GL_UNSIGNED_INT,0);
// 这上面是绘图的代码
glfwSwapBuffers(window);
glfwPollEvents();
}
// 7.程序结束之前:
glfwTerminate();
return 0;
}
vertex shader(没改):
#version 330 core
layout (location = 0) in vec3 inPos;
layout (location = 1) in vec3 inCol;
layout (location = 2) in vec2 inTexCoor;
out vec3 col;
out vec2 texCoor;
void main()
{
gl_Position = vec4(inPos,1);
col = inCol;
texCoor = inTexCoor;
}
fragment shader:
#version 330 core
in vec2 texCoor;
in vec3 col;
out vec4 fragCol;
uniform sampler2D texData;
uniform sampler2D texData2;
void main()
{
fragCol = mix(texture(texData,texCoor),texture(texData2,texCoor),0.5) * vec4(col,1);
}
运行结果: