filters and multisamples

Filters seem to disable multisamples for me, which is a huge issue for me.
Can someone check if they have the same problem so we can post a bug report?

from pandac.PandaModules import *
loadPrcFileData('', 'multisamples 1')
import direct.directbase.DirectStart
from direct.filter.CommonFilters import CommonFilters

filters = CommonFilters(,
filters.setBloom(size = "large")

env = loader.loadModel('environment')

state = False
def switchBloom():
	global state
	if state == False:
		state = True
		filters.setBloom(size = "large")
		state = False

base.accept('enter', switchBloom)


This is a known limitation.

Normally I don’t choose an engine for the amount of shaders that come bundled with it, but if using your own one wouldn’t solve this either (if the “issue” is in FilterManager/CommonFilters), then it means no antialiasing. I don’t want to sound rude, but you can’t really live without it.
When I hear people use the term issue instead of bug in my experience it usually means it won’t be solved anytime soon, though in my opinion this should be high priority. Is it the case?

I wasn’t aware of this as a known limitation. Please feel free to submit a bug report.

But note that we don’t have a lot of volunteers with time to run down bugs like this right now. Is this something that you’d be able to do?



you can use fxaa shader instead, look for my post in code snippets on deferred shading. Fxaa is a post process and it even works on high frequency normal maps speculars.

It’s because FilterManager renders the whole scene to a texture, applies that texture to a fullscreen quad, and renders that quad to the main window. So a usual ms framebuffer will happily multisample render that quad, which is of course pointless.

I’ve investigated, but I couldn’t get a buffer with antialiasing going properly. It has to be possible, but there’s probably something deep inside the FBO code that’s preventing it from working.

I agree that it is an important issue, so please feel free to report a bug on Launchpad.

@drwr: I’m afraid I don’t have enough knowledge in Cg and C++, which I assume is the case for most people here, so who do you mean by volunteers? Doesn’t the library have a dev team, or is everything done by the community? I’m just guessing the engine developers might find issue in the code they have written themselves more easily than someone else, if they are still around that is.

@rdb: will do

@Manou: I’ve never heard of a “fxaa” shader. Are you saying it’s not a FilterManager shader? If so I don’t think I can use it, as I need the ShaderGenerator. Nice work though.

There was a full-time core development team, back in the day. There isn’t now, and hasn’t been for a while; for at least the past five years or so, development on Panda has largely been by volunteers, students, and part-time developers.

rdb has been doing great things, but he’s only one guy. I’m helping out where I can, too, but I have many other competing commitments. There are a handful of other great individuals who are also contributing to pieces here and there, but for the most part, we need more volunteers if you want to see things happen.

So, feel free to put the word out. :slight_smile:


That’s kind of sad, do you think this project can continue like this?

I posted the bug report.

Yes, I think it can survive. But it depends on our users, people like you, successfully getting the word out. :slight_smile:


FXAA is a post-process anti-aliasing :, the main purpose of it is to work with everything (deferred shading, specular, shader effects…), the quality is inferior to hardware FSAA but it’s quite good I think.

As it is a shader, the users don’t have to activate anti-aliasing with their drivers.

This works with the last dev version of panda, I don’t know about 1.7 :

  1. Create a filter manager with :
filter_man = FilterManager(, my_camera)

my_camera is the camera you want to use ( for example)

  1. Create a fullscreen quad with :
my_map = Texture()
final_quad = filter_man.renderSceneInto(colortex = my_map)
  1. Apply the shader to your quad :
  1. Pass the rendered scene texture to the shader :
final_quad.setShaderInput("color", my_map)
  1. Activate the shader :
final_quad.setShaderInput("active", 1)

The shader code (


varying vec4 posPos; 
uniform float FXAA_SUBPIX_SHIFT = 1.0/4.0; 
const float rt_w = 1024; // resolution width 
const float rt_h = 768; // resolution height 

void vshader(float4 vtx_position : POSITION, 
             out float4 l_position : POSITION, 
             out float2 l_texcoord : TEXCOORD0, 
             out float4 l_posPos : TEXCOORD1, 
             uniform float4 texpad_color, 
             uniform float4x4 mat_modelproj) 
  l_position = mul(mat_modelproj, vtx_position); 
  l_texcoord = (vtx_position.xz * texpad_color.xy) + texpad_color.xy; 
  vec2 rcpFrame = vec2(1.0/rt_w, 1.0/rt_h); 
  posPos.xy = l_texcoord.xy; = l_texcoord.xy - (rcpFrame * (0.5 + FXAA_SUBPIX_SHIFT)); 

  l_posPos = posPos; 

uniform float vx_offset; 
uniform float FXAA_SPAN_MAX = 8.0; 
uniform float FXAA_REDUCE_MUL = 1.0/8.0; 

#define FxaaInt2 ivec2 
#define FxaaFloat2 vec2 
#define FxaaTexLod0(t, p) texture2DLod(t, p, 0.0) 
#define FxaaTexOff(t, p, o, r) tex2Dlod(t, float4(p.xy + (o * rcpFrame), 0, 0)) 

vec3 FxaaPixelShader( 
  vec4 posPos, // Output of FxaaVertexShader interpolated across screen. 
  sampler2D tex, // Input texture. 
  vec2 rcpFrame) // Constant {1.0/frameWidth, 1.0/frameHeight}. 
    #define FXAA_REDUCE_MIN   (1.0/128.0) 
    //#define FXAA_REDUCE_MUL   (1.0/8.0) 
    //#define FXAA_SPAN_MAX     8.0 
    vec3 rgbNW = FxaaTexLod0(tex,; 
    vec3 rgbNE = FxaaTexOff(tex,, FxaaInt2(1,0), rcpFrame.xy).xyz; 
    vec3 rgbSW = FxaaTexOff(tex,, FxaaInt2(0,1), rcpFrame.xy).xyz; 
    vec3 rgbSE = FxaaTexOff(tex,, FxaaInt2(1,1), rcpFrame.xy).xyz; 
    vec3 rgbM  = FxaaTexLod0(tex, posPos.xy).xyz; 
    vec3 luma = vec3(0.299, 0.587, 0.114); 
    float lumaNW = dot(rgbNW, luma); 
    float lumaNE = dot(rgbNE, luma); 
    float lumaSW = dot(rgbSW, luma); 
    float lumaSE = dot(rgbSE, luma); 
    float lumaM  = dot(rgbM,  luma); 
    float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE))); 
    float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE))); 
    vec2 dir; 
    dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE)); 
    dir.y =  ((lumaNW + lumaSW) - (lumaNE + lumaSE)); 
    float dirReduce = max( 
        (lumaNW + lumaNE + lumaSW + lumaSE) * (0.25 * FXAA_REDUCE_MUL), 
    float rcpDirMin = 1.0/(min(abs(dir.x), abs(dir.y)) + dirReduce); 
    dir = min(FxaaFloat2( FXAA_SPAN_MAX,  FXAA_SPAN_MAX), 
          max(FxaaFloat2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), 
          dir * rcpDirMin)) * rcpFrame.xy; 
    vec3 rgbA = (1.0/2.0) * ( 
        FxaaTexLod0(tex, posPos.xy + dir * (1.0/3.0 - 0.5)).xyz + 
        FxaaTexLod0(tex, posPos.xy + dir * (2.0/3.0 - 0.5)).xyz); 
    vec3 rgbB = rgbA * (1.0/2.0) + (1.0/4.0) * ( 
        FxaaTexLod0(tex, posPos.xy + dir * (0.0/3.0 - 0.5)).xyz + 
        FxaaTexLod0(tex, posPos.xy + dir * (3.0/3.0 - 0.5)).xyz); 
    float lumaB = dot(rgbB, luma); 
    if((lumaB < lumaMin) || (lumaB > lumaMax)) return rgbA; 
    return rgbB; } 

vec4 PostFX(float4 pos, sampler2D tex, vec2 uv, float time) 
  vec4 c = vec4(0.0); 
  vec2 rcpFrame = vec2(1.0/rt_w, 1.0/rt_h); 
  c.rgb = FxaaPixelShader(pos, tex, rcpFrame); 
  //c.rgb = 1.0 - texture2D(tex, pos.xy).rgb; 
  c.a = 1.0; 
  return c; 

void fshader(float2 l_texcoord : TEXCOORD0, 
             float4 l_posPos : TEXCOORD1, 
             uniform sampler2D k_color : TEXUNIT0, 
             uniform float k_active, 
             uniform float4 texpix_color, 
             uniform float4 texpad_color, 
             out float4 o_color : COLOR) 
  float4 without_fxaa = tex2D(k_color, l_texcoord); 

  vec2 uv =; 
  o_color = PostFX(l_posPos, k_color, uv, 0.0); 

  if(k_active == 0) o_color = without_fxaa; 

If you get an error (cg program too complex), write this at the beginning of your main class :

loadPrcFileData('', 'basic-shaders-only 0')

OK, will try, thanks. Though I am targeting old PCs with no shader support as well.
EDIT: Any ideas on how to use the CommonFilters and FilterManager at the same time, with the same display region and camera?

filters = CommonFilters(,
filter_man = FilterManager(,
StandardError: Could not find appropriate DisplayRegion to filter

@drwr: I could help with updating the engine in ModDB, the info seems outdated.


I haven’t had the time to get into CG, but on a scale from 1 to 10…how much of a pain in the arse is CG to learn?

The stuff looks like chicken scratch to me.

I think that CommonFilters uses a FilterManager, so you can directly access it. See the CommonFilters source code for more pointers.

Or you could chain them up, by letting the result of a chain of buffers render as a filter or something like that. In that case, you’d be creating one of the filter chains, and then passing one of the buffers to the other object.

You’re right. I don’t think I understand the second option, but the first one seems to disable the commonfilters completely:

from pandac.PandaModules import *
import direct.directbase.DirectStart
from direct.filter.FilterManager import *
from direct.filter.CommonFilters import CommonFilters

filters = CommonFilters(,
filters.setBloom(size = "large")

filter_man = filters.manager
my_map = Texture()
final_quad = filter_man.renderSceneInto(colortex = my_map)
final_quad.setShaderInput("color", my_map)
final_quad.setShaderInput("active", 1)

scene = loader.loadModel('environment')


Am I doing something wrong?