# How do I pass vertex and color positions to OpenGL shaders?

I've been trying to get this to work for the past two days, telling myself I wouldn't ask for help. I think you can see where that got me...

I thought I'd try my hand at a little OpenGL, because DirectX is complex and depressing. I picked OpenGL 3.x, because even with my OpenGL 4 graphics card, all my friends don't have that, and I like to let them use my programs. There aren't really any great tutorials for OpenGL 3, most are just "type this and this will happen--the end".

I'm trying to just draw a simple triangle, and so far, all I have is a blank screen with my clear color (when I set the draw type to GL_POINTS I just get a black dot). I have no idea what the problem is, so I'll just slap down the code:

Here is the function that creates the triangle:

void CEntityRenderable::CreateBuffers()
{
m_vertices = new Vertex3D[3];
m_vertexCount = 3;

m_vertices[0].x = -1.0f;
m_vertices[0].y = -1.0f;
m_vertices[0].z =  0.0f;
m_vertices[0].r = 1.0f;
m_vertices[0].g = 0.0f;
m_vertices[0].b = 0.0f;
m_vertices[0].a = 1.0f;

m_vertices[1].x =  1.0f;
m_vertices[1].y = -1.0f;
m_vertices[1].z =  0.0f;
m_vertices[1].r = 1.0f;
m_vertices[1].g = 0.0f;
m_vertices[1].b = 0.0f;
m_vertices[1].a = 1.0f;

m_vertices[2].x =  0.0f;
m_vertices[2].y =  1.0f;
m_vertices[2].z =  0.0f;
m_vertices[2].r = 1.0f;
m_vertices[2].g = 0.0f;
m_vertices[2].b = 0.0f;
m_vertices[2].a = 1.0f;

//Create the VAO
glGenVertexArrays(1, &m_vaoID);
//Bind the VAO
glBindVertexArray(m_vaoID);

//Create a vertex buffer
glGenBuffers(1, &m_vboID);
//Bind the buffer
glBindBuffer(GL_ARRAY_BUFFER, m_vboID);
//Set the buffers data
glBufferData(GL_ARRAY_BUFFER, sizeof(m_vertices), m_vertices, GL_STATIC_DRAW);
//Set its usage
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex3D), 0);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex3D), (void*)(3*sizeof(float)));

//Enable
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
//Check for errors
if(glGetError() != GL_NO_ERROR)
{
Error("Failed to create VBO: %s", gluErrorString(glGetError()));
}
//Unbind...
glBindVertexArray(0);
}


The Vertex3D struct is as such...

struct Vertex3D
{
Vertex3D() : x(0), y(0), z(0), r(0), g(0), b(0), a(1) {}

float x, y, z;
float r, g, b, a;
};


And finally the render function:

void CEntityRenderable::RenderEntity()
{
//Render...
glBindVertexArray(m_vaoID);
//Use our attribs

glDrawArrays(GL_POINTS, 0, m_vertexCount);

glBindVertexArray(0); //unbind
OnRender();
}


(And yes, I am binding and unbinding the shader. That is just in a different place) I think my problem is that I haven't fully wrapped my mind around this whole VertexAttribArray thing (the only thing I like better in DirectX was input layouts D:).

#version 330

//Matrices
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform mat4 modelMatrix;
//In values
layout(location = 0) in vec3 position;
layout(location = 1) in vec4 color;
//Out values
out vec4 frag_color;
void main(void)
{
//Position in world
gl_Position = vec4(position, 1.0);
//gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(in_Position, 1.0);
//No color changes
frag_color = color;
}


#version 330
//In values
in vec4 frag_color;
//Out values
out vec4 out_color;
void main(void)
{
out_color = frag_color;
}


As you can see, I've disable the matrices, because that just makes debugging this thing so much harder. I tried to debug using glslDevil, but my program just crashes right before the shaders are created... so I gave up with that. This is my first shot at OpenGL since the good old days of LWJGL, but that was when I didn't even know what a shader was. Thanks for your help :)

I'd also like to add this, I only saw it in one tutorial:

m_defaultShader->BindAttrib(0, "position");


BindAttrib looks like this:

void IShader::BindAttrib(int index, char* name)
{
}


I thought maybe that may be an issue

• Try openglbook.com or google gltut. OpenGL has crap community documentation, but those are both reall good. GL Book has only published a few chapters so far, but enough to get you past this sticking point. – Sean Middleditch Apr 15 '12 at 0:07
• @seanmiddleditch I've read most of openglbook.com and various other tutorials on OpenGL. Almost all of them have the same code, and as far as I can tell, so do I. This is why I am so confused. There is probably one little thing I have been overlooking. – smoth190 Apr 15 '12 at 0:10
• You appear to be doing everything by the book. I suggest trying to hardcode a color value in the shader. Can you show your fragment shader, too? – sam hocevar Apr 15 '12 at 0:16
• Try running in gDebugger, too. It might find the error for you. It's a little wonky and buggy for core profile stuff (I always get errors under gDebugger in calls to LinkProgram that the actual API never throws), but it gets the job done. Also, check your matrix math. You may just have the camera looking off in lala-land (or just be totally bogus). – Sean Middleditch Apr 15 '12 at 1:44
• The two things I would try are setting the normalized boolean in your second glVertexAttribPointer call to GL_FALSE, and also making your color input variable in your shader a vec4 value rather than a vec3 (since you're passing 4 values for each one). Try those then update us on what happened. – kevintodisco Apr 15 '12 at 2:05

### Nitpicks

Things that aren't actually your problem but you should correct anyway.

First, Vertex3D is not a POD, by the C++03 rules defining POD structs. As such, C++03 offers no guarantees of the layout of such a struct, so you can't just shove it into OpenGL.

Now, that being said, your struct will likely work. Most compilers will provide the expected layout for this struct. And C++11 extends the rules of layout such that this struct is guaranteed to have the expected layout.

Next, m_vertices = new Vertex3D[3];. I don't see a delete[] anywhere. Now yes, m_vertices is likely a member variable, but there's no reason to keep this array around. What happens if someone calls CreateBuffers twice?

Indeed, there's no reason to use a naked array at all. Use a std::vector<Vertex3D> instead. That way, it'll be properly scoped and everything; you won't have to worry about when it goes away.

Next:

glVertexAttribPointer(1, 4, GL_FLOAT, GL_TRUE,  sizeof(Vertex3D), (void*)(3*sizeof(float)));


There is no such thing as a normalized float. Normalization specifies how integer values are interpreted as floats. The byte value 255, when interpreted as a normalized unsigned byte, will become 1.0f. When interpreted as a non-normalized unsigned byte, it will be 255.0f.

This won't actually cause an error; it'll just be ignored because it makes no sense. But you still shouldn't do it.

### Actual Problems

Things that are actual problems, but may not be your real problem.

glBufferData(GL_ARRAY_BUFFER, sizeof(m_vertices), m_vertices, GL_STATIC_DRAW);


That doesn't do what you think it does. m_vertices is a Vertex3D*. Therefore, sizeof(m_vertices) is... 4. Or 8 if you're compiling in 64-bit mode.

You probably wanted the size of the array. This is yet another reason to use std::vector; it's much easier to compute. In that it's actually possible to compute it ;)

glBufferData(GL_ARRAY_BUFFER, m_vertices.size() * sizeof(Vertex3D), &m_vertices[0], GL_STATIC_DRAW);


This is your vertex position data:

m_vertices[0].x = -1.0f;
m_vertices[0].y = -1.0f;
m_vertices[0].z = -5.0f;
m_vertices[1].x =  1.0f;
m_vertices[1].y = -1.0f;
m_vertices[1].z = -5.0f;
m_vertices[2].x =  0.0f;
m_vertices[2].y =  1.0f;
m_vertices[2].z = -5.0f;


Notice that all of the Z values are at -5.0f. Since you are using no matrix transforms, this means that the clip-space vertices that you get will be at -5.0f in the Z direction.

Clip-space (or to be technical, Normalized Device Coordinate space) only extends from [-1, 1] in all directions. That includes Z. Your -5.0f Z coordinate places your vertex positions outside of the world.

I would suggest 0.0f for the Z.

It's this:

I'd also like to add this, I only saw it in one tutorial:

The thought behind you making this statement is the source of your problem. You aren't coding; you're copying and pasting bits of code extracted from various online sources.

If you understood what, for example, OpenGLBook.com, was saying about layout(location), and then read what another tutorial was saying that glBindAttribLocation does, then you would quickly realize that they both set the same thing. There's no sense in using both of them for the same shader. It's like having a getter for a public variable; there's no point to it and it only ends up confusing the user.

You should never do anything just because you "saw it in one tutorial". You use it because you understand what it does and see a need to do that in your application.

I would say that you have a strong case of "I want to do X"itus. This is a common disease found among many programmers who are new to something. They see something and want to perform some specific task. So they go online and find information. But since none of that information tells them how to do exactly what they want to do, they just find bits of code and copy them into their code, building up a Frankenstein's Monster of an application.

It may live, but it's not the most pleasant form of life.

For example, I have my own series of GL 3.3 tutorials. I think they're pretty decent. But they will not teach you how to write exactly what you're writing. If you try to copy and paste from them, you won't get anything more useful than you'll get from other tutorials.

But if you read them, then they will try to teach you how to be a graphics programmer. The first three chapters covers most of the mistakes and problems your codebase has. It explains about Normalized Device Coordinate space and the extents thereof. It explains how to use glBufferData (though it's still up to you to pass in the correct size). It doesn't explain normalized attributes, but that's because it sticks with floats; it says to leave it as GL_FALSE.

To put it another way, forget about what you want to learn from any tutorial. Simply learn whatever lesson it is intending to teach you. Once you understand the material, you don't need to copy their code at all; you can just write it yourself.

• Jeez, alot of stuff here! First of all, my vertex array isn't delete because I have later plans for its usage. It is deleted in the destructor. I don't use std::vector because in my opinion its most complicated, and when something doesn't work I try to keep it simple. I always assumed that the Z value was it's Z position, but that isn't my problem right now, because I can see the dot in POINT mode. About the "I saw this in a tutorial", this is what I normally do: I write things, and then I find them online to confirm they work. I rarely copy+paste... and I (almost) always read the docs. – smoth190 Apr 15 '12 at 15:32
• And I ran out of room, but I have read your tutorials. They were easy to read because they are clear and the website is easy to look at. The reason I tend to change things is because there are so many crappy tutorials out there that don't explain this stuff, I don't know which is right. I do things, for example, change normalized to TRUE because I picked the wrong tutorial for "right". – smoth190 Apr 15 '12 at 15:37
• Ok, it works now. What you said under "Actual Problems" were my real problems, thank you :) – smoth190 Apr 15 '12 at 15:52