PDA

View Full Version : Register Combiner question



Ninja
07-24-2002, 04:22 AM
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

kon
07-24-2002, 05:08 AM
Try to rewrite it with dotproducts:
rgb*(tex0 dot col0 + tex1 dot col1) and having c0 = (cred*cred, cgreen*cgreen, 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

vincoof
07-24-2002, 05:58 AM
What is col.r and col.g ?
Are they constant colors, or are they primary or secondary colors ?

vincoof
07-24-2002, 06:39 AM
Also, what is rgb ? Is it a constant or not ?

Ninja
07-24-2002, 07:24 AM
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

vincoof
07-24-2002, 08:09 AM
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.

Ninja
07-24-2002, 01:36 PM
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

vincoof
07-25-2002, 12:07 AM
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.r*col.r, col.g*col.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.r*col.r, col.g*col.g, col.r*col.g) in the general combiner stage(s).

vincoof
07-25-2002, 12:18 AM
(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.r*col.r, col.g*col.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

Ninja
07-25-2002, 12:18 AM
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

vincoof
07-25-2002, 12:33 AM
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...

Ninja
07-25-2002, 12:33 AM
But the colors are not constant, what can I do then?

-Ninja

Ninja
07-25-2002, 12:37 AM
I was planning to set one color to
(col.r, col.g, 1) just to get the sum of
(col.r*col.r, col.g*col.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

vincoof
07-25-2002, 12:48 AM
I was planning to set one color to
(col.r, col.g, 1) just to get the sum of
(col.r*col.r, col.g*col.g, col.g) after the muliply.
But (col.r*col.r, col.g*col.g, col.g) is not what you need . You need (col.r*col.r, col.g*col.g, col.g*col.r).

To use separate primary and secondary colors, you have to use the EXT_secondary_color (http://oss.sgi.com/projects/ogl-sample/registry/EXT/secondary_color.txt) and EXT_separate_specular_color (http://oss.sgi.com/projects/ogl-sample/registry/EXT/separate_specular_color.txt) 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...)

vincoof
07-25-2002, 01:56 AM
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.r*col.r) + (tex1.g*col.g) + (tex1.b*1)
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.g*col.g, col.r*col.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.r*col.r, col.g*col.g, col.r*col.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.r*col.r, col.g*col.g, col.r*col.g)
spare0 = (tex0.r*col.r*col.r) + (tex0.g*col.g*col.g) + (tex0.b*col.r*col.g)

spare1 = CD
spare1 = rgb * ((tex1.r*col.r) + (tex1.g*col.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.r*col.r*col.r) + (tex0.g*col.g*col.g) + (tex0.b*col.r*col.g)
C = texture2 = (0, 0, 0)
D = spare0 = rgb * ((tex1.r*col.r) + (tex1.g*col.g) + tex1.b)

And so that the output is :



RGBout = AB+(1-A)C+D
RGBout = rgb*((tex0.r*col.r*col.r) + (tex0.g*col.g*col.g) + (tex0.b*col.r*col.g)) + (1-A)*(0,0,0) + rgb * ((tex1.r*col.r) + (tex1.g*col.g) + tex1.b)
RGBout = 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)


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 http://www.opengl.org/discussion_boards/ubb/smile.gif

Hope this helps !

Ninja
07-25-2002, 02:38 AM
Thanks man, this look great!

-Ninja

vincoof
07-25-2002, 03:44 AM
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

Ninja
07-25-2002, 04:01 AM
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!

vincoof
07-25-2002, 04:44 AM
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);

vincoof
07-25-2002, 04:57 AM
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.

Ninja
07-25-2002, 05:11 AM
I'm not sure why I use GL_EXPAND_NORMAL_NV.
I guess I cut it from some bumpmap demo.
Shall I change it to GL_UNSIGNED_IDENTITY_NV?

What happens if I don't discard all outputs
for Alpha portion?

-Ninja

vincoof
07-25-2002, 06:14 AM
Originally posted by Ninja:
I'm not sure why I use GL_EXPAND_NORMAL_NV.
I guess I cut it from some bumpmap demo.
lol. I'm currently using this document as register combiners reference document http://www.opengl.org/discussion_boards/ubb/smile.gif
Moreover when I saw your code, the first time I thought "ah he's plainly copy-pasting the sample code" !


Shall I change it to GL_UNSIGNED_IDENTITY_NV?
Yes you should.


What happens if I don't discard all outputs
for Alpha portion?
If you don't configure alpha portion, then the latest configuration will be kept. Since this algorithm never use any alpha portion, that's not a problem. But in practice there's a matter of performance : when you explicitly tell OpenGL to discard all outputs, then OpenGL will certainly skip any computation on this portion.