Control texture buffer


#1

I decided to master the shaders, however, to work with several shaders, third-party buffers are required. In the glow-filter example, this is well illustrated. The problem is that I can not get rid of the background black. I understand that somehow it can be defined as an alpha channel with transparency. I understand how to make transparency in the texture.

https://www.panda3d.org/manual/?title=Texture_Modes

However, with the work of makeTextureBuffer, I am having problems.

I think need to clarify what I mean. When I add another geometry, it turns out to be illuminated.

#!/usr/bin/env python

# Author: Kwasi Mensah (kmensah@andrew.cmu.edu)
# Date: 7/25/2005

from direct.showbase.ShowBase import ShowBase
from panda3d.core import Filename, Shader, TextureStage
from panda3d.core import PandaNode, NodePath, Vec4
from panda3d.core import ColorBlendAttrib
from panda3d.core import AmbientLight, DirectionalLight
from panda3d.core import TextNode, LPoint3, LVector4
from direct.showbase.DirectObject import DirectObject
from direct.gui.OnscreenText import OnscreenText
from direct.actor.Actor import Actor
import sys
import os

# Function to put instructions on the screen.
def addInstructions(pos, msg):
    return OnscreenText(text=msg, style=1, fg=(1, 1, 1, 1),
                        parent=base.a2dTopLeft, align=TextNode.ALeft,
                        pos=(0.08, -pos - 0.04), scale=.05)

# Function to put title on the screen.
def addTitle(text):
    return OnscreenText(text=text, style=1, fg=(1, 1, 1, 1),
                        parent=base.a2dBottomRight, align=TextNode.ARight,
                        pos=(-0.1, 0.09), scale=.08)


# This function is responsible for setting up the two blur filters.
# It just makes a temp Buffer, puts a screen aligned card, and then sets
# the appropiate shader to do all the work. Gaussian blurs are decomposable
# into a two-pass algorithm which is faster than the equivalent one-pass
# algorithm, so we do it in two passes: one pass that blurs in the horizontal
# direction, and one in the vertical direction.
def makeFilterBuffer(srcbuffer, name, sort, prog):
    blurBuffer = base.win.makeTextureBuffer(name, 512, 512)
    blurBuffer.setSort(sort)
    blurBuffer.setClearColor(LVector4(1, 0, 0, 1))
    blurCamera = base.makeCamera2d(blurBuffer)
    blurScene = NodePath("new Scene")
    blurCamera.node().setScene(blurScene)
    shader = loader.loadShader(prog)
    card = srcbuffer.getTextureCard()
    card.reparentTo(blurScene)
    card.setShader(shader)
    return blurBuffer


class GlowDemo(ShowBase):

    def __init__(self):
        # Initialize the ShowBase class from which we inherit, which will
        # create a window and set up everything we need for rendering into it.
        ShowBase.__init__(self)
        
        # Load the environment model.
        self.scene = self.loader.loadModel("models/environment")
        # Reparent the model to render.
        self.scene.reparentTo(self.render)
        # Apply scale and position transforms on the model.
        self.scene.setScale(0.25, 0.25, 0.25)
        self.scene.setPos(-8, 42, 0)

        base.disableMouse()
        #base.setBackgroundColor(0, 0, 0)
        camera.setPos(0, -50, 0)

        # Check video card capabilities.
        if not base.win.getGsg().getSupportsBasicShaders():
            addTitle(
                "Glow Filter: Video driver reports that Cg shaders are not supported.")
            return

        # Post the instructions
        self.title = addTitle("Panda3D: Tutorial - Glow Filter")
        self.inst1 = addInstructions(0.06, "ESC: Quit")
        self.inst2 = addInstructions(0.12, "Space: Toggle Glow Filter On/Off")
        self.inst3 = addInstructions(0.18, "Enter: Toggle Running/Spinning")
        self.inst4 = addInstructions(0.24, "V: View the render-to-texture results")

        # Create the shader that will determime what parts of the scene will
        # glow
        glowShader = loader.loadShader("shaders/glowShader.sha")

        # load our model
        self.tron = Actor()
        self.tron.loadModel("models/tron")
        self.tron.loadAnims({"running": "models/tron_anim"})
        self.tron.reparentTo(render)
        self.interval = self.tron.hprInterval(60, LPoint3(360, 0, 0))
        self.interval.loop()
        self.isRunning = False

        # put some lighting on the tron model
        dlight = DirectionalLight('dlight')
        alight = AmbientLight('alight')
        dlnp = render.attachNewNode(dlight)
        alnp = render.attachNewNode(alight)
        dlight.setColor(LVector4(1.0, 0.7, 0.2, 1))
        alight.setColor(LVector4(0.2, 0.2, 0.2, 1))
        dlnp.setHpr(0, -60, 0)
        render.setLight(dlnp)
        render.setLight(alnp)

        # create the glow buffer. This buffer renders like a normal scene,
        # except that only the glowing materials should show up nonblack.
        glowBuffer = base.win.makeTextureBuffer("Glow scene", 512, 512)
        glowBuffer.setSort(-3)
        glowBuffer.setClearColor(LVector4(0, 0, 0, 1))

        # We have to attach a camera to the glow buffer. The glow camera
        # must have the same frustum as the main camera. As long as the aspect
        # ratios match, the rest will take care of itself.
        glowCamera = base.makeCamera(
            glowBuffer, lens=base.cam.node().getLens())

        # Tell the glow camera to use the glow shader
        tempnode = NodePath(PandaNode("temp node"))
        tempnode.setShader(glowShader)
        glowCamera.node().setInitialState(tempnode.getState())

        # set up the pipeline: from glow scene to blur x to blur y to main
        # window.
        blurXBuffer = makeFilterBuffer(
            glowBuffer,  "Blur X", -2, "shaders/XBlurShader.sha")
        blurYBuffer = makeFilterBuffer(
            blurXBuffer, "Blur Y", -1, "shaders/YBlurShader.sha")
        self.finalcard = blurYBuffer.getTextureCard()
        self.finalcard.reparentTo(render2d)

        # This attribute is used to add the results of the post-processing
        # effects to the existing framebuffer image, rather than replace it.
        # This is mainly useful for glow effects like ours.
        self.finalcard.setAttrib(ColorBlendAttrib.make(ColorBlendAttrib.MAdd))

        # Panda contains a built-in viewer that lets you view the results of
        # your render-to-texture operations.  This code configures the viewer.
        self.accept("v", base.bufferViewer.toggleEnable)
        self.accept("V", base.bufferViewer.toggleEnable)
        base.bufferViewer.setPosition("llcorner")
        base.bufferViewer.setLayout("hline")
        base.bufferViewer.setCardSize(0.652, 0)

        # event handling
        self.accept("space", self.toggleGlow)
        self.accept("enter", self.toggleDisplay)
        self.accept("escape", sys.exit, [0])

        self.glowOn = True

    def toggleGlow(self):
        if self.glowOn:
            self.finalcard.reparentTo(hidden)
        else:
            self.finalcard.reparentTo(render2d)
        self.glowOn = not(self.glowOn)

    def toggleDisplay(self):
        self.isRunning = not(self.isRunning)
        if not(self.isRunning):
            camera.setPos(0, -50, 0)
            self.tron.stop("running")
            self.tron.pose("running", 0)
            self.interval.loop()
        else:
            camera.setPos(0, -170, 3)
            self.interval.finish()
            self.tron.setHpr(0, 0, 0)
            self.tron.loop("running")

demo = GlowDemo()
demo.run()


#2

I am struggling to understand your question; could you rephrase it in a different way?


#3

Yes, I myself do not understand what I said. :smiley: The problem is when I add another geometry, example “glow-filter” the scene gets brighter. I gave the code above, I do not understand how to get rid of the shader actions on the whole scene.


#4

Maybe it’s this line that is bothering you? It makes the result colours added to the existing colours in the scene, rather than replacing them.


#5

I tried different blending modes, it does not solve the problem. If you look at the first buffer, then everything is fine, but the blur will somehow affect the whole scene.


#6

I think the glow sample is a bad example. For bloom/glow it is ok to just additive blend the result of the blur shader on top os the scene. In most other cases you take the result of the previous step as an input for the next step, or have a shader that takes all the outputs and blends them in the right way (eg. multiply ao and add bloom). I think the code in the manual is more clear, but if that’s not helpful I bet I can find a sample in one of my projects.


#7

The fact is that from the examples there are no working options. It is not suitable for the production of games.

Now I don’t understand how the geometry of the render node appeared in the off-screen buffer. I think can hide the geometry for the camera buffer.


#8

I tested my theory, and oh yeah. It works.

#!/usr/bin/env python

# Author: Kwasi Mensah (kmensah@andrew.cmu.edu)
# Date: 7/25/2005

from direct.showbase.ShowBase import ShowBase
from panda3d.core import Filename, Shader, TextureStage
from panda3d.core import PandaNode, NodePath, Vec4, BitMask32
from panda3d.core import ColorBlendAttrib
from panda3d.core import AmbientLight, DirectionalLight
from panda3d.core import TextNode, LPoint3, LVector4
from direct.showbase.DirectObject import DirectObject
from direct.gui.OnscreenText import OnscreenText
from direct.actor.Actor import Actor
import sys
import os

# Function to put instructions on the screen.
def addInstructions(pos, msg):
    return OnscreenText(text=msg, style=1, fg=(1, 1, 1, 1),
                        parent=base.a2dTopLeft, align=TextNode.ALeft,
                        pos=(0.08, -pos - 0.04), scale=.05)

# Function to put title on the screen.
def addTitle(text):
    return OnscreenText(text=text, style=1, fg=(1, 1, 1, 1),
                        parent=base.a2dBottomRight, align=TextNode.ARight,
                        pos=(-0.1, 0.09), scale=.08)


# This function is responsible for setting up the two blur filters.
# It just makes a temp Buffer, puts a screen aligned card, and then sets
# the appropiate shader to do all the work. Gaussian blurs are decomposable
# into a two-pass algorithm which is faster than the equivalent one-pass
# algorithm, so we do it in two passes: one pass that blurs in the horizontal
# direction, and one in the vertical direction.
def makeFilterBuffer(srcbuffer, name, sort, prog):
    blurBuffer = base.win.makeTextureBuffer(name, 512, 512)
    blurBuffer.setSort(sort)
    blurBuffer.setClearColor(LVector4(1, 0, 0, 1))
    blurCamera = base.makeCamera2d(blurBuffer)
    blurScene = NodePath("new Scene")
    blurCamera.node().setScene(blurScene)
    shader = loader.loadShader(prog)
    card = srcbuffer.getTextureCard()
    card.reparentTo(blurScene)
    card.setShader(shader)
    return blurBuffer


class GlowDemo(ShowBase):

    def __init__(self):
        # Initialize the ShowBase class from which we inherit, which will
        # create a window and set up everything we need for rendering into it.
        ShowBase.__init__(self)
        
        # Load the environment model.
        self.scene = self.loader.loadModel("models/environment")
        self.scene.hide(BitMask32.bit(0))
        # Reparent the model to render.
        self.scene.reparentTo(self.render)
        # Apply scale and position transforms on the model.
        self.scene.setScale(0.25, 0.25, 0.25)
        self.scene.setPos(-8, 42, 0)

        base.disableMouse()
        #base.setBackgroundColor(0, 0, 0)
        camera.setPos(0, -50, 0)

        # Check video card capabilities.
        if not base.win.getGsg().getSupportsBasicShaders():
            addTitle(
                "Glow Filter: Video driver reports that Cg shaders are not supported.")
            return

        # Post the instructions
        self.title = addTitle("Panda3D: Tutorial - Glow Filter")
        self.inst1 = addInstructions(0.06, "ESC: Quit")
        self.inst2 = addInstructions(0.12, "Space: Toggle Glow Filter On/Off")
        self.inst3 = addInstructions(0.18, "Enter: Toggle Running/Spinning")
        self.inst4 = addInstructions(0.24, "V: View the render-to-texture results")

        # Create the shader that will determime what parts of the scene will
        # glow
        glowShader = loader.loadShader("shaders/glowShader.sha")

        # load our model
        self.tron = Actor()
        self.tron.loadModel("models/tron")
        self.tron.loadAnims({"running": "models/tron_anim"})
        self.tron.reparentTo(render)
        self.interval = self.tron.hprInterval(60, LPoint3(360, 0, 0))
        self.interval.loop()
        self.isRunning = False

        # put some lighting on the tron model
        dlight = DirectionalLight('dlight')
        alight = AmbientLight('alight')
        dlnp = render.attachNewNode(dlight)
        alnp = render.attachNewNode(alight)
        dlight.setColor(LVector4(1.0, 0.7, 0.2, 1))
        alight.setColor(LVector4(0.2, 0.2, 0.2, 1))
        dlnp.setHpr(0, -60, 0)
        render.setLight(dlnp)
        render.setLight(alnp)

        # create the glow buffer. This buffer renders like a normal scene,
        # except that only the glowing materials should show up nonblack.
        glowBuffer = base.win.makeTextureBuffer("Glow scene", 512, 512)
        glowBuffer.setSort(-3)
        glowBuffer.setClearColor(LVector4(0, 0, 0, 1))

        # We have to attach a camera to the glow buffer. The glow camera
        # must have the same frustum as the main camera. As long as the aspect
        # ratios match, the rest will take care of itself.
        glowCamera = base.makeCamera(
            glowBuffer, lens=base.cam.node().getLens())

        # Tell the glow camera to use the glow shader
        tempnode = NodePath(PandaNode("temp node"))
        tempnode.setShader(glowShader)
        glowCamera.node().setInitialState(tempnode.getState())
        glowCamera.node().setCameraMask(BitMask32.bit(0))

        # set up the pipeline: from glow scene to blur x to blur y to main
        # window.
        blurXBuffer = makeFilterBuffer(
            glowBuffer,  "Blur X", -2, "shaders/XBlurShader.sha")
        blurYBuffer = makeFilterBuffer(
            blurXBuffer, "Blur Y", -1, "shaders/YBlurShader.sha")
        self.finalcard = blurYBuffer.getTextureCard()
        self.finalcard.reparentTo(render2d)

        # This attribute is used to add the results of the post-processing
        # effects to the existing framebuffer image, rather than replace it.
        # This is mainly useful for glow effects like ours.
        self.finalcard.setAttrib(ColorBlendAttrib.make(ColorBlendAttrib.MAdd))

        # Panda contains a built-in viewer that lets you view the results of
        # your render-to-texture operations.  This code configures the viewer.
        self.accept("v", base.bufferViewer.toggleEnable)
        self.accept("V", base.bufferViewer.toggleEnable)
        base.bufferViewer.setPosition("llcorner")
        base.bufferViewer.setLayout("hline")
        base.bufferViewer.setCardSize(0.652, 0)

        # event handling
        self.accept("space", self.toggleGlow)
        self.accept("enter", self.toggleDisplay)
        self.accept("escape", sys.exit, [0])

        self.glowOn = True

    def toggleGlow(self):
        if self.glowOn:
            self.finalcard.reparentTo(hidden)
        else:
            self.finalcard.reparentTo(render2d)
        self.glowOn = not(self.glowOn)

    def toggleDisplay(self):
        self.isRunning = not(self.isRunning)
        if not(self.isRunning):
            camera.setPos(0, -50, 0)
            self.tron.stop("running")
            self.tron.pose("running", 0)
            self.interval.loop()
        else:
            camera.setPos(0, -170, 3)
            self.interval.finish()
            self.tron.setHpr(0, 0, 0)
            self.tron.loop("running")

demo = GlowDemo()
demo.run()

I added two lines.

self.scene.hide(BitMask32.bit(0))
glowCamera.node().setCameraMask(BitMask32.bit(0))

Now need to use the stencil buffer, I do not know how to do it yet. And given the transparency of the bamboo, most likely will need a shader …