Shadow mapping 'shadow acne' artifacts using OpenGL and GLSL -


i wrote simple 3d application implementing hard , pcf shadow mapping algorithms using famous front face culling technique. unfortunatly, problem technique sealed meshes can produce cast shadows. example plane can't produce such effect because plane front face itself.

so solution use function 'glpolygonoffset' goal modify depth value during depth rendring path of each vertex visible 'light view'. in other words function needed avoid 'shadow acne' artifacts keeping time meshes front faces.

here's display of such rendering using hard shadow mapping algorithm:

enter image description here

as can see shadow rendering perfect without artifacts!

here's c++ client code defining depth texture rendering path:

/*glenable(gl_cull_face);   //old technique     glcullface(gl_front);*/  (uint32_t idy = 0; idy < lightscenenodelist.size(); idy++) {        if (lightscenenodelist[idy]->isshadowenabled())     {         type::shadowcasterptr pshadowcaster = shadowmanager::getsingleton()             .findshadowcasterbyname(lightscenenodelist[idy]->getname());         {             pshadowcaster->bind(target_fbo);             {                 glenable(gl_polygon_offset_fill);   //new technique                 glpolygonoffset(1.1f, 4.0f);                  glclear(gl_depth_buffer_bit);                 glcolormask(gl_false, gl_false, gl_false, gl_false);                 {                     pshadowcaster->updatefrustrumposition(                         lightscenenodelist[idy]->getparentmodelmatrix());                     pshadowcaster->setviewport();                     {                         (uint32_t idx = 0; idx < pbatchlist.size(); idx++)                             pbatchlist[idx]->render(pshadowcaster);                     }                 }                 gldisable(gl_polygon_offset_fill);             }             pshadowcaster->unbind(target_fbo);         }     } } //gldisable(gl_cull_face); 

and code used in fragment shader code compute shadow factor during second rendering path:

/* ** \brief recover depth value shadow map projection */ float tex2d_proj(sampler2dshadow shadowsampler, vec4 lighttovertexdir_ls) {     float shadowfactor = 1.0f;     {         vec3 lighttovertexdir_cs = lighttovertexdir_ls.xyz/lighttovertexdir_ls.w;          shadowfactor = texture(shadowsampler, lighttovertexdir_cs);     }     return (shadowfactor); } /* ** \brief returns biased hard shadow factor. */ float get_2d_hard_shadowfactor(sampler2dshadow shadowsampler, int index) {     float shadowfactor = 1.0f;     {         if (shadowcoords[index].z <= maxshadowdist[index])         {             if (shadowcoords[index].w > 0.0f);             {                 shadowfactor = tex2d_proj(shadowsampler, shadowcoords[index]);             }         }     }     return (shadowfactor); } 

the 'shadowcoords' uniform variable vertex position in light space , 'index' light index.

but have problem using pcf shadow mapping algorithm (an example 4 samples) using function 'glpolygonoffset' during first path:

enter image description here

as can see can see 'shadow acne' artifacts!

here's code fragment shader:

float get_2d_pcf_shadowfactor(sampler2dshadow shadowsampler, int index) {     float shadowfactor = 0.0f;     {         int kernel_base = int(pcfkerneltype[index])/2;         float kernel_count = pow(int(pcfkerneltype[index]), 2.0f);          if (shadowcoords[index].z <= maxshadowdist[index])         {             if (shadowcoords[index].w > 0.0f)             {                 shadowfactor += textureprojoffset(shadowsampler, shadowcoords[index], ivec2(-1, 1));                 shadowfactor += textureprojoffset(shadowsampler, shadowcoords[index], ivec2(1, 1));                 shadowfactor += textureprojoffset(shadowsampler, shadowcoords[index], ivec2(1, -1));                 shadowfactor += textureprojoffset(shadowsampler, shadowcoords[index], ivec2(-1, -1));                  shadowfactor *= 0.25f;             }         }     }     return (shadowfactor); } 

the 'textureprojoffset' code equal following one:

float tex2d_proj_offset(sampler2dshadow shadowsampler, vec4 lighttovertexdir_ls, vec2 offsetcoords, vec2 shadowmapsize) {     float offset_x = 1.0f/shadowmapsize.x;     float offset_y = 1.0f/shadowmapsize.y;      float shadowfactor = 1.0f;     {         vec3 lighttovertexdir_cs = lighttovertexdir_ls.xyz/lighttovertexdir_ls.w;         vec2 shadowtexcoords = vec2(lighttovertexdir_cs.x, lighttovertexdir_cs.y);          vec2 derivedshadowtexcoords = vec2(             shadowtexcoords.x + offsetcoords.x * offset_x,                 shadowtexcoords.y + offsetcoords.y * offset_y);          shadowfactor = texture(shadowsampler, vec3(             derivedshadowtexcoords, lighttovertexdir_cs.z));     }     return (shadowfactor); } 

only call of 'textureprojoffset(shadowsampler, shadowcoords[index], ivec2(0, 0))' works correctly (of course refers first hard shadow mapping technique).

if use following call (so simple hard shadow mapping using offset):

shadowfactor = textureprojoffset(shadowsampler, shadowcoords[index], ivec2(-1, 0)); 

i have following rendering:

enter image description here

as can see, there 'shadow acne' artifacts on right face of cube!

to resolve problem tried several combinations of code adding bias values deal vertex depth value in light space without success.

don't know if helps. maybe i'm over-complicating question. code objective c application, relevant code c. runs , works. you'll see in scene fragment shader statement: if (depthinshadow > 0.006). depth in shadow number had "tweak" rid of acne.

this edit. after re-reading post see statement: if (shadowcoords[index].w > 0.0f). looks similar depthinshadow statement in scene fragment shader had "tweak" little greater 0.0 rid of acne. give try.

i'll leave code posted below in case it's of interest else coming who's new shadow mapping.

many of variables declared in .h file, you'll idea. pretty standard shadow mapping code, if you've seen before, can stop here , save long read.

i set shadow buffer , shaders:

// ************************************* save current frame buffer  glgetintegerv(gl_framebuffer_binding, renderbuffer);  // ************************************ create shadow map texture  glgentextures(1, shadowtexture); glbindtexture(gl_texture_2d, shadowtexture[0]);  gltexparameteri ( gl_texture_2d , gl_texture_min_filter , gl_nearest ); gltexparameteri ( gl_texture_2d , gl_texture_mag_filter , gl_nearest );  gltexparameterf( gl_texture_2d, gl_texture_wrap_s, gl_clamp ); gltexparameterf( gl_texture_2d, gl_texture_wrap_t, gl_clamp );  glteximage2d(gl_texture_2d, 0, gl_depth_component32, shadowmapratio * viewwidth, shadowmapratio * viewheight, 0, gl_depth_component, gl_float, null);  glactivetexture(gl_texture5); glbindtexture(gl_texture_2d, shadowtexture[0]);  // ************************************ create shadow map frame buffer  glgenframebuffersext(1, shadowbuffer); glbindframebufferext(gl_framebuffer_ext, shadowbuffer[0]);  // **************************************** no color attachment  gldrawbuffer(gl_none); glreadbuffer(gl_none);  // ************************************* attach shadow texture  glframebuffertexture2dext(gl_framebuffer_ext, gl_depth_attachment_ext, gl_texture_2d, shadowtexture[0], 0);  // ******************************* check see if frame buffer complete  glenum framebufferstatus = glcheckframebufferstatus(gl_framebuffer_ext); if(framebufferstatus != gl_framebuffer_complete) {     nslog(@"there problem shadow frame buffer, %d", framebufferstatus);     if(framebufferstatus == gl_invalid_enum) nslog(@"invalid enum.");     if(framebufferstatus == gl_invalid_value) nslog(@"invalid value.");     if(framebufferstatus == gl_invalid_operation) nslog(@"invalid operation");     if(framebufferstatus == gl_framebuffer_incomplete_attachment) nslog(@"incomplete attachment");     if(framebufferstatus == gl_framebuffer_unsupported) nslog(@"unsupported"); }  // *********************************** reset original frame buffer  glbindframebufferext(gl_framebuffer_ext, renderbuffer[0]);  // ************************************** compile , link shadow shaders  shaderinfo shadowshaderinfo[] = {         { gl_vertex_shader, "path/shadow120.vsh" },         { gl_fragment_shader, "path/shadow120.fsh" },         { gl_none, null }     };  shadowshaders = loadshaders(shadowshaderinfo);  gluseprogram(shadowshaders);  shadowpositionloc = glgetattriblocation(shadowshaders, "shadowposition");  shadowviewmatrixloc= glgetuniformlocation(shadowshaders, "shadowviewmatrix"); if(shadowviewmatrixloc == -1) nslog(@"view matrix not found in shadow shader");  shadowmodelmatrixloc= glgetuniformlocation(shadowshaders, "shadowmodelmatrix"); if(shadowmodelmatrixloc == -1) nslog(@"model matrix not found in shadow shader");  shadowprojectionmatrixloc= glgetuniformlocation(shadowshaders, "shadowprojectionmatrix"); if(shadowprojectionmatrixloc == -1) nslog(@"projection matrix not found in shadow shader");  shadowcolorloc= glgetuniformlocation(shadowshaders, "frontcolor"); if(shadowcolorloc == -1) nslog(@"front color not found in shadow shader"); 

the uniform shadow matrices are, of course, camera position.

the shadow shaders used render shadow buffer trivial.

shadow vertex shader:

#version 120  attribute vec4 shadowposition;  uniform mat4 shadowmodelmatrix; uniform mat4 shadowviewmatrix; uniform mat4 shadowprojectionmatrix;  void main() {     gl_position = shadowprojectionmatrix * shadowviewmatrix * shadowmodelmatrix * shadowposition; } 

the shadow fragment shader:

#version 120  uniform vec4 frontcolor;  void main() {      gl_fragcolor = frontcolor; } 

i first render scene shadow buffer with:

gluseprogram(shadowshaders);  glbindframebufferext(gl_framebuffer_ext, shadowbuffer[0]);  glcolormask ( gl_false , gl_false , gl_false , gl_false );  glactivetexture(gl_texture5); glbindtexture(gl_texture_2d, shadowtexture[0]);  glcleardepth(1.0); glclear(gl_depth_buffer_bit);  gluniformmatrix4fv(shadowmodelmatrixloc, 1, gl_false, lightglkmodelmatrix.m); gluniformmatrix4fv(shadowviewmatrixloc, 1, gl_false, lightglkviewmatrix.m); gluniformmatrix4fv(shadowprojectionmatrixloc, 1, gl_false, lightglkprojectionmatrix.m); gluniform4fv(shadowcolorloc, 1, worldambient);  .... rendering code ....  gldisable(gl_polygon_offset_fill); glbindframebufferext(gl_framebuffer_ext, renderbuffer[0]); glcolormask ( gl_true , gl_true , gl_true , gl_true ); 

i render scene using these shaders:

scene vertex shader:

#version 120  attribute vec4 ringposition; attribute vec3 ringnormal;  uniform vec4 lightposition;  uniform mat4 ringmodelmatrix; uniform mat4 ringviewmatrix; uniform mat4 ringprojectionmatrix; uniform mat3 ringnormalmatrix;  uniform mat4 shadowbiasmatrix; uniform mat4 shadowmodelmatrix; uniform mat4 shadowviewmatrix; uniform mat4 shadowprojectionmatrix;  varying float diffuseintensity; varying float specularintensity; varying vec4 shadowcoordinate;  const float specularcontribution = 1.0; const float diffusecontribution = 1.0;  void main() {     mat4 shadowmatrix =  shadowbiasmatrix * shadowprojectionmatrix * shadowviewmatrix * shadowmodelmatrix;      shadowcoordinate = shadowmatrix * ringposition;      vec3 lightposition= vec3(lightposition);     float shininess = gl_frontmaterial.shininess;      vec3 ecposition = vec3(ringviewmatrix * ringmodelmatrix  * ringposition);     vec3 tnorm = normalize(ringnormalmatrix * ringnormal);     vec3 lightvec = normalize(lightposition - ecposition);     vec3 reflectvec = reflect(-lightvec, tnorm);     vec3 viewvec = normalize(-ecposition);      float spec = clamp(dot(reflectvec, viewvec), 0.0, 1.0);     specularintensity = specularcontribution * pow(spec, shininess / 5.0);      diffuseintensity = diffusecontribution * max(dot(lightvec, tnorm), 0.0);      gl_position = ringprojectionmatrix * ringviewmatrix * ringmodelmatrix * ringposition; } 

scene fragment shader:

#version 120  uniform sampler2d shadowmap;  varying float diffuseintensity; varying float specularintensity; varying vec4 shadowcoordinate;  void main() {      vec3 emission = vec3(gl_frontmaterial.emission);     vec3 ambient = vec3(gl_frontmaterial.ambient);     vec3 diffuse = vec3(gl_frontmaterial.diffuse);     vec3 specular = vec3(gl_frontmaterial.specular);      // normalize shadow map coordinates     // shadowcoordinatewdivide.z = current fragment depth light      vec3 shadowcoordinatewdivide = shadowcoordinate.xyz / shadowcoordinate.w ;      float distancefromlight = texture2d(shadowmap, shadowcoordinatewdivide.xy).r;      float depthinshadow = shadowcoordinatewdivide.z - distancefromlight;      float specularintensity = specularintensity;     float diffuseintensity = diffuseintensity;      if (depthinshadow > 0.006)     {         specularintensity = specularintensity * 0.0;         diffuseintensity = diffuseintensity * 0.0;     }      vec3 lightcolor = emission;     lightcolor = lightcolor + ambient;     lightcolor = lightcolor + (specularintensity * specular);     lightcolor = lightcolor + (diffuseintensity * diffuse);      lightcolor = clamp(lightcolor, 0.0, 1.0);      gl_fragcolor = vec4(lightcolor, 1.0);  } 

the shadow bias matrix is:

glfloat shadowbiasmatrix[16] = { 0.5, 0.0, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.5, 0.0, 0.5, 0.5, 0.5, 1.0}; 

Comments

Popular posts from this blog

python - mat is not a numerical tuple : openCV error -

c# - MSAA finds controls UI Automation doesn't -

wordpress - .htaccess: RewriteRule: bad flag delimiters -