使用纹理数组时,为什么我不必将采样器绑定到着色器?
When using texture arrays, why do I not have to bind the sampler to the shader?
我正在我的代码中使用 GL_TEXTURE_2D_ARRAY
创建纹理数组:
// Load all images ito opengl
unsigned int width, height;
std::vector<unsigned char> textures;
int num = 0;
for ( auto each : image_list )
{
// Load PNG
std::vector<unsigned char> buffer, this_texture;
lodepng::load_file(buffer, each.string().c_str());
auto lode_error = lodepng::decode(this_texture, width, height, buffer);
if (lode_error)
{
LOG_ERROR("lodepng has reported this error: " + std::string(lodepng_error_text(lode_error)));
return false;
}
m_indexes.insert(std::make_pair(each.filename().string(), num));
textures.insert(textures.end(), this_texture.begin(), this_texture.end());
num++;
}
// Active texture
glActiveTexture(GL_TEXTURE0);
// Generate texture
glGenTextures(1, &m_texture_id);
glBindTexture(GL_TEXTURE_2D_ARRAY, m_texture_id);
// Send pixels
glTexImage3D(GL_TEXTURE_2D_ARRAY,
0,
GL_RGBA,
width, height,
image_list.size(),
0,
GL_RGBA,
GL_UNSIGNED_BYTE,
textures.data());
// Set options
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
以下是我使用的着色器:
顶点着色器
#version 430 core
/* layouts */
layout (location = 0) in vec3 in_vertex;
layout (location = 1) in vec2 in_uv;
layout (location = 2) in vec4 in_tint;
layout (location = 3) in mat4 in_model;
layout (location = 7) in vec3 in_scale;
layout (location = 8) in float in_textured_index;
/* uniforms */
uniform mat4 ortho;
uniform mat4 view;
/* outputs */
out vec4 tint;
out vec2 uv;
out float textured_index;
void main()
{
mat4 mvp = ortho * view * in_model;
gl_Position = mvp * vec4(in_vertex * in_scale, 1.0);
tint = in_tint;
uv = in_uv;
textured_index = in_textured_index;
}
片段着色器
#version 430 core
/* inputs from vertex shader */
in vec4 tint;
in vec2 uv;
in float textured_index;
/* output to GPU */
out vec4 fragment;
/* texture sampler */
uniform sampler2DArray sampler_unit;
void main()
{
fragment = texture(sampler_unit, vec3(uv.xy, textured_index)).rgba;
fragment = fragment * tint;
}
绑定纹理数组的代码:
void ArrayTextures::attach()
{
if (glIsTexture(m_texture_id)){
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D_ARRAY, m_texture_id);
}
}
我注意到,我不必将纹理单元或纹理 ID 附加到我的着色器,只要纹理与上述函数绑定即可。它只是工作。我想明白为什么。在 OpenGL 3.X 中,您必须先将采样器绑定到着色器,然后才能使用它。幕后是否有任何我不知道的自动化?由于我有 5700XT,这可能是 AMD 特有的怪癖吗?这里的正确方法是什么,所以我可以确定它也适用于 NVIDIA?
这与采样器类型无关。纹理对象和纹理采样器之间的绑定是纹理单元。纹理对象必须绑定到一个纹理单元,纹理单元编号必须设置为纹理采样器统一。
在 GLSL 中,几乎所有的东西都默认初始化为 0 和 0.0。因此默认Binding point为0。如果纹理绑定到纹理单元0(GL_Texture0
),则不需要设置纹理采样器统一,因为它默认为0。
我正在我的代码中使用 GL_TEXTURE_2D_ARRAY
创建纹理数组:
// Load all images ito opengl
unsigned int width, height;
std::vector<unsigned char> textures;
int num = 0;
for ( auto each : image_list )
{
// Load PNG
std::vector<unsigned char> buffer, this_texture;
lodepng::load_file(buffer, each.string().c_str());
auto lode_error = lodepng::decode(this_texture, width, height, buffer);
if (lode_error)
{
LOG_ERROR("lodepng has reported this error: " + std::string(lodepng_error_text(lode_error)));
return false;
}
m_indexes.insert(std::make_pair(each.filename().string(), num));
textures.insert(textures.end(), this_texture.begin(), this_texture.end());
num++;
}
// Active texture
glActiveTexture(GL_TEXTURE0);
// Generate texture
glGenTextures(1, &m_texture_id);
glBindTexture(GL_TEXTURE_2D_ARRAY, m_texture_id);
// Send pixels
glTexImage3D(GL_TEXTURE_2D_ARRAY,
0,
GL_RGBA,
width, height,
image_list.size(),
0,
GL_RGBA,
GL_UNSIGNED_BYTE,
textures.data());
// Set options
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
以下是我使用的着色器:
顶点着色器
#version 430 core
/* layouts */
layout (location = 0) in vec3 in_vertex;
layout (location = 1) in vec2 in_uv;
layout (location = 2) in vec4 in_tint;
layout (location = 3) in mat4 in_model;
layout (location = 7) in vec3 in_scale;
layout (location = 8) in float in_textured_index;
/* uniforms */
uniform mat4 ortho;
uniform mat4 view;
/* outputs */
out vec4 tint;
out vec2 uv;
out float textured_index;
void main()
{
mat4 mvp = ortho * view * in_model;
gl_Position = mvp * vec4(in_vertex * in_scale, 1.0);
tint = in_tint;
uv = in_uv;
textured_index = in_textured_index;
}
片段着色器
#version 430 core
/* inputs from vertex shader */
in vec4 tint;
in vec2 uv;
in float textured_index;
/* output to GPU */
out vec4 fragment;
/* texture sampler */
uniform sampler2DArray sampler_unit;
void main()
{
fragment = texture(sampler_unit, vec3(uv.xy, textured_index)).rgba;
fragment = fragment * tint;
}
绑定纹理数组的代码:
void ArrayTextures::attach()
{
if (glIsTexture(m_texture_id)){
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D_ARRAY, m_texture_id);
}
}
我注意到,我不必将纹理单元或纹理 ID 附加到我的着色器,只要纹理与上述函数绑定即可。它只是工作。我想明白为什么。在 OpenGL 3.X 中,您必须先将采样器绑定到着色器,然后才能使用它。幕后是否有任何我不知道的自动化?由于我有 5700XT,这可能是 AMD 特有的怪癖吗?这里的正确方法是什么,所以我可以确定它也适用于 NVIDIA?
这与采样器类型无关。纹理对象和纹理采样器之间的绑定是纹理单元。纹理对象必须绑定到一个纹理单元,纹理单元编号必须设置为纹理采样器统一。
在 GLSL 中,几乎所有的东西都默认初始化为 0 和 0.0。因此默认Binding point为0。如果纹理绑定到纹理单元0(GL_Texture0
),则不需要设置纹理采样器统一,因为它默认为0。