Depth-of-field support in Panda?

Hey there everyone,

My name is Brian, and this is my first post in the forums. I’ve been having a lot of fun with Panda recently, I’m just finishing up an implementation of the medieval Hnefatafl board game (http://en.wikipedia.org/wiki/Hnefatafl) as my first project. I’ll be sure to post it once I’m finished, my artist is currently modeling me up some pieces so I don’t have to keep using the chess ones included with Panda.

I’ve got a great idea for my next project; however, it relies heavily on the use of depth-of-field. Unfortunately I don’t have a ton of experience with shaders yet so I was hoping that maybe Panda already supports it (though I’ve found no evidence of it) or that maybe someone in the community has implemented it (haven’t found anything searching the forums).

I really appreciate any insight you can provide, thanks!

-Brian

hi, and welcome to panda3d :slight_smile:

afaik there is no build-in-ready-to-use DOF shader yet.
however i think pro-rsoft experimented with something like that some while ago. results where not that perfect but looked not too bad for some situations.

Hmm, I think aurilliance did plan on doing something like that.
But yeah, sooner or later, it will be added to panda.

But you could also create your own shader for it. It will be screen-space so it won’t interfere with the shader generator.

Oleyb, welcome :slight_smile:
What pro-rsoft says is right. I’ve got a work in progress dof shader going, based on the algorithm used in starcraft II. If you want to read about it, check this link here: http://ati.amd.com/developer/siggraph08/chapter05-filion-starcraftii.pdf

It’s nowhere near done yet, but when I finish it it will definitely be available for community use… No time frame for that yet, sorry :wink: However I’ve got 1 month until holidays, so I may have some time to look at it then.

Regards,

Thanks for the input everyone. Aurilliance, is there anything I can do or learn about to help out with the shader?

Oleyb, just me being pedantic, but I generally try to spell aurilliance lowercase :wink: (I try to anyway lol). Sure you can help out. If you read over the starcraft spec about DOF, I’ll send you the source code and you could keep working on it in the mean time :wink: If you’re not to sure about shaders, there are a few tutes in the manual (some of them aren’t in the table of contents though, so try googling), they might help get you started with panda shaders.

Let me know if you’d like the code.
regards,

aurilliance check this out: why not to share here for everybody your code? I guess it will grow faster being in as many hands as possible

I’ve made a minimum version, color leaking is not handled yet.

        self.tex = Texture()
        self.depthmap = Texture()
        self.manager = FilterManager(base.win,base.cam)
        self.quad = self.manager.renderSceneInto(colortex=self.tex,depthtex=self.depthmap)
        self.quad.setShader(loader.loadShader("shaders/dof.sha"))
        self.quad.setShaderInput("src",self.tex)
        self.quad.setShaderInput("dtex",self.depthmap)
//Cg
//Cg profile arbvp1 arbfp1
// clcheung: Depth of Field

void vshader(float4 vtx_position : POSITION, 
             float2 vtx_texcoord0 : TEXCOORD0,
             out float4 l_position : POSITION,
      	     out float2 l_texcoord0 : TEXCOORD0,
			 uniform float4 texpad_src,
             uniform float4x4 mat_modelproj)
{
  l_position=mul(mat_modelproj, vtx_position);
  //l_texcoord0=vtx_texcoord0;
  l_texcoord0 = vtx_position.xz * texpad_src.xy + texpad_src.xy;
}

float2 poissonDisk[12] = {
	float2(-0.326212,-0.40508),
	float2(-0.840144, -0.07358),
	float2(-0.695914, 0.457137),
	float2(-0.203345, 0.620716),
	float2(0.96234, -0.194983),
	float2(0.473434, -0.480026),
	float2(0.519456, 0.767022),
	float2(0.185461, -0.893124),
	float2(0.507431, 0.064425),
	float2(0.89642, 0.412458),
	float2(-0.32194, -0.932615),
	float2(-0.791559, -0.59771) 
};

float4 PCF_Filter( float2 uv, float r, sampler2D map )
{
   float4 sum = float4(0,0,0,0);
   for ( int i = 0; i < 12; ++i ){
      float2 offset = poissonDisk[i] * r;   
      float4 mapval = tex2D(map,uv+offset);
      sum += mapval;
   }
   return saturate(sum / 12.0);
}

void fshader(float2 l_texcoord0 : TEXCOORD0,
             out float4 o_color : COLOR,
			 uniform float4 k_param1,
             uniform sampler2D k_src : TEXUNIT0,
			 uniform sampler2D k_dtex : TEXUNIT1)
{
   float depth = tex2D(k_dtex, l_texcoord0).x;
   float focus = k_param1.x;
   float d = abs(focus - depth);
   //float4 c = tex2D(k_src, l_texcoord0);

   float radius = min(d * k_param1.y, k_param1.z);
   o_color.rgb  = PCF_Filter(l_texcoord0, radius, k_src).xyz;
   o_color.w = 1;
}

See also:

developer.amd.com/media/gpu_asse … lation.pdf

That’s basically a little less than what we’ve already accomplished:
pro-rsoft.com/screens/depth-of-field.jpg

We need to do a per-sample depth comparison to make sure no color leaks.

I say thankyou to cheung for his code nonetheless cos he gave me the opportunity to get an idea and learn - don’t forget not everybody here is a cutting edge dev :wink:

Yes, it is a good way to learn to implement some thing less cutting edge and easy to understand. Here a simple handling to remove leaking. Please let me know if I am not doing them correctly…I’m still a beginner.

//Cg
//Cg profile arbvp1 arbfp1
// clcheung: Depth of Field
// handle also color leaking

void vshader(float4 vtx_position : POSITION, 
             float2 vtx_texcoord0 : TEXCOORD0,
             out float4 l_position : POSITION,
      	     out float2 l_texcoord0 : TEXCOORD0,
			 uniform float4 texpad_src,
             uniform float4x4 mat_modelproj)
{
  l_position=mul(mat_modelproj, vtx_position);
  //l_texcoord0=vtx_texcoord0;
  l_texcoord0 = vtx_position.xz * texpad_src.xy + texpad_src.xy;
}

float2 poissonDisk[12] = {
	float2(-0.326212,-0.40508),
	float2(-0.840144, -0.07358),
	float2(-0.695914, 0.457137),
	float2(-0.203345, 0.620716),
	float2(0.96234, -0.194983),
	float2(0.473434, -0.480026),
	float2(0.519456, 0.767022),
	float2(0.185461, -0.893124),
	float2(0.507431, 0.064425),
	float2(0.89642, 0.412458),
	float2(-0.32194, -0.932615),
	float2(-0.791559, -0.59771) 
};

void fshader(float2 l_texcoord0 : TEXCOORD0,
             out float4 o_color : COLOR,
			 uniform float4 k_param1,
             uniform sampler2D k_src : TEXUNIT0,
			 uniform sampler2D k_dtex : TEXUNIT1)
{
   float depth = tex2D(k_dtex, l_texcoord0).x;
   float focus = k_param1.x;
   float d = abs(focus - depth);
   //float4 c = tex2D(k_src, l_texcoord0);

   float radius = min(d * k_param1.y, k_param1.z);
   
   float4 sum = float4(0,0,0,0);
   float total = 0;
   for ( int i = 0; i < 12; ++i ){
	  float2 uv = l_texcoord0 +  poissonDisk[i] * radius;
      float depth_sample = tex2D(k_dtex, uv).x;
	  if (depth_sample > depth) {
		  float blurness = min(abs(depth_sample - focus) * k_param1.y, k_param1.z) / k_param1.z;
          float4 tapColor = tex2D(k_src,uv);
		  sum += tapColor * blurness;
		  total += blurness;
	  }
   }
   if (total == 0)
		o_color.rgb  = tex2D(k_src, l_texcoord0).xyz;
   else
        o_color.rgb  = (sum/total).xyz;
   o_color.w = 1;
}

Hey, that’s cool.
However, I think this shader is a bit too heavy to be included into Panda. Especially “if” statements are very slow in Cg - and I also think that instead of a large loop (which probably gets unrolled by the compiler into a huge block of code) we should use a multi-pass shader.
So, I think DOF can be achieved with much lighter shaders.

Nevertheless, nice work.

I do not aware of this. It runs pretty fast on my PC, with a quite new Nvidia card.

How can one know if a particular shader is slow if one does not have old video card to test out ?

Clcheung, excellent work! Thanks for sharing as well!

I haven’t gotten a chance to test it out in my code yet, but if you want to upload a demo I can run it on my laptop (Geforce Go 7400 - its getting old) and let you know how it performs.

Sure. But it is embedded in demomaster and will be included in the next release.

@clcheung

In the old ages of shader writing, shaders had to be written in assembler. Each generation (shader model 1, 2, …) has new features and old limitations are not relevant anymore.

What may help is the NVIDIA FX Composer. You can analyze how shaders perform on some selected GPUs.

I see. Thank you Azraiyl.

links here:
FX COMPOSER
Overview (video)
Features (video)

2 things I have to add.

1: With old ages I mean 3 years ago (it’s astonishing how GPUs have improved), therefore it is likely that your friends GPU is more than 10 times slower than your GPU.

2: FX Composer: I have an ambivalence to this program, something between hate and usefull. The application has tons of bugs, a nobody fixes them. Never try to ask a question on the NVIDIA forum, nobody answers them (there are dozens of bug list, …). On the other side if you invest maybe 3-4 hours and get around about the most obvious bugs, it may still be usefull.