Adding a Euler vector to a Quaternion

I’ve seen similar questions before, but I believe this issue is slightly different. For some multiplayer code, I need to predict the future rotation using a rotation and angular velocity.

The basic formula is:
prediction = rotation + angularVelocity*time

In code using quaternions, I thought that would be:

public override void Apply(Quaternion rotation, Vector3 angularVelocity, float timeBetweenPackets)
			Logger.Info("Local Rotation: " + transform.eulerAngles + " Received Rotation: " + rotation.eulerAngles + " Received Velocity: " + angularVelocity);
			goal = rotation * Quaternion.Euler(angularVelocity * timeBetweenPackets);
			Logger.Info("Result Rotation: " + goal.eulerAngles);
			transform.rotation = goal;

			timeToReachGoal = timeBetweenPackets;
			currentTime = 0;

Here is the output log from that. You can see the “result” value seems to jump around a lot, producing very jittery predictions:

Image seems to be broken, so here’s a mirror:

Can you see any issues in the code?

Don’t try to do angle math in rulers, you will run right into Gimble lock, which is the whole reason for Quaternions to start with.

Do the math in Quats and, if you need a result in Eulers, just convert the final Quaternion.

After some studying on Quaternions, I found a much better way to represent angular velocity. Instead of storing it in a Euler vector, I stored a Vector3 axis to rotate around, and a float for the speed to rotate around that axis.

Finding angular velocity:

private void CalculateAngularVelocity(Quaternion start, Quaternion end, float time)
			Quaternion rotation = end*Quaternion.Inverse(start);

			// calculate angle and axis from rotation
			float angle;
			Vector3 axis;
			rotation.ToAngleAxis(out angle, out axis);

			if (angle > 180)
				// use smallest angle
				angle -= 360;

			AverageRotatePerSecond = angle *time;
			AverageRotateAxis = axis;

Applying the velocity (no smoothing):

public override void Apply(Quaternion rotation, Vector3 angleAxis, float angleVelocity, float timeBetweenPackets)
			Transform.rotation = Quaternion.AngleAxis(angleVelocity*timeBetweenPackets, angleAxis)*rotation;