learnopengl——纹理
原文网址:https://learnopengl.com/Getting-started/Textures
纹理单元
你可能很想知道为什么sampler2D变量是一个全局变量,如果我们不适用glUniform对其赋值。使用glUniform1i,这样我们可以一次指定一个纹理对象,也可以一次指定多个纹理对象。这个纹理的位置就是通常所说的纹理单元。默认的纹理单元是0,这个是默认的激活的纹理单元,所以之前的章节我们没有对其指定位置。注意到不是所有的图形设备需要一个默认的纹理单元,所以之前的章节也许渲染不出对象。
纹理单元的主要目的是,它允许我们的shader使用多张纹理。通过指定纹理单元给采样器,我们可以一次绑定多个纹理,只要我们激活对应的纹理单元即可。像glBindTexture,我们可以使用glActiveTexture激活一个纹理单元,如下:
glActiveTexture(GL_TEXTURE0); // activate the texture unit first before binding texture
glBindTexture(GL_TEXTURE_2D, texture);
在激活纹理单元之后,紧接着使用glBindTexture,会绑定纹理到当前激活的纹理单元。纹理单元GL_TEXTURE0通常默认是激活的,所以之前的章节,我们不需要激活纹理单元,而直接调用了glBindTexture。
OpenGL应该至少有16个纹理单元供你使用。我们可以使用GL_TEXTURE0到GL_TEXTURE15激活对应的纹理单元。它们是按照顺序定义的,为了得到GL_TEXTURE8,可以使用GL_TEXTURE0+8形式。这个在循环迭代的时候获取指定的纹理单元很有用。
我们还需要编辑片段着色器来接收另外一个采样器,如下:
#version 330 core
...
uniform sampler2D texture1;
uniform sampler2D texture2;
void main()
{
FragColor = mix(texture(texture1, TexCoord), texture(texture2, TexCoord), 0.2);
}
最后的输出颜色,是结合了两张纹理。GLSL的内置函数mix,接收两个参数,然后在两者之间根据第三个参数进行线性插值。如果第三个参数是0,它返回第一个参数。如果第三个参数是1,则返回第二个参数。如果第三个参数是0.2,则返回80%的第一个参数,20%的第二个参数,这样就混合了两张贴图。
现在我们需要加载并创建另外一个纹理。你应该很熟悉这个过程了。确保创建另外一个纹理对象,加载和创建最终的纹理使用glTexImage2D。
unsigned char *data = stbi_load("awesomeface.png", &width, &height, &nrChannels, 0);
if (data)
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
}
注意到,我们加载了一张png后缀的图,它包含了透明通道。所以我们需要指定图片数据包含透明通道,使用GL_RGBA即可。否则OpenGL会不正确解析图片数据。
为了使用第二个纹理,我们需要修改对应的程序,绑定两个纹理。
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture1);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, texture2);
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
我们还需要告诉OpenGL,哪个纹理单元属于哪个shader采样器,通过glUniform1i设定每个采样器。我们仅仅需要设定一次即可,所以我们可以在进入循环之前调用一次。
ourShader.use(); // don't forget to activate the shader before setting uniforms!
glUniform1i(glGetUniformLocation(ourShader.ID, "texture1"), 0); // set it manually
ourShader.setInt("texture2", 1); // or with shader class
while(...)
{
[...]
}