Advertisement

Cubemap Sampling Artifacts

Started by December 18, 2024 07:26 PM
6 comments, last by NubDevice 1 week, 2 days ago

Hi guys,

This is not strickly a games related question but I was hoping that some of you with more experience than me might be able to shed some light on why I am getting the following results.

Using Opengl, I was able to generate capture the depth of a scene around a viewer location and generate a flat rendering of this scene after using spherical coordinates to sample a previously generated cubemap containing the depth information of a scene.

The result was the resulting image,

image

At a first glance looks exactly what I was after. However, when this image (containing depths) is differentiated numerically in both the vertical and horizontal direction respectively, we get some artifacts,

image
image

You can see at the bottom how it appears to pick up the seams of the cubemap. These will be more or less obvious depending on the viewpoint location. I made sure that glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS) was included before sampling the cubemap.

My goal is to produce a rendering where each pixel contains the depth of a regular fixed azimuth and pitch. Sampling of the previously created cubemap is done using spherical coordinates (I am using the following fragment shader).

#version 440 core
uniform vec2 display_size;
uniform vec2 offset; // current viewer's camera yaw and pitch
uniform vec2 fov;
uniform samplerCube cube;
out float color;
void main()
{
   // Calculate angles used for sampling
   float u = (gl_FragCoord.x / display_size.x) * 2 - 1;
   float v = (gl_FragCoord.y / display_size.y) * 2 - 1;
   float theta = u * radians(fov.x/2) + radians(offset.x);    
   float phi   =  v * radians(fov.y/2) + radians(offset.y);
   // make sure that phi is between [-89.9, 89.9]
   phi = clamp(phi, radians(-89.9), radians(89.9));
   // calculate sampling coordinates
   vec3 dir;
   dir.x = -cos(phi) * cos(theta);
   dir.y = sin(phi);
   dir.z = cos(phi) * sin(theta);
   color = texture(cube, dir).r;
}  

Could this due to the sampling scheme I am using? (I do not think so as it appears to be sampling smoothly across the cubemap faces. Artifacts only appear when three faces are used, specifically the bottom Y- face). Is there anyway to resolve this?

Any comments, suggestions will be very welcome!!

Thanks,

M.

I believe the artifacts in your derivative images are inherent to the cube map representation. When you sample the cube map, the values are continuous (C0 continuity), but they are not continuous in their derivatives (not C1 continuous).

You also probably want to linearize the depth, since the depth buffer you sample will not contain the raw depth, but instead contains 1/depth. Any nonlinearities in the depth values could be causing lack of C1 continuity when calculating derivatives across the cube faces.

Advertisement

Many thanks @@Aressera !!

The depth is actually not the depth derived from the depth buffer but the one derived from finding the distance from the camera location to each pixel.

Hmmm,… what I find more concerning is what you mention about the discontinuities for the derivatives. Why wouldn't these appear when sampling across (i.e. when sampling the cubemap faces X+ X- Z+ Z-) the cubemap faces???

Also I have come across the following link about Dual-Paraboloid Reflections. Would this be able to solve this problem and if so, how would this be implemented???

Thanks again.

mllobera said:
Hmmm,… what I find more concerning is what you mention about the discontinuities for the derivatives. Why wouldn't these appear when sampling across (i.e. when sampling the cubemap faces X+ X- Z+ Z-) the cubemap faces???

The artifacts are most visible in the corners of the cube.
It helps to increase the resolution of the texture, so the corners cover less texels and the artifacts become smaller, but ther is no way to avoid these artifacts.
Also keep in mind that the bilinear texture filter itself is not C1.
Basically we have only low quality filtering with GPUs. If we need better quality, we need to implement a higher order filter ourselves. (Which is much slower than HW acceleration ofc.)

mllobera said:
Dual-Paraboloid Reflections.

The problem area moves from the cube vertices to the split diameter.

It might be better for your case eventually,
but i would just calculate the color from the spherical coordinates directly, not using any form of environment texture.
(You could still use a 1D gradient texture to achieve the desired coloring if needed)

Thanks @JoeJ

i would just calculate the color from the spherical coordinates directly, not using any form of environment texture.
(You could still use a 1D gradient texture to achieve the desired coloring if needed)

I was not able to understand your last suggestion. Could you elaborate a bit more?

mllobera said:
I was not able to understand your last suggestion. Could you elaborate a bit more?

Oh, never mind.
I was thinking you would render a terrain mesh, using the vertex normals for the cubemap to get the coloring.
But now after reading your code, i see the mountains are in the cubemap texture, and the spike artifacts at the bottom are probably cube edges.

Looking closeley, i think the problem is maybe in the texture. Make sure there is some color dilation across the UV boundary. It looks like you could fix it by painting green over the texture, at the right spots?
It does not look like the typical corner filtering artifact i was talking about. Your corners should be just green, so the artifact should not affect your example.

Otherwise i would guess something like texture wrapping mode is wrong, although i'm not sure if such mistake is possible using cube maps.

Advertisement

Pitching the view direction down might reveal a clue? Or cubemap width is not a power of two?

Dev careful. Pixel on board.

Advertisement