C and GLSL vec3 Position and Color Problem

Started by
12 comments, last by mojobojo 8 years, 9 months ago

So in my render loop I am trying to draw a GL_POINT with a color. I have a shader that it runs through for matrix transformations. For some reason I can set the color, set the position, but not both. When I set the color the positions gl_Position gets messed up for some reason. I am sure this boils down to me not knowing much about GLSL. If somebody could help that would be great.

C code


internal void
Render(game_memory *Memory)
{
    game_state *GameState = (game_state *)Memory->PermanentStorage;

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glm::mat4 Model = glm::mat4(1.0f);
    glm::mat4 Projection = glm::ortho(0.0f, 1280.0f, 720.0f, 0.0f, 0.0f, 1.0f);

    GLint ModelUniform = glGetUniformLocation(GameState->ShaderProgram, "Model");
    Assert(ModelUniform != -1);
    glUniformMatrix4fv(ModelUniform, 1, GL_FALSE, glm::value_ptr(Model));

    GLint ProjectionUniform = glGetUniformLocation(GameState->ShaderProgram, "Projection");
    Assert(ProjectionUniform != -1);
    glUniformMatrix4fv(ProjectionUniform, 1, GL_FALSE, glm::value_ptr(Projection));

    r32 SinOfTime = sinf(GameState->ElapsedTime);
    r32 CosOfTime = cosf(GameState->ElapsedTime);

    v2 Location;
    Location.x = 500.0f + 100.0f * SinOfTime;
    Location.y = 500.0f + 100.0f * CosOfTime;

    glDisable(GL_TEXTURE_2D);
    glPointSize(10.0f);
    glBegin(GL_POINTS);
    glColor3f(fabs(SinOfTime), 0.0f, 0.0f);
    glVertex3f(Location.x, Location.y, 0.0f);
    glEnd();
    glEnable(GL_TEXTURE_2D);

    SDL_GL_SwapWindow(GameState->SdlWindow);
}

Additional code that sets the position attribute so I can use it.


    GLint PosAttrib = glGetAttribLocation(GameState->ShaderProgram, "position");
    glEnableVertexAttribArray(PosAttrib);
    glVertexAttribPointer(PosAttrib, 3, GL_FLOAT, GL_FALSE, 0, 0);

Fragment Shader


#version 130

in vec4 Color;

void main(void)
{
    gl_FragColor = Color;
}

Vertex Shader


#version 130

in vec3 position;
out vec4 Color;
uniform mat4 Model;
uniform mat4 Projection;

void main(void)
{
    Color = gl_Color; // If I comment this line out and not set the color the
                      // position sets fine. If its like this, color changes
                      // but the position sticks in the top left corner of 
                      // the screen.
    gl_Position = Projection * Model * vec4(position, 1.0);
}

Advertisement
You are mixing so many GL versions it's a little hard to track what all could be going wrong.

I'd advise explicitly declaring a colour attribute, rather than relying on the built-in gl_Color input - not all drivers properly support mixing and matching between generic and built-in attributes.

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

You are mixing so many GL versions it's a little hard to track what all could be going wrong.

I'd advise explicitly declaring a colour attribute, rather than relying on the built-in gl_Color input - not all drivers properly support mixing and matching between generic and built-in attributes.

Because of the lack of up to date or concise guides out there I guess its no surprise my code looks like mixed GL versions. It would be nice to know what I am mixing and why its wrong. And I did as well try defining a color attribute with the same result.

It would be nice to know what I am mixing and why its wrong.

It's not wrong, per se - unless you explicitly tell OpenGL that you want a Core/ForwardCompatible context, you can freely mix versions. It is however confusing to the reader smile.png

Typically, one doesn't mix built-in attributes with generic attributes (i.e. use gl_Vertex and gl_Color, or provide both as generic attributes), nor mix shaders with immediate mode (glBegin/glEnd - prefer glDrawArrays/glDrawElements and vertex buffers).

In this case, I think the issue is that you are both providing a position through glVertexAttribPointer(), and via glVertex(). Or, in other words, you are providing 3 peices of vertex data (glVertexAttribPointer, glVertex, glColor), and only consuming 2.

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

In this case, I think the issue is that you are both providing a position through glVertexAttribPointer(), and via glVertex(). Or, in other words, you are providing 3 peices of vertex data (glVertexAttribPointer, glVertex, glColor), and only consuming 2.

I seem to have a misunderstanding as to how glColor and glVertex get passed into the shader perhaps. I thought I had to use glVertexAttribPointer to specify what I wanted to get passed to the shader.

EDIT:

Okay so I am starting to understand whats going on here. I got it working by removing the position input and doing. So if I understand correctly glVertex goes into gl_Vertex just as glColor goes into gl_Color?


void main(void)
{
    Color = gl_Color;
    gl_Position = Projection * Model * gl_Vertex;
}

What version of OpenGL do you want to use?

Okay so I am starting to understand whats going on here. I got it working by removing the position input and doing. So if I understand correctly glVertex goes into gl_Vertex just as glColor goes into gl_Color?

Yes. That is the legacy mechanism for defining vertex data.

These days, one would specify both position and colour as explicit attributes in the shader, store the actual data for each one in a vertex buffer, bind each one with glVertexAttribPointer, and draw them using glDrawArrays.

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

What version of OpenGL do you want to use?

I am thinking 3.1. It is what I am telling SDL to initialize to and it seems like its what most people have. Is there any good reason to target 4.x? I don't have a set in stone target version simply because I am just exploring right now but I am open to suggestions. For right now I just want my own little sandbox where I can play around with 2D graphics using modern OpenGL and GLSL.

I am looking into drawing the points another way right now. Its not working but I think I am on the right track perhaps.

In the render loop


internal void
Render(game_memory *Memory)
{
    game_state *GameState = (game_state *)Memory->PermanentStorage;

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glm::mat4 Model = glm::mat4(1.0f);
    glm::mat4 Projection = glm::ortho(0.0f, 1280.0f, 720.0f, 0.0f, 0.0f, 1.0f);


    GLint ModelUniform = glGetUniformLocation(GameState->ShaderProgram, "Model");
    Assert(ModelUniform != -1);
    glUniformMatrix4fv(ModelUniform, 1, GL_FALSE, glm::value_ptr(Model));

    GLint ProjectionUniform = glGetUniformLocation(GameState->ShaderProgram, "Projection");
    Assert(ProjectionUniform != -1);
    glUniformMatrix4fv(ProjectionUniform, 1, GL_FALSE, glm::value_ptr(Projection));

    // I am perfectly aware allocating and unallocating new arrays each frame is slow
    // This is just test code so I can get an idea of what I am doing.
    GLuint VertexArrayObject;
    glGenVertexArrays(1, &VertexArrayObject);
    glBindVertexArray(VertexArrayObject);

    GLuint VertexBufferObject;
    glGenBuffers(1, &VertexBufferObject);

    GLfloat Point[] = 
    {
    //  Position        | Color
        0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f
    };

    glBindBuffer(GL_ARRAY_BUFFER, VertexBufferObject);
    glBufferData(GL_ARRAY_BUFFER, sizeof(Point), Point, GL_STATIC_DRAW);

    GLuint ElementBufferObject;
    glGenBuffers(1, &ElementBufferObject);

    GLuint Elements[] = 
    {
        0
    };

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ElementBufferObject);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Elements), Elements, GL_STATIC_DRAW);

    glDrawElements(GL_POINTS, 1, GL_UNSIGNED_INT, 0);
    
    glDeleteBuffers(1, &VertexBufferObject);
    glDeleteBuffers(1, &ElementBufferObject);
    glDeleteVertexArrays(1, &VertexArrayObject);

    SDL_GL_SwapWindow(GameState->SdlWindow);
}

Code for setting the vertex properties


    // Before here is where I compile the shaders
    GLint PosAttrib = glGetAttribLocation(GameState->ShaderProgram, "position");
    glEnableVertexAttribArray(PosAttrib);
    glVertexAttribPointer(PosAttrib, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), 0);

    GLint ColAttrib = glGetAttribLocation(GameState->ShaderProgram, "color");
    glEnableVertexAttribArray(ColAttrib);
    glVertexAttribPointer(ColAttrib , 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (void *)(3 * sizeof(GLfloat)));
    // After here is where I enter the game loop

Fragment Shader


#version 150

in vec4 Color;

void main(void)
{
    gl_FragColor = Color;
}

Vertex Shader


#version 150

in vec3 color;
in vec3 position;
out vec4 Color;
uniform mat4 Model;
uniform mat4 Projection;

void main(void)
{
    Color = vec4(color, 1.0f);
    gl_Position = Projection * Model * vec4(position, 1.0);
}

You need to call glVertexAttribPointer while the buffer is bound (i.e. right after glBindBuffer).

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

You need to call glVertexAttribPointer while the buffer is bound (i.e. right after glBindBuffer).

Ah, I see, thanks. That makes sense. Moved it right after the binds however still not drawing.

EDIT:
Silly me, I needed to set the point size tongue.png

glPointSize(10.0f);

This topic is closed to new replies.

Advertisement