Sign in to follow this  
billouparis

More than one shader programs [SOLVED]

Recommended Posts

Hello, I've been searching for an answer for this since days, and I am still stuck.
I simply want to display 3 objects, using two different shader programs just like this:
My first use-case was actually wrong, I spent a lot of time on this, and the use cases are as follow: draw()
{

glUseProgram(program1);
drawObject1();

glUseProgram(program2)
drawObject2();

drawObject3();

}

In this case, object 1 is drawn using program 1, and object 2 and object 3 are drawn using program 2. which is fine!
But now I have this other use case causing the issue:

draw()
{

glUseProgram(program1);
drawObject1();

glUseProgram(program2)
drawObject2();

glUseProgram(program1)
drawObject3();

}

then object 1 and object 3 are drawn using program1, whereas object 2 is not drawn at all.

It looks like the fact to swap back to another program (program1) before the end of draw function would sort of invalidate the drawing made by program2. Maybe I should add some method to force the rendering in program2, before swapping back to program1? I tried to add some glFinish, and/or glFlush before swapping programs, but none of them helped in anyway to get my object 2 drawn…. Yes, I am Desperate!

Any idea?


Thank you!

Share this post


Link to post
Share on other sites
[quote]
It looks like the fact to swap back to another program (program1) before the end of draw function would sort of invalidate the drawing made by program2. Maybe I should add some method to force the rendering in program2, before swapping back to program1? I tried to add some glFinish, and/or glFlush before swapping programs, but none of them helped in anyway to get my object 2 drawn…
[/quote]

No, no, no... you certainly don't need anything like this. You can swap shaders all you want and it won't invalidate anything, and you don't need to call glFlush or glFinish for any reason here. Once you issue a draw command, it [b]will[/b] be drawn, and there's nothing you can do to stop it, intentionally or accidentally.

You must be doing something else that you're not accounting for here that is causing your second object not to be rendered. There's nothing theoretically wrong with either of the program flows you've posted.

If you can't figure it out, post your real code and let someone take a look at it.

Share this post


Link to post
Share on other sites
[quote name='karwosts' timestamp='1302568600' post='4797323']
[quote]
It looks like the fact to swap back to another program (program1) before the end of draw function would sort of invalidate the drawing made by program2. Maybe I should add some method to force the rendering in program2, before swapping back to program1? I tried to add some glFinish, and/or glFlush before swapping programs, but none of them helped in anyway to get my object 2 drawn…
[/quote]

No, no, no... you certainly don't need anything like this. You can swap shaders all you want and it won't invalidate anything, and you don't need to call glFlush or glFinish for any reason here. Once you issue a draw command, it [b]will[/b] be drawn, and there's nothing you can do to stop it, intentionally or accidentally.

You must be doing something else that you're not accounting for here that is causing your second object not to be rendered. There's nothing theoretically wrong with either of the program flows you've posted.

If you can't figure it out, post your real code and let someone take a look at it.
[/quote]

Hello Karwosts, thank you for your answer.
My code is based on Qt QGLWidget class, and the rendering method is a bit complex because it is based on some structures of 3D objects. But maybe it can still be useful by someone to help me with my issue, so here it goes:

PaintGL() is called each time we want the scene redrawn, and an automatic swapbuffers is executed at the end of this function, I tried to simplify it as much as possible.
As you can see I have two program already linked, one is used for most of the objects in the scene, the second one called qGLShaderProgramScreen is used only for one specific object (with index 59 in my list of objects in my scene):
[color="#808000"]void myWidget::paintGL()
{
// Clear the colorbuffer and depth-buffer
QColor bgColor(10,15,255,255);
qglClearColor( bgColor );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
model->draw(qGLShaderProgramTextures, qGLShaderProgramScreen, fAngle, yValue, zValue);
}
[/color]

Then the model->draw(...) call is as follow:
[color="#808000"]void Model::draw(QGLShaderProgram *programTextures, QGLShaderProgram *programScreen, GLfloat fAngle, GLfloat yValue,GLfloat zValue)
{
bool status = false;
QGLShaderProgram *program = NULL;
qDebug("model draw");
QMatrix4x4 matModelViewStaticParts ( 1.0f, 0.0, 0.0, 0.0, /*second row*/ 0.0, 1.0, 0.0, yValue, /*thirs row*/ 0.0, 0.0, 1.0, zValue, /*last row*/ 0.0, 0.0, 0.0, 1.0); //Construct all textures only once
static bool loop = 1;
if (1 == loop)
{
constructAllTextures();
constructVBO();
loop = 0;
}

unsigned int index = 0;
GLMgroup* group;
group = model->groups;
unsigned int indexColor = 0;
//main loop through all objects in the scene to render
foreach(ModelGroup grp, groups)
{
//Here we swap between shaderprogram when object to be drawn is index 59
if (index != 59)
{
program = programTextures;
}
else
{
program = programScreen;
}

//bind either program1 or program2 depending on the object to render
status = program->bind();
if (status == false)
{
qDebug()<<"Error while binding program ";
exit(1);
}

//retrieve the corresponding material/texture
//qDebug()<<model->materials[group->material].colorMapFilename;
if (strcmp (model->materials[group->material].colorMapFilename, "default") != 0)
{
glBindTexture( GL_TEXTURE_2D, textures[group->material] );
}
else
{
glBindTexture( GL_TEXTURE_2D, NULL );
}


// Set the sampler texture unit to 0
GLint g_hSamplerLoc = 0;
g_hSamplerLoc = program->uniformLocation("s_texture");
program->setUniformValue(g_hSamplerLoc, 0);
g_hSamplerLoc = program->uniformLocation("g_matModelView");
program->setUniformValue( g_hSamplerLoc, *composeeScene);

//vertices
//bind vertex buffer object status = buf[index]->bind();
if (status == false)
{
qDebug()<<"error binding buffer";
}

program->enableAttributeArray(0);
program->setAttributeBuffer(0, GL_FLOAT, 0, 3, 0);
program->enableAttributeArray(1);
program->setAttributeBuffer(1, GL_FLOAT, group->numtriangles * 3*3*sizeof(float), 3, 0);
program->enableAttributeArray(2);
program->setAttributeBuffer(2, GL_FLOAT, 2 * group->numtriangles * 3*3*sizeof(float), 3, 0);
glDrawArrays(GL_TRIANGLES, 0, group->numtriangles*3);
program->disableAttributeArray(0);
program->disableAttributeArray(1);
program->disableAttributeArray(2);

index++;
group = group->next;
indexColor++;
}

}
[/color]


So when running the previous code, all my objects are drawn, and object index 59 is not rendered at all.
Now if I change this:
[color="#008000"]//main loop through all objects in the scene to render[/color]
[color="#808000"]foreach[/color][color="#000000"]([/color]ModelGroup grp[color="#000000"],[/color] groups[color="#000000"])[/color]
[color="#000000"]{[/color]
[color="#006400"]//Here we swap between shaderprogram when object to be drawn is index 59[/color] [color="#c0c0c0"]
[/color][color="#808000"]if[/color] [color="#000000"]([/color]index [color="#000000"]!=[/color] [color="#000080"]59[/color][color="#000000"])[/color] [color="#000000"]
{[/color]
program [color="#000000"]=[/color] programTextures[color="#000000"];[/color] [color="#000000"]}[/color]
[color="#808000"]else[/color]
[color="#000000"]{[/color]
program [color="#000000"]=[/color] programScreen[color="#000000"];[/color]
[color="#000000"]}[/color]


with this:
[color="#008000"]//main loop through all objects in the scene to render[/color]
program = programTextures;
[color="#808000"]foreach[/color][color="#000000"]([/color]ModelGroup grp[color="#000000"],[/color] groups[color="#000000"])[/color]
[color="#000000"]{[/color] [color="#c0c0c0"]
[/color][color="#006400"]//Here we swap between shaderprogram when object to be drawn is index 59[/color] [color="#c0c0c0"]
[/color][color="#808000"]if[/color] [color="#000000"]([/color]index [color="#000000"]==[/color] [color="#000080"]59[/color][color="#000000"])[/color]
[color="#000000"]{[/color] [color="#c0c0c0"] [/color]
program [color="#000000"]=[/color] programScreen[color="#000000"];[/color] [color="#c0c0c0"]
[color="#000000"]}[/color]

[color="#000000"]Then all objects from index 59 to the end of my list of objects are drawn with the second shader program.[/color]
[/color]

Share this post


Link to post
Share on other sites
Hmm, unfortunately I don't see any error in your code that would explain what you're seeing, maybe some more debugging is needed. I don't know much about Qt, but I'm pretty familiar with OpenGL and I can't think that it would work any differently under the hood.

Have you tried rendering object 59 by itself (if index != 59 {continue;})? What does it look like, what kind of object is it? (an image may help). What happens if you leave the code as it was in your original example, but do either of the following:

1) Render objects 0-59 only.
2) Render objects 59-N only.

Do you see what you expect in both cases? You should only have one shader switch in both situations.

FYI, if you want to paste large code blocks, you can use the [code] tags.

Share this post


Link to post
Share on other sites
Hello,

i gathered up a small example program which presents the same defect, I will attach it to this email if you are willing to help me :)
Inside the draw function, there is 4 defines macro, you can select one or the other, and see the result!
Of course, you need Qt, to get it work. But you can still look at the source code.
Thank you,

Share this post


Link to post
Share on other sites
I'm not a Qt user either. Are you sure your shaders are getting compiled?
[code]
//#version 140
varying in vec2 v_texCoord;
uniform sampler2D s_texture;
varying out vec4 FragColor;
void main()
{
FragColor = vec4(1, 0, 0, 1);
}
[/code]

The above looks invalid because of the "varying" keyword.
You can have
smooth in vec2 v_texCoord;

but not varying in vec2 v_texCoord;

The output can never be a varying. You must have
out vec4 FragColor;

Perhaps qGLFragmentShader->compileSourceCode is not doing such a great job.

Besides that I noticed some deprecated code.

Share this post


Link to post
Share on other sites
[quote name='V-man' timestamp='1302718175' post='4798052']
I'm not a Qt user either. Are you sure your shaders are getting compiled?
[code]
//#version 140
varying in vec2 v_texCoord;
uniform sampler2D s_texture;
varying out vec4 FragColor;
void main()
{
FragColor = vec4(1, 0, 0, 1);
}
[/code]

The above looks invalid because of the "varying" keyword.
You can have
smooth in vec2 v_texCoord;

but not varying in vec2 v_texCoord;

The output can never be a varying. You must have
out vec4 FragColor;

Perhaps qGLFragmentShader->compileSourceCode is not doing such a great job.

Besides that I noticed some deprecated code.
[/quote]

Thank you for your comments, I still have the issue though, but I finally ended with using a single program to get rid of my problems.
Bill

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this