DirectCameraManipulation.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. from PandaObject import *
  2. from DirectGrid import DirectGrid
  3. class DirectCameraManipulation(PandaObject):
  4. def __init__():
  5. # Create the grid
  6. self.grid = DirectGrid(render)
  7. self.grid.hide()
  8. self.hitPt = Point3(0)
  9. self.iPoint = Point3(0)
  10. self.centerOfRotation = render.attachNewNode( NamedNode() )
  11. self.centerOfRotation.node().setName( 'centerOfRotation' )
  12. self.centerOfRotation.setPosHpr(Vec3(0), Vec3(0))
  13. self.orthoViewRoll = 0.0
  14. self.lastView = 0
  15. self.targetNodePath = render.attachNewNode(NamedNode('targetNode'))
  16. self.zeroBaseVec = VBase3(0)
  17. self.zeroVector = Vec3(0)
  18. self.centerVec = Vec3(0., 1., 0.)
  19. self.zeroPoint = Point3(0)
  20. def centerCam(chan):
  21. # Chan is a display region context
  22. self.centerCamIn(chan, 1.0)
  23. def centerCamNow(chan):
  24. self.centerCamIn(chan, 0.)
  25. def centerCamIn(chan,t):
  26. # Chan is a display region context
  27. taskMgr.removeTasksNamed('manipulateCamera')
  28. widgetToCam = direct.widget.getPos( chan.camera )
  29. dist = Vec3(widgetToCam - zeroPoint).length()
  30. scaledCenterVec = centerVec * dist.
  31. delta = widgetToCam - scaledCenterVec.
  32. relNodePath = render.attachNewNode(Node())
  33. relNodePath.setPosHpr(chan.camera, Point3(0), Point3(0))
  34. ###
  35. [ chan camera setPos: relNodePath pos: delta t: t.
  36. ] spawnTaskNamed: 'manipulateCamera'
  37. uponDeath: [ relNodePath removeNode. ]
  38. ###
  39. def homeCam(chan):
  40. chan.camera.setMat(Mat4.identMat())
  41. def mouseFlyStart(chan):
  42. # Record starting mouse positions
  43. initMouseX = chan.mouseX
  44. initMouseY = chan.mouseY
  45. # Where are we in the channel?
  46. if ((initMouseX abs < 0.9) & (initMouseY abs < 0.9)):
  47. # Mouse is in central region
  48. # spawn task to determine mouse fly mode"
  49. self.determineMouseFlyMode()
  50. else:
  51. #Mouse is in outer frame, spawn mouseRotateTask
  52. self.spawnMouseRotateTask()
  53. def mouseFlyStop():
  54. taskMgr.removeTasksNamed('determineMouseFlyMode')
  55. taskMgr.removeTasksNamed('manipulateCamera')
  56. def removeManipulateCameraTask():
  57. taskMgr.removeTasksNamed('manipulateCamera')
  58. def enableMouseFly():
  59. self.enableMouseInteraction()
  60. self.enableHotKeys()
  61. def enableMouseInteraction():
  62. # disable C++ fly interface
  63. base.disableMouse()
  64. # Accept middle mouse events
  65. self.accept('mouse2', self.mouseFlyStart, [chanCenter])
  66. self.accept('mouse2-up' self.mouseFlyStop)
  67. def disableMouseFly():
  68. # Accept middle mouse events
  69. self.ignore('mouse2')
  70. self.ignore:'mouse2-up')
  71. self.ignore('u')
  72. self.ignore('c')
  73. self.ignore('h')
  74. for i in range(0,10):
  75. self.ignore(`i`)
  76. self.ignore('=')
  77. self.ignore('+')
  78. self.ignore('-')
  79. self.ignore('=')
  80. def enableHotKeys():
  81. self.accept('u', self.uprightCam, [chanCenter])
  82. self.accept('c', self.centerCamIn, [chanCenter, 0.5])
  83. self.accept('h', self.homeCam, [chanCenter])
  84. for i in range(1,8):
  85. self.accept(`i`, self.moveToView, [chanCenter, i])
  86. self.accept('9', self.swingCamAboutWidget, [chanCenter, -90.0, 1.0])
  87. self.accept('0', self.swingCamAboutWidget, [chanCenter, 90.0, 1.0])
  88. self.accept('8', self.removeManipulateCameraTask)
  89. self.accept('=', self.zoomCam, [chanCenter, 0.5, 1.0])
  90. self.accept('+', self.zoomCam, [chanCenter, 0.5, 1.0])
  91. self.accept('-', self.zoomCam, [chanCenter, -2.0, 1.0])
  92. self.accept('=', self.zoomCam, [chanCenter, -2.0, 1.0])
  93. def SpawnMoveToView(chan, view):
  94. # Kill any existing tasks
  95. taskMgr.removeTasksNamed('manipulateCamera')
  96. # Calc hprOffset
  97. hprOffset = VBase3()
  98. if view = 1:
  99. hprOffset.set(180., 0., 0.)
  100. elif view = 2:
  101. hprOffset set(0., 0., 0.)
  102. elif view = 3:
  103. hprOffset set(90., 0., 0.)
  104. elif view = 4:
  105. hprOffset set(-90., 0., 0.)
  106. elif view = 5:
  107. hprOffset set(0., -90., 0.)
  108. elif view = 6:
  109. hprOffset set(0., 90., 0.)
  110. elif view = 7:
  111. hprOffset set(135., -35.264, 0.)
  112. # Position target
  113. targetNodePath.setPosHpr(direct.widget,
  114. self.zeroBaseVec,
  115. hprOffset)
  116. # Scale center vec by current distance to target
  117. offsetDistance = Vec3(chan.camera.getPos(targetNodePath) - \
  118. zeroPoint).length()
  119. scaledCenterVec = centerVec * (-1.0 * offsetDistance).
  120. # Now put the targetNodePath at that point
  121. targetNodePath.setPosHpr(targetNodePath,
  122. scaledCenterVec,
  123. zeroBaseVec)
  124. # Start off with best view if change is to new view
  125. if (view != lastView):
  126. orthoViewRoll = 0.0
  127. lastView = view.
  128. [ chan camera setPosHpr: targetNodePath pos: zeroBaseVec
  129. hpr: (VBase3 new: 0.0 y: 0.0 z: orthoViewRoll)
  130. t: 1.0.
  131. "Try another roll next time"
  132. orthoViewRoll = (orthoViewRoll + 90.0) rem: 360.0.]
  133. spawnTaskNamed: #manipulateCamera.
  134. def determineMouseFlyMode():
  135. # Get mouse intersection point
  136. # TBS
  137. # Find this point to camera space
  138. gridToCamera = grid getMat: chanCenter camera.
  139. hitPt operatorAssign: (gridToCamera xformPoint: iPoint).
  140. "Make sure hitPt is in front of the camera"
  141. hitPt setY: (hitPt at: 1) abs.
  142. "Handle case of bad hit point (too close or too far)"
  143. hitDistance = (hitPt - zeroPoint) length.
  144. ((hitDistance < (1.1 * chanCenter near)) | (hitDistance > chanCenter far)) ifTrue: [
  145. "Just use grid origin"
  146. "hitPt operatorAssign: centerVec * (0.5 * (chanCenter far + chanCenter near))"
  147. hitPt operatorAssign: (grid getPos: chanCenter camera).
  148. ].
  149. (direct fShift) ifTrue: [ self.spawnHPPan. ]
  150. ifFalse: [
  151. [[deltaX = chanCenter mouseX - initMouseX.
  152. deltaY = chanCenter mouseY - initMouseY.
  153. ((deltaX abs < 0.1) & (deltaY abs < 0.1))] taskWhileTrue: [ nil ]
  154. ] spawnTaskNamed: #determineMouseFlyMode
  155. uponDeath: [
  156. (deltaY abs > 0.1) ifTrue: [
  157. self.spawnHPanYZoom]
  158. ifFalse: [
  159. self.spawnXZTranslate ].
  160. ].
  161. ].
  162. ! !
  163. !DirectCameraManipulation methodsFor: 'event handling' stamp: 'panda 00/00/0000 00:00'!
  164. spawnHPPan
  165. [[true] taskWhileTrue:
  166. [ chanCenter camera setHpr: chanCenter camera
  167. h: (0.5 * chanCenter mouseDeltaX * chanCenter fovH)
  168. p: (-0.5 * chanCenter mouseDeltaY * chanCenter fovV)
  169. r: 0.0 ]]
  170. spawnTaskNamed: #manipulateCamera.
  171. ! !
  172. !DirectCameraManipulation methodsFor: 'event handling' stamp: 'panda 00/00/0000 00:00'!
  173. spawnHPanYZoom
  174. | targetVector distToMove |
  175. targetVector = Vec3 new: (hitPt at: 0) y: (hitPt at: 1) z: (hitPt at: 2).
  176. [[true] taskWhileTrue:
  177. [ distToMove = targetVector * (-1.0 * chanCenter mouseDeltaY).
  178. chanCenter camera setPosHpr: chanCenter camera
  179. x: (distToMove at: 0)
  180. y: (distToMove at: 1)
  181. z: (distToMove at: 2)
  182. h: (0.5 * chanCenter mouseDeltaX * chanCenter fovH)
  183. p: 0.0 r: 0.0. ]]
  184. spawnTaskNamed: #manipulateCamera.
  185. ! !
  186. !DirectCameraManipulation methodsFor: 'event handling' stamp: 'panda 00/00/0000 00:00'!
  187. spawnMouseRotateTask
  188. | wrtMat |
  189. centerOfRotation setPos: grid pos: iPoint.
  190. centerOfRotation setHpr: chanCenter camera h: 0.0 p: 0.0 r: 0.0.
  191. wrtMat = chanCenter camera getMat: centerOfRotation.
  192. [[true] taskWhileTrue:
  193. [ centerOfRotation setHpr: centerOfRotation
  194. h: (-0.5 * chanCenter mouseDeltaX * 180.0)
  195. p: (0.5 * chanCenter mouseDeltaY * 180.0)
  196. r: 0.0.
  197. chanCenter camera setMat: centerOfRotation mat: wrtMat. ]]
  198. spawnTaskNamed: #manipulateCamera.
  199. ! !
  200. !DirectCameraManipulation methodsFor: 'event handling' stamp: 'panda 00/00/0000 00:00'!
  201. spawnXZTranslate
  202. | scaleFactor |
  203. scaleFactor = ((hitPt at: 1) / chanCenter near).
  204. [[true] taskWhileTrue:
  205. [ chanCenter camera setPos: chanCenter camera
  206. x: (-0.5 * chanCenter mouseDeltaX * chanCenter nearWidth * scaleFactor)
  207. y: 0.0
  208. z: (-0.5 * chanCenter mouseDeltaY * chanCenter nearHeight * scaleFactor) ] ]
  209. spawnTaskNamed: #manipulateCamera.
  210. ! !
  211. !DirectCameraManipulation methodsFor: 'event handling' stamp: 'panda 00/00/0000 00:00'!
  212. spawnXZTranslateOrHPPan
  213. | scaleFactor |
  214. scaleFactor = ((hitPt at: 1) / chanCenter near).
  215. [[true] taskWhileTrue:
  216. [ direct fShift
  217. ifTrue: [ chanCenter camera setHpr: chanCenter camera
  218. h: (0.5 * chanCenter mouseDeltaX * chanCenter fovH)
  219. p: (-0.5 * chanCenter mouseDeltaY * chanCenter fovV)
  220. r: 0.0 ]
  221. ifFalse: [ chanCenter camera setPos: chanCenter camera
  222. x: (-0.5 * chanCenter mouseDeltaX * chanCenter nearWidth * scaleFactor)
  223. y: 0.0
  224. z: (-0.5 * chanCenter mouseDeltaY * chanCenter nearHeight * scaleFactor)]
  225. ]]
  226. spawnTaskNamed: #manipulateCamera.
  227. ! !
  228. !DirectCameraManipulation methodsFor: 'event handling' stamp: 'panda 00/00/0000 00:00'!
  229. swingCamAboutWidget: chan deg: degrees in: t
  230. | relNodePath parent |
  231. Task removeTasksNamed: #manipulateCamera.
  232. relNodePath = showBase render attachNewNode: (Node new).
  233. "Coincident with widget"
  234. relNodePath setPos: direct widget pos: (Point3 zero).
  235. "But aligned with render space"
  236. relNodePath setHpr: (Point3 zero).
  237. parent = chanCenter camera getParent.
  238. chanCenter camera wrtReparentTo: relNodePath.
  239. [ relNodePath setHpr: (VBase3 new: degrees y: 0.0 z: 0.0) t: t. ]
  240. spawnTaskNamed: #manipulateCamera
  241. uponDeath: [
  242. chanCenter camera wrtReparentTo: parent.
  243. relNodePath reparentTo: showBase hidden.
  244. relNodePath removeNode.
  245. ].! !
  246. !DirectCameraManipulation methodsFor: 'event handling' stamp: 'panda 00/00/0000 00:00'!
  247. uprightCam: chan
  248. | currH |
  249. Task removeTasksNamed: #manipulateCamera.
  250. currH = chan camera getH.
  251. [ chan camera setHpr: showBase render h: currH p: 0.0 r: 0.0 t: 1.0.
  252. ] spawnTaskNamed: #manipulateCamera.! !
  253. !DirectCameraManipulation methodsFor: 'event handling' stamp: 'panda 00/00/0000 00:00'!
  254. zoomCam: chan zoom: zoom in: t
  255. | relNodePath zoomPtToCam |
  256. Task removeTasksNamed: #manipulateCamera.
  257. "Find a point zoom factor times the current separation of the widget and cam"
  258. zoomPtToCam = (direct widget getPos: chan camera) * zoom.
  259. "Put a target nodePath there"
  260. relNodePath = showBase render attachNewNode: (Node new).
  261. relNodePath setPos: chanCenter camera pos: zoomPtToCam.
  262. "Move to that point"
  263. [ chan camera setPos: relNodePath pos: (Point3 zero) t: t. ]
  264. spawnTaskNamed: #manipulateCamera
  265. uponDeath: [ relNodePath removeNode. ].! !