2
\$\begingroup\$

I'd like to implement shadows and reflective surfaces in my OpenGL app. I already have ideas which I will provide below. But I would like to ask someone more experienced than me before I put too much effort into the implementation. (I'm still very new and so I don't know all options I have on modern graphic cards.)

I would like to know if there are any common improvements or common techniques that would improve the quality and/or performance. (Or even if my idea is completely nonsense)

Shadows

I would render a cube map at the center of each light source in a separate Framebuffer. When rendering the real scene I can lookup the depth information in the the relevant cube map (for each light source) and compare the depth value with xyz-Position of the Fragment. And check if the Fragment is behind an object. Additionally I could also take surrounding depth values into account to render blurred shadows depending on the distance to the object.

For the special case that the light source is stationary I could render all other stationary objects at the beginning. For each frame I still have to render the dynamic objects and reset to the "stationary scene" afterwards.

Reflection

For plane mirrors you could simply mirror the view matrix around the plane and render the scene a second time (with the stencil buffer to clip the rendering process to the mirror surface). Also I should clip the rendering volume with glClipPlane(). I found this technique on Google, so it seems to be very common.

But for arbitrary surfaces I had to think about something different. My idea is to render a cube map at the center of every object that has reflection enabled in its material definition. When I am in the real rendering process, I would read out the pixel value in the cube map, depending on the surface normal and the fragment xyz-Position. The problem is that you get an parallax error for near objects because the fragment obviously isn't at the center of the object. I couldn't solve this problem. (Maybe I could render the normals of the mirror object and then use this to make some transformations while rendering the cube map?)

For stationary mirror objects I could do same trick that I described in the Shadows section.

Instead of cube maps I could also use a single map and transform the Cartesian coordinates to spherical coordinates (phi, theta, r). So that the resulting texture has the dimension phi * theta (r is the depth value). But I don't know which method is generally faster. Also a single map would generate different texture qualities depending on theta. I'm not sure how bad this will be in the result.

The main problem that I have is that this all sounds very performance intensive. Maybe there are tricks I don't know?

An advice would be helpful. Thanks in advance.

\$\endgroup\$
2
\$\begingroup\$

You are not so far off with your observation. The approach you describe in both cases is OK but needs refinement.

Shadows

When looking into shadows you need to consider different issues. As you describe you can handle everything dynamically. The process is basically as you describe, except for directional lights and spotlights you would use "normal" 2D frame buffers.

There are a number of optimizations you can do. For example you can ask the question which lights actually need shadows. Often when designing a level you will put many small point lights into places where low "ambient" light is expected, such as glow from illuminated signs and such. Here you can get away with no shadows at all.

The next optimization is, you can precompute static lights on static geometry and "bake" the lightmaps. You would then blend the dynamic lights with the static lights to achieve the final result for static objects. Dynamic objects would then be lit by all lights. But again here you may want to have some lights only contribute to the static scene. You can see this allot in the Unreal Engine.

If you have static lights you may also create "light volumes". This technique precomputes the area the light touches in a 3D texture. This allows static geometry to shadow dynamic objects by looking up into that texture.

The next thing you need to consider is filtering. The filtering will greatly influence the quality and performance of the final result. There are many different filtering algorithms and with different tradeoffs. It is hard to recommend one.

Reflection

As to reflection, it depends. It depends if you are trying to do proper reflection or just do first order ambient lighting.

Many implementation get away with "reflection captures" scattered in the scene. You can see this when the glossy tiles on the floor don't perfectly match up with the wall behind. This is one cubemap or spheremap that is used for all objects close by. Here you can either do a single capture once, every couple of frames or every frame. It depends on how dynamic your scene is. If you are going to blur the result anyway, this works great.

When you need perfect reflection it makes sense to explicitly capture reflection at the object. But in this case you would limit the number of objects that actually need it.

It is interesting with how few captures you need to make a scene look good. The question here is, will you let level designers place the captures or do you want to try to place them procedurally. Unfortunately I have not yet found a good algorithm that would do that for me.

\$\endgroup\$

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.