Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gizmo rotate updates #7327

Merged
merged 9 commits into from
Feb 4, 2025
Merged
Show file tree
Hide file tree
Changes from 7 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
9 changes: 9 additions & 0 deletions examples/src/examples/gizmos/transform-rotate.controls.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,15 @@ export const controls = ({ observer, ReactPCUI, React, jsx, fragment }) => {
max: 10,
precision: 0
})
),
jsx(
LabelGroup,
{ text: 'Orbit Rotation' },
jsx(BooleanInput, {
type: 'toggle',
binding: new BindingTwoWay(),
link: { observer, path: 'gizmo.orbitRotation' }
})
)
),
jsx(
Expand Down
1 change: 1 addition & 0 deletions examples/src/examples/gizmos/transform-rotate.example.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ gizmo.attach(box);
data.set('gizmo', {
size: gizmo.size,
snapIncrement: gizmo.snapIncrement,
orbitRotation: gizmo.orbitRotation,
xAxisColor: Object.values(gizmo.xAxisColor),
yAxisColor: Object.values(gizmo.yAxisColor),
zAxisColor: Object.values(gizmo.zAxisColor),
Expand Down
55 changes: 48 additions & 7 deletions src/extras/gizmo/rotate-gizmo.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,14 @@ class RotateGizmo extends TransformGizmo {
})
};

/**
* Internal selection starting angle in world space.
*
* @type {number}
* @private
*/
_selectionStartAngle = 0;

/**
* Internal mapping from each attached node to their starting rotation in local space.
*
Expand Down Expand Up @@ -126,6 +134,13 @@ class RotateGizmo extends TransformGizmo {
*/
snapIncrement = 5;

/**
* This forces the rotation to always be calculated based on the mouse position around the gizmo.
*
* @type {boolean}
*/
orbitRotation = false;

/**
* Creates a new RotateGizmo object.
*
Expand All @@ -139,7 +154,11 @@ class RotateGizmo extends TransformGizmo {

this._createTransform();

this.on(TransformGizmo.EVENT_TRANSFORMSTART, () => {
this.on(TransformGizmo.EVENT_TRANSFORMSTART, (point, x, y) => {
// store start angle
this._selectionStartAngle = this._calculateAngle(point, x, y);

// store initial node rotations
this._storeNodeRotations();

// store guide points
Expand All @@ -149,9 +168,10 @@ class RotateGizmo extends TransformGizmo {
this._drag(true);
});

this.on(TransformGizmo.EVENT_TRANSFORMMOVE, (pointDelta, angleDelta) => {
this.on(TransformGizmo.EVENT_TRANSFORMMOVE, (point, x, y) => {
const axis = this._selectedAxis;

let angleDelta = this._calculateAngle(point, x, y) - this._selectionStartAngle;
if (this.snap) {
angleDelta = Math.round(angleDelta / this.snapIncrement) * this.snapIncrement;
}
Expand Down Expand Up @@ -451,11 +471,10 @@ class RotateGizmo extends TransformGizmo {
/**
* @param {number} x - The x coordinate.
* @param {number} y - The y coordinate.
* @returns {{ point: Vec3, angle: number }} The point and angle.
* @returns {Vec3} The point in world space.
* @protected
*/
_screenToPoint(x, y) {
const gizmoPos = this.root.getPosition();
const mouseWPos = this._camera.screenToWorld(x, y, 1);

const axis = this._selectedAxis;
Expand All @@ -464,14 +483,32 @@ class RotateGizmo extends TransformGizmo {
const plane = this._createPlane(axis, axis === GIZMOAXIS_FACE, false);

const point = new Vec3();
let angle = 0;

plane.intersectsRay(ray, point);

return point;
}

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

const axis = this._selectedAxis;

const plane = this._createPlane(axis, axis === GIZMOAXIS_FACE, false);

let angle = 0;

// calculate angle
const facingDir = tmpV2.copy(this.facing);
const facingDot = plane.normal.dot(facingDir);
if (Math.abs(facingDot) > FACING_THRESHOLD) {
if (this.orbitRotation || Math.abs(facingDot) > FACING_THRESHOLD) {
// plane facing camera so based on mouse position around gizmo
tmpV1.sub2(point, gizmoPos);

Expand All @@ -484,14 +521,18 @@ class RotateGizmo extends TransformGizmo {
// convert rotation axis to screen space
tmpV1.copy(gizmoPos);
tmpV2.cross(plane.normal, facingDir).normalize().add(gizmoPos);

// convert world space vectors to screen space
this._camera.worldToScreen(tmpV1, tmpV3);
this._camera.worldToScreen(tmpV2, tmpV4);

// angle is dot product with mouse position
tmpV1.sub2(tmpV4, tmpV3).normalize();
tmpV2.set(x, y, 0);
angle = tmpV1.dot(tmpV2);
}

return { point, angle };
return angle;
}
}

Expand Down
11 changes: 6 additions & 5 deletions src/extras/gizmo/scale-gizmo.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { BoxLineShape } from './shape/boxline-shape.js';
// temporary variables
const tmpV1 = new Vec3();
const tmpV2 = new Vec3();
const tmpV3 = new Vec3();
const tmpQ1 = new Quat();

// constants
Expand Down Expand Up @@ -139,7 +140,8 @@ class ScaleGizmo extends TransformGizmo {
this._storeNodeScales();
});

this.on(TransformGizmo.EVENT_TRANSFORMMOVE, (pointDelta) => {
this.on(TransformGizmo.EVENT_TRANSFORMMOVE, (point) => {
const pointDelta = tmpV3.copy(point).sub(this._selectionStartPoint);
if (this.snap) {
pointDelta.mulScalar(1 / this.snapIncrement);
pointDelta.round();
Expand Down Expand Up @@ -437,7 +439,7 @@ class ScaleGizmo extends TransformGizmo {
/**
* @param {number} x - The x coordinate.
* @param {number} y - The y coordinate.
* @returns {{ point: Vec3, angle: number }} The point and angle.
* @returns {Vec3} The point in world space.
* @protected
*/
_screenToPoint(x, y) {
Expand All @@ -453,7 +455,6 @@ class ScaleGizmo extends TransformGizmo {
const plane = this._createPlane(axis, isScaleUniform, !isPlane);

const point = new Vec3();
const angle = 0;

plane.intersectsRay(ray, point);

Expand Down Expand Up @@ -489,7 +490,7 @@ class ScaleGizmo extends TransformGizmo {
point[axis] = 1;
}

return { point, angle };
return point;
}

// rotate point back to world coords
Expand All @@ -499,7 +500,7 @@ class ScaleGizmo extends TransformGizmo {
this._projectToAxis(point, axis);
}

return { point, angle };
return point;
}
}

Expand Down
34 changes: 7 additions & 27 deletions src/extras/gizmo/transform-gizmo.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,14 +122,6 @@ class TransformGizmo extends Gizmo {
f: COLOR_YELLOW.clone()
};

/**
* Internal point delta.
*
* @type {Vec3}
* @private
*/
_pointDelta = new Vec3();

/**
* Internal gizmo starting rotation in world space.
*
Expand Down Expand Up @@ -226,14 +218,6 @@ class TransformGizmo extends Gizmo {
*/
_selectionStartPoint = new Vec3();

/**
* Internal selection starting angle in world space.
*
* @type {number}
* @protected
*/
_selectionStartAngle = 0;

/**
* Internal state for if the gizmo is being dragged.
*
Expand Down Expand Up @@ -294,11 +278,10 @@ class TransformGizmo extends Gizmo {
this._selectedIsPlane = this._getIsPlane(meshInstance);
this._rootStartPos.copy(this.root.getPosition());
this._rootStartRot.copy(this.root.getRotation());
const pointInfo = this._screenToPoint(x, y);
this._selectionStartPoint.copy(pointInfo.point);
this._selectionStartAngle = pointInfo.angle;
const point = this._screenToPoint(x, y);
this._selectionStartPoint.copy(point);
this._dragging = true;
this.fire(TransformGizmo.EVENT_TRANSFORMSTART);
this.fire(TransformGizmo.EVENT_TRANSFORMSTART, point, x, y);
});

this.on(Gizmo.EVENT_POINTERMOVE, (x, y, meshInstance) => {
Expand All @@ -315,10 +298,8 @@ class TransformGizmo extends Gizmo {
return;
}

const pointInfo = this._screenToPoint(x, y);
this._pointDelta.copy(pointInfo.point).sub(this._selectionStartPoint);
const angleDelta = pointInfo.angle - this._selectionStartAngle;
this.fire(TransformGizmo.EVENT_TRANSFORMMOVE, this._pointDelta, angleDelta);
const point = this._screenToPoint(x, y);
this.fire(TransformGizmo.EVENT_TRANSFORMMOVE, point, x, y);

this._hoverAxis = '';
this._hoverIsPlane = false;
Expand Down Expand Up @@ -613,7 +594,7 @@ class TransformGizmo extends Gizmo {
* @param {number} y - The y coordinate.
* @param {boolean} isFacing - Whether the axis is facing the camera.
* @param {boolean} isLine - Whether the axis is a line.
* @returns {{ point: Vec3, angle: number }} - The point and angle.
* @returns {Vec3} - The point.
* @protected
*/
_screenToPoint(x, y, isFacing = false, isLine = false) {
Expand All @@ -625,10 +606,9 @@ class TransformGizmo extends Gizmo {
const plane = this._createPlane(axis, isFacing, isLine);

const point = new Vec3();
const angle = 0;
plane.intersectsRay(ray, point);

return { point, angle };
return point;
}

/**
Expand Down
9 changes: 5 additions & 4 deletions src/extras/gizmo/translate-gizmo.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { SphereShape } from './shape/sphere-shape.js';
// temporary variables
const tmpV1 = new Vec3();
const tmpV2 = new Vec3();
const tmpV3 = new Vec3();
const tmpQ1 = new Quat();

// constants
Expand Down Expand Up @@ -136,7 +137,8 @@ class TranslateGizmo extends TransformGizmo {
this._storeNodePositions();
});

this.on(TransformGizmo.EVENT_TRANSFORMMOVE, (pointDelta) => {
this.on(TransformGizmo.EVENT_TRANSFORMMOVE, (point) => {
const pointDelta = tmpV3.copy(point).sub(this._selectionStartPoint);
if (this.snap) {
pointDelta.mulScalar(1 / this.snapIncrement);
pointDelta.round();
Expand Down Expand Up @@ -445,7 +447,7 @@ class TranslateGizmo extends TransformGizmo {
/**
* @param {number} x - The x coordinate.
* @param {number} y - The y coordinate.
* @returns {{ point: Vec3, angle: number }} The point and angle.
* @returns {Vec3} The point in world space.
* @protected
*/
_screenToPoint(x, y) {
Expand All @@ -458,7 +460,6 @@ class TranslateGizmo extends TransformGizmo {
const plane = this._createPlane(axis, axis === GIZMOAXIS_FACE, !isPlane);

const point = new Vec3();
const angle = 0;

plane.intersectsRay(ray, point);

Expand All @@ -469,7 +470,7 @@ class TranslateGizmo extends TransformGizmo {
this._projectToAxis(point, axis);
}

return { point, angle };
return point;
}
}

Expand Down