Drawing big Objects far away

Hey,

i want to develop a universe-game. The problem is, the planets are really really huge and they are far far away. I dont know how to draw those objects since i dont want to set the far-plane to high and still want to see the planets in the distance.
how can i solve this problem? maybe draw smaller planets closer, but then how to calculate the size/position?

The solution to that is to use a floating-point Depth-Buffer, and a special Shader that changes the way OpenGL computes the depth for all vertices/fragments.

Note that changing the way the depth-buffer is used can create a (very) bad performance hit if done wrong.

Read the following blogposts, as they help a LOT:



Read one by one, in the given order, or else some things just wont make sense.

Have a nice day!

  • Longor1996

32 bit floating point numbers (being multiplied by various matrices) suffer from severe inaccuracies anyway, when dealing with astronomical scales. I think it’d be easiest to scale your geometry, bring it closer to the camera, and you can’t see the difference.

that outerra guys are going pretty crazy on that depthbuffer issue - best stuff i could find about that topic.

a more simple idea is to split the rendering into objects “far away” and “near”. give them different clipping planes.

http://www.opengl.org/wiki/Depth_Buffer_Precision

see “There is no way that a standard-sized depth buffer will have enough precision for my astronomically large scene. What are my options?”

Nope

Doing it the way the Outerra guys are doing it (The ‘Outerra-way’) is MUCH simpler.
With the splitting of ‘near’ and ‘far’ object, you are going to have to deal with a lot more coding (and bugs), than with the Outerra-way.

The Outerra-way, only needs a FBO (FrameBufferObject) with floating-point Depth enabled, and slightly modified Vertex/Fragment-Shaders for drawing into that FBO. You can set the whole thing up in a couple of minutes if you already have Shaders and FBOs implemented in the Engine/Framework you use.

And from the top of my head there are only two main drawbacks of this method:

  • It costs a lot of performance if you do something wrong in the Shaders. ‘A lot’ meaning: A HELL of a lot.
  • You cannot have big polygons close to the camera, as that produces (very noticable) artifacts.

In the end, you have to choose between:

  • A more complex implementation (more bugs), but better performance. (Near/Far Splitting)
  • A more simple, but worse performance. (Outerra-way)
  • And all the other ways there are.

Pick your flavor, and have a nice day!

  • Longor1996

by simple i mean, no extra shaders or fbo’s. it’s doable in fixed-pipeline.

writing gl_FragDepth is more simple, once your shaders and whatnots are set up.

What exactly is the “Outerra way”?

This is the ‘Outerra-way’:



This is also the method that the ‘Space-Engine’ uses.
I you don’t know what ‘Space-Engine’ is, I recommend to check it out, its awesome.

Have a nice day.

  • Longor1996

outerra is an exceptional piece of software.

I was testing some large drawing distances (perspective from 0.1 to 12.000) and while it looks awesome to see mountains kilometers away, the depth buffer started getting really inaccurate, causing some horrible artifacts.

Looking at “the Outerra way” I added the following, but it doesn’t seem to make any difference at all. Did anyone successfully implement it or understand it good enough to give me a bump in the right direction?

I added in the initialization of OpenGL (right after Display.create):
NVDepthBufferFloat.glDepthRangedNV(-1, 1);

I changed the internal format for the depth buffer component of all FBOs to:
ARBDepthBufferFloat.GL_DEPTH_COMPONENT32F

I added the following at the end of all of my vertex shaders:
float Fcoef = 2.0 / log2(12000.0 + 1.0); //Fixed far plane of 12000 for testing
gl_Position.z = log2(max(1e-6, 1.0 + gl_Position.w)) * Fcoef - 1.0;

Any idea?

Kind regards,
Mike

After a lot of testing I’ll answer my own question :slight_smile:

The documents explain two ways to solve the issue, using the glDepthRangedNV function (which also works on new AMD drivers), OR using the shaders, there is no point in mixing the two.

As glDepthRangedNV was a lot easier to implement and the huge drawing distance is more for newer graphics cards anyway I went for that. The results are great, I’m getting 0.1mm resolution on a distance of 100.000 meters. No more flickering evah!

Note:
Set NVDepthBufferFloat.glDepthRangedNV(-1, 1) after the binding of the FBO, not after Display.create()
The internal depth buffer format of the FBO needs to be a 24 or 32 bit float or it won’t work
You need to change two values of the projection matrix, something like this if you are handling the matrices old style:
GL11.glGetFloat(GL11.GL_PROJECTION_MATRIX, projection);
projection.put(10, nearPlane / (nearPlane - farPlane));
projection.put(14, farPlane * nearPlane / (nearPlane - farPlane));
GL11.glLoadMatrix(projection);

Mike

sweet, thanks for the info!