texture dilation filter- need HELP!

Mr.Pink

Newcomer
i' m implementing real time skin rendering using lightmap blurring like in ATI Ruby demo, i have found presentation slides from GDC 04-05, and a chapter in GPU gems1 about that

http://ati.amd.com/developer/gdc/Gosselin_skin.pdf
http://ati.amd.com/developer/siggraph04/Sander_SkinSketch.pdf

and discussed in thread
http://www.beyond3d.com/forum/archive/index.php/t-10661.html


here is UV parametrization of the mesh( it is not perfect ;) )
pic1:


alpha channel of a texture used in blur shader to know where sampling outside boundaries
pic2:


my problems come after blurring lightmap: due to large filter kernel 9x9 and subsequent blur pass, texture seams become evident (black eyes and mouth countours)
pic3:


relevant code snippet of lightmap computation fragment shader
alphaMap is pic2
Code:
gl_FragColor.rgb = AshikShirDiff(NdotL, dot(N, V), lightColor );
 gl_FragColor.a = texture2D(alphaMap, gl_TexCoord[0].st).a; //1 outside texture boundaryes
blurring fragment shader(vertical same as horizontal):
skinSamp1 is the light map
Code:
vec4 weight[5] = {
        {0.021, 0.0, 0.0, 1.0},
        {0.07, 0.0, 0.0, 1.0},
        {0.13, 0.086, 0.086, 1.0},
        {0.179, 0.244, 0.244, 1.0},
        {0.2, 0.33, 0.33, 1.0},
    };


vec4 mainCol = texture2D(skinSamp1, vec2(gl_TexCoord[0].s,gl_TexCoord[0].t)) * weight[4];
    vec4 OutCol = mainCol;
    float flag = OutCol.a;
    
    vec4 currCol = texture2D(skinSamp1, vec2(gl_TexCoord[0].s+ TexelIncrement * 4.0,gl_TexCoord[0].t)) * weight[0];
    OutCol += currCol ;
    flag = max(flag, currCol.a);
    if (currCol.a < mainCol.a)
        mainCol = currCol;

    currCol = texture2D(skinSamp1, vec2(gl_TexCoord[0].s+ TexelIncrement * 3.0,gl_TexCoord[0].t)) * weight[1];
    OutCol += currCol ;
    flag = max(flag, currCol.a);
    if (currCol.a < mainCol.a)
        mainCol = currCol;
 
     currCol = texture2D(skinSamp1, vec2(gl_TexCoord[0].s+ TexelIncrement * 2.0,gl_TexCoord[0].t)) * weight[2];
    OutCol += currCol ;
    flag = max(flag, currCol.a);
    if (currCol.a < mainCol.a)
        mainCol = currCol;
        
    currCol = texture2D(skinSamp1, vec2(gl_TexCoord[0].s+ TexelIncrement * 1.0,gl_TexCoord[0].t)) * weight[3];
    OutCol += currCol ;
    flag = max(flag, currCol.a);
    if (currCol.a < mainCol.a)
        mainCol = currCol;    
  
     currCol = texture2D(skinSamp1, vec2(gl_TexCoord[0].s- TexelIncrement * 1.0,gl_TexCoord[0].t)) * weight[3];
    OutCol += currCol ;
    flag = max(flag, currCol.a);
    if (currCol.a < mainCol.a)
        mainCol = currCol;

     currCol = texture2D(skinSamp1, vec2(gl_TexCoord[0].s- TexelIncrement * 2.0,gl_TexCoord[0].t)) * weight[2];
    OutCol += currCol ;
    flag = max(flag, currCol.a);
    if (currCol.a < mainCol.a)
        mainCol = currCol;
        
    currCol = texture2D(skinSamp1, vec2(gl_TexCoord[0].s- TexelIncrement * 3.0,gl_TexCoord[0].t)) * weight[1];
    OutCol += currCol ;
    flag = max(flag, currCol.a);
    if (currCol.a < mainCol.a)
        mainCol = currCol;
    
    currCol = texture2D(skinSamp1, vec2(gl_TexCoord[0].s- TexelIncrement * 4.0,gl_TexCoord[0].t)) * weight[0];
    OutCol += currCol ;
    flag = max(flag, currCol.a);
    if (currCol.a < mainCol.a)
        mainCol = currCol;
 
   if (flag == 1.0)
        gl_FragColor = vec4(mainCol.xyz, 1.0);
    else gl_FragColor = vec4(OutCol.xyz, 0.0);
i implemented dilation filter like explained in ATI presentation but with wrong result.
alphaMap is same resolution of lightMap
any ideas to remove these artifacts due to several blurring pass?
thanks
 
Last edited by a moderator:
I'm also working on this problem. I'm currently implementing this type of real-time sub-surface scattering as a new node in ShaderFX. I also tried the method that you have posted and ran into problems - not quite like the ones in your screen shot - those are really weird looking - but I wasn't getting the results I wanted. I came up with a different method that works better, but it's still not perfect. I don't have ready access to my code at the moment, but I'll try to post it tomorrow.

One of the problems, I think, is that this method of dilation was created for use with the Poisson Disc filter and here we're trying to use it with the 2 pass gaussian filter instead. What I'm doing in my ShaderFX node is implementing both the Poisson Disc filter and also the Gaussian filter and allowing the user to choose which one he wants based on performance and visual quality requirements. In my most recent tests this past Friday I found that this method of dilation works really well for the Poisson Disc Filter - so, you might try switching over to that method instead.

Like I said, I'll try to post some code for you tomorrow. Maybe we can collaborate on this a bit. I really enjoy working together with others on projects.
 
I'm also working on this problem. I'm currently implementing this type of real-time sub-surface scattering as a new node in ShaderFX. I also tried the method that you have posted and ran into problems - not quite like the ones in your screen shot - those are really weird looking - but I wasn't getting the results I wanted. I came up with a different method that works better, but it's still not perfect. I don't have ready access to my code at the moment, but I'll try to post it tomorrow.

One of the problems, I think, is that this method of dilation was created for use with the Poisson Disc filter and here we're trying to use it with the 2 pass gaussian filter instead. What I'm doing in my ShaderFX node is implementing both the Poisson Disc filter and also the Gaussian filter and allowing the user to choose which one he wants based on performance and visual quality requirements. In my most recent tests this past Friday I found that this method of dilation works really well for the Poisson Disc Filter - so, you might try switching over to that method instead.

Like I said, I'll try to post some code for you tomorrow. Maybe we can collaborate on this a bit. I really enjoy working together with others on projects.

it would be fantastic to collaborate; i'm doing my master thesis about translucent material, this is one of the algorithm i implemented. i think also my mesh has bad UV parametrization(i have found it on the Web) so we could work on the same mesh to compare our results.

regards
 
i tried Poisson disc filter like explained in ATI siggraph2006 course, and it work much better, but i have not a well UV parametrized model to compare


here is the GLSL fragment shader code

Code:
uniform sampler2D lightMap;
uniform sampler2D blurAmountMap;

uniform float mapSize;

vec4 PoissonFilter(sampler2D tSource, vec2 vTexCoord, float fRadius ) 
{ 
    vec2 vTexelSize = vec2(1.0 / mapSize, 1.0 / mapSize); 
    
    vec4 centerweight = vec4(0.200, 0.300, 0.300, 1.0);
    
    vec4 weights[12] = {
        {0.004, 0.0, 0.0, 1.0},
        {0.011, 0.0, 0.0, 1.0},
        {0.026, 0.005, 0.005, 1.0},
        {0.075, 0.045, 0.045, 1.0},
        {0.125, 0.086, 0.086, 1.0},
        {0.159, 0.210, 0.210, 1.0},
        {0.159, 0.210, 0.210, 1.0},
        {0.075, 0.045, 0.045, 1.0},    
        {0.125, 0.086, 0.086, 1.0},
        {0.026, 0.005, 0.005, 1.0},
        {0.011, 0.0, 0.0, 1.0},
        {0.004, 0.0, 0.0, 1.0},
    };
    
    // Tap locations on unit disc 
    vec2 vTaps[12] = {vec2(-0.326212,-0.40581), vec2(-0.840144,-0.07358), 
                        vec2(-0.695914,0.457137), vec2(-0.203345,0.620716), 
                        vec2(0.96234,-0.194983), vec2(0.473434,-0.480026), 
                        vec2(0.519456,0.767022), vec2(0.185461,-0.893124), 
                        vec2(0.507431,0.064425), vec2(0.89642,0.412458), 
                        vec2(-0.32194,-0.932615), vec2(-0.791559,-0.59771)}; 
    
    // Take a sample at the disc’s center 
    vec4 center = texture2D(tSource, vTexCoord); 
    
    float flag = center.a;
    vec3 cOut = center.rgb * centerweight;
    
    // Take 12 samples in disc 
    for ( int nTapIndex = 0; nTapIndex < 12; nTapIndex++ ) 
    { 
        // Compute new texture coord inside disc 
        vec2 vTapCoord = vTexCoord + vTexelSize * vTaps[nTapIndex] * fRadius; 
        // Accumulate samples 
        vec4 sample = texture2D( tSource, vTapCoord ); 
        cOut += sample.rgb * weights[nTapIndex];
        
        flag = max(sample.a, flag);
        if (sample.a < center.a) {
            center = sample;
        }
    } 
    
    if (flag == 1.0) {
        return vec4(center.rgb, 1.0);
    } else {
        return vec4(cOut, 0.0); // Return average 
    }
    
} 


void main()
{
    float radius = texture2D(blurAmountMap, gl_TexCoord[0].st ); 
    gl_FragColor = PoissonFilter(lightMap, gl_TexCoord[0].st, radius);
}


does anyone have a well UV-parametrized head model to give me, to make some tests?
 
I don't have a head that I can give you, but I can probably fix the UVs on the one that you have pretty easily. Let me know where you found it and I'll see what I can do.

My experience with the Poisson Disc filter is that it doesn't look that great if you run it just once, but if you run it again in a second pass, the quality improves a lot. The nice thing about the seond pass is that you can remove the code that does the dilation. That's only needed in the first pass.

Sorry I haven't posted my code head for the gaussian filter edge fix-up. I have lots going on at the moment.
 
I don't have a head that I can give you, but I can probably fix the UVs on the one that you have pretty easily. Let me know where you found it and I'll see what I can do.

i have found this mesh in nvidia sdk: it is useful because it has normal map and specular map

(right click- save link as..)
http://demasprojects.altervista.org/TestHead.obj


near ears and mouth there is overlapping mesh, do what you can for UV parametrization.

My experience with the Poisson Disc filter is that it doesn't look that great if you run it just once, but if you run it again in a second pass, the quality improves a lot. The nice thing about the seond pass is that you can remove the code that does the dilation. That's only needed in the first pass.

Sorry I haven't posted my code head for the gaussian filter edge fix-up. I have lots going on at the moment.

i fully implemented Poisson filter with 2 distinct shaders, for 1st pass and Nth pass, i obtain similar result like Gaussian filter in 20 passes!

thanks Ben
 
Sounds like you're making some progress - although 20 passes is insane. Are you joking? I got similar results with 2 passes, and really nice looking results with 4 - but that's probably too many for real-time.

Can you put the file somewhere else? I tried grabbing it at that link and just got a bunch of errors.

-Ben
 
Sounds like you're making some progress - although 20 passes is insane. Are you joking? I got similar results with 2 passes, and really nice looking results with 4 - but that's probably too many for real-time.

with Gaussian filter i did 3 horizontal and 3 vertical passes but i did not use normal map during light map computation, probably 20 is too much, better 10!
btw it depends a lot on the resolution of offscreen render target (eg: 512x512->10passes, 256x256->5passes)

Can you put the file somewhere else? I tried grabbing it at that link and just got a bunch of errors.

-Ben

http://www.wikiupload.com/download_page.php?id=87605


click on this link-->then on the right of the page there is "download file" button-->insert verification code and click "get" button


i'm also implementing BSSRDF via dipole approximation, do you have ever tried that? i also examined skin shader of Adrienne new nVidia demo, it is pretty cool, i hope at GDC07 they will explain it.



thanks again
 
Last edited by a moderator:
Back
Top