Glossy reflections - how to do a proper blur

Started by
6 comments, last by kalle_h 9 years ago
Hi guys - and ladies,
I'm wondering how to do a proper glossy("very blurry") reflection, using a cubemap. Looking a bit into PBS and such, I was experimenting with roughness settings. Had blurry reflections before, but the quality has been "meh" so far, especially when comparing them to -for example- Marmoset Toolbag.
>> Sampling lower LODs
My first guess was to simply use "roughness" as the sampling LOD setting, thus picking smaller(blurred) levels of the environment cubeMap when things get rough. But... it looks like crap when going too low-res. Having ATIcubeGen doing the filtering certainly helped a bit, but still. Things just look blocky when sampling too low, not like a smooth guassian alike blur.
>> Irradiance map
Second thing I tried was to convert the cubeMap to an irradience map, which sort of gives a highly blurred result. But as the name says, these maps are meant for diffuse lighting purposes, not reflections. Result was a bit weird. Moreover, mixing between sharp reflections and this map didn't give a nice result.
Speaking of irradiance and IBL btw, is it common for games to provide 2 different cubeMaps/probes (1 irradiance map, 1 regular environment map for sharper reflections)? Or maybe storing the irradiance map with spherical harmonics...
>> Blurring by taking lots of samples
Third attempt was to take lots of samples (32) and use a noiseMap to randomly distort the reflection vector, and taking an average of all the samples. That alone still didn't bring me a nice blur, plus you'll have to be careful with the noise not to create a certain pattern that repeats all over the surface. It makes you feel itchy.
Combining the multiple samples with a lower LOD (but not the lowest ones!) actually did give me quite a good result. But still... a small "Close but no cigar" voice is there (maybe because my multi-sample method is dumb and straight forward), and moreover, taking 32 samples sounds like an overkill for real-time game purposes. Of course, less samples can do (16 is still pretty ok), but at a quality cost.
Any proven fast methods for doing this / smarter multi-sample tricks?
Thanks for the always great help here in advance!
Advertisement

Have a look at this presentation by Epic, they show how they deal with IBL for their shading pipeline in Unreal 4

Slides: http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_slides.pdf

Course notes: http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf

They do a split-sum approach where they encode one part of their BRDF data in a lookup texture and the irradiance data in an importance sampled cube texture. Every mip level of this cube texture represents a different roughness level, so you can achieve these rough glossy reflections.

I gets all your texture budgets!

Thanks for the information!

I'll idea of splitting up the lighting function (BRDF) in a 2D LUT and environment map, though I never really understand the formula's in such papers. But first, I guess that on itself doesn't improve the reflection sampling.

When I simply fetch the lower LOD's, for example:


float lodLevel = roughness * numOfMips;
vec3 reflDir = normalize( -V, N );
vec3 result = textureCubeLod( envMap, reflDir, lodLevel );

the result gets blocky or "cubic" (see left side of the attached image in 1st post), instead of "nicely blurred". It gets better by NOT accessing the deepest LOD's and doing multiple samples, yet I guess it can be done more efficient. Maybe my CubeMap just sucks to begin with (though with ATIcubeGen which should blur & still respect the seams, it still doesn't look good). Or maybe my OpenGL texture sampling method is just wrong?

The Unreal Engine paper notices "Pre-filtered Environment maps". Now maybe here's the catch, If I understand well, the EnvMap doesn't just contains a traditional (mipmapped) "snapshot of the environment", but encodes the 1st sum of the BRDF, where each mip filters its content with a certain roughness setting.

But what is this "First Sum"? The paper mentions the formula (1/N) Li (lk) - sorry can't write it, but its on page 12. Call me stupid, but I never understand how to interpretate that. It likely covers the diffuse and/or specular calculations, such as dot(L,N), but I miss the details plus a five-year-old explanation.

Sorry for the long post. I have to speak loud to understand myself hehe.

One simple thing that could help regarding your "Sampling lower LODs" idea:

Blur the texture before you make the next Mip Map level. Simply summing up 4 Texels * 0.25 is not so good.

(It may be that Graphics APIs or Cube Map Gen already do that, or it is related to the Mip Map generation quality settings in driver... i don't know)

Blurring makes the Mip Map smoother and also causes very bright pixels to bleed over a larger area, but energy is conserved.

@JoeJ

First I had OpenGL automatically generating the mipmaps. Having ATIgenCubeMap tool doing it indeed does a better job (plus you can do more filtering). The attached picture is showing results with OpenGL generated mipMaps.

Yet, when sampling the deepest levels, I keep getting that "box" effect, wether its blurred or not. In the ATI tool preview this "artefect" is far less visible, which makes me think maybe some sampler settings are wrong / too simplistic.

Either way, combined with multiple samples, the result gets acceptable. But I'm curious if someone can explain some details about the Epic paper that was posted by Radikalizm here above!

https://www.opengl.org/wiki/Cubemap_Texture#Seamless_cubemap

Subtle, but certainly another step forward! Doing glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS)? & having higher quality lower LOD levels almost ellimated the ugly "box" effect and the need of multiple distorted samples. At least I can do with far less samples to get a pretty cool result. I always like these more simple solutions :)

http://www.frostbite.com/2014/11/moving-frostbite-to-pbr/

There is trick called dominant direction. Basically it skews reflection vector towards normal vector with rough surfaces.

This topic is closed to new replies.

Advertisement