Skip to content

Commit e2f5e07

Browse files
committed
Gizmo render update cleanup (#7983)
* Add internal facing direction tracking to RotateGizmo * fix: only update position rotation and scale if enabled * fix: replace direct render update calls with internal flag for efficiency * fix: enable render updates in RotateGizmo after angle adjustment * fix: add check for facing direction change in RotateGizmo * fix: update comment to clarify purpose of internal facing direction vector * fix: optimize shape visibility updates in ScaleGizmo and TranslateGizmo * fix: optimize facing direction check in RotateGizmo to reduce unnecessary updates * fix: move render update check to update method in Gizmo class
1 parent b678fc1 commit e2f5e07

File tree

5 files changed

+180
-35
lines changed

5 files changed

+180
-35
lines changed

src/extras/gizmo/gizmo.js

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,14 @@ class Gizmo extends EventHandler {
212212
*/
213213
_layer;
214214

215+
/**
216+
* Internal flag to track if a render update is required.
217+
*
218+
* @type {boolean}
219+
* @protected
220+
*/
221+
_renderUpdate = false;
222+
215223
/**
216224
* The graph nodes attached to the gizmo.
217225
*
@@ -302,7 +310,7 @@ class Gizmo extends EventHandler {
302310
const enabled = state ? this.nodes.length > 0 && cameraDist > DIST_EPSILON : false;
303311
if (enabled !== this.root.enabled) {
304312
this.root.enabled = enabled;
305-
this.fire(Gizmo.EVENT_RENDERUPDATE);
313+
this._renderUpdate = true;
306314
}
307315
}
308316

@@ -500,7 +508,8 @@ class Gizmo extends EventHandler {
500508

501509
this.root.setLocalPosition(position);
502510
this.fire(Gizmo.EVENT_POSITIONUPDATE, position);
503-
this.fire(Gizmo.EVENT_RENDERUPDATE);
511+
512+
this._renderUpdate = true;
504513
}
505514

506515
/**
@@ -518,7 +527,8 @@ class Gizmo extends EventHandler {
518527

519528
this.root.setLocalEulerAngles(angles);
520529
this.fire(Gizmo.EVENT_ROTATIONUPDATE, angles);
521-
this.fire(Gizmo.EVENT_RENDERUPDATE);
530+
531+
this._renderUpdate = true;
522532
}
523533

524534
/**
@@ -541,7 +551,8 @@ class Gizmo extends EventHandler {
541551

542552
this.root.setLocalScale(this._scale, this._scale, this._scale);
543553
this.fire(Gizmo.EVENT_SCALEUPDATE, this._scale);
544-
this.fire(Gizmo.EVENT_RENDERUPDATE);
554+
555+
this._renderUpdate = true;
545556
}
546557

547558
/**
@@ -662,6 +673,15 @@ class Gizmo extends EventHandler {
662673
* gizmo.update();
663674
*/
664675
update() {
676+
if (this._renderUpdate) {
677+
this._renderUpdate = false;
678+
this.fire(Gizmo.EVENT_RENDERUPDATE);
679+
}
680+
681+
if (!this.enabled) {
682+
return;
683+
}
684+
665685
this._updatePosition();
666686
this._updateRotation();
667687
this._updateScale();

src/extras/gizmo/rotate-gizmo.js

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ const color = new Color();
2828
// constants
2929
const ROTATE_FACING_EPSILON = 0.1;
3030
const RING_FACING_EPSILON = 1e-4;
31+
const UPDATE_EPSILON = 1e-6;
3132

3233
/**
3334
* The RotateGizmo provides interactive 3D manipulation handles for rotating/reorienting
@@ -158,6 +159,14 @@ class RotateGizmo extends TransformGizmo {
158159
*/
159160
_guideAngleLines;
160161

162+
/**
163+
* Internal copy of facing direction to avoid unnecessary updates.
164+
*
165+
* @type {Vec3}
166+
* @private
167+
*/
168+
_facingDir = new Vec3();
169+
161170
/**
162171
* @override
163172
*/
@@ -398,6 +407,8 @@ class RotateGizmo extends TransformGizmo {
398407
}
399408
q1.setFromAxisAngle(v1, angleDelta);
400409
q1.transformVector(this._guideAngleStart, this._guideAngleEnd);
410+
411+
this._renderUpdate = true;
401412
}
402413

403414
/**
@@ -461,8 +472,11 @@ class RotateGizmo extends TransformGizmo {
461472
dot = facingDir.dot(this.root.forward);
462473
sector = 1 - Math.abs(dot) > RING_FACING_EPSILON;
463474
this._shapes.z.show(sector ? 'sector' : 'ring');
475+
}
464476

465-
this.fire(TransformGizmo.EVENT_RENDERUPDATE);
477+
if (!facingDir.equalsApprox(this._facingDir, UPDATE_EPSILON)) {
478+
this._facingDir.copy(facingDir);
479+
this._renderUpdate = true;
466480
}
467481
}
468482

@@ -490,7 +504,8 @@ class RotateGizmo extends TransformGizmo {
490504
}
491505
}
492506
}
493-
this.fire(TransformGizmo.EVENT_RENDERUPDATE);
507+
508+
this._renderUpdate = true;
494509
}
495510

496511
/**

src/extras/gizmo/scale-gizmo.js

Lines changed: 69 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -445,37 +445,92 @@ class ScaleGizmo extends TransformGizmo {
445445
const cameraDir = this.cameraDir;
446446

447447
// axes
448-
let dot = cameraDir.dot(this.root.right);
449-
this._shapes.x.entity.enabled = 1 - Math.abs(dot) > GLANCE_EPSILON;
448+
let changed = false;
449+
let dot, enabled, flipAxis;
450+
dot = cameraDir.dot(this.root.right);
451+
enabled = 1 - Math.abs(dot) > GLANCE_EPSILON;
452+
if (this._shapes.x.entity.enabled !== enabled) {
453+
this._shapes.x.entity.enabled = enabled;
454+
changed = true;
455+
}
450456
if (this.flipAxes) {
451-
this._shapes.x.flipped = dot < 0;
457+
flipAxis = dot < 0;
458+
if (this._shapes.x.flipped !== flipAxis) {
459+
this._shapes.x.flipped = flipAxis;
460+
changed = true;
461+
}
452462
}
453463
dot = cameraDir.dot(this.root.up);
454-
this._shapes.y.entity.enabled = 1 - Math.abs(dot) > GLANCE_EPSILON;
464+
enabled = 1 - Math.abs(dot) > GLANCE_EPSILON;
465+
if (this._shapes.y.entity.enabled !== enabled) {
466+
this._shapes.y.entity.enabled = enabled;
467+
changed = true;
468+
}
455469
if (this.flipAxes) {
456-
this._shapes.y.flipped = dot < 0;
470+
flipAxis = dot < 0;
471+
if (this._shapes.y.flipped !== flipAxis) {
472+
this._shapes.y.flipped = flipAxis;
473+
changed = true;
474+
}
457475
}
458476
dot = cameraDir.dot(this.root.forward);
459-
this._shapes.z.entity.enabled = 1 - Math.abs(dot) > GLANCE_EPSILON;
477+
enabled = 1 - Math.abs(dot) > GLANCE_EPSILON;
478+
if (this._shapes.z.entity.enabled !== enabled) {
479+
this._shapes.z.entity.enabled = enabled;
480+
changed = true;
481+
}
460482
if (this.flipAxes) {
461-
this._shapes.z.flipped = dot > 0;
483+
flipAxis = dot > 0;
484+
if (this._shapes.z.flipped !== flipAxis) {
485+
this._shapes.z.flipped = flipAxis;
486+
changed = true;
487+
}
462488
}
463489

464490
// planes
491+
let flipped;
465492
v1.cross(cameraDir, this.root.right);
466-
this._shapes.yz.entity.enabled = 1 - v1.length() > GLANCE_EPSILON;
467493
if (this.flipPlanes) {
468-
this._shapes.yz.flipped = v2.set(0, +(v1.dot(this.root.forward) < 0), +(v1.dot(this.root.up) < 0));
494+
enabled = 1 - v1.length() > GLANCE_EPSILON;
495+
if (this._shapes.yz.entity.enabled !== enabled) {
496+
this._shapes.yz.entity.enabled = enabled;
497+
changed = true;
498+
}
499+
}
500+
flipped = v2.set(0, +(v1.dot(this.root.forward) < 0), +(v1.dot(this.root.up) < 0));
501+
if (!this._shapes.yz.flipped.equals(flipped)) {
502+
this._shapes.yz.flipped = flipped;
503+
changed = true;
469504
}
470505
v1.cross(cameraDir, this.root.forward);
471-
this._shapes.xy.entity.enabled = 1 - v1.length() > GLANCE_EPSILON;
472506
if (this.flipPlanes) {
473-
this._shapes.xy.flipped = v2.set(+(v1.dot(this.root.up) < 0), +(v1.dot(this.root.right) > 0), 0);
507+
enabled = 1 - v1.length() > GLANCE_EPSILON;
508+
if (this._shapes.xy.entity.enabled !== enabled) {
509+
this._shapes.xy.entity.enabled = enabled;
510+
changed = true;
511+
}
512+
}
513+
flipped = v2.set(+(v1.dot(this.root.up) < 0), +(v1.dot(this.root.right) > 0), 0);
514+
if (!this._shapes.xy.flipped.equals(flipped)) {
515+
this._shapes.xy.flipped = flipped;
516+
changed = true;
474517
}
475518
v1.cross(cameraDir, this.root.up);
476-
this._shapes.xz.entity.enabled = 1 - v1.length() > GLANCE_EPSILON;
477519
if (this.flipPlanes) {
478-
this._shapes.xz.flipped = v2.set(+(v1.dot(this.root.forward) > 0), 0, +(v1.dot(this.root.right) > 0));
520+
enabled = 1 - v1.length() > GLANCE_EPSILON;
521+
if (this._shapes.xz.entity.enabled !== enabled) {
522+
this._shapes.xz.entity.enabled = enabled;
523+
changed = true;
524+
}
525+
}
526+
flipped = v2.set(+(v1.dot(this.root.forward) > 0), 0, +(v1.dot(this.root.right) > 0));
527+
if (!this._shapes.xz.flipped.equals(flipped)) {
528+
this._shapes.xz.flipped = flipped;
529+
changed = true;
530+
}
531+
532+
if (changed) {
533+
this._renderUpdate = true;
479534
}
480535
}
481536

@@ -509,7 +564,7 @@ class ScaleGizmo extends TransformGizmo {
509564
}
510565
}
511566

512-
this.fire(TransformGizmo.EVENT_RENDERUPDATE);
567+
this._renderUpdate = true;
513568
}
514569

515570
/**

src/extras/gizmo/transform-gizmo.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -545,7 +545,7 @@ class TransformGizmo extends Gizmo {
545545
}
546546

547547
if (changed) {
548-
this.fire(Gizmo.EVENT_RENDERUPDATE);
548+
this._renderUpdate = true;
549549
}
550550
}
551551

src/extras/gizmo/translate-gizmo.js

Lines changed: 69 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -425,37 +425,92 @@ class TranslateGizmo extends TransformGizmo {
425425
const cameraDir = this.cameraDir;
426426

427427
// axes
428-
let dot = cameraDir.dot(this.root.right);
429-
this._shapes.x.entity.enabled = 1 - Math.abs(dot) > GLANCE_EPSILON;
428+
let changed = false;
429+
let dot, enabled, flipAxis;
430+
dot = cameraDir.dot(this.root.right);
431+
enabled = 1 - Math.abs(dot) > GLANCE_EPSILON;
432+
if (this._shapes.x.entity.enabled !== enabled) {
433+
this._shapes.x.entity.enabled = enabled;
434+
changed = true;
435+
}
430436
if (this.flipAxes) {
431-
this._shapes.x.flipped = dot < 0;
437+
flipAxis = dot < 0;
438+
if (this._shapes.x.flipped !== flipAxis) {
439+
this._shapes.x.flipped = flipAxis;
440+
changed = true;
441+
}
432442
}
433443
dot = cameraDir.dot(this.root.up);
434-
this._shapes.y.entity.enabled = 1 - Math.abs(dot) > GLANCE_EPSILON;
444+
enabled = 1 - Math.abs(dot) > GLANCE_EPSILON;
445+
if (this._shapes.y.entity.enabled !== enabled) {
446+
this._shapes.y.entity.enabled = enabled;
447+
changed = true;
448+
}
435449
if (this.flipAxes) {
436-
this._shapes.y.flipped = dot < 0;
450+
flipAxis = dot < 0;
451+
if (this._shapes.y.flipped !== flipAxis) {
452+
this._shapes.y.flipped = flipAxis;
453+
changed = true;
454+
}
437455
}
438456
dot = cameraDir.dot(this.root.forward);
439-
this._shapes.z.entity.enabled = 1 - Math.abs(dot) > GLANCE_EPSILON;
457+
enabled = 1 - Math.abs(dot) > GLANCE_EPSILON;
458+
if (this._shapes.z.entity.enabled !== enabled) {
459+
this._shapes.z.entity.enabled = enabled;
460+
changed = true;
461+
}
440462
if (this.flipAxes) {
441-
this._shapes.z.flipped = dot > 0;
463+
flipAxis = dot > 0;
464+
if (this._shapes.z.flipped !== flipAxis) {
465+
this._shapes.z.flipped = flipAxis;
466+
changed = true;
467+
}
442468
}
443469

444470
// planes
471+
let flipped;
445472
v1.cross(cameraDir, this.root.right);
446-
this._shapes.yz.entity.enabled = 1 - v1.length() > GLANCE_EPSILON;
447473
if (this.flipPlanes) {
448-
this._shapes.yz.flipped = v2.set(0, +(v1.dot(this.root.forward) < 0), +(v1.dot(this.root.up) < 0));
474+
enabled = 1 - v1.length() > GLANCE_EPSILON;
475+
if (this._shapes.yz.entity.enabled !== enabled) {
476+
this._shapes.yz.entity.enabled = enabled;
477+
changed = true;
478+
}
479+
}
480+
flipped = v2.set(0, +(v1.dot(this.root.forward) < 0), +(v1.dot(this.root.up) < 0));
481+
if (!this._shapes.yz.flipped.equals(flipped)) {
482+
this._shapes.yz.flipped = flipped;
483+
changed = true;
449484
}
450485
v1.cross(cameraDir, this.root.forward);
451-
this._shapes.xy.entity.enabled = 1 - v1.length() > GLANCE_EPSILON;
452486
if (this.flipPlanes) {
453-
this._shapes.xy.flipped = v2.set(+(v1.dot(this.root.up) < 0), +(v1.dot(this.root.right) > 0), 0);
487+
enabled = 1 - v1.length() > GLANCE_EPSILON;
488+
if (this._shapes.xy.entity.enabled !== enabled) {
489+
this._shapes.xy.entity.enabled = enabled;
490+
changed = true;
491+
}
492+
}
493+
flipped = v2.set(+(v1.dot(this.root.up) < 0), +(v1.dot(this.root.right) > 0), 0);
494+
if (!this._shapes.xy.flipped.equals(flipped)) {
495+
this._shapes.xy.flipped = flipped;
496+
changed = true;
454497
}
455498
v1.cross(cameraDir, this.root.up);
456-
this._shapes.xz.entity.enabled = 1 - v1.length() > GLANCE_EPSILON;
457499
if (this.flipPlanes) {
458-
this._shapes.xz.flipped = v2.set(+(v1.dot(this.root.forward) > 0), 0, +(v1.dot(this.root.right) > 0));
500+
enabled = 1 - v1.length() > GLANCE_EPSILON;
501+
if (this._shapes.xz.entity.enabled !== enabled) {
502+
this._shapes.xz.entity.enabled = enabled;
503+
changed = true;
504+
}
505+
}
506+
flipped = v2.set(+(v1.dot(this.root.forward) > 0), 0, +(v1.dot(this.root.right) > 0));
507+
if (!this._shapes.xz.flipped.equals(flipped)) {
508+
this._shapes.xz.flipped = flipped;
509+
changed = true;
510+
}
511+
512+
if (changed) {
513+
this._renderUpdate = true;
459514
}
460515
}
461516

@@ -488,7 +543,7 @@ class TranslateGizmo extends TransformGizmo {
488543
}
489544
}
490545

491-
this.fire(TransformGizmo.EVENT_RENDERUPDATE);
546+
this._renderUpdate = true;
492547
}
493548

494549
/**

0 commit comments

Comments
 (0)