Skip to main content
GameDev.net gamedev.net
🔒 Locked

OpenGL CG normalize() problem

Started by Hybrid666 Jan 7, 2007 at 12:31 PM 2 replies 4.2k views
Original Post
Hybrid666
Hybrid666
Hi, I'm finding that calling normalize() in my CG fragment shader is producing different output to calling my own vector normalise routine in code. (the code version definitely works! ;)) I need to call normalize() in the shader though instead of in my code, so i need to figure out why my 2 normalisation methods produce different outputs. All components are in the range [-1,+1] range when stored in the normal map texture, and then i read back out of this texture in my shader. i read something about converting between ranges [0,1] and [-1,+1], but this didnt seem to help me, am i missing something? CG line: fNormal = normalize(fNormal); Normal map texture creation line: glTexImage2D(GL_TEXTURE_2D, 0, 4, m_uiWidth, m_uiHeight, 0, GL_RGBA, GL_FLOAT, c_pData); Thanks in advance for any help! Hybrid
Hybrid666
Hybrid666
Hi,

I've been reading some more stuff on the net and it seems i have some conflicting information.

the stuff im reading says that no matter what i store in my texture map, it will get clamped to [0,1] range by the time it reaches the pixel shader. this would expain my problems as i thought i could leave my data in [-1,+1] format and pull it back out with my tex2D call in the shader.

however, the reason i assumed this, was that i have seen shader code which is annotated to imply that it is possible to only store the xy normal values, and then assume z is always +1 (which is ok for a heightmap scenario) and just normalise the normal vector based on float3(x, y, 1). but that means x and y could need to be greater than 1 (or less than -1) as we would no longer be storing unitised vector components.

of course, i can solve this problem by storing the xy components of a normalised vector and then using some pythagorus to re-compute my z on the fly, but im still a little confused by this seemingly conflicting information, but maybe i am missing something?

Hybrid
Todo
Todo
You're confusing two distinct facts:

1) texels of normalized integer textures (those from OpenGL 1.1) have their components clamped to the range [0;1] inclusive. This simply means that whether you load the texture from an 8-bits integer map or a 16-bits floating point map (like you do with the glTexImage2D call), any value outside a minimum and maximum will be lost. Using the GL_FLOAT constant does not tell you anything about the INTERNAL FORMAT of the texture, which in this context is an 8-bits RGBA integer texture (implied by the number 4 in your call). For floating point inputs, the minimum is 0. and the maximum is 1. Thus, loading a FP normal map will kill any information in the negative range of the spectrum. Instead, what you need to do (and what you've read on various sites but are confused about) is this:

- normal map components generally are mapped from their source domain (real numbers ranging from -1 to 1) to an encoded 8-bits RGB(A) format. You could do without both the alpha component and one of R, G and B (and calculate the missing component using trigo as mentioned in your second post), but that doesn't matter, what matters is the transformation: X = (u8)( ( X + 1. ) * 127. ) (for X, Y and Z)

- in the CG shader, you then decode this information back to the range [-1;1] using the reverse op (be aware that OpenGL represents texel components as normalized floating point number, regardless of the internal format): float4 N = ( T * 2. ) - 1.

- the resulting vector N should then be normalized in the event of point filtering, but if the texel was filtered, you should again normalize N (using the normalize() call, which will now behave as expected)

Hope that helped at least a bit :-)

EDIT: alternatively, on new hardware, you could use floating point textures (which do allow the use of floating point channels internally).


[Edited by - Todo on January 8, 2007 7:30:14 AM]
Hybrid666
Hybrid666
Hi,

thanks a lot that's totally cleared everything up for me! Had a bit of a look at floating point textures but it doesn't seem like there's any point me using those for this particular problem, so i'll stick to converting my ranges from [-1,+1] to [0,1] and then decompressing them in the fragment shader.

really comprehensive reply, very much appreciated!!

Hybrid

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.