• Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
Question by PlaguedShadow · Apr 05, 2014 at 04:57 PM · cameraclippingclipping plane

3rd Person Camera clips through walls

Right now what I have sort of works. It does stop the camera from clipping most of the time. However if you rotate the camera too quickly it will clip. There is something that is causing the issue, but I just can't figure out what it is.

This is my camera code:


 using UnityEngine;
 using System.Collections;
 
 public class CameraControl2 : MonoBehaviour 
 {
     // Inspector serialized
     [SerializeField]
     private float _distanceBehind;                // Distance behind the player where camera will be.
     [SerializeField]
     private float _distanceUp;
     [SerializeField]
     public static float _lookAtSmoothing;
     [SerializeField]
     private Transform _targetXForm;
     [SerializeField]
     private CharacterControllerLogic2 targetScript;
     
     // Smoothing and damping
     private Vector3 velocityCamSmooth = Vector3.zero;
     [SerializeField]
     private float camSmoothDampTime = 0.1f;
     
     // Private global
     private Vector3 _lookDir;
     private Vector3 _targetPos;
     private float rightX = 0;
     private float rightY = 0;
     
     private Transform transparentObj;
     private AutoTransparent transparentObjScript;
         
     private CamStates camState = CamStates.Behind;
     private Animator _playerAnimator;
     
     public LayerMask ignoreCamCollisionLayer;
 
     public struct clipPlanePoints
     {
         public Vector3 upperLeft;
         public Vector3 upperRight;
         public Vector3 lowerLeft;
         public Vector3 lowerRight;
         
     }
     public float occlusionDistanceStep = 0.5f;
     public int maxOcclusionChecks = 10;
     private float tempDesiredDistance = 0f;
     private float desiredDistance = 0f;
     public float distanceSmooth = 0.5f;
     private float velDistance = 0f;
     private Vector3 desiredPosition;
     
     public enum CamStates
     {
         Behind,
         Target,
         Free
     }
     
     public CamStates CamState 
     {
         get { return this.camState; }
     }
 
     void OnEnable()
     {
         Messenger.AddListener("EnterTargeting", EnterTargeting);
         Messenger.AddListener("ExitTargeting", ExitTargeting);
     }
 
     void OnDisable()
     {
         Messenger.RemoveListener("EnterTargeting", EnterTargeting);
         Messenger.RemoveListener("ExitTargeting", ExitTargeting);
     }
     
     void Awake()
     {
         targetScript = GameObject.FindGameObjectWithTag("Player").GetComponent<CharacterControllerLogic2>();
     }
     
     // Use this for initialization
     void Start () 
     {
         targetScript = GameObject.FindGameObjectWithTag("Player").GetComponent<CharacterControllerLogic2>();
         _targetXForm = GameObject.FindGameObjectWithTag("Player").transform;
         _playerAnimator = GameObject.FindGameObjectWithTag("Player").GetComponent<Animator>();
         _lookDir = _targetXForm.forward;
         
         if (targetScript == null)
         {
             Debug.LogError("Could not find \"CharacterControllerLogic2\"!");
         }
         ignoreCamCollisionLayer = ~ignoreCamCollisionLayer;
     }
     
     // Update is called once per frame
     void Update () 
     {
         
     }
     
     void FixedUpdate()
     {    
         rightX = 0;
         rightY = 0;
         
         if (GameSettings.KEYBOARD)
         {
             rightX = Input.GetAxis("KBCameraH");
             rightY = Input.GetAxis("KBCameraV");
         }
         else if (GameSettings.XBOX)
         {
             rightX = Input.GetAxis("XBOXCameraH");
             rightY = Input.GetAxis("XBOXCameraV");
         }
         else if (GameSettings.PS3)
         {
             rightX = Input.GetAxis("PS3CameraH");
             if (GameSettings.PS3_OSX)
             {
                 rightY = Input.GetAxis("PS3CameraVOSX");    
             }
             else
             {
                 rightY = Input.GetAxis("PS3CameraV");
             }
         }
         
         Vector3 characterOffset = Vector3.zero;
         
         characterOffset = _targetXForm.position + new Vector3(0, _distanceUp, 0);
         
         if (!_playerAnimator.GetBool("Targeting"))
         {
             camState = CamStates.Behind;    
         }
         
         switch(camState)
         {
         case CamStates.Behind:
             
             // Calculate direction from camera to player, kill y, and normalize to give a valid direction with unit magnitude.
             _lookDir = characterOffset - this.transform.position;
             _lookDir.y = 0;
             _lookDir.Normalize();
             Debug.DrawRay(this.transform.position, _lookDir, Color.black);
             
             //Debug.DrawRay(_targetXForm.position, Vector3.up * _distanceUp, Color.red);
             //Debug.DrawRay(_targetXForm.position, -Vector3.forward * _distanceBehind, Color.blue);
             //Debug.DrawLine(_targetXForm.position, _targetPos, Color.magenta);
             
             break;
             
         case CamStates.Target:
             
             rightX = 0;
             rightY = 0;
 
             _lookDir = _targetXForm.forward;
 
             break;
         }
 
         if (PlayerCharacter.currentPlayerState == PlayerCharacter.playersState.PLAY)
         {
             // allow free rotation with right joystick
             transform.RotateAround(_targetXForm.position, Vector3.up, rightX * 200 * Time.deltaTime);
         }
         else if (PlayerCharacter.currentPlayerState == PlayerCharacter.playersState.DEAD)
         {
             // allow free rotation with right joystick
             transform.RotateAround(_targetXForm.position, Vector3.up, rightX * 50 * Time.deltaTime);
         }
         
         Vector3 relativePos = _targetXForm.position - transform.position;
         Vector3 relativePosRight = Vector3.Cross(relativePos, Vector3.up);
         
         if (PlayerCharacter.currentPlayerState == PlayerCharacter.playersState.PLAY)
             transform.RotateAround(_targetXForm.position, relativePosRight, rightY * 200 * Time.deltaTime);
         
         // Setting target position to be correct offset.
         _targetPos = characterOffset + (_targetXForm.up * _distanceUp) - (_lookDir * _distanceBehind);
         
         CompensateForWalls(characterOffset, ref _targetPos);
         
         // Move camera to new position smoothly.
         SmoothPosition(this.transform.position, _targetPos);
         
         //Vector3 lookAtTarget = characterOffset;
 
         //if (targetScript.PushingObject)
             //lookAtTarget = _targetXForm.forward;
 
         // Look at player.
         transform.LookAt(characterOffset);    
         
         //Debug.Log (rightX + " " + rightY);
     }
     Vector3 CalculateDesiredPosition(Vector3 characterOffset)
     {
         tempDesiredDistance = Mathf.SmoothDamp(tempDesiredDistance, _distanceBehind, ref velDistance, distanceSmooth);
         
         desiredPosition = CalculatePosition(tempDesiredDistance, characterOffset);
         
         return desiredPosition;
     }
     
     Vector3 CalculatePosition(float distance, Vector3 characterOffset)
     {
         return characterOffset + (_targetXForm.up * _distanceUp) - (_lookDir * distance);
     }
     
     public static clipPlanePoints ClipPlaneAtNear(Vector3 pos)
     {
         var clipPlanePoints = new clipPlanePoints();
         
         if(Camera.main == null)
         {return clipPlanePoints;}
         
         var transform = Camera.main.transform;
         var halfFOV = (Camera.main.fieldOfView/2)*Mathf.Deg2Rad;
         var aspect = Camera.main.aspect;
         var distance = Camera.main.nearClipPlane;
         var height = distance *Mathf.Tan(halfFOV);
         var width = height * aspect;
         
         //'draw' the points
         
         clipPlanePoints.lowerRight = pos + transform.right *width;
         clipPlanePoints.lowerRight -= transform.up*height;
         clipPlanePoints.lowerRight += transform.forward * distance;
         
         clipPlanePoints.lowerLeft = pos - transform.right *width;
         clipPlanePoints.lowerLeft -= transform.up*height;
         clipPlanePoints.lowerLeft += transform.forward * distance;
         
         clipPlanePoints.upperRight = pos + transform.right *width;
         clipPlanePoints.upperRight += transform.up*height;
         clipPlanePoints.upperRight += transform.forward * distance;
         
         clipPlanePoints.upperLeft = pos - transform.right *width;
         clipPlanePoints.upperLeft += transform.up*height;
         clipPlanePoints.upperLeft += transform.forward * distance;
 
         return clipPlanePoints;
     }
     
     bool CheckIfOccluded(int count, Vector3 characterOffset)
     {
         var isOccluded = false;
         
         var nearestDistance = checkCameraPoints(characterOffset,  _targetPos);
         
         if(nearestDistance != -1)
         {
             if(count < maxOcclusionChecks)
             {
                 isOccluded = true;
                 tempDesiredDistance -= occlusionDistanceStep;
                 
                 if (tempDesiredDistance < 0.25f)
                 {
                     tempDesiredDistance = 0.25f;
                 }
             }
             else
             {
                 tempDesiredDistance = nearestDistance - Camera.main.nearClipPlane;
             }
             desiredDistance = tempDesiredDistance;
         }
         
         return isOccluded;
     }
     
     float checkCameraPoints(Vector3 from, Vector3 to)
     {
         float nearDistance = -1.0f;
         
         RaycastHit hitInfo;
         
         clipPlanePoints clipPlanePoints;
         
         clipPlanePoints = ClipPlaneAtNear(to);
         
         //draw lines 
         Debug.DrawLine(from, to + transform.forward * -camera.nearClipPlane, Color.red);
         Debug.DrawLine(from, clipPlanePoints.upperLeft);
         Debug.DrawLine(from, clipPlanePoints.upperRight);
         Debug.DrawLine(from, clipPlanePoints.lowerLeft);
         Debug.DrawLine(from, clipPlanePoints.lowerRight);
         
         Debug.DrawLine(clipPlanePoints.upperLeft, clipPlanePoints.upperRight);
         Debug.DrawLine(clipPlanePoints.upperRight, clipPlanePoints.lowerRight);
         Debug.DrawLine(clipPlanePoints.lowerRight, clipPlanePoints.lowerLeft);
         Debug.DrawLine(clipPlanePoints.lowerLeft, clipPlanePoints.upperLeft);
         
         if(Physics.Linecast(from, clipPlanePoints.upperLeft, out hitInfo, ignoreCamCollisionLayer))
         {
             nearDistance = hitInfo.distance;
         }
         if(Physics.Linecast(from, clipPlanePoints.lowerLeft, out hitInfo, ignoreCamCollisionLayer))
         {
             if(hitInfo.distance < nearDistance || nearDistance == -1)
             {
                 nearDistance = hitInfo.distance;
             }
         }
         if(Physics.Linecast(from, clipPlanePoints.upperRight, out hitInfo, ignoreCamCollisionLayer))
         {
             if(hitInfo.distance < nearDistance || nearDistance == -1)
             {
                 nearDistance = hitInfo.distance;
             }
         }
         if(Physics.Linecast(from, clipPlanePoints.lowerRight, out hitInfo, ignoreCamCollisionLayer))
         {
             if(hitInfo.distance < nearDistance || nearDistance == -1)
             {
                 nearDistance = hitInfo.distance;
             }
             //Debug.LogWarning(hitInfo.normal);
         }
         //        if(Physics.Linecast(from, to + transform.forward * -camera.nearClipPlane, out hitInfo) && hitInfo.collider.tag != "Player")
         //        {
         //            if(hitInfo.distance < nearDistance || nearDistance == -1)
         //            {
         //                nearDistance = hitInfo.distance;
         //            }
         //        }
         
         //Debug.Log("NearDistance: " + nearDistance);
 
         return nearDistance;
         
     }
     
     private void SmoothPosition(Vector3 fromPos, Vector3 toPos)
     {
         this.transform.position = Vector3.SmoothDamp(fromPos, toPos, ref velocityCamSmooth, camSmoothDampTime);        
     }
     
     private void SmoothLookAt(Vector3 fromPos, Vector3 targetPos)
     {
         Quaternion rotation = Quaternion.LookRotation(targetPos - fromPos);
         this.transform.rotation = Quaternion.Slerp(this.transform.rotation, rotation, Time.deltaTime * _lookAtSmoothing);    
     }
     
     private void CompensateForWalls(Vector3 fromObject,  ref Vector3 toTarget)
     {
         RaycastHit wallHit;
         
         //        if (Physics.Linecast(fromObject, toTarget, out wallHit, ignoreCamCollisionLayer))
         //        {
         //            if (wallHit.transform.tag.Equals("Transparent"))
         //            {
         //                transparentObj = wallHit.transform;
         //                 
         //                transparentObjScript = transparentObj.GetComponent<AutoTransparent>();
         //                if (transparentObjScript == null) // if no script is attached, attach one
         //                {
         //                    transparentObjScript = transparentObj.gameObject.AddComponent<AutoTransparent>();
         //                }
         //                transparentObjScript.BeTransparent = true;
         //            }
         //            else
         //            {
         //                if (transparentObjScript != null)
         //                {
         //                    transparentObjScript.BeTransparent = false;
         //                    transparentObjScript = null;
         //                }
         //            }
         //        }
         //        else
         //        {
         //            if (transparentObjScript != null)
         //            {
         //                transparentObjScript.BeTransparent = false;
         //                transparentObjScript = null;
         //            }
         
         var count = 0;
         do
         {
             count++;
         }while (CheckIfOccluded(count, fromObject));
         
         toTarget = CalculateDesiredPosition(fromObject);
         //}
     }
 
     private void EnterTargeting()
     {
         if (PlayerCharacter.currentPlayerState == PlayerCharacter.playersState.PLAY)
         {
             _playerAnimator.SetBool("Targeting", true);
             camState = CamStates.Target;
         }
     }
 
     private void ExitTargeting()
     {
         if (PlayerCharacter.currentPlayerState == PlayerCharacter.playersState.PLAY)
         {
             _playerAnimator.SetBool("Targeting", false);
             camState = CamStates.Behind;
         }
     }
 }
Comment

People who like this

0 Show 0
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

0 Replies

· Add your reply
  • Sort: 

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Welcome to Unity Answers

If you’re new to Unity Answers, please check our User Guide to help you navigate through our website and refer to our FAQ for more information.

Before posting, make sure to check out our Knowledge Base for commonly asked Unity questions.

Check our Moderator Guidelines if you’re a new moderator and want to work together in an effort to improve Unity Answers and support our users.

Follow this Question

Answers Answers and Comments

21 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Is there any way to create a fade effect in order to hide what isn't rendered by the camera? 0 Answers

camera clipping planes flickering 2 Answers

Near clipping plane is different when game is maximized 0 Answers

MouseOrbitImproved camera distance seemingly inverted 1 Answer

Camera Clips though Walls 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges