Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 34 additions & 46 deletions src/extras/gizmo/rotate-gizmo.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,14 +122,6 @@ class RotateGizmo extends TransformGizmo {
*/
_selectionStartAngle = 0;

/**
* Internal selection screen point in 2D space.
*
* @type {Vec2}
* @private
*/
_selectionScreenPoint = new Vec2();

/**
* Internal mapping from each attached node to their starting rotation in local space.
*
Expand All @@ -154,6 +146,22 @@ class RotateGizmo extends TransformGizmo {
*/
_nodeOffsets = new Map();

/**
* Internal vector for storing the mouse position in screen space.
*
* @type {Vec2}
* @private
*/
_screenPos = new Vec2();

/**
* Internal vector for storing the mouse start position in screen space.
*
* @type {Vec2}
* @private
*/
_screenStartPos = new Vec2();

/**
* Internal vector for the start point of the guide line angle.
*
Expand Down Expand Up @@ -213,6 +221,8 @@ class RotateGizmo extends TransformGizmo {

this._createTransform();

this._guideMouseLine = new MeshLine(this._app, this._layer);

this._guideAngleLines = [
new MeshLine(this._app, this._layer),
new MeshLine(this._app, this._layer)
Expand All @@ -222,12 +232,13 @@ class RotateGizmo extends TransformGizmo {
line.entity.enabled = false;
});

this.on(TransformGizmo.EVENT_TRANSFORMSTART, (point, x, y) => {
this.on(TransformGizmo.EVENT_TRANSFORMSTART, (_point, x, y) => {
// store start screen point
this._selectionScreenPoint.set(x, y);
this._screenPos.set(x, y);
this._screenStartPos.set(x, y);

// store start angle
this._selectionStartAngle = this._calculateArcAngle(point, x, y);
this._selectionStartAngle = this._calculateArcAngle(x, y);

// store initial node rotations
this._storeNodeRotations();
Expand All @@ -248,17 +259,19 @@ class RotateGizmo extends TransformGizmo {
return;
}

// update screen point
this._screenPos.set(x, y);

if (axis === 'xyz') {
// calculate angle axis and delta and update node rotations
const facingDir = v1.copy(this.facingDir);
const delta = v2.copy(point).sub(this._selectionStartPoint);
const angleAxis = v1.cross(facingDir, delta).normalize();

const angleDelta = screen.set(x, y).distance(this._selectionScreenPoint);
const angleDelta = this._screenPos.distance(this._screenStartPos);
this._setNodeRotations(axis, angleAxis, angleDelta);
} else {
// calculate angle axis and delta and update node rotations
let angleDelta = this._calculateArcAngle(point, x, y) - this._selectionStartAngle;
let angleDelta = this._calculateArcAngle(x, y) - this._selectionStartAngle;
if (this.snap) {
angleDelta = Math.round(angleDelta / this.snapIncrement) * this.snapIncrement;
}
Expand All @@ -269,7 +282,6 @@ class RotateGizmo extends TransformGizmo {
this._updateGuidePoints(angleDelta);
this._angleGuide(true);
}

});

this.on(TransformGizmo.EVENT_TRANSFORMEND, () => {
Expand Down Expand Up @@ -633,13 +645,12 @@ class RotateGizmo extends TransformGizmo {
}

/**
* @param {Vec3} point - The point.
* @param {number} x - The x coordinate.
* @param {number} y - The y coordinate.
* @returns {number} The angle.
* @protected
*/
_calculateArcAngle(point, x, y) {
_calculateArcAngle(x, y) {
const gizmoPos = this.root.getLocalPosition();

const axis = this._selectedAxis;
Expand All @@ -652,35 +663,12 @@ class RotateGizmo extends TransformGizmo {
const facingDir = v2.copy(this.facingDir);
const facingDot = plane.normal.dot(facingDir);
if (this.orbitRotation || (1 - Math.abs(facingDot)) < ROTATE_FACING_EPSILON) {
// plane facing camera so based on mouse position around gizmo
v1.sub2(point, gizmoPos);

switch (axis) {
case 'x': {
// convert to local space
q1.copy(this._rootStartRot).invert().transformVector(v1, v1);
angle = Math.atan2(v1.z, v1.y) * math.RAD_TO_DEG;
break;
}
case 'y': {
// convert to local space
q1.copy(this._rootStartRot).invert().transformVector(v1, v1);
angle = Math.atan2(v1.x, v1.z) * math.RAD_TO_DEG;
break;
}
case 'z': {
// convert to local space
q1.copy(this._rootStartRot).invert().transformVector(v1, v1);
angle = Math.atan2(v1.y, v1.x) * math.RAD_TO_DEG;
break;
}
case 'f': {
// convert to camera space
q1.copy(this._camera.entity.getRotation()).invert().transformVector(v1, v1);
angle = Math.sign(facingDot) * Math.atan2(v1.y, v1.x) * math.RAD_TO_DEG;
break;
}
}
// convert gizmo position to screen space
const screenPos = this._camera.worldToScreen(gizmoPos, v1);

// calculate angle based on mouse position around gizmo
const dir = screen.set(x - screenPos.x, y - screenPos.y).normalize();
angle = -Math.sign(facingDot) * Math.atan2(dir.y, dir.x) * math.RAD_TO_DEG;
} else {
// convert rotation axis to screen space
v1.copy(gizmoPos);
Expand Down
24 changes: 6 additions & 18 deletions src/extras/gizmo/scale-gizmo.js
Original file line number Diff line number Diff line change
Expand Up @@ -447,36 +447,24 @@ class ScaleGizmo extends TransformGizmo {
// axes
let dot = cameraDir.dot(this.root.right);
this._shapes.x.entity.enabled = 1 - Math.abs(dot) > GLANCE_EPSILON;
if (this.flipAxes) {
this._shapes.x.flipped = dot < 0;
}
this._shapes.x.flipped = this.flipAxes && dot < 0;
dot = cameraDir.dot(this.root.up);
this._shapes.y.entity.enabled = 1 - Math.abs(dot) > GLANCE_EPSILON;
if (this.flipAxes) {
this._shapes.y.flipped = dot < 0;
}
this._shapes.y.flipped = this.flipAxes && dot < 0;
dot = cameraDir.dot(this.root.forward);
this._shapes.z.entity.enabled = 1 - Math.abs(dot) > GLANCE_EPSILON;
if (this.flipAxes) {
this._shapes.z.flipped = dot > 0;
}
this._shapes.z.flipped = this.flipAxes && dot > 0;

// planes
v1.cross(cameraDir, this.root.right);
this._shapes.yz.entity.enabled = 1 - v1.length() > GLANCE_EPSILON;
if (this.flipPlanes) {
this._shapes.yz.flipped = v2.set(0, +(v1.dot(this.root.forward) < 0), +(v1.dot(this.root.up) < 0));
}
this._shapes.yz.flipped = this.flipPlanes ? v2.set(0, +(v1.dot(this.root.forward) < 0), +(v1.dot(this.root.up) < 0)) : Vec3.ZERO;
v1.cross(cameraDir, this.root.forward);
this._shapes.xy.entity.enabled = 1 - v1.length() > GLANCE_EPSILON;
if (this.flipPlanes) {
this._shapes.xy.flipped = v2.set(+(v1.dot(this.root.up) < 0), +(v1.dot(this.root.right) > 0), 0);
}
this._shapes.xy.flipped = this.flipPlanes ? v2.set(+(v1.dot(this.root.up) < 0), +(v1.dot(this.root.right) > 0), 0) : Vec3.ZERO;
v1.cross(cameraDir, this.root.up);
this._shapes.xz.entity.enabled = 1 - v1.length() > GLANCE_EPSILON;
if (this.flipPlanes) {
this._shapes.xz.flipped = v2.set(+(v1.dot(this.root.forward) > 0), 0, +(v1.dot(this.root.right) > 0));
}
this._shapes.xz.flipped = this.flipPlanes ? v2.set(+(v1.dot(this.root.forward) > 0), 0, +(v1.dot(this.root.right) > 0)) : Vec3.ZERO;
}

/**
Expand Down
24 changes: 6 additions & 18 deletions src/extras/gizmo/translate-gizmo.js
Original file line number Diff line number Diff line change
Expand Up @@ -427,36 +427,24 @@ class TranslateGizmo extends TransformGizmo {
// axes
let dot = cameraDir.dot(this.root.right);
this._shapes.x.entity.enabled = 1 - Math.abs(dot) > GLANCE_EPSILON;
if (this.flipAxes) {
this._shapes.x.flipped = dot < 0;
}
this._shapes.x.flipped = this.flipAxes && dot < 0;
dot = cameraDir.dot(this.root.up);
this._shapes.y.entity.enabled = 1 - Math.abs(dot) > GLANCE_EPSILON;
if (this.flipAxes) {
this._shapes.y.flipped = dot < 0;
}
this._shapes.y.flipped = this.flipAxes && dot < 0;
dot = cameraDir.dot(this.root.forward);
this._shapes.z.entity.enabled = 1 - Math.abs(dot) > GLANCE_EPSILON;
if (this.flipAxes) {
this._shapes.z.flipped = dot > 0;
}
this._shapes.z.flipped = this.flipAxes && dot > 0;

// planes
v1.cross(cameraDir, this.root.right);
this._shapes.yz.entity.enabled = 1 - v1.length() > GLANCE_EPSILON;
if (this.flipPlanes) {
this._shapes.yz.flipped = v2.set(0, +(v1.dot(this.root.forward) < 0), +(v1.dot(this.root.up) < 0));
}
this._shapes.yz.flipped = this.flipPlanes ? v2.set(0, +(v1.dot(this.root.forward) < 0), +(v1.dot(this.root.up) < 0)) : Vec3.ZERO;
v1.cross(cameraDir, this.root.forward);
this._shapes.xy.entity.enabled = 1 - v1.length() > GLANCE_EPSILON;
if (this.flipPlanes) {
this._shapes.xy.flipped = v2.set(+(v1.dot(this.root.up) < 0), +(v1.dot(this.root.right) > 0), 0);
}
this._shapes.xy.flipped = this.flipPlanes ? v2.set(+(v1.dot(this.root.up) < 0), +(v1.dot(this.root.right) > 0), 0) : Vec3.ZERO;
v1.cross(cameraDir, this.root.up);
this._shapes.xz.entity.enabled = 1 - v1.length() > GLANCE_EPSILON;
if (this.flipPlanes) {
this._shapes.xz.flipped = v2.set(+(v1.dot(this.root.forward) > 0), 0, +(v1.dot(this.root.right) > 0));
}
this._shapes.xz.flipped = this.flipPlanes ? v2.set(+(v1.dot(this.root.forward) > 0), 0, +(v1.dot(this.root.right) > 0)) : Vec3.ZERO;
}

/**
Expand Down