Elimination of seams during texture tiling

First of all, I wish everyone a Merry Christmas :christmas_tree:

I use mipmap textures in a wgsl shader with r160. The result is significantly better than without mipmaps.
I now have to solve a related problem that arises during tiling, seams.
As you can see in the screenshot, black lines appear between the tiles when tiling.

I would now like to eliminate these seams. Since this isn’t a new phenomenon, I thought I’d ask if anyone had a solution that would help me save time. I imagine, for example, in front of which the edge pixels of the texture are repeated around the texture and are blended with the neighboring tile during tiling. Does anyone have a nice solution?

Merry XMas!

Are you tiling a subregion of a texture, or the whole texture?
Filtering relies on having texel data outside the bounds of the uv rectangle that you’re tiling… so if you’re trying to tile a region inside an atlas, you may need to create a border around the region that duplicates the edge pixels into the border region, so that filtering doesn’t pull incorrect data from outside the edges. The size of the border needed depends on the filtering anistropy(?). I think 16 pixels is a good rule of thumb.

If you’re tiling a whole texture, then you shouldn’t really see seams even under mipmapping, since the hardware knows how to properly filter across full texture boundaries…
If you are seeing seams, then perhaps there is an issue with the way that you are generating mipmaps?

Hi manthrax,

thank you and Merry Christmas to you too. For me, Christmas is always a wonderful time.

I tile entire textures. With r160, mipmaps for the storage textures were added. You can’t go wrong when creating a mipmap. For that I just have to do the following:

this.derivative = new StorageTexture(params.size, params.size);
this.derivative.type = THREE.HalfFloatType;

//with this settings the mipmaps will be created directly after the texture is computed
this.derivative.generateMipmaps = true;
this.derivative.minFilter = THREE.LinearMipMapLinearFilter; 
this.derivative.magFilter = THREE.LinearFilter;

I have now managed to filter the edges quite well. To do this, I take the color value of the edge pixels at half the pixel width from the edge and interpolate this in a linearly decreasing manner up to half the pixel width of the opposite edge pixel of the tiled texture. This technique then will works for all mipmap levels, even the smallest one with 1 x 1 pixel.

What’s still bothering me at the moment are the corners.

I don’t seem to have any talent for finding solutions on the web. Paper and pencil are often my most important tools when finding solutions. Paper coding :smile:

Interesting. I’m still kinda confused tho, because hardware generated mipmaps and using texture2D( in your shader, should just work and not give you seams?
You shouldn’t have to do any heroics to make them tile?
Do you perhaps not have texture.wrapS = texture.wrapT = THREE.RepeatWrapping?

1 Like

I use:

this.derivative.wrapS = this.derivative.wrapT = THREE.RepeatWrapping;

However, this is of no use.

There is no “texture2D” in WebGPU.
The analogue is “textureSample”. To do this you then have to use a sampler which you also have to set yourself. For that I simply used the texture. Hm… maybe I have to use a different sampler? :thinking:
I’ll read what’s available in the W3C manual.
I can solve it by myself, but if there is something that saves unnecessary coding in the shader, I’ll be happy to take it.
In glsl I never had to worry about anything like that, there were no seams, but wgsl is a slightly different world.

This video popped up on my feed, not sure if it’s the same ordeal, but he seams to be going down the same path as you.

1 Like

Yes, it’s the same math, a beautiful ocean. My 3js ocean will be just as good.
I just noticed something interesting when I wanted to do the pixel filtering for the deeper mipmaps.
If I retrieve the individual mipmaps with textureSampleLevel then there are no seams. The tiling fits wonderfully on every mipmap level. That’s strange. The same sampler, the same uv coordinates, the same texture. With textureSample I see seams but with textureSampleLevel there are none. I have to read the W3C manual to see if there’s anything to consider.

2 Likes

I think I’ve found the cause. I read a little about how textureSample works. wgsl is kept fairly simple in terms of buildIn functionality to maximize performance. The internal filtering of textureSample between the mipmaps causes artifacts and hence the seams. Every mipmap level is perfectly tiled. I checked them all individually with textureSampleLevel. There isn’t even an analog command in wgsl to read out the current mipmap lod level like you can do in glsl. So I had to build my own mipmap lod level interpolation function and behold, everything was perfectly clean without any seams.

You can’t even begin to see any transitions.

That’s the price for the impressive performance with wgsl, you have to tackle some things much more deeply than in glsl.
Then I can soon look at the extension with the DepthTexture for the wgsl shaders. The depthTexture will be pretty important.

2 Likes