@vyr/three 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (127) hide show
  1. package/package.json +26 -0
  2. package/src/actor/ComposerServiceActor.ts +107 -0
  3. package/src/actor/GeometryActor.ts +13 -0
  4. package/src/actor/HTMLConvertActor.ts +55 -0
  5. package/src/actor/MaterialActor.ts +13 -0
  6. package/src/actor/NodeActor.ts +25 -0
  7. package/src/actor/OrbitControllerActor.ts +110 -0
  8. package/src/actor/PassActor.ts +24 -0
  9. package/src/actor/SceneServiceActor.ts +122 -0
  10. package/src/actor/TextureActor.ts +13 -0
  11. package/src/actor/TransformControllerActor.ts +23 -0
  12. package/src/actor/index.ts +10 -0
  13. package/src/asset/index.ts +187 -0
  14. package/src/controls/CameraControls.ts +2360 -0
  15. package/src/controls/TransformControls.ts +1747 -0
  16. package/src/controls/index.ts +2 -0
  17. package/src/descriptor/ComposerServiceDescriptor.ts +47 -0
  18. package/src/descriptor/GeoMapDescriptor.ts +24 -0
  19. package/src/descriptor/HTMLConvertDescriptor.ts +12 -0
  20. package/src/descriptor/InstancedMeshDescriptor.ts +21 -0
  21. package/src/descriptor/MeshDescriptor.ts +16 -0
  22. package/src/descriptor/ModelDescriptor.ts +15 -0
  23. package/src/descriptor/OrbitControllerDescriptor.ts +84 -0
  24. package/src/descriptor/OrthographicCameraDescriptor.ts +12 -0
  25. package/src/descriptor/ParticleDescriptor.ts +88 -0
  26. package/src/descriptor/PassDescriptor.ts +33 -0
  27. package/src/descriptor/PerspectiveCameraDescriptor.ts +15 -0
  28. package/src/descriptor/PointsDescriptor.ts +16 -0
  29. package/src/descriptor/SceneServiceDescriptor.ts +39 -0
  30. package/src/descriptor/SpriteDescriptor.ts +16 -0
  31. package/src/descriptor/TextDescriptor.ts +41 -0
  32. package/src/descriptor/TransformControllerDescriptor.ts +32 -0
  33. package/src/descriptor/animation/AnimationActionDescriptor.ts +52 -0
  34. package/src/descriptor/geometry/BoxGeometryDescriptor.ts +26 -0
  35. package/src/descriptor/geometry/BufferGeometryDescriptor.ts +15 -0
  36. package/src/descriptor/geometry/CircleGeometryDescriptor.ts +22 -0
  37. package/src/descriptor/geometry/CylinderGeometryDescriptor.ts +30 -0
  38. package/src/descriptor/geometry/ExtrudeGeometryDescriptor.ts +35 -0
  39. package/src/descriptor/geometry/GeometryDescriptor.ts +8 -0
  40. package/src/descriptor/geometry/PlaneGeometryDescriptor.ts +22 -0
  41. package/src/descriptor/geometry/RingGeometryDescriptor.ts +26 -0
  42. package/src/descriptor/geometry/SphereGeometryDescriptor.ts +27 -0
  43. package/src/descriptor/geometry/SurfaceGeometryDescriptor.ts +15 -0
  44. package/src/descriptor/geometry/TubeGeometryDescriptor.ts +25 -0
  45. package/src/descriptor/helper/AxesHelperDescriptor.ts +8 -0
  46. package/src/descriptor/index.ts +45 -0
  47. package/src/descriptor/light/AmbientLightDescriptor.ts +8 -0
  48. package/src/descriptor/light/DirectionalLightDescriptor.ts +33 -0
  49. package/src/descriptor/light/HemisphereLightDescriptor.ts +16 -0
  50. package/src/descriptor/light/LightDescriptor.ts +16 -0
  51. package/src/descriptor/light/PointLightDescriptor.ts +24 -0
  52. package/src/descriptor/light/RectAreaLightDescriptor.ts +20 -0
  53. package/src/descriptor/light/SpotLightDescriptor.ts +30 -0
  54. package/src/descriptor/material/MaterialDescriptor.ts +84 -0
  55. package/src/descriptor/material/MeshBasicMaterialDescriptor.ts +53 -0
  56. package/src/descriptor/material/MeshPhongMaterialDescriptor.ts +102 -0
  57. package/src/descriptor/material/MeshStandardMaterialDescriptor.ts +99 -0
  58. package/src/descriptor/material/PointsMaterialDescriptor.ts +31 -0
  59. package/src/descriptor/material/ShaderMaterialDescriptor.ts +35 -0
  60. package/src/descriptor/material/ShadowMaterialDescriptor.ts +19 -0
  61. package/src/descriptor/material/SpriteMaterialDescriptor.ts +31 -0
  62. package/src/descriptor/texture/TextureDescriptor.ts +110 -0
  63. package/src/index.ts +9 -0
  64. package/src/interpreter/ComposerServiceInterpreter.ts +25 -0
  65. package/src/interpreter/GeoMapInterpreter.ts +253 -0
  66. package/src/interpreter/HTMLConvertInterpreter.ts +31 -0
  67. package/src/interpreter/InstancedMeshInterpreter.ts +76 -0
  68. package/src/interpreter/MeshInterpreter.ts +25 -0
  69. package/src/interpreter/ModelInterpreter.ts +61 -0
  70. package/src/interpreter/NodeInterpreter.ts +65 -0
  71. package/src/interpreter/OrbitControllerInterpreter.ts +47 -0
  72. package/src/interpreter/OrthographicCameraInterpreter.ts +13 -0
  73. package/src/interpreter/ParticleInterpreter.ts +221 -0
  74. package/src/interpreter/PassInterpreter.ts +43 -0
  75. package/src/interpreter/PerspectiveCameraInterpreter.ts +33 -0
  76. package/src/interpreter/PointsInterpreter.ts +61 -0
  77. package/src/interpreter/SceneServiceInterpreter.ts +119 -0
  78. package/src/interpreter/ServiceSchedulerInterpreter.ts +23 -0
  79. package/src/interpreter/SpriteInterpreter.ts +45 -0
  80. package/src/interpreter/TextInterpreter.ts +76 -0
  81. package/src/interpreter/TransformControllerInterpreter.ts +44 -0
  82. package/src/interpreter/animation/AnimationActionInterpreter.ts +66 -0
  83. package/src/interpreter/geometry/BoxGeometryInterpreter.ts +34 -0
  84. package/src/interpreter/geometry/BufferGeometryInterpreter.ts +47 -0
  85. package/src/interpreter/geometry/CircleGeometryInterpreter.ts +34 -0
  86. package/src/interpreter/geometry/CylinderGeometryInterpreter.ts +34 -0
  87. package/src/interpreter/geometry/ExtrudeGeometryInterpreter.ts +55 -0
  88. package/src/interpreter/geometry/PlaneGeometryInterpreter.ts +34 -0
  89. package/src/interpreter/geometry/RingGeometryInterpreter.ts +34 -0
  90. package/src/interpreter/geometry/SphereGeometryInterpreter.ts +34 -0
  91. package/src/interpreter/geometry/SurfaceGeometryInterpreter.ts +39 -0
  92. package/src/interpreter/geometry/TubeGeometryInterpreter.ts +42 -0
  93. package/src/interpreter/helper/AxesHelperInterpreter.ts +38 -0
  94. package/src/interpreter/index.ts +45 -0
  95. package/src/interpreter/light/AmbientLightInterpreter.ts +30 -0
  96. package/src/interpreter/light/DirectionalLightInterpreter.ts +84 -0
  97. package/src/interpreter/light/HemisphereLightInterpreter.ts +32 -0
  98. package/src/interpreter/light/PointLightInterpreter.ts +46 -0
  99. package/src/interpreter/light/RectAreaLightInterpreter.ts +34 -0
  100. package/src/interpreter/light/SpotLightInterpreter.ts +68 -0
  101. package/src/interpreter/material/MaterialInterpreter.ts +34 -0
  102. package/src/interpreter/material/MeshBasicMaterialInterpreter.ts +43 -0
  103. package/src/interpreter/material/MeshPhongMaterialInterpreter.ts +63 -0
  104. package/src/interpreter/material/MeshStandardMaterialInterpreter.ts +58 -0
  105. package/src/interpreter/material/PointsMaterialInterpreter.ts +36 -0
  106. package/src/interpreter/material/ShaderMaterialInterpreter.ts +51 -0
  107. package/src/interpreter/material/ShadowMaterialInterpreter.ts +31 -0
  108. package/src/interpreter/material/SpriteMaterialInterpreter.ts +36 -0
  109. package/src/interpreter/texture/TextureInterpreter.ts +59 -0
  110. package/src/locale/Language.ts +10 -0
  111. package/src/locale/LanguageProvider.ts +16 -0
  112. package/src/locale/index.ts +2 -0
  113. package/src/preset/execute/GeoMap/drilldown.ts +61 -0
  114. package/src/preset/execute/GeoMap/index.ts +1 -0
  115. package/src/preset/execute/index.ts +1 -0
  116. package/src/preset/index.ts +7 -0
  117. package/src/preset/routine/GeoMap/drilldown.ts +26 -0
  118. package/src/preset/routine/GeoMap/index.ts +1 -0
  119. package/src/preset/routine/index.ts +1 -0
  120. package/src/utils/dispose/index.ts +23 -0
  121. package/src/utils/geometry/index.ts +82 -0
  122. package/src/utils/index.ts +7 -0
  123. package/src/utils/material/index.ts +53 -0
  124. package/src/utils/pickup/index.ts +16 -0
  125. package/src/utils/random/index.ts +7 -0
  126. package/src/utils/text/index.ts +492 -0
  127. package/src/utils/texture/index.ts +19 -0
@@ -0,0 +1,1747 @@
1
+ //@ts-nocheck
2
+ import {
3
+ BoxGeometry,
4
+ BufferGeometry,
5
+ Camera,
6
+ CylinderGeometry,
7
+ DoubleSide,
8
+ Euler,
9
+ Float32BufferAttribute,
10
+ Line,
11
+ LineBasicMaterial,
12
+ Matrix4,
13
+ Mesh,
14
+ MeshBasicMaterial,
15
+ Object3D,
16
+ OctahedronGeometry,
17
+ PlaneGeometry,
18
+ Quaternion,
19
+ Raycaster,
20
+ SphereGeometry,
21
+ TorusGeometry,
22
+ Vector3,
23
+ } from 'three'
24
+ import { Asset, NodeDescriptor, UpdateArgs, ServiceDescriptor, Graphics, Scriptable, Descriptor } from '@vyr/engine'
25
+ import { TransformControllerChangeArgs, TransformControllerDescriptor, SceneServiceDescriptor, OrbitControllerDescriptor } from '../descriptor'
26
+ import { NodeActor, SceneServiceActor } from '../actor'
27
+
28
+ const _raycaster = new Raycaster()
29
+ const _tempVector = new Vector3()
30
+ const _tempVector2 = new Vector3()
31
+ const _tempQuaternion = new Quaternion()
32
+ const _unit = {
33
+ X: new Vector3(1, 0, 0),
34
+ Y: new Vector3(0, 1, 0),
35
+ Z: new Vector3(0, 0, 1),
36
+ }
37
+
38
+ // mouse / touch event handlers
39
+
40
+ function getPointer(event: PointerEvent) {
41
+ if (this.domElement.ownerDocument.pointerLockElement) {
42
+ return {
43
+ x: 0,
44
+ y: 0,
45
+ button: event.button,
46
+ }
47
+ } else {
48
+ const rect = this.domElement.getBoundingClientRect()
49
+
50
+ return {
51
+ x: ((event.clientX - rect.left) / rect.width) * 2 - 1,
52
+ y: (-(event.clientY - rect.top) / rect.height) * 2 + 1,
53
+ button: event.button,
54
+ }
55
+ }
56
+ }
57
+
58
+ function onPointerHover(event: PointerEvent) {
59
+ if (this.enabled === false) return
60
+
61
+ switch (event.pointerType) {
62
+ case 'mouse':
63
+ case 'pen':
64
+ this.pointerHover(this._getPointer(event))
65
+ break
66
+ }
67
+ }
68
+
69
+ function onPointerDown(event: PointerEvent) {
70
+ if (this.enabled === false) return
71
+
72
+ this.domElement.addEventListener('pointermove', this._onPointerMove)
73
+
74
+ this.pointerHover(this._getPointer(event))
75
+ this.pointerDown(this._getPointer(event))
76
+ }
77
+
78
+ function onPointerMove(event: PointerEvent) {
79
+ if (this.enabled === false) return
80
+
81
+ this.pointerMove(this._getPointer(event))
82
+ }
83
+
84
+ function onPointerUp(event: PointerEvent) {
85
+ if (this.enabled === false) return
86
+
87
+ this.domElement.removeEventListener('pointermove', this._onPointerMove)
88
+
89
+ this.pointerUp(this._getPointer(event))
90
+ }
91
+
92
+ function intersectObjectWithRay(object: Object3D, raycaster: Raycaster, includeInvisible = false) {
93
+ const allIntersections = raycaster.intersectObject(object, true)
94
+
95
+ for (let i = 0; i < allIntersections.length; i++) {
96
+ if (allIntersections[i].object.visible || includeInvisible) {
97
+ return allIntersections[i]
98
+ }
99
+ }
100
+
101
+ return false
102
+ }
103
+
104
+ //
105
+
106
+ // Reusable utility variables
107
+
108
+ const _tempEuler = new Euler()
109
+ const _alignVector = new Vector3(0, 1, 0)
110
+ const _zeroVector = new Vector3(0, 0, 0)
111
+ const _lookAtMatrix = new Matrix4()
112
+ const _tempQuaternion2 = new Quaternion()
113
+ const _idActorQuaternion = new Quaternion()
114
+ const _dirVector = new Vector3()
115
+ const _tempMatrix = new Matrix4()
116
+
117
+ const _unitX = new Vector3(1, 0, 0)
118
+ const _unitY = new Vector3(0, 1, 0)
119
+ const _unitZ = new Vector3(0, 0, 1)
120
+
121
+ const _v1 = new Vector3()
122
+ const _v2 = new Vector3()
123
+ const _v3 = new Vector3()
124
+
125
+ class TransformControlsGizmo extends Object3D {
126
+ isTransformControlsGizmo: boolean;
127
+ gizmo: {
128
+ translate: Object3D;
129
+ rotate: Object3D;
130
+ scale: Object3D;
131
+ };
132
+ picker: {
133
+ translate: Object3D;
134
+ rotate: Object3D;
135
+ scale: Object3D;
136
+ };
137
+ helper: {
138
+ translate: Object3D;
139
+ rotate: Object3D;
140
+ scale: Object3D;
141
+ };
142
+ type: string
143
+ constructor() {
144
+ super()
145
+
146
+ this.isTransformControlsGizmo = true
147
+
148
+ this.type = 'TransformControlsGizmo'
149
+
150
+ // shared materials
151
+
152
+ const gizmoMaterial = new MeshBasicMaterial({
153
+ depthTest: false,
154
+ depthWrite: false,
155
+ fog: false,
156
+ toneMapped: false,
157
+ transparent: true,
158
+ })
159
+
160
+ const gizmoLineMaterial = new LineBasicMaterial({
161
+ depthTest: false,
162
+ depthWrite: false,
163
+ fog: false,
164
+ toneMapped: false,
165
+ transparent: true,
166
+ })
167
+
168
+ // Make unique material for each axis/color
169
+
170
+ const matInvisible = gizmoMaterial.clone()
171
+ matInvisible.opacity = 0.15
172
+
173
+ const matHelper = gizmoLineMaterial.clone()
174
+ matHelper.opacity = 0.5
175
+
176
+ const matRed = gizmoMaterial.clone()
177
+ matRed.color.setHex(0xff0000)
178
+
179
+ const matGreen = gizmoMaterial.clone()
180
+ matGreen.color.setHex(0x00ff00)
181
+
182
+ const matBlue = gizmoMaterial.clone()
183
+ matBlue.color.setHex(0x0000ff)
184
+
185
+ const matRedTransparent = gizmoMaterial.clone()
186
+ matRedTransparent.color.setHex(0xff0000)
187
+ matRedTransparent.opacity = 0.5
188
+
189
+ const matGreenTransparent = gizmoMaterial.clone()
190
+ matGreenTransparent.color.setHex(0x00ff00)
191
+ matGreenTransparent.opacity = 0.5
192
+
193
+ const matBlueTransparent = gizmoMaterial.clone()
194
+ matBlueTransparent.color.setHex(0x0000ff)
195
+ matBlueTransparent.opacity = 0.5
196
+
197
+ const matWhiteTransparent = gizmoMaterial.clone()
198
+ matWhiteTransparent.opacity = 0.25
199
+
200
+ const matYellowTransparent = gizmoMaterial.clone()
201
+ matYellowTransparent.color.setHex(0xffff00)
202
+ matYellowTransparent.opacity = 0.25
203
+
204
+ const matYellow = gizmoMaterial.clone()
205
+ matYellow.color.setHex(0xffff00)
206
+
207
+ const matGray = gizmoMaterial.clone()
208
+ matGray.color.setHex(0x787878)
209
+
210
+ // reusable geometry
211
+
212
+ const arrowGeometry = new CylinderGeometry(0, 0.04, 0.1, 12)
213
+ arrowGeometry.translate(0, 0.05, 0)
214
+
215
+ const scaleHandleGeometry = new BoxGeometry(0.08, 0.08, 0.08)
216
+ scaleHandleGeometry.translate(0, 0.04, 0)
217
+
218
+ const lineGeometry = new BufferGeometry()
219
+ lineGeometry.setAttribute(
220
+ 'position',
221
+ new Float32BufferAttribute([0, 0, 0, 1, 0, 0], 3)
222
+ )
223
+
224
+ const lineGeometry2 = new CylinderGeometry(0.0075, 0.0075, 0.5, 3)
225
+ lineGeometry2.translate(0, 0.25, 0)
226
+
227
+ function CircleGeometry(radius, arc) {
228
+ const geometry = new TorusGeometry(
229
+ radius,
230
+ 0.0075,
231
+ 3,
232
+ 64,
233
+ arc * Math.PI * 2
234
+ )
235
+ geometry.rotateY(Math.PI / 2)
236
+ geometry.rotateX(Math.PI / 2)
237
+ return geometry
238
+ }
239
+
240
+ // Special geometry for transform helper. If scaled with position vector it spans from [0,0,0] to position
241
+
242
+ function TranslateHelperGeometry() {
243
+ const geometry = new BufferGeometry()
244
+
245
+ geometry.setAttribute(
246
+ 'position',
247
+ new Float32BufferAttribute([0, 0, 0, 1, 1, 1], 3)
248
+ )
249
+
250
+ return geometry
251
+ }
252
+
253
+ // Gizmo definitions - custom hierarchy definitions for setupGizmo() function
254
+
255
+ const gizmoTranslate = {
256
+ X: [
257
+ [new Mesh(arrowGeometry, matRed), [0.5, 0, 0], [0, 0, -Math.PI / 2]],
258
+ [new Mesh(arrowGeometry, matRed), [-0.5, 0, 0], [0, 0, Math.PI / 2]],
259
+ [new Mesh(lineGeometry2, matRed), [0, 0, 0], [0, 0, -Math.PI / 2]],
260
+ ],
261
+ Y: [
262
+ [new Mesh(arrowGeometry, matGreen), [0, 0.5, 0]],
263
+ [new Mesh(arrowGeometry, matGreen), [0, -0.5, 0], [Math.PI, 0, 0]],
264
+ [new Mesh(lineGeometry2, matGreen)],
265
+ ],
266
+ Z: [
267
+ [new Mesh(arrowGeometry, matBlue), [0, 0, 0.5], [Math.PI / 2, 0, 0]],
268
+ [new Mesh(arrowGeometry, matBlue), [0, 0, -0.5], [-Math.PI / 2, 0, 0]],
269
+ [new Mesh(lineGeometry2, matBlue), null, [Math.PI / 2, 0, 0]],
270
+ ],
271
+ XYZ: [
272
+ [
273
+ new Mesh(new OctahedronGeometry(0.1, 0), matWhiteTransparent.clone()),
274
+ [0, 0, 0],
275
+ ],
276
+ ],
277
+ XY: [
278
+ [
279
+ new Mesh(
280
+ new BoxGeometry(0.15, 0.15, 0.01),
281
+ matBlueTransparent.clone()
282
+ ),
283
+ [0.15, 0.15, 0],
284
+ ],
285
+ ],
286
+ YZ: [
287
+ [
288
+ new Mesh(
289
+ new BoxGeometry(0.15, 0.15, 0.01),
290
+ matRedTransparent.clone()
291
+ ),
292
+ [0, 0.15, 0.15],
293
+ [0, Math.PI / 2, 0],
294
+ ],
295
+ ],
296
+ XZ: [
297
+ [
298
+ new Mesh(
299
+ new BoxGeometry(0.15, 0.15, 0.01),
300
+ matGreenTransparent.clone()
301
+ ),
302
+ [0.15, 0, 0.15],
303
+ [-Math.PI / 2, 0, 0],
304
+ ],
305
+ ],
306
+ }
307
+
308
+ const pickerTranslate = {
309
+ X: [
310
+ [
311
+ new Mesh(new CylinderGeometry(0.2, 0, 0.6, 4), matInvisible),
312
+ [0.3, 0, 0],
313
+ [0, 0, -Math.PI / 2],
314
+ ],
315
+ [
316
+ new Mesh(new CylinderGeometry(0.2, 0, 0.6, 4), matInvisible),
317
+ [-0.3, 0, 0],
318
+ [0, 0, Math.PI / 2],
319
+ ],
320
+ ],
321
+ Y: [
322
+ [
323
+ new Mesh(new CylinderGeometry(0.2, 0, 0.6, 4), matInvisible),
324
+ [0, 0.3, 0],
325
+ ],
326
+ [
327
+ new Mesh(new CylinderGeometry(0.2, 0, 0.6, 4), matInvisible),
328
+ [0, -0.3, 0],
329
+ [0, 0, Math.PI],
330
+ ],
331
+ ],
332
+ Z: [
333
+ [
334
+ new Mesh(new CylinderGeometry(0.2, 0, 0.6, 4), matInvisible),
335
+ [0, 0, 0.3],
336
+ [Math.PI / 2, 0, 0],
337
+ ],
338
+ [
339
+ new Mesh(new CylinderGeometry(0.2, 0, 0.6, 4), matInvisible),
340
+ [0, 0, -0.3],
341
+ [-Math.PI / 2, 0, 0],
342
+ ],
343
+ ],
344
+ XYZ: [[new Mesh(new OctahedronGeometry(0.2, 0), matInvisible)]],
345
+ XY: [
346
+ [
347
+ new Mesh(new BoxGeometry(0.2, 0.2, 0.01), matInvisible),
348
+ [0.15, 0.15, 0],
349
+ ],
350
+ ],
351
+ YZ: [
352
+ [
353
+ new Mesh(new BoxGeometry(0.2, 0.2, 0.01), matInvisible),
354
+ [0, 0.15, 0.15],
355
+ [0, Math.PI / 2, 0],
356
+ ],
357
+ ],
358
+ XZ: [
359
+ [
360
+ new Mesh(new BoxGeometry(0.2, 0.2, 0.01), matInvisible),
361
+ [0.15, 0, 0.15],
362
+ [-Math.PI / 2, 0, 0],
363
+ ],
364
+ ],
365
+ }
366
+
367
+ const helperTranslate = {
368
+ START: [
369
+ [
370
+ new Mesh(new OctahedronGeometry(0.01, 2), matHelper),
371
+ null,
372
+ null,
373
+ null,
374
+ 'helper',
375
+ ],
376
+ ],
377
+ END: [
378
+ [
379
+ new Mesh(new OctahedronGeometry(0.01, 2), matHelper),
380
+ null,
381
+ null,
382
+ null,
383
+ 'helper',
384
+ ],
385
+ ],
386
+ DELTA: [
387
+ [
388
+ new Line(TranslateHelperGeometry(), matHelper),
389
+ null,
390
+ null,
391
+ null,
392
+ 'helper',
393
+ ],
394
+ ],
395
+ X: [
396
+ [
397
+ new Line(lineGeometry, matHelper.clone()),
398
+ [-1e3, 0, 0],
399
+ null,
400
+ [1e6, 1, 1],
401
+ 'helper',
402
+ ],
403
+ ],
404
+ Y: [
405
+ [
406
+ new Line(lineGeometry, matHelper.clone()),
407
+ [0, -1e3, 0],
408
+ [0, 0, Math.PI / 2],
409
+ [1e6, 1, 1],
410
+ 'helper',
411
+ ],
412
+ ],
413
+ Z: [
414
+ [
415
+ new Line(lineGeometry, matHelper.clone()),
416
+ [0, 0, -1e3],
417
+ [0, -Math.PI / 2, 0],
418
+ [1e6, 1, 1],
419
+ 'helper',
420
+ ],
421
+ ],
422
+ }
423
+
424
+ const gizmoRotate = {
425
+ XYZE: [
426
+ [new Mesh(CircleGeometry(0.5, 1), matGray), null, [0, Math.PI / 2, 0]],
427
+ ],
428
+ X: [[new Mesh(CircleGeometry(0.5, 0.5), matRed)]],
429
+ Y: [
430
+ [
431
+ new Mesh(CircleGeometry(0.5, 0.5), matGreen),
432
+ null,
433
+ [0, 0, -Math.PI / 2],
434
+ ],
435
+ ],
436
+ Z: [
437
+ [
438
+ new Mesh(CircleGeometry(0.5, 0.5), matBlue),
439
+ null,
440
+ [0, Math.PI / 2, 0],
441
+ ],
442
+ ],
443
+ E: [
444
+ [
445
+ new Mesh(CircleGeometry(0.75, 1), matYellowTransparent),
446
+ null,
447
+ [0, Math.PI / 2, 0],
448
+ ],
449
+ ],
450
+ }
451
+
452
+ const helperRotate = {
453
+ AXIS: [
454
+ [
455
+ new Line(lineGeometry, matHelper.clone()),
456
+ [-1e3, 0, 0],
457
+ null,
458
+ [1e6, 1, 1],
459
+ 'helper',
460
+ ],
461
+ ],
462
+ }
463
+
464
+ const pickerRotate = {
465
+ XYZE: [[new Mesh(new SphereGeometry(0.25, 10, 8), matInvisible)]],
466
+ X: [
467
+ [
468
+ new Mesh(new TorusGeometry(0.5, 0.1, 4, 24), matInvisible),
469
+ [0, 0, 0],
470
+ [0, -Math.PI / 2, -Math.PI / 2],
471
+ ],
472
+ ],
473
+ Y: [
474
+ [
475
+ new Mesh(new TorusGeometry(0.5, 0.1, 4, 24), matInvisible),
476
+ [0, 0, 0],
477
+ [Math.PI / 2, 0, 0],
478
+ ],
479
+ ],
480
+ Z: [
481
+ [
482
+ new Mesh(new TorusGeometry(0.5, 0.1, 4, 24), matInvisible),
483
+ [0, 0, 0],
484
+ [0, 0, -Math.PI / 2],
485
+ ],
486
+ ],
487
+ E: [[new Mesh(new TorusGeometry(0.75, 0.1, 2, 24), matInvisible)]],
488
+ }
489
+
490
+ const gizmoScale = {
491
+ X: [
492
+ [
493
+ new Mesh(scaleHandleGeometry, matRed),
494
+ [0.5, 0, 0],
495
+ [0, 0, -Math.PI / 2],
496
+ ],
497
+ [new Mesh(lineGeometry2, matRed), [0, 0, 0], [0, 0, -Math.PI / 2]],
498
+ [
499
+ new Mesh(scaleHandleGeometry, matRed),
500
+ [-0.5, 0, 0],
501
+ [0, 0, Math.PI / 2],
502
+ ],
503
+ ],
504
+ Y: [
505
+ [new Mesh(scaleHandleGeometry, matGreen), [0, 0.5, 0]],
506
+ [new Mesh(lineGeometry2, matGreen)],
507
+ [
508
+ new Mesh(scaleHandleGeometry, matGreen),
509
+ [0, -0.5, 0],
510
+ [0, 0, Math.PI],
511
+ ],
512
+ ],
513
+ Z: [
514
+ [
515
+ new Mesh(scaleHandleGeometry, matBlue),
516
+ [0, 0, 0.5],
517
+ [Math.PI / 2, 0, 0],
518
+ ],
519
+ [new Mesh(lineGeometry2, matBlue), [0, 0, 0], [Math.PI / 2, 0, 0]],
520
+ [
521
+ new Mesh(scaleHandleGeometry, matBlue),
522
+ [0, 0, -0.5],
523
+ [-Math.PI / 2, 0, 0],
524
+ ],
525
+ ],
526
+ XY: [
527
+ [
528
+ new Mesh(new BoxGeometry(0.15, 0.15, 0.01), matBlueTransparent),
529
+ [0.15, 0.15, 0],
530
+ ],
531
+ ],
532
+ YZ: [
533
+ [
534
+ new Mesh(new BoxGeometry(0.15, 0.15, 0.01), matRedTransparent),
535
+ [0, 0.15, 0.15],
536
+ [0, Math.PI / 2, 0],
537
+ ],
538
+ ],
539
+ XZ: [
540
+ [
541
+ new Mesh(new BoxGeometry(0.15, 0.15, 0.01), matGreenTransparent),
542
+ [0.15, 0, 0.15],
543
+ [-Math.PI / 2, 0, 0],
544
+ ],
545
+ ],
546
+ XYZ: [
547
+ [new Mesh(new BoxGeometry(0.1, 0.1, 0.1), matWhiteTransparent.clone())],
548
+ ],
549
+ }
550
+
551
+ const pickerScale = {
552
+ X: [
553
+ [
554
+ new Mesh(new CylinderGeometry(0.2, 0, 0.6, 4), matInvisible),
555
+ [0.3, 0, 0],
556
+ [0, 0, -Math.PI / 2],
557
+ ],
558
+ [
559
+ new Mesh(new CylinderGeometry(0.2, 0, 0.6, 4), matInvisible),
560
+ [-0.3, 0, 0],
561
+ [0, 0, Math.PI / 2],
562
+ ],
563
+ ],
564
+ Y: [
565
+ [
566
+ new Mesh(new CylinderGeometry(0.2, 0, 0.6, 4), matInvisible),
567
+ [0, 0.3, 0],
568
+ ],
569
+ [
570
+ new Mesh(new CylinderGeometry(0.2, 0, 0.6, 4), matInvisible),
571
+ [0, -0.3, 0],
572
+ [0, 0, Math.PI],
573
+ ],
574
+ ],
575
+ Z: [
576
+ [
577
+ new Mesh(new CylinderGeometry(0.2, 0, 0.6, 4), matInvisible),
578
+ [0, 0, 0.3],
579
+ [Math.PI / 2, 0, 0],
580
+ ],
581
+ [
582
+ new Mesh(new CylinderGeometry(0.2, 0, 0.6, 4), matInvisible),
583
+ [0, 0, -0.3],
584
+ [-Math.PI / 2, 0, 0],
585
+ ],
586
+ ],
587
+ XY: [
588
+ [
589
+ new Mesh(new BoxGeometry(0.2, 0.2, 0.01), matInvisible),
590
+ [0.15, 0.15, 0],
591
+ ],
592
+ ],
593
+ YZ: [
594
+ [
595
+ new Mesh(new BoxGeometry(0.2, 0.2, 0.01), matInvisible),
596
+ [0, 0.15, 0.15],
597
+ [0, Math.PI / 2, 0],
598
+ ],
599
+ ],
600
+ XZ: [
601
+ [
602
+ new Mesh(new BoxGeometry(0.2, 0.2, 0.01), matInvisible),
603
+ [0.15, 0, 0.15],
604
+ [-Math.PI / 2, 0, 0],
605
+ ],
606
+ ],
607
+ XYZ: [
608
+ [new Mesh(new BoxGeometry(0.2, 0.2, 0.2), matInvisible), [0, 0, 0]],
609
+ ],
610
+ }
611
+
612
+ const helperScale = {
613
+ X: [
614
+ [
615
+ new Line(lineGeometry, matHelper.clone()),
616
+ [-1e3, 0, 0],
617
+ null,
618
+ [1e6, 1, 1],
619
+ 'helper',
620
+ ],
621
+ ],
622
+ Y: [
623
+ [
624
+ new Line(lineGeometry, matHelper.clone()),
625
+ [0, -1e3, 0],
626
+ [0, 0, Math.PI / 2],
627
+ [1e6, 1, 1],
628
+ 'helper',
629
+ ],
630
+ ],
631
+ Z: [
632
+ [
633
+ new Line(lineGeometry, matHelper.clone()),
634
+ [0, 0, -1e3],
635
+ [0, -Math.PI / 2, 0],
636
+ [1e6, 1, 1],
637
+ 'helper',
638
+ ],
639
+ ],
640
+ }
641
+
642
+ // Creates an Object3D with gizmos described in custom hierarchy definition.
643
+
644
+ function setupGizmo(gizmoMap) {
645
+ const gizmo = new Object3D()
646
+
647
+ for (const name in gizmoMap) {
648
+ for (let i = gizmoMap[name].length; i--;) {
649
+ const object = gizmoMap[name][i][0].clone()
650
+ const position = gizmoMap[name][i][1]
651
+ const rotation = gizmoMap[name][i][2]
652
+ const scale = gizmoMap[name][i][3]
653
+ const tag = gizmoMap[name][i][4]
654
+
655
+ // name and tag properties are essential for picking and updating logic.
656
+ object.name = name
657
+ object.tag = tag
658
+
659
+ if (position) {
660
+ object.position.set(position[0], position[1], position[2])
661
+ }
662
+
663
+ if (rotation) {
664
+ object.rotation.set(rotation[0], rotation[1], rotation[2])
665
+ }
666
+
667
+ if (scale) {
668
+ object.scale.set(scale[0], scale[1], scale[2])
669
+ }
670
+
671
+ object.updateMatrix()
672
+
673
+ const tempGeometry = object.geometry.clone()
674
+ tempGeometry.applyMatrix4(object.matrix)
675
+ object.geometry = tempGeometry
676
+ object.renderOrder = Infinity
677
+
678
+ object.position.set(0, 0, 0)
679
+ object.rotation.set(0, 0, 0)
680
+ object.scale.set(1, 1, 1)
681
+
682
+ gizmo.add(object)
683
+ }
684
+ }
685
+
686
+ return gizmo
687
+ }
688
+
689
+ // Gizmo creation
690
+
691
+ this.gizmo = {}
692
+ this.picker = {}
693
+ this.helper = {}
694
+
695
+ this.add((this.gizmo['translate'] = setupGizmo(gizmoTranslate)))
696
+ this.add((this.gizmo['rotate'] = setupGizmo(gizmoRotate)))
697
+ this.add((this.gizmo['scale'] = setupGizmo(gizmoScale)))
698
+ this.add((this.picker['translate'] = setupGizmo(pickerTranslate)))
699
+ this.add((this.picker['rotate'] = setupGizmo(pickerRotate)))
700
+ this.add((this.picker['scale'] = setupGizmo(pickerScale)))
701
+ this.add((this.helper['translate'] = setupGizmo(helperTranslate)))
702
+ this.add((this.helper['rotate'] = setupGizmo(helperRotate)))
703
+ this.add((this.helper['scale'] = setupGizmo(helperScale)))
704
+
705
+ // Pickers should be hidden always
706
+
707
+ this.picker['translate'].visible = false
708
+ this.picker['rotate'].visible = false
709
+ this.picker['scale'].visible = false
710
+ }
711
+
712
+ // updateMatrixWorld will update transformations and appearance of individual handles
713
+
714
+ updateMatrixWorld(force) {
715
+ const space = this.mode === 'scale' ? 'local' : this.space // scale always oriented to local rotation
716
+
717
+ const quaternion =
718
+ space === 'local' ? this.worldQuaternion : _idActorQuaternion
719
+
720
+ // Show only gizmos for current transform mode
721
+
722
+ this.gizmo['translate'].visible = this.mode === 'translate'
723
+ this.gizmo['rotate'].visible = this.mode === 'rotate'
724
+ this.gizmo['scale'].visible = this.mode === 'scale'
725
+
726
+ this.helper['translate'].visible = this.mode === 'translate'
727
+ this.helper['rotate'].visible = this.mode === 'rotate'
728
+ this.helper['scale'].visible = this.mode === 'scale'
729
+
730
+ let handles = []
731
+ handles = handles.concat(this.picker[this.mode].children)
732
+ handles = handles.concat(this.gizmo[this.mode].children)
733
+ handles = handles.concat(this.helper[this.mode].children)
734
+
735
+ for (let i = 0; i < handles.length; i++) {
736
+ const handle = handles[i]
737
+
738
+ // hide aligned to camera
739
+
740
+ handle.visible = true
741
+ handle.rotation.set(0, 0, 0)
742
+ handle.position.copy(this.worldPosition)
743
+
744
+ let factor
745
+
746
+ if (this.camera.isOrthographicCamera) {
747
+ factor = (this.camera.top - this.camera.bottom) / this.camera.zoom
748
+ } else {
749
+ factor =
750
+ this.worldPosition.distanceTo(this.cameraPosition) *
751
+ Math.min(
752
+ (1.9 * Math.tan((Math.PI * this.camera.fov) / 360)) /
753
+ this.camera.zoom,
754
+ 7
755
+ )
756
+ }
757
+
758
+ handle.scale.set(1, 1, 1).multiplyScalar((factor * this.size) / 4)
759
+
760
+ if (handle.tag === 'helper') {
761
+ handle.visible = false
762
+
763
+ if (handle.name === 'AXIS') {
764
+ handle.visible = !!this.axis
765
+
766
+ if (this.axis === 'X') {
767
+ _tempQuaternion.setFromEuler(_tempEuler.set(0, 0, 0))
768
+ handle.quaternion.copy(quaternion).multiply(_tempQuaternion)
769
+
770
+ if (
771
+ Math.abs(
772
+ _alignVector
773
+ .copy(_unitX)
774
+ .applyQuaternion(quaternion)
775
+ .dot(this.eye)
776
+ ) > 0.9
777
+ ) {
778
+ handle.visible = false
779
+ }
780
+ }
781
+
782
+ if (this.axis === 'Y') {
783
+ _tempQuaternion.setFromEuler(_tempEuler.set(0, 0, Math.PI / 2))
784
+ handle.quaternion.copy(quaternion).multiply(_tempQuaternion)
785
+
786
+ if (
787
+ Math.abs(
788
+ _alignVector
789
+ .copy(_unitY)
790
+ .applyQuaternion(quaternion)
791
+ .dot(this.eye)
792
+ ) > 0.9
793
+ ) {
794
+ handle.visible = false
795
+ }
796
+ }
797
+
798
+ if (this.axis === 'Z') {
799
+ _tempQuaternion.setFromEuler(_tempEuler.set(0, Math.PI / 2, 0))
800
+ handle.quaternion.copy(quaternion).multiply(_tempQuaternion)
801
+
802
+ if (
803
+ Math.abs(
804
+ _alignVector
805
+ .copy(_unitZ)
806
+ .applyQuaternion(quaternion)
807
+ .dot(this.eye)
808
+ ) > 0.9
809
+ ) {
810
+ handle.visible = false
811
+ }
812
+ }
813
+
814
+ if (this.axis === 'XYZE') {
815
+ _tempQuaternion.setFromEuler(_tempEuler.set(0, Math.PI / 2, 0))
816
+ _alignVector.copy(this.rotationAxis)
817
+ handle.quaternion.setFromRotationMatrix(
818
+ _lookAtMatrix.lookAt(_zeroVector, _alignVector, _unitY)
819
+ )
820
+ handle.quaternion.multiply(_tempQuaternion)
821
+ handle.visible = this.dragging
822
+ }
823
+
824
+ if (this.axis === 'E') {
825
+ handle.visible = false
826
+ }
827
+ } else if (handle.name === 'START') {
828
+ handle.position.copy(this.worldPositionStart)
829
+ handle.visible = this.dragging
830
+ } else if (handle.name === 'END') {
831
+ handle.position.copy(this.worldPosition)
832
+ handle.visible = this.dragging
833
+ } else if (handle.name === 'DELTA') {
834
+ handle.position.copy(this.worldPositionStart)
835
+ handle.quaternion.copy(this.worldQuaternionStart)
836
+ _tempVector
837
+ .set(1e-10, 1e-10, 1e-10)
838
+ .add(this.worldPositionStart)
839
+ .sub(this.worldPosition)
840
+ .multiplyScalar(-1)
841
+ _tempVector.applyQuaternion(
842
+ this.worldQuaternionStart.clone().invert()
843
+ )
844
+ handle.scale.copy(_tempVector)
845
+ handle.visible = this.dragging
846
+ } else {
847
+ handle.quaternion.copy(quaternion)
848
+
849
+ if (this.dragging) {
850
+ handle.position.copy(this.worldPositionStart)
851
+ } else {
852
+ handle.position.copy(this.worldPosition)
853
+ }
854
+
855
+ if (this.axis) {
856
+ handle.visible = this.axis.search(handle.name) !== -1
857
+ }
858
+ }
859
+
860
+ // If updating helper, skip rest of the loop
861
+ continue
862
+ }
863
+
864
+ // Align handles to current local or world rotation
865
+
866
+ handle.quaternion.copy(quaternion)
867
+
868
+ if (this.mode === 'translate' || this.mode === 'scale') {
869
+ // Hide translate and scale axis facing the camera
870
+
871
+ const AXIS_HIDE_THRESHOLD = 0.99
872
+ const PLANE_HIDE_THRESHOLD = 0.2
873
+
874
+ if (handle.name === 'X') {
875
+ if (
876
+ Math.abs(
877
+ _alignVector
878
+ .copy(_unitX)
879
+ .applyQuaternion(quaternion)
880
+ .dot(this.eye)
881
+ ) > AXIS_HIDE_THRESHOLD
882
+ ) {
883
+ handle.scale.set(1e-10, 1e-10, 1e-10)
884
+ handle.visible = false
885
+ }
886
+ }
887
+
888
+ if (handle.name === 'Y') {
889
+ if (
890
+ Math.abs(
891
+ _alignVector
892
+ .copy(_unitY)
893
+ .applyQuaternion(quaternion)
894
+ .dot(this.eye)
895
+ ) > AXIS_HIDE_THRESHOLD
896
+ ) {
897
+ handle.scale.set(1e-10, 1e-10, 1e-10)
898
+ handle.visible = false
899
+ }
900
+ }
901
+
902
+ if (handle.name === 'Z') {
903
+ if (
904
+ Math.abs(
905
+ _alignVector
906
+ .copy(_unitZ)
907
+ .applyQuaternion(quaternion)
908
+ .dot(this.eye)
909
+ ) > AXIS_HIDE_THRESHOLD
910
+ ) {
911
+ handle.scale.set(1e-10, 1e-10, 1e-10)
912
+ handle.visible = false
913
+ }
914
+ }
915
+
916
+ if (handle.name === 'XY') {
917
+ if (
918
+ Math.abs(
919
+ _alignVector
920
+ .copy(_unitZ)
921
+ .applyQuaternion(quaternion)
922
+ .dot(this.eye)
923
+ ) < PLANE_HIDE_THRESHOLD
924
+ ) {
925
+ handle.scale.set(1e-10, 1e-10, 1e-10)
926
+ handle.visible = false
927
+ }
928
+ }
929
+
930
+ if (handle.name === 'YZ') {
931
+ if (
932
+ Math.abs(
933
+ _alignVector
934
+ .copy(_unitX)
935
+ .applyQuaternion(quaternion)
936
+ .dot(this.eye)
937
+ ) < PLANE_HIDE_THRESHOLD
938
+ ) {
939
+ handle.scale.set(1e-10, 1e-10, 1e-10)
940
+ handle.visible = false
941
+ }
942
+ }
943
+
944
+ if (handle.name === 'XZ') {
945
+ if (
946
+ Math.abs(
947
+ _alignVector
948
+ .copy(_unitY)
949
+ .applyQuaternion(quaternion)
950
+ .dot(this.eye)
951
+ ) < PLANE_HIDE_THRESHOLD
952
+ ) {
953
+ handle.scale.set(1e-10, 1e-10, 1e-10)
954
+ handle.visible = false
955
+ }
956
+ }
957
+ } else if (this.mode === 'rotate') {
958
+ // Align handles to current local or world rotation
959
+
960
+ _tempQuaternion2.copy(quaternion)
961
+ _alignVector
962
+ .copy(this.eye)
963
+ .applyQuaternion(_tempQuaternion.copy(quaternion).invert())
964
+
965
+ if (handle.name.search('E') !== -1) {
966
+ handle.quaternion.setFromRotationMatrix(
967
+ _lookAtMatrix.lookAt(this.eye, _zeroVector, _unitY)
968
+ )
969
+ }
970
+
971
+ if (handle.name === 'X') {
972
+ _tempQuaternion.setFromAxisAngle(
973
+ _unitX,
974
+ Math.atan2(-_alignVector.y, _alignVector.z)
975
+ )
976
+ _tempQuaternion.multiplyQuaternions(_tempQuaternion2, _tempQuaternion)
977
+ handle.quaternion.copy(_tempQuaternion)
978
+ }
979
+
980
+ if (handle.name === 'Y') {
981
+ _tempQuaternion.setFromAxisAngle(
982
+ _unitY,
983
+ Math.atan2(_alignVector.x, _alignVector.z)
984
+ )
985
+ _tempQuaternion.multiplyQuaternions(_tempQuaternion2, _tempQuaternion)
986
+ handle.quaternion.copy(_tempQuaternion)
987
+ }
988
+
989
+ if (handle.name === 'Z') {
990
+ _tempQuaternion.setFromAxisAngle(
991
+ _unitZ,
992
+ Math.atan2(_alignVector.y, _alignVector.x)
993
+ )
994
+ _tempQuaternion.multiplyQuaternions(_tempQuaternion2, _tempQuaternion)
995
+ handle.quaternion.copy(_tempQuaternion)
996
+ }
997
+ }
998
+
999
+ // Hide disabled axes
1000
+ handle.visible =
1001
+ handle.visible && (handle.name.indexOf('X') === -1 || this.showX)
1002
+ handle.visible =
1003
+ handle.visible && (handle.name.indexOf('Y') === -1 || this.showY)
1004
+ handle.visible =
1005
+ handle.visible && (handle.name.indexOf('Z') === -1 || this.showZ)
1006
+ handle.visible =
1007
+ handle.visible &&
1008
+ (handle.name.indexOf('E') === -1 ||
1009
+ (this.showX && this.showY && this.showZ))
1010
+
1011
+ // highlight selected axis
1012
+
1013
+ handle.material._color =
1014
+ handle.material._color || handle.material.color.clone()
1015
+ handle.material._opacity =
1016
+ handle.material._opacity || handle.material.opacity
1017
+
1018
+ handle.material.color.copy(handle.material._color)
1019
+ handle.material.opacity = handle.material._opacity
1020
+
1021
+ if (this.enabled === true && this.axis) {
1022
+ if (handle.name === this.axis) {
1023
+ handle.material.color.setHex(0xffff00)
1024
+ handle.material.opacity = 1.0
1025
+ } else if (
1026
+ this.axis.split('').some(function (a) {
1027
+ return handle.name === a
1028
+ })
1029
+ ) {
1030
+ handle.material.color.setHex(0xffff00)
1031
+ handle.material.opacity = 1.0
1032
+ }
1033
+ }
1034
+ }
1035
+
1036
+ super.updateMatrixWorld(force)
1037
+ }
1038
+ }
1039
+
1040
+ class TransformControlsPlane extends Mesh {
1041
+ constructor() {
1042
+ super(
1043
+ new PlaneGeometry(100000, 100000, 2, 2),
1044
+ new MeshBasicMaterial({
1045
+ visible: false,
1046
+ wireframe: true,
1047
+ side: DoubleSide,
1048
+ transparent: true,
1049
+ opacity: 0.1,
1050
+ toneMapped: false,
1051
+ })
1052
+ )
1053
+
1054
+ this.isTransformControlsPlane = true
1055
+
1056
+ this.type = 'TransformControlsPlane'
1057
+ }
1058
+
1059
+ updateMatrixWorld(force) {
1060
+ let space = this.space
1061
+
1062
+ this.position.copy(this.worldPosition)
1063
+
1064
+ if (this.mode === 'scale') space = 'local' // scale always oriented to local rotation
1065
+
1066
+ _v1
1067
+ .copy(_unitX)
1068
+ .applyQuaternion(
1069
+ space === 'local' ? this.worldQuaternion : _idActorQuaternion
1070
+ )
1071
+ _v2
1072
+ .copy(_unitY)
1073
+ .applyQuaternion(
1074
+ space === 'local' ? this.worldQuaternion : _idActorQuaternion
1075
+ )
1076
+ _v3
1077
+ .copy(_unitZ)
1078
+ .applyQuaternion(
1079
+ space === 'local' ? this.worldQuaternion : _idActorQuaternion
1080
+ )
1081
+
1082
+ // Align the plane for current transform mode, axis and space.
1083
+
1084
+ _alignVector.copy(_v2)
1085
+
1086
+ switch (this.mode) {
1087
+ case 'translate':
1088
+ case 'scale':
1089
+ switch (this.axis) {
1090
+ case 'X':
1091
+ _alignVector.copy(this.eye).cross(_v1)
1092
+ _dirVector.copy(_v1).cross(_alignVector)
1093
+ break
1094
+ case 'Y':
1095
+ _alignVector.copy(this.eye).cross(_v2)
1096
+ _dirVector.copy(_v2).cross(_alignVector)
1097
+ break
1098
+ case 'Z':
1099
+ _alignVector.copy(this.eye).cross(_v3)
1100
+ _dirVector.copy(_v3).cross(_alignVector)
1101
+ break
1102
+ case 'XY':
1103
+ _dirVector.copy(_v3)
1104
+ break
1105
+ case 'YZ':
1106
+ _dirVector.copy(_v1)
1107
+ break
1108
+ case 'XZ':
1109
+ _alignVector.copy(_v3)
1110
+ _dirVector.copy(_v2)
1111
+ break
1112
+ case 'XYZ':
1113
+ case 'E':
1114
+ _dirVector.set(0, 0, 0)
1115
+ break
1116
+ }
1117
+
1118
+ break
1119
+ case 'rotate':
1120
+ default:
1121
+ // special case for rotate
1122
+ _dirVector.set(0, 0, 0)
1123
+ }
1124
+
1125
+ if (_dirVector.length() === 0) {
1126
+ // If in rotate mode, make the plane parallel to camera
1127
+ this.quaternion.copy(this.cameraQuaternion)
1128
+ } else {
1129
+ _tempMatrix.lookAt(_tempVector.set(0, 0, 0), _dirVector, _alignVector)
1130
+
1131
+ this.quaternion.setFromRotationMatrix(_tempMatrix)
1132
+ }
1133
+
1134
+ super.updateMatrixWorld(force)
1135
+ }
1136
+ }
1137
+
1138
+ class TransformControls extends Object3D {
1139
+ readonly events: number[] = []
1140
+ camera!: Camera
1141
+ scriptable!: Scriptable
1142
+ sourceTarget!: NodeDescriptor
1143
+ object!: Object3D
1144
+ args!: UpdateArgs
1145
+ descriptor!: TransformControllerDescriptor
1146
+ graphics!: Graphics
1147
+ domElement!: HTMLElement
1148
+ isTransformControls: boolean
1149
+ private _gizmo: TransformControlsGizmo
1150
+ private _plane: TransformControlsPlane
1151
+ private _offset = new Vector3()
1152
+ private _startNorm = new Vector3()
1153
+ private _endNorm = new Vector3()
1154
+ private _cameraScale = new Vector3()
1155
+
1156
+ mode: 'translate' | 'rotate' | 'scale' = 'translate'
1157
+ space: 'world' | 'local' = 'world'
1158
+ axis: string | null = null
1159
+ dragging: boolean = false
1160
+ worldPosition = new Vector3()
1161
+ worldQuaternion = new Quaternion()
1162
+ cameraPosition = new Vector3()
1163
+ cameraQuaternion = new Quaternion()
1164
+ eye = new Vector3()
1165
+ showX = true
1166
+ showY = true
1167
+ showZ = true
1168
+ size = 1
1169
+
1170
+ private _parentPosition = new Vector3()
1171
+ private _parentQuaternion = new Quaternion()
1172
+ private _parentQuaternionInv = new Quaternion()
1173
+ private _parentScale = new Vector3()
1174
+
1175
+ private _worldScaleStart = new Vector3()
1176
+ private _worldQuaternionInv = new Quaternion()
1177
+ private _worldScale = new Vector3()
1178
+
1179
+ private _positionStart = new Vector3()
1180
+ private _quaternionStart = new Quaternion()
1181
+ private _scaleStart = new Vector3()
1182
+
1183
+ private _getPointer = getPointer.bind(this)
1184
+ private _onPointerDown = onPointerDown.bind(this)
1185
+ private _onPointerHover = onPointerHover.bind(this)
1186
+ private _onPointerMove = onPointerMove.bind(this)
1187
+ private _onPointerUp = onPointerUp.bind(this)
1188
+
1189
+ constructor() {
1190
+ super()
1191
+
1192
+ this.isTransformControls = true
1193
+
1194
+ this.visible = false
1195
+
1196
+ const _gizmo = new TransformControlsGizmo()
1197
+ this._gizmo = _gizmo
1198
+ this.add(_gizmo)
1199
+
1200
+ const _plane = new TransformControlsPlane()
1201
+ this._plane = _plane
1202
+ this.add(_plane)
1203
+
1204
+ this.setCustomProperty('object', undefined)
1205
+ this.setCustomProperty('enabled', false)
1206
+ this.setCustomProperty('axis', null)
1207
+ this.setCustomProperty('mode', 'translate')
1208
+ this.setCustomProperty('translationSnap', null)
1209
+ this.setCustomProperty('rotationSnap', null)
1210
+ this.setCustomProperty('scaleSnap', null)
1211
+ this.setCustomProperty('space', 'world')
1212
+ this.setCustomProperty('size', 1)
1213
+ this.setCustomProperty('dragging', false)
1214
+ this.setCustomProperty('showX', true)
1215
+ this.setCustomProperty('showY', true)
1216
+ this.setCustomProperty('showZ', true)
1217
+
1218
+ // Reusable utility variables
1219
+
1220
+ const worldPosition = new Vector3()
1221
+ const worldPositionStart = new Vector3()
1222
+ const worldQuaternion = new Quaternion()
1223
+ const worldQuaternionStart = new Quaternion()
1224
+ const cameraPosition = new Vector3()
1225
+ const cameraQuaternion = new Quaternion()
1226
+ const pointStart = new Vector3()
1227
+ const pointEnd = new Vector3()
1228
+ const rotationAxis = new Vector3()
1229
+ const rotationAngle = 0
1230
+ const eye = new Vector3()
1231
+
1232
+ this.setCustomProperty('worldPosition', worldPosition)
1233
+ this.setCustomProperty('worldPositionStart', worldPositionStart)
1234
+ this.setCustomProperty('worldQuaternion', worldQuaternion)
1235
+ this.setCustomProperty('worldQuaternionStart', worldQuaternionStart)
1236
+ this.setCustomProperty('cameraPosition', cameraPosition)
1237
+ this.setCustomProperty('cameraQuaternion', cameraQuaternion)
1238
+ this.setCustomProperty('pointStart', pointStart)
1239
+ this.setCustomProperty('pointEnd', pointEnd)
1240
+ this.setCustomProperty('rotationAxis', rotationAxis)
1241
+ this.setCustomProperty('rotationAngle', rotationAngle)
1242
+ this.setCustomProperty('eye', eye)
1243
+ }
1244
+
1245
+ change(type = 'change') {
1246
+ if (!this.scriptable) return
1247
+
1248
+ this.sourceTarget.position.x = this.object.position.x
1249
+ this.sourceTarget.position.y = this.object.position.y
1250
+ this.sourceTarget.position.z = this.object.position.z
1251
+ this.sourceTarget.scale.x = this.object.scale.x
1252
+ this.sourceTarget.scale.y = this.object.scale.y
1253
+ this.sourceTarget.scale.z = this.object.scale.z
1254
+ this.sourceTarget.rotation.x = this.object.rotation.x
1255
+ this.sourceTarget.rotation.y = this.object.rotation.y
1256
+ this.sourceTarget.rotation.z = this.object.rotation.z
1257
+
1258
+ const _args: TransformControllerChangeArgs = { ...this.args, event: { type, target: this.descriptor.target } }
1259
+ this.scriptable.execute(this.descriptor, this.graphics, _args)
1260
+ }
1261
+
1262
+ listen(descriptor: TransformControllerDescriptor, graphics: Graphics, args: UpdateArgs) {
1263
+ this.unlisten(graphics)
1264
+
1265
+ const sourceTarget = graphics.variableProxy.get<NodeDescriptor>(descriptor.target, graphics, args)
1266
+ if (sourceTarget === null) return
1267
+ const sourceTargetActor = graphics.getActor(sourceTarget, args)
1268
+ if (sourceTargetActor instanceof NodeActor) {
1269
+ const camera = graphics.variableProxy.get<NodeDescriptor>(graphics.scheduler.camera, graphics, args)
1270
+ const actor = graphics.getActor(camera, args) as NodeActor
1271
+ const scriptable = Asset.get(descriptor.event)
1272
+
1273
+ this.setCustomProperty('camera', actor.object)
1274
+ this.setCustomProperty('graphics', graphics)
1275
+ this.setCustomProperty('args', args)
1276
+ this.setCustomProperty('descriptor', descriptor)
1277
+ this.setCustomProperty('mode', descriptor.mode)
1278
+ this.setCustomProperty('scriptable', scriptable)
1279
+ this.setCustomProperty('sourceTarget', sourceTarget)
1280
+ this.setCustomProperty('enabled', true)
1281
+
1282
+ this.attach(sourceTargetActor.object)
1283
+
1284
+ this.domElement = this.getWrapper(descriptor, graphics, args)
1285
+
1286
+ this.events.push(graphics.engine.inputSystem.listen('pointerdown', this._onPointerDown, { target: this.domElement }))
1287
+ this.events.push(graphics.engine.inputSystem.listen('pointerdown', this._onPointerDown, { target: this.domElement }))
1288
+ this.events.push(graphics.engine.inputSystem.listen('pointerup', this._onPointerUp, { target: this.domElement }))
1289
+ }
1290
+ }
1291
+
1292
+ unlisten(graphics: Graphics) {
1293
+ this.unbind(graphics)
1294
+ this.detach()
1295
+ this.setCustomProperty('args', undefined)
1296
+ this.setCustomProperty('descriptor', undefined)
1297
+ this.setCustomProperty('camera', undefined)
1298
+ this.setCustomProperty('scriptable', undefined)
1299
+ this.setCustomProperty('sourceTarget', undefined)
1300
+ this.setCustomProperty('enabled', false)
1301
+ }
1302
+
1303
+ // update(descriptor: TransformControllerDescriptor, graphics: Graphics, args: UpdateArgs) {
1304
+ // this.listen(descriptor, graphics, args)
1305
+ // }
1306
+
1307
+ unbind(graphics: Graphics) {
1308
+ for (const e of this.events) graphics.engine.inputSystem.unlisten(e)
1309
+ this.events.length = 0
1310
+ }
1311
+
1312
+ dispose(graphics: Graphics) {
1313
+ this.unbind(graphics)
1314
+
1315
+ this.traverse(function (child) {
1316
+ //@ts-ignore
1317
+ if (child.geometry) child.geometry.dispose()
1318
+ //@ts-ignore
1319
+ if (child.material) child.material.dispose()
1320
+ })
1321
+ }
1322
+
1323
+ private getWrapper(descriptor: TransformControllerDescriptor, graphics: Graphics, args: UpdateArgs) {
1324
+ let wrapper
1325
+ const service = graphics.traceService(descriptor)
1326
+ if (service instanceof SceneServiceDescriptor) {
1327
+ const interpreter = graphics.getInterpreter(service)
1328
+ const actor = interpreter.getActor<SceneServiceActor>(service, args)
1329
+ wrapper = actor.getWrapper()
1330
+ }
1331
+ return wrapper as HTMLElement
1332
+ }
1333
+
1334
+ private setCustomProperty(propName: string, defaultValue: any) {
1335
+ const scope = this as any
1336
+ scope[propName] = defaultValue
1337
+ scope._plane[propName] = defaultValue
1338
+ scope._gizmo[propName] = defaultValue
1339
+ }
1340
+
1341
+ // updateMatrixWorld updates key transformation variables
1342
+ updateMatrixWorld() {
1343
+ if (this.enabled === false) return
1344
+
1345
+ if (this.object !== undefined) {
1346
+ this.object.updateMatrixWorld()
1347
+ if (this.object.parent === null) {
1348
+ console.error(
1349
+ 'TransformControllerActor: The attached 3D object must be a part of the scene graph.'
1350
+ )
1351
+ } else {
1352
+ this.object.parent.matrixWorld.decompose(
1353
+ this._parentPosition,
1354
+ this._parentQuaternion,
1355
+ this._parentScale
1356
+ )
1357
+ }
1358
+
1359
+ this.object.matrixWorld.decompose(
1360
+ this.worldPosition,
1361
+ this.worldQuaternion,
1362
+ this._worldScale
1363
+ )
1364
+
1365
+ this._parentQuaternionInv.copy(this._parentQuaternion).invert()
1366
+ this._worldQuaternionInv.copy(this.worldQuaternion).invert()
1367
+ }
1368
+
1369
+ this.camera.updateMatrixWorld()
1370
+ this.camera.matrixWorld.decompose(
1371
+ this.cameraPosition,
1372
+ this.cameraQuaternion,
1373
+ this._cameraScale
1374
+ )
1375
+
1376
+ //@ts-ignore
1377
+ if (this.camera.isOrthographicCamera) {
1378
+ this.camera.getWorldDirection(this.eye).negate()
1379
+ } else {
1380
+ this.eye.copy(this.cameraPosition).sub(this.worldPosition).normalize()
1381
+ }
1382
+
1383
+ super.updateMatrixWorld(this)
1384
+ }
1385
+
1386
+ pointerHover(pointer) {
1387
+ if (this.object === undefined || this.dragging === true) return
1388
+
1389
+ _raycaster.setFromCamera(pointer, this.camera)
1390
+
1391
+ const intersect = intersectObjectWithRay(
1392
+ this._gizmo.picker[this.mode],
1393
+ _raycaster
1394
+ )
1395
+
1396
+ if (intersect) {
1397
+ this.axis = intersect.object.name
1398
+ } else {
1399
+ this.axis = null
1400
+ }
1401
+ }
1402
+
1403
+ pointerDown(pointer) {
1404
+ if (
1405
+ this.object === undefined ||
1406
+ this.dragging === true ||
1407
+ pointer.button !== 0
1408
+ )
1409
+ return
1410
+
1411
+ if (this.axis !== null) {
1412
+ _raycaster.setFromCamera(pointer, this.camera)
1413
+
1414
+ const planeIntersect = intersectObjectWithRay(
1415
+ this._plane,
1416
+ _raycaster,
1417
+ true
1418
+ )
1419
+
1420
+ if (planeIntersect) {
1421
+ this.object.updateMatrixWorld()
1422
+ this.object.parent.updateMatrixWorld()
1423
+
1424
+ this._positionStart.copy(this.object.position)
1425
+ this._quaternionStart.copy(this.object.quaternion)
1426
+ this._scaleStart.copy(this.object.scale)
1427
+
1428
+ this.object.matrixWorld.decompose(
1429
+ this.worldPositionStart,
1430
+ this.worldQuaternionStart,
1431
+ this._worldScaleStart
1432
+ )
1433
+
1434
+ this.pointStart.copy(planeIntersect.point).sub(this.worldPositionStart)
1435
+ }
1436
+
1437
+ this.dragging = true
1438
+ this.change('mousedown')
1439
+ }
1440
+ }
1441
+
1442
+ pointerMove(pointer) {
1443
+ const axis = this.axis
1444
+ const mode = this.mode
1445
+ const object = this.object
1446
+ let space = this.space
1447
+
1448
+ if (mode === 'scale') {
1449
+ space = 'local'
1450
+ } else if (axis === 'E' || axis === 'XYZE' || axis === 'XYZ') {
1451
+ space = 'world'
1452
+ }
1453
+
1454
+ if (
1455
+ object === undefined ||
1456
+ axis === null ||
1457
+ this.dragging === false ||
1458
+ pointer.button !== -1
1459
+ )
1460
+ return
1461
+
1462
+ _raycaster.setFromCamera(pointer, this.camera)
1463
+
1464
+ const planeIntersect = intersectObjectWithRay(this._plane, _raycaster, true)
1465
+
1466
+ if (!planeIntersect) return
1467
+
1468
+ this.pointEnd.copy(planeIntersect.point).sub(this.worldPositionStart)
1469
+
1470
+ if (mode === 'translate') {
1471
+ // Apply translate
1472
+
1473
+ this._offset.copy(this.pointEnd).sub(this.pointStart)
1474
+
1475
+ if (space === 'local' && axis !== 'XYZ') {
1476
+ this._offset.applyQuaternion(this._worldQuaternionInv)
1477
+ }
1478
+
1479
+ if (axis.indexOf('X') === -1) this._offset.x = 0
1480
+ if (axis.indexOf('Y') === -1) this._offset.y = 0
1481
+ if (axis.indexOf('Z') === -1) this._offset.z = 0
1482
+
1483
+ if (space === 'local' && axis !== 'XYZ') {
1484
+ this._offset
1485
+ .applyQuaternion(this._quaternionStart)
1486
+ .divide(this._parentScale)
1487
+ } else {
1488
+ this._offset
1489
+ .applyQuaternion(this._parentQuaternionInv)
1490
+ .divide(this._parentScale)
1491
+ }
1492
+
1493
+ object.position.copy(this._offset).add(this._positionStart)
1494
+
1495
+ // Apply translation snap
1496
+
1497
+ if (this.translationSnap) {
1498
+ if (space === 'local') {
1499
+ object.position.applyQuaternion(
1500
+ _tempQuaternion.copy(this._quaternionStart).invert()
1501
+ )
1502
+
1503
+ if (axis.search('X') !== -1) {
1504
+ object.position.x =
1505
+ Math.round(object.position.x / this.translationSnap) *
1506
+ this.translationSnap
1507
+ }
1508
+
1509
+ if (axis.search('Y') !== -1) {
1510
+ object.position.y =
1511
+ Math.round(object.position.y / this.translationSnap) *
1512
+ this.translationSnap
1513
+ }
1514
+
1515
+ if (axis.search('Z') !== -1) {
1516
+ object.position.z =
1517
+ Math.round(object.position.z / this.translationSnap) *
1518
+ this.translationSnap
1519
+ }
1520
+
1521
+ object.position.applyQuaternion(this._quaternionStart)
1522
+ }
1523
+
1524
+ if (space === 'world') {
1525
+ if (object.parent) {
1526
+ object.position.add(
1527
+ _tempVector.setFromMatrixPosition(object.parent.matrixWorld)
1528
+ )
1529
+ }
1530
+
1531
+ if (axis.search('X') !== -1) {
1532
+ object.position.x =
1533
+ Math.round(object.position.x / this.translationSnap) *
1534
+ this.translationSnap
1535
+ }
1536
+
1537
+ if (axis.search('Y') !== -1) {
1538
+ object.position.y =
1539
+ Math.round(object.position.y / this.translationSnap) *
1540
+ this.translationSnap
1541
+ }
1542
+
1543
+ if (axis.search('Z') !== -1) {
1544
+ object.position.z =
1545
+ Math.round(object.position.z / this.translationSnap) *
1546
+ this.translationSnap
1547
+ }
1548
+
1549
+ if (object.parent) {
1550
+ object.position.sub(
1551
+ _tempVector.setFromMatrixPosition(object.parent.matrixWorld)
1552
+ )
1553
+ }
1554
+ }
1555
+ }
1556
+ } else if (mode === 'scale') {
1557
+ if (axis.search('XYZ') !== -1) {
1558
+ let d = this.pointEnd.length() / this.pointStart.length()
1559
+
1560
+ if (this.pointEnd.dot(this.pointStart) < 0) d *= -1
1561
+
1562
+ _tempVector2.set(d, d, d)
1563
+ } else {
1564
+ _tempVector.copy(this.pointStart)
1565
+ _tempVector2.copy(this.pointEnd)
1566
+
1567
+ _tempVector.applyQuaternion(this._worldQuaternionInv)
1568
+ _tempVector2.applyQuaternion(this._worldQuaternionInv)
1569
+
1570
+ _tempVector2.divide(_tempVector)
1571
+
1572
+ if (axis.search('X') === -1) {
1573
+ _tempVector2.x = 1
1574
+ }
1575
+
1576
+ if (axis.search('Y') === -1) {
1577
+ _tempVector2.y = 1
1578
+ }
1579
+
1580
+ if (axis.search('Z') === -1) {
1581
+ _tempVector2.z = 1
1582
+ }
1583
+ }
1584
+
1585
+ // Apply scale
1586
+
1587
+ object.scale.copy(this._scaleStart).multiply(_tempVector2)
1588
+
1589
+ if (this.scaleSnap) {
1590
+ if (axis.search('X') !== -1) {
1591
+ object.scale.x =
1592
+ Math.round(object.scale.x / this.scaleSnap) * this.scaleSnap ||
1593
+ this.scaleSnap
1594
+ }
1595
+
1596
+ if (axis.search('Y') !== -1) {
1597
+ object.scale.y =
1598
+ Math.round(object.scale.y / this.scaleSnap) * this.scaleSnap ||
1599
+ this.scaleSnap
1600
+ }
1601
+
1602
+ if (axis.search('Z') !== -1) {
1603
+ object.scale.z =
1604
+ Math.round(object.scale.z / this.scaleSnap) * this.scaleSnap ||
1605
+ this.scaleSnap
1606
+ }
1607
+ }
1608
+ } else if (mode === 'rotate') {
1609
+ this._offset.copy(this.pointEnd).sub(this.pointStart)
1610
+
1611
+ const ROTATION_SPEED =
1612
+ 20 /
1613
+ this.worldPosition.distanceTo(
1614
+ _tempVector.setFromMatrixPosition(this.camera.matrixWorld)
1615
+ )
1616
+
1617
+ if (axis === 'E') {
1618
+ this.rotationAxis.copy(this.eye)
1619
+ this.rotationAngle = this.pointEnd.angleTo(this.pointStart)
1620
+
1621
+ this._startNorm.copy(this.pointStart).normalize()
1622
+ this._endNorm.copy(this.pointEnd).normalize()
1623
+
1624
+ this.rotationAngle *=
1625
+ this._endNorm.cross(this._startNorm).dot(this.eye) < 0 ? 1 : -1
1626
+ } else if (axis === 'XYZE') {
1627
+ this.rotationAxis.copy(this._offset).cross(this.eye).normalize()
1628
+ this.rotationAngle =
1629
+ this._offset.dot(
1630
+ _tempVector.copy(this.rotationAxis).cross(this.eye)
1631
+ ) * ROTATION_SPEED
1632
+ } else if (axis === 'X' || axis === 'Y' || axis === 'Z') {
1633
+ this.rotationAxis.copy(_unit[axis])
1634
+
1635
+ _tempVector.copy(_unit[axis])
1636
+
1637
+ if (space === 'local') {
1638
+ _tempVector.applyQuaternion(this.worldQuaternion)
1639
+ }
1640
+
1641
+ this.rotationAngle =
1642
+ this._offset.dot(_tempVector.cross(this.eye).normalize()) *
1643
+ ROTATION_SPEED
1644
+ }
1645
+
1646
+ // Apply rotation snap
1647
+
1648
+ if (this.rotationSnap)
1649
+ this.rotationAngle =
1650
+ Math.round(this.rotationAngle / this.rotationSnap) * this.rotationSnap
1651
+
1652
+ // Apply rotate
1653
+ if (space === 'local' && axis !== 'E' && axis !== 'XYZE') {
1654
+ object.quaternion.copy(this._quaternionStart)
1655
+ object.quaternion
1656
+ .multiply(
1657
+ _tempQuaternion.setFromAxisAngle(
1658
+ this.rotationAxis,
1659
+ this.rotationAngle
1660
+ )
1661
+ )
1662
+ .normalize()
1663
+ } else {
1664
+ this.rotationAxis.applyQuaternion(this._parentQuaternionInv)
1665
+ object.quaternion.copy(
1666
+ _tempQuaternion.setFromAxisAngle(
1667
+ this.rotationAxis,
1668
+ this.rotationAngle
1669
+ )
1670
+ )
1671
+ object.quaternion.multiply(this._quaternionStart).normalize()
1672
+ }
1673
+ }
1674
+
1675
+ this.change()
1676
+ }
1677
+
1678
+ pointerUp(pointer) {
1679
+ if (pointer.button !== 0) return
1680
+
1681
+ if (this.dragging && this.axis !== null) {
1682
+ this.change('mouseup')
1683
+ }
1684
+
1685
+ this.dragging = false
1686
+ this.axis = null
1687
+ }
1688
+
1689
+ // Set current object
1690
+ attach(object) {
1691
+ this.object = object
1692
+ this.visible = true
1693
+
1694
+ return this
1695
+ }
1696
+
1697
+ // Detach from object
1698
+ detach() {
1699
+ this.object = undefined
1700
+ this.visible = false
1701
+ this.axis = null
1702
+
1703
+ return this
1704
+ }
1705
+
1706
+ reset() {
1707
+ if (this.enabled === false) return
1708
+
1709
+ if (this.dragging) {
1710
+ this.object.position.copy(this._positionStart)
1711
+ this.object.quaternion.copy(this._quaternionStart)
1712
+ this.object.scale.copy(this._scaleStart)
1713
+
1714
+ this.change()
1715
+
1716
+ this.pointStart.copy(this.pointEnd)
1717
+ }
1718
+ }
1719
+
1720
+ getRaycaster() {
1721
+ return _raycaster
1722
+ }
1723
+
1724
+ setTranslationSnap(translationSnap) {
1725
+ this.translationSnap = translationSnap
1726
+ }
1727
+
1728
+ setRotationSnap(rotationSnap) {
1729
+ this.rotationSnap = rotationSnap
1730
+ }
1731
+
1732
+ setScaleSnap(scaleSnap) {
1733
+ this.scaleSnap = scaleSnap
1734
+ }
1735
+
1736
+ setSize(size) {
1737
+ this.size = size
1738
+ }
1739
+
1740
+ setSpace(space) {
1741
+ this.space = space
1742
+ }
1743
+ }
1744
+
1745
+ export {
1746
+ TransformControls
1747
+ }