D3DXVECTOR3 with doubles

Started by
8 comments, last by BMW 10 years, 9 months ago

I am using D3DXVECTOR3s to store the eye point and look at point.

When the position of the player becomes large (i.e. 100000.0f) the movement becomes jerky due to the float losing precision. Is there any D3DXVECTOR3 that uses doubles instead of floats?

Advertisement

This is how D3DXVECTOR is defined:

typedef struct D3DXVECTOR3 {
FLOAT x;
FLOAT y;
FLOAT z;
} D3DXVECTOR3, *LPD3DXVECTOR3

FLOAT type is defined in WinDef.h uder that line : typedef float FLOAT; ( http://www.csee.umbc.edu/~squire/download/WinDef.h ) So actually it is impossible. But 100000.f isnt big enough for floats. Are you shure about the precision issue, double check your code!

Yeah I'm pretty sure it's the problem. Here's my code: (mouse_offset_* are floats, *_angle are floats)


GetCursorPos(&mouseloc);
	
GetClientRect(hWnd, &rc);
ScreenToClient(hWnd, &mouseloc);
	
mouse_offset_x = (float)rc.right / 2.0f;
mouse_offset_y = (float)rc.bottom / 2.0f;
mouse_offset_x -= (float)mouseloc.x;
mouse_offset_y -= (float)mouseloc.y;

x_angle -= ((mouse_offset_x / 5000) * mouseSensitivity);
y_angle -= ((mouse_offset_y / 5000) * mouseSensitivity);

if(x_angle > (2.0f * D3DX_PI))
	x_angle = 0;
if(x_angle < 0)
	x_angle = (2.0f * D3DX_PI);

y_angle = __max(-D3DX_PI / 2.0f, y_angle);
y_angle = __min(+D3DX_PI / 2.0f, y_angle);

D3DXMatrixRotationYawPitchRoll(&mat, x_angle, y_angle, 0.0f);
D3DXVec3TransformCoord(&vAhead, &vNorth, &mat);
D3DXVec3TransformCoord(&vAbove, &vUp, &mat);
D3DXVec3TransformCoord(&vLeft, &vWest, &mat);
D3DXMatrixRotationYawPitchRoll(&mat, x_angle, 0.0f, 0.0f);
D3DXVec3TransformCoord(&vAheadWalk, &vNorth, &mat);

vLookAtPt = vEyePt + vAhead;
D3DXMatrixLookAtLH(&mat2, &vEyePt, &vLookAtPt, &vAbove);

cGraphics->setTransform(D3DTS_VIEW, &mat2);

mouseloc.x = rc.right / 2;
mouseloc.y = rc.bottom / 2;

ClientToScreen(hWnd, &mouseloc);
SetCursorPos(mouseloc.x, mouseloc.y);

But 100000.f isnt big enough for floats.

I thought floats had a precision of 7 significant figures, so if the value was 100000.0f then it only has 1 decimal place of precision, causing jerky movement...

Would increasing the Look At Point distance from the player help? E.g. say we only have 1 decimal place of precision, so the Look At Point jumps from 100000.0 to 100000.1 which rotates the camera quite a lot cause it to appear jerky. If I increase the distance of the Look At Point, the angle of rotation would be less, decreasing the jerky-ness. Is this correct? I will try it and see if it helps.

EDIT: Increasing the Look At Point distance helps a bit, but I think the problem is also with the transformation of the vertices, they are jerky/glitchy at high numbers.

I don't know why you would be having movement so far away from the origin, 100,000 is a pretty good distance. I made a scale model of the solar system that didn't even go out to 100,000 units lol.

The game I'm working on atm has a HUGE world, bigger than World of Warcraft I think. And it's entire world is about 10,000 units wide and we have yet to cover half of it.

I agree that 100,000 is suspiciously far from the origin. For best precision the centre of the world should be at(0,0,0). However it might be possible to improve the precision. Look at this line of code:

vLookAtPt = vEyePt + vAhead;

If the vEyePt is big, and vAhead is a unit vector then the precision will be poor. However D3DXMatrixLookAtLH really only cares about the direction, and not the actual position. Try:

vLookAtPt = vEyePt + (vAhead * 1000.0f);

That way after the addition the direction will be represented with more bits, and should be more accurate.

If you look at the maths in the documentation you'll see it subtracts the two values and normalizes the result. So the other option is to bypass that function and write your own version which uses the direction directly instead of calculating it from two points. That will give you even better precision.

Of course that may not be the only precision problem you have.

I agree that 100,000 is suspiciously far from the origin. For best precision the centre of the world should be at(0,0,0). However it might be possible to improve the precision. Look at this line of code:

vLookAtPt = vEyePt + vAhead;

If the vEyePt is big, and vAhead is a unit vector then the precision will be poor. However D3DXMatrixLookAtLH really only cares about the direction, and not the actual position. Try:

vLookAtPt = vEyePt + (vAhead * 1000.0f);

That way after the addition the direction will be represented with more bits, and should be more accurate.

If you look at the maths in the documentation you'll see it subtracts the two values and normalizes the result. So the other option is to bypass that function and write your own version which uses the direction directly instead of calculating it from two points. That will give you even better precision.

Of course that may not be the only precision problem you have.

The eye vector still makes its way into the matrix for the translation part, where it will still cause precision issues. The worst precision issues are going to be in positioning all the other things in your world out that far away from the origin, so even if you fix the camera, you won't be able to animate anything close to the camera correctly. And if there's nothing out there, the camera shouldn't be out there anyway.

You could do all your CPU math with doubles, 64-bit integers, whatever you want. You're still going to use Direct3D to draw it all, though. So, unless there are some vertex shader data types I don't know about (a likely scenario, actually) you're still going to use single-precision floats on the GPU, and still get issues.

If you want to make a really big world, break it into tiles. I personally don't work on a big-world game right now, but I've seen plenty of good comments from other people who know how to do that here. You should be able to track objects in terms of offsets from the closest tile center, and use the closest tile to the camera as the origin.

The reason I have it so far from the origin is because I am making a semi-infinite voxel world, and I haven't yet included support for negative positions. I manage blocks in chunks of 16x16x128, so I guess it won't be too hard.

I imagine negative positions wouldn't be hard to add in there, try that out and see what happens. If it doesn't work you can easily create your own Vector3 with doubles. If that doesn't work, then it's in your math.

100,000 shouldn't be to high for you to get those jerky results IMO. Do some optimizations so that you're doing as little math as possible on those large numbers is my suggestion. But I could be wrong. Good Luck :)

I imagine negative positions wouldn't be hard to add in there, try that out and see what happens. If it doesn't work you can easily create your own Vector3 with doubles. If that doesn't work, then it's in your math.

100,000 shouldn't be to high for you to get those jerky results IMO. Do some optimizations so that you're doing as little math as possible on those large numbers is my suggestion. But I could be wrong. Good Luck smile.png

Yup, I added support for negative positions, or rather removed obstacles for them. I made the mistake of limiting the game in the early stages - "i wont need negative positions". However it didn't prove too difficult at all. All I did was changed unsigned ints to ints and remove a few negative-checks, added in a few negative-checkers (-1 off negative numbers because they truncate upwards whereas positive numbers truncate downwards). I am glad that I used the concept of chunks in the early stages.

This seems to have solved the problem.

Here is a video of the game showing off the (semi)infinite terrain generation (although it's very slow at the moment):

This topic is closed to new replies.

Advertisement