FilterManager issue with overlaying shaders on 2d+3d scene

Hi there, I am currently trying to apply GLSL shaders on both the 3d (render) and 2d (render2d) nodes on the scene graph. I’m currently using FilterManager to initialize these shaders since most of them require a ShaderInput.

I make two FilterManagers, one for base.cam [render] and base.cam2d [render2d] respectively. Here’s how I set the shaders up:

self.manager = FilterManager(base.win, base.cam)
self.manager2d = FilterManager(base.win, base.cam2d)
...
shader = Shader.load(Shader.SLGLSL, self.vertexShader, self.fragmentShader)
self.enabled = True # shader input
...

## 3D
colortex = Texture()  # Create an empty Texture object
# quad is a GeomNode (NodePath) known as filter-base-quad
self.quad = self.manager.renderSceneInto(colortex=colortex)  # Render-to-texture our scene (3D)
self.quad.setShader(shader) # Load shaders
self.quad.setShaderInput("colorTexture", colortex) # Pass our rendered scene texture for the shader to process
self.quad.setShaderInput("enabled", (self.enabled, self.enabled))

## 2D
colortex2d = Texture()
colortex2d.setClearColor((0, 0, 0, 0)) # doesn't help
self.quad2d = self.manager2d.renderSceneInto(colortex=colortex2d)
self.quad2d.setShader(shader)
self.quad2d.setShaderInput("colorTexture", colortex2d)
self.quad2d.setShaderInput("enabled", (self.enabled, self.enabled))

Both the 2D GUI in render2d and the nodes in render have the shader applied as intended, however, when render2d has the shader applied, it causes everything in render to become invisible/overlayed with the background color.

It seems that I can’t have both the 2d and 3d nodes have shaders applied and visible at the same time. Though, when I hide render2d or quad2d, I can see the scene again. This makes me believe that there’s a masking/alpha issue going on in render2d that makes all the empty space supersede anything in render and below…

I tried doing a lot of debugging, such as setting quad2d’s transparency, doing setColor, setColorScale, changing the bin, etc. I also tried debugging the Texture object that’s created for the render-to-texture, checking to see whether the issue was related to having only 3 channels on the generated texture. I doubt it has anything to do with the shader code itself, as this is a re-occurring issue with other shaders I’ve been using.

Here’s the code snippet I did to extract the render-to-texture data:

tex = self.shader.tex2d
base.graphicsEngine.extractTextureData(tex, base.win.gsg)
tex.write("snapshot2d.png")



(Images were both outputted in PNG format with transparent backgrounds)

For the sake of convenience, I’ve uploaded the source code for this sample. I’ve also added in some hotkeys to demonstrate this issue:

  • 0 → loads shader
  • 1/2 → hides/shows quad2D
  • 3/4 → hides/shows render2d
  • 5/6 → hides/shows render
  • 7/8 → take snapshot of 3d/2d scene

I am currently using the latest version of Panda3D with this program (1.10.10). I have no clue if this is a limitation of the FilterManager class itself or if I’m not adding in something. :confused:

Source code for this:
shader.rar (124.4 KB)

Based on a look at the shader and some quick experimentation, it looks to me that the problem is that for the GUI you’re rendering the entire quad, and rendering it as opaque geometry.

Again, based on some quick experimentation, I found two potential solutions. I don’t know whether either is a good solution, or which is better, but here they are:

  1. You can render the non-GUI parts of render2d as transparent
    • This can be done via two changes:
      1. In your fragment shader, read the alpha-value of “colourTexture” and use it to write an alpha-value
      2. In your Python code, enable transparency on your GUI-quad
  2. You can “discard” the non-GUI parts of render2d
    • This can be done by having your fragment shader read the alpha-value of “colourTexture”, and then “discard” when that alpha-value is below a given threshold.
2 Likes