Jump to content
  • Advertisement
codingJoe

3D float or double for my vertices / normals?

Recommended Posts

Hello,

I have my 3D application use floats for almost everything. Now I realize that I lack precision (typically for transformation matrices, that are cumulative with a hierarchial arrangement of objects). So I want to switch to double for matrix/vector calculation and most other things.

My question is: what should I do with my vertices and normal vectors? From a storage point of view, going from float to double will almost double my file sizes, which is not really problematic. But passing doubles to a graphic card is another story I think, since twice that many data need to be passed, which very probably represents a bottleneck. I am using pure old openGl, but want to switch to vtk or something similar. What are people normally doing in this situation?

Thanks for any insight

Share this post


Link to post
Share on other sites
Advertisement
13 minutes ago, codingJoe said:

But passing doubles to a graphic card is another story I think, since twice that many data need to be passed, which very probably represents a bottleneck.

Not only due to memory, but mainly for computation. Unless you have very specific uses and constraints, use float to store your vertices, normals and other attributes. 

Share this post


Link to post
Share on other sites

Multiplying pretty many rotational matrices over each other doesn't introduce too much error. The error can pop up with positions, if they're really big. Do you have really big positions or scales in your matrices? What for?

Share this post


Link to post
Share on other sites

 

I'm not sure if this is really addressing your problem but I'll give you my experiences with double and float.

I'm building worlds with a very large range of numbers. It requires doubles or alternatively some likely error prone system of coordinate translation. My current strategy is to calculate everything in double on the CPU side. Although I'm sure you can mix and match in places, I think for initial development keeping everything double will save you some heartache.  Later you can go back an optimize things if you feel the  need.

The GPU is a whole different story since typically many cards aren't really optimized for double (apparently many intentionally). The trick is when going from CPU to GPU to translate everything so your camera is near (0.0,0.0,0.0) and as you do so simultaneously convert to float.

Since things in the distance need far less precision this works fairly well. For instance if a far away hill that  is 100 meters height is now 99.5 meters high due to precision loss, a player will never notice it.  As you approach the hill you will have to send it's vertexes down again anyway to get the required detail with you terrain and and that point the precision will fix itself since the data will be progressively closer to the camera.

This does however add one more requirement to your system....... You need a very robust LOD (Level of Detail) system.  Detailed objects at distance are going to be  a problem be they will induce Z-fighting since the precision simply isn't there. How you handle this has a lot to do with your basic graphics system.  But generally you are not displaying small objects at distance anyway, so hopefully a lot of his should take care of itself.

Again I'm not sure if this really answers you question, but maybe you can glean something from it.

Edited by Gnollrunner

Share this post


Link to post
Share on other sites

Thanks for the replies.

I do not have large positions, but I have sometimes a chain of 20+ objects built on top of each other. Each object stores its local transformation matrix. If you want to modify the absolute orientation of the object at the end of the chain, e.g. rotate it absolutely by 1 degree around a specific axis, then you first compute 20X matrix multiplications to get the absolute matrix, then you rotate that matrix, and compute another 19X matrix multiplications, inverse it, and multiply it with the modified matrix, in order to obtain the new local matrix for that object.

I am aware that above operation can be performed in a more simple way, but there are many such similar cases where a float just isn't enough anymore. Another example is to read and set the same absolute matrix of that object that is at the end of the chain: the object can very slowly drift. 

(just for precision: I am not really using matrices, but position vectors and quaternions. But the problem is similar)

Edited by codingJoe

Share this post


Link to post
Share on other sites

Try and find the operations that accumulate errors and post them, there may be a better way to do them. For example:

Instead of  asin(x)   try   2 * atan(x / (1 + sqrt(1 - x * x))
Instead of  pow(a,b)   try   exp(log(a) * b)

I would say the basic premise of expecting hundreds of operations to be reversed to return the same float might need a basic design rethink but you didn't really say what you're doing or why.

Share this post


Link to post
Share on other sites
34 minutes ago, codingJoe said:

I am aware that above operation can be performed in a more simple way, but there are many such similar cases where a float just isn't enough anymore.

Then why use this example? If you can provide examples where this is a problem you will be more likely to get solutions.

51 minutes ago, codingJoe said:

Another example is to read and set the same absolute matrix of that object that is at the end of the chain: the object can very slowly drift.

Can you elaborate on this? And what are the actual numerical values of the transform where you are getting drift? With quaternions could it be something like you are not normalizing them?

Share this post


Link to post
Share on other sites

@TeaTreeTimpow(a,b) actually is implemented as exp(log(a) * b) on modern architectures. There's no power intrinsic function (neither in x86. x87, amd64, SSE, SSE2, ..., nor on the GPUs) :)

Share this post


Link to post
Share on other sites
1 minute ago, pcmaster said:

@TeaTreeTimpow(a,b) actually is implemented as exp(log(a) * b) on modern architectures. There's no power intrinsic function (neither in x86. x87, amd64, SSE, SSE2, ..., nor on the GPUs) :)

I tested these examples about 10 years ago (so probably DX 11 on a card circa 2010 ish) to reduce floating point rounding errors in HLSL shader operations. They were just supposed to be an example of modified functions reducing the risk of rounding errors.

Share this post


Link to post
Share on other sites

GPUs can be very slow with doubles so there's usually a better way, but it depends on the case. Either find a way to change your calculations so that floats are sufficient, or use doubles only on the CPU. For example in the large-world case, you can use double matrices on the CPU for model-to-world-space and world-to-view-space transformations, and then combine them into a model-to-view-space matrix and convert it to floats for the GPU, so the GPU can transform vertices directly from model-space to view-space and never has to calculate with large floats (for objects close to the camera at least). Additionally, if you can't easily transform everything to view-space and would prefer doing some GPU calculation in world-space (e.g. some world-space light maps that are difficult to rotate), then instead of using the actual world-space where coordinates near the camera can be too large for floats, you can use a camera-centered-world-space that is centered around the camera but oriented according to world axes, sending a model-to-camera-centered-world-space matrix to the GPU.

 

 

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

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!