Depth Of Field RenderPass - jME 1.0, the source and shaders

Hello people!



Here it is the initial version of Depth Of Field effect for jme1.0. Feel free to port it to jME 2.0.



Tar.gzipped version downloadable here in another forum post:



http://forum.freegamedev.net/index.php?t=msg&goto=10484#msg_10484













(The second shot is an older one, with bleeding, but the actual shader is corrected since that shot, as seen on the first one, i’m lazy to upload a new one :P)



Cheers,

Paul

Oh, a bit of effective optimization:



"  if (d.r>0.001)

  {

"

part was missing for part of the screen that not need to be rendered to blur because they are close.




uniform float sampleDist0;
uniform sampler2D scene;            // full resolution image
uniform sampler2D depth;            // full resolution image with depth values

varying vec2 vTexCoord;


void main()
{

   vec2 samples00 = vec2(-0.326212, -0.405805);
   vec2 samples01 = vec2(-0.840144, -0.073580);
   vec2 samples02 = vec2(-0.695914,  0.457137);
   vec2 samples03 = vec2(-0.203345,  0.620716);
   vec2 samples04 = vec2( 0.962340, -0.194983);
   vec2 samples05 = vec2( 0.473434, -0.480026);
   vec2 samples06 = vec2( 0.519456,  0.767022);
   vec2 samples07 = vec2( 0.185461, -0.893124);
   vec2 samples08 = vec2( 0.507431,  0.064425);
   vec2 samples09 = vec2( 0.896420,  0.412458);
   vec2 samples10 = vec2(-0.321940, -0.932615);
   vec2 samples11 = vec2(-0.791559, -0.597705);

   vec2 newCoord;
   vec4 sum = texture2D(scene, vTexCoord);

   
   vec4 d = texture2D(depth, vTexCoord);
 
  if (d.r>0.001)
  {
 
   sampleDist0 = (d.r)*sampleDist0;
 
   float additionCount = 1;
   
   vec4 dCheck = 0;
   newCoord = vTexCoord + sampleDist0 * samples00;
   dCheck = texture2D(depth, newCoord);
   if (abs(dCheck.r-d.r)<0.1)
   {
       sum += texture2D(scene, newCoord);
       additionCount = additionCount+1;
   }
  
   newCoord = vTexCoord + sampleDist0 * samples01;
   dCheck = texture2D(depth, newCoord);
   if (abs(dCheck.r-d.r)<0.1)
   {
       sum += texture2D(scene, newCoord);
       additionCount = additionCount+1;
   }

   newCoord = vTexCoord + sampleDist0 * samples02;
   dCheck = texture2D(depth, newCoord);
   if (abs(dCheck.r-d.r)<0.1)
   {
       sum += texture2D(scene, newCoord);
       additionCount = additionCount+1;
   }

   newCoord = vTexCoord + sampleDist0 * samples03;
   dCheck = texture2D(depth, newCoord);
   if (abs(dCheck.r-d.r)<0.1)
   {
       sum += texture2D(scene, newCoord);
       additionCount = additionCount+1;
   }

   newCoord = vTexCoord + sampleDist0 * samples04;
   dCheck = texture2D(depth, newCoord);
   if (abs(dCheck.r-d.r)<0.1)
   {
       sum += texture2D(scene, newCoord);
       additionCount = additionCount+1;
   }

   newCoord = vTexCoord + sampleDist0 * samples05;
   dCheck = texture2D(depth, newCoord);
   if (abs(dCheck.r-d.r)<0.1)
   {
       sum += texture2D(scene, newCoord);
       additionCount = additionCount+1;
   }

   newCoord = vTexCoord + sampleDist0 * samples06;
   dCheck = texture2D(depth, newCoord);
   if (abs(dCheck.r-d.r)<0.1)
   {
       sum += texture2D(scene, newCoord);
       additionCount = additionCount+1;
   }

   newCoord = vTexCoord + sampleDist0 * samples07;
   dCheck = texture2D(depth, newCoord);
   if (abs(dCheck.r-d.r)<0.1)
   {
       sum += texture2D(scene, newCoord);
       additionCount = additionCount+1;
   }

   newCoord = vTexCoord + sampleDist0 * samples08;
   dCheck = texture2D(depth, newCoord);
   if (abs(dCheck.r-d.r)<0.1)
   {
       sum += texture2D(scene, newCoord);
       additionCount = additionCount+1;
   }

   newCoord = vTexCoord + sampleDist0 * samples09;
   dCheck = texture2D(depth, newCoord);
   if (abs(dCheck.r-d.r)<0.1)
   {
       sum += texture2D(scene, newCoord);
       additionCount = additionCount+1;
   }

   newCoord = vTexCoord + sampleDist0 * samples10;
   dCheck = texture2D(depth, newCoord);
   if (abs(dCheck.r-d.r)<0.1)
   {
       sum += texture2D(scene, newCoord);
       additionCount = additionCount+1;
   }

   newCoord = vTexCoord + sampleDist0 * samples11;
   dCheck = texture2D(depth, newCoord);
   if (abs(dCheck.r-d.r)<0.1)
   {
       sum += texture2D(scene, newCoord);
       additionCount = additionCount+1;
   }

   sum /= additionCount;
   sum.a = d.r*2;
   gl_FragColor =  sum;
  
   } else
   {
      sum.a = 0;
    gl_FragColor =  sum;
   }
      
}

remember that conditionals are slow as hell on most cards. it's usually faster to just do all the tex samples in the whole shader and cancel out values by operations making them zero.

MrCoder said:

remember that conditionals are slow as hell on most cards. it's usually faster to just do all the tex samples in the whole shader and cancel out values by operations making them zero.

What do you exactly mean , with what operation can I cancel out?

By my test it is really faster on a 6200Go with the condition.

I don't think it looks quite right. Shouldn't the edges of the shapes blur into the darkness as well?

I agree, the edges look too sharp…especially on the two torus. Also, the blurring looks a bit too intensive.



Other than that, still looks cool :slight_smile:

Starnick said:

I agree, the edges look too sharp...especially on the two torus. Also, the blurring looks a bit too intensive.

Other than that, still looks cool :)


Well, it's intentionally not blurred if you don't have say an object near to it, to prevent bleeding the depth texture is checked. This means that if you don't put a spatial behind it, it won't blur it together... well it may result in some not so good looking scenarios. Probably some kind of switch for it?

Also you can set the blursize parameter if it's too strong lower it from default value. :)

Ahh I see…so I guess having a skybox then would solve that?



I was referring to the port to 2.0 with the dancing nutcracker, the pictures you posted were awesome :wink: Especially that last one!

IMHO It looks pretty bad with those settings, on the first screens the blur is nice but pixelated. On kevglass's screen it looks like the whole scene has been warpsharp'd, the blur radius is too big and the convolution matrix too small, making it looks less like blur and more like many clones of the same models.

timong said:

Well, it's intentionally not blurred if you don't have say an object near to it, to prevent bleeding the depth texture is checked. This means that if you don't put a spatial behind it, it won't blur it together... well it may result in some not so good looking scenarios. Probably some kind of switch for it?


I just remember seeing a pic from MrCoder back when he wrote the bloom pass:

Okay, I've modified the shaders to have a blurry effect at background + far spatial edges (but still not blurring the background, which IMHO wouldn't be too nice for a clear sky for example):



depth shader:


// "Depth of Field" demo for Ogre
// Copyright (C) 2006  Christian Lindequist Larsen
//
// This code is in the public domain. You may do whatever you want with it.

// dofParams coefficients:
// x = near blur depth; y = focal plane depth; z = far blur depth
// w = blurriness cutoff constant for objects behind the focal plane
uniform vec4 dofParams;

varying float depth; // in view space

uniform sampler2D mainTexture;

void main()
{
   float f;
   vec4 texCol = texture2D(mainTexture,gl_TexCoord[0].st);
   
   if (depth < dofParams.y)
   {
      // scale depth value between near blur distance and focal distance to
      // [-1, 0] range
      f = (depth - dofParams.y) / (dofParams.y - dofParams.x);
   }
   else
   {
      // scale depth value between focal distance and far blur distance to
      // [0, 1] range
      f = (depth - dofParams.y) / (dofParams.z - dofParams.y);
      // clamp the far blur to a maximum blurriness
      f = clamp(f, 0.0, dofParams.w);
   }

   // scale and bias into [0, 1] range
   vec4 sum = vec4(0.5*f + 0.5);
   sum.a = texCol.a;
   sum.r += 0.001; // setting r a bit higher to let dof_2 shader know this is a rendered spatial pixel, not background
   gl_FragColor = sum;
}



I've added comment too :)


// "Depth of Field" demo for Ogre
// Copyright (C) 2006  Christian Lindequist Larsen
//
// This code is in the public domain. You may do whatever you want with it.

uniform float sampleDist0;
uniform sampler2D scene;            // full resolution image
uniform sampler2D depth;            // full resolution image with depth values

varying vec2 vTexCoord;


void main()
{

   vec2 samples00 = vec2(-0.326212, -0.405805);
   vec2 samples01 = vec2(-0.840144, -0.073580);
   vec2 samples02 = vec2(-0.695914,  0.457137);
   vec2 samples03 = vec2(-0.203345,  0.620716);
   vec2 samples04 = vec2( 0.962340, -0.194983);
   vec2 samples05 = vec2( 0.473434, -0.480026);
   vec2 samples06 = vec2( 0.519456,  0.767022);
   vec2 samples07 = vec2( 0.185461, -0.893124);
   vec2 samples08 = vec2( 0.507431,  0.064425);
   vec2 samples09 = vec2( 0.896420,  0.412458);
   vec2 samples10 = vec2(-0.321940, -0.932615);
   vec2 samples11 = vec2(-0.791559, -0.597705);

   vec2 newCoord;
   vec4 sum = texture2D(scene, vTexCoord);

   
   vec4 d = texture2D(depth, vTexCoord);
 
  if (d.r>0.001) // in the scenario, but not the closest parts which should be kept alpha = 0 (see else)...
  {
 
   sampleDist0 = (d.r)*sampleDist0;
 
   float additionCount = 1;
   
   vec4 dCheck = 0;
   newCoord = vTexCoord + sampleDist0 * samples00;
   dCheck = texture2D(depth, newCoord);
   // if out of rendered spatials pixel (background - r = zero) or near, mix it
   if (dCheck.r==0 || abs(dCheck.r-d.r)<0.1)
   {
       sum += texture2D(scene, newCoord);
       additionCount = additionCount+1;
   }
  
   newCoord = vTexCoord + sampleDist0 * samples01;
   dCheck = texture2D(depth, newCoord);
   if (dCheck.r==0 || abs(dCheck.r-d.r)<0.1)
   {
       sum += texture2D(scene, newCoord);
       additionCount = additionCount+1;
   }

   newCoord = vTexCoord + sampleDist0 * samples02;
   dCheck = texture2D(depth, newCoord);
   if (dCheck.r==0 || abs(dCheck.r-d.r)<0.1)
   {
       sum += texture2D(scene, newCoord);
       additionCount = additionCount+1;
   }

   newCoord = vTexCoord + sampleDist0 * samples03;
   dCheck = texture2D(depth, newCoord);
   if (dCheck.r==0 || abs(dCheck.r-d.r)<0.1)
   {
       sum += texture2D(scene, newCoord);
       additionCount = additionCount+1;
   }

   newCoord = vTexCoord + sampleDist0 * samples04;
   dCheck = texture2D(depth, newCoord);
   if (dCheck.r==0 || abs(dCheck.r-d.r)<0.1)
   {
       sum += texture2D(scene, newCoord);
       additionCount = additionCount+1;
   }

   newCoord = vTexCoord + sampleDist0 * samples05;
   dCheck = texture2D(depth, newCoord);
   if (dCheck.r==0 || abs(dCheck.r-d.r)<0.1)
   {
       sum += texture2D(scene, newCoord);
       additionCount = additionCount+1;
   }

   newCoord = vTexCoord + sampleDist0 * samples06;
   dCheck = texture2D(depth, newCoord);
   if (dCheck.r==0 || abs(dCheck.r-d.r)<0.1)
   {
       sum += texture2D(scene, newCoord);
       additionCount = additionCount+1;
   }

   newCoord = vTexCoord + sampleDist0 * samples07;
   dCheck = texture2D(depth, newCoord);
   if (dCheck.r==0 || abs(dCheck.r-d.r)<0.1)
   {
       sum += texture2D(scene, newCoord);
       additionCount = additionCount+1;
   }

   newCoord = vTexCoord + sampleDist0 * samples08;
   dCheck = texture2D(depth, newCoord);
   if (dCheck.r==0 || abs(dCheck.r-d.r)<0.1)
   {
       sum += texture2D(scene, newCoord);
       additionCount = additionCount+1;
   }

   newCoord = vTexCoord + sampleDist0 * samples09;
   dCheck = texture2D(depth, newCoord);
   if (dCheck.r==0 || abs(dCheck.r-d.r)<0.1)
   {
       sum += texture2D(scene, newCoord);
       additionCount = additionCount+1;
   }

   newCoord = vTexCoord + sampleDist0 * samples10;
   dCheck = texture2D(depth, newCoord);
   if (dCheck.r==0 || abs(dCheck.r-d.r)<0.1)
   {
       sum += texture2D(scene, newCoord);
       additionCount = additionCount+1;
   }

   newCoord = vTexCoord + sampleDist0 * samples11;
   dCheck = texture2D(depth, newCoord);
   if (dCheck.r==0 || abs(dCheck.r-d.r)<0.1)
   {
       sum += texture2D(scene, newCoord);
       additionCount = additionCount+1;
   }

   sum /= additionCount;
   sum.a = d.r*2;
   gl_FragColor =  sum;
  
   } else
   {
      sum.a = 0;
    //gl_FragColor =  sum;
   }
      
}



And this part which now blurs a bit together the edges with background. Do you like it better or should we use the previous one with little less GPU stressing? :)

Now its looking good! Good job guys!

nymon said:

timong said:

Well, it's intentionally not blurred if you don't have say an object near to it, to prevent bleeding the depth texture is checked. This means that if you don't put a spatial behind it, it won't blur it together... well it may result in some not so good looking scenarios. Probably some kind of switch for it?


I just remember seeing a pic from MrCoder back when he wrote the bloom pass:


Yeah, right, but this is unsolvable with my depth texture technique + bleeding prevention, because my shader doesn't blur together distant parts (distant from each other in the scene, having big difference in z) of a scenario (which is leading to bleeding). Also blurring the whole faraway part is not a good thing IMHO, the sky box have to be clear.

Here i've posted the updated shader files with the optimization and better background blurring changes:



http://forum.freegamedev.net/index.php?t=msg&goto=10549#msg_10549


Gee, a little bit of error in the shader made it outlining :smiley:

Corrected version:




uniform float sampleDist0;
uniform sampler2D scene;            // full resolution image
uniform sampler2D depth;            // full resolution image with depth values

varying vec2 vTexCoord;


void main()
{

   vec2 samples00 = vec2(-0.326212, -0.405805);
   vec2 samples01 = vec2(-0.840144, -0.073580);
   vec2 samples02 = vec2(-0.695914,  0.457137);
   vec2 samples03 = vec2(-0.203345,  0.620716);
   vec2 samples04 = vec2( 0.962340, -0.194983);
   vec2 samples05 = vec2( 0.473434, -0.480026);
   vec2 samples06 = vec2( 0.519456,  0.767022);
   vec2 samples07 = vec2( 0.185461, -0.893124);
   vec2 samples08 = vec2( 0.507431,  0.064425);
   vec2 samples09 = vec2( 0.896420,  0.412458);
   vec2 samples10 = vec2(-0.321940, -0.932615);
   vec2 samples11 = vec2(-0.791559, -0.597705);

   vec2 newCoord;
   vec4 sum = texture2D(scene, vTexCoord);

   
   vec4 d = texture2D(depth, vTexCoord);
 
  if (d.r>0.001) // in the scenario, but not the closest parts which should be kept alpha = 0 (see else)...
  {
 
   sampleDist0 = (d.r)*sampleDist0;
 
   float additionCount = 1;
   
   vec4 dCheck = 0;
   newCoord = vTexCoord + sampleDist0 * samples00;
   dCheck = texture2D(depth, newCoord);
   // if out of rendered spatials pixel (background - r = zero) or near, mix it
   if (dCheck.r==0 || abs(dCheck.r-d.r)<0.1)
   {
       sum += texture2D(scene, newCoord);
       additionCount = additionCount+1;
   }
  
   newCoord = vTexCoord + sampleDist0 * samples01;
   dCheck = texture2D(depth, newCoord);
   if (dCheck.r==0 || abs(dCheck.r-d.r)<0.1)
   {
       sum += texture2D(scene, newCoord);
       additionCount = additionCount+1;
   }

   newCoord = vTexCoord + sampleDist0 * samples02;
   dCheck = texture2D(depth, newCoord);
   if (dCheck.r==0 || abs(dCheck.r-d.r)<0.1)
   {
       sum += texture2D(scene, newCoord);
       additionCount = additionCount+1;
   }

   newCoord = vTexCoord + sampleDist0 * samples03;
   dCheck = texture2D(depth, newCoord);
   if (dCheck.r==0 || abs(dCheck.r-d.r)<0.1)
   {
       sum += texture2D(scene, newCoord);
       additionCount = additionCount+1;
   }

   newCoord = vTexCoord + sampleDist0 * samples04;
   dCheck = texture2D(depth, newCoord);
   if (dCheck.r==0 || abs(dCheck.r-d.r)<0.1)
   {
       sum += texture2D(scene, newCoord);
       additionCount = additionCount+1;
   }

   newCoord = vTexCoord + sampleDist0 * samples05;
   dCheck = texture2D(depth, newCoord);
   if (dCheck.r==0 || abs(dCheck.r-d.r)<0.1)
   {
       sum += texture2D(scene, newCoord);
       additionCount = additionCount+1;
   }

   newCoord = vTexCoord + sampleDist0 * samples06;
   dCheck = texture2D(depth, newCoord);
   if (dCheck.r==0 || abs(dCheck.r-d.r)<0.1)
   {
       sum += texture2D(scene, newCoord);
       additionCount = additionCount+1;
   }

   newCoord = vTexCoord + sampleDist0 * samples07;
   dCheck = texture2D(depth, newCoord);
   if (dCheck.r==0 || abs(dCheck.r-d.r)<0.1)
   {
       sum += texture2D(scene, newCoord);
       additionCount = additionCount+1;
   }

   newCoord = vTexCoord + sampleDist0 * samples08;
   dCheck = texture2D(depth, newCoord);
   if (dCheck.r==0 || abs(dCheck.r-d.r)<0.1)
   {
       sum += texture2D(scene, newCoord);
       additionCount = additionCount+1;
   }

   newCoord = vTexCoord + sampleDist0 * samples09;
   dCheck = texture2D(depth, newCoord);
   if (dCheck.r==0 || abs(dCheck.r-d.r)<0.1)
   {
       sum += texture2D(scene, newCoord);
       additionCount = additionCount+1;
   }

   newCoord = vTexCoord + sampleDist0 * samples10;
   dCheck = texture2D(depth, newCoord);
   if (dCheck.r==0 || abs(dCheck.r-d.r)<0.1)
   {
       sum += texture2D(scene, newCoord);
       additionCount = additionCount+1;
   }

   newCoord = vTexCoord + sampleDist0 * samples11;
   dCheck = texture2D(depth, newCoord);
   if (dCheck.r==0 || abs(dCheck.r-d.r)<0.1)
   {
       sum += texture2D(scene, newCoord);
       additionCount = additionCount+1;
   }

   sum /= additionCount;
   sum.a = d.r*2;
   gl_FragColor =  sum;
  
   } else
   {
      sum.a = 0;
    gl_FragColor =  sum;
   }
      
}



I though th last gl_FragColor = sum was unnecessary but it isn't. :)

thanks to kevglass's porting and proposing as a patch the DoF pass has been committed to jme2.0 trunk by Renanse. Thanks guys!