Hi, welcome to the community! No worries, this kind of question is not actually so rare, given that Panda3D tends to be a popular choice for esoteric rendering set-ups.
This would not be very difficult. There are two ways I can see to do this:
- Disable the clear settings on the window (you will need to provide your own card behind the scene to ensure you don’t see the results of previous render). In a task, apply a ColorWriteAttrib to only render one of the channels depending on which frame you are rendering:
n = task.frame % 3
if n == 0:
render.setAttrib(ColorWriteAttrib.make(ColorWriteAttrib.C_red))
elif n == 1:
render.setAttrib(ColorWriteAttrib.make(ColorWriteAttrib.C_green))
else:
render.setAttrib(ColorWriteAttrib.make(ColorWriteAttrib.C_blue))
With this method, you may need to make sure that all the textures and colours in your scene are monochrome to begin with, so that different channels don’t end up writing different values, or you can apply a shader to your scene that filters the colour values down to a monochrome value.
- Alternatively, you can render each frame into a different texture, and either, create a shader to composite the three together into a third texture, or set the formats of the three textures to
Texture.F_red
, F_green
and F_blue
and use texture blending to composite them on a fullscreen card.
I think the first approach is easier; I trivially modified the Hello World demo to implement that approach, here it is. (To fully work, you also need to make sure that the scene is monochrome to begin with, as pointed out earlier).
from panda3d.core import *
# Limit frame rate so you can see the effect better
loadPrcFileData("", """
clock-mode limited
clock-frame-rate 10
""")
from direct.showbase.ShowBase import ShowBase
from direct.task import Task
from direct.actor.Actor import Actor
from math import pi, sin, cos
class MyApp(ShowBase):
def __init__(self):
ShowBase.__init__(self)
# Disable window clear; it clears all channels.
self.win.setClearColor((0, 0, 0, 1))
self.win.setClearColorActive(False)
# Instead put a black card behind everything.
cm = CardMaker("card")
cm.setFrame(-100, 100, -100, 100)
card = self.render.attachNewNode(cm.generate())
card.setColor((0, 0, 0, 1))
card.setBin("background", 0)
card.setDepthTest(False)
card.setDepthWrite(False)
# 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)
# Add the spinCameraTask procedure to the task manager.
self.taskMgr.add(self.spinCameraTask, "SpinCameraTask")
# Add the task to set the color mask
self.taskMgr.add(self.setColorMaskTask, "ColorMaskTask")
# Load and transform the panda actor.
self.pandaActor = Actor("models/panda-model",
{"walk": "models/panda-walk4"})
self.pandaActor.setScale(0.005, 0.005, 0.005)
self.pandaActor.reparentTo(self.render)
# Loop its animation.
self.pandaActor.loop("walk")
def setColorMaskTask(self, task):
n = task.frame % 3
if n == 0:
render.setAttrib(ColorWriteAttrib.make(ColorWriteAttrib.C_red))
elif n == 1:
render.setAttrib(ColorWriteAttrib.make(ColorWriteAttrib.C_green))
else:
render.setAttrib(ColorWriteAttrib.make(ColorWriteAttrib.C_blue))
return task.cont
# Define a procedure to move the camera.
def spinCameraTask(self, task):
angleDegrees = task.time * 6.0
angleRadians = angleDegrees * (pi / 180.0)
self.camera.setPos(20 * sin(angleRadians), -20.0 * cos(angleRadians), 3)
self.camera.setHpr(angleDegrees, 0, 0)
return Task.cont
app = MyApp()
app.run()