Filter shader chain

I must be doing something wrong… or it’s the heat…

I’m trying (again) to make a simple(-ish) deferred shading pipeline, and I got stuck…

This is the code I got so far:

from panda3d.core import *
from direct.filter.FilterManager import *

class DeferredRenderer():
    def __init__(self, base, scene_mask=1, light_mask=2):
        render.setShaderAuto()
        # Camera setup 
        self.light_cam = base.makeCamera(base.win)
        self.light_cam.reparentTo(base.cam)
        base.cam.node().getLens().setNearFar(1.0, 5000.0)
        
        self.scene_mask = BitMask32(scene_mask)
        self.light_mask = BitMask32(light_mask)

        base.cam.node().setCameraMask(self.scene_mask)
        self.light_cam.node().setCameraMask(self.light_mask)        

        base.cam.node().getDisplayRegion(0).setSort(1)
        self.light_cam.node().getDisplayRegion(0).setSort(2)
        base.win.setSort(3)

        self.light_cam.node().getDisplayRegion(0).setClearColor(Vec4(.0, .0, .0, 1))
        self.light_cam.node().getDisplayRegion(0).setClearColorActive(1)
        
        #Buffers creation 
        self.manager = FilterManager(base.win, base.cam)
        self.depth = Texture()
        self.albedo = Texture()
        self.normal = Texture()        
        final_quad=self.manager.renderSceneInto(colortex = self.albedo,
                                                depthtex = self.depth,
                                                auxtex = self.normal,
                                                auxbits = AuxBitplaneAttrib.ABOAuxNormal)
        #light list
        self.lights=[]   
        #geometry list
        self.geometery=[]
        
    def addGeometry(self, node):
        if isinstance(node, basestring):
            node=loader.loadModel(node)
        node.reparentTo(render)
        node.hide(self.light_mask)
        node.setShader(Shader.load("gshader.sha"))
        self.geometery.append(node)
        #return the index of the node to remove it later
        return self.geometery.index(self.geometery[-1])
    
    def removeGeometry(self, geometryID):
        if self.geometery[geometryID]:
            self.geometery[geometryID].removeNode()
            self.geometery[geometryID]=None
    
    def addLight(self, color, model="volume/sphere", pos=None, radius=1.0, diffuse=Vec3(1,1,1), specular=Vec3(.8,.8,.8), attenuation=Vec3(0.1,0.2,0.003)):
        #light geometry
        if isinstance(model, basestring):
            model=loader.loadModel(model)
        self.lights.append(model)
        self.lights[-1].reparentTo(render)
        if pos:
            self.lights[-1].setPos(pos)
        self.lights[-1].setColor(color)
        self.lights[-1].setScale(radius)
        self.lights[-1].reparentTo(render)
        self.lights[-1].setAttrib(DepthTestAttrib.make(RenderAttrib.MLess))
        self.lights[-1].setAttrib(CullFaceAttrib.make(CullFaceAttrib.MCullCounterClockwise))
        #self.lights[-1].setAttrib(CullFaceAttrib.make(CullFaceAttrib.MCullClockwise)) #??
        self.lights[-1].setAttrib(ColorBlendAttrib.make(ColorBlendAttrib.MAdd, ColorBlendAttrib.OOne, ColorBlendAttrib.OOne))
        self.lights[-1].setAttrib(DepthWriteAttrib.make(DepthWriteAttrib.MOff))
        self.lights[-1].hide(self.scene_mask)
        #light shader
        self.lights[-1].setShader(loader.loadShader("def_light.cg"))
        self.lights[-1].setShaderInput("albedo", self.albedo)
        self.lights[-1].setShaderInput("depth", self.depth)
        self.lights[-1].setShaderInput("normal", self.normal)
        self.lights[-1].setShaderInput("Kd", diffuse)
        self.lights[-1].setShaderInput("Ks",specular)
        self.lights[-1].setShaderInput("att_params",attenuation)
        self.lights[-1].setShaderInput("light_radius", radius)
        self.lights[-1].setShaderInput("camera",base.camera)         
        #return the index of the light to remove it later
        return self.lights.index(self.lights[-1])
    
    def removeLight(self, lightID):
        if self.lights[lightID]:
            self.lights[lightID].removeNode()
            self.lights[lightID]=None

It’s basically the code by Manou ([UPDATE] - Fur - Deferred shading) wraped into a class.

My problem is that I have no idea how to get the rendered, lit scene, filter it with a bloom/fxaa/whatever shader and put it back in the main window.

You could just use my pipeline which does everything for you :stuck_out_tongue:

Or you could use my RenderTarget wrapper, which simplifies the setup to:

target = RenderTarget("myFancyEffect")
target.addColorTexture()
target.prepareSceneRender()
target.setShader(myShader)
target.setShader("source", target.getColorTexture())

in your target you now have access to a sampler2D source, where you can do what you want with :slight_smile:

Your pipeline is a bit intimidating to steal bits and pieces from and last time I tried my gpu couldn’t handle it out of the box.

I’ve used Manu’s code before, and used renderQuadInto to apply post processing.

This is code that doesn’t seem to be working anymore, but I did have post-processing working at one stage using the same technique.

        # Glow pass
        self.glow = Texture()

        # Final output
        self.finalBuffer = Texture()

        # Deferred shading quad
        self.finalQuad = self.filterManager.renderSceneInto(colortex = self.albedo, depthtex = self.depth, auxtex = self.normal,auxbits = AuxBitplaneAttrib.ABOAuxNormal)

        # Post processing quad
        self.postQuad = self.filterManager.renderQuadInto(colortex = self.finalBuffer)

        # Create a buffer for glow
        self.interquad = self.filterManager.renderQuadInto(colortex = self.shadowmap)
        self.interquad.setShader(loader.loadShader('shaders/glow.sha'))
        self.interquad.setShaderInput('src', self.albedo)
        self.interquad.setShaderInput('srcglow', self.spec)

        # Add the blur into the final generated buffer
        self.postQuad.setShader(loader.loadShader('shaders/blur.sha'))
        self.postQuad.setShaderInput('src', self.shadowmap)
        self.postQuad.setShaderInput('src2', self.finalBuffer)

Tobias’ Rendertarget snippet sounds like it might be better then my hackathon.

Maikeru -> that looks about what I’m doing. It’s not working :cry:

If I do this (the rest of the code as in my first post):

self.manager = FilterManager(base.win, base.cam)
        self.depth = Texture()
        self.albedo = Texture()
        self.normal = Texture()    
        self.final=Texture()        
        final_quad=self.manager.renderSceneInto(colortex = self.albedo,
                                                depthtex = self.depth,
                                                auxtex = self.normal,
                                                auxbits = AuxBitplaneAttrib.ABOAuxNormal)
                                                
        self.postQuad = self.manager.renderQuadInto(colortex = self.final)
        self.postQuad.setShader(loader.loadShader('mix.cg'))
        self.postQuad.setShaderInput('final', self.final)

Then ‘self.final’ is all black, and it’s not on the screen.

What are you trying to do? How about this?

self.manager = FilterManager(base.win, base.cam)
        self.depth = Texture()
        self.albedo = Texture()
        self.normal = Texture()        
        final_quad=self.manager.renderSceneInto(colortex = self.albedo,
                                                depthtex = self.depth,
                                                auxtex = self.normal,
                                                auxbits = AuxBitplaneAttrib.ABOAuxNormal)

        final_quad.setShader(loader.loadShader('display.cg'))
        final_quad.setShaderInput('color', self.albedo)

And display.cg just outputs the tex2D(color, texcoord), or whatever post process effect you want to achieve.

About your given code, it is expected that the screen is black, as you don’t set a shader to the final_quad, and also no texture. The result of postQuad is never applied to the screen.

Hmm, looks like I was wrong, didn’t get post process filters working with Manus code. It seems not much of my code works after switching to ATI.

Anyway, I think it has something to do with there being a separate light camera and scene camera, changing the display region sorts makes the post process effect appear, but then the lighting is stuffed.