Filtering Cubemaps

Started by
5 comments, last by Batzer 9 years, 9 months ago

Hey guys,

I'm currently trying to implement Variance Shadow Maps and I just can't figure out how to filter the cubemaps for the omnidirectional lights. For the spotlights I just apply a gaussian blur, but I can' find a way to do this with cubemaps. How do other games tend to solve this problem?

Advertisement

A cubemap is just 6 2D textures, one for each face of the cube, so if you are able to filter a regular 2D texture then filtering a cubemap would just be an extension of that. The simplest approach would be

1. Create additional cubemap to hold result.
2. Bind each face of the cubemap created in 1, sample the sample face in the shadow cubemap and do your filtering.
3. Write result into the output texture ( current face of the cubemap created in 1. )
4. Repeat for the other 5 faces.

Thank you for your answer!

But wouldn't this approche have potential artifacts at the edges of each face? I mean when a shadow is spread across two faces, shouldn't the blur take some texels from both faces?

Yes, you will potentially get artifacts along the seams of the cube map if you blur them the way cgrant suggests. I think a lot of games solve this problem by just not having shadowmap support for point lights (or if they do, they might use dual paraboloid mapping or something to minimize both the number of seams that have to be hidden and the memory footprint of the shadowmap).

If you really want to use cube maps and filter them correctly you'll have to filter one face at a time, and for each texel you will have to reconstruct the normal that corresponds to that texel, then perform the gaussian blur by sampling the cubemap in the neighborhood around that normal on the unit sphere.

I think a lot of games solve this problem by just not having shadowmap support for point lights

They use a single 2D texture with all 6 faces on it.


I just can't figure out how to filter the cubemaps for the omnidirectional lights.

Filtering a cubemap texture is extremely slow.
The solution is not to use cubemaps at all. Use a single 2D texture.
If you want a cubemap resolution of 512-by-512, make a 2D texture 512-by-3,072.
The [0,0] - [512,512] area is the left face.
The [0,512] - [512,1024] area is the front face.
Etc.
You render each face of the “cube” into one 512-by-512 section of the 2D texture.

Next you perform filtering. This is fairly basic. You simply have to make a coordinate converter so that taps off the edge of one face go to the proper part of the texture where the correct face is stored.
With that function, filtering is done the standard way.

Rendering with that texture is also fairly basic.
You just have to write your own 3D coordinate converter to take a 3D vector and pick the correct part of the texture to read. This can be made very efficient depending on how you organize the faces of the cube inside the texture.


This is how most game companies do it, and it runs in real-time on devices as low as iPad 3/Xbox 360/PlayStation 3.


L. Spiro

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid

On all modern hardware a cubemap is just a texture array with NumSlices = 6, so there's not really much difference (from a hardware POV) between a cubemap and an 'atlased' texture where 6 faces are packed into one long horizontal strip. The main difference is that if you want to you have access to an easy direction->UV conversion in shader, or alternatively if you just want to treat it as an array you can easily address each face using an array index. In D3D11 which behavior you get is dependent on how you set up your shader resource view, and what type is declared in your shader. Personally I would probably go with a cubemap to get the nice cubemap behavior when sampling the filtered shadow map, especially since in D3D11 hardware filtering works correctly across cubemap seams.

Nvm got it to work.

This topic is closed to new replies.

Advertisement