Sign in to follow this  
RobMaddison

Compressed Normals into Vertex Shader

Recommended Posts

Hi all In order to save memory, I am compressing my terrain normals into two seperate bytes. I lose a bit of accuracy doing it this way, but it should be okay. My question, is how do I get those two bytes into my vertex shader? I can't see any way of importing BYTEs into the vertex shader, is the lowest common denominator a FLOAT type? If so, that surely means that the lowest type you can have in a vertex buffer is a FLOAT which kind of defeats the object of my compression slightly. Is there a way to import BYTEs into a vertex shader, or if not, is there a way to import a 4 byte float and then carry out bitwise ops on it? Or, can anyone think of a better way to represent normals for lighting a 4096x4096 terrain in the shader? (without using lightmaps). Thanks in advance

Share this post


Link to post
Share on other sites
(I'm not a D3D expert, so treat the following as tips to start with.)

Looking into the DeclarationType (of D3D9), I see
Ubyte4 -> [v0,v1,v2,v3]
which costs 4 bytes of storage, and expands its (4) values as they are. Since you need only 2 values, you may use
Ushort2 -> [v0,v1,0,1]
instead, which costs the same but gives you a higher precision.

Or you go with one of the normalized types, namely
Short2N -> [v0/32767,v1/32767,0,1]
or even the designated compressed 3D vector type
Dec3N -> [v0/511,v1/511,v2/511,1]

All of them cost 4 bytes per normal, but are presumbly better suited than a Float.

Share this post


Link to post
Share on other sites
It does get a little fiddly when dealing with D3D9 vertex shaders as, from memory, the ubyte4 and possibly short/half precisions aren't universally supported by all hardware. Check the cardcaps.xls file for more details and, obviously, check in your code [smile]

Compression systems don't really become 'natural' until you're at D3D10 and above due to the lack of bitwise ops in D3D8 and D3D9 so doing thing like shortening down to a XY and Sign at half precision can allow you to reconstruct the full normal later on...


hth
Jack

Share this post


Link to post
Share on other sites
I have to admit to finding it hard to visualise how you can "recompute the z component". How can you know what the z is without any clue as to what it was pre-compression?

Apologies for my ignorance, this is my first intro into geometry compression techniques.

Share this post


Link to post
Share on other sites
The cross product of two axis will give the third - so normalize(cross(nx,ny)) = nz with one huge caveat - you don't know what sign the resultant axis is. I forget the finer mathematical details, but you have to be careful of this... It's a neat trick for tangent space normals as you can know that its +Z, but for regular normal vectors it could be + or - so sometimes storing extra information elsewhere (e.g. in an unused diffuse channel) can help...

hth
Jack

Share this post


Link to post
Share on other sites
Thanks, Jack... I was just reading another site and how it works suddenly dawned on me! I raced to post my new understanding but you'd posted first :)

My compression is on tangent normals, so I don't really need to worry about the sign of the z (or in my case, y).

I've also been reading about DXT5_NM compression which looks promising.

Rob

Share this post


Link to post
Share on other sites
For your normal, you know the length should be 1. Tell the shader that normal is a float3. Normal.z will be 0, as short2 is expanded to x,y,0,1. The 0 makes it a float3 which we can use for dot products (I don't think there is a 2D dot product... maybe there is in later shader models).

Since the input is XY, and you probably want it in XZ, I swizzle the input during the scaling phase.

float3 xyzscaled = IN.normal.xzy / 32767.0f;
float lensq = dot(xyzscaled, xyzscaled);
xyzscaled.y = sqrt(1.0f - lensq);

While it's true that we don't know the sign of the computed axis (Y in this case). But as you said it's for terrain, we can probably safely assume the land is facing UP.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this