OpenGL 立方体贴图纹理不起作用
OpenGL cube map texture doesn't work
我在让立方体贴图在 OpenGL 中工作时遇到问题。我按照一些教程创建了自己的 class 包装 OpenGL 立方体贴图纹理。
首先,我尝试为立方体贴图的侧面加载六张图像并将它们渲染到盆模型上。我想最终创建一个像镜子一样的效果,但现在我只使用法线作为立方体贴图纹理坐标。问题是片段着色器中的采样器似乎只返回零,所以整个模型都是黑色的。
到目前为止我的发现:
- 纹理数据应该上传到 GPU - 我通过上传 (
glTexImage2D
) 和检索数据 (glGetTexImage2D
) 来检查这一点。
- 我检查了 glGetError() 并且 returns 没有错误,即使我设置了
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);
或
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
对于立方体贴图纹理,当我尝试渲染镜子(锅)时,在渲染循环中出现无效操作错误 - 奇怪。
- 锅的法线应该没问题,我已经通过渲染检查了它们(见下图)。
- 我加载的 ppm 图像是 512 x 512,适用于 2D 纹理,所以应该没有问题。
下面是我如何初始化立方体贴图:
texture_cube = new TextureCubeMap(512,TEXEL_TYPE_COLOR);
cout << "cubemap loading: " << texture_cube->load_ppms("rock.ppm","rock.ppm","rock.ppm","rock.ppm","rock.ppm","rock.ppm") << endl;
texture_cube->update_gpu();
...
glUniform1i(sampler_location,0); // 'tex' unit
glUniform1i(sampler_cube_location,0); // 'tex_cube' unit
这是我的渲染循环:
void render()
{
glClear(GL_COLOR_BUFFER_BIT);
glClear(GL_DEPTH_BUFFER_BIT);
glUniformMatrix4fv(view_matrix_location,1,GL_TRUE,glm::value_ptr(CameraHandler::camera_transformation.get_matrix()));
texture_cup->bind(0);
glUniformMatrix4fv(model_matrix_location,1,GL_TRUE,glm::value_ptr(transformation_cup.get_matrix()));
geometry_cup->draw_as_triangles();
texture_rock->bind(0);
glUniformMatrix4fv(model_matrix_location,1,GL_TRUE,glm::value_ptr(transformation_rock.get_matrix()));
geometry_rock->draw_as_triangles();
texture_cow->bind(0);
glUniformMatrix4fv(model_matrix_location,1,GL_TRUE,glm::value_ptr(transformation_cow.get_matrix()));
geometry_cow->draw_as_triangles();
texture_room->bind(0);
glUniformMatrix4fv(model_matrix_location,1,GL_TRUE,glm::value_ptr(glm::mat4(1.0)));
geometry_room->draw_as_triangles();
glUniformMatrix4fv(model_matrix_location,1,GL_TRUE, glm::value_ptr(transformation_mirror.get_matrix()));
// draw the mirror:
texture_cube->bind(0);
glUniform1ui(mirror_location,1);
geometry_mirror->draw_as_triangles();
glUniform1ui(mirror_location,0);
ErrorWriter::checkGlErrors("rendering loop");
glutSwapBuffers();
}
这是我的片段着色器:
#version 330
in vec3 transformed_normal;
in vec2 uv_coords;
uniform vec3 light_direction;
uniform sampler2D tex;
uniform samplerCube tex_cube;
uniform bool mirror;
out vec4 FragColor;
float diffuse_intensity;
float lighting_intensity;
void main()
{
diffuse_intensity = clamp(dot(normalize(transformed_normal),-1 * light_direction),0.0,1.0);
lighting_intensity = clamp(0.4 + diffuse_intensity,0.0,1.0);
if (mirror)
{
FragColor = texture(tex_cube, transformed_normal);
}
else
{
FragColor = 0.3 * vec4(lighting_intensity, lighting_intensity, lighting_intensity, 1.0);
FragColor += texture(tex, uv_coords);
}
}
这是我的整个立方体贴图 class(Image2D 是我自己的 class,应该可以正常工作,我已经用 2D 纹理对其进行了测试):
class TextureCubeMap: public Texture
{
protected:
unsigned int size;
public:
Image2D *image_front;
Image2D *image_back;
Image2D *image_left;
Image2D *image_right;
Image2D *image_top;
Image2D *image_bottom;
/**
* Initialises a new cube map object.
*
* @size width and height resolution in pixels (cube map must
* have square size)
*/
TextureCubeMap(unsigned int size, unsigned int texel_type = TEXEL_TYPE_COLOR)
{
this->size = size;
glGenTextures(1,&(this->to));
glBindTexture(GL_TEXTURE_CUBE_MAP,this->to);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
glBindTexture(GL_TEXTURE_CUBE_MAP,0);
this->image_front = new Image2D(size,size,texel_type);
this->image_back = new Image2D(size,size,texel_type);
this->image_left = new Image2D(size,size,texel_type);
this->image_right = new Image2D(size,size,texel_type);
this->image_top = new Image2D(size,size,texel_type);
this->image_bottom = new Image2D(size,size,texel_type);
}
virtual ~TextureCubeMap()
{
delete this->image_front;
delete this->image_back;
delete this->image_left;
delete this->image_right;
delete this->image_top;
delete this->image_bottom;
}
virtual void update_gpu()
{
int i;
Image2D *images[] =
{this->image_front,
this->image_back,
this->image_left,
this->image_right,
this->image_bottom,
this->image_top};
GLuint targets[] =
{GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
GL_TEXTURE_CUBE_MAP_POSITIVE_X,
GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
GL_TEXTURE_CUBE_MAP_POSITIVE_Y};
glBindTexture(GL_TEXTURE_CUBE_MAP,this->to);
for (i = 0; i < 6; i++)
{
glTexImage2D(targets[i],0,GL_RGBA,this->size,this->size,0,GL_RGBA,GL_FLOAT,images[i]->get_data_pointer());
// glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
}
glBindTexture(GL_TEXTURE_CUBE_MAP,0);
}
virtual void load_from_gpu()
{
int i;
glBindTexture(GL_TEXTURE_CUBE_MAP,this->to);
Image2D *images[] =
{this->image_front,
this->image_back,
this->image_left,
this->image_right,
this->image_bottom,
this->image_top};
GLuint targets[] =
{GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
GL_TEXTURE_CUBE_MAP_POSITIVE_X,
GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
GL_TEXTURE_CUBE_MAP_POSITIVE_Y};
for (i = 0; i < 6; i++)
{
images[i]->set_size(this->size,this->size);
glGetTexImage(targets[i],0,GL_RGBA,GL_FLOAT,images[i]->get_data_pointer());
}
}
bool load_ppms(string front, string back, string left, string right, string bottom, string top)
{
bool result = true;
result = result && this->image_front->load_ppm(front);
result = result && this->image_back->load_ppm(back);
result = result && this->image_left->load_ppm(left);
result = result && this->image_right->load_ppm(right);
result = result && this->image_bottom->load_ppm(bottom);
result = result && this->image_top->load_ppm(top);
auto lambda_size_ok = [](Image2D *image, int size)
{
return (image->get_width() == size) && (image->get_height() == size);
};
if (!lambda_size_ok(this->image_front,this->size) ||
!lambda_size_ok(this->image_back,this->size) ||
!lambda_size_ok(this->image_left,this->size) ||
!lambda_size_ok(this->image_right,this->size) ||
!lambda_size_ok(this->image_top,this->size) ||
!lambda_size_ok(this->image_bottom,this->size))
ErrorWriter::write_error("Loaded cubemap images don't have the same size.");
return result;
}
virtual void print()
{
cout << "front:" << endl;
this->image_front->print();
cout << "back:" << endl;
this->image_back->print();
cout << "left:" << endl;
this->image_left->print();
cout << "right:" << endl;
this->image_right->print();
cout << "bottom:" << endl;
this->image_bottom->print();
cout << "top:" << endl;
this->image_top->print();
}
virtual void bind(unsigned int unit)
{
switch (unit)
{
case 0: glActiveTexture(GL_TEXTURE0); break;
case 1: glActiveTexture(GL_TEXTURE1); break;
case 2: glActiveTexture(GL_TEXTURE2); break;
case 3: glActiveTexture(GL_TEXTURE3); break;
case 4: glActiveTexture(GL_TEXTURE4); break;
case 5: glActiveTexture(GL_TEXTURE5); break;
case 6: glActiveTexture(GL_TEXTURE6); break;
case 7: glActiveTexture(GL_TEXTURE7); break;
case 8: glActiveTexture(GL_TEXTURE8); break;
case 9: glActiveTexture(GL_TEXTURE9); break;
default:
break;
}
glBindTexture(GL_TEXTURE_CUBE_MAP,this->to);
}
};
以及错误的图像(第一个是我得到的,第二个是法线渲染的):
您在评论中自己找到了解决方案,但要求提供更多背景信息以了解其行为方式的原因。
是的,如果你想在同一个片段着色器中使用两个不同的纹理,你必须将两个纹理绑定到不同的纹理单元,并将采样器统一变量的值设置为匹配的纹理单元索引。
对于两个纹理使用相同目标的情况,很明显这一定是真的。否则您的纹理绑定代码将如下所示:
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex1);
glBindTexture(GL_TEXTURE_2D, tex2);
和第二个 glBindTexture()
调用当然会覆盖第一个。因此,您将使用不同的纹理单元:
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex1);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, tex2);
在您使用两个不同纹理目标的情况下,事情就不那么明显了。在这个调用序列之后:
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex1);
glBindTexture(GL_TEXTURE_CUBE_MAP, tex2);
您确实有两个 纹理绑定到纹理单元 0。在 OpenGL 状态下,每个纹理单元包含每个目标的绑定。
现在,如果您想在同一个着色器中使用 2D 和立方体贴图纹理,那么您可以如上所示绑定两个纹理,并将两个采样器统一设置为值 0 似乎是一个完全合理的期望.但其实这个是不支持的,因为...就是这么定义的
这是 OpenGL 3.3 规范第 74 页的“2.11.5 采样器”部分:
It is not allowed to have variables of different sampler types pointing to the same texture image unit within a program object. This situation can only be detected at the next rendering command issued, and an INVALID_OPERATION error will then be generated.
虽然这基于 GPU 通常如何从着色器代码访问采样器是有意义的,但不幸的是,您可以通过着色器代码无法使用的方式为纹理绑定设置状态。部分原因可能是基于 OpenGL 的悠久历史。
要完成这项工作,您将必须使用两个不同的纹理单元,就像您在两个纹理使用相同目标的情况下所做的那样:
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex1);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_CUBE_MAP, tex2);
我在让立方体贴图在 OpenGL 中工作时遇到问题。我按照一些教程创建了自己的 class 包装 OpenGL 立方体贴图纹理。 首先,我尝试为立方体贴图的侧面加载六张图像并将它们渲染到盆模型上。我想最终创建一个像镜子一样的效果,但现在我只使用法线作为立方体贴图纹理坐标。问题是片段着色器中的采样器似乎只返回零,所以整个模型都是黑色的。
到目前为止我的发现:
- 纹理数据应该上传到 GPU - 我通过上传 (
glTexImage2D
) 和检索数据 (glGetTexImage2D
) 来检查这一点。 - 我检查了 glGetError() 并且 returns 没有错误,即使我设置了
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);
或glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
对于立方体贴图纹理,当我尝试渲染镜子(锅)时,在渲染循环中出现无效操作错误 - 奇怪。 - 锅的法线应该没问题,我已经通过渲染检查了它们(见下图)。
- 我加载的 ppm 图像是 512 x 512,适用于 2D 纹理,所以应该没有问题。
下面是我如何初始化立方体贴图:
texture_cube = new TextureCubeMap(512,TEXEL_TYPE_COLOR);
cout << "cubemap loading: " << texture_cube->load_ppms("rock.ppm","rock.ppm","rock.ppm","rock.ppm","rock.ppm","rock.ppm") << endl;
texture_cube->update_gpu();
...
glUniform1i(sampler_location,0); // 'tex' unit
glUniform1i(sampler_cube_location,0); // 'tex_cube' unit
这是我的渲染循环:
void render()
{
glClear(GL_COLOR_BUFFER_BIT);
glClear(GL_DEPTH_BUFFER_BIT);
glUniformMatrix4fv(view_matrix_location,1,GL_TRUE,glm::value_ptr(CameraHandler::camera_transformation.get_matrix()));
texture_cup->bind(0);
glUniformMatrix4fv(model_matrix_location,1,GL_TRUE,glm::value_ptr(transformation_cup.get_matrix()));
geometry_cup->draw_as_triangles();
texture_rock->bind(0);
glUniformMatrix4fv(model_matrix_location,1,GL_TRUE,glm::value_ptr(transformation_rock.get_matrix()));
geometry_rock->draw_as_triangles();
texture_cow->bind(0);
glUniformMatrix4fv(model_matrix_location,1,GL_TRUE,glm::value_ptr(transformation_cow.get_matrix()));
geometry_cow->draw_as_triangles();
texture_room->bind(0);
glUniformMatrix4fv(model_matrix_location,1,GL_TRUE,glm::value_ptr(glm::mat4(1.0)));
geometry_room->draw_as_triangles();
glUniformMatrix4fv(model_matrix_location,1,GL_TRUE, glm::value_ptr(transformation_mirror.get_matrix()));
// draw the mirror:
texture_cube->bind(0);
glUniform1ui(mirror_location,1);
geometry_mirror->draw_as_triangles();
glUniform1ui(mirror_location,0);
ErrorWriter::checkGlErrors("rendering loop");
glutSwapBuffers();
}
这是我的片段着色器:
#version 330
in vec3 transformed_normal;
in vec2 uv_coords;
uniform vec3 light_direction;
uniform sampler2D tex;
uniform samplerCube tex_cube;
uniform bool mirror;
out vec4 FragColor;
float diffuse_intensity;
float lighting_intensity;
void main()
{
diffuse_intensity = clamp(dot(normalize(transformed_normal),-1 * light_direction),0.0,1.0);
lighting_intensity = clamp(0.4 + diffuse_intensity,0.0,1.0);
if (mirror)
{
FragColor = texture(tex_cube, transformed_normal);
}
else
{
FragColor = 0.3 * vec4(lighting_intensity, lighting_intensity, lighting_intensity, 1.0);
FragColor += texture(tex, uv_coords);
}
}
这是我的整个立方体贴图 class(Image2D 是我自己的 class,应该可以正常工作,我已经用 2D 纹理对其进行了测试):
class TextureCubeMap: public Texture
{
protected:
unsigned int size;
public:
Image2D *image_front;
Image2D *image_back;
Image2D *image_left;
Image2D *image_right;
Image2D *image_top;
Image2D *image_bottom;
/**
* Initialises a new cube map object.
*
* @size width and height resolution in pixels (cube map must
* have square size)
*/
TextureCubeMap(unsigned int size, unsigned int texel_type = TEXEL_TYPE_COLOR)
{
this->size = size;
glGenTextures(1,&(this->to));
glBindTexture(GL_TEXTURE_CUBE_MAP,this->to);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
glBindTexture(GL_TEXTURE_CUBE_MAP,0);
this->image_front = new Image2D(size,size,texel_type);
this->image_back = new Image2D(size,size,texel_type);
this->image_left = new Image2D(size,size,texel_type);
this->image_right = new Image2D(size,size,texel_type);
this->image_top = new Image2D(size,size,texel_type);
this->image_bottom = new Image2D(size,size,texel_type);
}
virtual ~TextureCubeMap()
{
delete this->image_front;
delete this->image_back;
delete this->image_left;
delete this->image_right;
delete this->image_top;
delete this->image_bottom;
}
virtual void update_gpu()
{
int i;
Image2D *images[] =
{this->image_front,
this->image_back,
this->image_left,
this->image_right,
this->image_bottom,
this->image_top};
GLuint targets[] =
{GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
GL_TEXTURE_CUBE_MAP_POSITIVE_X,
GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
GL_TEXTURE_CUBE_MAP_POSITIVE_Y};
glBindTexture(GL_TEXTURE_CUBE_MAP,this->to);
for (i = 0; i < 6; i++)
{
glTexImage2D(targets[i],0,GL_RGBA,this->size,this->size,0,GL_RGBA,GL_FLOAT,images[i]->get_data_pointer());
// glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
}
glBindTexture(GL_TEXTURE_CUBE_MAP,0);
}
virtual void load_from_gpu()
{
int i;
glBindTexture(GL_TEXTURE_CUBE_MAP,this->to);
Image2D *images[] =
{this->image_front,
this->image_back,
this->image_left,
this->image_right,
this->image_bottom,
this->image_top};
GLuint targets[] =
{GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
GL_TEXTURE_CUBE_MAP_POSITIVE_X,
GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
GL_TEXTURE_CUBE_MAP_POSITIVE_Y};
for (i = 0; i < 6; i++)
{
images[i]->set_size(this->size,this->size);
glGetTexImage(targets[i],0,GL_RGBA,GL_FLOAT,images[i]->get_data_pointer());
}
}
bool load_ppms(string front, string back, string left, string right, string bottom, string top)
{
bool result = true;
result = result && this->image_front->load_ppm(front);
result = result && this->image_back->load_ppm(back);
result = result && this->image_left->load_ppm(left);
result = result && this->image_right->load_ppm(right);
result = result && this->image_bottom->load_ppm(bottom);
result = result && this->image_top->load_ppm(top);
auto lambda_size_ok = [](Image2D *image, int size)
{
return (image->get_width() == size) && (image->get_height() == size);
};
if (!lambda_size_ok(this->image_front,this->size) ||
!lambda_size_ok(this->image_back,this->size) ||
!lambda_size_ok(this->image_left,this->size) ||
!lambda_size_ok(this->image_right,this->size) ||
!lambda_size_ok(this->image_top,this->size) ||
!lambda_size_ok(this->image_bottom,this->size))
ErrorWriter::write_error("Loaded cubemap images don't have the same size.");
return result;
}
virtual void print()
{
cout << "front:" << endl;
this->image_front->print();
cout << "back:" << endl;
this->image_back->print();
cout << "left:" << endl;
this->image_left->print();
cout << "right:" << endl;
this->image_right->print();
cout << "bottom:" << endl;
this->image_bottom->print();
cout << "top:" << endl;
this->image_top->print();
}
virtual void bind(unsigned int unit)
{
switch (unit)
{
case 0: glActiveTexture(GL_TEXTURE0); break;
case 1: glActiveTexture(GL_TEXTURE1); break;
case 2: glActiveTexture(GL_TEXTURE2); break;
case 3: glActiveTexture(GL_TEXTURE3); break;
case 4: glActiveTexture(GL_TEXTURE4); break;
case 5: glActiveTexture(GL_TEXTURE5); break;
case 6: glActiveTexture(GL_TEXTURE6); break;
case 7: glActiveTexture(GL_TEXTURE7); break;
case 8: glActiveTexture(GL_TEXTURE8); break;
case 9: glActiveTexture(GL_TEXTURE9); break;
default:
break;
}
glBindTexture(GL_TEXTURE_CUBE_MAP,this->to);
}
};
以及错误的图像(第一个是我得到的,第二个是法线渲染的):
您在评论中自己找到了解决方案,但要求提供更多背景信息以了解其行为方式的原因。
是的,如果你想在同一个片段着色器中使用两个不同的纹理,你必须将两个纹理绑定到不同的纹理单元,并将采样器统一变量的值设置为匹配的纹理单元索引。
对于两个纹理使用相同目标的情况,很明显这一定是真的。否则您的纹理绑定代码将如下所示:
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex1);
glBindTexture(GL_TEXTURE_2D, tex2);
和第二个 glBindTexture()
调用当然会覆盖第一个。因此,您将使用不同的纹理单元:
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex1);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, tex2);
在您使用两个不同纹理目标的情况下,事情就不那么明显了。在这个调用序列之后:
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex1);
glBindTexture(GL_TEXTURE_CUBE_MAP, tex2);
您确实有两个 纹理绑定到纹理单元 0。在 OpenGL 状态下,每个纹理单元包含每个目标的绑定。
现在,如果您想在同一个着色器中使用 2D 和立方体贴图纹理,那么您可以如上所示绑定两个纹理,并将两个采样器统一设置为值 0 似乎是一个完全合理的期望.但其实这个是不支持的,因为...就是这么定义的
这是 OpenGL 3.3 规范第 74 页的“2.11.5 采样器”部分:
It is not allowed to have variables of different sampler types pointing to the same texture image unit within a program object. This situation can only be detected at the next rendering command issued, and an INVALID_OPERATION error will then be generated.
虽然这基于 GPU 通常如何从着色器代码访问采样器是有意义的,但不幸的是,您可以通过着色器代码无法使用的方式为纹理绑定设置状态。部分原因可能是基于 OpenGL 的悠久历史。
要完成这项工作,您将必须使用两个不同的纹理单元,就像您在两个纹理使用相同目标的情况下所做的那样:
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex1);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_CUBE_MAP, tex2);