0

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?

GarrickW
  • 2,181
  • 5
  • 31
  • 38
  • You should take a look at this: http://stackoverflow.com/questions/4202456/how-do-you-get-the-modelview-and-projection-matrices-in-opengl (it clarifies when you may and may not use the built-in gl_ModelViewProjectionMatrix, etc. directly inside your glsl shader code) – Rahul Banerjee Mar 02 '13 at 14:06
  • 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 Mar 02 '13 at 14:13
  • `glEnableClientState` is deprecated. – Bartek Banachewicz Mar 04 '13 at 20:19
  • 1
    Oh my god it's such a TLDR; What about SSCCE? – Bartek Banachewicz Mar 06 '13 at 15:55

2 Answers2

4

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.

ltjax
  • 15,837
  • 3
  • 39
  • 62
  • This is it!! Thank you! I never knew that! I thought you could just set uniforms willy-nilly. – GarrickW Mar 06 '13 at 16:51
  • 1
    You're welcome. Unfortunately, you made so many edits to your original question, that this turned into a community wiki and I don't get any imaginary internet points ;-) Either way, the fact that the glUniform* calls do not take the program as a parameter (as opposed to the glGetUniformLocation calls) serves as a hint that it needs programs to be bound. Yes, this is a very bad aspect about OpenGL.. – ltjax Mar 07 '13 at 10:52
1

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.

dimmak111
  • 21
  • 4
  • Unfortunately, that doesn't seem to help - there is still nothing visible onscreen. – GarrickW Mar 02 '13 at 14:46
  • Then, it certainly doesn't come from here, maybe your VBO/Shader init or Rendering. – dimmak111 Mar 02 '13 at 14:50
  • Well, I do have an old setup that works fine with a shader that uses deprecated functions - I've added the code for that above. – GarrickW Mar 02 '13 at 15:03
  • Well, glEnableClientState is how you tell OpenGL to use fixed-function attribute (gl_Vertex, gl_Color) but thoses are removed from Core Profil. You should instead use glEnableVertexAttribArray and specify your position array or use attribute location look this [link](http://en.wikibooks.org/wiki/OpenGL_Programming) – dimmak111 Mar 02 '13 at 15:09
  • I've updated my code to reflect the approach in the Wikibook, and everything works fine until comes time to multiply the projection, view and model matrices. If I perform the multiplication, the object disappears. Multiplying by the model matrix alone works fine, and I can rotate and translate things (in screen-space) without issue. Adding either projection or view matrices makes the object go away. – GarrickW Mar 04 '13 at 20:03
  • Then either of these matrices is bad. – Bartek Banachewicz Mar 04 '13 at 20:18
  • I have implemented GLM, and that doesn't help. In fact, comparing my matrices to GLM's matrices shows that they are practically identical. – GarrickW Mar 06 '13 at 14:50