I am trying to get the uniform block name from a shader handle using glGetProgramResourceName().
Yet it throws (0xC0000005: Access violation executing location 0x0000000000000000) on std::vector<GLchar> blockName and I can't figure out why.
GLint numUniformBlocks = 0;
GLint maxLength;
GLsizei size;
glGetProgramiv(handle_, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxLength);
glGetProgramInterfaceiv(handle_, GL_UNIFORM_BLOCK, GL_ACTIVE_RESOURCES, &numUniformBlocks);
std::array<GLenum, 3> blockProperties{GL_NAME_LENGTH, GL_NUM_ACTIVE_VARIABLES, GL_BUFFER_DATA_SIZE};
std::array<GLint, 3> blockData{};
for (int blockIx = 0; blockIx < numUniformBlocks; ++blockIx) {
glGetProgramResourceiv(handle_,GL_UNIFORM_BLOCK,blockIx,blockProperties.size(), blockProperties.data(), blockData.size(),nullptr,blockData.data()
);
//Retrieve name
//std::string blockName(blockData[0], ' ');
//std::vector<char> blockName(blockData[0]);
std::vector<GLchar> blockName; //Yes, not std::string. There's a reason for that.
blockName.resize(blockData[0]);
//GLchar* blockName = static_cast<GLchar*>(malloc(maxLength));
glGetProgramResourceName(handle_, GL_UNIFORM_BLOCK, blockIx, blockName.size(), &size, blockName.data());
}
Here is my shader
#version 400
layout (location = 0) in vec4 VertexPosition;
out vec2 TexCoords;
layout(std140) uniform Matrices_XY{
mat4 cameraToClipMatrix;
mat4 worldToCameraMatrix;
mat4 modelToWorldMatrix;
mat4 NormalMatrix;
};
void main(){
gl_Position = cameraToClipMatrix * worldToCameraMatrix * modelToWorldMatrix * vec4(VertexPosition.xy, 0.0, 1.0);
TexCoords = VertexPosition.zw;
}
I've tried std::string, std::vector<char>, GLchar* name = static_cast<GLchar*>(malloc(maxLength)) and all throw. I've tried appending '\0' and adjusting the size sent into function called but all throws. I am expecting to get the name of the lone UBO which is "Matrices_XY"
I'm on OpenGL 4.6, C++20, MSVC 2022/17.3.6, Windows Pro10, x64, MFC
I did not have function defined; once I added, all is well
glGetProgramResourceName = (PFNGLGETPROGRAMRESOURCENAMEPROC)wglGetProcAddress("glGetProgramResourceName");
Related
I have been trying to pass a mat4 into VS.
I am activating the shader program before passing the data:
renderProg.use(); // glUseProgram( m_programHandle );
glm::mat4 mv = view * model;
renderProg.setUniform("u_ModelViewMatrix", mv);
renderProg.setUniform("u_MVP", projection * mv);
But for some reason the uniform variable(u_ModelViewMatrix) is not being activated and returning -1 in the "Location" of glGetUniformLocation. Here is the VS code:
#version 460
layout (location = 0 ) in vec3 VertexPosition;
uniform mat4 u_MVP;
uniform mat4 u_ModelViewMatrix;
out vec3 Position;
void main()
{
vec4 vp = vec4(VertexPosition, 1.0);
Position = (u_ModelViewMatrix * vp).xyz;
gl_Position = u_MVP * vp;
}
FS Code:
#version 460
in vec3 Position;
uniform vec4 Color;
layout( location = 0 ) out vec4 FragColor;
void main() {
FragColor = Color;
}
Only one uniform is not being able to set "u_ModelViewMatrix", the other is being successfully accessed "u_MVP". Both uniforms use the same call for receiving data:
glUniformMatrix4fv(loc, 1, GL_FALSE, &m[0][0]);
Right after successful linking and compiling of the Vertex and the Fragment shader , if I am querying the active uniforms , its returning two location of uniforms , one is from FS "Color" the other is from VS "u_MVP"
for( int i = 0; i < nUniforms; ++i ) {
glGetActiveUniform( m_programHandle, i, maxLen, &written, &size, &type, name );
location = glGetUniformLocation(m_programHandle, name);
qDebug() << "Location: " << location << " Name: " << name;
}
Output:
Location: 0 Name: Color
Location: 1 Name: u_MVP
What am I doing wrong here?
The interface variabel Position is not used in the fragment shader. So the uniform variable u_ModelViewMatrix is not required. This uniform is "optimized out" by the linker and does not become an active program resource. Therefor you'll not get a uniform location for "u_ModelViewMatrix".
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.
I did run into some trouble setting up my animation shader for my OpenGL application. Basically it takes in an array of 50 glm::mat4 matrices and should set them as uniform in my GLSL shader. Yet only the first value is actually send to the shader, all other array entries in the shader are set to 0.
I think the problem occurs when passing from C++ to GLSL:
class model{
...
glm::mat4 finalBoneTransforms[50];
...
}
model::draw(){
//Set Joints
int jointLoc = glGetUniformLocation(shaderID, "jointTransforms");
glUniformMatrix4fv(jointLoc, 50 , GL_FALSE, glm::value_ptr(finalBoneTransforms[0]));
...
}
So how comes that only the first value is passed? Shouldn't OpenGL take in 50 elements stored in the contiguous memory to the first element, which is referenced via the value_ptr?
I would highly prefer to use arrays instead of vectors to make sure not to suffer any pointer loss due to reallocation. Arent elements in an array stored in contiguous memory? Any other obvious mistakes causing that weird behaviour?
Edit: Heres the shader code:
#version 330 core
const int MAX_JOINTS = 50;
const int MAX_WEIGHTS = 4;
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormals;
layout (location = 2) in vec2 aTexCoord;
layout (location = 3) in vec4 aBoneWeight;
layout (location = 4) in ivec4 aBoneIndex;
out vec2 texCoords;
uniform mat4 jointTransforms[MAX_JOINTS];
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main(void) {
vec4 totalLocalPos = vec4(0.0);
vec4 totalNormal = vec4(0.0);
for (int i = 0; i<MAX_WEIGHTS; i++) {
mat4 jointTransform = jointTransforms[aBoneIndex[i]];
vec4 posePosition = jointTransform * vec4(aPos, 1.0);
totalLocalPos += posePosition * aBoneWeight[i];
}
gl_Position = projection*view * totalLocalPos;
texCoords = aTexCoord;
};
Part of the geometry shader code looks like this:
layout(std430) restrict coherent buffer BufferName
{
uint bufferName[][MAX_EXPECTED_ENTRIES];
};
...
void main()
{
...
bufferName[a][b] = someValue;
...
}
Everything works as expected until I add a writeonly statement to either BufferName, bufferName or both.
With the writeonly statement I get the following error: error C7586: OpenGL does not allow reading writeonly variable 'bufferName'.
What's going on here?
All I do is writing to bufferName and the spec says that writeonly is allowed. This also happens for one-dimensional arrays within a storage block.
Thanks in advance.
Here's the full shader code (BufferName from the example is now IDsPerVertex):
#version 450
#define MAX_EXPECTED_VERTEX_PRIMITIVE_IDS 10
layout(triangles) in;
layout(triangle_strip, max_vertices = 3) out;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
layout(std430) restrict coherent buffer IDsPerVertex
{
uint iDsPerVertex[][MAX_EXPECTED_VERTEX_PRIMITIVE_IDS];
};
layout(std430) restrict coherent buffer Counter
{
uint counter[];
};
in int ID[3]; // contains gl_VertexID
out vec4 debugColor;
uint index[3];
void writeIDsPerVertex()
{
// get the next free location for each vertex
index[0] = atomicAdd(counter[ID[0]], 1u);
index[1] = atomicAdd(counter[ID[1]], 1u);
index[2] = atomicAdd(counter[ID[2]], 1u);
// write the triangle primitive ID to each vertex list
iDsPerVertex[ID[0]][index[0]] = gl_PrimitiveIDIn;
iDsPerVertex[ID[1]][index[1]] = gl_PrimitiveIDIn;
iDsPerVertex[ID[2]][index[2]] = gl_PrimitiveIDIn;
}
void passThrough()
{
for(int i = 0; i < gl_in.length(); i++)
{
gl_Position = projection * view * model * gl_in[i].gl_Position;
debugColor = vec4(1);
EmitVertex();
}
EndPrimitive();
}
void main()
{
writeIDsPerVertex();
passThrough();
}
The full error message my environment gives me:
SHADER PROGRAM 37 LOG
Geometry info
-------------
(0) : error C7586: OpenGL does not allow reading writeonly variable 'iDsPerVertex'
I've been staring at this for too long and I'm too new to GLSL to know what is wrong. All I know is that when checking to see if the vertex shader compiles, it says that it could not do so. If someone could help me find out what I've done wrong that would be amazing.
textureShader.vert
#version 140
uniform mat4 mvpMatrix;
attribute vec3 position;
attribute vec2 textCoord;
varying vec2 TextCoord;
varying vec3 lightDir,normal;
void main()
{
normal = normalize(gl_NormalMatrix * gl_Normal);
lightDir = normalize(vec3(gl_LightSource[0].position));
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_Position = position;
}
textureShader.frag
#version 140
uniform sampler2D texUnit;
varying vec2 TextCoord;
varying vec3 lightDir,normal;
void main()
{
vec3 ct,cf;
vec4 texel;
float intensity,at,af;
intensity = max(dot(lightDir,normalize(normal)),0.0);
cf = intensity * (gl_FrontMaterial.diffuse).rgb + gl_FrontMaterial.ambient.rgb;
af = gl_FrontMaterial.diffuse.a;
texel = texture2D(texUnit, TextCoord);
ct = texel.rgb;
at = texel.a;
gl_FragColor = vec4(ct * cf, at * af);
}
What I'm doing to check the compilation. DBOUT is a function to write to the Visual Studio output box.
glCompileShader(shader_vp);
validateShader(shader_vp, vsFile);
GLint compiled;
glGetShaderiv(shader_vp, GL_COMPILE_STATUS, &compiled);
if (!compiled){
DBOUT("Couldn't Compile Vertex Shader: Aborting Mission\n");
abort();
}
glCompileShader(shader_fp);
validateShader(shader_fp, fsFile);
glGetShaderiv(shader_fp, GL_COMPILE_STATUS, &compiled);
if (!compiled){
DBOUT("Couldn't Compile Fragment Shader: Aborting Mission\n");
abort();
}
The output I receive:
Couldn't Compile Vertex Shader: Aborting Mission
Debug Error!
SOLVED
So with everyones help I go this to compile. I had to replace these lines:
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_Position = position;
With these ones:
TextCoord = vec2(textCoord);
gl_Position = mvpMatrix * vec4(position,1.0f);
Thank you everyone!
I didn't look at your shader but you can get an error message from the compiler with something like:
auto error = GLint();
::glGetShaderiv(id, GL_COMPILE_STATUS, &error);
if(error != GL_TRUE)
{
auto length = GLint();
::glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);
if(length > 0)
{
auto log = std::vector<GLchar>(length, 0);
::glGetShaderInfoLog(id, length, nullptr, &log[0]);
auto message = std::string(log.begin(), log.end());
...
}
}
One possible error in the shader might be:
gl_Position = position;
The gl_Position should be of type vec4, but the position is an attribute of vec3, you probably forgot to do something like:
gl_Position = mvpMatrix * vec4(position, 1.0f);