Archived

This topic is now archived and is closed to further replies.

Leyder Dylan

Per Pixel Lighting -> ARB Conversion Problem

Recommended Posts

To Vincof : I corrected all lol Hi, For doing PPL, I was using the "GL_NV_vertex_program" extension and as you can say, it''s only for a Nvidia video card. For the moment, I''m trying to convert the code for using "ARB_vertex_program" extension. Everything is OK but not the blending. For the light, I''m using this texture : The background is white and the light is black. So, with the "GL_NV_vertex_program", I had this result : And now, with the "ARB_vertex_program", with the same blending params, I''ve this result : Here''re the blending params : 1st pass : // Blending Params glBlendFunc(GL_ONE, GL_ONE); glEnable(GL_BLEND); // The PPL code here ... 2nd pass : // Blending Params glBlendFunc(GL_DST_COLOR, GL_ZERO); // The modulated map with PPL For me, the error comes from the fact that I''m not using the Register Combiners. I cannot use that because it''s, another time, a Nvidia specific extension. ======================== Leyder Dylan (dylan.leyder@slug-production.be.tf http://www.slug-production.be.tf/

Share this post


Link to post
Share on other sites
quote:
Original post by Leyder Dylan
To Vincof : I corrected all lol




quote:
Original post by Leyder Dylan
For the light, I''m using this texture :

click

If the texture is meant to represent an attenuated light contribution, I guess the intensities are inverted. It would be logical to have white in the centetr and black in the border, even though if the fragment stage inverts it it''s not a problem see below).


quote:
Original post by Leyder Dylan So, with the "GL_NV_vertex_program", I had this result :

click


And now, with the "ARB_vertex_program", with the same blending params, I''ve this result :

click

(...)

For me, the error comes from the fact that I''m not using the Register Combiners. I cannot use that because it''s, another time, a Nvidia specific extension.

Yes it looks like you''re using register combiners.
You may invert the texture entry in one of your combiner stages, and in the register combiners path only.
IMHO, the best thing to do would be to redesign a little bit your engine, because it''s not logical to send an inverted lightmap (well, if it''s meant to be a lightmap).
The easiest thing to test would be to invert the blending stage for the non-register combiner path.
That is, replace :
glBlendFunc(GL_DST_COLOR, GL_ZERO);
with :
glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ZERO);

This might look easier, but in the long run I''d prefer treating lightmaps as they "should" be.

You''re free to select whichever solution you prefer

Share this post


Link to post
Share on other sites
You're right, it's more logical that I've in the texture a white center and black border.

So now, I've inverterd the texture, I use this one :





I changed the blending params and now, no light is applyed on the polygon :




Again, here's the blending params :

1st Pass :


// Blending Params
glBlendFunc(GL_ONE, GL_ONE);
glEnable(GL_BLEND);




2nd Pass :

// Blending Params
//glBlendFunc(GL_DST_COLOR, GL_ZERO);
glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ZERO);



I know that my bigger problem is to understand the m..... blenging params so, Vincof, sorry for wasting your time ...

When you say :

quote:

You may invert the texture entry in one of your combiner stages, and in the register combiners path only.



I don't use the RC because I want that the PPL works on another video card than a Nvidia GeForce ... You knwo what I mean, I want that everybody with a good video card can use this demo.

And the final word, after your help, I need to re-write some part of my light (dynamic lightmapping, static lightmapping) demos but it's not a problem, gonna do that soon but always these f...... blending params.

========================
Leyder Dylan (dylan.leyder@slug-production.be.tf
http://www.slug-production.be.tf/

[edited by - Leyder Dylan on October 7, 2003 8:43:32 AM]

Share this post


Link to post
Share on other sites
I think vincoof was saying to either invert the lightmap or the blending parameters, not both. So with an inverted lightmap your blending parameters should stay as glBlendFunc(GL_DST_COLOR, GL_ZERO);

Enigma

Share this post


Link to post
Share on other sites
quote:

Yes it looks like you''re using register combiners.

Where is the combiner setup? I could only see BlendFunc stuff (which seems to work in a way which can feature wise make combiners useless).

To me, this BlendFunc''ing looks like multipass rendering and combiners are single-pass, multi-texturing things.

Are those combiners used or not?

Share this post


Link to post
Share on other sites
Strange... Is your code now exactly the same as it was when you posted the original picture? It looks to me like you may have accidently changed something, but I''m no expert. I''d suggest either:
A) get your program back identical to how it was originally (i.e. with the lightmap ''inside-out'') and then invert the lightmap again.
B) wait for vincoof to show up again!

Anyway, hope you get it working,

Enigma

Share this post


Link to post
Share on other sites
Indeed, Enigma got the right point.

Leyder Dylan : I''m pretty sure you changed something in your demo. It''s like you now load a black texture, just like if you bind a black texture when the file does not exist for instance.

When I first saw the OpenGL blending function, I couldn''t even translate what the tokens meant
In fact, it''s pretty easy.

The blending stage is the final straight line to the color buffer.
This is a stage which has two inputs and an output for a given pixel position :
- input 1 : the fragment that has just been rasterized. it comes from texturing, fog, etc of the triangle being rendered actually, which has been invoked by glVertex for instance. it s called the source color.
- input 2 : the color that is already present in the color buffer at this pixel position. it''s the color of the last object that has been rendered at this pixel, or the color of glClearColor if this pixel is filled for the first time in this frame. it is called the destination color.
- output : the fragment that will replace the color buffer''s value at this pixel position.

So, the blengind stage is a function of two inputs and give an output :
output = f(input1, input2)

In the most basic OpenGL specification, blending is a function that multiplies each input with a specific color determined by glBlendFunc, and adds them together and clamps them.
Say, if you called glBlendFunc(A, B), then :
output = (input1 * A) + (input2 * B)
and for it to be clamped, it should be written like that, but for clarity we will ignore that formula :
output = min(max((input1*A)+(input2*B), 0), 1)

So, the input1 is the source color and the input2 is the destination color. Let''s call them SRC_COLOR and DST_COLOR, respectively.
output = (SRC_COLOR * A) + (DST_COLOR * B)

Now, when you call :
glBlendFunc(GL_DST_COLOR, GL_ZERO), it simply means that the output color is computed as is :
output = (SRC_COLOR * DST_COLOR) + (DST_COLOR * ZERO)
so, the output is :
output = SRC_COLOR * DST_COLOR
which means that the input fragment (source color) is multiplied by the already existing fragment in the color buffer (destination color).

These are two simple examples :
1- if you want each rendered fragment to replace the current color buffer, just as if blending was disabled : call glBlendFunc(GL_ONE, GL_ZERO).
2- if you want to ignore completely the fragments that are rendered (that would be pretty dumb, heh) : call glBlendFunc(GL_ZERO, GL_ONE).

Is it clear enough ? Or it is useless since you already knew it ?

Share this post


Link to post
Share on other sites
Vincoof,

First, it''s more easy to ask to anyone instead trying to understand myself, so now, I want to understant the "glBlendFunc", so don''t laugh about me ...

Just remember :

quote:

Asking a question isn''t stupid,
Not asking one when you don''t know is stupid.






According "OpenGL 1.2" book :


The RGBA value for "GL_ZERO" is RGBA (0,0,0,0)
The RGBA value for "GL_ONE" is RGBA (1,1,1,1)




So, now, if I''ve a understood a few things, when I write (0,0,0,0): it''s the same as "GL_ZERO" and for (1,1,1,1), it''s the same as "GL_ONE".





Vincoof, following your 2 examples :




quote:

1- if you want each rendered fragment to replace the current color buffer, just as if blending was disabled : call glBlendFunc(GL_ONE, GL_ZERO).



==> For the 1st example. Am I right ? :

(SRC_COLOR * GL_ONE) + (DST_COLOR * GL_ZERO)
==> Output = (SRC_COLOR * (1,1,1,1)) + (DST_COLOR * (0,0,0,0))
= (SRC_COLOR) + (0,0,0,0)
= (SRC_COLOR) ==> The destination color has been replaced by the source color ?




quote:

2- if you want to ignore completely the fragments that are rendered (that would be pretty dumb, heh) : call glBlendFunc(GL_ZERO, GL_ONE).



==> For the 2nd example is :

(SRC_COLOR * GL_ZERO) + (DST_COLOR * GL_ONE)
==> Output = (SRC_COLOR * (0,0,0,0)) + (DST_COLOR * (1,1,1,1))
= (0,0,0,0) + (DST_COLOR)
= (DST_COLOR) ==> The destination color has not changed, nothing has changed in the destination color




If at this point, I''m on the right way, thanks god otherwise, please lights my mind ...
And finally (only if I''m right for the moment), I''ve a doubt at this :

quote:

Now, when you call :
glBlendFunc(GL_DST_COLOR, GL_ZERO), it simply means that the output color is computed as is :
output = (SRC_COLOR * DST_COLOR) + (DST_COLOR * ZERO)
so, the output is :
output = SRC_COLOR * DST_COLOR
which means that the input fragment (source color) is multiplied by the already existing fragment in the color buffer (destination color).



==> For this :

(SRC_COLOR * GL_DST_COLOR) + (DST_COLOR * GL_ZERO)
==> Output = (SRC_COLOR * GL_DST_COLOR) + (DST_COLOR * (0,0,0,0))
= (SRC_COLOR * GL_DST_COLOR) + (0,0,0,0)
= SRC_COLOR * GL_DST_COLOR
=> What''s the result ? It depends from the source color ?

I''m trying to understand this since 3 hours and now, my mind begins to understand ...

Hope that I''m in the good way otherwise, please try again ...


========================
Leyder Dylan (dylan.leyder@slug-production.be.tf
http://www.slug-production.be.tf/

Share this post


Link to post
Share on other sites
I was asking me if the problem does not come from the ARB program ?

I''m not sure, but here''s the ARB vertex program :



"!!ARBvp1.0\
#\n\
# This is a sample ARB Vertex Program\n\
#\n\
ATTRIB iPos = vertex.position;\
ATTRIB iColor = vertex.color;\
ATTRIB iTex0 = vertex.texcoord[0];\
PARAM mvp[4] = { state.matrix.mvp };\
OUTPUT oPos = result.position;\
OUTPUT oColor = result.color;\
OUTPUT oTex0 = result.texcoord[0];\
# This just does out vertex transform by the modelview projection matrix\n\
DP4 oPos.x, mvp[0], iPos;\
DP4 oPos.y, mvp[1], iPos;\
DP4 oPos.z, mvp[2], iPos;\
DP4 oPos.w, mvp[3], iPos;\
# Write our color out directly\n\
MOV oColor, iColor;\
# Write out the texture coordinates directly\n\
MOV oTex0, iTex0;\
END"
;




========================
Leyder Dylan (dylan.leyder@slug-production.be.tf
http://www.slug-production.be.tf/

Share this post


Link to post
Share on other sites
quote:

==> For the 1st example. Am I right ? :

(SRC_COLOR * GL_ONE) + (DST_COLOR * GL_ZERO)
==> Output = (SRC_COLOR * (1,1,1,1)) + (DST_COLOR * (0,0,0,0))
= (SRC_COLOR) + (0,0,0,0)
= (SRC_COLOR) ==> The destination color has been replaced by the source color ?
quote:

==> For the 2nd example is :

(SRC_COLOR * GL_ZERO) + (DST_COLOR * GL_ONE)
==> Output = (SRC_COLOR * (0,0,0,0)) + (DST_COLOR * (1,1,1,1))
= (0,0,0,0) + (DST_COLOR)
= (DST_COLOR) ==> The destination color has not changed, nothing has changed in the destination color

Yup that's exactly that.

quote:

==> For this :

(SRC_COLOR * GL_DST_COLOR) + (DST_COLOR * GL_ZERO)
==> Output = (SRC_COLOR * GL_DST_COLOR) + (DST_COLOR * (0,0,0,0))
= (SRC_COLOR * GL_DST_COLOR) + (0,0,0,0)
= SRC_COLOR * GL_DST_COLOR
=> What's the result ? It depends from the source color ?

It depends on both the source color and destination color. The '*' operation is simply the component-by-component multiplication, also known as modulation in OpenGL.
The source color is modulated by the destination color, which means that if any of the source or destination color is black, then the result is black ; if both the source and destination colors are white, then the result is white ; and for example if the source color is yellow (1,1,0,1) and the destination color magenta (1,0,1,1) then the result is red because (1,1,0,1)*(1,0,1,1)=(1,0,0,1).

I'm not laughing at you at all. As I stated above, I myself couldn't bare the specification in the first sight, with regard to the blending paragraph. But then it's just a matter of logic. Like most things in OpenGL, once you've been able to see what the designers wanted, it all comes incredibly clear.

[edited by - vincoof on October 7, 2003 11:24:41 PM]

Share this post


Link to post
Share on other sites
The vertex program looks fine. At least it is syntaxically correct otherwise you wouldn't even see your triangles rendered (usually rendering is skipped when an invalid vertex program is bound).

There are only two things you could improve :
1- if you render your models in multipass (which seems to be the case here) and if at least one of the passes does not use vertex programs, then it's better to use the ARB_position_invariant option which guarantees that rasterized fragments will be done exactly at the same position. It's especially important for Z-buffer issues that are typically needed for multipass rendering.
2- if in your code you use a non-identity texture matrix, you should multiply the texture coordinate by this matrix instead of copying the input texcoord to the output texcoord directly.

But these are just improvements. I'm not sure it's vital actually.

[edited by - vincoof on October 7, 2003 10:38:50 PM]

Share this post


Link to post
Share on other sites
Why do you use VP. All you do in it can be done(faster?) using fixed function pipeline.

A small thing that might help you is to write a function to loop trough all possible glBlendFunc( parm1, parm2 ) combinations and see if the problem is even here. If none of combination is correct then you have problem somewhere else.

You should never let your fears become the boundaries of your dreams.

Share this post


Link to post
Share on other sites
Yup Mirko, you got it.
The problem is due to the fact that the first pass uses two texture units, but the vertex program here does only transfer texture coordinate 0. Without vertex programs, there would have been no problem as Mirko pointed out
So, simply add those lines in the vertex program (I think you will guess where to insert them) :
ATTRIB iTex1 = vertex.texcoord[1];\
OUTPUT oTex1 = result.texcoord[1];\
MOV oTex1, iTex1;\

Cheers

Share this post


Link to post
Share on other sites
Thanks all, no it works !

The problem was coming from the ARB String. No, all is OK.

With this adventure, I've decided to write a simple article with that so, can you take a look on it (sended by e-mail) and tell me if it's correct and if I can add it in my website ?

Thanks.

========================
Leyder Dylan (dylan.leyder@slug-production.be.tf
http://www.slug-production.be.tf/

[edited by - Leyder Dylan on October 8, 2003 1:30:29 PM]

Share this post


Link to post
Share on other sites