5
\$\begingroup\$

I'm a new to OpenGL or graphics in general. Trying to write a game with realistic scale. I had a perfectly fine rendering of earth at a small scale, but when I try to scale it up to 1:1 I get this artifact. Any ideas what this could be? I suspect it's because I am using floats, but I would rather avoid using doubles in the shader for performance reasons.

Weird artifacts

\$\endgroup\$
  • 3
    \$\begingroup\$ What do you mean by "scale to 1:1" ? There's no reason for a planet to be drawn with "real-life scale" coordinates, it serves zero purpose; not sure if that's what you meant you were doing or not. I know this almost this exact question has been asked before but I cant' find it; see for starters, though: gamedev.stackexchange.com/questions/55731/… \$\endgroup\$ – Sean Middleditch Jun 23 '13 at 4:32
  • 2
    \$\begingroup\$ Could you post another screenshot of what it's supposed to look like? How is your projection matrix set up? What are the zNear/zFar values? Does this help? \$\endgroup\$ – Andreas Haferburg Jun 23 '13 at 9:56
  • \$\begingroup\$ @SeanMiddleditch: By 1:1 I meant I scaled the sphere to the size of earth in meters. The reason is this will go in to a game with satellites and ships orbiting it where I need to report orbital altitudes. I figured scaling the actual value shouldn't be a problem since it's all in floats. \$\endgroup\$ – omikun Jun 23 '13 at 12:56
  • \$\begingroup\$ @AndreasHaferburg: Thanks! It was because of my zNear value was too close. Bumping it from 10.0f to 10000.0f fixed it. Post it as an answer so I can check it. Thanks again! \$\endgroup\$ – omikun Jun 23 '13 at 12:57
  • 1
    \$\begingroup\$ You might also want to double check that back face culling is enabled and working. I'm not sure what other geometry could be messing up the depth buffering, and it should make it render quicker. \$\endgroup\$ – Adam Jun 23 '13 at 21:01
4
\$\begingroup\$

When rendering massive 3D bodies can occur 2 problems, both of them related to precision.

1) Jitter: Most of today’s GPUs support only 32-bit floating-point values, which does not provide enough precision for manipulating large positions in planetary scale terrains. Jitter occurs when the viewer zooms in and rotates or moves, then the polygons start to bounce back and forth.

The best solution for this is to use "Rendering Relative to Eye Using the GPU" method. This method is described in the book "3D Engine Design for Virtual Globes" (I'm sure you can find it on the internet aswell) in where basically you have to set all your positions with doubles on CPU (patches, clipmaps, objects, frustrum, camera, etc) and then MV is centered around the viewer by setting its translation to (0, 0, 0)T and the doubles are encoded in a fixed-point representation using the fraction (mantissa) bits of two floats, low and high by some method (read about Using Ohlarik’s implementation and The DSFUN90 Fortran library).

Although the vertex shader requires only an additional two subtractions and one addition, GPU RTE doubles the amount of vertex buffer memory required for positions. This doesn’t necessarily double the memory requirements unless only positions are stored.

2) Depth Buffer Precision: Z-fighting. As we are rendering very large terrains, in this case: planets, the Z-buffer has to be HUGE, but it doesn't matter wich values you set for znear and zfar, there will always be problems.

As the Z-buffer depends on a float point interval, and also it is linear (although perspective projection is non linear) values near the eye suffer from Z-fighting because the lack of precision 32-bit floats have.

The best way to solve this problem is to use a "Logarithmic Depth Buffer" http://outerra.blogspot.com/2012/11/maximizing-depth-buffer-range-and.html

A logarithmic depth buffer improves depth buffer precision for distant objects by using a logarithmic distribution for zscreen. It trades precision for close objects for precision for distant objects. Since we are rendering with a LOD method, far objects require less precision because they have less triangles.

The problem you have (as I can see from the image you posted) is z-fighting. Try to solve it first by moving the znear to a very far plane and the zfar a little more close to the camera, for example, put znear in some range between the orbit of the satellite and your camera, and switch to 1000, 100, 10, 1 meters as you are approaching the surface of the planet, the zfar value can alway be set to a little more distant to the center of the planet, because is a fact that you will never see the back part of the sphere, so you cull half of the globe. If this solution doesn't fit your needs, go for the logaritmkc depth buffer.

| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ Just found your answer after a long hiatus. I followed your advice and used RTE and played with near/far to get it right. Haven't had much luck with the logarithmic depth buffer. For things farther away like the sun and other planets I found success with using depth clamp and painters algorithm. \$\endgroup\$ – omikun Mar 26 '14 at 23:37
  • \$\begingroup\$ Glad to that I helped. The painter's algorithm is the right way when rendering other bodies like the sun and other planets/moons. There is another method listed in the book "3D Engine Design for Virtual Globes" (if you still need it you can email me and I'll send it to you <nosmirck at gmail dot com>) that talks about rendering with different frustrums, but that requires a little bit more computation (clipping at every frustrum). \$\endgroup\$ – nosmirck Mar 27 '14 at 16:06
4
\$\begingroup\$

Do not use real-life scales. You absolutely, positively, for-sure do not need them at all in this use case.

You give the example of satellites. They are a few dozen meters across usually. The earth is 12,742,000 meters in diameter. A satellite that is three dozen (36) meters wide is still 1/76166th the size of earth. If you can see the whole earth as a globe then your monitor cannot possibly render the satellite; it'd be significantly significantly smaller than a single pixel on even the highest end >$30k medical-oriented displays on the market.

The point being that using "real meters" doesn't help you. You're either rendering a satellite in a visible way with the earth being a distant object that has no significant detail (so it can be a "tiny" sphere with a low-quality texture) or you're zoomed in to the earth (and can still use a "tiny" sphere with more heightmap data and higher-quality textures). Using meters for the earth does absolutely nothing mathematically in terms of making the earth more "real" nor simplifying all the hard parts of graphically rendering it. Using a near plane of 10000.0f just means that you can't get close to satellites or the earth's surface without it being clipped.

Instead, deal the LOD (level of detail). When you are far enough away to see the earth as a globe, render it as a small sphere with a reasonable unit size in graphics, say 10 or 100. After you close in enough, switch to a higher detailed model or set of textures and "reset" the camera to an equivalent position. Remember that an object twice as far away is half as large visually will help you work out the right math to use here. Using LOD, you can zoom in and out of the earth, surrounding space, individual satellites, etc. all without incurring float-precision problems.

Assuming I did all this math right: say a 40m satellite is at maximal low-earth orbit, ~2,000,000 meters. The earth does not need to be its "real" diameter to keep 1:1 scaling visually intact. If you put the camera right up against the farthest point on the satellite, the earth will still be 1/50000th the size than "normal" when rendered (2 million meters is 50000x larger than 40 meters). Keeping consistent units of meters hence means it only needs to be ~255 units wide if rendered at the same z-depth from the camera as the satellite. You can render the earth at a consistent 100 or even 10 units and scale it "slightly" to appear visually correct based on a function of distance to get the exact same visual effect as if you rendered it at a 1:1 ratio and set the camera at a "real" distance (and all the floating point impression you'll get as a result of that).

Far more likely, if you're close enough to the earth to see a satellite, the earth is not just a sphere anymore. You'll be looking at at a patch of the earth something like:

low-earth orbit

You now have no need to even think of the earth as a complete sphere. You'll be rendering a portion of the earth and trying to find a scale that lets you apply a height/normal map plus "zoomed-in" textures, which again can be rendered with units where 1 unit > 1 meter. If a whole mountain is only 3 pixels wide, do you really need to represent that mountain as 5000 units=meters in width? Of course not.

You do however still need to completely change how you're rendering the earth. Your work is not going to be simplified in any significant capacity by using astronomical (literally) measures to represent objects. Most of your work is going to come into scene management, LOD, and so on.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ That makes a lot of sense. Though I still have to keep track of objects in 1:1 scale, then fake it like you said during rendering. I was trying to imitate Kerbal Space Program. I now suspect they implemented the approach you detailed for space ship closeups and a version of my current approach for showing a map of the solar system. \$\endgroup\$ – omikun Jun 24 '13 at 2:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.