0
\$\begingroup\$

When our game's ships move around, mouse aiming causes them to shake around a lot. The body being aimed is moved kinematically. I think we've narrowed it down to this block of mouse tracking code.

Demonstration of the glitch

You can see around 0:35 where I disable the mouse tracking code momentarily, the ship stops shaking.

    public static Quaternion RotateToMouse(this Ship ship, Transform transform, float ShipRotateSpeed)
    {
        // Generate a plane that intersects the transform's position with an upwards normal.
        Plane playerPlane = new Plane(Vector3.up, Vector3.zero);

        // Generate a ray from the cursor position
        Ray ray = Camera.main.ScreenPointToRay (Input.mousePosition);

        // Determine the point where the cursor ray intersects the plane.
        float hitdist = 0.0f;
        // If the ray is parallel to the plane, Raycast will return false.
        if (playerPlane.Raycast (ray, out hitdist)) 
        {
            // Get the point along the ray that hits the calculated distance.
            Vector3 targetPoint = ray.GetPoint(hitdist);

            // Determine the target rotation.  This is the rotation if the transform looks at the target point.
            Quaternion targetRotation = Quaternion.LookRotation(targetPoint - transform.position);


            // Smoothly rotate towards the target point.
            transform.rotation = Quaternion.RotateTowards(transform.rotation, targetRotation, ShipRotateSpeed);
            transform.eulerAngles = new Vector3(0, transform.eulerAngles.y, 0);
        }
        return transform.rotation;
    }

We've got no idea whats going wrong, any help will be greatly appreciated. thanks.

\$\endgroup\$
3
  • \$\begingroup\$ I don't have much time to write a formal answer (and think it through enough to warrant a formal answer) but, instead of Quaternion.RotateTowards(), you likely want Quaternion.Slerp() (link) to ensure you don't overshoot your target rotation. \$\endgroup\$ Commented May 2, 2013 at 18:56
  • \$\begingroup\$ Using quaternions for a rotation in a plane seems a bit overkill, and probably helps to obscure the bug. That said, this code as best I can tell is functionally correct. @chaosTechnician Nope, RotateTowards should not overshoot according to the specification, Slerp produce a different effect that I presume undesirable for the purpose. \$\endgroup\$ Commented May 2, 2013 at 19:09
  • \$\begingroup\$ As eBusiness said, using quaternions here is weird. Some things to check: Is targetPoint.y always exactly zero? Is transform.position.y always exactly zero? If not, then Quaternion.LookRotation will produce a rotation that is not exactly about the y axis. Also, Unity documentation considers Quaternion.RotateTowards to be "only for exotic uses", so maybe the function just isn't very robust(docs.unity3d.com/Documentation/ScriptReference/Quaternion.html). \$\endgroup\$ Commented May 3, 2013 at 15:43

2 Answers 2

1
\$\begingroup\$

Something i forgot to include was the fact the camera was moving with the ships. When I made the Camera stationary it seamed to work perfectly, so i simply created another camera and kept it at Vector3(0,30,0) and used it to track the mouse instead.

Changing the code slightly to be:

    public static Quaternion RotateToMouse(this Ship ship, Transform transform, float ShipRotateSpeed)
    {
        Vector3 MousePos = Input.mousePosition;

        // Generate a plane that intersects the transform's position with an upwards normal.
        Plane playerPlane = new Plane(Vector3.up, Vector3.zero);

        // Generate a ray from the cursor position

        Ray ray = Vitals.MouseCam.ScreenPointToRay (MousePos);


        // Determine the point where the cursor ray intersects the plane.
        float hitdist = 0.0f;
        // If the ray is parallel to the plane, Raycast will return false.
        if (playerPlane.Raycast (ray, out hitdist)) 
        {       
            // Get the point along the ray that hits the calculated distance.
            Vector3 targetPoint = ray.GetPoint(hitdist);
            targetPoint += transform.position;
            // Determine the target rotation.  This is the rotation if the transform looks at the target point.
            Quaternion targetRotation = Quaternion.LookRotation(targetPoint - transform.position);

            // Smoothly rotate towards the target point.
            transform.rotation = Quaternion.RotateTowards(transform.rotation, targetRotation, ShipRotateSpeed);
        }           
        return transform.rotation;
    }

Something about the Camera moving caused the calculations to be slightly different every tick? Ideas ?

\$\endgroup\$
2
  • \$\begingroup\$ My guess is that it's an order issue. Maybe whatever is moving the ship is doing that before the camera or vice-versa. Try moving some code from Update to LateUpdate in one script or another and see if it helps things. \$\endgroup\$
    – Tetrad
    Commented May 17, 2013 at 22:32
  • \$\begingroup\$ @Tetrad That was my guess as well, I did move the camera movement code around but it didn't seem to help. It may have just have ended up with slightly different angles because of the positions. \$\endgroup\$
    – Dusty
    Commented May 18, 2013 at 12:14
0
\$\begingroup\$

There is simpler solution. That jittering happens because GUI is updated more frequently than the Update or LateUpdate. Just move the code related to raycasting from moving camera through cursor position into the OnGUI() function instead of Update() or LateUpdate(). Everything runs smoothly. Just remember that it may be called more than one time per frame so do there only what is necessary.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .