http://www.iquilezles.org/www/articles/texturerepetition/texturerepetition.htm

 

이니고 퀼레즈의 100번째 컴퓨터 그래픽스 아티클!!!

 

 

Problem



One of the most typical problems with texture mapping of large surfaces is the visible repetition of the texture. While things like GL_ARB_texture_mirrored_repeat can help alleviate the problem a bit by making the period of repetition twice bigger, the hardware cannot solve the problem on its own. However, if we are okey with paying the cost of more than a single texture fetch per sample, then there are pretty decent ways to prevent texture repetition.



The texture to be tiled

Regular texture tiling with GL_REPEAT

The proposed solutions with "Technique 1"



Technique 1



One way to prevent the visual repetition of the texture is to assign a random offset and orientation to each tile of the repetition. We can do that by determining in which tile we are, creating a series of four pseudo-random values for the tile, and then using these to offset and re-orient the texture. Re-orientation can be something as simple as mirroring in x or y or both. This produces a non repeating pattern over the whole surface.

The technique just described comes with some caveats that needs to be solved: First, the pattern will show seams across the tile boundaries, since the differently offseted texture tiles won't match at the tile borders. Secondly, because of the discontinuity introduced on the final texture fetch coordinates themselves, the derivatives will have huge jumps at the tile borders and mipmapping will break apart, creating line artifcats.

One solution to solve both problems is to sample the texture with the offset and orientation mentioned above at four texture tiles, and blend between them when sufficiently close to the border of the current tile (in the possitive U and V directions for example). While this will introduced some amount of blurring in the certain areas of the tile, it is acceptable in most cases, as shown in the image at the beginning of the article.

Of course, for this to work we must use custom texture gradients of course, which must come from the original repeating UV mapping.

The code is pretty simple, and you can find it live in Shadertoy: https://www.shadertoy.com/view/lt2GDd

vec4 textureNoTile( sampler2D samp, in vec2 uv )
{
    ivec2 iuv = ivec2( floor( uv ) );
     vec2 fuv = fract( uv );

    // generate per-tile transform
    vec4 ofa = hash4( iuv + ivec2(0,0) );
    vec4 ofb = hash4( iuv + ivec2(1,0) );
    vec4 ofc = hash4( iuv + ivec2(0,1) );
    vec4 ofd = hash4( iuv + ivec2(1,1) );
    
    vec2 ddx = dFdx( uv );
    vec2 ddy = dFdy( uv );

    // transform per-tile uvs
    ofa.zw = sign( ofa.zw-0.5 );
    ofb.zw = sign( ofb.zw-0.5 );
    ofc.zw = sign( ofc.zw-0.5 );
    ofd.zw = sign( ofd.zw-0.5 );
    
    // uv's, and derivarives (for correct mipmapping)
    vec2 uva = uv*ofa.zw + ofa.xy, ddxa = ddx*ofa.zw, ddya = ddy*ofa.zw;
    vec2 uvb = uv*ofb.zw + ofb.xy, ddxb = ddx*ofb.zw, ddyb = ddy*ofb.zw;
    vec2 uvc = uv*ofc.zw + ofc.xy, ddxc = ddx*ofc.zw, ddyc = ddy*ofc.zw;
    vec2 uvd = uv*ofd.zw + ofd.xy, ddxd = ddx*ofd.zw, ddyd = ddy*ofd.zw;
        
    // fetch and blend
    vec2 b = smoothstep( 0.25,0.75, fuv );
    
    return mix( mix( textureGrad( samp, uva, ddxa, ddya ), 
                     textureGrad( samp, uvb, ddxb, ddyb ), b.x ), 
                mix( textureGrad( samp, uvc, ddxc, ddyc ),
                     textureGrad( samp, uvd, ddxd, ddyd ), b.x), b.y );
}

Note that the code propagates the orientation mirror transformation to the derivatives. Since the underlaying hardware is probably taking the absolute value of these, you can pretty savely optimize those away and simply pass ddx and ddy to the textureGrad() function.

The only remaining caveat with this technique is that the per-tile hash function might by alias at high minification factors. For example, if this technique is used to texture a huge terrain, depending on the way this texturing method is used, aliasing might occur in the horizon or distant parts of the terrain.



Technique 2


Another way to get even more organic looking texture un-tile-fication (just invented a word there) is to bomb the whole surface with randomly scaled, offseted and rotated copies of the original texture which get blended together, with the blending weight factor dependant on the distance to the center of each of these copies. This can be accomplised with a smooth voronoi patter for example. Blending weights proportional to a gaussian fallof for each feature point in the voronoi pattern works fine. Just rememner to renormalize the final color to the total contribution of each feature point, otherwise textue brightness range will be lost.

Live code in Shadertoy can be reached here: https://www.shadertoy.com/view/4tsGzf

vec4 textureNoTile( sampler2D samp, in vec2 uv )
{
    vec2 p = floor( uv );
    vec2 f = fract( uv );
	
    // derivatives (for correct mipmapping)
    vec2 ddx = dFdx( uv );
    vec2 ddy = dFdy( uv );
    
    // voronoi contribution
    vec4 va = vec4( 0.0 );
    float wt = 0.0;
    for( int j=-1; j<=1; j++ )
    for( int i=-1; i<=1; i++ )
    {
        vec2 g = vec2( float(i), float(j) );
        vec4 o = hash4( p + g );
        vec2 r = g - f + o.xy;
        float d = dot(r,r);
        float w = exp(-5.0*d );
        vec4 c = textureGrad( samp, uv + o.zw, ddx, ddy );
        va += w*c;
        wt += w;
    }
	
    // normalization
    return va/wt;
}


Of course, the drawback is the algorith samples the texture 9 times, which might streess the memory bus too much. But in the other hand, it really help with high quality imagery or situation where just simply can affort it.



Regular texture tiling with GL_REPEAT

Smooth Voronoi based tiling

'게임개발 > 필기노트' 카테고리의 다른 글

유니티 셰이더 공부  (0) 2016.06.02
피타고라스의 정리  (0) 2016.05.26
라디안(radian)과 디그리(degree)  (0) 2016.05.13
프랙탈 연습  (0) 2016.04.01
3D Max object에 Skin으로 bone 연결해주기  (0) 2016.03.16

+ Recent posts