Combining CommonFilters with FilterManager

Is there any way to combine CommonFilters with FilterManager? Because when I create a quad with FilterManager:

manager = FilterManager(base.win, base.cam)
tex = Texture()
quad = manager.renderSceneInto(colortex=tex)

then the initialisation of the CommonFilters object:

filters = CommonFilters(base.win, base.cam)

causes an error:

Exception: Could not find appropriate DisplayRegion to filter

Which one do you want to run first?

CommonFilters uses FilterManager under the hood. FilterManager replaces the display region with one that renders a fullscreen quad, then creates an offscreen buffer to render the scene into, and reassigns the main camera to render that one.

So when you are creating your other FilterManager/CommonFilters, it can’t find a display region on the window matching the main camera. You either need to point it at the camera used by the other object to render the fullscreen quad, or you need to point it at the offscreen buffer created by the other FilterManager/CommonFilters.

1 Like

Thank you for your answer.
I would prefer CommonFilters first, then FilterManager. Because I want to use the built-in setVolumetricLighting() and possibly setBloom(), and then apply some of my own filters (vignetting, radial blur and the like). I tried to somehow find the appropriate base.win and base.cam in the CommonFilters class object, but I didn’t find it (I’m still not sure how it works).
Alternatively, if CommonFilters first was a big problem, then it might be acceptable the other way around and FilterManager first. Although the effect would probably be worse.
I will be grateful for any hints.

With what you’re doing, it may be worth it to dive into the source code of CommonFilters and FilterManager to see what it’s doing, or even just rip out the parts of CommonFilters that you need and reimplement them on top of your own FilterManager.

That said, it should be possible to chain two FilterManager objects (CommonFilters uses FilterManager under the hood, use .manager to access it). However, the second object will not be able to access the original scene’s depth texture, etc, because it will just be capturing the output color that is a result from the compositing process of the first one. Maybe it is possible to interleave two objects’ operations in complex ways, but if I were you, I would really just save myself the trouble and copy CommonFilters.py into my own codebase and modify it to add my own effects.

You can wanted to try and chain them, you can set one up to use the other one’s internal buffer (manager.buffers[0]) with the default camera, or you can do the reverse by using the regular window but using the camera object that the other FilterManager assigned to it (base.win.display_regions[0].camera, or maybe it is region 1, not sure).

A question, if I may: Could one just use the FilterManager object owned by the CommonFilters object in place of the second FilterManager object?

That is, something like this:

filters = CommonFilters(base.win, base.cam)
# <CommonFilters stuff here...>

manager = filters.manager
tex = Texture()
quad = manager.renderSceneInto(colortex = tex)

You could, but CommonFilters also calls renderSceneInto, so this will cause your scene to be rendered twice. If your scene is expensive to render, this will be slow.

1 Like

Is that not already the case in this scenario, however? After all, the original post has the separate FilterManager calling “renderSceneInto” alongside usage of CommonFilters. Or does FilterManager have some clever trick of re-using render-results across FilterManager instances…?

In the case of FilterManager chaining, the “scene” rendered by renderSceneInto will be the fullscreen quad that is being rendered by the previous manager, containing the output image.

That’s why I said that the second manager couldn’t access the depth buffers, etc. of the original scene, but I just realised that that’s wrong, because of course you can just have the second FilterManager access the .textures[] dictionary of the CommonFilters instance.

Ah, I see, I believe. More appropriate then–both in terms of performance and initial (apparent) intent–might be to replace the second “renderSceneInto” with “renderQuadInto”; is that correct?

The first FilterManager you set up is rendering its final quad, with the compositing shader and everything applied to it, into the window. You need to instead capture this final render result into a texture so you can use that as input of one or more of your subsequent filters. This is what the renderSceneInto of your second manager accomplishes, because it redirects the output of whatever “scene” (which may in fact be the final filter pass of the first manager) into a texture buffer, and then it replaces the original scene (ie. the quad rendered to the main window) with a quad to show the final result of the second manager in its place. But renderQuadInto doesn’t do this first step. It just creates a new pass with a fullscreen quad, disconnected from everything.

One way of thinking about these methods is that renderSceneInto sets up the input and output of the filter chain (so the scene pass and the final pass), whereas renderQuadInto is used to set up intermediate passes.

I think that I understand you correctly, and I think that that’s exactly what I had in mind: CommonFilters calls “renderSceneInto”, setting things up, then the developer calls “renderQuadInto” on the FilterManager within CommonFilters to perform subsequent filtering. Note that miklesz indicated about that they wanted “CommonFilters first, then FilterManager”.

But it’s possible that I’m misunderstanding–for some reason, I’ve always had trouble fully keeping in mind the flow of FilterManager…

Ah, I see what you mean, rather than chaining two of them, you just have a single CommonFilters and you try and rewire things inside it by inserting your own passes.

Yes, that would work. You would need to change the shader inputs of the finalQuad member to point it to the output of your intermediate passes.

1 Like

Thanks for the answers. I haven’t visited this thread for a while and I see that I have sparked a lively discussion.

In the end, I decided to do it differently. Because my need to combine CommonFilters with FilterManager was because I absolutely wanted to be able to use the built-in filters and marry them with my own shaders. However, it would still mean locking myself into the archaic world of #version 120 because of:
https://docs.panda3d.org/1.10/python/programming/shaders/known-shader-issues#problem-glsl-versions-on-macos

That’s why I decided to abandon CommonFilters and just create my own versions of these filters, this time already in #version 410.

So, thank you again for your support. Let the thread stay, hope someone else will find it useful. And I already have most of the filters I need rewritten for the newer OpenGL (actually, I could even offer them to the community, but I’m just learning shaders, so my implementations are probably still quite amateur - although they work so-so).

2 Likes

Hi - (and if I may interfere…)

I end up using the Technologicat system ( CommonFilters - some new filters, and the future - Panda Features in Development - Panda3D), as it enables you to easily use multi stacked filters. I use it, with some adaptations (e.g. simplification, convertion from cg to GLSL, and python upgrade).

One thing that is still a little bit annoying is that FilterManager depends on the camera. This implies to regenerate all the Filters at each camera change. I don’t know whether or not this can be addressed by another design in a next future…

Having an easy-to-use, customizable and multi-stacked post processing “framework” is one thing that could be interesting for P3D 11.

2 Likes