I'm referring to the OpenGL SuperBible. I use their framework to create an own program. I wanted to do something with an Interface Block (specifically a Uniform Block). If I call
glGetActiveUniformsiv(program, 1, uniformIndices, GL_UNIFORM_OFFSET, uniformOffsets);
I get an error, namely GL_INVALID_VALUE.
But if I call the same function with a 0 instead of a 1, it doesn't make that error. I assumed then, that I have no active uniforms. I should have 3 of them, however.
How do I activate them? Here's my shader:
#version 450 core
layout (location = 0) in vec4 position;
layout (location = 1) in vec4 color;
out vec4 vs_color;
uniform TransformBlock {
mat4 translation;
mat4 rotation;
mat4 projection_matrix;
};
void main(void)
{
mat4 mvp = projection_matrix * translation * rotation ;
gl_Position = mvp * position;
vs_color = color;
}
Here is some code from the startup method:
static const GLchar* uniformNames[3] = {
"TransformBlock.translation",
"TransformBlock.rotation",
"TransformBlock.projection_matrix",
};
GLuint uniformIndices[3];
glUseProgram(program);
glGetUniformIndices(program, 3, uniformNames, uniformIndices);
GLint uniformOffsets[3];
GLint matrixStrides[3];
glGetActiveUniformsiv(program, 3, uniformIndices, GL_UNIFORM_OFFSET, uniformOffsets);
glGetActiveUniformsiv(program, 3, uniformIndices, GL_UNIFORM_MATRIX_STRIDE, matrixStrides);
unsigned char* buffer1 = (unsigned char*)malloc(4096);
//fill buffer1 in a for-loop
GLuint block_index = glGetUniformBlockIndex(program, "TransformBlock");
glUniformBlockBinding(program, block_index, 0);
glBindBufferBase(GL_UNIFORM_BUFFER, 0, (GLuint)buffer1);
free(buffer1);
However, as a consequence of the function returning GL_INVALID_VALUE there's an error with the calls:
*((float *)(buffer1 + offset)) = ...
and the whole program interrupts. Without adding the offset, I don't get an error here, so I think the second error depends on the first error.
I think it goes wrong at glGetUniformIndices, because you prefixed your uniform names with TransformBlock. You don't use that to access the uniforms with that prefix in the GLSL code, either. If you wanted that, you'd had to set an instance name for the uniform block, the block name is not relevant for accessing / naming the uniforms at all. It is only used for matching interfaces if you link together multiple shaders accessing the same interface block.
Related
It seems that the glsl compiler optimizes unused variable (remove).
In my case I used the variable but the glGetUniformLocation returns -1
rgbScene.addRenderStage(
[&obj = std::as_const(model)](Camera* cam) {
auto& mesh = std::get<Mesh>(obj);
auto& program = std::get<ShaderProgram>(obj);
glUseProgram(program);
glBindVertexArray(mesh.getData<VAO>());
int loc;
glUniformMatrix4fv(
loc = glGetUniformLocation(program, "proj_matrix"),
1, GL_FALSE,
glm::value_ptr(cam->getProjectionMatrix())
);
glUniformMatrix4fv(
loc = glGetUniformLocation(program, "view_matrix"),
1, GL_FALSE,
glm::value_ptr(cam->getViewMatrix())
);
glUniformMatrix4fv(
loc = glGetUniformLocation(program, "model_matrix"),
1, GL_FALSE,
glm::value_ptr(mesh.getModelMatrix())
);
glUniform3fv(
loc = glGetUniformLocation(program, "light_direction"),
1, glm::value_ptr(-(cam->getForward()))
);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, mesh.getData<VertexData>());
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, mesh.getData<NormalData>());
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
glDrawArrays(GL_TRIANGLES, 0, mesh.getSize());
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(0);
});
I checked variable loc by debuging line by line in Visual Studio 2019 and at the last glGetUniformLocation returns -1
here's my vertex shader code
#version 460 core
uniform mat4 proj_matrix;
uniform mat4 view_matrix;
uniform mat4 model_matrix;
uniform vec3 light_direction;
layout(location = 0) in vec3 pos;
layout(location = 1) in vec3 normal;
out VS_OUT
{
vec3 N;
vec3 L;
vec3 V;
} vs_out;
void main(void)
{
vec4 P = view_matrix * model_matrix * vec4(pos, 1.0);
vs_out.N = mat3(view_matrix * model_matrix) * normal;
vs_out.L = mat3(view_matrix) * (-light_direction);
vs_out.V = -P.xyz;
gl_Position = proj_matrix * P;
}
I tried changing the variable name, different order... but cannot fixed this problem
Is there any other rules for uniform variable in shader??
-- Edit --
for fragment shader,
#version 460 core
layout (location = 0) out vec4 color;
in VS_OUT
{
vec3 N;
vec3 L;
vec3 V;
} fs_in;
uniform vec3 diffuse_albedo = vec3(0.8, 0.3, 0.2);
uniform vec3 specular_albedo = vec3(0.7);
uniform float specular_power = 128.0;
void main(void)
{
vec3 N = normalize(fs_in.N);
vec3 L = normalize(fs_in.L);
vec3 V = normalize(fs_in.V);
vec3 R = reflect(-L, N);
vec3 diffuse = max(dot(N, L), 0.0) * diffuse_albedo;
vec3 specular = pow(max(dot(R, V), 0.0), specular_power) * specular_albedo;
color = vec4(diffuse + specular, 1.0);
// color = vec4(1.0,1.0, 1.0, 1.0);
}
The fragment shader inputs N, L and V variables have to be "used", too.
Note, the active resources are determined when the program is linked. If an input to the fragment shader is unused, the uniforms which set the corresponding output variable in the vertex shader may not become active.
See OpenGL 4.6 Core Profile Specification - 7.3.1 Program Interfaces, page 102:
7.3.1 Program Interfaces
When a program object is made part of the current rendering state, its executable code may communicate with other GL pipeline stages or application code through a variety of interfaces. When a program is linked, the GL builds a list of active resources for each interface. Examples of active resources include variables, interface blocks, and subroutines used by shader code. Resources referenced in shader code are considered active unless the compiler and linker can conclusively determine that they have no observable effect on the results produced by the executable code of the program. For example, variables might be considered inactive if they are declared but not used in executable code, used only in a clause of an if statement that would never be executed, used only in functions that are never called, or used only in computations of temporary variables having no effect on any shader output. In cases where the compiler or linker cannot make a conclusive determination, any resource referenced by shader code will be considered active. The set of active resources for any interface is implementation-dependent because it depends on various analysis and optimizations performed by the compiler and linker
If a program is linked successfully, the GL will generate lists of active resources based on the executable code produced by the link.
When I try to compile this GLSL code in OpenGL 4.0 I get error 1282
Vertex shader:
#version 330 core
layout(location = 0) in vec2 aPos;
uniform mat4 model[100];
uniform mat4 projection;
out int instanceID;
void main()
{
instanceID = gl_InstanceID;
gl_Position = projection * model[gl_InstanceID] * vec4(aPos.x, aPos.y, 0.0, 1.0);
}
Fragment shader:
#version 330 core
in int instanceID;
out vec4 FragColor;
uniform vec4 color[100];
void main()
{
FragColor = color[instanceID];
}
The code is regular ShaderProgram creation because I get the error before drawing or anything like that but just in case here is the code:
unsigned int vertex, fragment;
vertex = glCreateShader(GL_VERTEX_SHADER);
std::string vShaderCode = ReadEntireTextFile(vertPath);
const char* c_vShaderCode = vShaderCode.c_str();
glShaderSource(vertex, 1, &c_vShaderCode, NULL);
glCompileShader(vertex);
std::string fShaderCode = ReadEntireTextFile(fragPath);
fragment = glCreateShader(GL_FRAGMENT_SHADER);
const char* c_fShaderCode = fShaderCode.c_str();
glShaderSource(fragment, 1, &c_fShaderCode, NULL);
glCompileShader(fragment);
// shader Program
m_RendererID = glCreateProgram();
glAttachShader(m_RendererID, vertex);
glAttachShader(m_RendererID, fragment);
glLinkProgram(m_RendererID);
// delete the shaders as they're linked into our program now and no longer necessery
glDeleteShader(vertex);
glDeleteShader(fragment);
glUseProgram(m_RendererID);
I know for sure that the error is because of instanceID because it worked when the shader didn't have that. but I tried to find where the problem is exactly with no luck.
UPDATE:
Made sure shaders were compiled successfully. and turns out they are compiled successfully.
I was able to pinpoint where the error occurs and it was the glUseProgram funtion.
I think the error is because of instanceID because when I change:
FragColor = color[instanceID];
to
FragColor = color[0];
the program works.
UPDATE(2):
I solved the problem.
Turns out I had 2 problems one being that I had too many components and I fixed that thanks to one of the answers alerting me.
The other was that I can't put uniforms directly in the fragment shader which I thought you could do.So I put the colors in the vertex shader and passed the one color I needed for the fragment shader.
Thanks for the help!
uniform mat4 model[100];
That is way outside of what is guaranteed by the spec. The limit here is GL_MAX_VERTEX_UNIFORM_COMPONENTS, which the spec guarantees to be at least 1024. Since a mat4 consumes 16 components, that's 64 matrices at most. Now your particular limit might be higher, but you also have the other uniforms in your program, like color[100].
(from comments):
It does not return anything for both fragment and vertex shaders and glGetShaderiv(shader, GL_COMPILE_STATUS, &output); returns true for both shaders.
But that does not imply that the program object linked successfully. Such ressource limits are usually enforced during linking.
I'm pretty sure program is an object created by openGL successfully, I'm not really sure about the others though. you see if i change the fragment shader main function to FragColor = color[0]; it will work so the issue is with instanceID I think.
That conclusion does not follow. If you write color[0], it will optimize your vec4r[100] array to vec4[1], and you might get below your particular limit.
I'm writing a 2D game in OpenTK, using OpenGL 4.4. Using colour and texture UV coordinates and a matrix I can succesfully draw textures between vertices with vertex shader:
public const string vertexShaderDefaultSrc =
#"
#version 330
uniform mat4 MVPMatrix;
layout (location = 0) in vec2 Position;
layout (location = 1) in vec2 Texture;
layout (location = 2) in vec4 Colour;
out vec2 InTexture;
out vec4 OutColour;
void main()
{
gl_Position = MVPMatrix * vec4(Position, 0, 1);
InTexture = Texture;
OutColour = Colour;
}";
and fragment shader:
public const string fragmentShaderDefaultSrc =
#"
#version 330
uniform sampler2D Sampler;
in vec2 InTexture;
in vec4 OutColour;
out vec4 OutFragColor;
void main()
{
OutFragColor = texture(Sampler, InTexture) * OutColour;
//Alpha test
if(OutFragColor.a <= 0)
discard;
}
";
BUT if I want to draw just a solid colour rather than a texture, I use this shader (with the same vertices, passing UV coords that won't be used):
public const string fragmentShaderSolidColourSrc =
#"
#version 330
uniform sampler2D Sampler;
in vec2 InTexture;
in vec4 OutColour;
out vec4 OutFragColor;
void main()
{
OutFragColor = OutColour;
//Alpha test
if(OutFragColor.a <= 0)
discard;
}
";
Now this works beautifully, but OpenGL reports an error - GL_INVALID_VALUE. It draws fine and everything seems to work, but ideally I would like OpenGL to be error free in that situation, so I can catch real errors. I would appreciate any help, and can share more detail of how the shader is compiled or used if that is helpful - what I don't understand is how the default shader can work but the solid colour doesn't.
I have tracked down the exact source of the errors in my render call (shader builds with no problems)
GL.EnableVertexAttribArray(shader.LocationPosition);
GL.VertexAttribPointer(shader.LocationPosition, 2, VertexAttribPointerType.Float, false, Stride, 0);
//-----everything up to here is fine
//this line throws an error
GL.EnableVertexAttribArray(shader.LocationTexture);
//as does this line
GL.VertexAttribPointer(shader.LocationTexture, 2, VertexAttribPointerType.Float, false, Stride, 8);
//this is all ok
GL.EnableVertexAttribArray(shader.LocationColour);
GL.VertexAttribPointer(shader.LocationColour, 4, VertexAttribPointerType.UnsignedByte, true, Stride, 16);
//ok
GL.BindBuffer(BufferTarget.ElementArrayBuffer, indexBuffer);
GL.DrawArrays(DrawType, 0, Vertices.Length);
//ok
GL.DisableVertexAttribArray(shader.LocationPosition);
//this line throws error
GL.DisableVertexAttribArray(shader.LocationTexture);
//this is ok
GL.DisableVertexAttribArray(shader.LocationColour);
It appears to me after some tests (would be nice to have this verified) that if a variable such as the texture coordinates are not used by the shader the compiler gets rid of it, so a call to get it's location returns -1. Simply checking if locationTexture was -1 here and then not binding locationTexture etc if so resolved my issues.
I have a program set up with deferred rendering. I am in the process of removing my position texture in favour of reconstructing positions from depth. I have done this before with no trouble but now for some reason I am getting a segfault when trying to access matrices I pass in through uniforms!
My fragment shader (vertex shader irrelevant):
#version 430 core
layout(location = 0) uniform sampler2D depth;
layout(location = 1) uniform sampler2D diffuse;
layout(location = 2) uniform sampler2D normal;
layout(location = 3) uniform sampler2D specular;
layout(location = 4) uniform mat4 view_mat;
layout(location = 5) uniform mat4 inv_view_proj_mat;
layout(std140) uniform light_data{
// position ect, works fine
} light;
in vec2 uv_f;
vec3 recontruct_pos(){
float z = texture(depth, uv_f);
vec4 pos = vec4(uv_f * 2.0 - 1.0, z * 2.0 - 1.0, 1.0);
//pos = inv_view_proj_mat * pos; //un-commenting this line causes segfault
return pos.xyz / pos.w;
}
layout(location = 3) out vec4 lit; // location 3 is lighting texture
void main(){
vec3 pos = reconstruct_pos();
lit = vec4(0.0, 1.0, 1.0, 1.0); // just fill screen with light blue
}
And as you can see the code causing this segfault is shown in the reconstruct_pos() function.
Why is this causing a segfault? I have checked the data within the application, it is correct.
EDIT:
The code I use to update my matrix uniforms:
// bind program
glUniformMatrix4fv(4, 1, GL_FALSE, &view_mat[0][0]);
glUniformMatrix4fv(5, 1, GL_FALSE, &inv_view_proj_mat[0][0]);
// do draw calls
The problem was my call to glBindBufferBase when allocating my light buffer. Now that I have corrected the arguments I am passing, everything works fine with no segfaults.
Now the next question is: Why are all of my uniform locations reporting to be -1 O_o
Maybe it's the default location, who knows.
glUniformMatrix() method expects the input data be a flattened array with column major order (i.e. float array[16];), not a two-dimensional array (i.e. float array[4][4]). The latter may cause you either a segfault or a program malfunction, due to the 4 single-dimensional arrays composing the 2-dimensional array not being located sequentially.
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);
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.
Try to update the buffer using glMapBuffer/glUnmapBuffer.