diff --git a/src/extras/gizmo/gizmo.js b/src/extras/gizmo/gizmo.js index a174c3a59d2..f3b00066b04 100644 --- a/src/extras/gizmo/gizmo.js +++ b/src/extras/gizmo/gizmo.js @@ -213,6 +213,14 @@ class Gizmo extends EventHandler { */ _layer; + /** + * Internal flag to track if a render update is required. + * + * @type {boolean} + * @protected + */ + _renderUpdate = false; + /** * The graph nodes attached to the gizmo. * @@ -303,7 +311,7 @@ class Gizmo extends EventHandler { const enabled = state ? this.nodes.length > 0 && cameraDist > DIST_EPSILON : false; if (enabled !== this.root.enabled) { this.root.enabled = enabled; - this.fire(Gizmo.EVENT_RENDERUPDATE); + this._renderUpdate = true; } } @@ -501,7 +509,8 @@ class Gizmo extends EventHandler { this.root.setLocalPosition(position); this.fire(Gizmo.EVENT_POSITIONUPDATE, position); - this.fire(Gizmo.EVENT_RENDERUPDATE); + + this._renderUpdate = true; } /** @@ -519,7 +528,8 @@ class Gizmo extends EventHandler { this.root.setRotation(rotation); this.fire(Gizmo.EVENT_ROTATIONUPDATE, rotation.getEulerAngles()); - this.fire(Gizmo.EVENT_RENDERUPDATE); + + this._renderUpdate = true; } /** @@ -542,7 +552,8 @@ class Gizmo extends EventHandler { this.root.setLocalScale(this._scale, this._scale, this._scale); this.fire(Gizmo.EVENT_SCALEUPDATE, this._scale); - this.fire(Gizmo.EVENT_RENDERUPDATE); + + this._renderUpdate = true; } /** @@ -663,6 +674,15 @@ class Gizmo extends EventHandler { * gizmo.update(); */ update() { + if (this._renderUpdate) { + this._renderUpdate = false; + this.fire(Gizmo.EVENT_RENDERUPDATE); + } + + if (!this.enabled) { + return; + } + this._updatePosition(); this._updateRotation(); this._updateScale(); diff --git a/src/extras/gizmo/rotate-gizmo.js b/src/extras/gizmo/rotate-gizmo.js index eb7f644cbc1..63de94dd291 100644 --- a/src/extras/gizmo/rotate-gizmo.js +++ b/src/extras/gizmo/rotate-gizmo.js @@ -29,6 +29,7 @@ const color = new Color(); // constants const RING_FACING_EPSILON = 1e-4; +const UPDATE_EPSILON = 1e-6; const AXES = /** @type {('x' | 'y' | 'z')[]} */ (['x', 'y', 'z']); /** @@ -184,6 +185,14 @@ class RotateGizmo extends TransformGizmo { */ _guideAngleLines; + /** + * Internal copy of facing direction to avoid unnecessary updates. + * + * @type {Vec3} + * @private + */ + _facingDir = new Vec3(); + /** * @override */ @@ -489,6 +498,8 @@ class RotateGizmo extends TransformGizmo { } q1.setFromAxisAngle(v1, angleDelta); q1.transformVector(this._guideAngleStart, this._guideAngleEnd); + + this._renderUpdate = true; } /** @@ -552,8 +563,11 @@ class RotateGizmo extends TransformGizmo { dot = facingDir.dot(this.root.forward); sector = 1 - Math.abs(dot) > RING_FACING_EPSILON; this._shapes.z.show(sector ? 'sector' : 'ring'); + } - this.fire(TransformGizmo.EVENT_RENDERUPDATE); + if (!facingDir.equalsApprox(this._facingDir, UPDATE_EPSILON)) { + this._facingDir.copy(facingDir); + this._renderUpdate = true; } } @@ -581,7 +595,8 @@ class RotateGizmo extends TransformGizmo { } } } - this.fire(TransformGizmo.EVENT_RENDERUPDATE); + + this._renderUpdate = true; } /** diff --git a/src/extras/gizmo/scale-gizmo.js b/src/extras/gizmo/scale-gizmo.js index c3dc0adcd7b..6af5e40c4af 100644 --- a/src/extras/gizmo/scale-gizmo.js +++ b/src/extras/gizmo/scale-gizmo.js @@ -422,23 +422,66 @@ class ScaleGizmo extends TransformGizmo { const cameraDir = this.cameraDir; // axes - let dot = cameraDir.dot(this.root.right); - this._shapes.x.entity.enabled = 1 - Math.abs(dot) > GLANCE_EPSILON; + let changed = false; + let dot, enabled; + dot = cameraDir.dot(this.root.right); + enabled = 1 - Math.abs(dot) > GLANCE_EPSILON; + if (this._shapes.x.entity.enabled !== enabled) { + this._shapes.x.entity.enabled = enabled; + changed = true; + } dot = cameraDir.dot(this.root.up); - this._shapes.y.entity.enabled = 1 - Math.abs(dot) > GLANCE_EPSILON; + enabled = 1 - Math.abs(dot) > GLANCE_EPSILON; + if (this._shapes.y.entity.enabled !== enabled) { + this._shapes.y.entity.enabled = enabled; + changed = true; + } dot = cameraDir.dot(this.root.forward); - this._shapes.z.entity.enabled = 1 - Math.abs(dot) > GLANCE_EPSILON; + enabled = 1 - Math.abs(dot) > GLANCE_EPSILON; + if (this._shapes.z.entity.enabled !== enabled) { + this._shapes.z.entity.enabled = enabled; + changed = true; + } // planes + let flipped; v1.cross(cameraDir, this.root.right); - this._shapes.yz.entity.enabled = 1 - v1.length() > GLANCE_EPSILON; - this._shapes.yz.flipped = this.flipPlanes ? v2.set(0, +(v1.dot(this.root.forward) < 0), +(v1.dot(this.root.up) < 0)) : Vec3.ZERO; + enabled = 1 - v1.length() > GLANCE_EPSILON; + if (this._shapes.yz.entity.enabled !== enabled) { + this._shapes.yz.entity.enabled = enabled; + changed = true; + } + flipped = this.flipPlanes ? v2.set(0, +(v1.dot(this.root.forward) < 0), +(v1.dot(this.root.up) < 0)) : Vec3.ZERO; + if (!this._shapes.yz.flipped.equals(flipped)) { + this._shapes.yz.flipped = flipped; + changed = true; + } v1.cross(cameraDir, this.root.forward); - this._shapes.xy.entity.enabled = 1 - v1.length() > GLANCE_EPSILON; - this._shapes.xy.flipped = this.flipPlanes ? v2.set(+(v1.dot(this.root.up) < 0), +(v1.dot(this.root.right) > 0), 0) : Vec3.ZERO; + enabled = 1 - v1.length() > GLANCE_EPSILON; + if (this._shapes.xy.entity.enabled !== enabled) { + this._shapes.xy.entity.enabled = enabled; + changed = true; + } + flipped = this.flipPlanes ? v2.set(+(v1.dot(this.root.up) < 0), +(v1.dot(this.root.right) > 0), 0) : Vec3.ZERO; + if (!this._shapes.xy.flipped.equals(flipped)) { + this._shapes.xy.flipped = flipped; + changed = true; + } v1.cross(cameraDir, this.root.up); - this._shapes.xz.entity.enabled = 1 - v1.length() > GLANCE_EPSILON; - this._shapes.xz.flipped = this.flipPlanes ? v2.set(+(v1.dot(this.root.forward) > 0), 0, +(v1.dot(this.root.right) > 0)) : Vec3.ZERO; + enabled = 1 - v1.length() > GLANCE_EPSILON; + if (this._shapes.xz.entity.enabled !== enabled) { + this._shapes.xz.entity.enabled = enabled; + changed = true; + } + flipped = this.flipPlanes ? v2.set(+(v1.dot(this.root.forward) > 0), 0, +(v1.dot(this.root.right) > 0)) : Vec3.ZERO; + if (!this._shapes.xz.flipped.equals(flipped)) { + this._shapes.xz.flipped = flipped; + changed = true; + } + + if (changed) { + this._renderUpdate = true; + } } /** @@ -471,7 +514,7 @@ class ScaleGizmo extends TransformGizmo { } } - this.fire(TransformGizmo.EVENT_RENDERUPDATE); + this._renderUpdate = true; } /** diff --git a/src/extras/gizmo/transform-gizmo.js b/src/extras/gizmo/transform-gizmo.js index 83221b30934..b0547229ee7 100644 --- a/src/extras/gizmo/transform-gizmo.js +++ b/src/extras/gizmo/transform-gizmo.js @@ -543,7 +543,7 @@ class TransformGizmo extends Gizmo { } if (changed) { - this.fire(Gizmo.EVENT_RENDERUPDATE); + this._renderUpdate = true; } } diff --git a/src/extras/gizmo/translate-gizmo.js b/src/extras/gizmo/translate-gizmo.js index 7f24cc11ec1..7662b535ee6 100644 --- a/src/extras/gizmo/translate-gizmo.js +++ b/src/extras/gizmo/translate-gizmo.js @@ -402,23 +402,66 @@ class TranslateGizmo extends TransformGizmo { const cameraDir = this.cameraDir; // axes - let dot = cameraDir.dot(this.root.right); - this._shapes.x.entity.enabled = 1 - Math.abs(dot) > GLANCE_EPSILON; + let changed = false; + let dot, enabled; + dot = cameraDir.dot(this.root.right); + enabled = 1 - Math.abs(dot) > GLANCE_EPSILON; + if (this._shapes.x.entity.enabled !== enabled) { + this._shapes.x.entity.enabled = enabled; + changed = true; + } dot = cameraDir.dot(this.root.up); - this._shapes.y.entity.enabled = 1 - Math.abs(dot) > GLANCE_EPSILON; + enabled = 1 - Math.abs(dot) > GLANCE_EPSILON; + if (this._shapes.y.entity.enabled !== enabled) { + this._shapes.y.entity.enabled = enabled; + changed = true; + } dot = cameraDir.dot(this.root.forward); - this._shapes.z.entity.enabled = 1 - Math.abs(dot) > GLANCE_EPSILON; + enabled = 1 - Math.abs(dot) > GLANCE_EPSILON; + if (this._shapes.z.entity.enabled !== enabled) { + this._shapes.z.entity.enabled = enabled; + changed = true; + } // planes + let flipped; v1.cross(cameraDir, this.root.right); - this._shapes.yz.entity.enabled = 1 - v1.length() > GLANCE_EPSILON; - this._shapes.yz.flipped = this.flipPlanes ? v2.set(0, +(v1.dot(this.root.forward) < 0), +(v1.dot(this.root.up) < 0)) : Vec3.ZERO; + enabled = 1 - v1.length() > GLANCE_EPSILON; + if (this._shapes.yz.entity.enabled !== enabled) { + this._shapes.yz.entity.enabled = enabled; + changed = true; + } + flipped = this.flipPlanes ? v2.set(0, +(v1.dot(this.root.forward) < 0), +(v1.dot(this.root.up) < 0)) : Vec3.ZERO; + if (!this._shapes.yz.flipped.equals(flipped)) { + this._shapes.yz.flipped = flipped; + changed = true; + } v1.cross(cameraDir, this.root.forward); - this._shapes.xy.entity.enabled = 1 - v1.length() > GLANCE_EPSILON; - this._shapes.xy.flipped = this.flipPlanes ? v2.set(+(v1.dot(this.root.up) < 0), +(v1.dot(this.root.right) > 0), 0) : Vec3.ZERO; + enabled = 1 - v1.length() > GLANCE_EPSILON; + if (this._shapes.xy.entity.enabled !== enabled) { + this._shapes.xy.entity.enabled = enabled; + changed = true; + } + flipped = this.flipPlanes ? v2.set(+(v1.dot(this.root.up) < 0), +(v1.dot(this.root.right) > 0), 0) : Vec3.ZERO; + if (!this._shapes.xy.flipped.equals(flipped)) { + this._shapes.xy.flipped = flipped; + changed = true; + } v1.cross(cameraDir, this.root.up); - this._shapes.xz.entity.enabled = 1 - v1.length() > GLANCE_EPSILON; - this._shapes.xz.flipped = this.flipPlanes ? v2.set(+(v1.dot(this.root.forward) > 0), 0, +(v1.dot(this.root.right) > 0)) : Vec3.ZERO; + enabled = 1 - v1.length() > GLANCE_EPSILON; + if (this._shapes.xz.entity.enabled !== enabled) { + this._shapes.xz.entity.enabled = enabled; + changed = true; + } + flipped = this.flipPlanes ? v2.set(+(v1.dot(this.root.forward) > 0), 0, +(v1.dot(this.root.right) > 0)) : Vec3.ZERO; + if (!this._shapes.xz.flipped.equals(flipped)) { + this._shapes.xz.flipped = flipped; + changed = true; + } + + if (changed) { + this._renderUpdate = true; + } } /** @@ -450,7 +493,7 @@ class TranslateGizmo extends TransformGizmo { } } - this.fire(TransformGizmo.EVENT_RENDERUPDATE); + this._renderUpdate = true; } /**