OpenGL Uniform buffers?
Asked Answered
H

2

8

I'm trying to use uniform buffers but it doesn't work as supposed. I have two uniform buffers, one is lighting and the other is for material. The problem is that the colors aren't what they are supposed to be and they change every time I move the camera. This problem didn't exist when I used normal uniforms. Here's pictures to show what I mean: When using uniform buffers and when using normal uniforms!

This is my fragment shader:

#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);
}

I'm not sure I have done everything right but here's how I create the uniform buffers:

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);

EDIT: Here's how I fill the buffers:

// 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);
Hemangioma answered 6/2, 2012 at 2:36 Comment(9)
What have you done to debug this? Have you tried printing out what values you get in the shader (by simply writing them as the fragment shader output)? At least with the colors, you should be able to see which values aren't coming out as you expect.Liaoyang
Also, where's the code that you use to fill those buffers with values?Liaoyang
@Gigi: I haven't seen this on the Cat 12.1's. It seems to work fine for me, and I use 2 blocks in my fragment shader. Also, have you filed bug reports on this?Liaoyang
@Gigi Yes, I have a HD 6970 with the 12.1 driversHemangioma
@Hemangioma Can you try to refactor the shader so that it use only a uniform block?Dextroamphetamine
@Dextroamphetamine Well I could but these are just basic shaders. I'm planning on to improve them and would rather have them separated.Hemangioma
@NicolBolas I've updated the main post with the buffer filling code!Hemangioma
@Hemangioma I've suggested it only to isolate the problem, not as a final solutionDextroamphetamine
@Dextroamphetamine It works just fine when everything is in one block :sHemangioma
S
2

I had the same problem, but only with AMD (not NVIDIA). The funny thing was that the problem only happened when changing the view matrix.

As I had a repeatable problem depending on change of the view matrix, I was able to trace to the root cause (doing arduous trial and error). When changing the view in my application, I allocate and free some OpenGL resources dynamically depending on what is needed. In this process, there is a call to glDeleteBuffers() for buffer 0. If I use a conditional statement so as not to call glDeleteBuffers for buffer 0, then the problem goes away.

According to documentation, buffer 0 will be silently ignored by glDeleteBuffers. My guess is that there is a bug in the AMD drivers.

Semination answered 24/7, 2012 at 19:22 Comment(0)
O
2

Try to update the buffer using glMapBuffer/glUnmapBuffer.

Officiary answered 18/11, 2014 at 12:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.