# C++ source file - (C) 2003 Robert Osfield, released under the OSGPL. # # Simple example of use of Producer.RenderSurface + KeyboardMouseCallback + SceneView # example that provides the user with control over view position with basic picking. import sys from PyOSG import * class MyKeyboardMouseCallback(Producer.KeyboardMouseCallback): def __init__(self, sceneView): Producer.KeyboardMouseCallback.__init__(self) self._mx=0.0 self._my=0.0 self._mbutton=0 self._done=False self._trackBall=Producer.Trackball() self._sceneView=sceneView self.resetTrackball() self._mouseMovingOnPreviousRelease = False def specialKeyPress(self,key): if key==Producer.KeyChar_Escape: self.shutdown() def shutdown(self): self._done = True def keyPress(self, key): if key==' ': self.resetTrackball() def mouseMotion(self, mx, my ): self._mx = mx self._my = my def buttonPress(self, mx, my, mbutton): self._mx = mx self._my = my self._mbutton |= (1<<(mbutton-1)) self._mx_buttonPress = self._mx self._my_buttonPress = self._my def buttonRelease(self, mx, my, mbutton ): self._mx = mx self._my = my self._mbutton &= ~(1<<(mbutton-1)) if self._mx==_mx_buttonPress and self._my_buttonPress==_my: if not self._mouseMovingOnPreviousRelease: # button press and release without moving so assume this means # the users wants to pick. self.pick(self._mx,self._my) self._mouseMovingOnPreviousRelease = False else: self._mouseMovingOnPreviousRelease = True def done(self): return self._done def mx(self): return self._mx def my(self): return self._my def mbutton(self): return self._mbutton def resetTrackball(self): scene = self._sceneView.getSceneData() if scene: bs = scene.getBound() self._trackBall.reset() self._trackBall.setOrientation( Producer.Trackball.Z_UP ) self._trackBall.setDistance(bs.radius()*2.0) self._trackBall.translate(-bs.center().x(),-bs.center().y(),-bs.center().z()) def getViewMatrix(self): self._trackBall.input( self.mx(), self.my(), self.mbutton() ) return osg.Matrixd(self._trackBall.getMatrix()) def pick(self, x, y): scene = self._sceneView.getSceneData() if scene: print "Picking %d\t%d" % (x, y) (origX, origY, width, height) = self._sceneView.getViewport() # convert Produce's non dimensional x,y coords back into pixel coords. winX = ((x+1.0)*0.5*float(width)) winY = ((y+1.0)*0.5*float(height)) nearPoint = osg.Vec3() farPoint = osg.Vec3() self._sceneView.projectWindowXYIntoObject(winX,winY,nearPoint,farPoint) print "nearPoint ",nearPoint," farPoint ", farPoint # make a line segment lineSegment = osg.LineSegment(nearPoint,farPoint) # create the IntersectVisitor to do the line intersection traversals. intersector = osgUtil.IntersectVisitor() intersector.addLineSegment(lineSegment) scene.accept(intersector) hits=intersector.getHitList(lineSegment) if not hits.empty(): print "Got hits" # just take the first hit - nearest the eye point. hit = hits.front() nodePath = hit._nodePath node = (nodePath.size()>=1) and nodePath[nodePath.size()-1] or 0 parent = (nodePath.size()>=2) and (nodePath[nodePath.size()-2]).asGroup() or 0 if parent and node: print "Hits ", node.className() print " parent ", parent.className() parentAsScribe = osgFX.asScribe(parent) if not parentAsScribe: # node not already picked, so highlight it with an osgFX.Scribe scribe = osgFX.Scribe() scribe.addChild(node) parent.replaceChild(node,scribe) else: # node already picked so we want to remove scribe to unpick it. parentList = parentAsScribe.getParents() for itr in parentList: itr.replaceChild(parentAsScribe,node) def main(argv ): if len(argv)<2: print argv[0],": requires filename argument." return 1 # load the scene. loadedModel = osgDB.readNodeFile(argv[1]) if not loadedModel: print argv[0], ": No data loaded." return 1 # create the window to draw to. renderSurface = Producer.RenderSurface() renderSurface.setWindowName("osgkeyboardmouse") renderSurface.setWindowRectangle(100,100,800,600) renderSurface.useBorder(True) renderSurface.realize() # create the view of the scene. sceneView = osgUtil.SceneView() sceneView.setDefaults() sceneView.setSceneData(loadedModel) # set up a KeyboardMouse to manage the events comming in from the RenderSurface kbm = Producer.KeyboardMouse(renderSurface) # create a KeyboardMouseCallback to handle the mouse events within this applications kbmcb = MyKeyboardMouseCallback(sceneView) # record the timer tick at the start of rendering. start_tick = osg.Timer.instance().tick() frameNum = 0 # main loop (note, window toolkits which take control over the main loop will require a window redraw callback containing the code below.) while( renderSurface.isRealized() and not kbmcb.done()): # set up the frame stamp for current frame to record the current time and frame number so that animtion code can advance correctly frameStamp = osg.FrameStamp() frameStamp.setReferenceTime(osg.Timer.instance().delta_s(start_tick,osg.Timer.instance().tick())) frameStamp.setFrameNumber(frameNum) frameNum += 1 # pass frame stamp to the SceneView so that the update, cull and draw traversals all use the same FrameStamp sceneView.setFrameStamp(frameStamp) # pass any keyboard mouse events onto the local keyboard mouse callback. kbm.update( kbmcb ) # set the view sceneView.setViewMatrix(kbmcb.getViewMatrix()) # update the viewport dimensions, incase the window has been resized. sceneView.setViewport(0,0,renderSurface.getWindowWidth(),renderSurface.getWindowHeight()) # do the update traversal the scene graph - such as updating animations sceneView.update() # do the cull traversal, collect all objects in the view frustum into a sorted set of rendering bins sceneView.cull() # draw the rendering bins. sceneView.draw() # Swap Buffers renderSurface.swapBuffers() return 0 if __name__ == "__main__": main(sys.argv)