How to move to a far corner of a game world w/o losing depth precision?

Started by
9 comments, last by _the_phantom_ 12 years, 10 months ago
Hey guys. I was having some serious issues with z-fighting and other graphical issues when my character was positioned pretty far in the world from position (0,0,0). For example, with a position of (130000, 10, 130000). Even setting the near/far plane in projection to 2 / 2000 had flickering where polygons intersected. After moving my guy's world position closer to the zero point, those issues went away. Now I don't know how big my world will eventually be but I don't want the depth precision(?) to decline the further out a player travels Do I have to organize my data so there's some relative position? I'm not sure how to go about setting that up. Currently the world is just separated in chunks and I draw the 9x9 chunks surrounding the player. Appreciate any help.
Advertisement

Hey guys. I was having some serious issues with z-fighting and other graphical issues when my character was positioned pretty far in the world from position (0,0,0). For example, with a position of (130000, 10, 130000). Even setting the near/far plane in projection to 2 / 2000 had flickering where polygons intersected. After moving my guy's world position closer to the zero point, those issues went away. Now I don't know how big my world will eventually be but I don't want the depth precision(?) to decline the further out a player travels Do I have to organize my data so there's some relative position? I'm not sure how to go about setting that up. Currently the world is just separated in chunks and I draw the 9x9 chunks surrounding the player. Appreciate any help.


A position of (130000, 0, 130000) is ridiculously far, assuming your standard unit is 1u = 1 meter this would mean that you'd be at a position of 130km at x and z, and I don't know a single game that has extremely huge maps like this

Either adjust your game units to a larger scale if larger maps are required, or really downscale your map, I think a realistic map size maximum is about 1000m² for games with FPS-like movement/speed (and 1000m² already is pretty generous)

After you've scaled everything accordingly you could, as you suggested, partition your world using relative coordinates for each partition
Absolute position can now be derived based on your position relative to your current partition, and the partition id or position in your world

I gets all your texture budgets!

Hi,

I recently did an analysis on where Z-fighting starts at various values for near and far plane.

The graph here shows the 4 different settings of near/far plane distance values. This is in DX9.

As you can see, the near plane is much more important than the far plane, and increasing it significantly reduces the Z-fighting.
Unlike conventional wizdom that the ratio of near/far is important, it's in fact much more important to increase the near plane. This is because of logarithmic z calculations.



DT3k0.jpg


Having said that, I agree that 130k is extremely far away, and there shouldn't really be a need for placing objects that far in unit space.
You should probably investigate various methods of placing objects relative to the camera, or give us a more detailed description of what your game is supposed to be like and why such distances matter.
If you already have the world broken down into smaller chunks and render only the eight chunks around the one where the player is (and the current chunk of course) think about applying the world transformations relative to the camera position as far as rendering goes, if the camera is the zero of your world always, you won't have this problem, objects at distances enough to have precision issues won't be visible.

Just as you have fractioned your physical representation of the world into chunks, you should also fraction your coordinate system, if you find yourself in a cell 10 cells away from the zero, the objects that are located in that cell do not need to have a position of 10*CellSize + N, they just need N relative to the cell center and that cell center can be transformed to camera coordinates to reduce it even further.

Game making is godlike

LinkedIn profile: http://ar.linkedin.com/pub/andres-ricardo-chamarra/2a/28a/272


To the OP: what is your camera near / far clip? If your far clip is extremely long compared to your near clip, you will lose precision.

I worked on a game with map units from -500k to 500k. Making the near clip plane longer fixed any precision issues.
Wow thanks for the replies guys!

Radikalism - I have the terrain scaled by 5 so I guess that'd be 5units for 1 meter? I'm really trying to figure out how to scale everything that works best. Each terrain chunk has a coord with coord 0,0 being at the 0,0xz absolute position. I only stay in the positive quadrant just to make data managment easier. So I was putting my character in an arbitrary far bottom right corner to see how things worked.

Currently, I just take my character's absolute position, figure out which coord the character is in, that ends up being the center chunk and i draw 8 chunks around that chunk. Everything is in absolute positions.

braincell - That chart is pretty awesome. I did notice pushing the near plane up to 6 or 7 really helped the z-fighting but at that point, my camera would start clipping through the terrain and I could see through the terrain. I guess I could increase the distance the camera could get to the ground but it already seemed big enough. (Camera freely rotated around the player's character)

nexuxskill - I think that's what I was trying to figure out how to do. You are right on how I set up each chunk's vertices. Instead of using the center of each chunk, could I use the upper left (0) vertex of each chunk? (The vertices aren't stored in a 2d array, just a single array) I'm having trouble mentally figuring how to set this up. Currently the vertex positions are in absolute. I would need to instead just set their positions to "local" position based on the upper left vertex? Which would make the position for vertices in every chunk the same actually. So then, if I'm correct so far, I need to determine the transformation matrix for each chunk based on that chunk's 0,0 position to the camera's position? I'm using XNA so would that be something like:

Matrix transform = Matrix.CreateTranslation(chunk's_upper_left_abs_pos - camera_abs_pos); And when sending the "World" effect parameter just send that transform instead of Matrix.Identity ?

Would that be correct?
Again, thanks for the replies guys, gave me some mental food to munch on.
How you store your vertices is pretty much irrelevant, use VertexBuffer and IndexBuffer to represent each mesh, the vertices transformation or positional data should be in the coordinate space of the object they represent, that object should have its own transformation in world cell space, and the world cell should have a transformation relative to an absolute world, however like I said, that last transformation should be transformed to camera space to reduce precision loss.

Look up nested transformations and coordinate spaces.


Game making is godlike

LinkedIn profile: http://ar.linkedin.com/pub/andres-ricardo-chamarra/2a/28a/272



How you store your vertices is pretty much irrelevant, use VertexBuffer and IndexBuffer to represent each mesh, the vertices transformation or positional data should be in the coordinate space of the object they represent, that object should have its own transformation in world cell space, and the world cell should have a transformation relative to an absolute world, however like I said, that last transformation should be transformed to camera space to reduce precision loss.

Look up nested transformations and coordinate spaces.





I think I got it! My character's face no longer has cracks in it. You're correct, I didn't have to touch the original positions of my terrain. In case anyone was curious, all I did was:

Create view matrix with position zero instead of absolute position so camera is zero point.

Then when drawing my terrain/models, i created a transform by Matrix.CreateTranslation(Vector3.Zero - camera_abs_pos); and passed that along to the shader as the world. That was a lot easier than I was anticipating. Thanks for your help Nexuskill!
An inverted depth range can also help with the z precision.

And there is also the other more insidious problem of precision of coordinates in the shader causing problems:

When working with units that far away, it becomes very important that the models are never processed in world space in the vertex shader.* They should be transformed directly to a camera relative position.


Wrong:

Model Coordinate -> (* LocalToWorld Matrix) =
World Coordinate -> (* WorldToViewProj Matrix) =
Clip Space Coordinate


Right:

Model Coordinate -> (*LocalToView matrix) =
ViewSpace Coordinate -> (*ViewToProj Matrix) =
Clip Space Coordinate



Say you are standing at 130,000.00, and a local model of a rock is next to the camera, with a bounding box of +/- 100 units, that is (0,50,200) units from the camera.

In the wrong case, the corners of the box get transformed from 100 to 130,100.00, then back to a camera origin of (0,50,200). The box originally had a numerical precision of 100.0001 approximately, but when it went to go visit the location 130,100 in the math, it lost about 5 decimal points of precision in the process. The effect looks nearly identical to z-fighting, as the vertices end up oscillating by huge deltas as you move the camera around, except it will even happen if the camera is near the object, if you are far enough away from the world origin.



(*) except for code the explicitly needs the world position for some reason, like doing texture projection for terrain or models on terrian that need to appear to be seamless etc.
http://www.gearboxsoftware.com/
It's probably a bit of a no-brainer, but you can also check the precision of your depth buffer. If you're using 16-bit depth the problem is obviously going to be worse than with 24 or 32.

Direct3D has need of instancing, but we do not. We have plenty of glVertexAttrib calls.

This topic is closed to new replies.

Advertisement