Unity Spaceship camera control

I'm trying to make a third person spaceship control system in Unity. In theory, it works like this: Let's suppose you move your mouse to the right. The targeted direction would rotate to the right compared to the current camera direction and the camera would rotate to face towards the new direction as well.

The problem lies in the calculations: how can I calculate the direction change using the current camera rotation? Also, please mind that the ship rolls with Q and E to the left and right, respectively, as to improve player control.

The system is designed this way to help controlling bigger, slower turning ships (where direct, limited mouse following is not an option because of the low turning speed). But if you have a suggestion for a better control system for such ships, I'd be glad to hear it.

• I believe there is a function in unity which can grab Mouse co-ordinates and transform them into a vector, you can then use this vector to rotate your ship and camera to look at that point – Matthew Pigram Feb 5 '14 at 5:51
• That's a pretty vague description, I could as well think of so much, the problem is I couldn't find out how to do the maths part (guess I missed an important factor somewhere to make up the calculations) – Daniel Rusznyak Feb 5 '14 at 17:22

Get the mouse coordinates in normalized device space (i.e. -1 to 1 in both axes.) Then multiply this by the inverse of the (projection * camera) matrix (with a depth of 1/2 in directx or 0 in OpenGL). This gets you a point in world space, where the mouse is pointing to. Construct a vector from the camera position to this point, and make it unit length. This is the desired direction the player wants to point their ship in.

Now comes the tricky part. You have the forward vector (normalized, of course) of the ship as the current forward direction, and a desired forward direction, which presumably are not the same. What to do next depends on the motion model of your ships. Is it newtonian? If so then you have to be careful not to overshoot, as you likely have limited angular acceleration. The cross product of these two vectors will give you the vector you want to rotate about (the axis), and it is the sin() of the angle. If you don't have angular momentum, then you could just turn the ship by this axis and an angle which is limited by RAD_PER_SEC * dt. You can use Quaternion.AxisAngle to turn this into a quaternion which you can multiply onto the spaceship's orientation.

vec3 desired = (inverse(projection * camera) * (mx,my, 0.5)) - camera.position;
desired = norm(desired)
vec3 actual = norm(ship.getForwardVector())
vec3 axisangle = crossproduct(desired, actual) // may need to negate
// depending on conventions
float angle = arcsin(length(axisangle))
float dangle = min(angle, RAD_PER_SEC * dt)
quat rotation = Quaterion.AxisAngle(dangle, norm(axisangle))
ship.orientation = ship.orientation * rotation.


Make sure that arcsin and AxisAngle both use degrees, or both use radians.

• Thank you for your answer, you've made me realise 2 errors I made, one on the general idea of how the control should work, the other one about the way I went about my calculations :) Question: what does that dt variable stand for? Maybe it's obvious, but I'm just a bit too tired to figure it out ^^ – Daniel Rusznyak Feb 6 '14 at 11:17
• That is the timestep, short for delta time. You'll see this convention in physics engines and such a lot. This is so the ship doesn't turn faster when the framerate changes. I would also point out that you might want to move the mouse cursor so that it is in the same direction after the turn, as otherwise the ship will continuously spin. That could be desirable, though. – user41442 Feb 6 '14 at 17:20
• It is indeed desirable, since I'm talking about battlecruisers and such here with kinda low turn rates, and I don't want the players "scrolling" their mouse all day for a 180 degrees turn (which might easily take like 10 seconds, depending on ship size). And yea, I completely forgot about the existence of delta time for some reason. – Daniel Rusznyak Feb 6 '14 at 22:44