| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377 |
- from PandaObject import *
- CAM_MOVE_DURATION = 1.0
- class DirectCameraControl(PandaObject):
- def __init__(self, direct):
- # Create the grid
- self.direct = direct
- self.chan = direct.chanCenter
- self.camera = self.chan.camera
- self.orthoViewRoll = 0.0
- self.lastView = 0
- self.coa = Point3(0)
- self.coaMarker = loader.loadModel('misc/sphere')
- self.coaMarker.setColor(1,0,0)
- self.coaMarkerPos = Point3(0)
- self.relNodePath = render.attachNewNode(NamedNode('targetNode'))
- self.zeroBaseVec = VBase3(0)
- self.zeroVector = Vec3(0)
- self.centerVec = Vec3(0, 1, 0)
- self.zeroPoint = Point3(0)
- def mouseFlyStart(self, chan):
- # Record starting mouse positions
- self.initMouseX = chan.mouseX
- self.initMouseY = chan.mouseY
- # Where are we in the channel?
- if ((abs(self.initMouseX) < 0.9) & (abs(self.initMouseY) < 0.9)):
- # MOUSE IS IN CENTRAL REGION
- if (self.direct.fShift):
- # If shift key is pressed, just perform horiz and vert pan:
- self.spawnHPPan()
- else:
- # Otherwise, check for a hit point based on current mouse position
- # And then spawn task to determine mouse mode
- numEntries = self.direct.iRay.pick(render,chan.mouseX,chan.mouseY)
- coa = Point3(0)
- if(numEntries):
- # Start off with first point
- minPt = 0
- # Find hit point in camera's space
- hitPt = self.direct.iRay.camToHitPt(minPt)
- coa.set(hitPt[0],hitPt[1],hitPt[2])
- coaDist = Vec3(coa - self.zeroPoint).length()
- # Check other intersection points, sorting them
- # TBD: Use TBS C++ function to do this
- if numEntries > 1:
- for i in range(1,numEntries):
- hitPt = self.direct.iRay.camToHitPt(i)
- dist = Vec3(hitPt - self.zeroPoint).length()
- if (dist < coaDist):
- coaDist = dist
- coa.set(hitPt[0],hitPt[1],hitPt[2])
- minPt = i
- # Handle case of bad coa point (too close or too far)
- if ((coaDist < (1.1 * self.chan.near)) |
- (coaDist > self.chan.far)):
- # Put it out in front of the camera
- coa.set(0,100,0)
- coaDist = 100
- else:
- # If no intersection point:
- # Put coa out in front of the camera
- coa.set(0,100,0)
- coaDist = 100
- # Update coa and marker
- self.updateCoa(coa, coaDist)
- # Now spawn task to determine mouse fly mode
- self.determineMouseFlyMode()
- # END MOUSE IN CENTRAL REGION
- else:
- # Mouse is in outer frame, spawn mouseRotateTask
- self.spawnMouseRotateTask()
- def mouseFlyStop(self):
- taskMgr.removeTasksNamed('determineMouseFlyMode')
- taskMgr.removeTasksNamed('manipulateCamera')
- def determineMouseFlyMode(self):
- # Otherwise, determine mouse fly mode
- t = Task.Task(self.determineMouseFlyModeTask)
- taskMgr.spawnTaskNamed(t, 'determineMouseFlyMode')
- def determineMouseFlyModeTask(self, state):
- deltaX = self.chan.mouseX - self.initMouseX
- deltaY = self.chan.mouseY - self.initMouseY
- if ((abs(deltaX) < 0.1) & (abs(deltaY) < 0.1)):
- return Task.cont
- else:
- if (abs(deltaY) > 0.1):
- self.spawnHPanYZoom()
- else:
- self.spawnXZTranslate()
- return Task.done
- def updateCoa(self, cam2point, coaDist = None):
- self.coa.set(cam2point[0], cam2point[1], cam2point[2])
- if coaDist:
- self.coaDist = coaDist
- else:
- self.coaDist = Vec3(self.coa - self.zeroPoint).length()
- # Place the marker in render space
- self.coaMarker.setPos(self.camera,self.coa)
- # Record marker pos in render space
- self.coaMarkerPos = self.coaMarker.getPos()
- def homeCam(self, chan):
- chan.camera.setMat(Mat4.identMat())
- def uprightCam(self, chan):
- taskMgr.removeTasksNamed('manipulateCamera')
- currH = chan.camera.getH()
- chan.camera.lerpHpr(currH, 0, 0,
- CAM_MOVE_DURATION,
- other = render,
- blendType = 'easeInOut',
- task = 'manipulateCamera')
- def centerCam(self, chan):
- # Chan is a display region context
- self.centerCamIn(chan, 1.0)
-
- def centerCamNow(self, chan):
- self.centerCamIn(chan, 0.)
- def centerCamIn(self, chan,t):
- # Chan is a display region context
- taskMgr.removeTasksNamed('manipulateCamera')
- markerToCam = self.coaMarker.getPos( chan.camera )
- dist = Vec3(markerToCam - self.zeroPoint).length()
- scaledCenterVec = self.centerVec * dist
- delta = markerToCam - scaledCenterVec
- self.relNodePath.setPosHpr(chan.camera, Point3(0), Point3(0))
- chan.camera.lerpPos(Point3(delta),
- CAM_MOVE_DURATION,
- other = self.relNodePath,
- blendType = 'easeInOut',
- task = 'manipulateCamera')
- def zoomCam(self, chan, zoomFactor, t):
- taskMgr.removeTasksNamed('manipulateCamera')
- # Find a point zoom factor times the current separation
- # of the widget and cam
- zoomPtToCam = self.coaMarker.getPos(chan.camera) * zoomFactor
- # Put a target nodePath there
- self.relNodePath.setPos(chan.camera, zoomPtToCam)
- # Move to that point
- chan.camera.lerpPos(self.zeroPoint,
- CAM_MOVE_DURATION,
- other = self.relNodePath,
- blendType = 'easeInOut',
- task = 'manipulateCamera')
-
- def SpawnMoveToView(self, chan, view):
- # Kill any existing tasks
- taskMgr.removeTasksNamed('manipulateCamera')
- # Calc hprOffset
- hprOffset = VBase3()
- if view == 8:
- # Try the next roll angle
- self.orthoViewRoll = (self.orthoViewRoll + 90.0) % 360.0
- # but use the last view
- view = self.lastView
-
- if view == 1:
- hprOffset.set(180., 0., 0.)
- elif view == 2:
- hprOffset.set(0., 0., 0.)
- elif view == 3:
- hprOffset.set(90., 0., 0.)
- elif view == 4:
- hprOffset.set(-90., 0., 0.)
- elif view == 5:
- hprOffset.set(0., -90., 0.)
- elif view == 6:
- hprOffset.set(0., 90., 0.)
- elif view == 7:
- hprOffset.set(135., -35.264, 0.)
- # Position target
- self.relNodePath.setPosHpr(self.coaMarker, self.zeroBaseVec,
- hprOffset)
- # Scale center vec by current distance to target
- offsetDistance = Vec3(chan.camera.getPos(self.relNodePath) -
- self.zeroPoint).length()
- scaledCenterVec = self.centerVec * (-1.0 * offsetDistance)
- # Now put the relNodePath at that point
- self.relNodePath.setPosHpr(self.relNodePath,
- scaledCenterVec,
- self.zeroBaseVec)
- # Store this view for next time
- # Reset orthoViewRoll if you change views
- if view != self.lastView:
- self.orthoViewRoll = 0.0
-
- self.lastView = view
- chan.camera.lerpPosHpr(self.zeroPoint,
- VBase3(0,0,self.orthoViewRoll),
- CAM_MOVE_DURATION,
- other = self.relNodePath,
- blendType = 'easeInOut',
- task = 'manipulateCamera')
-
- def swingCamAboutWidget(self, chan, degrees, t):
- # Remove existing camera manipulation task
- taskMgr.removeTasksNamed('manipulateCamera')
-
- # Coincident with widget
- self.relNodePath.setPos(self.coaMarker, self.zeroPoint)
- # But aligned with render space
- self.relNodePath.setHpr(self.zeroPoint)
- parent = self.camera.getParent()
- self.camera.wrtReparentTo(self.relNodePath)
- manipTask = self.relNodePath.lerpHpr(VBase3(degrees,0,0),
- CAM_MOVE_DURATION,
- blendType = 'easeInOut',
- task = 'manipulateCamera')
- # Upon death, reparent Cam to parent
- manipTask.parent = parent
- manipTask.uponDeath = self.reparentCam
- def reparentCam(self, state):
- self.camera.wrtReparentTo(state.parent)
- def spawnHPanYZoom(self):
- # Kill any existing tasks
- taskMgr.removeTasksNamed('manipulateCamera')
- # Negate vec to give it the correct sense for mouse motion below
- targetVector = self.coa * -1
- t = Task.Task(self.HPanYZoomTask)
- t.targetVector = targetVector
- taskMgr.spawnTaskNamed(t, 'manipulateCamera')
- def HPanYZoomTask(self,state):
- targetVector = state.targetVector
- distToMove = targetVector * self.chan.mouseDeltaY
- self.camera.setPosHpr(self.camera,
- distToMove[0],
- distToMove[1],
- distToMove[2],
- (0.5 * self.chan.mouseDeltaX *
- self.chan.fovH),
- 0.0, 0.0)
- return Task.cont
- def spawnXZTranslateOrHPPan(self):
- # Kill any existing tasks
- taskMgr.removeTasksNamed('manipulateCamera')
- t = Task.Task(self.XZTranslateOrHPPanTask)
- t.scaleFactor = (self.coaDist / self.chan.near)
- taskMgr.spawnTaskNamed(t, 'manipulateCamera')
- def XZTranslateOrHPPanTask(self, state):
- if self.direct.fShift:
- self.camera.setHpr(self.camera,
- (0.5 * self.chan.mouseDeltaX *
- self.chan.fovH),
- (-0.5 * self.chan.mouseDeltaY *
- self.chan.fovV),
- 0.0)
- else:
- self.camera.setPos(self.camera,
- (-0.5 * self.chan.mouseDeltaX *
- self.chan.nearWidth *
- state.scaleFactor),
- 0.0,
- (-0.5 * self.chan.mouseDeltaY *
- self.chan.nearHeight *
- state.scaleFactor))
- return Task.cont
- def spawnXZTranslate(self):
- # Kill any existing tasks
- taskMgr.removeTasksNamed('manipulateCamera')
- t = Task.Task(self.XZTranslateTask)
- t.scaleFactor = (self.coaDist / self.chan.near)
- taskMgr.spawnTaskNamed(t, 'manipulateCamera')
- def XZTranslateTask(self,state):
- self.camera.setPos(self.camera,
- (-0.5 * self.chan.mouseDeltaX *
- self.chan.nearWidth *
- state.scaleFactor),
- 0.0,
- (-0.5 * self.chan.mouseDeltaY *
- self.chan.nearHeight *
- state.scaleFactor))
- return Task.cont
- def spawnMouseRotateTask(self):
- # Kill any existing tasks
- taskMgr.removeTasksNamed('manipulateCamera')
- # Set at markers position in render coordinates
- self.relNodePath.setPos(self.coaMarkerPos)
- self.relNodePath.setHpr(self.camera, self.zeroPoint)
- t = Task.Task(self.mouseRotateTask)
- t.wrtMat = self.camera.getMat( self.relNodePath )
- taskMgr.spawnTaskNamed(t, 'manipulateCamera')
- def mouseRotateTask(self, state):
- wrtMat = state.wrtMat
- self.relNodePath.setHpr(self.relNodePath,
- (-0.5 * self.chan.mouseDeltaX * 180.0),
- (0.5 * self.chan.mouseDeltaY * 180.0),
- 0.0)
- self.camera.setMat(self.relNodePath, wrtMat)
- return Task.cont
- def spawnHPPan(self):
- # Kill any existing tasks
- taskMgr.removeTasksNamed('manipulateCamera')
- t = Task.Task(self.HPPanTask)
- taskMgr.spawnTaskNamed(t, 'manipulateCamera')
- def HPPanTask(self, state):
- self.camera.setHpr(self.camera,
- (0.5 * self.chan.mouseDeltaX *
- self.chan.fovH),
- (-0.5 * self.chan.mouseDeltaY *
- self.chan.fovV),
- 0.0)
- return Task.cont
- def enableMouseFly(self):
- self.enableMouseInteraction()
- self.enableHotKeys()
- self.coaMarker.reparentTo(render)
- def enableMouseInteraction(self):
- # disable C++ fly interface
- base.disableMouse()
- # Accept middle mouse events
- self.accept('handleMouse2', self.mouseFlyStart, [self.chan])
- self.accept('handleMouse2Up', self.mouseFlyStop)
- def enableHotKeys(self):
- t = CAM_MOVE_DURATION
- self.accept('u', self.uprightCam, [self.chan])
- self.accept('c', self.centerCamIn, [self.chan, 0.5])
- self.accept('h', self.homeCam, [self.chan])
- for i in range(1,9):
- self.accept(`i`, self.SpawnMoveToView, [self.chan, i])
- self.accept('9', self.swingCamAboutWidget, [self.chan, -90.0, t])
- self.accept('0', self.swingCamAboutWidget, [self.chan, 90.0, t])
- self.accept('`', self.removeManipulateCameraTask)
- self.accept('=', self.zoomCam, [self.chan, 0.5, t])
- self.accept('+', self.zoomCam, [self.chan, 0.5, t])
- self.accept('-', self.zoomCam, [self.chan, -2.0, t])
- self.accept('_', self.zoomCam, [self.chan, -2.0, t])
- def disableMouseFly(self):
- # Hide the marker
- self.coaMarker.reparentTo(hidden)
- # Ignore middle mouse events
- self.ignore('handleMouse2')
- self.ignore('handleMouse2Up')
- self.ignore('u')
- self.ignore('c')
- self.ignore('h')
- for i in range(0,10):
- self.ignore(`i`)
- self.ignore('=')
- self.ignore('+')
- self.ignore('-')
- self.ignore('_')
- self.ignore('`')
- def removeManipulateCameraTask(self):
- taskMgr.removeTasksNamed('manipulateCamera')
|