5
\$\begingroup\$

I recently implemented a sky in my deferred rendered game. It is a procedurally calculated sphere with a texture applied to it. Unfortunately all lighting shaders (light sources, ambient occlusion) are applied to that sky dome geometry as well.

Therefore the sky is completely dark without a huge light source in the level. And if there is one, the edges between triangles of that sphere are darkened by the ambient occlusion shader.

My quick and dirty fix was to read the depth texture to determine whether the lighting effect should be applied or not. For example, the view distance is 1000.0f and every pixel with a depth higher than 900.0f isn't shaded anymore. That works partly since every pixel of the sky is between 900.0f and 1000.0f.

But there are some issues with this approach. For example level geometry further away than 900.0f isn't shaded, too. Moreover the depth values come from projecting the scene on a plane, the screen. That means that the distance to the sky, which is equally in all directions from the players world position, differs over the image. Sky seen on the sides of the screen is nearer than sky pixels seen in the center of the screen. That effect varies with the field of view setting. The issue with that is that for every field of view setting I would need different depth thresholds for shading.

Is there a common way to not, or differently, shade some pixels of the image? In my case, I would need to not shader sky pixels. If I could determine which pixel is from the sky, I could store that in a buffer and read from that in lighting shaders to skip those pixels. But I have no idea how to approach this.

\$\endgroup\$

3 Answers 3

7
\$\begingroup\$

You can easily use the Z-Buffer to render only the pixels that matter during skybox/light passes.

I render the skybox last (after all lights). When rendering the skybox, make sure your depth buffer is still intact and use GL_GEQUAL for the depth function. Then in the vertext shader of the skybox, set the z value of gl_Position to its w value. This makes sure the skybox is rendered onto the far plane.

If you want to skip the rendering of skybox pixels during the rendering of ligths, you can set the z-clear value to 1 and use GL_LEQUAL for depth comparison during the light pass.

\$\endgroup\$
0
3
\$\begingroup\$

I ended up using the stencil buffers. Basically, this are the steps my application goes through every frame.

  • Draw geometry except skydome and set stencil buffer to 1.
  • Disable depth mask to not distort depth buffer.
  • Draw skydome where stencil is still 0.
  • Use stencil test to only compute lighting and other shader computations where stencil is 1 and therefore where geometry is.
  • Disable stencil test for computations which include the sky, like antialiasing and user interface.
\$\endgroup\$
1
\$\begingroup\$

I'd suggest using the alpha channel of your color buffer to store a "lighting factor", which you can then use to linearly interpolate between a lit and unlit version of your geometry. Alternatively, using max seems attractive too - the calculation might be something like:

max (litColor * unlitColor.a, unlitColor)

The reason why that would appeal is that you could use it for other effects too, such as glowing regions on textures, or lightning flashes lighting up clouds in your sky. It also means that your stencil buffer remains unused, and therefore available should you also wish to use it for something else.

\$\endgroup\$
1
  • \$\begingroup\$ Good consideration. I may use this when implementing glows or similar effects. Since the I need only one bit in the stencil buffer, that's not a problem for now. \$\endgroup\$
    – danijar
    Commented Jun 23, 2013 at 11:40

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .