Reg Combiners ... Clueless

OK - this is the first time I’ve used register combiners, and I’m stuck.

I want to take an RBG texture and occasionally convert it to gray scale. But I haven’t got a clue how to do it quite frankly.

I know that I need to …
input RGBA

and output
R = (R * 0.3) + (G * 0.59) + (B * 0.11)
G = (R * 0.3) + (G * 0.59) + (B * 0.11)
B = (R * 0.3) + (G * 0.59) + (B * 0.11)
A = A

But I’m looking at sample code which seems to bear no resmeblence to the spec. I think I’ve confused myself here. Or maybe getting up at 3am didn’t help!!!

My code so far is …

glEnable(GL_REGISTER_COMBINERS_NV);
glDisable(GL_REGISTER_COMBINERS_NV);

Impressive huh? All I need is the bits in the middle. Can anyone help? Please?

Regards

Originally posted by Shag:
[b]OK - this is the first time I’ve used register combiners, and I’m stuck.

I want to take an RBG texture and occasionally convert it to gray scale. But I haven’t got a clue how to do it quite frankly.

I know that I need to …
input RGBA

and output
R = (R * 0.3) + (G * 0.59) + (B * 0.11)
G = (R * 0.3) + (G * 0.59) + (B * 0.11)
B = (R * 0.3) + (G * 0.59) + (B * 0.11)
A = A

But I’m looking at sample code which seems to bear no resmeblence to the spec. I think I’ve confused myself here. Or maybe getting up at 3am didn’t help!!!

My code so far is …

glEnable(GL_REGISTER_COMBINERS_NV);
glDisable(GL_REGISTER_COMBINERS_NV);

Impressive huh? All I need is the bits in the middle. Can anyone help? Please?

Regards[/b]

Ok, I’ve never used the registry combiners before, but what you want is (using NVParse):

const0 = (0.3, 0.59, 0.11, 1);
out.rgb = tex0.const0

I think that’s right…

Nope, that’s not right…

const0 = (0.3, 0.59, 0.11, 1);
{
rgb
{
spare0 = tex0.const0
}
}
out.rgb = spare0

That should work.

[This message has been edited by NitroGL (edited 03-07-2002).]

And in terms of

glCombinerInputNV()
glCombinerOutputNV()
etc

Regards

Using the spec and sample code to understand RC’s is probably not the easiest way. Have a look at the RC presentations on NVIDIA’s site, these contain invaluable diagrams.

Funny, that was actually the purpose of an Effect I submitted to the nVIDIA contest that took place some time ago (no wonder why I didn’t win a thing…).

Actually, I did two versions: one with texture shaders (which was the aim !) and then one with the register combiners (after I realised that it was the most obvious and simple solution…).

Anyway, here is the snippet that sets the RC up:

// Texture 0 - Normal texture//
glActiveTextureARB(GL_TEXTURE0_ARB);
glBindTexture(GL_TEXTURE_2D,1);
glEnable(GL_TEXTURE_2D);
glEnable(GL_REGISTER_COMBINERS_NV);
glCombinerParameteriNV(GL_NUM_GENERAL_COMBINERS_NV,2);
float fGreyscale[4]={0.3,0.59,0.11,1};
glCombinerParameterfvNV(GL_CONSTANT_COLOR0_NV,fGreyscale);
float fAlpha[4]={0,0,0,fFade};
glCombinerParameterfvNV(GL_CONSTANT_COLOR1_NV,fAlpha);
// Combiner 0 calculates the grey texture //
glCombinerInputNV(GL_COMBINER0_NV,GL_RGB,GL_VARIABLE_A_NV,GL_TEXTURE0_ARB,GL_UNSIGNED_IDENTITY_NV,GL_RGB);
glCombinerInputNV(GL_COMBINER0_NV,GL_RGB,GL_VARIABLE_B_NV,GL_CONSTANT_COLOR0_NV,GL_UNSIGNED_IDENTITY_NV,GL_RGB);
glCombinerOutputNV(GL_COMBINER0_NV,GL_RGB,GL_SPARE0_NV,GL_DISCARD_NV,GL_DISCARD_NV,GL_NONE,GL_NONE,GL_TRUE,GL_FALSE,GL_FALSE);
// Combiner 1 interpolates between grey and color //
glCombinerInputNV(GL_COMBINER1_NV,GL_RGB,GL_VARIABLE_A_NV,GL_TEXTURE0_ARB,GL_UNSIGNED_IDENTITY_NV,GL_RGB);
glCombinerInputNV(GL_COMBINER1_NV,GL_RGB,GL_VARIABLE_B_NV,GL_CONSTANT_COLOR1_NV,GL_UNSIGNED_IDENTITY_NV,GL_ALPHA);
glCombinerInputNV(GL_COMBINER1_NV,GL_RGB,GL_VARIABLE_C_NV,GL_SPARE0_NV,GL_UNSIGNED_IDENTITY_NV,GL_RGB);
glCombinerInputNV(GL_COMBINER1_NV,GL_RGB,GL_VARIABLE_D_NV,GL_CONSTANT_COLOR1_NV,GL_UNSIGNED_INVERT_NV,GL_ALPHA);
glCombinerOutputNV(GL_COMBINER1_NV,GL_RGB,GL_DISCARD_NV,GL_DISCARD_NV,GL_SPARE1_NV,GL_NONE,GL_NONE,GL_FALSE,GL_FALSE,GL_FALSE);
glFinalCombinerInputNV(GL_VARIABLE_A_NV, GL_ZERO, GL_UNSIGNED_IDENTITY_NV, GL_RGB);
glFinalCombinerInputNV(GL_VARIABLE_B_NV, GL_ZERO, GL_UNSIGNED_IDENTITY_NV, GL_RGB);
glFinalCombinerInputNV(GL_VARIABLE_C_NV, GL_ZERO, GL_UNSIGNED_IDENTITY_NV, GL_RGB);
glFinalCombinerInputNV(GL_VARIABLE_D_NV, GL_SPARE1_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB);

Hopefully this is enough for you to go on (I don’t remember the effect itself very well but I can have a look if something is missing).

If you want the full source code, I can e-mail it to you.

Regards.

Eric

EDIT: Just remembered that this actually more than you need ! This piece of code also interpolates between the greyscale version and the colored one according to the alpha value of GL_CONSTANT_COLOR1_NV… Anyway, you should be able to remove the useless part !

[This message has been edited by Eric (edited 03-07-2002).]

Cheers Eric/Opla, much appreciated.

The spec implies

glCombinerInputNV(GL_COMBINER0_NV, GL_RGB
should be …
glCombinerInputNV(GL_RGB, GL_COMBINER0_NV

or am I just reading this wrong?

Head spinning lol

Thanks again

[This message has been edited by Shag (edited 03-07-2002).]

The specs says:

GLvoid glCombinerInputNV(GLenum stage,GLenum portion,GLenum variable,GLenum input,GLenum mapping,GLenum componentUsage);

Stage is GL_COMBINERi_NV and portion is GL_RGB or GL_ALPHA.

Why do you say that the specs imply the opposite ?

Regards.

Eric

it’s glCombinerInputNV(GL_COMBINER0_NV, GL_RGB, …

Arghh, Eric was faster …

Eric, je n’ai toujours pas reussi a t’envoyer d’email. a chaque fois j’ai un message d’erreur. peut-etre un filtre anti-spam …

sacre bleu!

I wrote down the params to each of the function - and for some reason swapped PORTION and STAGE around.

Some people are beyond help … no clues as to who!

If it’s of any use to anyone else, this works. But obviously there’s no lighting … yet

float Grey[4] = {0.3f, 0.59f, 0.11f, 1.0f};

glEnable(GL_REGISTER_COMBINERS_NV);
glCombinerParameteriNV(GL_NUM_GENERAL_COMBINERS_NV,1);
glCombinerParameterfvNV(GL_CONSTANT_COLOR0_NV, Grey);

glCombinerInputNV(GL_COMBINER0_NV,GL_RGB,GL_VARIABLE_A_NV,GL_TEXTURE0_ARB,GL_UNSIGNED_IDENTITY_NV,GL_RGB);
glCombinerInputNV(GL_COMBINER0_NV,GL_RGB,GL_VARIABLE_B_NV,GL_CONSTANT_COLOR0_NV,GL_UNSIGNED_IDENTITY_NV,GL_RGB);
glCombinerOutputNV(GL_COMBINER0_NV,GL_RGB,GL_SPARE0_NV,GL_DISCARD_NV,GL_DISCARD_NV,GL_NONE,GL_NONE,GL_TRUE,GL_FALSE,GL_FALSE);

glPushMatrix();
glRotated(yrot,0,0,1);
glCallList(2);
glPopMatrix();

glDisable(GL_REGISTER_COMBINERS_NV);

Regards

[This message has been edited by Shag (edited 03-07-2002).]

Where does 0.3, 0.59, and 0.11 come from?

Is this some magical gray-scale conversion numbers that some genius devised one day or something?

Originally posted by Nutty:
[b]Where does 0.3, 0.59, and 0.11 come from?

Is this some magical gray-scale conversion numbers that some genius devised one day or something?[/b]

Pretty much…

Yeah - it’s magic. I spent the last few weeks devising a method to accurately describe the luminunce value from an RGB input.

OK, I lied. I saw it in a post in here

Apparently it’s used to convert colour TV signals etc to B&W.

[This message has been edited by Shag (edited 03-07-2002).]

I don’t think you can find a method that would actually prove that these values are correct: they just reflect how each component (R,G,B) is seen in terms of luminance by the human eye.

Basically, green is the brightest, then comes red, and then blue.

I have searched the web for a scientific explanation but I suppose the guy who defined those values did a good old “trial’n’error” experiment !

Regards.

Eric

Aren’t these constants derived from the behaviour of an NTSC (Never The Same Color) scheme. (A happy PAL user )

Well, Roy Hall “Illumination And Color In Computer Generated Imagery” names a few other constants too, but in Section 5.2 “NTSC and RGB Video” footnote 15 you’ll find
Y = 0.299 * R + 0.587 * G + 0.114 * B.
which is one of the three components YIQ (cite) “used in some broadcast components and recording formats such as Betacam”.
For people interested in the two other components they are
I = 0.877 * (R-Y)
Q = 0.493 * (B-Y)

[This message has been edited by Relic (edited 03-08-2002).]

A sidenote … you don’t need register combiners to do this, the GL_ARB_texture_env_dot3 extension is sufficient and allows it to work on many cards, including the Radeon/GeForce/Kyro series.

glColor3f(0.3f, 0.59f, 0.11f);

glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_DOT3_RGBA_EXT);

glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PRIMARY_COLOR_ARB);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);

glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);

Not true, the dot3 extension doesn’t allow you to disable the implicit scale and bias of [0,1] to [-1,1].

  • Matt

Heh, reminds me I’ve done the same mistake once before on this forum proposing the same nonworking solution to the very same problem. You can make it work though with the dot3 extension, but you’ll burn another texture unit and loose some precision.

Can’t wait to get 64bit rendering so we can just store stuff and their real values instead of squeezing it into [0,1].