Fonix
Fonix

Reputation: 11597

2 Shaders using the same vertex data

So im having problems rendering using 2 different shaders. Im currently rendering shapes that represent dice, what i want is if the dice is selected by the user, it draws an outline by drawing the dice completely red and slightly scaled up, then render the proper dice over it. At the moment some of the dice, for some reason, render the wrong dice for the outline, but the right one for the proper foreground dice.

Im wondering if they aren't getting their vertex data mixed up somehow. Im not sure if doing something like this is even allowed in openGL:

glGenBuffers(1, &_vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, numVertices*sizeof(GLfloat), vertices, GL_STATIC_DRAW);

glEnableVertexAttribArray(effect->vertCoord);        
glVertexAttribPointer(effect->vertCoord, 3, GL_FLOAT, GL_FALSE, 0, 0);

glEnableVertexAttribArray(effect->toon_vertCoord);        
glVertexAttribPointer(effect->toon_vertCoord, 3, GL_FLOAT, GL_FALSE, 0, 0);

im trying to bind the vertex data to 2 different shaders here when i load my first shader i have:

vertCoord = glGetAttribLocation(TexAndLighting, "position");

and the other shader has:

toon_vertCoord = glGetAttribLocation(Toon, "position");

if I use the shaders independently of each other they work fine, but when i try to render both one on top of the other they get the model mixed up some times. here is how my draw function looks:

- (void) draw {
[EAGLContext setCurrentContext:context];

glBindVertexArrayOES(_vertexArray); 

effect->modelViewMatrix = mvm;
effect->numberColour = GLKVector4Make(numbers[colorSelected].r, numbers[colorSelected].g, numbers[colorSelected].b, 1);
effect->faceColour = GLKVector4Make(faceColors[colorSelected].r, faceColors[colorSelected].g, faceColors[colorSelected].b, 1);

if(selected){
    [effect drawOutline]; //this function prepares the shader
    glDrawElements(GL_TRIANGLES, numIndices, GL_UNSIGNED_SHORT, 0);
}

[effect prepareToDraw]; //same with this one
glDrawElements(GL_TRIANGLES, numIndices, GL_UNSIGNED_SHORT, 0);
}

this is what it looks like, as you can see most of the outlines are using the wrong dice, or none at all: picture of dice

links to full code:
http://pastebin.com/yDKb3wrD Dice.mm //rendering stuff
http://pastebin.com/eBK0pzrK Effects.mm //shader stuff
http://pastebin.com/5LtDAk8J //my shaders, shouldn't be anything to do with them though

TL;DR: trying to use 2 different shaders that use the same vertex data, but its getting the models mixed up when rendering using both at the same time, well thats what i think is going wrong, quite stumped actually.

Upvotes: 1

Views: 211

Answers (1)

Tim
Tim

Reputation: 35923

You're correct, in that this is not allowed (or rather it doesn't do what you think):

glEnableVertexAttribArray(effect->vertCoord);        
glVertexAttribPointer(effect->vertCoord, 3, GL_FLOAT, GL_FALSE, 0, 0);

glEnableVertexAttribArray(effect->toon_vertCoord);        
glVertexAttribPointer(effect->toon_vertCoord, 3, GL_FLOAT, GL_FALSE, 0, 0);

Attributes have no particular linkage to shaders. You can't tell OpenGL "attribute N is for this shader, and attribute M is for this other shader."

Attributes simply bind to indexes, and any shader that happens to have an input at that index will slurp the data that was last bound to that particular index.

So if you have two shaders, lets call them "toon" and "normal", which have the following inputs (this is hypothetical):

normal
  input vertCoord (index = 0)
  input texCoord (index = 1)

toon
  input toon_vertCoord (index = 0)
  input toon_somethingElse (index = 1)

Then when you run this code:

glEnableVertexAttribArray(effect->vertCoord);        
glVertexAttribPointer(effect->vertCoord, 3, GL_FLOAT, GL_FALSE, 0, 0);

glEnableVertexAttribArray(effect->toon_vertCoord);        
glVertexAttribPointer(effect->toon_vertCoord, 3, GL_FLOAT, GL_FALSE, 0, 0);

draw_normal_object();

Your effect->vertCoord is no longer bound to anything, because toon_vertCoord has the same index, and you've overwritten the input pointer. So here your normal shader will be sampling from the toon_vertCoord, and everything will be all messed up.

What you want to do is to enable/pointer all of the attributes for "normal shader", draw the normal objects, then switch to the toon shader, enable/pointer all of the toon attributes, and then draw the toon objects.

Upvotes: 2

Related Questions