Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Voting for the Unity Awards are OPEN! We’re looking to celebrate creators across games, industry, film, and many more categories. Cast your vote now for all categories
    Dismiss Notice
  3. Dismiss Notice

MouseOrbitImproved - Collision with Other Objects Causes Glitching

Discussion in 'Getting Started' started by GeekBrony, Apr 8, 2018.

  1. GeekBrony

    GeekBrony

    Joined:
    Feb 17, 2017
    Posts:
    6
    Hello!

    Since this is my first post here, I'm not sure exactly where this thread is supposed to go in the forum, so I think it's a safe bet to try this subforum.


    Anyway, I have a camera orbiting my player in 3rd Person (video above), and the way I'm doing it is with the MouseOrbitImproved script. I have modified it a little bit to fit my tastes (essentially making the camera y-axis a little bit higher so that it focuses slightly above the character).

    The problem here is that when you move the camera to collide with an object, the camera is trying to figure out a perfect distance away from the player, but it clips through the object and causes the MouseOrbitImproved script to glitch out.

    My intentions with this problem are, like most people would agree with, to lower the distance from the camera to the player as it hits something. Is there any way to get that to work properly?

    Here is the modified MouseOrbitImproved script:
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. [AddComponentMenu("Camera-Control/Mouse Orbit with zoom")]
    4. public class MouseOrbitImproved : MonoBehaviour {
    5.     public Transform target;
    6.     public float distance = 5.0f;
    7.     public float xSpeed = 120.0f;
    8.     public float ySpeed = 120.0f;
    9.     public float yMinLimit = -20f;
    10.     public float yMaxLimit = 80f;
    11.     public float distanceMin = .5f;
    12.     public float distanceMax = 15f;
    13.     private Rigidbody rigidbody;
    14.     float x = 0.0f;
    15.     float y = 0.0f;
    16.     // Use this for initialization
    17.     void Start ()
    18.     {
    19.         Vector3 angles = transform.eulerAngles;
    20.         x = angles.y;
    21.         y = angles.x;
    22.         rigidbody = GetComponent<Rigidbody>();
    23.         // Make the rigid body not change rotation
    24.         if (rigidbody != null)
    25.         {
    26.             rigidbody.freezeRotation = true;
    27.         }
    28.     }
    29.     void LateUpdate ()
    30.     {
    31.         if (target)
    32.         {
    33.             x += Input.GetAxis("Mouse X") * xSpeed * distance * 0.5f * Time.deltaTime;
    34.             y -= Input.GetAxis("Mouse Y") * ySpeed * 0.5f * Time.deltaTime;
    35.             y = ClampAngle(y, yMinLimit, yMaxLimit);
    36.             Quaternion rotation = Quaternion.Euler(y, x, 0);
    37.             distance = Mathf.Clamp(distance - Input.GetAxis("Mouse ScrollWheel")*5, distanceMin, distanceMax);
    38.             RaycastHit hit;
    39.             if (Physics.Linecast (target.position, transform.position, out hit))
    40.             {
    41.                 distance -=  hit.distance;
    42.             }
    43.             Vector3 negDistance = new Vector3(0.0f, 3.0f, -distance);
    44.             Vector3 position = rotation * negDistance + target.position;
    45.             transform.rotation = rotation;
    46.             transform.position = position;
    47.         }
    48.     }
    49.     public static float ClampAngle(float angle, float min, float max)
    50.     {
    51.         if (angle < -360F)
    52.             angle += 360F;
    53.         if (angle > 360F)
    54.             angle -= 360F;
    55.         return Mathf.Clamp(angle, min, max);
    56.     }
    57. }
     
  2. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,840
    Hmm. This appears to be using a Rigidbody. That seems like a horrible idea to me — I'd instead just cast a ray from the target position, in the direction your x/y angles indicate. If it hits nothing, then position the camera at the end of that ray. If it his something, then position it at the hit point.
     
  3. GeekBrony

    GeekBrony

    Joined:
    Feb 17, 2017
    Posts:
    6
    Rigidbody and everything aside, the script does its own raycasting, and I figured out how it works (kinda), and the issue of it "glitching" was because the distance was clamped at a minimum and maximum value - which turned out that the Raycaster was trying to subtract the ray distance from the main distance (in the LateUpdate() loop).

    So then I changed this:

    if (Physics.Linecast (target.position, transform.position, out hit))
    {
    distance -= hit.distance;
    }


    to this:

    if (Physics.Linecast (target.position, transform.position, out hit))
    {
    distance = hit.distance;
    }


    and then it worked... mostly.

    Now the camera moves to the distance I need it to, and when I get closer to the wall, I get closer to the camera. The only problem is that when I rotate the camera (after I get close), it sees through the walls, which is not the desired behavior.

    Any way to figure that one out?
     
  4. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,840
    Your fix looks correct. Good catch on that one!

    I don't know why it's still seeing through walls — it could be simply a matter of, the collider needs to extend outward from the visible wall at least as far as your camera's "hither" value.
     
  5. GeekBrony

    GeekBrony

    Joined:
    Feb 17, 2017
    Posts:
    6
    I came back to my project after a few months and figured out that occlusion is a thing, which works in a way that you set layers to collide with when raycasting.

    So I built this script with a friend's help. (the mouse sensitivity might be off a bit tho)

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. [AddComponentMenu("Camera-Control/Mouse Orbit with zoom")]
    4. public class MouseOrbitImproved : MonoBehaviour {
    5.     [Header("Look At")]
    6.     public Transform target;
    7.    
    8.     [Header("Mouse Speed")]
    9.     public float xSpeed = 120.0f;
    10.     public float ySpeed = 120.0f;
    11.    
    12.     [Header("Angle Limiting")]
    13.     public float ClampMinLimit = -6f;
    14.     public float ClampMaxLimit = 20f;
    15.     [Header("Distance Control")]
    16.     public float distance = 5.0f;
    17.     public float distanceMin = 2f;
    18.     public float distanceMax = 15f;
    19.     public float DistanceUp;
    20.  
    21.     [Header("Smoothing Control")]
    22.     public bool enableSmoothing = false;
    23.     public float smooth = 4.0f;
    24.     float smoothingMultiplier = 4.0f;
    25.  
    26.     float cameraHeight = 55f;
    27.     float cameraPan = 0f;
    28.     float camRotateSpeed = 90f;
    29.     float rotateAround = 70f;
    30.  
    31.     [Header("Raycast Occlusion Layer Selection")]
    32.     public LayerMask CamOcclusion = 0;
    33.     Vector3 camPosition;
    34.     Vector3 camMask;
    35.     Vector3 followMask;
    36.     private Rigidbody rb;
    37.  
    38.     // Use this for initialization
    39.     void Start ()
    40.     {
    41.         rb = GetComponent<Rigidbody>();
    42.         // Make the rigid body not change rotation
    43.         if (rb != null) rb.freezeRotation = true;
    44.  
    45.         smoothingMultiplier = smooth;
    46.     }
    47.     void Update ()
    48.     {
    49.         if(Input.GetAxis("Mouse ScrollWheel") != 0) {
    50.             distance = Mathf.Clamp(distance - Input.GetAxis("Mouse ScrollWheel")*2, distanceMin, distanceMax);
    51.         }
    52.     }
    53.    
    54.     void LateUpdate ()
    55.     {
    56.         if (target)
    57.         {
    58.             Vector3 targetOffset = new Vector3(target.position.x, (target.position.y + 4f), target.position.z);
    59.             Quaternion rotation = Quaternion.Euler(cameraHeight, rotateAround, cameraPan);
    60.             Vector3 vectorMask = Vector3.one;
    61.             Vector3 rotateVector = rotation * vectorMask;
    62.  
    63.             camPosition = targetOffset + Vector3.up * DistanceUp - rotateVector * distance;
    64.             camMask = targetOffset + Vector3.up * DistanceUp - rotateVector * distance;
    65.  
    66.             occludeRay(ref targetOffset);
    67.             smoothCamMethod();
    68.  
    69.             transform.LookAt(target);
    70.             if(rotateAround > 360){
    71.                 rotateAround = 0f;
    72.             } else if(rotateAround < 0f){
    73.                 rotateAround = (rotateAround + 360f);
    74.             }
    75.  
    76.             rotateAround += (Input.GetAxis("Mouse X") * xSpeed * 0.096f) * camRotateSpeed * Time.fixedDeltaTime;
    77.             DistanceUp = Mathf.Clamp(DistanceUp += -(Input.GetAxis("Mouse Y") * ySpeed * 0.75f * Time.fixedDeltaTime), ClampMinLimit, ClampMaxLimit);
    78.  
    79.         }
    80.     }
    81.  
    82.     void smoothCamMethod(){
    83.         if(enableSmoothing) {
    84.             smoothingMultiplier = smooth;
    85.         } else {
    86.             smoothingMultiplier = 50f;
    87.         }
    88.         transform.position = Vector3.Lerp(transform.position, camPosition, Time.deltaTime * smoothingMultiplier);
    89.     }
    90.  
    91.     /* Prevent Wall Clipping */
    92.     void occludeRay(ref Vector3 targetFollow)
    93.     {
    94.         RaycastHit wallHit = new RaycastHit();
    95.         if(Physics.Linecast(targetFollow, camMask, out wallHit, CamOcclusion))
    96.         {
    97.             /* The smooth is increased to detect geometry collisions faster */
    98.             if(enableSmoothing) {
    99.                 smoothingMultiplier = smooth * 3;
    100.             } else {
    101.                 smoothingMultiplier = 100f;
    102.             }
    103.             camPosition = new Vector3(wallHit.point.x + wallHit.normal.x * 0.5f, camPosition.y, wallHit.point.z + wallHit.normal.z * 0.5f);
    104.         }
    105.     }
    106.     public static float ClampAngle(float angle, float min, float max)
    107.     {
    108.         if (angle < -360F)
    109.             angle += 360F;
    110.         if (angle > 360F)
    111.             angle -= 360F;
    112.         return Mathf.Clamp(angle, min, max);
    113.     }
    114.  
    115. }
    Anyway, consider this problem fixed.