🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

Floating-point precision problems with world-to-screen

Started by
3 comments, last by GuyWithBeard 5 years, 2 months ago

Hi,

I am working on a target reticule for a 3D game I am working on. You know, your typical HUD element that sits on top of an object in the world. If you turn your camera away from the object so that it goes off screen the marker sticks to an edge of the screen, giving you a hint at how to turn to face it again. In some games these turn into arrows as they stick to the corners etc.

I am doing it by transforming a world space coordinate to NDC through my camera, something like this:


Vec4 posHomogeneous(worldPosition, 1.0f);
Vec4 posInClipSpace = posHomogeneous * camera->getViewMatrix() * camera->getProjectionMatrix();
Vec3 posInNDC(posInClipSpace.x / posInClipSpace.w, posInClipSpace.y / posInClipSpace.w, posInClipSpace.z / posInClipSpace.w);

That works well in most cases, and from the NDC coordinate I can get the screen coordinates to draw the HUD element etc. However, in some cases this introduces some precision problems which makes the HUD element jump around on the screen. It seems to me it comes from the w component of posInClipSpace.

Imagine you are standing at (0, 0, 0) and the target object is at (100, 0, 0), ie. a hundred units to the right of you. If you turn left/right the object switches from being "in front of you" to being "behind you" but is stays very close to zero. This, of course also makes posInClipSpace.w very small, which, in turn causes the NDC values to jump around as the perspective divide (third line above) is performed.

How would you solve this? I was thinking you don't necessarily need to use clip space or NDC space for off screen objects and instead rely on view space for that, but it somehow seems "mathematically incorrect". Any ideas?

EDIT: Well, I tried simply feeding the view space coordinates into it and it works surprisingly well. Maybe this is the right way to go...

Advertisement
12 hours ago, GuyWithBeard said:

Well, I tried simply feeding the view space coordinates into it and it works surprisingly well. Maybe this is the right way to go...

It is. You don't actually want the perspective divide (w goes to 0 when in the same plane as the camera) when determining if an object is in front or behind the camera. To check if it is in the view frustum you can simply check against the frustum planes in view space.

Funny, I'm actually doing the same thing for my game right now. Next step will be the off-screen markers - so, thanks for the hint :D

22 hours ago, l0calh05t said:

You don't actually want the perspective divide (w goes to 0 when in the same plane as the camera) when determining if an object is in front or behind the camera.

I would never do that. To determine if the object is in front or behind the camera you can just do a dot product with the camera-to-object vector and the camera-forward vector and check the sign.

I was lost in NDC-land because you obviously need to do the perspective divide for the marker when the object is on-screen, and I did not realize it makes sense to switch to another space when the object goes off-screen. Instead I let the values get "extrapolated" outside of the view frustum when the object went off-screen, which worked well except when the object's depth value was close to zero.

Anyway, thanks for your input, and I am glad if this helped someone else :)

This topic is closed to new replies.

Advertisement