This code throws nvoglv32.dll exception. I think there is an error in glShaderSource somewherer, but I can't find it
ifstream ifs("vertexShader.txt");
string vertexShadersSource((istreambuf_iterator<char>(ifs)),
(std::istreambuf_iterator<char>()));
ifs.close();
ifs.open("fragmentShader.txt");
string fragmentShadersSource((istreambuf_iterator<char>(ifs)),
(std::istreambuf_iterator<char>()));
cout << fragmentShadersSource.c_str() << endl;
cout << vertexShadersSource.c_str() << endl;
GLuint shaderProgram;
GLuint fragmentShader, vertexShader;
vertexShader = glCreateShader(GL_VERTEX_SHADER);
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
const char *data = vertexShadersSource.c_str();
glShaderSource(vertexShader, 1, &data, (GLint*)vertexShadersSource.size());
data = fragmentShadersSource.c_str();
glShaderSource(fragmentShader, 1, &data, (GLint*)fragmentShadersSource.size());
EDIT:
Although I think the shader is correct, here you can see the shader code
VertexShader:
#version 150
// in_Position was bound to attribute index 0 and in_Color was bound to attribute index 1
//in vec2 in_Position;
//in vec3 in_Color;
// We output the ex_Color variable to the next shader in the chain
out vec3 ex_Color;
void main(void) {
// Since we are using flat lines, our input only had two points: x and y.
// Set the Z coordinate to 0 and W coordinate to 1
//gl_Position = vec4(in_Position.x, in_Position.y, 0.0, 1.0);
// GLSL allows shorthand use of vectors too, the following is also valid:
// gl_Position = vec4(in_Position, 0.0, 1.0);
// We're simply passing the color through unmodified
ex_Color = vec3(1.0, 1.0, 0.0);
}
FragmentShader:
#version 150
// It was expressed that some drivers required this next line to function properly
precision highp float;
in vec3 ex_Color;
out vec4 gl_FragColor;
void main(void) {
// Pass through our original color with full opacity.
gl_FragColor = vec4(ex_Color,1.0);
}
Your call is wrong:
glShaderSource(vertexShader, 1, &data, (GLint*)vertexShadersSource.size());
and the type cast from a size_t to a pointer type should have raised some red flags while you wrote it.
glShaderSource() expects a pointer to an array of string lenghts - one element per separate string. Since you only use 1 string, it will try to access lenght[0]. This means it treats your string size as an address, and that address is very likely to not belong to your process.
Since you already use 0-terminated C-Strings, you can simply use NULL as the length parameter. Or, if you absolutely want to use it, you have to just pass a pointer to an GLint:
GLint len=vertexShadersSource.size();
glShaderSource(..., 1, ..., &len);
Related
I have a very basic engine based on OpenGL that can render polygons in any color to a resizeable window. I'm now trying to implement matrices for my shaders by giving the model, perspective and view matrices as uniforms via my shader. Before adding the uniforms everything worked as it should, I could even pass in a uniform vec2 to simulate a light source at my mouse position. The uniform mat4s doesn't work as well as the vec2s.
For debugging purposes I'm only rendering one yellow square centered on the screen. When using no uniforms the square shows as expected. i now try passing in one mat4, set as an identity matrix. In the vertex shader I'm multiplying gl_Position by the identity matrix I uniformed. When I run the program it only shows a black window.
I've tried manually creating an identity matrix in the vertex shader and multiplying gl_Position by that matrix instead of the uniform one. When I do that my yellow square shows as normal. This leads me to believe that the uniform mat4 doesn't get the correct values, however, I don't know how to check the values of the matrix when it's being used in the shader.
This is how my vertex shader looks:
#version 430 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec4 color;
out vec4 Color;
uniform mat4 model;
uniform mat4 view;
uniform mat4 project;
void main()
{
mat4 id;
id[0] = vec4(1.0, 0.0, 0.0, 0.0);
id[1] = vec4(0.0, 1.0, 0.0, 0.0);
id[2] = vec4(0.0, 0.0, 1.0, 0.0);
id[3] = vec4(0.0, 0.0, 0.0, 1.0);
Color = color;
gl_Position = id * vec4(position, 1.0);
}
The mat4 id is the manually created identity matrix, when changing id * to model * I get the black window.
This is how my fragment shader looks:
#version 430 core
in vec4 Color;
out vec4 outColor;
void main()
{
outColor = Color;
}
The shader is initialized by this code:
m_shaderID = glCreateProgram();
const char* vertexSource = ReadFile::readFile(vertpath);
const char* fragmentSource = ReadFile::readFile(fragpath);
GLint status;
// Vertex Shader
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexSource, NULL);
glCompileShader(vertexShader);
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &status);
if (status != GL_TRUE)
{
std::cout << "Failed to compile vertex shader!\nInfo log: " << std::endl;
char buffer[512];
glGetShaderInfoLog(vertexShader, 512, NULL, buffer);
std::cout << buffer << std::endl;
glDeleteShader(vertexShader);
}
// Fragment Shader
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentSource, NULL);
glCompileShader(fragmentShader);
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &status);
if (status != GL_TRUE)
{
std::cout << "Failed to compile fragment shader!\nInfo log: " << std::endl;
char buffer[512];
glGetShaderInfoLog(fragmentShader, 512, NULL, buffer);
std::cout << buffer << std::endl;
glDeleteShader(fragmentShader);
}
// Shader program
glAttachShader(m_shaderID, vertexShader);
glAttachShader(m_shaderID, fragmentShader);
glLinkProgram(m_shaderID);
glValidateProgram(m_shaderID);
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
The matrix is created as a uniform by this code:
void Shader::setUniformmat4(const GLchar* name, glm::mat4 matrix)
{
for (int i = 0; i <= 3; i++)
printf("%f, %f, %f, %f\n", matrix[i].x, matrix[i].y, matrix[i].z, matrix[i].w);
glUniformMatrix4fv(glGetUniformLocation(m_shaderID, name), 1, GL_FALSE, glm::value_ptr(matrix));
}
The printf is for checking the values of the matrix as they are used to create the uniform, and they have the values of an identity matrix at that point.
The function setUniformmat4 is called by this code:
glm::mat4 model = glm::mat4(1.0);
shader.setUniformmat4("model", model);
When creating a lighting effect I create the uniform by calling this function:
void Shader::setUniformvec2(const GLchar* name, glm::vec2 vector)
{
glUniform2f(glGetUniformLocation(m_shaderID, name), vector.x, vector.y);
}
via this piece of code:
shader.setUniformvec2("light_pos", glm::vec2((x / window.getWidth()) * 2.0 - 1.0, 1.0 - 2.0 * (y / window.getHeight())));
Where x and y are the mouses coordinates. I then add the line
uniform vec2 light_pos;
To the fragment shader. This works no problem, and it traces the mouse perfectly. The function used for setting the uniform mat4 looks the same as the function for setting the uniform vec2, only difference is the 4fv for the mat4 and 2f for the vec2.
As you can see, I'm using glm for the matrices and vectors.
My main function looks like this:
Window window(720, 720, "Window");
Shader shader("shader.vert", "shader.frag");
glm::mat4 model = glm::mat4(1.0);
shader.setUniformmat4("model", model);
Renderer* renderer = new Renderer();
std::vector<StaticSprite*> sprites;
sprites.push_back(new StaticSprite(-0.5, -0.5, 0.0, 1.0, 1.0, glm::vec4(1.0, 1.0, 0.0, 1.0), &shader));
while (!window.closed())
{
window.clear();
shader.enable();
double x, y;
window.getMousePosition(x, y);
shader.setUniformvec2("light_pos", glm::vec2((x / window.getWidth()) * 2.0 - 1.0, 1.0 - 2.0 * (y / window.getHeight())));
for (StaticSprite* sprite : sprites)
renderer->submit(sprite);
renderer->flush();
shader.disable();
window.update();
}
return 0;
My question summarized is basically why are the values of the uniform mat4 not correct, is there any way to find out what those values are, and what should I change in the code to make the uniform mat4s work?
Please ask for any additional information needed to give an answer, I will happily provide anything I forgot to include.
glUniform* specify the value of a uniform variable for the current program object. This means the program has to be installed by glUseProgram before:
Shader shader("shader.vert", "shader.frag");
shader.enable(); // <--- this is missing
glm::mat4 model = glm::mat4(1.0);
shader.setUniformmat4("model", model);
Active program resources can be get from a program object which is not the "current" program (e.g. glGetUniformLocation). Note, the program object is a parameter of glGetUniformLocation.
But to set the value of a uniform by glUniform*, the program has to be the currently installed program.
The chunk of code below works correctly as-is. But if I uncomment the call to glGetUniformLocation() it crashes at that line:
GLint pipeline;
glGenProgramPipelines(1, &pipeline);
glUseProgram(0);
glBindProgramPipeline(pipeline);
GLint vert_pgm = glCreateShaderProgramv(...);
glUseProgramStages(pipeline, GL_VERTEX_SHADER_BIT, vert_pgm);
GLint frag_pgm = glCreateShaderProgramv(...);
glUseProgramStages(pipeline, GL_FRAGMENT_SHADER_BIT, frag_pgm);
// If I uncomment the line below, it crashes:
//
// GLint myArg_loc = glGetUniformLocation(frag_pgm, "material_id");
glBindBufferBase(GL_UNIFORM_BUFFER, ubo_index, mp_data->ubo);
glBindVertexArray(vao);
glEnableVertexAttribArray(0)
...
glEnableVertexAttribArray(10)
glBindVertexBuffer(...);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ...);
glDrawElements(GL_TRIANGLES, ...);
The inputs for the fragment shader are declared as follows:
layout( binding = 0, std140, column_major )
uniform uniform_data
{
transform_data transform;
material_data material;
lighting_data lighting;
vec4 select;
vec4 normal;
}
uniforms;
uniform int material_id;
in attribute_data
{
smooth vec4 pos;
smooth vec4 colour;
smooth float radius;
smooth vec3 tangent;
smooth vec3 normal;
flat int face_id;
}
inputs;
Any ideas why it's crashing?
Is it not legal to use interface blocks and individual uniforms together in the same shader?
Check for: NULL pointer AND recursion.
My wrapper function for glGetUniformLocation was calling itself rather
than the function pointer it was supposed to wrap. Ironically the wrapper function is there for my protection. It checks to make sure the function pointer isn't null and throws an error if it is.
typedef
GLint
(*PFN_glGetUniformLocation)
(
/**/ GLuint program
, const GLchar* name
);
PFN_glGetUniformLocation
pfn_glGetUniformLocation;
GLint
glGetUniformLocation
(
/**/ GLuint program
, const GLchar* name
){
//! My Mistake: !//
//! Exists(glGetUniformLocation);!//
//! return(glGetUniformLocation( !//
//! program, name !//
//! ));; !//
//:My Fix:
Exists(pfn_glGetUniformLocation);
return(pfn_glGetUniformLocation(
program, name
));;
}
"Exists" throws an error if the function pointer is NULL.
"pfn" is a prefix for "Pointer to a FuNction"
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 am using openGL 3.1 and programming with QGLfunctions. I cannot pass in the uniform vec4 mycolor to the fragment shader I have initialized my program using:
m_program = new QOpenGLShaderProgram(this);
m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShaderSource);
m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShaderSource);
m_program->link();
m_posAttr = m_program->attributeLocation("posAttr");
m_mycolor = m_program->uniformLocation("mycolor");
m_matrixUniform = m_program->uniformLocation("matrix");
and then I try to send color
GLfloat color[] = {
0.0f, 1.0f, 0.0f, 1.0f };
glUniform4fv(m_mycolor, 4, color);
to my fragment shader which is:
static const char *fragmentShaderSource =
"uniform vec4 mycolor;\n"
"void main() {\n"
" gl_FragColor = mycolor;\n"
"}\n";
and I get nothing displayed
glUniform4fv(m_mycolor, 4, color);
From the glUniform documentation about the count parameter:
Specifies the number of elements that are to be modified. This should
be 1 if the targeted uniform variable is not an array, and 1 or more
if it is an array.
The count parameter in your case should be 1 since your color[] array still only represents one vec4 entry.
you are trying to fill a uniform vec4 color[4] array.
The correct version :
glUniform4fv(m_mycolor, 1, color);
As #Bahbar also pointed out : "GL_INVALID_OPERATION is generated if count is greater than 1 and the indicated uniform variable is not an array variable." So.. check your GL errors!
I am trying to add lighting to my current scene of a simple cube. After setting up my uniforms I get a 1282 error from glGetError() for this piece of code
GLuint ambientHandle = glGetUniformLocation(program->getHandle(), "ambientProduct");
glUniform4fv( ambientHandle, 1, ambientProduct );
GLuint diffuseHandle = glGetUniformLocation(program->getHandle(), "diffuseProduct");
glUniform4fv( diffuseHandle, 1, diffuseProduct );
GLuint specularHandle = glGetUniformLocation(program->getHandle(), "specularProduct");
glUniform4fv( specularHandle, 1, specularProduct );
GLuint lightPosHandle = glGetUniformLocation(program->getHandle(), "lightPosition");
glUniform4fv( lightPosHandle, 1, light.position );
GLuint shinyHandle = glGetUniformLocation(program->getHandle(), "shininess");
glUniform1f( shinyHandle, materialShininess );
Here are my shaders:
vertex.glsl
#version 120
attribute vec4 coord3d;
attribute vec3 normal3d;
// output values that will be interpretated per-fragment
varying vec3 fN;
varying vec3 fE;
varying vec3 fL;
uniform vec4 lightPosition;
uniform mat4 mTransform;
void main()
{
fN = normal3d;
fE = coord3d.xyz;
fL = lightPosition.xyz;
if( lightPosition.w != 0.0 ) {
fL = lightPosition.xyz - coord3d.xyz;
}
gl_Position = mTransform*coord3d;
}
fragment.glsl
// per-fragment interpolated values from the vertex shader
varying vec3 fN;
varying vec3 fL;
varying vec3 fE;
uniform vec4 ambientProduct, diffuseProduct, specularProduct;
uniform mat4 mTransform;
uniform vec4 lightPosition;
uniform float shininess;
void main()
{
// Normalize the input lighting vectors
vec3 N = normalize(fN);
vec3 E = normalize(fE);
vec3 L = normalize(fL);
vec3 H = normalize( L + E );
vec4 ambient = ambientProduct;
float Kd = max(dot(L, N), 0.0);
vec4 diffuse = Kd*diffuseProduct;
float Ks = pow(max(dot(N, H), 0.0), shininess);
vec4 specular = Ks*specularProduct;
// discard the specular highlight if the light's behind the vertex
if( dot(L, N) < 0.0 ) {
specular = vec4(0.0, 0.0, 0.0, 1.0);
}
gl_FragColor = ambient + diffuse + specular;
gl_FragColor.a = 1.0;
}
The products and position are each a struct of three GLfloats and shininess is a float. I have checked all of the values of the handles and the values I am passing and they all seem valid. Ideas?
--EDIT:
I have narrowed it to the glUniform4fv calls. It happens after each one. Also I have double checked that the program->getHandle() is pointing to something that looks valid.
I have checked program->getHandle is a valid program
Here are the values of all handles:
Program handle 3
ambientHandle 0
diffuseHandle 1
specularHandle 5
lightPosHandle 2
shinyHandle 4
So they all look good. For testing I am commenting out the lines below the ones for ambientProduct. For clarity I am explicitly using this line instead
glUniform4f( ambientHandle, ambientProd.x, ambientProd.y, ambientProd.z, ambientProd.w );
These are the values for ambientProd at the time that line is executed.
x = 0.200000003, y = 0.0, z = 0.200000003, w = 1.0
A collaborator on this project moved the call for glUseProgram. Thanks for the help folks.
Error number ยด1282` is not very descriptive.
Possible error codes for glGetUniformLocation are:
GL_INVALID_VALUE
GL_INVALID_OPERATION
Which don't have a fixed value. Try to get the error string with gluErrorString() or take a look in the header to which of those 1282 maps.
Just a shot in the dark: but did you ...
check your shader got compiled without error?
check your shader got linked without error?
BTW: return type is GLint not GLuint
"Shaders compiled and linked without error" Hmm, this looks odd.
According to spec (see: http://www.opengl.org/sdk/docs/man/xhtml/glGetUniformLocation.xml) GL_INVALID_OPERATION should only be generated if:
program is not a program objec
program has not been successfully linked
Other question:
are you sure the getHandle()method of the class your program Object belongs to returns the right id. I mean the one that was used in the sucessfully linking.
you should be able to verify with checking if glIsProgram(program-getHandle()) returns GL_TRUE
EDIT: Ah - I missed those calls to glUniform4fv in your example.
Correct return type for glGetUniformLocation is still GLint, but I don't think thats the problem.
According to spec (see: http://www.opengl.org/sdk/docs/man/xhtml/glUniform.xml) GLUniformXX generates GL_INVALID_OPERATION for a whole bunch of reasons. To me the only one that possibly seems to apply is:
there is no current program object
Did you call glUseProgram (program->getHandle()) prior to trying to calling glUniform()?
Generally this error number occurs when you are using a different programID from the programID generated by openGL at the time of creating the shader. It means that you are using a different programID at the time of binding vertexShader or fragmentShader or whatever other shader you are using.