@@ -7,10 +7,16 @@ export const useFollowCam = function (props: UseFollowCamProps) {
7
7
const { scene, camera } = useThree ( ) ;
8
8
// const { rapier, world } = useRapier();
9
9
10
+ let isMouseDown = false ;
11
+ let previousTouch1 : Touch = null ;
12
+ let previousTouch2 : Touch = null ;
13
+
10
14
let originZDis = props . camInitDis ;
11
15
const camMaxDis = props . camMaxDis ;
12
16
const camMinDis = props . camMinDis ;
13
- const camCollisionOff = 0.7 ;
17
+ const camMoveSpeed = props . camMoveSpeed ;
18
+ const camZoomSpeed = props . camZoomSpeed ;
19
+ const camCollisionOffset = props . camCollisionOffset ;
14
20
const pivot = useMemo ( ( ) => new THREE . Object3D ( ) , [ ] ) ;
15
21
const followCam = useMemo ( ( ) => {
16
22
const origin = new THREE . Object3D ( ) ;
@@ -40,9 +46,9 @@ export const useFollowCam = function (props: UseFollowCamProps) {
40
46
41
47
// Mouse move event
42
48
const onDocumentMouseMove = ( e : MouseEvent ) => {
43
- if ( document . pointerLockElement ) {
44
- pivot . rotation . y -= e . movementX * 0.002 ;
45
- const vy = followCam . rotation . x + e . movementY * 0.002 ;
49
+ if ( document . pointerLockElement || isMouseDown ) {
50
+ pivot . rotation . y -= e . movementX * 0.002 * camMoveSpeed ;
51
+ const vy = followCam . rotation . x + e . movementY * 0.002 * camMoveSpeed ;
46
52
47
53
cameraDistance = followCam . position . length ( ) ;
48
54
@@ -57,18 +63,76 @@ export const useFollowCam = function (props: UseFollowCamProps) {
57
63
58
64
// Mouse scroll event
59
65
const onDocumentMouseWheel = ( e : Event ) => {
60
- if ( document . pointerLockElement ) {
61
- const vz = originZDis - ( e as WheelEvent ) . deltaY * 0.002 ;
62
- const vy = followCam . rotation . x + ( e as WheelEvent ) . movementY * 0.002 ;
66
+ const vz = originZDis - ( e as WheelEvent ) . deltaY * 0.002 * camZoomSpeed ;
67
+ const vy = followCam . rotation . x ;
68
+
69
+ if ( vz >= camMaxDis && vz <= camMinDis ) {
70
+ originZDis = vz ;
71
+ followCam . position . z = originZDis * Math . cos ( - vy ) ;
72
+ followCam . position . y = originZDis * Math . sin ( - vy ) ;
73
+ }
74
+ return false ;
75
+ } ;
76
+
77
+ // Touch start event
78
+ const onTouchStart = ( e : TouchEvent ) => {
79
+ // prevent swipe to navigate gesture
80
+ e . preventDefault ( ) ;
81
+ e . stopImmediatePropagation ( ) ;
82
+ }
83
+
84
+ // Touch end event
85
+ const onTouchEnd = ( e : TouchEvent ) => {
86
+ previousTouch1 = null
87
+ previousTouch2 = null
88
+ }
89
+
90
+ // Touch move event
91
+ const onTouchMove = ( e : TouchEvent ) => {
92
+ const touch1 = e . targetTouches [ 0 ] ;
93
+ const touch2 = e . targetTouches [ 1 ] ;
94
+
95
+ // One finger touch to rotate camera
96
+ if ( previousTouch1 && ! previousTouch2 ) {
97
+ const touch1MovementX = touch1 . pageX - previousTouch1 . pageX ;
98
+ const touch1MovementY = touch1 . pageY - previousTouch1 . pageY ;
99
+
100
+ pivot . rotation . y -= touch1MovementX * 0.005 * camMoveSpeed ;
101
+ const vy = followCam . rotation . x + touch1MovementY * 0.005 * camMoveSpeed ;
102
+
103
+ cameraDistance = followCam . position . length ( ) ;
104
+
105
+ if ( vy >= - 0.5 && vy <= 1.5 ) {
106
+ followCam . rotation . x = vy ;
107
+ followCam . position . y = - cameraDistance * Math . sin ( - vy ) ;
108
+ followCam . position . z = - cameraDistance * Math . cos ( - vy ) ;
109
+ }
110
+ }
111
+
112
+ // Two fingers touch to zoom in/out camera
113
+ if ( previousTouch2 ) {
114
+ const prePinchDis = Math . hypot (
115
+ previousTouch1 . pageX - previousTouch2 . pageX ,
116
+ previousTouch1 . pageY - previousTouch2 . pageY
117
+ ) ;
118
+ const pinchDis = Math . hypot (
119
+ e . touches [ 0 ] . pageX - e . touches [ 1 ] . pageX ,
120
+ e . touches [ 0 ] . pageY - e . touches [ 1 ] . pageY
121
+ ) ;
122
+
123
+ const vz = originZDis - ( prePinchDis - pinchDis ) * 0.01 * camZoomSpeed ;
124
+ const vy = followCam . rotation . x ;
63
125
64
126
if ( vz >= camMaxDis && vz <= camMinDis ) {
65
127
originZDis = vz ;
66
128
followCam . position . z = originZDis * Math . cos ( - vy ) ;
67
129
followCam . position . y = originZDis * Math . sin ( - vy ) ;
68
130
}
69
131
}
70
- return false ;
71
- } ;
132
+
133
+ previousTouch1 = touch1 ;
134
+ previousTouch2 = touch2 ;
135
+ }
72
136
73
137
// Custom traverse function
74
138
// Prepare intersect objects for camera collision
@@ -106,8 +170,8 @@ export const useFollowCam = function (props: UseFollowCamProps) {
106
170
intersects = camRayCast . intersectObjects ( intersectObjects ) ;
107
171
if ( intersects . length && intersects [ 0 ] . distance <= - originZDis ) {
108
172
smallestDistance =
109
- - intersects [ 0 ] . distance * camCollisionOff < - 0.7
110
- ? - intersects [ 0 ] . distance * camCollisionOff
173
+ - intersects [ 0 ] . distance * camCollisionOffset < - 0.7
174
+ ? - intersects [ 0 ] . distance * camCollisionOffset
111
175
: - 0.7 ;
112
176
} else {
113
177
smallestDistance = originZDis ;
@@ -144,11 +208,24 @@ export const useFollowCam = function (props: UseFollowCamProps) {
144
208
followCam . add ( camera ) ;
145
209
pivot . add ( followCam ) ;
146
210
211
+ document . addEventListener ( "mousedown" , ( ) => { isMouseDown = true } ) ;
212
+ document . addEventListener ( "mouseup" , ( ) => { isMouseDown = false } ) ;
147
213
document . addEventListener ( "mousemove" , onDocumentMouseMove ) ;
148
214
document . addEventListener ( "mousewheel" , onDocumentMouseWheel ) ;
215
+ // Touch event
216
+ document . addEventListener ( "touchstart" , onTouchStart , { passive : false } ) ;
217
+ document . addEventListener ( "touchend" , onTouchEnd ) ;
218
+ document . addEventListener ( "touchmove" , onTouchMove ) ;
219
+
149
220
return ( ) => {
221
+ document . removeEventListener ( "mousedown" , ( ) => { isMouseDown = true } ) ;
222
+ document . removeEventListener ( "mouseup" , ( ) => { isMouseDown = false } ) ;
150
223
document . removeEventListener ( "mousemove" , onDocumentMouseMove ) ;
151
224
document . removeEventListener ( "mousewheel" , onDocumentMouseWheel ) ;
225
+ // Touch event
226
+ document . removeEventListener ( "touchstart" , onTouchStart ) ;
227
+ document . removeEventListener ( "touchend" , onTouchEnd ) ;
228
+ document . removeEventListener ( "touchmove" , onTouchMove ) ;
152
229
} ;
153
230
} ) ;
154
231
@@ -159,4 +236,7 @@ export type UseFollowCamProps = {
159
236
camInitDis : number ;
160
237
camMaxDis : number ;
161
238
camMinDis : number ;
239
+ camMoveSpeed : number ;
240
+ camZoomSpeed : number ;
241
+ camCollisionOffset : number ;
162
242
} ;
0 commit comments