This is a module for individual camera control. The subject is a visualization, which is a diagram on the plane Y = 0, so the cameras always point down the Y axis (or up it). The arrow keys move the camera parallel to the plane. The mouse left-button selects a region for zooming in. The mouse right-button grabs & scrolls or drags. The wheel zooms in or out by a proportion. Multiple cameras operate individually; the keys control the camera of whatever view the mouse is currently over. The View and ViewGroup classes should be de-coupled from other dependencies by now.
if __name__== '__main__':
import direct.directbase.DirectStart
from direct.showbase.DirectObject import DirectObject
from panda3d.core import *
import random as ran
class ViewGroup(DirectObject):
def __init__(self):
self.accept("arrow_up", self.route, ['scroll3'] )
self.accept("arrow_down", self.route, ['scroll4'] )
self.accept("arrow_left", self.route, ['scroll1'] )
self.accept("arrow_right", self.route, ['scroll2'] )
self.accept("arrow_up-repeat", self.route, ['scroll3'] )
self.accept("arrow_down-repeat", self.route, ['scroll4'] )
self.accept("arrow_left-repeat", self.route, ['scroll1'] )
self.accept("arrow_right-repeat", self.route, ['scroll2'] )
self.accept("page_up", self.route, ['zoom1'] )
self.accept("page_down", self.route, ['zoom2'] )
self.accept("page_up-repeat", self.route, ['zoom1'] )
self.accept("page_down-repeat", self.route, ['zoom2'] )
self.accept("wheel_up", self.route, ['zoom1'] )
self.accept("wheel_down", self.route, ['zoom2'] )
self.accept("mouse1", self.route, ['mouse1','mouse1','down'] )
self.accept("mouse1-up", self.route, ['mouse1up','mouse1','up'] )
self.accept("mouse3", self.route, ['mouse3','mouse3','down'] )
self.accept("mouse3-up", self.route, ['mouse3up','mouse3','up'] )
self.accept('window-event', self.windowEvent )
self.prevreg= { }
self.views= [ ]
def addViews( self, *views ):
for view in views:
self.views.append( view )
def windowEvent( self, win ):
for v in self.views:
v.rezoom( relzoom= 1 )
def route( self, methName, *args ):
if not base.mouseWatcherNode.hasMouse( ):
return
if args and args[1]== 'up':
reg= self.prevreg.pop( args[0], None )
if reg is None:
return
args= args[2:]
else:
x=base.mouseWatcherNode.getMouseX()
y=base.mouseWatcherNode.getMouseY()
reg= base.mouseWatcherNode.getOverRegion( x, y )
if reg is None:
return
if args and args[1]== 'down':
self.prevreg[ args[0] ]= reg
args= args[2:]
if not reg.getName( ).startswith( 'region-' ):
return
view= int( reg.getName( )[ 7 ] )
view= self.views[ view ]
getattr( view, methName )( *args )
class View( ):
mouseselR= LineSegs( 'mousesel' ) # where I really want to put this...
mouseselR.setColor( 0, 0, 0, 1 )
mouseselY= 0
mouseselR.moveTo( 0, mouseselY, 0 )
mouseselR.drawTo( 1, mouseselY, 0 )
mouseselR.drawTo( 1, mouseselY, 1 )
mouseselR.drawTo( 0, mouseselY, 1 )
mouseselR.drawTo( 0, mouseselY, 1 )
mouseselN= mouseselR.create( )
mousesel= NodePath( mouseselN )
mousesel.reparentTo( render2d )
mousesel.hide( )
def __init__( self, i, rect, zoom0, pos0 ):
self.lens= OrthographicLens( )
self.cam= Camera( 'cam', self.lens )
self.dispreg= base.win.makeDisplayRegion( *rect )
self.dispreg.setClearColorActive( True )
r, g= ran.uniform( .8, 1 ), ran.uniform( .8, 1 )
b= 2.5- r- g
self.dispreg.setClearColor( VBase4( r, g, b, 1 ) )
self.camP= NodePath( self.cam )
self.dispreg.setCamera( self.camP )
self.camP.reparentTo( render )
self.camP.setPos( *pos0 )
self.rezoom( zoom0 )
self.mousereg= MouseWatcherRegion( 'region-%i'%i, *[ x*2-1 for x in rect ] )
base.mouseWatcherNode.addRegion( self.mousereg )
self.mousewatN= MouseWatcher( 'mousewatcher-%i'%i )
self.mousewatN.setDisplayRegion( self.dispreg )
self.mousewat= NodePath( self.mousewatN )
self.mousewat.reparentTo( base.mouseWatcher.getParent( ) )
self.mouse1x1=self.mouse1x2=None
self.mouse3p= None
def reshape( self, rect ):
self.dispreg.setDimensions( *rect )
self.mousereg.setFrame( *[ x*2-1 for x in rect ] )
self.rezoom( relzoom= 1 )
def zoom1( self ):
self.rezoom( relzoom= 1/ .825 )
def zoom2( self ):
self.rezoom( relzoom= .825 )
def rezoom( self, zoom= None, relzoom= None ):
if zoom is not None:
self.zoom= zoom
else:
self.zoom= zoom= self.zoom* relzoom
x= self.dispreg.getPixelWidth( )/ float( zoom )
y= self.dispreg.getPixelHeight( )/ float( zoom )
self.lens.setFilmSize( x, y )
def scroll1( self ):
self.camP.setX( self.camP, -1 )
def scroll2( self ):
self.camP.setX( self.camP, 1 )
def scroll3( self ):
self.camP.setZ( self.camP, 1 )
def scroll4( self ):
self.camP.setZ( self.camP, -1 )
def screen_to_yplane( self, x, y ):
a, b, c= Point3( ), Point3( ), Point3( )
self.lens.extrude( Point2( x, y ), a, b )
a= NodePath( ).getRelativePoint( self.camP, a )
b= NodePath( ).getRelativePoint( self.camP, b )
p= Plane( Point3( 0,0,0 ), Point3( 1,0,0 ), Point3( 0,0,1 ) )
p.intersectsLine( c, a, b )
return c
def mouse1( self ):
if not self.mousewatN.hasMouse():
return
taskMgr.add( self.dragging1, 'dragging1')
self.mouse1x1, self.mouse1y1= self.mousewatN.getMouse( )
self.mouse1vx1, self.mouse1vy1= base.mouseWatcherNode.getMouse()
self.mousesel.show( )
def mouse1up( self ):
taskMgr.remove( 'dragging1' )
self.mousesel.hide( )
if self.mouse1x1 is None or self.mouse1x2 is None:
return
if self.mouse1x1==self.mouse1x2 or self.mouse1y1==self.mouse1y2:
return
p00= self.screen_to_yplane( self.mouse1x1, self.mouse1y1 )
p11= self.screen_to_yplane( self.mouse1x2, self.mouse1y2 )
x3, y3, z3= ( p00+ p11 )/ 2
self.camP.setX( x3 )
self.camP.setZ( z3 )
xz= self.dispreg.getPixelWidth( )/ abs( p00[ 0 ]- p11[ 0 ] )
zz= self.dispreg.getPixelHeight( )/ abs( p00[ 2 ]- p11[ 2 ] )
zoom= max( xz, zz )
self.rezoom( zoom )
self.mouse1x1= self.mouse1x2= None
def dragging1( self, task ):
if not self.mousewatN.hasMouse():
return task.cont
self.mouse1x2, self.mouse1y2= self.mousewatN.getMouse()
self.mouse1vx2, self.mouse1vy2= base.mouseWatcherNode.getMouse()
self.mouseselR.setVertex( 0, self.mouse1vx1, self.mouseselY, self.mouse1vy1 )
self.mouseselR.setVertex( 1, self.mouse1vx2, self.mouseselY, self.mouse1vy1 )
self.mouseselR.setVertex( 2, self.mouse1vx2, self.mouseselY, self.mouse1vy2 )
self.mouseselR.setVertex( 3, self.mouse1vx1, self.mouseselY, self.mouse1vy2 )
self.mouseselR.setVertex( 4, self.mouse1vx1, self.mouseselY, self.mouse1vy1 )
return task.cont
def mouse3( self ):
if not self.mousewatN.hasMouse():
return
taskMgr.add( self.dragging3, 'dragging3')
x1, y1= self.mousewatN.getMouse( )
self.mouse3p= self.screen_to_yplane( x1, y1 )
def mouse3up( self ):
taskMgr.remove( 'dragging3' )
self.mouse3p= None
def dragging3( self, task ):
if not self.mousewatN.hasMouse():
return task.cont
x2, y2= self.mousewatN.getMouse( )
p2= self.screen_to_yplane( x2, y2 )
x3, y3, z3= self.mouse3p- p2
self.camP.setX( self.camP, x3 )
self.camP.setZ( self.camP, z3 )
return task.cont
if __name__== '__main__':
''' demo for panda3d.org forums '''
cm= CardMaker( 'cardmaker' )
c= NodePath( cm.generate( ) )
c.reparentTo( render )
base.cam.removeNode( )
viewgroup= ViewGroup()
viewgroup.addViews( View( 0, ( 0, 1, 0, .5 ), 50, ( 5, -2, 3 ) ),
View( 1, ( .25, 1, .5, 1 ), 20, ( 5, -2, 3 ) ) )
def press1( ):
viewgroup.views[ 1 ].reshape( ( ran.uniform( .1, .7 ), 1, .5, 1 ) )
base.accept( '1', press1 )
run( )
If you can use this, great. If it can use something you have, great.