opengltexturesopentkartifactsskybox

OpenGL skybox texture wrapping artifacts


I am trying to make a path tracer using OpenTK and a compute shader, but I have been struggling with textures repeating on the edges of my skybox. I followed the tutorial from learnopengl and adapted it to work with my compute shader but I have not been able to get rid of these artifacts. Here you can see the texture repeating on the edges

This is the snippet that loads the skybox texture:

private TextureHandle _skyboxTexture;
...
protected override void OnLoad() {
    base.OnLoad();
    GL.Enable(EnableCap.TextureCubeMapSeamless);
    ...
    _skyboxTexture = GL.CreateTexture(TextureTarget.TextureCubeMap);
    GL.BindTexture(TextureTarget.TextureCubeMap, _skyboxTexture);
    foreach (var file in Directory.GetFiles(@"Images\Skybox")) {
        using (var image = SixLabors.ImageSharp.Image.Load(file)) {
            image.Mutate(img => img.Rotate(180)); // without this the textures dont line up
            using (var ms = new MemoryStream()) {
                image.Save(ms, new BmpEncoder());
                GL.TexImage2D(Texture.CubeMapTextureTargetFromString(file), 0, (int)InternalFormat.Rgb, 2048, 2048, 0, OpenTK.Graphics.OpenGL.PixelFormat.Bgr, PixelType.UnsignedByte, ms.ToArray());
            }
        }
    }
    GL.TexParameteri(TextureTarget.TextureCubeMap, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
    GL.TexParameteri(TextureTarget.TextureCubeMap, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
    GL.TexParameteri(TextureTarget.TextureCubeMap, TextureParameterName.TextureWrapS, (int)TextureWrapMode.ClampToEdge);
    GL.TexParameteri(TextureTarget.TextureCubeMap, TextureParameterName.TextureWrapT, (int)TextureWrapMode.ClampToEdge);
    GL.TexParameteri(TextureTarget.TextureCubeMap, TextureParameterName.TextureWrapR, (int)TextureWrapMode.ClampToEdge);
    ...
}

These are a couple screenshots from RenderDoc, you can clearly see the artifact in the skybox texture. In the other picture you can see that the clamping and seamless settings are loaded correctly. Artifact in renderdoc

This image is blurry on stackoverflow but when you click it it's better. RenderDoc data

I don't think it is an issue with the sampling logic in my compute shader, because when using RenderDoc I can also see the artifact in the texture. I also tried saving the image from the MemoryStream to a .bmp to check if something is going wrong during the loading of the image, but the exported image looks fine. It's also not a problem with the skybox textures, it happens with all textures I try.


Solution

  • Thanks to derhass, I got it working. The problem was that the bitmap header caused a misalignment in the textures. I am using ImageSharp for image processing, so I created a new class that implements IImageEncoder and just puts the raw rgb values in the stream. I don't need the alpha channel so I omitted it but it can be added easily I think.

    public class RawBytesEncoder : IImageEncoder {
        public void Encode<TPixel>(Image<TPixel> image, Stream stream) where TPixel : unmanaged, IPixel<TPixel> {
            for (var y = 0; y < image.Height; y++)
            for (var x = 0; x < image.Width; x++) {
                var target = new Rgba32();
                image[x, y].ToRgba32(ref target);
                stream.WriteByte(target.R);
                stream.WriteByte(target.G);
                stream.WriteByte(target.B);
            }
        }
    
        public Task EncodeAsync<TPixel>(Image<TPixel> image, Stream stream, CancellationToken cancellationToken) where TPixel : unmanaged, IPixel<TPixel> {
            throw new NotImplementedException();
        }
    }
    

    I also had to change some stuff in the other part of my code. The image no longer needed to be rotated 180 degrees but needs to be flipped now, and the PixelFormat in glTexImage is Rgb again now.

    foreach (var file in Directory.GetFiles(@"Images\Skybox"))
        using (var image = Image.Load(file)) {
            image.Mutate(img => img.Flip(FlipMode.Horizontal));
            using (var ms = new MemoryStream()) {
                image.Save(ms, new RawBytesEncoder());
                GL.TexImage2D(Texture.CubeMapTextureTargetFromString(file), 0, (int)InternalFormat.Rgb, 2048, 2048, 0, PixelFormat.Rgb, PixelType.UnsignedByte, ms.ToArray());
            }
        }
    }