@2112-lab/central-plant 0.1.0
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/README.md +0 -0
- package/dist/bundle/index.js +14259 -0
- package/dist/cjs/_virtual/_rollupPluginBabelHelpers.js +353 -0
- package/dist/cjs/node_modules/three/examples/jsm/controls/OrbitControls.js +1292 -0
- package/dist/cjs/node_modules/three/examples/jsm/controls/TransformControls.js +1543 -0
- package/dist/cjs/node_modules/three/examples/jsm/loaders/GLTFLoader.js +4374 -0
- package/dist/cjs/node_modules/three/examples/jsm/loaders/RGBELoader.js +465 -0
- package/dist/cjs/node_modules/three/examples/jsm/utils/BufferGeometryUtils.js +117 -0
- package/dist/cjs/src/ConnectionManager.js +114 -0
- package/dist/cjs/src/Pathfinder.js +88 -0
- package/dist/cjs/src/animationManager.js +121 -0
- package/dist/cjs/src/componentManager.js +151 -0
- package/dist/cjs/src/debugLogger.js +176 -0
- package/dist/cjs/src/disposalManager.js +185 -0
- package/dist/cjs/src/environmentManager.js +1015 -0
- package/dist/cjs/src/hotReloadManager.js +252 -0
- package/dist/cjs/src/index.js +126 -0
- package/dist/cjs/src/keyboardControlsManager.js +206 -0
- package/dist/cjs/src/modelPreloader.js +360 -0
- package/dist/cjs/src/nameUtils.js +106 -0
- package/dist/cjs/src/pathfindingManager.js +321 -0
- package/dist/cjs/src/performanceMonitor.js +718 -0
- package/dist/cjs/src/sceneExportManager.js +292 -0
- package/dist/cjs/src/sceneInitializationManager.js +540 -0
- package/dist/cjs/src/sceneOperationsManager.js +560 -0
- package/dist/cjs/src/textureConfig.js +195 -0
- package/dist/cjs/src/transformControlsManager.js +851 -0
- package/dist/esm/_virtual/_rollupPluginBabelHelpers.js +328 -0
- package/dist/esm/node_modules/three/examples/jsm/controls/OrbitControls.js +1287 -0
- package/dist/esm/node_modules/three/examples/jsm/controls/TransformControls.js +1537 -0
- package/dist/esm/node_modules/three/examples/jsm/loaders/GLTFLoader.js +4370 -0
- package/dist/esm/node_modules/three/examples/jsm/loaders/RGBELoader.js +461 -0
- package/dist/esm/node_modules/three/examples/jsm/utils/BufferGeometryUtils.js +113 -0
- package/dist/esm/src/ConnectionManager.js +110 -0
- package/dist/esm/src/Pathfinder.js +84 -0
- package/dist/esm/src/animationManager.js +112 -0
- package/dist/esm/src/componentManager.js +123 -0
- package/dist/esm/src/debugLogger.js +167 -0
- package/dist/esm/src/disposalManager.js +155 -0
- package/dist/esm/src/environmentManager.js +989 -0
- package/dist/esm/src/hotReloadManager.js +244 -0
- package/dist/esm/src/index.js +117 -0
- package/dist/esm/src/keyboardControlsManager.js +196 -0
- package/dist/esm/src/modelPreloader.js +337 -0
- package/dist/esm/src/nameUtils.js +99 -0
- package/dist/esm/src/pathfindingManager.js +295 -0
- package/dist/esm/src/performanceMonitor.js +712 -0
- package/dist/esm/src/sceneExportManager.js +286 -0
- package/dist/esm/src/sceneInitializationManager.js +513 -0
- package/dist/esm/src/sceneOperationsManager.js +536 -0
- package/dist/esm/src/textureConfig.js +168 -0
- package/dist/esm/src/transformControlsManager.js +827 -0
- package/dist/index.d.ts +259 -0
- package/package.json +53 -0
|
@@ -0,0 +1,1537 @@
|
|
|
1
|
+
import { Raycaster, Vector3, Quaternion, Object3D, Euler, Matrix4, MeshBasicMaterial, LineBasicMaterial, CylinderGeometry, BoxGeometry, BufferGeometry, Float32BufferAttribute, Mesh, OctahedronGeometry, Line, SphereGeometry, TorusGeometry, PlaneGeometry, DoubleSide } from 'three';
|
|
2
|
+
|
|
3
|
+
const _raycaster = new Raycaster();
|
|
4
|
+
|
|
5
|
+
const _tempVector = new Vector3();
|
|
6
|
+
const _tempVector2 = new Vector3();
|
|
7
|
+
const _tempQuaternion = new Quaternion();
|
|
8
|
+
const _unit = {
|
|
9
|
+
X: new Vector3( 1, 0, 0 ),
|
|
10
|
+
Y: new Vector3( 0, 1, 0 ),
|
|
11
|
+
Z: new Vector3( 0, 0, 1 )
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const _changeEvent = { type: 'change' };
|
|
15
|
+
const _mouseDownEvent = { type: 'mouseDown' };
|
|
16
|
+
const _mouseUpEvent = { type: 'mouseUp', mode: null };
|
|
17
|
+
const _objectChangeEvent = { type: 'objectChange' };
|
|
18
|
+
|
|
19
|
+
class TransformControls extends Object3D {
|
|
20
|
+
|
|
21
|
+
constructor( camera, domElement ) {
|
|
22
|
+
|
|
23
|
+
super();
|
|
24
|
+
|
|
25
|
+
if ( domElement === undefined ) {
|
|
26
|
+
|
|
27
|
+
console.warn( 'THREE.TransformControls: The second parameter "domElement" is now mandatory.' );
|
|
28
|
+
domElement = document;
|
|
29
|
+
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
this.isTransformControls = true;
|
|
33
|
+
|
|
34
|
+
this.visible = false;
|
|
35
|
+
this.domElement = domElement;
|
|
36
|
+
this.domElement.style.touchAction = 'none'; // disable touch scroll
|
|
37
|
+
|
|
38
|
+
const _gizmo = new TransformControlsGizmo();
|
|
39
|
+
this._gizmo = _gizmo;
|
|
40
|
+
this.add( _gizmo );
|
|
41
|
+
|
|
42
|
+
const _plane = new TransformControlsPlane();
|
|
43
|
+
this._plane = _plane;
|
|
44
|
+
this.add( _plane );
|
|
45
|
+
|
|
46
|
+
const scope = this;
|
|
47
|
+
|
|
48
|
+
// Defined getter, setter and store for a property
|
|
49
|
+
function defineProperty( propName, defaultValue ) {
|
|
50
|
+
|
|
51
|
+
let propValue = defaultValue;
|
|
52
|
+
|
|
53
|
+
Object.defineProperty( scope, propName, {
|
|
54
|
+
|
|
55
|
+
get: function () {
|
|
56
|
+
|
|
57
|
+
return propValue !== undefined ? propValue : defaultValue;
|
|
58
|
+
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
set: function ( value ) {
|
|
62
|
+
|
|
63
|
+
if ( propValue !== value ) {
|
|
64
|
+
|
|
65
|
+
propValue = value;
|
|
66
|
+
_plane[ propName ] = value;
|
|
67
|
+
_gizmo[ propName ] = value;
|
|
68
|
+
|
|
69
|
+
scope.dispatchEvent( { type: propName + '-changed', value: value } );
|
|
70
|
+
scope.dispatchEvent( _changeEvent );
|
|
71
|
+
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
} );
|
|
77
|
+
|
|
78
|
+
scope[ propName ] = defaultValue;
|
|
79
|
+
_plane[ propName ] = defaultValue;
|
|
80
|
+
_gizmo[ propName ] = defaultValue;
|
|
81
|
+
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Define properties with getters/setter
|
|
85
|
+
// Setting the defined property will automatically trigger change event
|
|
86
|
+
// Defined properties are passed down to gizmo and plane
|
|
87
|
+
|
|
88
|
+
defineProperty( 'camera', camera );
|
|
89
|
+
defineProperty( 'object', undefined );
|
|
90
|
+
defineProperty( 'enabled', true );
|
|
91
|
+
defineProperty( 'axis', null );
|
|
92
|
+
defineProperty( 'mode', 'translate' );
|
|
93
|
+
defineProperty( 'translationSnap', null );
|
|
94
|
+
defineProperty( 'rotationSnap', null );
|
|
95
|
+
defineProperty( 'scaleSnap', null );
|
|
96
|
+
defineProperty( 'space', 'world' );
|
|
97
|
+
defineProperty( 'size', 1 );
|
|
98
|
+
defineProperty( 'dragging', false );
|
|
99
|
+
defineProperty( 'showX', true );
|
|
100
|
+
defineProperty( 'showY', true );
|
|
101
|
+
defineProperty( 'showZ', true );
|
|
102
|
+
|
|
103
|
+
// Reusable utility variables
|
|
104
|
+
|
|
105
|
+
const worldPosition = new Vector3();
|
|
106
|
+
const worldPositionStart = new Vector3();
|
|
107
|
+
const worldQuaternion = new Quaternion();
|
|
108
|
+
const worldQuaternionStart = new Quaternion();
|
|
109
|
+
const cameraPosition = new Vector3();
|
|
110
|
+
const cameraQuaternion = new Quaternion();
|
|
111
|
+
const pointStart = new Vector3();
|
|
112
|
+
const pointEnd = new Vector3();
|
|
113
|
+
const rotationAxis = new Vector3();
|
|
114
|
+
const rotationAngle = 0;
|
|
115
|
+
const eye = new Vector3();
|
|
116
|
+
|
|
117
|
+
// TODO: remove properties unused in plane and gizmo
|
|
118
|
+
|
|
119
|
+
defineProperty( 'worldPosition', worldPosition );
|
|
120
|
+
defineProperty( 'worldPositionStart', worldPositionStart );
|
|
121
|
+
defineProperty( 'worldQuaternion', worldQuaternion );
|
|
122
|
+
defineProperty( 'worldQuaternionStart', worldQuaternionStart );
|
|
123
|
+
defineProperty( 'cameraPosition', cameraPosition );
|
|
124
|
+
defineProperty( 'cameraQuaternion', cameraQuaternion );
|
|
125
|
+
defineProperty( 'pointStart', pointStart );
|
|
126
|
+
defineProperty( 'pointEnd', pointEnd );
|
|
127
|
+
defineProperty( 'rotationAxis', rotationAxis );
|
|
128
|
+
defineProperty( 'rotationAngle', rotationAngle );
|
|
129
|
+
defineProperty( 'eye', eye );
|
|
130
|
+
|
|
131
|
+
this._offset = new Vector3();
|
|
132
|
+
this._startNorm = new Vector3();
|
|
133
|
+
this._endNorm = new Vector3();
|
|
134
|
+
this._cameraScale = new Vector3();
|
|
135
|
+
|
|
136
|
+
this._parentPosition = new Vector3();
|
|
137
|
+
this._parentQuaternion = new Quaternion();
|
|
138
|
+
this._parentQuaternionInv = new Quaternion();
|
|
139
|
+
this._parentScale = new Vector3();
|
|
140
|
+
|
|
141
|
+
this._worldScaleStart = new Vector3();
|
|
142
|
+
this._worldQuaternionInv = new Quaternion();
|
|
143
|
+
this._worldScale = new Vector3();
|
|
144
|
+
|
|
145
|
+
this._positionStart = new Vector3();
|
|
146
|
+
this._quaternionStart = new Quaternion();
|
|
147
|
+
this._scaleStart = new Vector3();
|
|
148
|
+
|
|
149
|
+
this._getPointer = getPointer.bind( this );
|
|
150
|
+
this._onPointerDown = onPointerDown.bind( this );
|
|
151
|
+
this._onPointerHover = onPointerHover.bind( this );
|
|
152
|
+
this._onPointerMove = onPointerMove.bind( this );
|
|
153
|
+
this._onPointerUp = onPointerUp.bind( this );
|
|
154
|
+
|
|
155
|
+
this.domElement.addEventListener( 'pointerdown', this._onPointerDown );
|
|
156
|
+
this.domElement.addEventListener( 'pointermove', this._onPointerHover );
|
|
157
|
+
this.domElement.addEventListener( 'pointerup', this._onPointerUp );
|
|
158
|
+
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// updateMatrixWorld updates key transformation variables
|
|
162
|
+
updateMatrixWorld() {
|
|
163
|
+
|
|
164
|
+
if ( this.object !== undefined ) {
|
|
165
|
+
|
|
166
|
+
this.object.updateMatrixWorld();
|
|
167
|
+
|
|
168
|
+
if ( this.object.parent === null ) {
|
|
169
|
+
|
|
170
|
+
console.error( 'TransformControls: The attached 3D object must be a part of the scene graph.' );
|
|
171
|
+
|
|
172
|
+
} else {
|
|
173
|
+
|
|
174
|
+
this.object.parent.matrixWorld.decompose( this._parentPosition, this._parentQuaternion, this._parentScale );
|
|
175
|
+
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
this.object.matrixWorld.decompose( this.worldPosition, this.worldQuaternion, this._worldScale );
|
|
179
|
+
|
|
180
|
+
this._parentQuaternionInv.copy( this._parentQuaternion ).invert();
|
|
181
|
+
this._worldQuaternionInv.copy( this.worldQuaternion ).invert();
|
|
182
|
+
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
this.camera.updateMatrixWorld();
|
|
186
|
+
this.camera.matrixWorld.decompose( this.cameraPosition, this.cameraQuaternion, this._cameraScale );
|
|
187
|
+
|
|
188
|
+
if ( this.camera.isOrthographicCamera ) {
|
|
189
|
+
|
|
190
|
+
this.camera.getWorldDirection( this.eye ).negate();
|
|
191
|
+
|
|
192
|
+
} else {
|
|
193
|
+
|
|
194
|
+
this.eye.copy( this.cameraPosition ).sub( this.worldPosition ).normalize();
|
|
195
|
+
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
super.updateMatrixWorld( this );
|
|
199
|
+
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
pointerHover( pointer ) {
|
|
203
|
+
|
|
204
|
+
if ( this.object === undefined || this.dragging === true ) return;
|
|
205
|
+
|
|
206
|
+
_raycaster.setFromCamera( pointer, this.camera );
|
|
207
|
+
|
|
208
|
+
const intersect = intersectObjectWithRay( this._gizmo.picker[ this.mode ], _raycaster );
|
|
209
|
+
|
|
210
|
+
if ( intersect ) {
|
|
211
|
+
|
|
212
|
+
this.axis = intersect.object.name;
|
|
213
|
+
|
|
214
|
+
} else {
|
|
215
|
+
|
|
216
|
+
this.axis = null;
|
|
217
|
+
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
pointerDown( pointer ) {
|
|
223
|
+
|
|
224
|
+
if ( this.object === undefined || this.dragging === true || pointer.button !== 0 ) return;
|
|
225
|
+
|
|
226
|
+
if ( this.axis !== null ) {
|
|
227
|
+
|
|
228
|
+
_raycaster.setFromCamera( pointer, this.camera );
|
|
229
|
+
|
|
230
|
+
const planeIntersect = intersectObjectWithRay( this._plane, _raycaster, true );
|
|
231
|
+
|
|
232
|
+
if ( planeIntersect ) {
|
|
233
|
+
|
|
234
|
+
this.object.updateMatrixWorld();
|
|
235
|
+
this.object.parent.updateMatrixWorld();
|
|
236
|
+
|
|
237
|
+
this._positionStart.copy( this.object.position );
|
|
238
|
+
this._quaternionStart.copy( this.object.quaternion );
|
|
239
|
+
this._scaleStart.copy( this.object.scale );
|
|
240
|
+
|
|
241
|
+
this.object.matrixWorld.decompose( this.worldPositionStart, this.worldQuaternionStart, this._worldScaleStart );
|
|
242
|
+
|
|
243
|
+
this.pointStart.copy( planeIntersect.point ).sub( this.worldPositionStart );
|
|
244
|
+
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
this.dragging = true;
|
|
248
|
+
_mouseDownEvent.mode = this.mode;
|
|
249
|
+
this.dispatchEvent( _mouseDownEvent );
|
|
250
|
+
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
pointerMove( pointer ) {
|
|
256
|
+
|
|
257
|
+
const axis = this.axis;
|
|
258
|
+
const mode = this.mode;
|
|
259
|
+
const object = this.object;
|
|
260
|
+
let space = this.space;
|
|
261
|
+
|
|
262
|
+
if ( mode === 'scale' ) {
|
|
263
|
+
|
|
264
|
+
space = 'local';
|
|
265
|
+
|
|
266
|
+
} else if ( axis === 'E' || axis === 'XYZE' || axis === 'XYZ' ) {
|
|
267
|
+
|
|
268
|
+
space = 'world';
|
|
269
|
+
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
if ( object === undefined || axis === null || this.dragging === false || pointer.button !== - 1 ) return;
|
|
273
|
+
|
|
274
|
+
_raycaster.setFromCamera( pointer, this.camera );
|
|
275
|
+
|
|
276
|
+
const planeIntersect = intersectObjectWithRay( this._plane, _raycaster, true );
|
|
277
|
+
|
|
278
|
+
if ( ! planeIntersect ) return;
|
|
279
|
+
|
|
280
|
+
this.pointEnd.copy( planeIntersect.point ).sub( this.worldPositionStart );
|
|
281
|
+
|
|
282
|
+
if ( mode === 'translate' ) {
|
|
283
|
+
|
|
284
|
+
// Apply translate
|
|
285
|
+
|
|
286
|
+
this._offset.copy( this.pointEnd ).sub( this.pointStart );
|
|
287
|
+
|
|
288
|
+
if ( space === 'local' && axis !== 'XYZ' ) {
|
|
289
|
+
|
|
290
|
+
this._offset.applyQuaternion( this._worldQuaternionInv );
|
|
291
|
+
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
if ( axis.indexOf( 'X' ) === - 1 ) this._offset.x = 0;
|
|
295
|
+
if ( axis.indexOf( 'Y' ) === - 1 ) this._offset.y = 0;
|
|
296
|
+
if ( axis.indexOf( 'Z' ) === - 1 ) this._offset.z = 0;
|
|
297
|
+
|
|
298
|
+
if ( space === 'local' && axis !== 'XYZ' ) {
|
|
299
|
+
|
|
300
|
+
this._offset.applyQuaternion( this._quaternionStart ).divide( this._parentScale );
|
|
301
|
+
|
|
302
|
+
} else {
|
|
303
|
+
|
|
304
|
+
this._offset.applyQuaternion( this._parentQuaternionInv ).divide( this._parentScale );
|
|
305
|
+
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
object.position.copy( this._offset ).add( this._positionStart );
|
|
309
|
+
|
|
310
|
+
// Apply translation snap
|
|
311
|
+
|
|
312
|
+
if ( this.translationSnap ) {
|
|
313
|
+
|
|
314
|
+
if ( space === 'local' ) {
|
|
315
|
+
|
|
316
|
+
object.position.applyQuaternion( _tempQuaternion.copy( this._quaternionStart ).invert() );
|
|
317
|
+
|
|
318
|
+
if ( axis.search( 'X' ) !== - 1 ) {
|
|
319
|
+
|
|
320
|
+
object.position.x = Math.round( object.position.x / this.translationSnap ) * this.translationSnap;
|
|
321
|
+
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
if ( axis.search( 'Y' ) !== - 1 ) {
|
|
325
|
+
|
|
326
|
+
object.position.y = Math.round( object.position.y / this.translationSnap ) * this.translationSnap;
|
|
327
|
+
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
if ( axis.search( 'Z' ) !== - 1 ) {
|
|
331
|
+
|
|
332
|
+
object.position.z = Math.round( object.position.z / this.translationSnap ) * this.translationSnap;
|
|
333
|
+
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
object.position.applyQuaternion( this._quaternionStart );
|
|
337
|
+
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
if ( space === 'world' ) {
|
|
341
|
+
|
|
342
|
+
if ( object.parent ) {
|
|
343
|
+
|
|
344
|
+
object.position.add( _tempVector.setFromMatrixPosition( object.parent.matrixWorld ) );
|
|
345
|
+
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
if ( axis.search( 'X' ) !== - 1 ) {
|
|
349
|
+
|
|
350
|
+
object.position.x = Math.round( object.position.x / this.translationSnap ) * this.translationSnap;
|
|
351
|
+
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
if ( axis.search( 'Y' ) !== - 1 ) {
|
|
355
|
+
|
|
356
|
+
object.position.y = Math.round( object.position.y / this.translationSnap ) * this.translationSnap;
|
|
357
|
+
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
if ( axis.search( 'Z' ) !== - 1 ) {
|
|
361
|
+
|
|
362
|
+
object.position.z = Math.round( object.position.z / this.translationSnap ) * this.translationSnap;
|
|
363
|
+
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
if ( object.parent ) {
|
|
367
|
+
|
|
368
|
+
object.position.sub( _tempVector.setFromMatrixPosition( object.parent.matrixWorld ) );
|
|
369
|
+
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
} else if ( mode === 'scale' ) {
|
|
377
|
+
|
|
378
|
+
if ( axis.search( 'XYZ' ) !== - 1 ) {
|
|
379
|
+
|
|
380
|
+
let d = this.pointEnd.length() / this.pointStart.length();
|
|
381
|
+
|
|
382
|
+
if ( this.pointEnd.dot( this.pointStart ) < 0 ) d *= - 1;
|
|
383
|
+
|
|
384
|
+
_tempVector2.set( d, d, d );
|
|
385
|
+
|
|
386
|
+
} else {
|
|
387
|
+
|
|
388
|
+
_tempVector.copy( this.pointStart );
|
|
389
|
+
_tempVector2.copy( this.pointEnd );
|
|
390
|
+
|
|
391
|
+
_tempVector.applyQuaternion( this._worldQuaternionInv );
|
|
392
|
+
_tempVector2.applyQuaternion( this._worldQuaternionInv );
|
|
393
|
+
|
|
394
|
+
_tempVector2.divide( _tempVector );
|
|
395
|
+
|
|
396
|
+
if ( axis.search( 'X' ) === - 1 ) {
|
|
397
|
+
|
|
398
|
+
_tempVector2.x = 1;
|
|
399
|
+
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
if ( axis.search( 'Y' ) === - 1 ) {
|
|
403
|
+
|
|
404
|
+
_tempVector2.y = 1;
|
|
405
|
+
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
if ( axis.search( 'Z' ) === - 1 ) {
|
|
409
|
+
|
|
410
|
+
_tempVector2.z = 1;
|
|
411
|
+
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// Apply scale
|
|
417
|
+
|
|
418
|
+
object.scale.copy( this._scaleStart ).multiply( _tempVector2 );
|
|
419
|
+
|
|
420
|
+
if ( this.scaleSnap ) {
|
|
421
|
+
|
|
422
|
+
if ( axis.search( 'X' ) !== - 1 ) {
|
|
423
|
+
|
|
424
|
+
object.scale.x = Math.round( object.scale.x / this.scaleSnap ) * this.scaleSnap || this.scaleSnap;
|
|
425
|
+
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
if ( axis.search( 'Y' ) !== - 1 ) {
|
|
429
|
+
|
|
430
|
+
object.scale.y = Math.round( object.scale.y / this.scaleSnap ) * this.scaleSnap || this.scaleSnap;
|
|
431
|
+
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
if ( axis.search( 'Z' ) !== - 1 ) {
|
|
435
|
+
|
|
436
|
+
object.scale.z = Math.round( object.scale.z / this.scaleSnap ) * this.scaleSnap || this.scaleSnap;
|
|
437
|
+
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
} else if ( mode === 'rotate' ) {
|
|
443
|
+
|
|
444
|
+
this._offset.copy( this.pointEnd ).sub( this.pointStart );
|
|
445
|
+
|
|
446
|
+
const ROTATION_SPEED = 20 / this.worldPosition.distanceTo( _tempVector.setFromMatrixPosition( this.camera.matrixWorld ) );
|
|
447
|
+
|
|
448
|
+
if ( axis === 'E' ) {
|
|
449
|
+
|
|
450
|
+
this.rotationAxis.copy( this.eye );
|
|
451
|
+
this.rotationAngle = this.pointEnd.angleTo( this.pointStart );
|
|
452
|
+
|
|
453
|
+
this._startNorm.copy( this.pointStart ).normalize();
|
|
454
|
+
this._endNorm.copy( this.pointEnd ).normalize();
|
|
455
|
+
|
|
456
|
+
this.rotationAngle *= ( this._endNorm.cross( this._startNorm ).dot( this.eye ) < 0 ? 1 : - 1 );
|
|
457
|
+
|
|
458
|
+
} else if ( axis === 'XYZE' ) {
|
|
459
|
+
|
|
460
|
+
this.rotationAxis.copy( this._offset ).cross( this.eye ).normalize();
|
|
461
|
+
this.rotationAngle = this._offset.dot( _tempVector.copy( this.rotationAxis ).cross( this.eye ) ) * ROTATION_SPEED;
|
|
462
|
+
|
|
463
|
+
} else if ( axis === 'X' || axis === 'Y' || axis === 'Z' ) {
|
|
464
|
+
|
|
465
|
+
this.rotationAxis.copy( _unit[ axis ] );
|
|
466
|
+
|
|
467
|
+
_tempVector.copy( _unit[ axis ] );
|
|
468
|
+
|
|
469
|
+
if ( space === 'local' ) {
|
|
470
|
+
|
|
471
|
+
_tempVector.applyQuaternion( this.worldQuaternion );
|
|
472
|
+
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
this.rotationAngle = this._offset.dot( _tempVector.cross( this.eye ).normalize() ) * ROTATION_SPEED;
|
|
476
|
+
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
// Apply rotation snap
|
|
480
|
+
|
|
481
|
+
if ( this.rotationSnap ) this.rotationAngle = Math.round( this.rotationAngle / this.rotationSnap ) * this.rotationSnap;
|
|
482
|
+
|
|
483
|
+
// Apply rotate
|
|
484
|
+
if ( space === 'local' && axis !== 'E' && axis !== 'XYZE' ) {
|
|
485
|
+
|
|
486
|
+
object.quaternion.copy( this._quaternionStart );
|
|
487
|
+
object.quaternion.multiply( _tempQuaternion.setFromAxisAngle( this.rotationAxis, this.rotationAngle ) ).normalize();
|
|
488
|
+
|
|
489
|
+
} else {
|
|
490
|
+
|
|
491
|
+
this.rotationAxis.applyQuaternion( this._parentQuaternionInv );
|
|
492
|
+
object.quaternion.copy( _tempQuaternion.setFromAxisAngle( this.rotationAxis, this.rotationAngle ) );
|
|
493
|
+
object.quaternion.multiply( this._quaternionStart ).normalize();
|
|
494
|
+
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
this.dispatchEvent( _changeEvent );
|
|
500
|
+
this.dispatchEvent( _objectChangeEvent );
|
|
501
|
+
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
pointerUp( pointer ) {
|
|
505
|
+
|
|
506
|
+
if ( pointer.button !== 0 ) return;
|
|
507
|
+
|
|
508
|
+
if ( this.dragging && ( this.axis !== null ) ) {
|
|
509
|
+
|
|
510
|
+
_mouseUpEvent.mode = this.mode;
|
|
511
|
+
this.dispatchEvent( _mouseUpEvent );
|
|
512
|
+
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
this.dragging = false;
|
|
516
|
+
this.axis = null;
|
|
517
|
+
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
dispose() {
|
|
521
|
+
|
|
522
|
+
this.domElement.removeEventListener( 'pointerdown', this._onPointerDown );
|
|
523
|
+
this.domElement.removeEventListener( 'pointermove', this._onPointerHover );
|
|
524
|
+
this.domElement.removeEventListener( 'pointermove', this._onPointerMove );
|
|
525
|
+
this.domElement.removeEventListener( 'pointerup', this._onPointerUp );
|
|
526
|
+
|
|
527
|
+
this.traverse( function ( child ) {
|
|
528
|
+
|
|
529
|
+
if ( child.geometry ) child.geometry.dispose();
|
|
530
|
+
if ( child.material ) child.material.dispose();
|
|
531
|
+
|
|
532
|
+
} );
|
|
533
|
+
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
// Set current object
|
|
537
|
+
attach( object ) {
|
|
538
|
+
|
|
539
|
+
this.object = object;
|
|
540
|
+
this.visible = true;
|
|
541
|
+
|
|
542
|
+
return this;
|
|
543
|
+
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
// Detach from object
|
|
547
|
+
detach() {
|
|
548
|
+
|
|
549
|
+
this.object = undefined;
|
|
550
|
+
this.visible = false;
|
|
551
|
+
this.axis = null;
|
|
552
|
+
|
|
553
|
+
return this;
|
|
554
|
+
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
reset() {
|
|
558
|
+
|
|
559
|
+
if ( ! this.enabled ) return;
|
|
560
|
+
|
|
561
|
+
if ( this.dragging ) {
|
|
562
|
+
|
|
563
|
+
this.object.position.copy( this._positionStart );
|
|
564
|
+
this.object.quaternion.copy( this._quaternionStart );
|
|
565
|
+
this.object.scale.copy( this._scaleStart );
|
|
566
|
+
|
|
567
|
+
this.dispatchEvent( _changeEvent );
|
|
568
|
+
this.dispatchEvent( _objectChangeEvent );
|
|
569
|
+
|
|
570
|
+
this.pointStart.copy( this.pointEnd );
|
|
571
|
+
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
getRaycaster() {
|
|
577
|
+
|
|
578
|
+
return _raycaster;
|
|
579
|
+
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
// TODO: deprecate
|
|
583
|
+
|
|
584
|
+
getMode() {
|
|
585
|
+
|
|
586
|
+
return this.mode;
|
|
587
|
+
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
setMode( mode ) {
|
|
591
|
+
|
|
592
|
+
this.mode = mode;
|
|
593
|
+
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
setTranslationSnap( translationSnap ) {
|
|
597
|
+
|
|
598
|
+
this.translationSnap = translationSnap;
|
|
599
|
+
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
setRotationSnap( rotationSnap ) {
|
|
603
|
+
|
|
604
|
+
this.rotationSnap = rotationSnap;
|
|
605
|
+
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
setScaleSnap( scaleSnap ) {
|
|
609
|
+
|
|
610
|
+
this.scaleSnap = scaleSnap;
|
|
611
|
+
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
setSize( size ) {
|
|
615
|
+
|
|
616
|
+
this.size = size;
|
|
617
|
+
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
setSpace( space ) {
|
|
621
|
+
|
|
622
|
+
this.space = space;
|
|
623
|
+
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
// mouse / touch event handlers
|
|
629
|
+
|
|
630
|
+
function getPointer( event ) {
|
|
631
|
+
|
|
632
|
+
if ( this.domElement.ownerDocument.pointerLockElement ) {
|
|
633
|
+
|
|
634
|
+
return {
|
|
635
|
+
x: 0,
|
|
636
|
+
y: 0,
|
|
637
|
+
button: event.button
|
|
638
|
+
};
|
|
639
|
+
|
|
640
|
+
} else {
|
|
641
|
+
|
|
642
|
+
const rect = this.domElement.getBoundingClientRect();
|
|
643
|
+
|
|
644
|
+
return {
|
|
645
|
+
x: ( event.clientX - rect.left ) / rect.width * 2 - 1,
|
|
646
|
+
y: - ( event.clientY - rect.top ) / rect.height * 2 + 1,
|
|
647
|
+
button: event.button
|
|
648
|
+
};
|
|
649
|
+
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
function onPointerHover( event ) {
|
|
655
|
+
|
|
656
|
+
if ( ! this.enabled ) return;
|
|
657
|
+
|
|
658
|
+
switch ( event.pointerType ) {
|
|
659
|
+
|
|
660
|
+
case 'mouse':
|
|
661
|
+
case 'pen':
|
|
662
|
+
this.pointerHover( this._getPointer( event ) );
|
|
663
|
+
break;
|
|
664
|
+
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
function onPointerDown( event ) {
|
|
670
|
+
|
|
671
|
+
if ( ! this.enabled ) return;
|
|
672
|
+
|
|
673
|
+
if ( ! document.pointerLockElement ) {
|
|
674
|
+
|
|
675
|
+
this.domElement.setPointerCapture( event.pointerId );
|
|
676
|
+
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
this.domElement.addEventListener( 'pointermove', this._onPointerMove );
|
|
680
|
+
|
|
681
|
+
this.pointerHover( this._getPointer( event ) );
|
|
682
|
+
this.pointerDown( this._getPointer( event ) );
|
|
683
|
+
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
function onPointerMove( event ) {
|
|
687
|
+
|
|
688
|
+
if ( ! this.enabled ) return;
|
|
689
|
+
|
|
690
|
+
this.pointerMove( this._getPointer( event ) );
|
|
691
|
+
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
function onPointerUp( event ) {
|
|
695
|
+
|
|
696
|
+
if ( ! this.enabled ) return;
|
|
697
|
+
|
|
698
|
+
this.domElement.releasePointerCapture( event.pointerId );
|
|
699
|
+
|
|
700
|
+
this.domElement.removeEventListener( 'pointermove', this._onPointerMove );
|
|
701
|
+
|
|
702
|
+
this.pointerUp( this._getPointer( event ) );
|
|
703
|
+
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
function intersectObjectWithRay( object, raycaster, includeInvisible ) {
|
|
707
|
+
|
|
708
|
+
const allIntersections = raycaster.intersectObject( object, true );
|
|
709
|
+
|
|
710
|
+
for ( let i = 0; i < allIntersections.length; i ++ ) {
|
|
711
|
+
|
|
712
|
+
if ( allIntersections[ i ].object.visible || includeInvisible ) {
|
|
713
|
+
|
|
714
|
+
return allIntersections[ i ];
|
|
715
|
+
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
return false;
|
|
721
|
+
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
//
|
|
725
|
+
|
|
726
|
+
// Reusable utility variables
|
|
727
|
+
|
|
728
|
+
const _tempEuler = new Euler();
|
|
729
|
+
const _alignVector = new Vector3( 0, 1, 0 );
|
|
730
|
+
const _zeroVector = new Vector3( 0, 0, 0 );
|
|
731
|
+
const _lookAtMatrix = new Matrix4();
|
|
732
|
+
const _tempQuaternion2 = new Quaternion();
|
|
733
|
+
const _identityQuaternion = new Quaternion();
|
|
734
|
+
const _dirVector = new Vector3();
|
|
735
|
+
const _tempMatrix = new Matrix4();
|
|
736
|
+
|
|
737
|
+
const _unitX = new Vector3( 1, 0, 0 );
|
|
738
|
+
const _unitY = new Vector3( 0, 1, 0 );
|
|
739
|
+
const _unitZ = new Vector3( 0, 0, 1 );
|
|
740
|
+
|
|
741
|
+
const _v1 = new Vector3();
|
|
742
|
+
const _v2 = new Vector3();
|
|
743
|
+
const _v3 = new Vector3();
|
|
744
|
+
|
|
745
|
+
class TransformControlsGizmo extends Object3D {
|
|
746
|
+
|
|
747
|
+
constructor() {
|
|
748
|
+
|
|
749
|
+
super();
|
|
750
|
+
|
|
751
|
+
this.isTransformControlsGizmo = true;
|
|
752
|
+
|
|
753
|
+
this.type = 'TransformControlsGizmo';
|
|
754
|
+
|
|
755
|
+
// shared materials
|
|
756
|
+
|
|
757
|
+
const gizmoMaterial = new MeshBasicMaterial( {
|
|
758
|
+
depthTest: false,
|
|
759
|
+
depthWrite: false,
|
|
760
|
+
fog: false,
|
|
761
|
+
toneMapped: false,
|
|
762
|
+
transparent: true
|
|
763
|
+
} );
|
|
764
|
+
|
|
765
|
+
const gizmoLineMaterial = new LineBasicMaterial( {
|
|
766
|
+
depthTest: false,
|
|
767
|
+
depthWrite: false,
|
|
768
|
+
fog: false,
|
|
769
|
+
toneMapped: false,
|
|
770
|
+
transparent: true
|
|
771
|
+
} );
|
|
772
|
+
|
|
773
|
+
// Make unique material for each axis/color
|
|
774
|
+
|
|
775
|
+
const matInvisible = gizmoMaterial.clone();
|
|
776
|
+
matInvisible.opacity = 0.15;
|
|
777
|
+
|
|
778
|
+
const matHelper = gizmoLineMaterial.clone();
|
|
779
|
+
matHelper.opacity = 0.5;
|
|
780
|
+
|
|
781
|
+
const matRed = gizmoMaterial.clone();
|
|
782
|
+
matRed.color.setHex( 0xff0000 );
|
|
783
|
+
|
|
784
|
+
const matGreen = gizmoMaterial.clone();
|
|
785
|
+
matGreen.color.setHex( 0x00ff00 );
|
|
786
|
+
|
|
787
|
+
const matBlue = gizmoMaterial.clone();
|
|
788
|
+
matBlue.color.setHex( 0x0000ff );
|
|
789
|
+
|
|
790
|
+
const matRedTransparent = gizmoMaterial.clone();
|
|
791
|
+
matRedTransparent.color.setHex( 0xff0000 );
|
|
792
|
+
matRedTransparent.opacity = 0.5;
|
|
793
|
+
|
|
794
|
+
const matGreenTransparent = gizmoMaterial.clone();
|
|
795
|
+
matGreenTransparent.color.setHex( 0x00ff00 );
|
|
796
|
+
matGreenTransparent.opacity = 0.5;
|
|
797
|
+
|
|
798
|
+
const matBlueTransparent = gizmoMaterial.clone();
|
|
799
|
+
matBlueTransparent.color.setHex( 0x0000ff );
|
|
800
|
+
matBlueTransparent.opacity = 0.5;
|
|
801
|
+
|
|
802
|
+
const matWhiteTransparent = gizmoMaterial.clone();
|
|
803
|
+
matWhiteTransparent.opacity = 0.25;
|
|
804
|
+
|
|
805
|
+
const matYellowTransparent = gizmoMaterial.clone();
|
|
806
|
+
matYellowTransparent.color.setHex( 0xffff00 );
|
|
807
|
+
matYellowTransparent.opacity = 0.25;
|
|
808
|
+
|
|
809
|
+
const matYellow = gizmoMaterial.clone();
|
|
810
|
+
matYellow.color.setHex( 0xffff00 );
|
|
811
|
+
|
|
812
|
+
const matGray = gizmoMaterial.clone();
|
|
813
|
+
matGray.color.setHex( 0x787878 );
|
|
814
|
+
|
|
815
|
+
// reusable geometry
|
|
816
|
+
|
|
817
|
+
const arrowGeometry = new CylinderGeometry( 0, 0.04, 0.1, 12 );
|
|
818
|
+
arrowGeometry.translate( 0, 0.05, 0 );
|
|
819
|
+
|
|
820
|
+
const scaleHandleGeometry = new BoxGeometry( 0.08, 0.08, 0.08 );
|
|
821
|
+
scaleHandleGeometry.translate( 0, 0.04, 0 );
|
|
822
|
+
|
|
823
|
+
const lineGeometry = new BufferGeometry();
|
|
824
|
+
lineGeometry.setAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 1, 0, 0 ], 3 ) );
|
|
825
|
+
|
|
826
|
+
const lineGeometry2 = new CylinderGeometry( 0.0075, 0.0075, 0.5, 3 );
|
|
827
|
+
lineGeometry2.translate( 0, 0.25, 0 );
|
|
828
|
+
|
|
829
|
+
function CircleGeometry( radius, arc ) {
|
|
830
|
+
|
|
831
|
+
const geometry = new TorusGeometry( radius, 0.0075, 3, 64, arc * Math.PI * 2 );
|
|
832
|
+
geometry.rotateY( Math.PI / 2 );
|
|
833
|
+
geometry.rotateX( Math.PI / 2 );
|
|
834
|
+
return geometry;
|
|
835
|
+
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
// Special geometry for transform helper. If scaled with position vector it spans from [0,0,0] to position
|
|
839
|
+
|
|
840
|
+
function TranslateHelperGeometry() {
|
|
841
|
+
|
|
842
|
+
const geometry = new BufferGeometry();
|
|
843
|
+
|
|
844
|
+
geometry.setAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 1, 1, 1 ], 3 ) );
|
|
845
|
+
|
|
846
|
+
return geometry;
|
|
847
|
+
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
// Gizmo definitions - custom hierarchy definitions for setupGizmo() function
|
|
851
|
+
|
|
852
|
+
const gizmoTranslate = {
|
|
853
|
+
X: [
|
|
854
|
+
[ new Mesh( arrowGeometry, matRed ), [ 0.5, 0, 0 ], [ 0, 0, - Math.PI / 2 ]],
|
|
855
|
+
[ new Mesh( arrowGeometry, matRed ), [ - 0.5, 0, 0 ], [ 0, 0, Math.PI / 2 ]],
|
|
856
|
+
[ new Mesh( lineGeometry2, matRed ), [ 0, 0, 0 ], [ 0, 0, - Math.PI / 2 ]]
|
|
857
|
+
],
|
|
858
|
+
Y: [
|
|
859
|
+
[ new Mesh( arrowGeometry, matGreen ), [ 0, 0.5, 0 ]],
|
|
860
|
+
[ new Mesh( arrowGeometry, matGreen ), [ 0, - 0.5, 0 ], [ Math.PI, 0, 0 ]],
|
|
861
|
+
[ new Mesh( lineGeometry2, matGreen ) ]
|
|
862
|
+
],
|
|
863
|
+
Z: [
|
|
864
|
+
[ new Mesh( arrowGeometry, matBlue ), [ 0, 0, 0.5 ], [ Math.PI / 2, 0, 0 ]],
|
|
865
|
+
[ new Mesh( arrowGeometry, matBlue ), [ 0, 0, - 0.5 ], [ - Math.PI / 2, 0, 0 ]],
|
|
866
|
+
[ new Mesh( lineGeometry2, matBlue ), null, [ Math.PI / 2, 0, 0 ]]
|
|
867
|
+
],
|
|
868
|
+
XYZ: [
|
|
869
|
+
[ new Mesh( new OctahedronGeometry( 0.1, 0 ), matWhiteTransparent.clone() ), [ 0, 0, 0 ]]
|
|
870
|
+
],
|
|
871
|
+
XY: [
|
|
872
|
+
[ new Mesh( new BoxGeometry( 0.15, 0.15, 0.01 ), matBlueTransparent.clone() ), [ 0.15, 0.15, 0 ]]
|
|
873
|
+
],
|
|
874
|
+
YZ: [
|
|
875
|
+
[ new Mesh( new BoxGeometry( 0.15, 0.15, 0.01 ), matRedTransparent.clone() ), [ 0, 0.15, 0.15 ], [ 0, Math.PI / 2, 0 ]]
|
|
876
|
+
],
|
|
877
|
+
XZ: [
|
|
878
|
+
[ new Mesh( new BoxGeometry( 0.15, 0.15, 0.01 ), matGreenTransparent.clone() ), [ 0.15, 0, 0.15 ], [ - Math.PI / 2, 0, 0 ]]
|
|
879
|
+
]
|
|
880
|
+
};
|
|
881
|
+
|
|
882
|
+
const pickerTranslate = {
|
|
883
|
+
X: [
|
|
884
|
+
[ new Mesh( new CylinderGeometry( 0.2, 0, 0.6, 4 ), matInvisible ), [ 0.3, 0, 0 ], [ 0, 0, - Math.PI / 2 ]],
|
|
885
|
+
[ new Mesh( new CylinderGeometry( 0.2, 0, 0.6, 4 ), matInvisible ), [ - 0.3, 0, 0 ], [ 0, 0, Math.PI / 2 ]]
|
|
886
|
+
],
|
|
887
|
+
Y: [
|
|
888
|
+
[ new Mesh( new CylinderGeometry( 0.2, 0, 0.6, 4 ), matInvisible ), [ 0, 0.3, 0 ]],
|
|
889
|
+
[ new Mesh( new CylinderGeometry( 0.2, 0, 0.6, 4 ), matInvisible ), [ 0, - 0.3, 0 ], [ 0, 0, Math.PI ]]
|
|
890
|
+
],
|
|
891
|
+
Z: [
|
|
892
|
+
[ new Mesh( new CylinderGeometry( 0.2, 0, 0.6, 4 ), matInvisible ), [ 0, 0, 0.3 ], [ Math.PI / 2, 0, 0 ]],
|
|
893
|
+
[ new Mesh( new CylinderGeometry( 0.2, 0, 0.6, 4 ), matInvisible ), [ 0, 0, - 0.3 ], [ - Math.PI / 2, 0, 0 ]]
|
|
894
|
+
],
|
|
895
|
+
XYZ: [
|
|
896
|
+
[ new Mesh( new OctahedronGeometry( 0.2, 0 ), matInvisible ) ]
|
|
897
|
+
],
|
|
898
|
+
XY: [
|
|
899
|
+
[ new Mesh( new BoxGeometry( 0.2, 0.2, 0.01 ), matInvisible ), [ 0.15, 0.15, 0 ]]
|
|
900
|
+
],
|
|
901
|
+
YZ: [
|
|
902
|
+
[ new Mesh( new BoxGeometry( 0.2, 0.2, 0.01 ), matInvisible ), [ 0, 0.15, 0.15 ], [ 0, Math.PI / 2, 0 ]]
|
|
903
|
+
],
|
|
904
|
+
XZ: [
|
|
905
|
+
[ new Mesh( new BoxGeometry( 0.2, 0.2, 0.01 ), matInvisible ), [ 0.15, 0, 0.15 ], [ - Math.PI / 2, 0, 0 ]]
|
|
906
|
+
]
|
|
907
|
+
};
|
|
908
|
+
|
|
909
|
+
const helperTranslate = {
|
|
910
|
+
START: [
|
|
911
|
+
[ new Mesh( new OctahedronGeometry( 0.01, 2 ), matHelper ), null, null, null, 'helper' ]
|
|
912
|
+
],
|
|
913
|
+
END: [
|
|
914
|
+
[ new Mesh( new OctahedronGeometry( 0.01, 2 ), matHelper ), null, null, null, 'helper' ]
|
|
915
|
+
],
|
|
916
|
+
DELTA: [
|
|
917
|
+
[ new Line( TranslateHelperGeometry(), matHelper ), null, null, null, 'helper' ]
|
|
918
|
+
],
|
|
919
|
+
X: [
|
|
920
|
+
[ new Line( lineGeometry, matHelper.clone() ), [ - 1e3, 0, 0 ], null, [ 1e6, 1, 1 ], 'helper' ]
|
|
921
|
+
],
|
|
922
|
+
Y: [
|
|
923
|
+
[ new Line( lineGeometry, matHelper.clone() ), [ 0, - 1e3, 0 ], [ 0, 0, Math.PI / 2 ], [ 1e6, 1, 1 ], 'helper' ]
|
|
924
|
+
],
|
|
925
|
+
Z: [
|
|
926
|
+
[ new Line( lineGeometry, matHelper.clone() ), [ 0, 0, - 1e3 ], [ 0, - Math.PI / 2, 0 ], [ 1e6, 1, 1 ], 'helper' ]
|
|
927
|
+
]
|
|
928
|
+
};
|
|
929
|
+
|
|
930
|
+
const gizmoRotate = {
|
|
931
|
+
XYZE: [
|
|
932
|
+
[ new Mesh( CircleGeometry( 0.5, 1 ), matGray ), null, [ 0, Math.PI / 2, 0 ]]
|
|
933
|
+
],
|
|
934
|
+
X: [
|
|
935
|
+
[ new Mesh( CircleGeometry( 0.5, 0.5 ), matRed ) ]
|
|
936
|
+
],
|
|
937
|
+
Y: [
|
|
938
|
+
[ new Mesh( CircleGeometry( 0.5, 0.5 ), matGreen ), null, [ 0, 0, - Math.PI / 2 ]]
|
|
939
|
+
],
|
|
940
|
+
Z: [
|
|
941
|
+
[ new Mesh( CircleGeometry( 0.5, 0.5 ), matBlue ), null, [ 0, Math.PI / 2, 0 ]]
|
|
942
|
+
],
|
|
943
|
+
E: [
|
|
944
|
+
[ new Mesh( CircleGeometry( 0.75, 1 ), matYellowTransparent ), null, [ 0, Math.PI / 2, 0 ]]
|
|
945
|
+
]
|
|
946
|
+
};
|
|
947
|
+
|
|
948
|
+
const helperRotate = {
|
|
949
|
+
AXIS: [
|
|
950
|
+
[ new Line( lineGeometry, matHelper.clone() ), [ - 1e3, 0, 0 ], null, [ 1e6, 1, 1 ], 'helper' ]
|
|
951
|
+
]
|
|
952
|
+
};
|
|
953
|
+
|
|
954
|
+
const pickerRotate = {
|
|
955
|
+
XYZE: [
|
|
956
|
+
[ new Mesh( new SphereGeometry( 0.25, 10, 8 ), matInvisible ) ]
|
|
957
|
+
],
|
|
958
|
+
X: [
|
|
959
|
+
[ new Mesh( new TorusGeometry( 0.5, 0.1, 4, 24 ), matInvisible ), [ 0, 0, 0 ], [ 0, - Math.PI / 2, - Math.PI / 2 ]],
|
|
960
|
+
],
|
|
961
|
+
Y: [
|
|
962
|
+
[ new Mesh( new TorusGeometry( 0.5, 0.1, 4, 24 ), matInvisible ), [ 0, 0, 0 ], [ Math.PI / 2, 0, 0 ]],
|
|
963
|
+
],
|
|
964
|
+
Z: [
|
|
965
|
+
[ new Mesh( new TorusGeometry( 0.5, 0.1, 4, 24 ), matInvisible ), [ 0, 0, 0 ], [ 0, 0, - Math.PI / 2 ]],
|
|
966
|
+
],
|
|
967
|
+
E: [
|
|
968
|
+
[ new Mesh( new TorusGeometry( 0.75, 0.1, 2, 24 ), matInvisible ) ]
|
|
969
|
+
]
|
|
970
|
+
};
|
|
971
|
+
|
|
972
|
+
const gizmoScale = {
|
|
973
|
+
X: [
|
|
974
|
+
[ new Mesh( scaleHandleGeometry, matRed ), [ 0.5, 0, 0 ], [ 0, 0, - Math.PI / 2 ]],
|
|
975
|
+
[ new Mesh( lineGeometry2, matRed ), [ 0, 0, 0 ], [ 0, 0, - Math.PI / 2 ]],
|
|
976
|
+
[ new Mesh( scaleHandleGeometry, matRed ), [ - 0.5, 0, 0 ], [ 0, 0, Math.PI / 2 ]],
|
|
977
|
+
],
|
|
978
|
+
Y: [
|
|
979
|
+
[ new Mesh( scaleHandleGeometry, matGreen ), [ 0, 0.5, 0 ]],
|
|
980
|
+
[ new Mesh( lineGeometry2, matGreen ) ],
|
|
981
|
+
[ new Mesh( scaleHandleGeometry, matGreen ), [ 0, - 0.5, 0 ], [ 0, 0, Math.PI ]],
|
|
982
|
+
],
|
|
983
|
+
Z: [
|
|
984
|
+
[ new Mesh( scaleHandleGeometry, matBlue ), [ 0, 0, 0.5 ], [ Math.PI / 2, 0, 0 ]],
|
|
985
|
+
[ new Mesh( lineGeometry2, matBlue ), [ 0, 0, 0 ], [ Math.PI / 2, 0, 0 ]],
|
|
986
|
+
[ new Mesh( scaleHandleGeometry, matBlue ), [ 0, 0, - 0.5 ], [ - Math.PI / 2, 0, 0 ]]
|
|
987
|
+
],
|
|
988
|
+
XY: [
|
|
989
|
+
[ new Mesh( new BoxGeometry( 0.15, 0.15, 0.01 ), matBlueTransparent ), [ 0.15, 0.15, 0 ]]
|
|
990
|
+
],
|
|
991
|
+
YZ: [
|
|
992
|
+
[ new Mesh( new BoxGeometry( 0.15, 0.15, 0.01 ), matRedTransparent ), [ 0, 0.15, 0.15 ], [ 0, Math.PI / 2, 0 ]]
|
|
993
|
+
],
|
|
994
|
+
XZ: [
|
|
995
|
+
[ new Mesh( new BoxGeometry( 0.15, 0.15, 0.01 ), matGreenTransparent ), [ 0.15, 0, 0.15 ], [ - Math.PI / 2, 0, 0 ]]
|
|
996
|
+
],
|
|
997
|
+
XYZ: [
|
|
998
|
+
[ new Mesh( new BoxGeometry( 0.1, 0.1, 0.1 ), matWhiteTransparent.clone() ) ],
|
|
999
|
+
]
|
|
1000
|
+
};
|
|
1001
|
+
|
|
1002
|
+
const pickerScale = {
|
|
1003
|
+
X: [
|
|
1004
|
+
[ new Mesh( new CylinderGeometry( 0.2, 0, 0.6, 4 ), matInvisible ), [ 0.3, 0, 0 ], [ 0, 0, - Math.PI / 2 ]],
|
|
1005
|
+
[ new Mesh( new CylinderGeometry( 0.2, 0, 0.6, 4 ), matInvisible ), [ - 0.3, 0, 0 ], [ 0, 0, Math.PI / 2 ]]
|
|
1006
|
+
],
|
|
1007
|
+
Y: [
|
|
1008
|
+
[ new Mesh( new CylinderGeometry( 0.2, 0, 0.6, 4 ), matInvisible ), [ 0, 0.3, 0 ]],
|
|
1009
|
+
[ new Mesh( new CylinderGeometry( 0.2, 0, 0.6, 4 ), matInvisible ), [ 0, - 0.3, 0 ], [ 0, 0, Math.PI ]]
|
|
1010
|
+
],
|
|
1011
|
+
Z: [
|
|
1012
|
+
[ new Mesh( new CylinderGeometry( 0.2, 0, 0.6, 4 ), matInvisible ), [ 0, 0, 0.3 ], [ Math.PI / 2, 0, 0 ]],
|
|
1013
|
+
[ new Mesh( new CylinderGeometry( 0.2, 0, 0.6, 4 ), matInvisible ), [ 0, 0, - 0.3 ], [ - Math.PI / 2, 0, 0 ]]
|
|
1014
|
+
],
|
|
1015
|
+
XY: [
|
|
1016
|
+
[ new Mesh( new BoxGeometry( 0.2, 0.2, 0.01 ), matInvisible ), [ 0.15, 0.15, 0 ]],
|
|
1017
|
+
],
|
|
1018
|
+
YZ: [
|
|
1019
|
+
[ new Mesh( new BoxGeometry( 0.2, 0.2, 0.01 ), matInvisible ), [ 0, 0.15, 0.15 ], [ 0, Math.PI / 2, 0 ]],
|
|
1020
|
+
],
|
|
1021
|
+
XZ: [
|
|
1022
|
+
[ new Mesh( new BoxGeometry( 0.2, 0.2, 0.01 ), matInvisible ), [ 0.15, 0, 0.15 ], [ - Math.PI / 2, 0, 0 ]],
|
|
1023
|
+
],
|
|
1024
|
+
XYZ: [
|
|
1025
|
+
[ new Mesh( new BoxGeometry( 0.2, 0.2, 0.2 ), matInvisible ), [ 0, 0, 0 ]],
|
|
1026
|
+
]
|
|
1027
|
+
};
|
|
1028
|
+
|
|
1029
|
+
const helperScale = {
|
|
1030
|
+
X: [
|
|
1031
|
+
[ new Line( lineGeometry, matHelper.clone() ), [ - 1e3, 0, 0 ], null, [ 1e6, 1, 1 ], 'helper' ]
|
|
1032
|
+
],
|
|
1033
|
+
Y: [
|
|
1034
|
+
[ new Line( lineGeometry, matHelper.clone() ), [ 0, - 1e3, 0 ], [ 0, 0, Math.PI / 2 ], [ 1e6, 1, 1 ], 'helper' ]
|
|
1035
|
+
],
|
|
1036
|
+
Z: [
|
|
1037
|
+
[ new Line( lineGeometry, matHelper.clone() ), [ 0, 0, - 1e3 ], [ 0, - Math.PI / 2, 0 ], [ 1e6, 1, 1 ], 'helper' ]
|
|
1038
|
+
]
|
|
1039
|
+
};
|
|
1040
|
+
|
|
1041
|
+
// Creates an Object3D with gizmos described in custom hierarchy definition.
|
|
1042
|
+
|
|
1043
|
+
function setupGizmo( gizmoMap ) {
|
|
1044
|
+
|
|
1045
|
+
const gizmo = new Object3D();
|
|
1046
|
+
|
|
1047
|
+
for ( const name in gizmoMap ) {
|
|
1048
|
+
|
|
1049
|
+
for ( let i = gizmoMap[ name ].length; i --; ) {
|
|
1050
|
+
|
|
1051
|
+
const object = gizmoMap[ name ][ i ][ 0 ].clone();
|
|
1052
|
+
const position = gizmoMap[ name ][ i ][ 1 ];
|
|
1053
|
+
const rotation = gizmoMap[ name ][ i ][ 2 ];
|
|
1054
|
+
const scale = gizmoMap[ name ][ i ][ 3 ];
|
|
1055
|
+
const tag = gizmoMap[ name ][ i ][ 4 ];
|
|
1056
|
+
|
|
1057
|
+
// name and tag properties are essential for picking and updating logic.
|
|
1058
|
+
object.name = name;
|
|
1059
|
+
object.tag = tag;
|
|
1060
|
+
|
|
1061
|
+
if ( position ) {
|
|
1062
|
+
|
|
1063
|
+
object.position.set( position[ 0 ], position[ 1 ], position[ 2 ] );
|
|
1064
|
+
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
if ( rotation ) {
|
|
1068
|
+
|
|
1069
|
+
object.rotation.set( rotation[ 0 ], rotation[ 1 ], rotation[ 2 ] );
|
|
1070
|
+
|
|
1071
|
+
}
|
|
1072
|
+
|
|
1073
|
+
if ( scale ) {
|
|
1074
|
+
|
|
1075
|
+
object.scale.set( scale[ 0 ], scale[ 1 ], scale[ 2 ] );
|
|
1076
|
+
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
object.updateMatrix();
|
|
1080
|
+
|
|
1081
|
+
const tempGeometry = object.geometry.clone();
|
|
1082
|
+
tempGeometry.applyMatrix4( object.matrix );
|
|
1083
|
+
object.geometry = tempGeometry;
|
|
1084
|
+
object.renderOrder = Infinity;
|
|
1085
|
+
|
|
1086
|
+
object.position.set( 0, 0, 0 );
|
|
1087
|
+
object.rotation.set( 0, 0, 0 );
|
|
1088
|
+
object.scale.set( 1, 1, 1 );
|
|
1089
|
+
|
|
1090
|
+
gizmo.add( object );
|
|
1091
|
+
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
return gizmo;
|
|
1097
|
+
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
// Gizmo creation
|
|
1101
|
+
|
|
1102
|
+
this.gizmo = {};
|
|
1103
|
+
this.picker = {};
|
|
1104
|
+
this.helper = {};
|
|
1105
|
+
|
|
1106
|
+
this.add( this.gizmo[ 'translate' ] = setupGizmo( gizmoTranslate ) );
|
|
1107
|
+
this.add( this.gizmo[ 'rotate' ] = setupGizmo( gizmoRotate ) );
|
|
1108
|
+
this.add( this.gizmo[ 'scale' ] = setupGizmo( gizmoScale ) );
|
|
1109
|
+
this.add( this.picker[ 'translate' ] = setupGizmo( pickerTranslate ) );
|
|
1110
|
+
this.add( this.picker[ 'rotate' ] = setupGizmo( pickerRotate ) );
|
|
1111
|
+
this.add( this.picker[ 'scale' ] = setupGizmo( pickerScale ) );
|
|
1112
|
+
this.add( this.helper[ 'translate' ] = setupGizmo( helperTranslate ) );
|
|
1113
|
+
this.add( this.helper[ 'rotate' ] = setupGizmo( helperRotate ) );
|
|
1114
|
+
this.add( this.helper[ 'scale' ] = setupGizmo( helperScale ) );
|
|
1115
|
+
|
|
1116
|
+
// Pickers should be hidden always
|
|
1117
|
+
|
|
1118
|
+
this.picker[ 'translate' ].visible = false;
|
|
1119
|
+
this.picker[ 'rotate' ].visible = false;
|
|
1120
|
+
this.picker[ 'scale' ].visible = false;
|
|
1121
|
+
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
// updateMatrixWorld will update transformations and appearance of individual handles
|
|
1125
|
+
|
|
1126
|
+
updateMatrixWorld( force ) {
|
|
1127
|
+
|
|
1128
|
+
const space = ( this.mode === 'scale' ) ? 'local' : this.space; // scale always oriented to local rotation
|
|
1129
|
+
|
|
1130
|
+
const quaternion = ( space === 'local' ) ? this.worldQuaternion : _identityQuaternion;
|
|
1131
|
+
|
|
1132
|
+
// Show only gizmos for current transform mode
|
|
1133
|
+
|
|
1134
|
+
this.gizmo[ 'translate' ].visible = this.mode === 'translate';
|
|
1135
|
+
this.gizmo[ 'rotate' ].visible = this.mode === 'rotate';
|
|
1136
|
+
this.gizmo[ 'scale' ].visible = this.mode === 'scale';
|
|
1137
|
+
|
|
1138
|
+
this.helper[ 'translate' ].visible = this.mode === 'translate';
|
|
1139
|
+
this.helper[ 'rotate' ].visible = this.mode === 'rotate';
|
|
1140
|
+
this.helper[ 'scale' ].visible = this.mode === 'scale';
|
|
1141
|
+
|
|
1142
|
+
|
|
1143
|
+
let handles = [];
|
|
1144
|
+
handles = handles.concat( this.picker[ this.mode ].children );
|
|
1145
|
+
handles = handles.concat( this.gizmo[ this.mode ].children );
|
|
1146
|
+
handles = handles.concat( this.helper[ this.mode ].children );
|
|
1147
|
+
|
|
1148
|
+
for ( let i = 0; i < handles.length; i ++ ) {
|
|
1149
|
+
|
|
1150
|
+
const handle = handles[ i ];
|
|
1151
|
+
|
|
1152
|
+
// hide aligned to camera
|
|
1153
|
+
|
|
1154
|
+
handle.visible = true;
|
|
1155
|
+
handle.rotation.set( 0, 0, 0 );
|
|
1156
|
+
handle.position.copy( this.worldPosition );
|
|
1157
|
+
|
|
1158
|
+
let factor;
|
|
1159
|
+
|
|
1160
|
+
if ( this.camera.isOrthographicCamera ) {
|
|
1161
|
+
|
|
1162
|
+
factor = ( this.camera.top - this.camera.bottom ) / this.camera.zoom;
|
|
1163
|
+
|
|
1164
|
+
} else {
|
|
1165
|
+
|
|
1166
|
+
factor = this.worldPosition.distanceTo( this.cameraPosition ) * Math.min( 1.9 * Math.tan( Math.PI * this.camera.fov / 360 ) / this.camera.zoom, 7 );
|
|
1167
|
+
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
handle.scale.set( 1, 1, 1 ).multiplyScalar( factor * this.size / 4 );
|
|
1171
|
+
|
|
1172
|
+
// TODO: simplify helpers and consider decoupling from gizmo
|
|
1173
|
+
|
|
1174
|
+
if ( handle.tag === 'helper' ) {
|
|
1175
|
+
|
|
1176
|
+
handle.visible = false;
|
|
1177
|
+
|
|
1178
|
+
if ( handle.name === 'AXIS' ) {
|
|
1179
|
+
|
|
1180
|
+
handle.visible = !! this.axis;
|
|
1181
|
+
|
|
1182
|
+
if ( this.axis === 'X' ) {
|
|
1183
|
+
|
|
1184
|
+
_tempQuaternion.setFromEuler( _tempEuler.set( 0, 0, 0 ) );
|
|
1185
|
+
handle.quaternion.copy( quaternion ).multiply( _tempQuaternion );
|
|
1186
|
+
|
|
1187
|
+
if ( Math.abs( _alignVector.copy( _unitX ).applyQuaternion( quaternion ).dot( this.eye ) ) > 0.9 ) {
|
|
1188
|
+
|
|
1189
|
+
handle.visible = false;
|
|
1190
|
+
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
if ( this.axis === 'Y' ) {
|
|
1196
|
+
|
|
1197
|
+
_tempQuaternion.setFromEuler( _tempEuler.set( 0, 0, Math.PI / 2 ) );
|
|
1198
|
+
handle.quaternion.copy( quaternion ).multiply( _tempQuaternion );
|
|
1199
|
+
|
|
1200
|
+
if ( Math.abs( _alignVector.copy( _unitY ).applyQuaternion( quaternion ).dot( this.eye ) ) > 0.9 ) {
|
|
1201
|
+
|
|
1202
|
+
handle.visible = false;
|
|
1203
|
+
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
if ( this.axis === 'Z' ) {
|
|
1209
|
+
|
|
1210
|
+
_tempQuaternion.setFromEuler( _tempEuler.set( 0, Math.PI / 2, 0 ) );
|
|
1211
|
+
handle.quaternion.copy( quaternion ).multiply( _tempQuaternion );
|
|
1212
|
+
|
|
1213
|
+
if ( Math.abs( _alignVector.copy( _unitZ ).applyQuaternion( quaternion ).dot( this.eye ) ) > 0.9 ) {
|
|
1214
|
+
|
|
1215
|
+
handle.visible = false;
|
|
1216
|
+
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
if ( this.axis === 'XYZE' ) {
|
|
1222
|
+
|
|
1223
|
+
_tempQuaternion.setFromEuler( _tempEuler.set( 0, Math.PI / 2, 0 ) );
|
|
1224
|
+
_alignVector.copy( this.rotationAxis );
|
|
1225
|
+
handle.quaternion.setFromRotationMatrix( _lookAtMatrix.lookAt( _zeroVector, _alignVector, _unitY ) );
|
|
1226
|
+
handle.quaternion.multiply( _tempQuaternion );
|
|
1227
|
+
handle.visible = this.dragging;
|
|
1228
|
+
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1231
|
+
if ( this.axis === 'E' ) {
|
|
1232
|
+
|
|
1233
|
+
handle.visible = false;
|
|
1234
|
+
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
|
|
1238
|
+
} else if ( handle.name === 'START' ) {
|
|
1239
|
+
|
|
1240
|
+
handle.position.copy( this.worldPositionStart );
|
|
1241
|
+
handle.visible = this.dragging;
|
|
1242
|
+
|
|
1243
|
+
} else if ( handle.name === 'END' ) {
|
|
1244
|
+
|
|
1245
|
+
handle.position.copy( this.worldPosition );
|
|
1246
|
+
handle.visible = this.dragging;
|
|
1247
|
+
|
|
1248
|
+
} else if ( handle.name === 'DELTA' ) {
|
|
1249
|
+
|
|
1250
|
+
handle.position.copy( this.worldPositionStart );
|
|
1251
|
+
handle.quaternion.copy( this.worldQuaternionStart );
|
|
1252
|
+
_tempVector.set( 1e-10, 1e-10, 1e-10 ).add( this.worldPositionStart ).sub( this.worldPosition ).multiplyScalar( - 1 );
|
|
1253
|
+
_tempVector.applyQuaternion( this.worldQuaternionStart.clone().invert() );
|
|
1254
|
+
handle.scale.copy( _tempVector );
|
|
1255
|
+
handle.visible = this.dragging;
|
|
1256
|
+
|
|
1257
|
+
} else {
|
|
1258
|
+
|
|
1259
|
+
handle.quaternion.copy( quaternion );
|
|
1260
|
+
|
|
1261
|
+
if ( this.dragging ) {
|
|
1262
|
+
|
|
1263
|
+
handle.position.copy( this.worldPositionStart );
|
|
1264
|
+
|
|
1265
|
+
} else {
|
|
1266
|
+
|
|
1267
|
+
handle.position.copy( this.worldPosition );
|
|
1268
|
+
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1271
|
+
if ( this.axis ) {
|
|
1272
|
+
|
|
1273
|
+
handle.visible = this.axis.search( handle.name ) !== - 1;
|
|
1274
|
+
|
|
1275
|
+
}
|
|
1276
|
+
|
|
1277
|
+
}
|
|
1278
|
+
|
|
1279
|
+
// If updating helper, skip rest of the loop
|
|
1280
|
+
continue;
|
|
1281
|
+
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1284
|
+
// Align handles to current local or world rotation
|
|
1285
|
+
|
|
1286
|
+
handle.quaternion.copy( quaternion );
|
|
1287
|
+
|
|
1288
|
+
if ( this.mode === 'translate' || this.mode === 'scale' ) {
|
|
1289
|
+
|
|
1290
|
+
// Hide translate and scale axis facing the camera
|
|
1291
|
+
|
|
1292
|
+
const AXIS_HIDE_THRESHOLD = 0.99;
|
|
1293
|
+
const PLANE_HIDE_THRESHOLD = 0.2;
|
|
1294
|
+
|
|
1295
|
+
if ( handle.name === 'X' ) {
|
|
1296
|
+
|
|
1297
|
+
if ( Math.abs( _alignVector.copy( _unitX ).applyQuaternion( quaternion ).dot( this.eye ) ) > AXIS_HIDE_THRESHOLD ) {
|
|
1298
|
+
|
|
1299
|
+
handle.scale.set( 1e-10, 1e-10, 1e-10 );
|
|
1300
|
+
handle.visible = false;
|
|
1301
|
+
|
|
1302
|
+
}
|
|
1303
|
+
|
|
1304
|
+
}
|
|
1305
|
+
|
|
1306
|
+
if ( handle.name === 'Y' ) {
|
|
1307
|
+
|
|
1308
|
+
if ( Math.abs( _alignVector.copy( _unitY ).applyQuaternion( quaternion ).dot( this.eye ) ) > AXIS_HIDE_THRESHOLD ) {
|
|
1309
|
+
|
|
1310
|
+
handle.scale.set( 1e-10, 1e-10, 1e-10 );
|
|
1311
|
+
handle.visible = false;
|
|
1312
|
+
|
|
1313
|
+
}
|
|
1314
|
+
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
if ( handle.name === 'Z' ) {
|
|
1318
|
+
|
|
1319
|
+
if ( Math.abs( _alignVector.copy( _unitZ ).applyQuaternion( quaternion ).dot( this.eye ) ) > AXIS_HIDE_THRESHOLD ) {
|
|
1320
|
+
|
|
1321
|
+
handle.scale.set( 1e-10, 1e-10, 1e-10 );
|
|
1322
|
+
handle.visible = false;
|
|
1323
|
+
|
|
1324
|
+
}
|
|
1325
|
+
|
|
1326
|
+
}
|
|
1327
|
+
|
|
1328
|
+
if ( handle.name === 'XY' ) {
|
|
1329
|
+
|
|
1330
|
+
if ( Math.abs( _alignVector.copy( _unitZ ).applyQuaternion( quaternion ).dot( this.eye ) ) < PLANE_HIDE_THRESHOLD ) {
|
|
1331
|
+
|
|
1332
|
+
handle.scale.set( 1e-10, 1e-10, 1e-10 );
|
|
1333
|
+
handle.visible = false;
|
|
1334
|
+
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1339
|
+
if ( handle.name === 'YZ' ) {
|
|
1340
|
+
|
|
1341
|
+
if ( Math.abs( _alignVector.copy( _unitX ).applyQuaternion( quaternion ).dot( this.eye ) ) < PLANE_HIDE_THRESHOLD ) {
|
|
1342
|
+
|
|
1343
|
+
handle.scale.set( 1e-10, 1e-10, 1e-10 );
|
|
1344
|
+
handle.visible = false;
|
|
1345
|
+
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1348
|
+
}
|
|
1349
|
+
|
|
1350
|
+
if ( handle.name === 'XZ' ) {
|
|
1351
|
+
|
|
1352
|
+
if ( Math.abs( _alignVector.copy( _unitY ).applyQuaternion( quaternion ).dot( this.eye ) ) < PLANE_HIDE_THRESHOLD ) {
|
|
1353
|
+
|
|
1354
|
+
handle.scale.set( 1e-10, 1e-10, 1e-10 );
|
|
1355
|
+
handle.visible = false;
|
|
1356
|
+
|
|
1357
|
+
}
|
|
1358
|
+
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1361
|
+
} else if ( this.mode === 'rotate' ) {
|
|
1362
|
+
|
|
1363
|
+
// Align handles to current local or world rotation
|
|
1364
|
+
|
|
1365
|
+
_tempQuaternion2.copy( quaternion );
|
|
1366
|
+
_alignVector.copy( this.eye ).applyQuaternion( _tempQuaternion.copy( quaternion ).invert() );
|
|
1367
|
+
|
|
1368
|
+
if ( handle.name.search( 'E' ) !== - 1 ) {
|
|
1369
|
+
|
|
1370
|
+
handle.quaternion.setFromRotationMatrix( _lookAtMatrix.lookAt( this.eye, _zeroVector, _unitY ) );
|
|
1371
|
+
|
|
1372
|
+
}
|
|
1373
|
+
|
|
1374
|
+
if ( handle.name === 'X' ) {
|
|
1375
|
+
|
|
1376
|
+
_tempQuaternion.setFromAxisAngle( _unitX, Math.atan2( - _alignVector.y, _alignVector.z ) );
|
|
1377
|
+
_tempQuaternion.multiplyQuaternions( _tempQuaternion2, _tempQuaternion );
|
|
1378
|
+
handle.quaternion.copy( _tempQuaternion );
|
|
1379
|
+
|
|
1380
|
+
}
|
|
1381
|
+
|
|
1382
|
+
if ( handle.name === 'Y' ) {
|
|
1383
|
+
|
|
1384
|
+
_tempQuaternion.setFromAxisAngle( _unitY, Math.atan2( _alignVector.x, _alignVector.z ) );
|
|
1385
|
+
_tempQuaternion.multiplyQuaternions( _tempQuaternion2, _tempQuaternion );
|
|
1386
|
+
handle.quaternion.copy( _tempQuaternion );
|
|
1387
|
+
|
|
1388
|
+
}
|
|
1389
|
+
|
|
1390
|
+
if ( handle.name === 'Z' ) {
|
|
1391
|
+
|
|
1392
|
+
_tempQuaternion.setFromAxisAngle( _unitZ, Math.atan2( _alignVector.y, _alignVector.x ) );
|
|
1393
|
+
_tempQuaternion.multiplyQuaternions( _tempQuaternion2, _tempQuaternion );
|
|
1394
|
+
handle.quaternion.copy( _tempQuaternion );
|
|
1395
|
+
|
|
1396
|
+
}
|
|
1397
|
+
|
|
1398
|
+
}
|
|
1399
|
+
|
|
1400
|
+
// Hide disabled axes
|
|
1401
|
+
handle.visible = handle.visible && ( handle.name.indexOf( 'X' ) === - 1 || this.showX );
|
|
1402
|
+
handle.visible = handle.visible && ( handle.name.indexOf( 'Y' ) === - 1 || this.showY );
|
|
1403
|
+
handle.visible = handle.visible && ( handle.name.indexOf( 'Z' ) === - 1 || this.showZ );
|
|
1404
|
+
handle.visible = handle.visible && ( handle.name.indexOf( 'E' ) === - 1 || ( this.showX && this.showY && this.showZ ) );
|
|
1405
|
+
|
|
1406
|
+
// highlight selected axis
|
|
1407
|
+
|
|
1408
|
+
handle.material._color = handle.material._color || handle.material.color.clone();
|
|
1409
|
+
handle.material._opacity = handle.material._opacity || handle.material.opacity;
|
|
1410
|
+
|
|
1411
|
+
handle.material.color.copy( handle.material._color );
|
|
1412
|
+
handle.material.opacity = handle.material._opacity;
|
|
1413
|
+
|
|
1414
|
+
if ( this.enabled && this.axis ) {
|
|
1415
|
+
|
|
1416
|
+
if ( handle.name === this.axis ) {
|
|
1417
|
+
|
|
1418
|
+
handle.material.color.setHex( 0xffff00 );
|
|
1419
|
+
handle.material.opacity = 1.0;
|
|
1420
|
+
|
|
1421
|
+
} else if ( this.axis.split( '' ).some( function ( a ) {
|
|
1422
|
+
|
|
1423
|
+
return handle.name === a;
|
|
1424
|
+
|
|
1425
|
+
} ) ) {
|
|
1426
|
+
|
|
1427
|
+
handle.material.color.setHex( 0xffff00 );
|
|
1428
|
+
handle.material.opacity = 1.0;
|
|
1429
|
+
|
|
1430
|
+
}
|
|
1431
|
+
|
|
1432
|
+
}
|
|
1433
|
+
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1436
|
+
super.updateMatrixWorld( force );
|
|
1437
|
+
|
|
1438
|
+
}
|
|
1439
|
+
|
|
1440
|
+
}
|
|
1441
|
+
|
|
1442
|
+
//
|
|
1443
|
+
|
|
1444
|
+
class TransformControlsPlane extends Mesh {
|
|
1445
|
+
|
|
1446
|
+
constructor() {
|
|
1447
|
+
|
|
1448
|
+
super(
|
|
1449
|
+
new PlaneGeometry( 100000, 100000, 2, 2 ),
|
|
1450
|
+
new MeshBasicMaterial( { visible: false, wireframe: true, side: DoubleSide, transparent: true, opacity: 0.1, toneMapped: false } )
|
|
1451
|
+
);
|
|
1452
|
+
|
|
1453
|
+
this.isTransformControlsPlane = true;
|
|
1454
|
+
|
|
1455
|
+
this.type = 'TransformControlsPlane';
|
|
1456
|
+
|
|
1457
|
+
}
|
|
1458
|
+
|
|
1459
|
+
updateMatrixWorld( force ) {
|
|
1460
|
+
|
|
1461
|
+
let space = this.space;
|
|
1462
|
+
|
|
1463
|
+
this.position.copy( this.worldPosition );
|
|
1464
|
+
|
|
1465
|
+
if ( this.mode === 'scale' ) space = 'local'; // scale always oriented to local rotation
|
|
1466
|
+
|
|
1467
|
+
_v1.copy( _unitX ).applyQuaternion( space === 'local' ? this.worldQuaternion : _identityQuaternion );
|
|
1468
|
+
_v2.copy( _unitY ).applyQuaternion( space === 'local' ? this.worldQuaternion : _identityQuaternion );
|
|
1469
|
+
_v3.copy( _unitZ ).applyQuaternion( space === 'local' ? this.worldQuaternion : _identityQuaternion );
|
|
1470
|
+
|
|
1471
|
+
// Align the plane for current transform mode, axis and space.
|
|
1472
|
+
|
|
1473
|
+
_alignVector.copy( _v2 );
|
|
1474
|
+
|
|
1475
|
+
switch ( this.mode ) {
|
|
1476
|
+
|
|
1477
|
+
case 'translate':
|
|
1478
|
+
case 'scale':
|
|
1479
|
+
switch ( this.axis ) {
|
|
1480
|
+
|
|
1481
|
+
case 'X':
|
|
1482
|
+
_alignVector.copy( this.eye ).cross( _v1 );
|
|
1483
|
+
_dirVector.copy( _v1 ).cross( _alignVector );
|
|
1484
|
+
break;
|
|
1485
|
+
case 'Y':
|
|
1486
|
+
_alignVector.copy( this.eye ).cross( _v2 );
|
|
1487
|
+
_dirVector.copy( _v2 ).cross( _alignVector );
|
|
1488
|
+
break;
|
|
1489
|
+
case 'Z':
|
|
1490
|
+
_alignVector.copy( this.eye ).cross( _v3 );
|
|
1491
|
+
_dirVector.copy( _v3 ).cross( _alignVector );
|
|
1492
|
+
break;
|
|
1493
|
+
case 'XY':
|
|
1494
|
+
_dirVector.copy( _v3 );
|
|
1495
|
+
break;
|
|
1496
|
+
case 'YZ':
|
|
1497
|
+
_dirVector.copy( _v1 );
|
|
1498
|
+
break;
|
|
1499
|
+
case 'XZ':
|
|
1500
|
+
_alignVector.copy( _v3 );
|
|
1501
|
+
_dirVector.copy( _v2 );
|
|
1502
|
+
break;
|
|
1503
|
+
case 'XYZ':
|
|
1504
|
+
case 'E':
|
|
1505
|
+
_dirVector.set( 0, 0, 0 );
|
|
1506
|
+
break;
|
|
1507
|
+
|
|
1508
|
+
}
|
|
1509
|
+
|
|
1510
|
+
break;
|
|
1511
|
+
case 'rotate':
|
|
1512
|
+
default:
|
|
1513
|
+
// special case for rotate
|
|
1514
|
+
_dirVector.set( 0, 0, 0 );
|
|
1515
|
+
|
|
1516
|
+
}
|
|
1517
|
+
|
|
1518
|
+
if ( _dirVector.length() === 0 ) {
|
|
1519
|
+
|
|
1520
|
+
// If in rotate mode, make the plane parallel to camera
|
|
1521
|
+
this.quaternion.copy( this.cameraQuaternion );
|
|
1522
|
+
|
|
1523
|
+
} else {
|
|
1524
|
+
|
|
1525
|
+
_tempMatrix.lookAt( _tempVector.set( 0, 0, 0 ), _dirVector, _alignVector );
|
|
1526
|
+
|
|
1527
|
+
this.quaternion.setFromRotationMatrix( _tempMatrix );
|
|
1528
|
+
|
|
1529
|
+
}
|
|
1530
|
+
|
|
1531
|
+
super.updateMatrixWorld( force );
|
|
1532
|
+
|
|
1533
|
+
}
|
|
1534
|
+
|
|
1535
|
+
}
|
|
1536
|
+
|
|
1537
|
+
export { TransformControls, TransformControlsGizmo, TransformControlsPlane };
|