CommonFilters with Custom Filter Support

I’ve seen a lot of people wishing that they could mix their own shaders into CommonFilters so I’ve edited the CommonFilters.py file a bit to support that.

Here’s an example:

from CommonFilters import CommonFilters
from direct.showbase.ShowBase import ShowBase

s = ShowBase()

p = s.loader.load_model("panda")
p.reparent_to(s.render)

c = CommonFilters(s.win, s.cam)
c.setBlurSharpen(0.5)

c.add_uniform("float raise_amount")
c.add_shader_inputs({"raise_amount": 0.5})
c.add_filter("""o_color += 0.5 * raise_amount;""", 0)

c.add_uniform("float increase_red")
c.add_shader_input("increase_red", 0.5})
c.add_filter("""o_color.r += increase_red;""", 0)

s.run()

As we can see it’s pretty simple to use.

I also added a simple Chromatic Aberration Filter and am planning on adding more filters along with better support for adding custom textures and using the ones CommonFilters already generates.

If anyone has any ideas for filters or feedback just let me know.

4 Likes

That’s pretty cool! Nicely done! :slight_smile:

2 Likes

I’ve added support for render targets so you can compose your own.

I’ve rewritten BlurSharpen as an example.

New BlurSharpen

    def setBlurSharpen(self, amount=0.0):
        """Enables the blur/sharpen filter. If the 'amount' parameter is 1.0, it will not have any effect. A value of 0.0 means fully blurred, and a value higher than 1.0 sharpens the image."""

        self.load_filter(
            "BlurSharpen",
            "  o_color = lerp(tex2D(k_txblur1, l_texcoord_blur1), o_color, k_blurval.x);\n",
            shader_inputs={"blurval": LVecBase4(amount, amount, amount, amount)},
            uniforms=["float4 k_blurval"],
            needed_textures=["blur0", "blur1"], 
            needed_coords=["blur1"],
            render_into={
                "filter-blur0": {
                    "colortex": {"texture": "blur0"},
                    "div": 2,
                    "shader_inputs": {
                        "src": {"texture": "color"}
                    },
                    "shader": Shader.make(BLUR_X, Shader.SL_Cg)
                },
                "filter-blur1": {
                    "colortex": {"texture": "blur1"},
                    "shader_inputs":
                        {
                            "src": {"texture": "blur0"}
                        },
                    "shader": Shader.make(BLUR_Y, Shader.SL_Cg)
                }
            }
        )

Also here’s a simple chromatic aberration shader example.


  def set_chromatic_aberration(self, r=1.07, g=1.05, b=1.03):
      coords = self.texcoords["color"]
      self.load_filter(
          "chromatic aberration",
          f"""
      float r = tex2D(k_txcolor, {coords}.xy / chromatic_offset_r).r;
      float g = tex2D(k_txcolor, {coords}.xy / chromatic_offset_g).g;
      float b = tex2D(k_txcolor, {coords}.xy / chromatic_offset_b).b;
      o_color = float4(r,g,b, o_color.a);""",
          uniforms=[
              "float chromatic_offset_r",
              "float chromatic_offset_g",
              "float chromatic_offset_b"
          ],
          shader_inputs={"chromatic_offset_r": r, "chromatic_offset_g": g, "chromatic_offset_b": b}
      )

Should look like this

1 Like

Bloom and Cartoon Ink have been ported. Also added vignette.

What the bloom code looks like.

  if size == 0 or size == "off":
      self.delBloom()
      return
  elif size == 1:
      size = "small"
  elif size == 2:
      size = "medium"
  elif size == 3:
      size = "large"

  if maxtrigger is None:
      maxtrigger = mintrigger + 0.8

  intensity *= 3.0
  if size == "large":
      scale = 8
      downsamplerName = "filter-down4"
      downsampler = DOWN_4
  elif size == "medium":
      scale = 4
      downsamplerName = "filter-copy"
      downsampler = COPY
  else:
      scale = 2
      downsamplerName = "filter-copy"
      downsampler = COPY

  self.load_filter("Bloom",
                   """
  o_color = saturate(o_color);
  float4 bloom = 0.5 * tex2D(k_txbloom3, l_texcoord_bloom3);
  o_color = 1-((1-bloom)*(1-o_color));
  """,
                   auxbits=[AuxBitplaneAttrib.ABOGlow],
                   needed_coords=["bloom3"],
                   needed_textures=["bloom0", "bloom1", "bloom2", "bloom3"],
                   render_into={
                       "filter-bloomi":
                           {
                               "shader_inputs":
                                   {
                                       "blend": (blend[0], blend[1], blend[2], blend[3] * 2.0),
                                       "trigger": (mintrigger, 1.0 / (maxtrigger - mintrigger), 0.0, 0.0),
                                       "desat": desat,
                                       "src": {"texture": "color"}
                                   },
                               "shader": Shader.make(BLOOM_I, Shader.SL_Cg),
                               "colortex": {"texture": "bloom0"},
                               "div": 2,
                               "align": scale

                           },
                       downsamplerName:
                           {
                               "colortex": {"texture": "bloom1"},
                               "div": scale,
                               "align": scale,
                               "shader": Shader.make(downsampler, Shader.SL_Cg),
                               "shader_inputs":
                                   {
                                       "src": {"texture": "bloom0"}
                                   }

                           },
                       "filter-bloomx":
                           {
                               "colortex": {"texture": "bloom2"},
                               "div": scale,
                               "align": scale,
                               "shader": Shader.make(BLOOM_X, Shader.SL_Cg),
                               "shader_inputs":
                                   {
                                       "src": {"texture": "bloom1"}
                                   }

                           },
                       "filter-bloomy":
                           {
                               "colortex": {"texture": "bloom3"},
                               "div": scale,
                               "align": scale,
                               "shader": Shader.make(BLOOM_Y, Shader.SL_Cg),

                               "shader_inputs":
                                   {
                                       "intensity": (intensity, intensity, intensity, intensity),
                                       "src": {"texture": "bloom2"}
                                   }
                           }
                   }
                   )

Cartoon Ink with Vignette

Also does anyone have any ideas of new common filters that should be added to Panda3D?

I have a list here but just because it’s there doesn’t mean it’ll be added. Todo · Issue #2 · raytopianprojects/CommonFilters · GitHub

1 Like

I’ve ported all the old shaders over to the new system. :raised_hands:

I’ll be opening my pull request once I add a few more effects.

Also here’s a distortion post process I’ve added:
python_ewjWaRdaDV

Pretty easy to make

load_filter("Distortion", """o_color = tex2D(k_txcolor, l_texcoord_color * tex2D(distortion_map, l_texcoord_color));""",
                         uniforms=["sampler2D distortion_map"],
                         shader_inputs={"distortion_map": base.loader.load_texture("maps/noise.rgb")},
                         )
2 Likes

Good work, and a cool new shader! :slight_smile:

It occurs to me to wonder: If I recall correctly, the old shaders were written in Cg; might it be worth porting them over to GLSL…?

1 Like

Thank you! :grinning:

Porting the shaders to GLSL is something I’ve been thinking of. It would be more convenient given that everyone already uses GLSL. So I’ll probably give it a go.

1 Like

This is very useful. Thanks!