DOT3 Texture Lighting

I currently have a 3D texture map containing a normalized gradient vector as RGB data. I am passing this to a register combiner using the DOT3 extension to simulate diffuse lighting. One issue I am experiencing is that the texture values are clamped to the range [0, 1] upon loading. The gradient can contain values that are negative. The clamping causes these “negative” surfaces to be incorrectly lit.

I am currently trying to store the gradient after dividing by 2 and shifting it 0.5 to move its range from [-1, 1] to [0, 1] in each dimension. I am then trying to undo these operations in multiple texture targets using the combiners.

Is there a better approach?

if you use arb_tex_env_dot3 and not nv register combiners you wont need to do the unpack manually and it will run on more hardware. but probably you need nvrc for other more complex operations…

Originally posted by jtipton:
I am then trying to undo these operations in multiple texture targets using the combiners.

What do you mean by “multiple texture targets”? Register combiners have modifiers on inputs to combiner stage which can do exactly this conversion.

The combiners for TEXTURE0 are loading the normal map
The combiners for TEXTURE1 are biasing and scaling the result of the previous unit
The combiners for TEXTURE2 are performing the DOT3 on the result of the previous unit and the primary color

Only standard OGL texture environments (GL_TEXTURE_ENV) are associated with texture units. NV register combiners are independent on texture units and can calculate this entire operation, including the dot product, in single combiner unit using input modifiers.

I am running on an ATI Radeon 9800, so the NV extension is not available to me. How do you typically account for a gradient vector with one or more negative dimensions if the gradient will be clamped when stored as an RGB texture?

Originally posted by jtipton:
I am running on an ATI Radeon 9800, so the NV extension is not available to me.

If you need compatibility with older hw, the ARB_texture_env_dot3 extension suggested by CrazyButcher does this bias and scale as part of the dot3 operation. If you do not need that compatibility, you can go for ARB_fragment_program or GLSL shaders.


How do you typically account for a gradient vector with one or more negative dimensions if the gradient will be clamped when stored as an RGB texture?

By biasing and scaling it like you do.

I am doing the scaling and bias but only portions of the volume are being lit. Portions whose gradients had a negative component are still being clamped to 0. My logic looks like this.

  1. Calculate gradient for each voxel {x,y,z}.
  2. Divide this vector by 2
  3. Add 0.5 to each component
  4. Store as an RGB texture.
  5. Set the primary color to the light direction
  6. Perform multitexturing as follows:
    • TEXTURE0 replace the fragment color with the normal
    • TEXTURE1 subtracts 0.5 from the previous unit, then scales the result by 2
    • TEXTURE2 performs DOT3 between the previous unit and the primary color

What am I missing here?
Is clamping performed between each texturing unit?
Is there a good open source piece of code that performs shading without fragment or vertex programs?


Is clamping performed between each texturing unit?

Yes it is. Values are clamped into <0,1> range.

I always thought that the values were clamped upon texture creation, and upon writing to the framebuffer. I didn’t think it occured between texture units in the texturing pipeline. I now have my application working using the algorithm above. It shouldn’t work if clamping occurs between units.

Everything is now working, so thank you all.