"Perfect" Free Rotation Method? (like Blender)

I have a 3D object sitting alone in a scene, and I need the ability to freely and precisely rotate the view around it by way of the mouse (and eventually, the iPad’s touch screen). If you happen to use Blender, what I need is exactly its method of rotating the camera around the model (middle mouse button in Windows). In Blender this is done very smoothly; each click and drag works exactly as you would expect it to, with complete accuracy and control.

I’ve put in a fair amount of work in Unity trying to replicate this effect, however I just can’t get it to behave with such precision. The closest method I’ve found is by applying this simple script directly to the object I wish to rotate:

#pragma strict

var speed : float = 550.0;
var mx : float;
var my : float;
		
function Update() {
	if (Input.GetMouseButton(0))
	{
		mx = -Input.GetAxis("Mouse X");
		my = Input.GetAxis("Mouse Y");
		transform.Rotate(Vector3(my, mx, 0) * Time.deltaTime * speed, Space.World);
	}
}

This comes pretty close to what I’m looking for, however it feels too out of control; sometimes it moves in a way I wouldn’t expect, and behaves oddly in some ways (e.g. if you click and swipe the mouse back and forth rapidly the model gradually rotates in a random direction, as opposed to accurately jumping back and forth to your mouse movements).

In following other scripts found here I’ve also tried rotating a camera around the object as opposed to rotating the object itself. The results felt a bit more precise than the above script, but were considerably more limiting (e.g. if you positioned the camera above the object so the top is facing you, you couldn’t move it from side to side; it still appeared to spin on its Y axis).

I’ve searched through a lot of questions here relating to mouse-based rotation, but they have yet to produce the right effect, so I thought I’d ask myself. Anyone have any ideas how one might go about doing this?

What you probably want is something like this (disclaimer: I don’t generally use JavaScript, and haven’t actually tried this code snippet live!):

var speed : float = 550.0;
var rotations : Vector3;

function Update() {
    if (Input.GetMouseButton(0))
    {
       rotations.x = -Input.GetAxis("Mouse X") * Time.deltaTime * speed;
       rotations.y = Input.GetAxis("Mouse Y") * Time.deltaTime * speed;
       transform.localEulerAngles = rotations;
    }
}

You might have to do some kind of normalization or something, but the key is to have the rotations around the individual axes driven directly by the translation of the mouse (if that makes sense :)).

I’m thinking the problem is diagonal motion. If I drag the mouse from lower-right to upper-left, it looks like (and makes sense) Blender is spinning the object around a (/)-looking axis (perpendicular to my motion.)

Rotating my hand, 90 degrees on x then 90 degrees global y (or local y) doesn’t give the same effect. So, maybe use transform.RotateAround whenever you have X and Y motion together (the around line would be something like (-Y,X).)

Also, you’re going to get incremental errors if you always rotate from last frame – all those little turns added up can drift the final result. A trick is to save the mouseDown spot, and each movement recompute from current pos to saved start pos.