0
votes

So I am trying to move to a more modern, shader-based rendering system in OpenGL, and part of that, as I understand, is performing the projections that used to be accomplished with the built-in matrix stack in older OpenGL by instead feeding my own matrices to a shader. Here is my shader (Apologies, for some reason I can't get whitespace to appear in code formatting):

//Vertex

attribute vec3 coord3d;
attribute vec3 v_color;
varying vec3 f_color;
uniform mat4 projection;
uniform mat4 model;
uniform mat4 view;

void main(void) 
{
        gl_Position = projection * view * model * vec4(coord3d, 1.0);
        f_color = v_color;
}

//Fragment

varying vec3 f_color;

void main(void) 
{
    gl_FragColor = vec4(f_color.x, f_color.y, f_color.z, 1.0);
}

I've been having some problems, though, in that multiplication by projection and/or view matrices makes my test object disappear. If I change the shader to this:

gl_Position = model * vec4(coord3d, 1.0);

The object appears as expected on-screen, flat and positioned relative to the [-1, 1] space of the screen. Let's go through this step by step.

I have three relevant classes, let's call them Scene, Object and Camera. In Scene's constructor, these GLuints are set:

//Model - must be changed for each model
Object::ModelUniform = glGetUniformLocation(ObjectShader, "model");

//View - must be changed once per frame
m_ViewUniform = glGetUniformLocation(ObjectShader, "view");

//Projection - must only be set once    
m_ProjectionUniform = glGetUniformLocation(ObjectShader, "projection");
glm::mat4 projection = glm::perspective(60.0f, 1.33f, 0.1f, 512.f);
glUniformMatrix4fv(m_ProjectionUniform, 1, GL_FALSE, glm::value_ptr(projection));

Then, once per frame (still in Scene; I have other objects in the background running on old shaders+glMultMatrixf() code, but I don't think there's any interaction between the two):

glm::vec3 Eye = glm::vec3(CameraPos.x, CameraPos.y, CameraPosz);

glm::vec3 Center = glm::vec3(ObjectPos.x, ObjectPos.y, ObjectPosz);

glm::vec3 Up = glm::vec3(0.0, 1.0, 0.0);

glm::mat4 view = glm::lookAt(Eye, Center, Up);
glUniformMatrix4fv(m_ViewUniform, 1, GL_FALSE, glm::value_ptr(view));
glUseProgram(ObjectShader);
Object->Cycle();

Then, in Object::Cycle():

glm::mat4 model = glm::translate(glm::mat4(1.0f), glm::vec3(Position.x, Position.y, Position.z));
glUniformMatrix4fv(Object::ModelUniform, 1, GL_FALSE, glm::value_ptr(model));
glEnableVertexAttribArray(CoordinateAttribute);
glBindBuffer(GL_ARRAY_BUFFER, m_VertexBuffer);
glVertexAttribPointer(CoordinateAttribute, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), 0);

glEnableVertexAttribArray(ColorAttribute);
glBindBuffer(GL_ARRAY_BUFFER, m_VertexBuffer);
glVertexAttribPointer(ColorAttribute, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*) (3 * sizeof(GLfloat)));

glDrawArrays(GL_TRIANGLES, 0, 6);

glDisableVertexAttribArray(ColorAttribute);
glDisableVertexAttribArray(CoordinateAttribute);

glDisable(GL_BLEND);

glBindBuffer(GL_ARRAY_BUFFER, 0);

All of the matrices I use work fine in old OpenGL using deprecated functions like glMultMatrixf().

As mentionned above, using only the model matrix works fine. Rotating the camera around doesn't locate the missing object.

What could be the problem here?

2
You should take a look at this: stackoverflow.com/questions/4202456/… (it clarifies when you may and may not use the built-in gl_ModelViewProjectionMatrix, etc. directly inside your glsl shader code) - Rahul Banerjee
Hm, I am aiming for OpenGL 3.3+, so GLSL 3.3+ as well. I'm not using the deprecated gl_ModelViewProjectionMatrix, but I assume you are referring to gl_Position, which is also deprecated? Should I instead simply use an out vec4? This doesn't seem to work either. - GarrickW
glEnableClientState is deprecated. - Bartek Banachewicz
Oh my god it's such a TLDR; What about SSCCE? - Bartek Banachewicz

2 Answers

4
votes

Here:

glUniformMatrix4fv(m_ProjectionUniform, 1, GL_FALSE, glm::value_ptr(projection));

and here

glm::mat4 view = glm::lookAt(Eye, Center, Up);
glUniformMatrix4fv(m_ViewUniform, 1, GL_FALSE, glm::value_ptr(view));
glUseProgram(ObjectShader);
Object->Cycle();

You are setting the view but you activate the shader after you do that. Maybe you have the same problem with the projection matrix, but I can't tell from your code. The shader needs to be active to set uniforms on it. You possibly just have no shader bound while you are setting those. On the other hand, just from the bits you posted, the shader could be active at all times, so this would work after the first frame. It's impossible to tell tho.

1
votes

Try this:

uniform mat4 ModelView;
uniform mat4 ProjectionView;

in vec4 position;

void main()
{
    gl_Position = ProjectionView * ModelView * position ;
}

Matrix Multiplication goes from right to left in OpenGL.