Problems with EnvCombiners

Hi

I´m rewriting some stuff to make it run on a Radeon.
What i want to do is, to take the dot-product between a texel and the (1,1,1) vector, which should give me the average brightness of a texel. I want to put this into the alpha channel to use it in the alpha-test.

This is the working register-combiners code:

glEnable (GL_REGISTER_COMBINERS_NV);
glCombinerParameteriNV(GL_NUM_GENERAL_COMBINERS_NV, 1);
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_ZERO,
GL_UNSIGNED_INVERT_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);

  		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_ZERO, 
  			GL_UNSIGNED_IDENTITY_NV, GL_RGB);

  		glFinalCombinerInputNV (GL_VARIABLE_G_NV, GL_SPARE0_NV, 
  			GL_UNSIGNED_IDENTITY_NV, GL_BLUE);

And this is my EnvironmentCombiner code:

ActivateTextureUnit (0);
float constant[4] = {1.0f, 1.0f, 1.0f, 1.0f};
glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, constant);
glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_DOT3_RGBA_ARB);
glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_CONSTANT);
glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);

The latter doesn´t work properly. I don´t know why. It must have something to do with the constant color, i´m not sure if i am setting it right.
Can someone see any error?

Thanks,
Jan.

the reason is probably that dot3_rgb{a} does a signed dot product, it uncompresses both operands from [0,1] to [-1,1] and does the dotproduct then , so it interpretes the dark areas of the texture as -1, the values around 0.5 as 0 in the dp calculation.

maybe you can use the ATI_texture_env_combine3 extension to scale by 0.5 and bias by 0.5 the texture, bringing it over 0.5 --> the signed dp should work then. of course you lose precision and use an additional texture unit, or do this as a preprocessing step before uploading the texture

check the spec for the exact formula.

i actually tested it with setup using 1 texunit for the scale, one for the bias and one for the dotproduct. the scale value is 0.125, this seemed to fit quite well by visual inspection, probably not very correct mathematicly
http://www.sund.de/schott/storage/gl_env_combine.jpg

// OpenGL texture environment
// file generated by gl_tut texture environment

//----------------
//|texture unit 0|
//----------------
GLuint tex_id0;
GLfloat env_color0[4] = {0.125000f,0.125000f,0.125000f,1.000000f};
GLint rgb_scale0 = 1;
GLint alpha_scale0 = 1;

glActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTUE_2D,tex_id0);

glTexEnvfv(GL_TEXTURE_ENV,GL_TEXTURE_ENV_COLOR,env_color0);
glTexEnvi (GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE);

// RGB combiner setup
glTexEnvi (GL_TEXTURE_ENV,GL_COMBINE_RGB,GL_MODULATE);
glTexEnvi (GL_TEXTURE_ENV,GL_RGB_SCALE,rgb_scale0);
// arg 0
glTexEnvi (GL_TEXTURE_ENV,GL_SOURCE0_RGB,GL_TEXTURE);
glTexEnvi (GL_TEXTURE_ENV,GL_OPERAND0_RGB,GL_SRC_COLOR);
// arg 1
glTexEnvi (GL_TEXTURE_ENV,GL_SOURCE1_RGB,GL_CONSTANT);
glTexEnvi (GL_TEXTURE_ENV,GL_OPERAND1_RGB,GL_SRC_COLOR);

// ALPHA combiner setup
glTexEnvi (GL_TEXTURE_ENV,GL_COMBINE_ALPHA,GL_MODULATE);
glTexEnvi (GL_TEXTURE_ENV,GL_ALPHA_SCALE,alpha_scale0);
// arg 0
glTexEnvi (GL_TEXTURE_ENV,GL_SOURCE0_ALPHA,GL_PREVIOUS);
glTexEnvi (GL_TEXTURE_ENV,GL_OPERAND0_ALPHA,GL_SRC_ALPHA);
// arg 1
glTexEnvi (GL_TEXTURE_ENV,GL_SOURCE1_ALPHA,GL_TEXTURE);
glTexEnvi (GL_TEXTURE_ENV,GL_OPERAND1_ALPHA,GL_SRC_ALPHA);

//----------------
//|texture unit 1|
//----------------
GLuint tex_id1;
GLfloat env_color1[4] = {0.500000f,0.500000f,0.500000f,1.000000f};
GLint rgb_scale1 = 1;
GLint alpha_scale1 = 1;

glActiveTexture(GL_TEXTURE1);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTUE_2D,tex_id1);

glTexEnvfv(GL_TEXTURE_ENV,GL_TEXTURE_ENV_COLOR,env_color1);
glTexEnvi (GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE);

// RGB combiner setup
glTexEnvi (GL_TEXTURE_ENV,GL_COMBINE_RGB,GL_ADD);
glTexEnvi (GL_TEXTURE_ENV,GL_RGB_SCALE,rgb_scale1);
// arg 0
glTexEnvi (GL_TEXTURE_ENV,GL_SOURCE0_RGB,GL_PREVIOUS);
glTexEnvi (GL_TEXTURE_ENV,GL_OPERAND0_RGB,GL_SRC_COLOR);
// arg 1
glTexEnvi (GL_TEXTURE_ENV,GL_SOURCE1_RGB,GL_CONSTANT);
glTexEnvi (GL_TEXTURE_ENV,GL_OPERAND1_RGB,GL_SRC_COLOR);

// ALPHA combiner setup
glTexEnvi (GL_TEXTURE_ENV,GL_COMBINE_ALPHA,GL_MODULATE);
glTexEnvi (GL_TEXTURE_ENV,GL_ALPHA_SCALE,alpha_scale1);
// arg 0
glTexEnvi (GL_TEXTURE_ENV,GL_SOURCE0_ALPHA,GL_PREVIOUS);
glTexEnvi (GL_TEXTURE_ENV,GL_OPERAND0_ALPHA,GL_SRC_ALPHA);
// arg 1
glTexEnvi (GL_TEXTURE_ENV,GL_SOURCE1_ALPHA,GL_TEXTURE);
glTexEnvi (GL_TEXTURE_ENV,GL_OPERAND1_ALPHA,GL_SRC_ALPHA);

//----------------
//|texture unit 2|
//----------------
GLuint tex_id2;
GLfloat env_color2[4] = {1.000000f,1.000000f,1.000000f,1.000000f};
GLint rgb_scale2 = 1;
GLint alpha_scale2 = 1;

glActiveTexture(GL_TEXTURE2);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTUE_2D,tex_id2);

glTexEnvfv(GL_TEXTURE_ENV,GL_TEXTURE_ENV_COLOR,env_color2);
glTexEnvi (GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE);

// RGB combiner setup
glTexEnvi (GL_TEXTURE_ENV,GL_COMBINE_RGB,GL_DOT3_RGBA);
glTexEnvi (GL_TEXTURE_ENV,GL_RGB_SCALE,rgb_scale2);
// arg 0
glTexEnvi (GL_TEXTURE_ENV,GL_SOURCE0_RGB,GL_PREVIOUS);
glTexEnvi (GL_TEXTURE_ENV,GL_OPERAND0_RGB,GL_SRC_COLOR);
// arg 1
glTexEnvi (GL_TEXTURE_ENV,GL_SOURCE1_RGB,GL_CONSTANT);
glTexEnvi (GL_TEXTURE_ENV,GL_OPERAND1_RGB,GL_SRC_COLOR);

// ALPHA combiner setup
// result of GL_COMBINE_ALPHA is ignored if GL_COMBINE_RGB==GL_DOT3_RGBA

[This message has been edited by ScottManDeath (edited 11-29-2003).]

Damn! That´s true, i didn´t know that it does a signed dot-product.
Well, i have to see if i can work around that.

Thanks for your help, i would never have thought of that.

Jan.

Ok, other problem:

ActivateTextureUnit (3);
glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS_ARB);
glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_CONSTANT_ARB);
glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);

This piece of code acts as if the textureunit 3 was either not enabled or the constant color was set to 1. Both is not the case. It simply does nothing.

The unit 3 is enabled, but i don´t bind a texture to it, since i really only need this unit to modulate the previous stuff by my constant color.

If i bind some texture to unit 3, it acts as if the constant-color was set to the texture-color.

Weird! Is that an additional f****** restriction of the texture combiners???

Thanks,
Jan.

[This message has been edited by Jan2000 (edited 11-30-2003).]

you have to bind a dummy texture and enable it, otherwise the texture unit outputs white(1.0f)

maybe you count the texture units wrong, activating a texture unit 3 works only on a 4+ tex unit card, so not on a radeon < 8500, they just have 3 texture units

if you use a radeon 8500, why not use ATI_fragment_shader?

Dotting with 1,1,1 doesn’t give you the luminance, even after your input RGB has been scaled/offset.

Step one would be to factor in the division by three, and dot with 0.33, 0.34, 0.33. This will give you white for white, and gray for gray, rahter than white for white and white for grays (all the way down to grays of about 1/3 fullbright) which you have now.

Step two would be to use a common formula for luminance to get a better match of color space. Something like:

L = 0.299 Red + 0.587 Green + 0.114 Blue

which can be expressed as dotting your pixel with 0.299,0.587,0.114. This is likely to match the response you’d get if you “turn down the color” on a TV set, say.

Step three would be to do this in linear space, not the implied-gamma space most typical texture maps are stored in. You’d need a number of dependent reads to do that, however.

I work on a Gf 4200, so i got 4 units. I don´t have a Radeon, i have a friend who tests it for me.

I do enable the unit. However when i bind a texture to it, i don´t get my constant color, but some other color, which is strange, since the constant color should not be affected by this.

Jan.

You did remember that each texture unit has its own constant color, right? Other than that, the texture env setup looks correct.

I’m not sure if you need a texture bound to the unit or not. I seem to recall the spec saying that if a texture isn’t bound to a unit, the result of the texture look-up will be {1, 1, 1, 1}. You’d have to look at the spec to be sure, though.

Originally posted by idr:
[b]You did remember that each texture unit has its own constant color, right? Other than that, the texture env setup looks correct.

I’m not sure if you need a texture bound to the unit or not. I seem to recall the spec saying that if a texture isn’t bound to a unit, the result of the texture look-up will be {1, 1, 1, 1}. You’d have to look at the spec to be sure, though.[/b]

What the spec says is that (free rephrasing ahead) if any of the texture state is inconsistent, is “as if texturing was disabled”. Not having a texture bound falls into this “inconsistent texture state” category.

When you aren’t dealing with multitexturing, this normally means a texture color of 1,1,1,1 whenever you use GL_TEXTURE as input of your first stage combiner.

When you deal with multitexturing it means that the given texture stage is disabled, so no color calculations happens for that stage no matter you read the texture input or not.

This is the discrepancy between Nvidia’s ENV_COMBINE4 and ARB’s TEXTURE_CROSSBAR extensions and the reason why Nvidia doesn’t support crossbar.

A bit more info:

Texture crossbar

If a texture environment for a given texture unit references a texture unit that is disabled or does not have a valid texture object bound to it, then it is as if texture blending is disabled for the given texture unit. Every texture unit implicitly references the texture object that is bound to it, regardless of the texture function specified by COMBINE_RGB_ARB or COMBINE_ALPHA_ARB.

while

Combine4

The arguments Arg0, Arg1, Arg2 and Arg3 are determined by the values
of SOURCE<n>_RGB_EXT, SOURCE<n>_ALPHA_EXT, OPERAND<n>_RGB_EXT and OPERAND<n>_ALPHA_EXT. In the following two tables, Ct and At are the filtered texture RGB and alpha values; Cc and Ac are the texture environment RGB and alpha values; Cf and Af are the RGB and alpha of the primary color of the incoming fragment; and Cp and Ap are the RGB and alpha values resulting from the previous texture environment. On texture environment 0, Cp and Ap are identical to Cf and Af, respectively. Ct<n> and At<n> are the filtered texture RGB and alpha values from the texture bound to the <n>th texture unit. If the <n>th texture unit is disabled, the value of each component is 1. The relationship is described in tables 3.22 and 3.23.

[This message has been edited by evanGLizr (edited 12-01-2003).]