@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.
- package/package.json +26 -0
- package/src/actor/ComposerServiceActor.ts +107 -0
- package/src/actor/GeometryActor.ts +13 -0
- package/src/actor/HTMLConvertActor.ts +55 -0
- package/src/actor/MaterialActor.ts +13 -0
- package/src/actor/NodeActor.ts +25 -0
- package/src/actor/OrbitControllerActor.ts +110 -0
- package/src/actor/PassActor.ts +24 -0
- package/src/actor/SceneServiceActor.ts +122 -0
- package/src/actor/TextureActor.ts +13 -0
- package/src/actor/TransformControllerActor.ts +23 -0
- package/src/actor/index.ts +10 -0
- package/src/asset/index.ts +187 -0
- package/src/controls/CameraControls.ts +2360 -0
- package/src/controls/TransformControls.ts +1747 -0
- package/src/controls/index.ts +2 -0
- package/src/descriptor/ComposerServiceDescriptor.ts +47 -0
- package/src/descriptor/GeoMapDescriptor.ts +24 -0
- package/src/descriptor/HTMLConvertDescriptor.ts +12 -0
- package/src/descriptor/InstancedMeshDescriptor.ts +21 -0
- package/src/descriptor/MeshDescriptor.ts +16 -0
- package/src/descriptor/ModelDescriptor.ts +15 -0
- package/src/descriptor/OrbitControllerDescriptor.ts +84 -0
- package/src/descriptor/OrthographicCameraDescriptor.ts +12 -0
- package/src/descriptor/ParticleDescriptor.ts +88 -0
- package/src/descriptor/PassDescriptor.ts +33 -0
- package/src/descriptor/PerspectiveCameraDescriptor.ts +15 -0
- package/src/descriptor/PointsDescriptor.ts +16 -0
- package/src/descriptor/SceneServiceDescriptor.ts +39 -0
- package/src/descriptor/SpriteDescriptor.ts +16 -0
- package/src/descriptor/TextDescriptor.ts +41 -0
- package/src/descriptor/TransformControllerDescriptor.ts +32 -0
- package/src/descriptor/animation/AnimationActionDescriptor.ts +52 -0
- package/src/descriptor/geometry/BoxGeometryDescriptor.ts +26 -0
- package/src/descriptor/geometry/BufferGeometryDescriptor.ts +15 -0
- package/src/descriptor/geometry/CircleGeometryDescriptor.ts +22 -0
- package/src/descriptor/geometry/CylinderGeometryDescriptor.ts +30 -0
- package/src/descriptor/geometry/ExtrudeGeometryDescriptor.ts +35 -0
- package/src/descriptor/geometry/GeometryDescriptor.ts +8 -0
- package/src/descriptor/geometry/PlaneGeometryDescriptor.ts +22 -0
- package/src/descriptor/geometry/RingGeometryDescriptor.ts +26 -0
- package/src/descriptor/geometry/SphereGeometryDescriptor.ts +27 -0
- package/src/descriptor/geometry/SurfaceGeometryDescriptor.ts +15 -0
- package/src/descriptor/geometry/TubeGeometryDescriptor.ts +25 -0
- package/src/descriptor/helper/AxesHelperDescriptor.ts +8 -0
- package/src/descriptor/index.ts +45 -0
- package/src/descriptor/light/AmbientLightDescriptor.ts +8 -0
- package/src/descriptor/light/DirectionalLightDescriptor.ts +33 -0
- package/src/descriptor/light/HemisphereLightDescriptor.ts +16 -0
- package/src/descriptor/light/LightDescriptor.ts +16 -0
- package/src/descriptor/light/PointLightDescriptor.ts +24 -0
- package/src/descriptor/light/RectAreaLightDescriptor.ts +20 -0
- package/src/descriptor/light/SpotLightDescriptor.ts +30 -0
- package/src/descriptor/material/MaterialDescriptor.ts +84 -0
- package/src/descriptor/material/MeshBasicMaterialDescriptor.ts +53 -0
- package/src/descriptor/material/MeshPhongMaterialDescriptor.ts +102 -0
- package/src/descriptor/material/MeshStandardMaterialDescriptor.ts +99 -0
- package/src/descriptor/material/PointsMaterialDescriptor.ts +31 -0
- package/src/descriptor/material/ShaderMaterialDescriptor.ts +35 -0
- package/src/descriptor/material/ShadowMaterialDescriptor.ts +19 -0
- package/src/descriptor/material/SpriteMaterialDescriptor.ts +31 -0
- package/src/descriptor/texture/TextureDescriptor.ts +110 -0
- package/src/index.ts +9 -0
- package/src/interpreter/ComposerServiceInterpreter.ts +25 -0
- package/src/interpreter/GeoMapInterpreter.ts +253 -0
- package/src/interpreter/HTMLConvertInterpreter.ts +31 -0
- package/src/interpreter/InstancedMeshInterpreter.ts +76 -0
- package/src/interpreter/MeshInterpreter.ts +25 -0
- package/src/interpreter/ModelInterpreter.ts +61 -0
- package/src/interpreter/NodeInterpreter.ts +65 -0
- package/src/interpreter/OrbitControllerInterpreter.ts +47 -0
- package/src/interpreter/OrthographicCameraInterpreter.ts +13 -0
- package/src/interpreter/ParticleInterpreter.ts +221 -0
- package/src/interpreter/PassInterpreter.ts +43 -0
- package/src/interpreter/PerspectiveCameraInterpreter.ts +33 -0
- package/src/interpreter/PointsInterpreter.ts +61 -0
- package/src/interpreter/SceneServiceInterpreter.ts +119 -0
- package/src/interpreter/ServiceSchedulerInterpreter.ts +23 -0
- package/src/interpreter/SpriteInterpreter.ts +45 -0
- package/src/interpreter/TextInterpreter.ts +76 -0
- package/src/interpreter/TransformControllerInterpreter.ts +44 -0
- package/src/interpreter/animation/AnimationActionInterpreter.ts +66 -0
- package/src/interpreter/geometry/BoxGeometryInterpreter.ts +34 -0
- package/src/interpreter/geometry/BufferGeometryInterpreter.ts +47 -0
- package/src/interpreter/geometry/CircleGeometryInterpreter.ts +34 -0
- package/src/interpreter/geometry/CylinderGeometryInterpreter.ts +34 -0
- package/src/interpreter/geometry/ExtrudeGeometryInterpreter.ts +55 -0
- package/src/interpreter/geometry/PlaneGeometryInterpreter.ts +34 -0
- package/src/interpreter/geometry/RingGeometryInterpreter.ts +34 -0
- package/src/interpreter/geometry/SphereGeometryInterpreter.ts +34 -0
- package/src/interpreter/geometry/SurfaceGeometryInterpreter.ts +39 -0
- package/src/interpreter/geometry/TubeGeometryInterpreter.ts +42 -0
- package/src/interpreter/helper/AxesHelperInterpreter.ts +38 -0
- package/src/interpreter/index.ts +45 -0
- package/src/interpreter/light/AmbientLightInterpreter.ts +30 -0
- package/src/interpreter/light/DirectionalLightInterpreter.ts +84 -0
- package/src/interpreter/light/HemisphereLightInterpreter.ts +32 -0
- package/src/interpreter/light/PointLightInterpreter.ts +46 -0
- package/src/interpreter/light/RectAreaLightInterpreter.ts +34 -0
- package/src/interpreter/light/SpotLightInterpreter.ts +68 -0
- package/src/interpreter/material/MaterialInterpreter.ts +34 -0
- package/src/interpreter/material/MeshBasicMaterialInterpreter.ts +43 -0
- package/src/interpreter/material/MeshPhongMaterialInterpreter.ts +63 -0
- package/src/interpreter/material/MeshStandardMaterialInterpreter.ts +58 -0
- package/src/interpreter/material/PointsMaterialInterpreter.ts +36 -0
- package/src/interpreter/material/ShaderMaterialInterpreter.ts +51 -0
- package/src/interpreter/material/ShadowMaterialInterpreter.ts +31 -0
- package/src/interpreter/material/SpriteMaterialInterpreter.ts +36 -0
- package/src/interpreter/texture/TextureInterpreter.ts +59 -0
- package/src/locale/Language.ts +10 -0
- package/src/locale/LanguageProvider.ts +16 -0
- package/src/locale/index.ts +2 -0
- package/src/preset/execute/GeoMap/drilldown.ts +61 -0
- package/src/preset/execute/GeoMap/index.ts +1 -0
- package/src/preset/execute/index.ts +1 -0
- package/src/preset/index.ts +7 -0
- package/src/preset/routine/GeoMap/drilldown.ts +26 -0
- package/src/preset/routine/GeoMap/index.ts +1 -0
- package/src/preset/routine/index.ts +1 -0
- package/src/utils/dispose/index.ts +23 -0
- package/src/utils/geometry/index.ts +82 -0
- package/src/utils/index.ts +7 -0
- package/src/utils/material/index.ts +53 -0
- package/src/utils/pickup/index.ts +16 -0
- package/src/utils/random/index.ts +7 -0
- package/src/utils/text/index.ts +492 -0
- 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
|
+
}
|