Excluding object from motion trails...

Hello,

So, using some visualizer code I found on the forum, and also the motion trails tutorial, I’ve created a pretty cool little visualizer where the data gathered from the visualizer code affects the shape of a cube, which then has the whirlpool effect applied to it from the sample programs.

However, I’m having some issues with the motion trail code. The game we’re working on involves shooting 3d targets that are created in sync with the visualizer, but I’m at a loss as to how I can stop those shapes from being eaten up and blurred/stretched by the motion trails code. Is there a way I can create another 3d layer on top of the window to put those shapes on?

Or a way I can make the motion trails, instead of affecting the entire scene graph, only affect a portion of it? If this were the case, I could put the motion trail stuff under a dummy node, and just put anything I want to have this motion trail effect under that node.

It looks like I would have to make some changes to this piece of code:

def takeSnapShot(self, task):
        if (task.time > self.nextclick):
            self.nextclick += 1.0 / self.clickrate
            if (self.nextclick < task.time):
                self.nextclick = task.time
            base.win.triggerCopy()
        return Task.cont

But I’m not sure at all what I’d have to do. Any suggestions would be greatly appreciated.

Alright, I got this to work, so I figure I would share it. As far as I can tell, this technique will allow the effects in the motion trail tutorial to affect some parts of a scene, but not others. The practical application I’m using it for is to have a visualizer in the background of my game created with motion trails, but that does not effect the game itself happening in the foreground.

General process:

  1. Create an offscreen buffer with its own scene graph, and attach any models/objects that you want the motion trails to affect.
  2. Using the motion trail code, I cause the required effect on this buffer.
  3. Copy a screen capture of this off-screen buffer into a background texture of the main window every frame.

I don’t really take any credit for this code, besides the addition for an off-screen buffer, but I thought someone else might possibly find it useful.

def addWhirlpoolEffect(self):
        #---------------------------------------------------------------
        # Here we create an infinite feedback loop, which causes our
        # whirlpool visualizer effect.  This is rendered off-screen in a
        # hidden window called vBuffer
        #---------------------------------------------------------------
    
        #create an off-screen buffer, and stick our visualizer cube on that buffer
        self.vBuffer = base.win.makeTextureBuffer("Visualizer_Buffer", 512, 512);
        self.vTexture = self.vBuffer.getTexture();
        self.vBuffer.setSort(-10);
        self.vCamera = base.makeCamera(self.vBuffer);
        self.vScene = NodePath("Visualizer_Scene_Graph");
        self.vCamera.node().setScene(self.vScene);
        
        #create an empty texture to copy the off-screen buffer to
        #self.tex = Texture();
        #self.tex.setMinfilter(Texture.FTLinear);
        #self.vBuffer.addRenderTexture(self.tex, GraphicsOutput.RTMTriggeredCopyTexture);
        
        # Create a 2d camera that points at the off-screen buffer, and have
        # it render behind the cube model (sorted at 0)
        self.backcam = base.makeCamera2d(self.vBuffer, sort=-10)
        self.background = NodePath("background")
        self.backcam.reparentTo(self.background)
        self.background.setDepthTest(0)
        self.background.setDepthWrite(0)
        self.backcam.node().getDisplayRegion(0).setClearDepthActive(0)

        #create two texture cards from the off-screen buffer, one which holds 
        #what our newly created 2d camera sees (and causes the effect), and one
        #that renders above the scene, on the gui, in case we want to hide the
        #effect
        self.bcard = self.vBuffer.getTextureCard()
        self.bcard.reparentTo(self.background)
        self.bcard.setTransparency(1)
        self.fcard = self.vBuffer.getTextureCard()
        self.fcard.reparentTo(render2d)
        self.fcard.setTransparency(1)

        #tell the texture card to spin, causing the whirlpool
        self.doEffectWhirlpool()
        
        #add the task that initiates the screenshots.
        taskMgr.add(self.takeSnapShot, "takeSnapShot")
        
        #openGl invert the texture; fix if so
        if (base.win.getGsg().getCopyTextureInverted()):
            self.bcard.setScale(1,1,-1)
            self.fcard.setScale(1,1,-1)
            
        #copy the texture containing the effect into our main window
        self.resultCam = base.makeCamera2d(base.win, sort=-10)
        self.resultBack = NodePath("VisualizerResult")
        self.resultCam.reparentTo(self.resultBack);
        self.resultBack.setDepthTest(0)
        self.resultBack.setDepthWrite(0)
        self.resultCam.node().getDisplayRegion(0).setClearDepthActive(0)
        
        self.resultCard = self.vBuffer.getTextureCard()
        self.resultCard.reparentTo(self.resultBack)
        self.resultCard.setTransparency(1)
            
    #the visualizer takes a snapshot of the screen and distorts it
    #to create the blur effect
    def takeSnapShot(self, task):
        if (task.time > self.nextclick):
            self.nextclick += 1.0 / self.clickrate
            if (self.nextclick < task.time):
                self.nextclick = task.time
            self.vBuffer.triggerCopy()
        return Task.cont
            
    #set properties of cards to make a whirlpool effect
    def doEffectWhirlpool(self):
        base.setBackgroundColor(0,0,0,1)
        self.bcard.show()
        self.fcard.hide()
        self.bcard.setColor(1,1,1,1)
        self.bcard.setScale(1.03)
        self.bcard.setPos(0,0,0)
        self.bcard.setR(1)
        self.clickrate = 10000
        self.nextclick = 0

Alright, I’ve got a very strange bug; the whirlpool effect seems to only occur when I move the window after the program starts…any ideas as to why that might be?

I have the hidden buffer rendering in the corner, and the whirlpool effect does not appear until I move the main window around a bit. Is there any function that Panda calls when the window is moved or routine it does that I could call programatically to make this work? I’m on a rather tight timeline, and any help would be greatly appreciated.

afaik moving the window can cause a window-event.

use this to intercept the event:

from direct.showbase import DirectObject
class myEventHandler( DirectObject.DirectObject ):
  def __init__( self ):
    self.accept( 'window-event', self.windowEvent)
  
  def windowEvent( self, window ):
    """
    This is a special callback.
    It is called when the panda window is modified.
    (window is usually base.win)
    """
    if window is not None: # window is none if panda3d is not started
      wp = window.getProperties()
      width = wp.getXSize() / float(wp.getYSize())
      height = wp.getYSize() / float(wp.getXSize())

you might also create the event youself (i didnt test this):

messenger.send('window-event', [base.win])

Thanks for the advice. After some more fiddling, I was able to get this working. It appears that the off-screen buffer was not copying to texture parts of the buffer that were not occupied by some sort of geometry (and for whatever reason, moving the window remedied this).

The solution that ended up working was to create a model on the off-screen buffer that was larger than the entire buffer, and then quickly dispose/scale down this model. This seems to cause the entire buffer to copy into the main window.

Or something like that. Anyway, it works now. :slight_smile: