Advertisement

Environment map seam

Started by May 14, 2019 02:48 PM
2 comments, last by dietrich 5 years, 8 months ago

Hi everyone!

I'm implementing image-based lighting in a demo program and I ran into a problem with sampling an environment map. For the map I use a free HDR sample from CGSkies, loaded with stb_image. I create the texture with DXGI_FORMAT_R32G32B32A32_FLOAT and call GenerateMips on it (I do intend to implement proper environment map filtering later). Here is fragment shader code that samples the map:


float3 reflectionDir = reflect(-dirToViewer, normal);
float theta = acos(reflectionDir.z);	 // lat, 0..PI
float phi = atan2(reflectionDir.y, reflectionDir.x); // lon, 0..2PI
float emx = phi / (PI*2);
float emy = theta / PI;
float3 emsample = textureEnv.Sample(samplerDiffuse, float2(emx, emy));
return float4(emsample, 1.0f);

The reflection on the sphere has a seam that passes through the sun (envmap01). Notice however, that the sun is in the middle of the texture, nowhere near any border. Also, if a add an offset to the x coordinate, the reflection moves, but not the seam (envmap02). If I move the camera, the seam moves with the reflection.


float emx = phi / (PI*2) + 0.2f;

Finally, the seam disappears if I do any of the following (envmap03):

1) Set sampler's MaxLOD to 0,

2) Create a Texture with only a single mip level,

3) Sample the texture with SampleLevel, even with a fractional LOD level.

And that's where I'm at right now. Looks like it has something to do with mip mapping, since first two methods effectively disable it, but I don't see how SampleLevel is different from regular Sample with a hardware-calculated level. Will greatly appreciate any pointers!

envmap01.jpg

envmap02.jpg

envmap03.jpg

CGSkies_0132_free.jpg

If you inspect the texture in Renderdoc, Nsight or some graphics debugger, are the MIP levels there? Sampling with SampleLevel and fractional MIP level might be still sampling MIP 0 if the MIP filtering of the sampler is set to POINT. Also, GenerateMips() might not be supported for DXGI_FORMAT_R32G32B32A32_FLOAT, I'm not sure, does the DX11 debug layer emit any errors, warnings?

Advertisement

@turanszkij thanks for the advice! I took a look at the texture in the VS graphics debugger and the mip maps are indeed there. My hardware doesn't support mipmap generation for DXGI_FORMAT_R32G32B32_FLOAT (3 components), but R32G32B32A32_FLOAT seems to work fine.

Anyway, looks like I was worrying too much about the texture being an HDR image, when in fact it had nothing to do with the problem, and didn't pay enough attention to the math behind the mapping. Apparently the mapping itself was causing the seam, namely, the function atan2(y, x), which has a discontinuity when x is negative and y changes sign. If I output the emx coordinate directly, the discontinuity is clearly visible. I'm guessing that this discontinuity caused the mip level selection to freak out (texture coordinate derivative very high) and sample the highest mip, which is a single bluish gray pixel, resulting in a visible seam. That also explains why there was no seam when selecting the mip level manually.

Now the question is what I should do about it, and the first answer that comes to mind is - nothing? I believe it is common to use environment map's  mip levels to store prefiltered versions of the map for glossy reflections; besides, I eventually intend to use cubemaps, eliminating the need for atan2. But learning of its limitations was still worth it, I guess?

envmap04.jpg

This topic is closed to new replies.

Advertisement