PDA

View Full Version : Rendering multiple 2D textures



blackwolf12333
01-24-2015, 11:14 AM
Hello everybody,

I am trying to write a little toy engine for myself. But I am experiencing difficulty rendering more than one texture. I have gone over the tutorials from open.gl and I can get everything to work with one texture. But as soon as I try to make it two or more everything breaks down. I'll paste the code below of my third iteration that still doesn't work. I am using a core profile for OpenGL 3.2. And I am using SDL for window management.

I have been reading a lot and as I understand it you should be able to use VAOs to make two different things render to the screen. So that has been my approach so far, basically I generate a VAO for the first texture, get some vertices set up and load the texture. Then I do the same with a second texture. When rendering I use GLSL shaders. Which is where the first problem seems to be at the moment. My game/engine receives a SIGSEGV when enabling a vertex attribute.



void Main::initShaders() {
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexSource, NULL);
glCompileShader(vertexShader);
checkShaderCompilerStatus(vertexShader);

GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentSource, NULL);
glCompileShader(fragmentShader);
checkShaderCompilerStatus(fragmentShader);

GLuint shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glBindFragDataLocation(shaderProgram, 0, "outColor");
glLinkProgram(shaderProgram);
glUseProgram(shaderProgram);

// This works fine
GLint posAttrib = glGetAttribLocation(shaderProgram, "position");
glEnableVertexAttribArray(posAttrib);
glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 7 * sizeof(GLfloat), 0);
checkGLError2(__LINE__, __FILE__);

// This results in error 1282(should be GL_INVALID_VALUE) that is caught in the checkGLError2 function below
GLint colAttrib = glGetAttribLocation(shaderProgram, "color");
glEnableVertexAttribArray(colAttrib);
glVertexAttribPointer(colAttrib, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(GLfloat), (void*)(2 * sizeof(GLfloat)));
checkGLError2(__LINE__, __FILE__);

// This does the same.
GLint texAttrib = glGetAttribLocation(shaderProgram, "texcoord");
glEnableVertexAttribArray(texAttrib);
glVertexAttribPointer(texAttrib, 2, GL_FLOAT, GL_FALSE, 7 * sizeof(GLfloat), (void*)(5 * sizeof(GLfloat)));
checkGLError2(__LINE__, __FILE__);
}


And the shaders I use:
vertex:


#version 150 core
in vec2 position;
in vec3 color;
in vec2 texcoord;

out vec3 Color;
out vec2 Texcoord;

void main() {
Color = color;
Texcoord = texcoord;

gl_Position = vec4(position, 0.0, 1.0);
}


fragment:


#version 150 core
in vec3 Color;
in vec2 Texcoord;

out vec4 outColor;

uniform sampler2D tex;

void main() {
outColor = texture(tex, Texcoord) * vec4(Color, 0.0);
}


As far as I know that shouldn't result in an error. Because the color and texcoord attributes are both there.

I won't paste the whole source here because that's too much for one forum post. But here it is. (https://gist.github.com/blackwolf12333/be2cf91cd557a07efcf9)

Here is some info about my system:
Kernel: Linux aristotle 3.18.3-1-ck #1 SMP PREEMPT Fri Jan 16 15:02:43 EST 2015 x86_64 GNU/Linux
GL version: 3.3.0 NVIDIA 340.65
GL vendor: NVIDIA Corporation
GL renderer: GeForce 8400M GS/PCIe/SSE2

Any advice about how to render multiple textures would be a nice addition :)

Thanks in advance,
Peter

malexander
01-24-2015, 03:04 PM
You're missing the binding of the buffer that contains the data in initShaders():


glBindBuffer(GL_ARRAY_BUFFER, vertex_data_buffer_id);

before the calls to the glVertexAttribPointer(). Pull all the glVertexAttribPointer() calls out of the initShaders() function and move them to initVertices1/2(), because the attribute location storage is not stored with the shader program, but instead in a VAO.

After fixing that, note that textures are not bound to VAOs, only buffers are. You'll need to bind each texture before the draw calls:

glBindVertexArray(vao1);
glBindTexture(GL_TEXTURE_2D, tex1);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
// glBindVertexArray(0); - no need to unbind vao1 when you immediately bind vao2

glBindVertexArray(vao2);
glBindTexture(GL_TEXTURE_2D, tex2);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); glBindVertexArray(0);


...which means you'll need to hold onto those texture ids that glGenTextures() produces. Right now, you're creating a texture and then losing the handle to it, effectively leaking it.

blackwolf12333
01-24-2015, 03:55 PM
I'm not sure I understand the first part.

Do I need to bind the vbo from each initVertices function when initializing the shaders?

Alfonse Reinheart
01-24-2015, 04:01 PM
It has nothing to do with shaders. It's how Vertex Specification works (https://www.opengl.org/wiki/Vertex_Specification#Vertex_Buffer_Object). To say that attribute X gets its vertex array data from a particular buffer, you must bind the buffer to GL_ARRAY_BUFFER, then call glVertexAttribPointer.

blackwolf12333
01-25-2015, 06:13 AM
Thanks guys, it's working now. :)