Skip to content

Commit

Permalink
Gizmos axis flipping (playcanvas#7063)
Browse files Browse the repository at this point in the history
* Added axis flipping to scale and translate gizmos

* Hides axes at glancing angles

* Fixed forward axis comparison

* Updated shape look at code to only update on angle change
  • Loading branch information
kpal81xd committed Oct 24, 2024
1 parent c99f63b commit 9889e72
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 18 deletions.
51 changes: 42 additions & 9 deletions src/extras/gizmo/scale-gizmo.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const tmpQ1 = new Quat();

// constants
const GLANCE_EPSILON = 0.98;
const CAMERA_EPSILON = 0.999;

/**
* Scaling gizmo.
Expand Down Expand Up @@ -95,6 +96,14 @@ class ScaleGizmo extends TransformGizmo {
*/
_nodeScales = new Map();

/**
* Internal forward vector of the camera in the direction of the gizmo.
*
* @type {Vec3}
* @private
*/
_forward = new Vec3();

/**
* Internal state if transform should use uniform scaling.
*
Expand All @@ -113,7 +122,7 @@ class ScaleGizmo extends TransformGizmo {
*
* @type {boolean}
*/
flipPlanes = true;
flipShapes = true;

/**
* The lower bound for scaling.
Expand Down Expand Up @@ -154,7 +163,7 @@ class ScaleGizmo extends TransformGizmo {
});

this._app.on('prerender', () => {
this._planesLookAtCamera();
this._shapesLookAtCamera();
});
}

Expand Down Expand Up @@ -371,22 +380,46 @@ class ScaleGizmo extends TransformGizmo {
/**
* @private
*/
_planesLookAtCamera() {
tmpV1.cross(this._camera.entity.forward, this.root.right);
_shapesLookAtCamera() {
tmpV1.copy(this.root.getPosition()).sub(this._camera.entity.getPosition()).normalize();
if (tmpV1.dot(this._forward) > CAMERA_EPSILON) {
return;
}
this._forward.copy(tmpV1);

let dot = this._forward.dot(this.root.right);
this._shapes.x.entity.enabled = Math.abs(dot) < GLANCE_EPSILON;
if (this.flipShapes) {
this._shapes.x.flipped = dot > 0;
}

dot = this._forward.dot(this.root.up);
this._shapes.y.entity.enabled = Math.abs(dot) < GLANCE_EPSILON;
if (this.flipShapes) {
this._shapes.y.flipped = dot > 0;
}

dot = this._forward.dot(this.root.forward);
this._shapes.z.entity.enabled = Math.abs(dot) < GLANCE_EPSILON;
if (this.flipShapes) {
this._shapes.z.flipped = dot < 0;
}

tmpV1.cross(this._forward, this.root.right);
this._shapes.yz.entity.enabled = tmpV1.length() < GLANCE_EPSILON;
if (this.flipPlanes) {
if (this.flipShapes) {
this._shapes.yz.flipped = tmpV2.set(0, +(tmpV1.dot(this.root.forward) > 0), +(tmpV1.dot(this.root.up) > 0));
}

tmpV1.cross(this._camera.entity.forward, this.root.forward);
tmpV1.cross(this._forward, this.root.forward);
this._shapes.xy.entity.enabled = tmpV1.length() < GLANCE_EPSILON;
if (this.flipPlanes) {
if (this.flipShapes) {
this._shapes.xy.flipped = tmpV2.set(+(tmpV1.dot(this.root.up) > 0), +(tmpV1.dot(this.root.right) < 0), 0);
}

tmpV1.cross(this._camera.entity.forward, this.root.up);
tmpV1.cross(this._forward, this.root.up);
this._shapes.xz.entity.enabled = tmpV1.length() < GLANCE_EPSILON;
if (this.flipPlanes) {
if (this.flipShapes) {
this._shapes.xz.flipped = tmpV2.set(+(tmpV1.dot(this.root.forward) < 0), 0, +(tmpV1.dot(this.root.right) < 0));
}
}
Expand Down
21 changes: 21 additions & 0 deletions src/extras/gizmo/shape/arrow-shape.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ class ArrowShape extends Shape {

_line;

_flipped = false;

constructor(device, options = {}) {
super(device, options);

Expand Down Expand Up @@ -95,6 +97,25 @@ class ArrowShape extends Shape {
return this._tolerance;
}

set flipped(value) {
if (this._flipped === value) {
return;
}
this._flipped = value;
if (this._rotation.equals(Vec3.ZERO)) {
tmpV1.set(0, 0, this._flipped ? 180 : 0);
} else {
tmpV1.copy(this._rotation).mulScalar(this._flipped ? -1 : 1);
}

this._line.enabled = !this._flipped;
this.entity.setLocalEulerAngles(tmpV1);
}

get flipped() {
return this._flipped;
}

_createArrow() {
this._createRoot('arrow');

Expand Down
21 changes: 21 additions & 0 deletions src/extras/gizmo/shape/boxline-shape.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ class BoxLineShape extends Shape {

_line;

_flipped = false;

constructor(device, options = {}) {
super(device, options);

Expand Down Expand Up @@ -84,6 +86,25 @@ class BoxLineShape extends Shape {
return this._tolerance;
}

set flipped(value) {
if (this._flipped === value) {
return;
}
this._flipped = value;
if (this._rotation.equals(Vec3.ZERO)) {
tmpV1.set(0, 0, this._flipped ? 180 : 0);
} else {
tmpV1.copy(this._rotation).mulScalar(this._flipped ? -1 : 1);
}

this._line.enabled = !this._flipped;
this.entity.setLocalEulerAngles(tmpV1);
}

get flipped() {
return this._flipped;
}

_createBoxLine() {
this._createRoot('boxLine');

Expand Down
51 changes: 42 additions & 9 deletions src/extras/gizmo/translate-gizmo.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const tmpQ1 = new Quat();

// constants
const GLANCE_EPSILON = 0.98;
const CAMERA_EPSILON = 0.999;

/**
* Translation gizmo.
Expand Down Expand Up @@ -107,6 +108,14 @@ class TranslateGizmo extends TransformGizmo {
*/
_nodePositions = new Map();

/**
* Internal forward vector of the camera in the direction of the gizmo.
*
* @type {Vec3}
* @private
*/
_forward = new Vec3();

/**
* @override
*/
Expand All @@ -117,7 +126,7 @@ class TranslateGizmo extends TransformGizmo {
*
* @type {boolean}
*/
flipPlanes = true;
flipShapes = true;

/**
* Creates a new TranslateGizmo object.
Expand Down Expand Up @@ -151,7 +160,7 @@ class TranslateGizmo extends TransformGizmo {
});

this._app.on('prerender', () => {
this._planesLookAtCamera();
this._shapesLookAtCamera();
});
}

Expand Down Expand Up @@ -360,22 +369,46 @@ class TranslateGizmo extends TransformGizmo {
/**
* @private
*/
_planesLookAtCamera() {
tmpV1.cross(this._camera.entity.forward, this.root.right);
_shapesLookAtCamera() {
tmpV1.copy(this.root.getPosition()).sub(this._camera.entity.getPosition()).normalize();
if (tmpV1.dot(this._forward) > CAMERA_EPSILON) {
return;
}
this._forward.copy(tmpV1);

let dot = this._forward.dot(this.root.right);
this._shapes.x.entity.enabled = Math.abs(dot) < GLANCE_EPSILON;
if (this.flipShapes) {
this._shapes.x.flipped = dot > 0;
}

dot = this._forward.dot(this.root.up);
this._shapes.y.entity.enabled = Math.abs(dot) < GLANCE_EPSILON;
if (this.flipShapes) {
this._shapes.y.flipped = dot > 0;
}

dot = this._forward.dot(this.root.forward);
this._shapes.z.entity.enabled = Math.abs(dot) < GLANCE_EPSILON;
if (this.flipShapes) {
this._shapes.z.flipped = dot < 0;
}

tmpV1.cross(this._forward, this.root.right);
this._shapes.yz.entity.enabled = tmpV1.length() < GLANCE_EPSILON;
if (this.flipPlanes) {
if (this.flipShapes) {
this._shapes.yz.flipped = tmpV2.set(0, +(tmpV1.dot(this.root.forward) > 0), +(tmpV1.dot(this.root.up) > 0));
}

tmpV1.cross(this._camera.entity.forward, this.root.forward);
tmpV1.cross(this._forward, this.root.forward);
this._shapes.xy.entity.enabled = tmpV1.length() < GLANCE_EPSILON;
if (this.flipPlanes) {
if (this.flipShapes) {
this._shapes.xy.flipped = tmpV2.set(+(tmpV1.dot(this.root.up) > 0), +(tmpV1.dot(this.root.right) < 0), 0);
}

tmpV1.cross(this._camera.entity.forward, this.root.up);
tmpV1.cross(this._forward, this.root.up);
this._shapes.xz.entity.enabled = tmpV1.length() < GLANCE_EPSILON;
if (this.flipPlanes) {
if (this.flipShapes) {
this._shapes.xz.flipped = tmpV2.set(+(tmpV1.dot(this.root.forward) < 0), 0, +(tmpV1.dot(this.root.right) < 0));
}
}
Expand Down

0 comments on commit 9889e72

Please sign in to comment.