Multi-pass rendering: setInitialState won't apply shader

I am rendering a scene into three buffers with three cameras respectively. For each camera, I call setInitialState to set a shader.
The problem is, only one buffer has shader applied, which owns lowest render sort as figure shows.


The scene is just made of several cube, one of these has a color by setColor method.
The shader just makes them green.
The code is like following:

from direct.showbase.ShowBase import ShowBase
from panda3d.core import *

class Test(ShowBase):
    def __init__(self):
        super().__init__()
        self.disable_mouse()
        self.accept('escape', exit)

    def enter(self):
        # the function simply load a cube and reparent it to render
        c1 = constant.GET_SHAPE('cube')
        c1.setPos(0, 10, 0)
        c1.setColor((0, 1, 1, 1))
        c2 = constant.GET_SHAPE('cube')
        c2.setPos(2, 14, 0)
        c3 = constant.GET_SHAPE('cube')
        c3.setPos(-3, 10, 0)
        c4 = constant.GET_SHAPE('cube')
        c4.setPos(3, 200, 30)
        c5 = constant.GET_SHAPE('cube')
        c5.setPos(-3, 201, 30)
        c6 = constant.GET_SHAPE('cube')
        c6.setPos(-0.2, 2, 0.3)
        c6.setScale(0.1)

        self.set_buffer()

    def set_buffer(self):
        buffer_size = (512, 512)
        buffer1 = base.win.makeTextureBuffer('cascaded shadow buffer - near', *buffer_size)
        buffer2 = base.win.makeTextureBuffer('cascaded shadow buffer - middle', *buffer_size)
        buffer3 = base.win.makeTextureBuffer('cascaded shadow buffer - far', *buffer_size)

        buffer1.setSort(-3)
        buffer2.setSort(-3)
        buffer3.setSort(-4)
        buffer1.setClearColor((1, 0, 0, 1))
        buffer2.setClearColor((1, 0, 0, 1))
        buffer3.setClearColor((1, 0, 0, 1))
        self.light_np1 = base.makeCamera(buffer1)
        self.light_np2 = base.makeCamera(buffer2)
        self.light_np3 = base.makeCamera(buffer3)
        self.light1 = self.light_np1.node()
        self.light2 = self.light_np2.node()
        self.light3 = self.light_np3.node()
        self.light1.setScene(render)
        self.light2.setScene(render)
        self.light3.setScene(render)
        self.light_np_all = NodePath('light np all')
        self.light_np_all.reparentTo(render)
        self.light_np1.reparentTo(self.light_np_all)
        self.light_np2.reparentTo(self.light_np_all)
        self.light_np3.reparentTo(self.light_np_all)


        caster_shader = Shader.load(Shader.SLGLSL, vertex='shaders/other/shadow_caster.vert',
                                    fragment='shaders/other/shadow_caster.frag')
        render_state = RenderState.make(ShaderAttrib.make(caster_shader))
        self.light1.setInitialState(render_state)
        self.light2.setInitialState(render_state)
        self.light3.setInitialState(render_state)

        # visualize
        test1 = buffer1.getTextureCard()
        test1.reparentTo(aspect2d)
        test1.setScale(0.3)
        test1.setPos(-1, 0, -0.5)

        test2 = buffer2.getTextureCard()
        test2.reparentTo(aspect2d)
        test2.setScale(0.3)
        test2.setPos(-0, 0, -0.5)

        test3 = buffer3.getTextureCard()
        test3.reparentTo(aspect2d)
        test3.setScale(0.3)
        test3.setPos(1, 0, -0.5)

t = Test()
import constant
t.enter()
t.run()

I don’t know if it is because of shared gsg, but when I use following code to create buffer:

        winprops = WindowProperties(size=(512, 512))
        props = FrameBufferProperties()
        props.setRgbColor(1)
        props.setAlphaBits(1)
        props.setDepthBits(1)
        buffer1 = base.graphicsEngine.makeOutput(
            base.pipe, "offscreen buffer", -2,
            props, winprops,
            GraphicsPipe.BFRefuseWindow)
        buffer2 = base.graphicsEngine.makeOutput(
            base.pipe, "offscreen buffer", -4,
            props, winprops,
            GraphicsPipe.BFRefuseWindow)
        buffer3 = base.graphicsEngine.makeOutput(
            base.pipe, "offscreen buffer", -1,
            props, winprops,
            GraphicsPipe.BFRefuseWindow)
        t1 = Texture()
        buffer1.addRenderTexture(t1, GraphicsOutput.RTMBindOrCopy, GraphicsOutput.RTPColor)
        t2 = Texture()
        buffer2.addRenderTexture(t2, GraphicsOutput.RTMBindOrCopy, GraphicsOutput.RTPColor)
        t3 = Texture()
        buffer3.addRenderTexture(t3, GraphicsOutput.RTMBindOrCopy, GraphicsOutput.RTPColor)

I get totally black like this:

To conclude, I want to get several buffer with a shader effect by:

  1. creating three buffer;
  2. making camera for these;
  3. calling cam.setInitialState;

The result is: only one buffer shows the effect, and I find it would be the buffer with the lowest render sort. The other two buffer render all cubes into white, regardless of the original color of the cube.
So I wonder how could it be solved. Any help would be appreciated.

Could you include the constant module and your shader so that I can try running your code?

Sure.
Related part of constant module is like following:

BASE_SHAPE_LIST = {
            'cube': loader.loadModel('models/general/cube'),
        }
def GET_SHAPE(shape):
    return BASE_SHAPE_LIST[shape].copyTo(render).children[0]

Or replace enter function of the main class with:

        c1 = loader.loadModel('models/general/cube')
        c1.reparentTo(render)
        c1.setPos(0, 10, 0)
        c1.setColor((0, 1, 1, 1))
        c2 = loader.loadModel('models/general/cube')
        c2.reparentTo(render)
        c2.setPos(2, 14, 0)
        c3 = loader.loadModel('models/general/cube')
        c3.reparentTo(render)
        c3.setPos(-3, 10, 0)
        c4 = loader.loadModel('models/general/cube')
        c4.reparentTo(render)
        c4.setPos(3, 200, 30)
        c5 = loader.loadModel('models/general/cube')
        c5.reparentTo(render)
        c5.setPos(-3, 201, 30)
        c6 = loader.loadModel('models/general/cube')
        c6.reparentTo(render)
        c6.setPos(-0.2, 2, 0.3)
        c6.setScale(0.1)

        self.set_buffer()

Which gives same result.

And my shader:
vertex:

#version 330 core

in vec4 p3d_Vertex;
uniform mat4 p3d_ModelViewProjectionMatrix;

void main()
{
	gl_Position = p3d_ModelViewProjectionMatrix * p3d_Vertex;
}

fragment:

#version 330 core

out vec4 frag_color;

void main()
{
	frag_color = vec4(0, 1, 0, 1);
}

And model file:
cube.egg (4.4 KB)

You’re right. When I set gl-version 3 2 in Config.prc (to request a core profile), then it shows all three green. But by default, it shows only one of them as green. I’ll investigate.

I have checked in a fix. It will be in the upcoming 1.10.6 release. In the meantime, you can probably work around it by setting gl-version 3 2 (note that this disables the fixed-function pipeline and requires use of GLSL shaders for all non-simple objects), or by using a different shader for each buffer, or by adding an object that doesn’t have a shader or has a different shader to each buffer.

1 Like