PDA

View Full Version : How to use NVs HILO textures for BM?



Diapolo
01-25-2003, 02:09 AM
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

jra101
01-25-2003, 09:29 AM
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.

Diapolo
01-26-2003, 06:31 AM
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* http://www.opengl.org/discussion_boards/ubb/smile.gif?

Ive only used RCs so far, but not Texture Shaders ...

Diapolo

NitroGL
01-26-2003, 07:58 AM
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 http://www.opengl.org/discussion_boards/ubb/smile.gif

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

jra101
01-26-2003, 07:13 PM
Take at look at this presentation: http://developer.nvidia.com/view.asp?IO=texture_shaders for more information on texture shaders.

Diapolo
01-27-2003, 03:28 AM
I read the presentation and Im 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 http://www.opengl.org/discussion_boards/ubb/wink.gif?

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

Regards,
Diapolo

MZ
01-27-2003, 04:23 AM
But what is unclear to me is, what really happens or how I use the results in the RCsThere 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... http://www.opengl.org/discussion_boards/ubb/frown.gif


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

Diapolo
01-28-2003, 03:02 AM
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

Diapolo
01-28-2003, 04:00 AM
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?

Im getting really confused ... Help!

Diapolo

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

jra101
01-28-2003, 07:20 AM
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.

Diapolo
01-28-2003, 09:43 AM
Ill have a look at that demo, but be sure: Ill be back http://www.opengl.org/discussion_boards/ubb/biggrin.gif.

Diapolo

Diapolo
01-28-2003, 10:16 AM
OK, now Im even more confused.
That demo is everything, but not straightforward http://www.opengl.org/discussion_boards/ubb/biggrin.gif.

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

jra101
01-28-2003, 10:50 AM
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.

Diapolo
01-28-2003, 12:10 PM
A great, that is what I call THE answer, thank you very much http://www.opengl.org/discussion_boards/ubb/smile.gif.

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).]

jra101
01-28-2003, 12:39 PM
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.

Diapolo
01-29-2003, 02:50 AM
I tried to use my existing unsigned RGB (no A) normalmap with the texture shader, but it produces strange artifacts.

Ive 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 whats happening there.

What could be wrong here?

Diapolo

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

Diapolo
01-29-2003, 06:52 AM
Oh and I cant 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

jra101
01-29-2003, 08:12 AM
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.

Diapolo
01-29-2003, 12:10 PM
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

jra101
01-29-2003, 12:24 PM
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.

jra101
01-29-2003, 12:26 PM
oops, yes, the texture setup should look like this:

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

Diapolo
01-29-2003, 01:05 PM
Hmmm, I think there is something wrong with my vectors.
Because I dont use Cubemap Normalisation, I have to normalize them myself (dont use VertexPrograms).

Could you have a look, please.

For the lightvector:
// Light Vector berechnen (Light Position - Vertex Position)
Vector_3D_Subtract(fLightPosition_OS, fQuad_XYZ[i], fLightVector_OS);
// Light Vector normalisieren (nicht bei CM Normalisation)
Vector_3D_Normalize(fLightVector_OS);

// Light Vector per Tangent Matrix in Tangent Space umwandeln
Vector_3D_Matrix_3x3_Multiply(fLightVector_OS, fTangentMatrix[i], fLightVector_TS);

// scale and bias (stellt sicher, dass Farbwert zwischen 0 und 1 liegt - nicht bei CM Normalisation)
fLightVector_TS[0] = fLightVector_TS[0] * 0.5 + 0.5;
fLightVector_TS[1] = fLightVector_TS[1] * 0.5 + 0.5;
fLightVector_TS[2] = fLightVector_TS[2] * 0.5 + 0.5;

The stuff for the Half-Angle vector looks similar.

Im sure, that the lookuptexture is correct and the normalmap is generated like you told me.

Here is a picture (only RGB Part - diffuse): http://Phil.Kaufmann.bei.t-online.de/OGL/wrong_result_TS.jpg

Here is a picture with the RCs and Cubemap Normalisation: http://Phil.Kaufmann.bei.t-online.de/OGL/good_result_RC.jpg

Diapolo

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

jra101
01-29-2003, 01:54 PM
That looks more like a problem with the normal map than with the light/halfangle vectors. Can you post the code that you use to create the HILO normalmap?

Diapolo
01-29-2003, 02:08 PM
Here is it.
Its only hacked into the normal loading function, but it should do it.

GLshort *HILO = NULL;
HILO = new GLshort[(iWidth * iHeight * 2)];
GLshort * sip = HILO;

for(int i = 0; i < iHeight; i++)
{
for(int j = 0; j < iWidth; j++)
{
fread(&rgbTexComponents, sizeof(uRGB), 1 , FilePtr);
memcpy(&Normalmap[iIndex], &rgbTexComponents, sizeof(uRGB));
Normalmap[iIndex].mag = 255;

*sip++ = (GLshort)(rgbTexComponents.glubRed * 32767);
*sip++ = (GLshort)(rgbTexComponents.glubGreen * 32767);

iIndex++;
}
}

But are you sure the Vector stuff is correct, too? Is scale and bias really needed?

Diapolo

jra101
01-29-2003, 02:19 PM
That looks correct.

No, the scale+bias isn't needed.

Are you putting the light and halfangle vectors into the appropriate texture coordinates?

NitroGL
01-29-2003, 02:21 PM
*127 instead of *32767

Diapolo
01-29-2003, 02:34 PM
Here are my TexCoords:

// decal
glMultiTexCoord2fvARB(GL_TEXTURE0_ARB, fQuad_ST[i]);
// normalmap
glMultiTexCoord2fvARB(GL_TEXTURE1_ARB, fQuad_ST[i]);
// L
glMultiTexCoord3fvARB(GL_TEXTURE2_ARB, fLightVector_TS);
// H
glMultiTexCoord3fvARB(GL_TEXTURE3_ARB, fHalfAngleVector_TS);

By the way, here an image with *127 and without the scale and bias (still wrong *g*):
http://Phil.Kaufmann.bei.t-online.de/OGL/wrong_result_2_TS.jpg

Diapolo

PS.: gettin crazy http://www.opengl.org/discussion_boards/ubb/biggrin.gif

jra101
01-29-2003, 06:46 PM
Whats it look like with the normal map multiplied by 32767?

Diapolo
01-30-2003, 02:01 AM
With 32767 and without the scale and bias it looks like that: http://Phil.Kaufmann.bei.t-online.de/OGL/wrong_result_3_TS.jpg

Here is a shoot of the diffuse lookup: http://Phil.Kaufmann.bei.t-online.de/OGL/diffuse_lookup.jpg

Here is a shoot of the specular lookup: http://Phil.Kaufmann.bei.t-online.de/OGL/specular_lookup.jpg

Here is the TS code:

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

glActiveTextureARB(GL_TEXTURE1_ARB);
glBindTexture(GL_TEXTURE_2D, texobj);
glTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, GL_TEXTURE_2D);

glActiveTextureARB(GL_TEXTURE2_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_TEXTURE1_ARB);

glActiveTextureARB(GL_TEXTURE3_ARB);
glBindTexture(GL_TEXTURE_2D, make_lookup_texture(128));
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_TEXTURE1_ARB);

And here the RC code for only outputting Tex3:

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_TEXTURE3_ARB, GL_SIGNED_IDENTITY_NV, GL_RGB);
glCombinerOutputNV(GL_COMBINER0_NV, GL_RGB, GL_DISCARD_NV, GL_DISCARD_NV, GL_DISCARD_NV, GL_NONE, GL_NONE, GL_FALSE, 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_TEXTURE3_ARB, GL_UNSIGNED_IDENTITY_NV, GL_RGB);

Diapolo

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

kon
01-30-2003, 05:10 AM
What should the register combiner compute? You are discarding all three outputs.

kon

Diapolo
01-30-2003, 09:34 AM
I only use the D variable in the final combiner, it should output the diffuse part of my lighting equation.

Diapolo

Diapolo
01-31-2003, 01:47 PM
jra101?
Any new hints for me?

Diapolo

jra101
01-31-2003, 03:07 PM
I'm not sure why this is failing for you, can you send me a zip of the source to your app so I can debug it and figure out whats going wrong?

Diapolo
01-31-2003, 03:59 PM
I sent you an email http://www.opengl.org/discussion_boards/ubb/smile.gif.

Diapolo