- Home /
"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?
After talking with my co-worker we decided my initial code will work for our needs- however I'm still very open to answers if anyone has more insight on how to achieve Blender's kind of camera rotation. Should I manage to figure it out myself down the road I'll be sure to update this with the solution.
Answer by apocriva · Mar 08, 2012 at 07:47 PM
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 :)).
Thanks for answering! I tried out your script, and after a bit of tweaking to get it working it seemed to apply the same effect as what I already had. From the sound of it I would have thought that having "the rotations around the individual axes driven directly by the translation of the mouse" was pretty much what the previous script was doing, but perhaps I'm misunderstanding.
Answer by Owen-Reynolds · Mar 08, 2012 at 09:06 PM
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.
Thanks for your answer! I guess I should have mentioned I'm still fairly new to Unity (been at it intensely for just a few months now) so a few of those concepts went a bit over my head.
I tried using "transform.RotateAround" by replacing the "transform.Rotate" line with this:
transform.RotateAround(Vector3.zero, Vector3(my, mx, 0), Time.deltaTime * speed);
But it pretty much produced the same effect- only without taking mouse motion speeds into account. Am I misusing the function?
And I'm most interested in your advice on the incremental errors; I wonder if maybe you could elaborate on "why" all the little turns adding up can drift it? It seems to me like the script I provided should just work as far as that's concerned, so I'd be curious to know what's going wrong exactly.
For using your trick to fix that issue, I think I understand saving the mouseDown spot (the object's current rotation when you click?) but I can't think of how I would go about using that in relation to the rotation, as right now it's just based on the mouse motion as it happens.
Thanks again.
Rotating around a line that isn't the x, y or z axis is just a regular trig concept. Easy to find the math, but Unity has it also built-in. How to use RotateAround is obvious once you get the trig. The thing is, I'm pretty sure Rotate((mx,my))
isn't the same thing at all. So, if blender spins around diagonal lines, of course yours isn't the same.
Looking more at Blender, the camera is clearly moving, and it also depends on where you start (a Left to Right drag spins very different on top or bottom of the screen.) I can't say how blender works, now.
For the "amount from start" idea, you can look up the actual $$anonymous$$ouse position (`Input.mousePosition`) and compute mx
and my
yourself. Depending on how you rotate, you may find out that spinRight + spinUp doesn't add to "spin diagonal right and up," so need this trick.
Thanks a lot for the assistance, although most of it still goes over my head; calculating complex rotations in 3D space seems to be a whole separate issue from learning Unity's API, and I can't seem to wrap my head around it very well. @.@ Anyway, I really appreciate your time.
Your answer
Follow this Question
Related Questions
fps MouseLook with animation applied to camera. 1 Answer
Mouse.position from center of player 1 Answer
Smooth camera rotation on mobile and pc when GetMouseButton()? 0 Answers
Making the players head face toward the location of the mouse? 1 Answer
Freeze Camera Rotation that is attached to the object in certain moments 0 Answers