How to use NVs HILO textures for BM?

Hi,

I read in the last NV Developer Relations Newsletter, that one can use the HILO8 or HILO16 format for Normalmaps (which seems much better, than RGBA textures).

But how can I build such a normalmap and where will the Z component be computed (z = sqrt(1 - x^2 - y^2)) … in the Combiners?

Any hints would be great,
Diapolo

HILO textures are only available to the texture shaders (NV_texture_shader) and fragment programs (NV_fragment_program and ARB_fragment_program). You can not directly access a HILO texture in the combiners.

OK, texture shaders come before the RCs (saw that in a presentation).

But how do they interact?
And how can I use and BUILD these HILO textures?

Which NV presentation should I read through g ?

I´ve only used RCs so far, but not Texture Shaders …

Diapolo

Just make one just like you would for an RGB texture, only leave out the B (Z) channel.

HI=Red (or X)
LO=Green (or Y)

The only thing you’ll probably have to do different is pass it as short or ushort to glTexImage2D.

Edit:
Just don’t forget to set the external and internal formats to HILO

[This message has been edited by NitroGL (edited 01-26-2003).]

Take at look at this presentation: http://developer.nvidia.com/view.asp?IO=texture_shaders for more information on texture shaders.

I read the presentation and I´m sure I have to use the Dot Product Texture 2D.

But what is unclear to me is, what really happens or how I use the results in the RCs.

Currently (the RC setup I use at the moment) I have Tex0 = Normalmap, Tex1 = Normalisation Cubemap for L, Tex2 = Normalisation Cubemap for H and Tex3 = base texture.

The texture shader operation generates a scalar, that is stored in every component (RGBA).

So I would do Tex1 <dot> Tex2 and Tex1 <dot> Tex3, but where is the result stored ?

And another thing.
I use the NV Normalmap tool for generating my Normalmaps, but I guess this won´t export to HILO format … so how can I build them (don´t want to do it by myself g).

Regards,
Diapolo

But what is unclear to me is, what really happens or how I use the results in the RCs
There is no way to use HILO value in RC (yes, i was disappointed too)

IMHO is very unfortunate, it would be very useful to have ability to simply cast 16-bit HILO into 8-bit RGBA (HI into RG, and LO into BA) in texture shader, and reverse it with CopyTexImage. This would allow amazing effects…

The texture shader operation generates a scalar, that is stored in every component (RGBA)
No, DOT_PRODUCT_xxxx generates scalar, that is used as texture coordinate in subsequent texture lookup - the “dependant read”. The only use of the HILO is to extend precision of the lookup, because with only 8-bit you may end up having no fractional part of the texture coordinate, so the effect of the dependent texture read will look as if it had GL_NEAREST filter set.

The only situation when the scalar is “stored in every component (RGBA)” is in DOT_PRODUCT_PASS_THROUGH instruction, but:

  • it requires NV_texture_shader3, so it works only on GF4, not on GF3
  • trying to use the RGBA value in RC gets you back to 8 bit precision
    (I’m not sure, but i would bet it is truncated immediately in texture shader)

Frankly, i find HILO not useful for anything real

OK, the thing I wanted to use the texture shader for is the specular lighting.
If I do N.H^16 in the RCs with an RGB Normalmap, the specular lighting produces ugly color banding artifacts and looks like the specular lighting would be filtered with nearest filtering.
I thought to avoid that, I could use 16 Bit per component in a normal map.

But how to do that is unclear to me, could anyone tell me how to do that with the texture shader?

Diapolo

OK, I know the code, I have to use for the texture shaders, for doing the dot product.

glActiveTextureARB(GL_TEXTURE0_ARB);
glBindTexture(GL_TEXTURE_2D, gluiNormalmapTexture);
glTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, GL_TEXTURE_2D);

glActiveTextureARB(GL_TEXTURE1_ARB);
glTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, GL_DOT_PRODUCT_NV);
glTexEnvi(GL_TEXTURE_SHADER_NV, GL_PREVIOUS_TEXTURE_INPUT_NV, GL_TEXTURE0_ARB);

glActiveTextureARB(GL_TEXTURE2_ARB);
glTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, GL_DOT_PRODUCT_TEXTURE_2D_NV);
glTexEnvi(GL_TEXTURE_SHADER_NV, GL_PREVIOUS_TEXTURE_INPUT_NV, GL_TEXTURE0_ARB);

Tex0 = Normalmap
Tex1 = Lightvector in TS
Tex2 = Half-Angle Vector in TS

The above code does Tex0 <dot> Tex1 and Tex0 <dot> Tex2, but OutCol for Tex1 is 0,0,0,0. For Tex2 it is RGBA.
One OutCol for 2 dot products?
How can I use Tex2 in the RCs for doing N.H^16 but not N.L?

I´m getting really confused … Help!

Diapolo

[This message has been edited by Diapolo (edited 01-28-2003).]

have you taken a look at the cg_bump_mapping demo in the Cg Toolkit? It does pretty much what you want using the fp20 Cg profile (which compiles to nvparse register combiner and texture shader code) and should be fairly easy to understand.

I´ll have a look at that demo, but be sure: I´ll be back .

Diapolo

OK, now I´m even more confused.
That demo is everything, but not straightforward .

What is that lookuptexture used for?

Someone could explain me the real differences between the RC only thing and the TS / RC thing.

I use some combiner stages to square the specular component and have got a normalisation cubemap (for L and H).

How is the way with texture shaders???

Diapolo

The lookup texture encodes a high quality N.H^128 and N.L into a look up table that is fetched from using the texture shaders.

Once you have this texture you setup your texture units (all 2D textures) like this:

tex0: decal
tex1: normal map
tex2: lookup table

and your texture coordinates like this:

texcoord0: decal texcoords
texcoord1: normal map texcoords
texcoord2: light vector
texcoord3: half angle vector

and your texture shader’s like this:

tex0: texture_2d();
tex1: texture_2d();
tex2: dot_product_2d_1of2(tex1);
tex3: dot_product_2d_2of2(tex1);

this texture shader setup will fetch the normal from the normal map (tex1), then perform two dot products to calculate the s and t values like so:

s = dot(lightVec, normal);
t = dot(halfVec, normal);

which are then used to lookup into the lookup table bound to tex2.

The result of the texture shader operation is then available to the register combiners in tex2 so tex2.rgb will hold the result of N.L and tex2.a will hold the result of N.H^128.

You can do essentially the same thing with just the register combiners but you won’t get the high quality normal map, the high precision dot product, or the high precision exponent for the specular.

A great, that is what I call THE answer, thank you very much .

But a few additional questions:

  1. What about the Cubemap Normalisation, is that still needed?

  2. Could the lookup texture be a pre-computed one or where do I find such one?

  3. The algo for creating the lookup texture is in the CG demo you mentioned, but what does it exactly do (RGB part is used for diffuse and Alpha for specular?)?

  4. Are there any tools, that create HILO Normalmaps for me (an updated version of the NV tool would be cool g)?

Diapolo

[This message has been edited by Diapolo (edited 01-28-2003).]

  1. Normalizing the vectors in the vertex shader should be fine.

  2. You can use the make_lookup_texture function in the cg_bump_mapping demo.

  3. Its actually a luminance alpha texture so the luminance channel holds the diffuse and the alpha holds the specular.

  4. Not that I know of but if your texture is stored as a heightmap on disk you can use the bumpmap_to_normalmap function to generate a high quality floating point normal map and then load the x and y components of each normal as your HILO texture (the z will get computed in the texture shaders). This is what the cg_bump_mapping demo does.

I tried to use my existing unsigned RGB (no A) normalmap with the texture shader, but it produces strange artifacts.

I´ve got the following setup:

bound textures:
tex0 = Normalmap
tex1 = none
tex2 = lookup texture
tex3 = base texture

tex coords:
tex0 = normalmap (2D tex / S, T)
tex1 = light vector in TS (S, T, R)
tex2 = half-angle vector in TS (S, T, R)
tex3 = base texture (2D tex / S, T)

And here is my TS code:

glActiveTextureARB(GL_TEXTURE0_ARB);
glBindTexture(GL_TEXTURE_2D, gluiNormalmapTexture);
glTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, GL_TEXTURE_2D);

glActiveTextureARB(GL_TEXTURE1_ARB);
glTexEnvi(GL_TEXTURE_SHADER_NV, GL_RGBA_UNSIGNED_DOT_PRODUCT_MAPPING_NV, GL_EXPAND_NORMAL_NV);
glTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, GL_DOT_PRODUCT_NV);
glTexEnvi(GL_TEXTURE_SHADER_NV, GL_PREVIOUS_TEXTURE_INPUT_NV, GL_TEXTURE0_ARB);

glActiveTextureARB(GL_TEXTURE2_ARB);
glBindTexture(GL_TEXTURE_2D, make_lookup_texture(128));
glTexEnvi(GL_TEXTURE_SHADER_NV, GL_RGBA_UNSIGNED_DOT_PRODUCT_MAPPING_NV, GL_EXPAND_NORMAL_NV);
glTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, GL_DOT_PRODUCT_TEXTURE_2D_NV);
glTexEnvi(GL_TEXTURE_SHADER_NV, GL_PREVIOUS_TEXTURE_INPUT_NV, GL_TEXTURE0_ARB);

glActiveTextureARB(GL_TEXTURE3_ARB);
glBindTexture(GL_TEXTURE_2D, gluiBaseTexture);
glTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, GL_TEXTURE_2D);

In the RCs I only use Tex2 as variable D, to see what´s happening there.

What could be wrong here?

Diapolo

[This message has been edited by Diapolo (edited 01-29-2003).]

Oh and I can´t use the make_normalmap algo from that demo.
What are the steps to convert a RGB Normalmap with 8 Bits per Component into the HILO16 format, which has 16 Bits per Component?

Diapolo

The way you bind your textures is important, the normalmap needs to be found in the texture unit before the lookup table, and nothing can be bound to the texture unit after the lookup table.

It has to be something like this:

tex0: normal map
tex1: lookup table
tex2: nothing
tex3: decal

Then setup your texture shader settinga appropriately.

To change your normal map to a HILO texture you’ll have to loop through all the pixels in your normal map and copy them into an array of GLshort’s like in the make_normalmap_texture function. You only need to copy the x and y values from each normal into the hilo map as the z portion will be recomputed by the texture shaders. You’ll notice that each component is multiplied by 32767 when its copied into the hilo map, this is to expand it from floating point to an integer representation.

If I use DOTPRODUCT_TEXTURE_2D, then the second TS stage has not got any textures bound.
The third one should be the lookup texture (because the third one generates RGBA values, while the second one is zero for RGBA).

Or am I reading the specs for that texture shader operation wrong???

Diapolo

you would have your texture shaders setup like this

tex0: TEXTURE_2D
tex1: DOT_PRODUCT_NV
tex2: DOT_PRODUCT_TEXTURE_2D_NV
tex3: TEXTURE_2D

so the color would get output from the DOT_PRODUCT_TEXTURE_2D_NV stage and would be available as tex2 in the register combiners.