Jump to content
  • Advertisement
Sign in to follow this  
Samurai Jack

glsl represent 1 big texture as 4 smaller ones (tearing)

This topic is 906 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

Hi!

 

I would like to represent 1 big texture (1024x1024) as 4 smaller textures (4x 512x512).

The reason of doing so is that mobile devices do usually not support textures greater

than 4096x4096 and I need to represent for example a 8192x8192 as 4 4096x4096

textures.

 

So the idea is very simple:

 

1.) Take one texture and split it into 4 smaller ones

2.) Instead of one 1024x1024 you get 4x 512x512 textures ( Upper left, Upper right, Lower right, Lower left)

3.) According to the UV coordinate, the shader picks the correct tile

 

When using 1 single texture on a geosphere (icosa) everything looks just fine.

sphere2.jpg

 

When I use a pixel shader that selects out of 4 textures I do get artifacts on

the clipping / boarder regions:

artifacts.jpg

 

The fragment/pixel shader code:

/* Texture clips */
uniform sampler2D clipTopLeft;
uniform sampler2D clipTopRight;
uniform sampler2D clipBottomRight;
uniform sampler2D clipBottomLeft;

/* UV from the vertex shader */
varying vec2 srcUv;

void main( void )
{
  /* Scale up source uv */
  vec2 dstUv = vec2(srcUv.x * 2.0, srcUv.y * 2.0);

  /* Clip & wrap the UV */
  if (dstUv.x > 1.0) dstUv.x -= 1.0;
  if (dstUv.x < 0.0) dstUv.x += 1.0;
  if (dstUv.y > 1.0) dstUv.y -= 1.0;
  if (dstUv.y < 0.0) dstUv.y += 1.0;

  /* Select clip */
  if (srcUv.x < 0.5 && srcUv.y > 0.5)
    gl_FragColor = texture2D( clipTopLeft, dstUv );
  else if (srcUv.x >= 0.5 && srcUv.y > 0.5)
    gl_FragColor = texture2D( clipTopRight, dstUv );
  else if (srcUv.x < 0.5 && srcUv.y <= 0.5)
    gl_FragColor = texture2D( clipBottomRight, dstUv );
  else if (srcUv.x >= 0.5 && srcUv.y <= 0.5)
    gl_FragColor = texture2D( clipBottomLeft, dstUv );
}

What could be wrong?
a) The if statement selection the correct clip

b) Destination UVs

c) Both ?

d) Something else?

 

Thank you in advance!

Share this post


Link to post
Share on other sites
Advertisement

Don't see anything immediately wrong. Your wrapping code is wrong if the UV is tiled. If the uv is tiled and has a value of 10.1, you clipped it to 9.1 instead of .1.

 

gl_FragColor = dstUv as well as srcUv, does that look fine or are their discontinuities in those as well?

 

 

  • /* Scale up source uv */
  • vec2 dstUv = vec2(srcUv.x * 2.0, srcUv.y * 2.0);

 

Didn't really get this, uv values should always be 0 to 1.  To get a proper quadrant it will be scaled by .5 and translated by .5. I assume your math works by the pic but based on this your uv values must be in 0 to .5 for some reason.

Edited by dpadam450

Share this post


Link to post
Share on other sites

You're gonna have trouble with bilinear (gets worse with trilinear) filtering at the edges because the GPU should be interpolating between the two textures, but obviously this won't happen, so you need to do it yourself.

 

Potentially you may have to sample all four textures and interpolate it yourself:

// Assuming layout of textures:
// |0|1|
// |2|3|
result = mix(
mix( c0, c1, fract( uv.x * 1024.0 - 0.5/1024.0 ),
mix( c2, c3, fract( uv.x * 1024.0 - 0.5/1024.0 ),
fract( uv.y * 1024.0 - 0.5/1024.0 ) );

If you're at the left/right edge, you only need c0 & c1 or c2 & c3; if you're at the top/bottom edge you only need c0 & c2 or c1 & c3. But if you're close to the cross intersection, you're going to need to sample and mix all 4 textures.

 

Also the mipmaps need to be generated offline based on the original 1024x1024 rather than generating them on the GPU since it will generate them based on the 512x512 blocks individually.

 

I can't think quickly of a way to fix the trilinear filtering problem though.

Edited by Matias Goldberg

Share this post


Link to post
Share on other sites

You're gonna have trouble with bilinear (gets worse with trilinear) filtering at the edges because the GPU should be interpolating between the two textures, but obviously this won't happen, so you need to do it yourself.

 

Potentially you may have to sample all four textures and interpolate it yourself:

// Assuming layout of textures:
// |0|1|
// |2|3|
result = mix(
mix( c0, c1, fract( uv.x * 1024.0 - 0.5/1024.0 ),
mix( c2, c3, fract( uv.x * 1024.0 - 0.5/1024.0 ),
fract( uv.y * 1024.0 - 0.5/1024.0 ) );

If you're at the left/right edge, you only need c0 & c1 or c2 & c3; if you're at the top/bottom edge you only need c0 & c2 or c1 & c3. But if you're close to the cross intersection, you're going to need to sample and mix all 4 textures.

 

Also the mipmaps need to be generated offline based on the original 1024x1024 rather than generating them on the GPU since it will generate them based on the 512x512 blocks individually.

 

I can't think quickly of a way to fix the trilinear filtering problem though.

 

If I recall correctly, we solved this (trilinear with discontinuous textures) in the past using tex2dGrad, which should be textureGrad on OpenGL... though that was sampling a texture in an atlas, rather than to another texture, so I'm not sure if it would still work.

Share this post


Link to post
Share on other sites

Sampling 4 times could be a bit expensive, considering you want to run this on hardware with a 512x512 texture size limit.

 

You could overlap the 512x512 textures one pixel line so that the duplicated data gives you a seamless linear filter and you end up with a 1023x1023 texture.

 

Also the mipmaps need to be generated offline based on the original 1024x1024 rather than generating them on the GPU since it will generate them based on the 512x512 blocks individually.

 

As long as everything is a power of two the generated mipmaps are the same except that a 1024 texture has one more texture level. If you use my idea above, you may need a custom mipmap generator.

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.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!