# rotation glitches when reaching 360 degrees

DJM
Posts:

**35**Memberim trying to create weapon sway based on the cameras' and players' rotation, the main idea works but when reaching the 360degrees it glitches. maybe i need the local rotation , but i cant figure it out.

how do i make it work? tnx

```
func doweaponsway(delta):
#calculate rotation
var wantedz
var wantedx
var wantedy
var xrot = $CamRoot.rotation_degrees.x - oldxrot
var yrot = self.rotation_degrees.y- oldyrot
wantedx = lerp(weaponsway.rotation_degrees.x,xrot,2 * delta)
wantedy = lerp(weaponsway.rotation_degrees.y,yrot,2 * delta)
weaponsway.rotation_degrees.x = clamp(wantedx, -2, 2)
weaponsway.rotation_degrees.y = clamp(wantedy, -2, 2)
#weaponsway.rotation_degrees.z =clamp(wantedz,-2,2)
oldxrot = $CamRoot.rotation_degrees.x
oldyrot = self.rotation_degrees.y
```

## Comments

5,028AdminWelcome to the forums @DJM!

I would recommend having the rotation for each axis in the weapon sway be a different node. This is because in Godot (and other game engines), having multiple axes of rotation that go over 180 degrees can lead to other axes being flipped to negative 180. I have found that when working with rotation and clamping, using separate nodes for each axes of rotation makes it

MUCHeasier. For example, instead of having`weaponsway`

modified on the X and Y, you'd want to have something like this:Then in your code you can modify the

`rotation_degrees`

of`weaponsway_x`

for the x axis and`weaponsway_y`

for the y axis. That may help with the 360 degrees issue if the reason it stops working is because of the -180 degree issue.Also, using

`rotation_degrees`

is the local rotation. If you want the global rotation of a node, you'll need to use`node.global_transform.basis`

to get the node's global rotations35Membertnx! im happy ive made the switch to godot.

sadly seperating the rotation axis on different nodes doesnt fix my issue.

ive also tried the global transform basis u suggested

in unity i used to use >

Mathf.DeltaAngle to get the shortest distance between rotations, i dont know if there is a similar function in gdscript

5,028AdminA shame that didn't fix it, but thankfully it means it's not the -180 issue that is causing the problem! I've found the -180 problem can be tricky to work around, so that's good that it's not what is causing the issue here.

I don't think there is anything built in that is similar to the

`Mathf.DeltaAngle`

function unfortunately.This StackOverflow solution provides a language agnostic way to get the difference of angles, though I'm not sure if the

`mod`

function in GDScript returns the sign or not. This Godot StackOverflow question also has an answer with many examples on lerping between two angles, which may work for getting the difference as well.35Memberactually i dont want to lerp between two angles. i only need to get the float between the current and last rotation per frame to do weaponsway calculations.

the issue thats occurring whit my current code is that when the current rotation is 0 and the last was 359 the weapon sway gets a short glitch because of the huge difference when i subtract the values

2,685ModeratorThis is a problem with Euler angles. As they go from 0 to 360 (or -180 to 180) then you will always have problems at the end of the range, especially when interpolating the value. Think of it like this, you want to rotate 30 degrees. But the angle is from 340 to 370 (or 10). If you just interpolate the values (340 and 10) instead of rotating 30 degrees, it will rotate 330 degrees, and in the wrong direction. You can account of this by looking at the values and adjusting them, but it is an inherent issue with using Euler angles.

A few things can help. First, try to always get 0 to 360 to make the math easier (so you don't get negative values or values above 360):

Then you can find the smaller angle. If you know your delta angle will never be more than 180 degrees (a pretty fair assumption for most games):

451MemberWorking with separate (euler) angles in 3d is just not worth the effort. You're in for a constant barrage of annoying gotchas

Do it the grownup way and represent your current and wanted orientation with quaternions, and interpolate between them. You can even simplify by just using two lookat vectors and slerp between them.

35Membertnx ! that works perfect

heres the code in case anybody wonders to do the same thing

`func doweaponsway(delta):

#calculate rotation

`

35Memberim not sure how to use that,

how to calculate "wanted" and what is "fraction" in your example?

2,685ModeratorWanted would be the next angle, current would be the previous angle, and fraction is a variable you set that controls how fast it interpolates.

2,685ModeratorAnd yes, avoid using Euler angles if you can. They make things easier in the beginning, and they are simpler to understand, but using more advanced structures like Quaternions end up with more robust functionality, less bugs, and less code.

35Memberok

im having trouble figuring out the local forward lookat from the camroot.

if i try the suggestion the weapon doesnt seem to point into the view direction im looking

451MemberThis was more at pseudocode level just to show the principle. We can discuss specifics but it'd be much easier if you could post how your nodes are set up.

35Memberhere u go

451MemberOk, here's a quick version using quaternions:

You just need to implement

calculate_sway_offset()to return horizontal and vertical sway offsets as Vector2. You can calculate it as you currently do from camera rotation deltas between frames.35Memberwhat do i put in the "calculate sway offset" func? how to return the vector2 values?

im currently calculating the movement in degrees so wont that have the same euler issues as i allready had?

451MemberI'd do it from controller/mouse deltas, or if you must deal with movement - again from transformation basis/quaternions.

451MemberHere's a way to calculate offsets from difference in rotation between frames. Using quaternions will ensure there are no wrapping and gimbal problems. You'll need to maintain player/camera basis from the previous frame:

2,685ModeratorRight, but this is also why Euler is much easier when starting out. It took me years to fully understand Quaternions, but I guess if you use Godot it does most of the math for you (but you still kind of have to understand what you're doing).

35Memberok heres what ive got right now, based on your code

im not sure what to write in the > do_sway(weaponsway, calculate_sway_offset( "what goes here?"), delta * softness)

i cant use mouse rotation , because it will sway the weapon even if theres no rotation happening.

451MemberWhat were you trying to base the sway on in the first place? It's typically done based on mouse input. In your initial post you said you want to base it on player

andcamera rotations. I'm not sure I understand why are you trying to base it on both.In my example, I assumed you want to do it based on changes in camera rotation - bigger the change, larger the offset. To do this you use camera rotations in previous and current frames (represented by transform basis) as arguments to that function. The function extracts "horizontal" and "vertical" camera rotatation deltas from total rotation of the camera between consecutive frames.

$sway and $cam are paths to your actual sway and camera nodes. In fact $cam stands for the node that does actual rotation in respect to global space. I'm assuming it's the player node in your case.

Of course you can base this offset on other things, depending on your system and actual effect you want to achieve. So it's up to you to decide that. I'd base it simply on

InputEventMouseMotion.relative. In which case the whole calculate_sway_offset() function in my previous post can simply return mouse offsets. It just needs to return zero offset if mouse motion didn't happen in the current frame and it'll all work fine.451MemberOne doesn't really need to fully understand quaternions and all the related math to be able to use them for 3d graphics. They have a wide general usage in math but in the world of computer graphics quaternion can be seen simply as a matrix-light that covers only rotations. You can use it as a black box that has certain neat properties and does certain useful things for you. Most people successfully use 4x4 transformation matrices this way.

But yeah, it's true that quaternions may look like an overkill for simple stuff that can kinda be solved using eulers. Especially when you see them for the first time. However eulers grossly fall short if you need to deal with lots of 3d orientation/targeting stuff, as is the case with first person shooters. Quaternions can handle most of such problems with ease in just a few lines of code.

35Membertnx for your reply

it sort of works but sway happens only on one axis, if i set $cam to the player node it rotates horizontaly if i set $cam to the camera node it happens only vertically

idont ant to use mouse motion as when u are looking down and the rotation is clamped , u will still get weapon sway even if there is no actual rotation happening

451MemberWell that's probably because different nodes handle rotations on different axes in your setup.

You can simply do the basis thing for both nodes, calculate both offsets and then use horizontal offset from one, and vertical offset from the other.

451MemberI'm beginning to think that wrapped-euler approach may be simpler for calculating the offsets here

35Memberso my initial idea was better?

451MemberIt's the same thing. Quaternions will elegantly eliminate all wrapping and gimbal lock glitches, which was the problem in the first place. Since angles are already separated into different nodes, @cybereality's euler wrap solution will do that job as well. However, even if offset is obtained directly from euler angles I'd still use quaternion slerping for setting the sway node rotation.

If you're working on a first person shooter thingy, don't shy sway from quaternions, but rather get acquainted with them. You'll need their help again... sooner or later

35Membertried it, now the gunsway rotates out of camera view and just gets all the rotation from the player and cam applied

451MemberLet's see the actual code.

35Member`func _process(delta):

window_activity()

var softness = 3.0

var cam_basis_last_frame = Basis()

var player_basis_last_frame = Basis()

func calculate_sway_offset(basis_last_frame: Basis, basis_current_frame: Basis):

var q1 = basis_last_frame.get_rotation_quat()

var q2 = basis_current_frame.get_rotation_quat()

var q = q1.inverse() * q2

var eu = q.get_euler()

return Vector2(eu.y, eu.x)

func do_sway(sway_node, offset: Vector2, fract: float):

var offset_quaternion: Quat = Quat(Vector3.UP, offset.x) * Quat(Vector3.RIGHT, offset.y)

sway_node.transform.basis = Basis(Quat(sway_node.transform.basis).slerp(offset_quaternion, fract))

`

451Membercam_basis_last_frameandplayer_basis_last_frameneed to be sctipt-level properties, not local variables. They are used to "remember" basis values from the last frame. If you declare them as local variables inside _process(), like you're doing now, they'll just be deleted when function exits, serving no purpose.p.s. please fix the code formatting.