OpenGL统一缓冲区是什么?

8
我正在尝试使用统一缓冲区,但它并没有按照预期工作。我有两个统一缓冲区,一个用于光照,另一个用于材质。问题是颜色不是应该的颜色,并且每次移动相机时都会改变。当我使用普通uniforms时,这个问题不存在。以下是图片以说明我的意思:使用统一缓冲区使用普通uniforms

这是我的片段着色器:

#version 400 // Fragment Shader
uniform layout(std140);

in vec3 EyePosition;
in vec3 EyeNormal;
in vec2 TexCoord;

out vec4 FragColor;

uniform sampler2D Texture;

uniform LightBlock
{
    vec4 Position;
    vec4 Intensity;
} Light;

uniform MaterialBlock
{
    vec4 Ambient;
    vec4 Diffuse;
} Material;

vec4 PointLight(in int i, in vec3 ECPosition, in vec3 ECNormal)
{
    vec3 n = normalize(ECNormal);
    vec3 s = normalize(Light.Position.xyz - ECPosition);

    return Light.Intensity * (Material.Ambient + Material.Diffuse * max(dot(s, n), 0.0));
}

void main()
{
    FragColor  = texture(Texture, TexCoord);
    FragColor *= PointLight(0, EyePosition, EyeNormal);
}

我不确定我是否做得完全正确,但这是我创建统一缓冲区的方法:
glGenBuffers(1, &light_buffer);
glGenBuffers(1, &material_buffer);

glBindBuffer(GL_UNIFORM_BUFFER, light_buffer);
glBufferData(GL_UNIFORM_BUFFER, sizeof(LightBlock), nullptr, GL_DYNAMIC_DRAW);

glBindBuffer(GL_UNIFORM_BUFFER, material_buffer);
glBufferData(GL_UNIFORM_BUFFER, sizeof(MaterialBlock), nullptr, GL_DYNAMIC_DRAW);

GLuint program = Shaders.GetProgram();

light_index = glGetUniformBlockIndex(program, "LightBlock");
material_index = glGetUniformBlockIndex(program, "MaterialBlock");

glUniformBlockBinding(program, light_index, 0);
glUniformBlockBinding(program, material_index, 1);

glBindBufferBase(GL_UNIFORM_BUFFER, 0, light_buffer);
glBindBufferBase(GL_UNIFORM_BUFFER, 1, material_buffer);

编辑:以下是我填充缓冲区的方法:

// Global structures
struct LightBlock
{
    Vector4 Position; // Vector4 is a vector class I made
    Vector4 Intensity;
};

struct MaterialBlock
{
    Vector4 Ambient;
    Vector4 Diffuse;
};

// This is called for every object rendered
LightBlock Light;
Light.Position = Vector3(0.0f, 5.0f, 5.0f) * Camera.GetCameraMatrix();
Light.Intensity = Vector4(1.0f);

glBindBuffer(GL_UNIFORM_BUFFER, light_buffer);
glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(LightBlock), &Light);

MaterialBlock Material;
Material.Diffuse = Vector4(1.0f);
Material.Ambient = Material.Diffuse * Vector4(0.3f);

glBindBuffer(GL_UNIFORM_BUFFER, material_buffer);
glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(MaterialBlock), &Material);

你已经做了哪些调试工作?你尝试过打印着色器中获取的值吗(通过将它们作为片段着色器输出简单地写出来)?至少对于颜色,你应该能够看到哪些值没有按照你的期望输出。 - Nicol Bolas
还有,你用来填充那些缓冲区的代码在哪里? - Nicol Bolas
@Gigi:我在Cat 12.1上没有看到过这个问题。对我来说它似乎工作正常,而且我在我的片段着色器中使用了2个块。另外,你是否已经提交了错误报告? - Nicol Bolas
@Gigi 是的,我有一张HD 6970显卡,使用12.1驱动程序。 - Traxmate
@Traxmate,你能否尝试重构着色器,以便仅使用统一块? - Gigi
显示剩余4条评论
2个回答

2
我遇到了同样的问题,但只有在使用AMD(而非NVIDIA)时才会出现。有趣的是,这个问题只发生在改变视图矩阵时。
由于我遇到了可以重复的问题,取决于视图矩阵的变化,因此我能够追溯到根本原因(通过艰苦的试错)。在我的应用程序中更改视图时,我动态地分配和释放一些OpenGL资源,具体取决于需要什么。在此过程中,会对缓冲区0调用glDeleteBuffers()。如果我使用条件语句,不对缓冲区0调用glDeleteBuffers,则问题就消失了。
根据文档,缓冲区0将被glDeleteBuffers静默忽略。我猜测这是AMD驱动程序的一个错误。

2
尝试使用glMapBuffer/glUnmapBuffer更新缓冲区。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接