Register Combiner question

Hi,

I’m new at RC and I have some problem here.
I want to calculate a big polynomial for each texel and put the sum as the resulting rgb-value.

This is the info I got:
One texture with rgb values, called rgb
Two textures with constants, tex0 and tex1
One color vector in tengent space,called col1

What I want to calculate is this:

result = rgb * ((tex0.r * col.r * col.r) +
(tex0.g * col.g * col.g) +
(tex0.b * col.r * col.g) +
(tex1.r * col.r) +
(tex1.g * col.g) +
(tex1.b))

Anyone know how to do this?
Is it possible to access individual values within a texel?

Thanks,
-Ninja

Try to rewrite it with dotproducts:
rgb*(tex0 dot col0 + tex1 dot col1) and having c0 = (credcred, cgreencgreen, cred*cgreen) and col1 = (cred, cgreen, 1)

In the first combiner calculate the sum and in the final combiner you can multiply the sum by the rgb-texture.

kon

What is col.r and col.g ?
Are they constant colors, or are they primary or secondary colors ?

Also, what is rgb ? Is it a constant or not ?

rgb is a just a picture (texture) with rgb-values in each texel. So I want to calculate the formula and then multiply each of the r, g and b with it.

col.r and col.g are constant in the easiest case and then it will look like flat shading I guess.

but for smooth shading col.r and col.g has to be interpolated across the triangel.
I’m not sure how to do that though?
And how can I give the register combiner that information?

-Ninja

If rgb is a texture, then you have 3 textures : rgb, tex0 and tex1. Am I right ?

Interpolation can be done by OpenGL. Just call glColor before each call to glVertex, when smooth shading is enabled (ie glShadeModel(GL_SMOOTH)) and then get the ‘primary color’ register.

If col.r and col.g is NOT constant, then it will be more complicated, and probably you should use vertex programs.

Yes, I have 3 textures.

Ok, so the col.r and col.g can be interpolated using GL_SMOOTH operator. That sounds good to me, and then they are not constant I guess, but why is this more complicted?

-Ninja

Because if they are constants, then you can load (col.r, col.g, 1) in the RGB portion of the register ‘constant 0’ and load (col.rcol.r, col.gcol.g, col.r*col.g) in the RGB portion of the register ‘contant 1’ and it’s very easy.

But if colors are NOT constants, then at each fragment you have eg (col.r, col.g, 1) in RGB portion of the register ‘primary color’ and it’s much more complicated because you have to compute (col.rcol.r, col.gcol.g, col.r*col.g) in the general combiner stage(s).

(If you have 3 textures, then you need a graphics card that supports at least 3 texture units, eg GeForce3 or GeForce4Ti (not GeForce4MX))

If they are constant colors, do the following :

  1. load tex0 into RGB portion of texture 0
  2. load tex1 into RGB portion of texture 1
  3. load rgb into RGB portion of texture 2
  4. load (col.rcol.r, col.gcol.g, col.r*col.g) into RGB portion of constant 0
  5. load (col.r, col.g, 1) into RGB portion of constant 1
  6. request one general combiner stage

RGB portion of general combiner stage 0
7. assign the RGB portion of texture 0 into variable A
8. assign the RGB portion of constant 0 into variable B
9. assign the RGB portion of texture 1 into variable C
10. assign the RGB portion of constant 1 into variable D
11. output AB+CD in the RGB portion of spare 0, and discard the other two outputs

Alpha portion of general combiner stage 0
12. discard all outputs

Final combiner stage
13. assign the RGB portion of texture 2 into variable A
14. assign the RGB portion of spare 0 into variable B
15. assign zero into variables C and D

Ok, but is it possible to interpolate both the specular and the diffuse light over the triangel?

I would like to set one color (specular) to
(col.r, col.g, 1) in all vertics and interpolate over the tringel.

Then I would in the same way set the next color (diffuse) to (col.r, col.g, col.g) and interpolate it too.

Then I could just multiply them to get
(col.r * col.r, col.g * col.g, col.g) which is what I need.

Is that possible? Can I really set different specular and diffuse lights in each vertex?

-Ninja

But the colors are not constant, what can I do then?

-Ninja

lol. You’re writing exactly what I was about to post !
Yes it is possible to define separate primary and secondary colors, and yes both colors will be interpolated.

But you propose to set (col.r, col.g, 1) in specular and (col.r, col.g, col.g) in diffuse, and I don’t think it could work.
BUT if you set (col.r, col.g, col.r) in specular and (col.r, col.g, col.g) in diffuse, then it may be possible to make it all work together. I have to think of it…

I was planning to set one color to
(col.r, col.g, 1) just to get the sum of
(col.rcol.r, col.gcol.g, col.g) after the muliply.

Hmm… I tried to set different specular and diffuse light for all verics but their was atleast no visual effect. But it is still interpolated in some way?

-Ninja

I was planning to set one color to
(col.r, col.g, 1) just to get the sum of
(col.rcol.r, col.gcol.g, col.g) after the muliply.

But (col.rcol.r, col.gcol.g, col.g) is not what you need . You need (col.rcol.r, col.gcol.g, col.g*col.r).

To use separate primary and secondary colors, you have to use the EXT_secondary_color and EXT_separate_specular_color extensions.

I think I have a complete proposition, but it obviously requires more genral combiner stages. (I’m writing it down and post it in a few minutes…)

The idea is to use the a register combiner ‘constant’ that holds (1, 1, 0).

I’m going to use to fact that you feed glColor with (col.r, col.g, col.r) and glSecondaryColor with (col.r, col.g, col.g).
Note that you can commutate them and it will give the same results (I mean, feed glColor with (col.r, col.g, col.g) and so on with glSecondaryColor).

So here it is. I’m assuming it is working with RGB portions only. Just discard all outputs for Alpha portions.

In the register initial state, set :

constant0 = (1, 1, 0)
texture0 = tex0
texture1 = tex1
texture2 = rgb

Also glColor and glSecondaryColor (that automatically interpolates colors) feed those registers :

primary = (col.r, col.g, col.r)
secondary = (col.r, col.g, col.g)

Require 3 general combiner stages.

In the general combiner stage 0, do the following :

  • load primary into variable A
  • load constant0 into variable B
  • load zero into variable C with the input map UNSIGNED_INVERT
  • load constant0 into variable D with the input map UNSIGNED_INVERT
    So that the variables contain :

A = primary = (col.r, col.g, col.r)
B = constant0 = (1, 1, 0)
C = 1-zero = (1, 1, 1)
D = 1-constant0 = (0, 0, 1)

And then, output AB+CD into spare 0, and discard the other two outputs.
Detailed formulas :

spare0 = AB+CD
spare0 = (col.r, col.g, col.r)(1, 1, 0) + (1, 1, 1)(0, 0, 1)
spare0 = (col.r, col.g, 0) + (0, 0, 1)
spare0 = (col.r, col.g, 1)

In the general combiner stage 1, do the following :

  • load texture1 into variable A
  • load spare0 into variable B
  • load primary into variable C
  • load secondary into variable D
    So that the variables contain :

A = texture1 = (tex1.r, tex1.g, tex1.b)
B = spare0 = (col.r, col.g, 1)
C = primary = (col.r, col.g, col.r)
D = secondary = (col.r, col.g, col.g)

Output A.B into spare 0, output CD into spare 1, and discard the other output.
Detailed formulas :

spare0 = A.B
spare0 = (tex1.r, tex1.g, tex1.b).(col.r, col.g, 1)
spare0 = (tex1.rcol.r) + (tex1.gcol.g) + (tex1.b1)
spare0 = (tex1.r
col.r) + (tex1.g*col.g) + tex1.b

spare1 = CD
spare1 = (col.r, col.g, col.r)(col.r, col.g, col.g)
spare1 = (col.r
col.r, col.gcol.g, col.rcol.g)

In the general combiner stage 2, do the following :

  • load texture0 into variable A
  • load spare1 into variable B
  • load texture2 into variable C
  • load spare0 into variable D
    So that the variables contain :

A = texture0 = (tex0.r, tex0.g, tex0.b)
B = spare1 = (col.rcol.r, col.gcol.g, col.rcol.g)
C = texture2 = rgb
D = spare0 = (tex1.r
col.r) + (tex1.g*col.g) + tex1.b

Output A.B into spare 0, output CD into spare 1, and discard the other output.
Detailed formulas :

spare0 = A.B
spare0 = (tex0.r, tex0.g, tex0.b).(col.rcol.r, col.gcol.g, col.rcol.g)
spare0 = (tex0.r
col.rcol.r) + (tex0.gcol.gcol.g) + (tex0.bcol.r*col.g)

spare1 = CD
spare1 = rgb * ((tex1.rcol.r) + (tex1.gcol.g) + tex1.b)

In the Final combiner stage, do the following :

  • load texture2 into variable A
  • load spare0 into variable B
  • load zero into variable C
  • load spare1 into variable D
    So that the variables contain :

A = texture2 = rgb
B = spare0 = (tex0.rcol.rcol.r) + (tex0.gcol.gcol.g) + (tex0.bcol.rcol.g)
C = texture2 = (0, 0, 0)
D = spare0 = rgb * ((tex1.rcol.r) + (tex1.gcol.g) + tex1.b)

And so that the output is :

RGBout = AB+(1-A)C+D
RGBout = rgb*((tex0.rcol.rcol.r) + (tex0.gcol.gcol.g) + (tex0.bcol.rcol.g)) + (1-A)(0,0,0) + rgb * ((tex1.rcol.r) + (tex1.gcol.g) + tex1.b)
RGBout = rgb
((tex0.rcol.rcol.r) + (tex0.gcol.gcol.g) + (tex0.bcol.rcol.g) + (tex1.rcol.r) + (tex1.gcol.g) + tex1.b)

That’s it, hopefully.

I think it’s possible to use only 2 general combiner stages thanks to Alpha registers, but I’m not going to try it today

Hope this helps !

Thanks man, this look great!

-Ninja

I could have written the code, but it’s much less explicit.

Does your card support 3 texture units and 3 general combiner stages ?

BTW, you should forget the implementation of “constant colors” case that I’ve written a few posts above because I just seen it needs a little modification to work :
instead of outputting AB+CD into spare 0, you should output A.B into spare0 and C.D into spare1, and then in the final combiner stage :

  • assign texture2 to variable A
  • assign spare0 to variable B
  • assign zero to variable C
  • assign texture2 to variable E
  • assign spare1 to variable F
  • assign E.F to variable D

Ok, how do I do this?

  • assign E.F to variable D

My code look like this now, what do you think?

glEnable(GL_REGISTER_COMBINERS_NV);
glCombinerParameteriNV(GL_NUM_GENERAL_COMBINERS_NV, 1);

glCombinerParameterfvNV(GL_CONSTANT_COLOR0_NV, col0);
glCombinerParameterfvNV(GL_CONSTANT_COLOR1_NV, col1);

glCombinerInputNV(GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_A_NV, GL_TEXTURE0_ARB,       GL_EXPAND_NORMAL_NV, GL_RGB);
glCombinerInputNV(GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_B_NV, GL_CONSTANT_COLOR0_NV, GL_EXPAND_NORMAL_NV, GL_RGB);
glCombinerInputNV(GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_C_NV, GL_TEXTURE1_ARB,       GL_EXPAND_NORMAL_NV, GL_RGB);
glCombinerInputNV(GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_D_NV, GL_CONSTANT_COLOR1_NV, GL_EXPAND_NORMAL_NV, GL_RGB);

glCombinerOutputNV(GL_COMBINER0_NV, GL_RGB, GL_SPARE0_NV, GL_SPARE1_NV, GL_DISCARD_NV, 
				   GL_NONE, GL_NONE, GL_TRUE, GL_TRUE, GL_FALSE);


glFinalCombinerInputNV(GL_VARIABLE_A_NV, GL_TEXTURE2_ARB,          GL_UNSIGNED_IDENTITY_NV, GL_RGB);
glFinalCombinerInputNV(GL_VARIABLE_B_NV, GL_SPARE0_NV,             GL_UNSIGNED_IDENTITY_NV, GL_RGB);

glFinalCombinerInputNV(GL_VARIABLE_E_NV, GL_TEXTURE2_ARB, GL_UNSIGNED_IDENTITY_NV, GL_RGB);
glFinalCombinerInputNV(GL_VARIABLE_F_NV, GL_SPARE1_NV,    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_ZERO, GL_UNSIGNED_IDENTITY_NV, GL_RGB);   // NEED TO BE FIXED!

The code looks ok, but why do you use GL_EXPAND_NORMAL_NV ? Do you want to use signed values ?

For E.F, do this :
glFinalCombinerInputNV(GL_VARIABLE_D_NV, GL_E_TIMES_F_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB);

Also, you should discard all outputs for Alpha portion :
glCombinerOutputNV(GL_COMBINER0_NV, GL_ALPHA, GL_DISCARD_NV, GL_DISCARD_NV, GL_DISCARD_NV, GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE);

Right, it is not possible to compute E.F, it computes EF. I don’t know why I’ve written E.F, anyway the algorithm is correct as it is.