Collision problems in off-screen rendering

Hi all,

I have set up an off-screen rendering of an environment and I project that environment using 12 cameras (associated with 12 off-screen buffers to get a panoramic effect) onto a round shape in the base window.

I have set up a movement task which allows me to move the cluster of 12 cameras around the environment.

I have then set up the pusher collision handler along with a traverser to create the ‘push’ effect against the walls of the environment as well as against geometrical objects. I have also changed the environment egg file adding the appropriate tags. The thing doing the collisions should be the camera cluster.

I have 3 problems:

I cannot seem to make a collision sphere around the camera cluster I have created and am forced to make a collision sphere around a ‘smiley’ and reparent the cluster to the smiley…

I have set

self.cTrav.showCollisions()

but I do not see any collisions even though they do happen. I cannot even see the collision spheres around the geometrical objects in the environment (even though if I load an object into the environment like a teapot I can see the sphere)…

Lastly, the push effect that I do get stutters and is not smooth whenever a collision happens.

Would anyone have any ideas what could be going wrong?

Below are snipets from the code in case it helps.

Thank you for any help!!
Pawel

This is how I make the 12 off-screen buffers with 12 cameras creating a panoramic view:

self.myscene = NodePath("My Scene")
self.environment=loader.loadModel("models/env2") 
self.environment.reparentTo(self.myscene)
self.lens2=PerspectiveLens()
self.lensfovx=30
self.lensfovy=70
self.mybuffer=[]
self.mycamera=[]
self.mytexture=[]

for i in range(0,12):
    self.mybuffer.append(base.win.makeTextureBuffer("My Buffer " + str(i), 1024, 1024))
    self.mytexture.append(self.mybuffer[i].getTexture())
    self.mybuffer[i].setSort(-100)
    self.mycamera.append(base.makeCamera(self.mybuffer[i],lens=self.lens2))
    self.mycamera[i].node().setScene(self.myscene)
    if i>0:
        self.mycamera[i].reparentTo(self.mycamera[0])
        self.mycamera[i].setHpr(i*self.lensfovx, 0, 0)
        self.mycamera[i].setPos(0,0,0)

I make a round shape using 12 slices and set the Texture of each slice from each of the 12 buffers:

self.screen=[]
for i in range(0,12):
   self.screen.append(loader.loadModel("models/slice12"))
    self.screen[i].reparentTo(self.render)
    self.screen[i].setScale(3, 3, 3)
    self.screen[i].setPos(0, 20, 0)
    self.screen[i].setHpr(-30*i, 0, 0)
    self.screen[i].setTexture(self.mytexture[i])

I load the smiley, set up a collision sphere around the smiley and reparent mycamera[0] (to which all other cameras are reparented to) to the smiley. The smiley is the reparented to back to myscene which is the node that the environment is reparented to - I have to do this because when I try to create a collision sphere around mycamera[0] it does not work…:

self.smiley = loader.loadModel("models/smiley")
self.smiley.reparentTo(self.myscene)
self.mycamera[0].reparentTo(self.smiley)
self.smiley.setPos(0,0,0)
self.smileyPath = self.smiley.attachNewNode(CollisionNode('cnode_smiley'))
self.smileyPath.node().addSolid(CollisionSphere(0,0,-1,2))
self.smileyPath.node().setIntoCollideMask(BitMask32.allOff())
self.smileyPath.node().setFromCollideMask(BitMask32.bit(0))

I set up a Pusher Collision Handler, and a traverser, and then set up a couple of tasks to initiate the traverser:

    self.pusher = CollisionHandlerPusher()
    self.cTrav = CollisionTraverser()
    self.pusher.addCollider(self.smileyPath, self.smiley)
    self.cTrav.addCollider(self.smileyPath, self.pusher)
    self.cTrav.showCollisions(self.myscene)

    self.start()
def start(self):
    taskMgr.add( self.pusherTask, 'pusherTask')
    taskMgr.add( self.moveTask, 'moveTask')
def pusherTask(self, task):
    self.cTrav.traverse(self.myscene)
    return task.cont
def moveTask(self, task): 
    dt = globalClock.getDt() 
    for key, action in MOVEFUNCTIONS.items(): 
        if keyPoller[ key ]: 
            self.smiley.setPos( self.smiley, action*dt)
    for key, action in ROTATEFUNCTIONS.items(): 
         if keyPoller[ key ]: 
            self.smiley.setHpr( self.smiley, action*dt )
    return task.cont

The movement task that is also initiated above first receives:

POLLKEYS = list(string.ascii_lowercase+string.digits) 
POLLKEYS.extend( 
  [ 'arrow_up', 'arrow_down', 'arrow_left', 'arrow_right' ] ) 
MOVEFUNCTIONS   = { 'arrow_up'   : Vec3(0,-10,0), 
                        'arrow_down' : Vec3(0, 10,0) } 
ROTATEFUNCTIONS = { 'arrow_left' : Vec3( 90,0,0), 
                        'arrow_right': Vec3(-90,0,0) }
class KeyPollerClass( DirectObject ):
    def __init__( self ): 
        self.data = dict() 
        for key in POLLKEYS: 
            self.accept( key, self.event, [key, True] ) 
            self.accept( key+"-up", self.event, [key, False] ) 
            self.data[ key ] = False
    def event( self, key, active ): 
        self.data[key] = active 
    def __getitem__( self, key ): 
        return self.data[key] 
    
keyPoller = KeyPollerClass()

[/code]

Well, I don’t understand what you mean when you say “it does not work” to put the sphere directly around the camera, since there’s nothing magic about a smiley node.

But as to the reason your collisions stutter, this is a common mistake that people run into when they have two tasks, one of which moves the camera, and the other one which computes collisions that adjust the camera. You want to be sure that the movement task runs first, followed by the collision task, followed by the rendering of the frame. If you simply call addTask(), the tasks are run in random order, and may not be the correct order, which will cause the collision fix-up to be one frame behind the rendering, which can cause the appearance of stuttering.

The way to fix the ordering is to use the sort value. Larger sort values are run later in the frame, so do:

taskMgr.add(self.moveTask, 'moveTask', sort = 10) 
taskMgr.add(self.pusherTask, 'pusherTask', sort = 20)

The point is that moveTask is set to a sort value lower than pusherTask, and both are lower than 50, which is the default sort value of igLoop (which is when the frame is rendered).

David

Hi David,

Thank you so much, that was indeed the problem!! It runs beautifully now, no stutter :slight_smile:

Sorry, I should explain a little better about the collision sphere around the camera. I build the collision sphere around the camera using the standard:

self.cameraPath = self.mycamera[0].attachNewNode(CollisionNode('cnode_camera'))
self.cameraPath.node().addSolid(CollisionSphere(0,0,0,2))
self.cameraPath.node().setIntoCollideMask(BitMask32.allOff())
self.cameraPath.node().setFromCollideMask(BitMask32.bit(0))

and self.mycamera[0] is the camera which the cluster of my 12 cameras is reparented to. I move this cluster in the offscreen-rendered environment via the movement task I described above, which only acts on mycamera[0].

Now I can render any objects such as a smiley into the offscreen environment, build a collision sphere around it, and move it around using the same movement task I have for the camera - and I can see it’s sphere and it collides with the geometrical objects fine (although as I mention below, the collision spheres around the geometrical objects do not show up).
However, when I try to build the sphere around the camera, the sphere is not built in the offscreen environment, but instead appears in the base window, which is the window I project the offscreen rendering onto a specific shape. I have attached a screen shot of what it looks like.
I make the cameras using:

base.makeCamera()

and I make the offscreen buffers using:

base.win.makeTextureBuffer()

Does that mean that the collision sphere appears in base window rather than my offscreen rendered environment because the calls are “base.”??

It is also a little strange I cannot see the collisions using

self.cTrav.showCollisions()

The spheres around the geometrical objects of my environment as well as the ‘red-box-point-of-collision’ should show up right? They don’t…

Reparenting the camera to the smiley and using the smiley’s collision sphere seems to work fine though…it’s just a little strange.

Cheers,
Pawel

It sounds like your camera is parented to the wrong node. Are your sure your camera is parented into the offscreen scene, and not in the main scene? If parenting something to the camera makes that something visible in the main scene, it follows that the camera itself is also in the main scene.

David

That was it, that makes a lot of sense…the camera wasn’t actually parented to anything! Instead I was using the setScene() call. But thank you again, works great now!!!

So would you have an idea as to why the collisions are not showing up when using .showCollisions()?

Cheers,
Pawel

The parameter to showCollisions() must be a node that is visible to the camera. The CollisionTraverser than attaches the temporary geometry to represent the collision results to the node you specify.

One guess is that perhaps you have used setScene() to a node that is something below render–this will mean that the camera doesn’t see render itself; it only sees the node that you specified or below. In this case, if you specify render as the parameter to showCollisions(), the geometry will not then be visible.

Or, perhaps there is some other similar conflict between the node that you’re actually seeing, and the one that you’re passing to showCollisions().

David