Jump to content
  • Advertisement
Sign in to follow this  
toasterthegamer

Texture Atlas seam issue.

This topic is 2592 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I want to support a large number of textures on my terrain using splatting. I decided that a texture atlas with splatting would be the best option. Each texture I am using is 512x512 pixels in size, and I store 4 of them on a 2048x2048 surface. I use this method to help reduce or remove UV seams cause of filtering: http://www.ogre3d.or...php?f=4&t=61602

It works great and I have no problems with it and filtering, however I still get UV seams not related to the filtering so I think my coords are a little off.

Here's my look up code:

GetTex(UV, float2(0, 0)) // I would use 1,0 or 1,1 to get the different textures. 0, 0 being the first texture.

GetTex function code:

UVOffset *= .5f;
float2 Coords = ((0.125f + UVOffset) + frac(UV) * (.25f));
return tex2D(Samp, Coords);

.125 is where the texture starts if my UV's are right, and then .375 would be where it ends. and the stuff around that is tiled texture in order to fix the seams when you mip map and filter the texture.

This should return the first texture in the atlas and it works good, I see the first texture it tiles good, the only problem is I still have seams where the texture isn't right. I've turned off all filtering and the problem still exists. I have a feeling its something to do with my UV coords, but I am not entirely sure. The seams are hardly noticeable, but its still annoying when you get close to the landscape, and on some textures the seams are very visible.

Any help will be greatly appreciated! :)

-Toaster

Share this post


Link to post
Share on other sites
Advertisement
Here is a screenshot of the issue:
http://i.imgur.com/eajsW.png

I know the texture is seamless so that is not an issue. I believe it to be the UV cords that I am using.

Have you concidered using a texture array instead?



This is not an option as I would like to stick with SM2.0 which provides only 8 texture samplers. This is simply not enough for my needs, I would like up to 12 textures atleast, and with this method I am using I should be able to store 12 textures inside of 3 texture samplers.

-Toaster

Share this post


Link to post
Share on other sites
There's not much to go off. You shader code looks fine, assuming that you've got a 512x512 tileable texture (1/4 width of atlas) located with a 256px margin (1/8th width of atlas)...

Do the artefacts go away if you disable mip-mapping?

If not, I'd have to guess that your atlas isn't correct -- if you use an image editor to cut out the 512x512 section, starting from the 256px margin, is that cut-out area tileable?

Share this post


Link to post
Share on other sites
Thanks for the fast reply! :)

[color="#1c2837"]Do the artifacts go away if you disable mip-mapping?[/quote]
Surprise they do. I thought adding the border around the texture would fix this. Does anyone have any advice?

At the advice of someone else I tried something like this:
[color=#1C2837][size=2]

[color=#1C2837][size=2]float HalfPixel = 0.5f / 512.0f;
UVOffset *= .5f;
float2 Coords = ((0.125f + UVOffset) + frac(UV) * (.25f));
return tex2D(Samp, clamp(Coords, (.125f + UVOffset) + HalfPixel, (.375f + UVOffset) - HalfPixel));

[color=#1C2837][size=2]

[color=#1C2837][size=2]Clamping doesn't seem to be the right thing to do here though cause you'd get sudden drop offs. I think instead I need to make sure the cords are always in between .125f + halfpixel and .375 - HalfPixel.
[color=#1C2837][size=2]

[color=#1C2837][size=2]I am going to keep cracking away at this. :)
[color=#1C2837][size=2]

[color=#1C2837][size=2]-Toaster

Share this post


Link to post
Share on other sites
[color="#1c2837"]Do the artifacts go away if you disable mip-mapping?
Surprise they do. I thought adding the border around the texture would fix this. Does anyone have any advice?[/quote]Ok I think I know what your problem is then -- the border pixels around the seam area are choosing a very low-res mip-level, whereas the rest of the pixels are choosing sensible mip-levels.

This is occurring because of the way that your GPU is choosing mip-levels: it looks at the UV coords of the current pixel and the UV coords of the neighbouring pixels, and compares them to determine the rate-of-change in the UV-coordinates.
If the UVs are changing quickly, it selects a low-res mip. If the UVs are changing slowly, it selects a high-res mip.

Your UV-wrapping logic is screwing up this algorithm, basically tricking the GPU into thinking that those border pixels are really zoomed out --- it sees the coord of 0.125 at one pixel, and 0.375 at the next pixel, and assumes you want to get the average of all values between those two texels.

To get around this, you need to determine the rate-of-change values manually. You can give these manually-calculated values to the GPU by using tex2Dgrad instead of tex2D.

When you write:float2 Coords = ((0.125f + UVOffset) + frac(UV) * (.25f));
return tex2D(Samp, Coords);
The GPU is actually doing:float2 Coords = ((0.125f + UVOffset) + frac(UV) * (.25f));
float2 dx = ddx(Coords);
float2 dy = ddy(Coords);
return tex2Dgrad(Samp, Coords, dx, dy);
But, instead, you want to the following - get the rate of change of the UV before doing your wrapping logic:float2 dx = ddx(UV * .25f);
float2 dy = ddy(UV * .25f);
float2 Coords = ((0.125f + UVOffset) + frac(UV) * (.25f));
return tex2Dgrad(Samp, Coords, dx, dy);

Share this post


Link to post
Share on other sites

[quote name='toasterthegamer' timestamp='1305783865' post='4812885']
[color="#1c2837"]Do the artifacts go away if you disable mip-mapping?
Surprise they do. I thought adding the border around the texture would fix this. Does anyone have any advice?[/quote]Ok I think I know what your problem is then -- the border pixels around the seam area are choosing a very low-res mip-level, whereas the rest of the pixels are choosing sensible mip-levels.

This is occurring because of the way that your GPU is choosing mip-levels: it looks at the UV coords of the current pixel and the UV coords of the neighbouring pixels, and compares them to determine the rate-of-change in the UV-coordinates.
If the UVs are changing quickly, it selects a low-res mip. If the UVs are changing slowly, it selects a high-res mip.

Your UV-wrapping logic is screwing up this algorithm, basically tricking the GPU into thinking that those border pixels are really zoomed out --- it sees the coord of 0.125 at one pixel, and 0.375 at the next pixel, and assumes you want to get the average of all values between those two texels.

To get around this, you need to determine the rate-of-change values manually. You can give these manually-calculated values to the GPU by using tex2Dgrad instead of tex2D.

When you write:float2 Coords = ((0.125f + UVOffset) + frac(UV) * (.25f));
return tex2D(Samp, Coords);
The GPU is actually doing:float2 Coords = ((0.125f + UVOffset) + frac(UV) * (.25f));
float2 dx = ddx(Coords);
float2 dy = ddy(Coords);
return tex2Dgrad(Samp, Coords, dx, dy);
But, instead, you want to the following - get the rate of change of the UV before doing your wrapping logic:float2 dx = ddx(UV * .25f);
float2 dy = ddy(UV * .25f);
float2 Coords = ((0.125f + UVOffset) + frac(UV) * (.25f));
return tex2Dgrad(Samp, Coords, dx, dy);

[/quote]

Wow that really worked nicely, and it makes sense too! :) Thank you so much for the help! I do notice though that ddx and ddy are not supported by SM2.0 while SM2.0a supports it but SM2.0b doesn't which is odd.

I think I am happy with leaving the lowest as 2.0a those are pretty older cards, and I think everyone should at least have SM3.0 cards by the time I plan on releasing stuff. Although I would be interested in hearing a possible work around for this. :) Also I get poor performance with SM2.0a which was kind of surprising. 45 FPS without normal mapping compared to the SM3.0 with normal mapping which is running at 80 fps. I guess some of the older commands are slower. :S

Thanks again!
-Toaster

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!