OrbitCameraController.qml 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. // Copyright (C) 2022 The Qt Company Ltd.
  2. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
  3. import QtQuick
  4. import QtQuick3D
  5. Item {
  6. id: root
  7. required property Node origin
  8. required property Camera camera
  9. property real xSpeed: 0.1
  10. property real ySpeed: 0.1
  11. property bool xInvert: false
  12. property bool yInvert: true
  13. property bool mouseEnabled: true
  14. property bool panEnabled: true
  15. property bool automaticClipping: true
  16. property alias acceptedButtons: dragHandler.acceptedButtons
  17. readonly property bool inputsNeedProcessing: status.useMouse || status.isPanning
  18. implicitWidth: parent.width
  19. implicitHeight: parent.height
  20. Connections {
  21. enabled: root.automaticClipping
  22. target: root.camera
  23. function onZChanged() {
  24. // Adjust near/far values based on distance
  25. let distance = root.camera.z
  26. if (distance < 1) {
  27. root.camera.clipNear = 0.01
  28. root.camera.clipFar = 100
  29. if (root.camera.z === 0) {
  30. console.warn("camera z set to 0, setting it to near clip")
  31. root.camera.z = root.camera.clipNear
  32. }
  33. } else if (distance < 100) {
  34. root.camera.clipNear = 0.1
  35. root.camera.clipFar = 1000
  36. } else {
  37. root.camera.clipNear = 1
  38. root.camera.clipFar = 10000
  39. }
  40. }
  41. }
  42. DragHandler {
  43. id: dragHandler
  44. target: null
  45. enabled: root.mouseEnabled
  46. acceptedModifiers: Qt.NoModifier
  47. onCentroidChanged: {
  48. root.mouseMoved(Qt.vector2d(centroid.position.x, centroid.position.y), false);
  49. }
  50. onActiveChanged: {
  51. if (active)
  52. root.mousePressed(Qt.vector2d(centroid.position.x, centroid.position.y));
  53. else
  54. root.mouseReleased(Qt.vector2d(centroid.position.x, centroid.position.y));
  55. }
  56. }
  57. DragHandler {
  58. id: ctrlDragHandler
  59. target: null
  60. enabled: root.mouseEnabled && root.panEnabled
  61. acceptedButtons: root.acceptedButtons
  62. acceptedModifiers: Qt.ControlModifier
  63. onCentroidChanged: {
  64. root.panEvent(Qt.vector2d(centroid.position.x, centroid.position.y));
  65. }
  66. onActiveChanged: {
  67. if (active)
  68. root.startPan(Qt.vector2d(centroid.position.x, centroid.position.y));
  69. else
  70. root.endPan();
  71. }
  72. }
  73. PinchHandler {
  74. id: pinchHandler
  75. target: null
  76. enabled: root.mouseEnabled
  77. onTranslationChanged: (delta) => {
  78. if (!root.panEnabled)
  79. return;
  80. delta.x = -(delta.x / root.width) * root.camera.z;
  81. delta.y = (delta.y / root.height) * root.camera.z;
  82. let movement = Qt.vector3d(0, 0, 0)
  83. // X Movement
  84. let xDirection = root.origin.right
  85. movement = movement.plus(Qt.vector3d(xDirection.x * delta.x,
  86. xDirection.y * delta.x,
  87. xDirection.z * delta.x));
  88. // Y Movement
  89. let yDirection = root.origin.up
  90. movement = movement.plus(Qt.vector3d(yDirection.x * delta.y,
  91. yDirection.y * delta.y,
  92. yDirection.z * delta.y));
  93. root.origin.position = root.origin.position.plus(movement)
  94. }
  95. onScaleChanged: (delta) => {
  96. root.camera.z = root.camera.z * (1 / delta)
  97. }
  98. }
  99. TapHandler {
  100. acceptedButtons: root.acceptedButtons
  101. onTapped: root.forceActiveFocus() // qmllint disable signal-handler-parameters
  102. }
  103. WheelHandler {
  104. id: wheelHandler
  105. orientation: Qt.Vertical
  106. target: null
  107. enabled: root.mouseEnabled
  108. acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
  109. onWheel: event => {
  110. let delta = -event.angleDelta.y * 0.01;
  111. root.camera.z += root.camera.z * 0.1 * delta
  112. }
  113. }
  114. function mousePressed(newPos) {
  115. root.forceActiveFocus()
  116. status.currentPos = newPos
  117. status.lastPos = newPos
  118. status.useMouse = true;
  119. }
  120. function mouseReleased(newPos) {
  121. status.useMouse = false;
  122. }
  123. function mouseMoved(newPos: vector2d) {
  124. status.currentPos = newPos;
  125. }
  126. function startPan(pos: vector2d) {
  127. status.isPanning = true;
  128. status.currentPanPos = pos;
  129. status.lastPanPos = pos;
  130. }
  131. function endPan() {
  132. status.isPanning = false;
  133. }
  134. function panEvent(newPos: vector2d) {
  135. status.currentPanPos = newPos;
  136. }
  137. FrameAnimation {
  138. id: updateTimer
  139. running: root.inputsNeedProcessing
  140. onTriggered: status.processInput(frameTime * 100)
  141. }
  142. QtObject {
  143. id: status
  144. property bool useMouse: false
  145. property bool isPanning: false
  146. property vector2d lastPos: Qt.vector2d(0, 0)
  147. property vector2d lastPanPos: Qt.vector2d(0, 0)
  148. property vector2d currentPos: Qt.vector2d(0, 0)
  149. property vector2d currentPanPos: Qt.vector2d(0, 0)
  150. function negate(vector) {
  151. return Qt.vector3d(-vector.x, -vector.y, -vector.z)
  152. }
  153. function processInput(frameDelta) {
  154. if (useMouse) {
  155. // Get the delta
  156. var rotationVector = root.origin.eulerRotation;
  157. var delta = Qt.vector2d(lastPos.x - currentPos.x,
  158. lastPos.y - currentPos.y);
  159. // rotate x
  160. var rotateX = delta.x * root.xSpeed * frameDelta
  161. if (root.xInvert)
  162. rotateX = -rotateX;
  163. rotationVector.y += rotateX;
  164. // rotate y
  165. var rotateY = delta.y * -root.ySpeed * frameDelta
  166. if (root.yInvert)
  167. rotateY = -rotateY;
  168. rotationVector.x += rotateY;
  169. root.origin.setEulerRotation(rotationVector);
  170. lastPos = currentPos;
  171. }
  172. if (isPanning) {
  173. let delta = currentPanPos.minus(lastPanPos);
  174. delta.x = -delta.x
  175. delta.x = (delta.x / root.width) * root.camera.z * frameDelta
  176. delta.y = (delta.y / root.height) * root.camera.z * frameDelta
  177. let velocity = Qt.vector3d(0, 0, 0)
  178. // X Movement
  179. let xDirection = root.origin.right
  180. velocity = velocity.plus(Qt.vector3d(xDirection.x * delta.x,
  181. xDirection.y * delta.x,
  182. xDirection.z * delta.x));
  183. // Y Movement
  184. let yDirection = root.origin.up
  185. velocity = velocity.plus(Qt.vector3d(yDirection.x * delta.y,
  186. yDirection.y * delta.y,
  187. yDirection.z * delta.y));
  188. root.origin.position = root.origin.position.plus(velocity)
  189. lastPanPos = currentPanPos
  190. }
  191. }
  192. }
  193. }