@@ -18,7 +18,6 @@ import { SphereShape } from './shape/sphere-shape.js';
1818 */
1919
2020// temporary variables
21- const screen = new Vec2 ( ) ;
2221const point = new Vec3 ( ) ;
2322const v1 = new Vec3 ( ) ;
2423const v2 = new Vec3 ( ) ;
@@ -242,13 +241,13 @@ class RotateGizmo extends TransformGizmo {
242241 line . entity . enabled = false ;
243242 } ) ;
244243
245- this . on ( TransformGizmo . EVENT_TRANSFORMSTART , ( _point , x , y ) => {
244+ this . on ( TransformGizmo . EVENT_TRANSFORMSTART , ( point , x , y ) => {
246245 // store start screen point
247246 this . _screenPos . set ( x , y ) ;
248247 this . _screenStartPos . set ( x , y ) ;
249248
250249 // store start angle
251- this . _selectionStartAngle = this . _calculateArcAngle ( x , y ) ;
250+ this . _selectionStartAngle = this . _calculateArcAngle ( point , x , y ) ;
252251
253252 // store initial node rotations
254253 this . _storeNodeRotations ( ) ;
@@ -281,7 +280,8 @@ class RotateGizmo extends TransformGizmo {
281280 this . _setNodeRotations ( axis , angleAxis , angleDelta ) ;
282281 } else {
283282 // calculate angle axis and delta and update node rotations
284- let angleDelta = this . _calculateArcAngle ( x , y ) - this . _selectionStartAngle ;
283+ let angleDelta = this . _calculateArcAngle ( point , x , y ) - this . _selectionStartAngle ;
284+
285285 if ( this . snap ) {
286286 angleDelta = Math . round ( angleDelta / this . snapIncrement ) * this . snapIncrement ;
287287 }
@@ -669,21 +669,30 @@ class RotateGizmo extends TransformGizmo {
669669
670670 const ray = this . _createRay ( mouseWPos ) ;
671671 const plane = this . _createPlane ( axis , axis === 'f' || axis === 'xyz' , false ) ;
672+
672673 if ( ! plane . intersectsRay ( ray , point ) ) {
673- // use gizmo position if ray does not intersect to position angle guide correctly
674- return point . copy ( this . root . getLocalPosition ( ) ) ;
674+ // if no intersection, try inverting the ray direction
675+ ray . direction . mulScalar ( - 1 ) ;
676+ const intersection = plane . intersectsRay ( ray , point ) ;
677+ ray . direction . mulScalar ( - 1 ) ;
678+
679+ if ( ! intersection ) {
680+ // use gizmo position if ray does not intersect to position angle guide correctly
681+ return point . copy ( this . root . getLocalPosition ( ) ) ;
682+ }
675683 }
676684
677685 return point ;
678686 }
679687
680688 /**
689+ * @param {Vec3 } point - The point.
681690 * @param {number } x - The x coordinate.
682691 * @param {number } y - The y coordinate.
683692 * @returns {number } The angle.
684693 * @protected
685694 */
686- _calculateArcAngle ( x , y ) {
695+ _calculateArcAngle ( point , x , y ) {
687696 const gizmoPos = this . root . getLocalPosition ( ) ;
688697
689698 const axis = this . _selectedAxis ;
@@ -721,12 +730,43 @@ class RotateGizmo extends TransformGizmo {
721730 break ;
722731 }
723732 case 'orbit' : {
724- // convert gizmo position to screen space§
725- const screenPos = this . _camera . worldToScreen ( gizmoPos , v1 ) ;
733+ // plane facing camera so based on mouse position around gizmo
734+ v1 . sub2 ( point , gizmoPos ) ;
735+
736+ switch ( axis ) {
737+ case 'x' : {
738+ // convert to local space
739+ q1 . copy ( this . _rootStartRot ) . invert ( ) . transformVector ( v1 , v1 ) ;
740+ angle = Math . atan2 ( v1 . z , v1 . y ) * math . RAD_TO_DEG ;
741+ break ;
742+ }
743+ case 'y' : {
744+ // convert to local space
745+ q1 . copy ( this . _rootStartRot ) . invert ( ) . transformVector ( v1 , v1 ) ;
746+ angle = Math . atan2 ( v1 . x , v1 . z ) * math . RAD_TO_DEG ;
747+ break ;
748+ }
749+ case 'z' : {
750+ // convert to local space
751+ q1 . copy ( this . _rootStartRot ) . invert ( ) . transformVector ( v1 , v1 ) ;
752+ angle = Math . atan2 ( v1 . y , v1 . x ) * math . RAD_TO_DEG ;
753+ break ;
754+ }
755+ case 'f' : {
756+ // convert to camera space
757+ q1 . copy ( this . _camera . entity . getRotation ( ) ) . invert ( ) . transformVector ( v1 , v1 ) ;
758+ angle = Math . sign ( facingDot ) * Math . atan2 ( v1 . y , v1 . x ) * math . RAD_TO_DEG ;
759+ break ;
760+ }
761+ }
762+
763+ // intersection point can be behind camera, so need to check to flip angle delta
764+ const dir = v1 . sub2 ( point , this . _camera . entity . getPosition ( ) ) . normalize ( ) ;
765+ const dot = dir . dot ( this . _camera . entity . forward ) ;
766+ if ( dot < 0 ) {
767+ angle += 180 ;
768+ }
726769
727- // calculate angle based on mouse position around gizmo
728- const dir = screen . set ( x - screenPos . x , y - screenPos . y ) . normalize ( ) ;
729- angle = Math . sign ( facingDot ) * Math . atan2 ( - dir . y , dir . x ) * math . RAD_TO_DEG ;
730770 break ;
731771 }
732772 }
0 commit comments