How to stop the camera from clipping through mesh/walls/objects?

I’m trying to make a camera that doesn’t go through walls. I have my test player run into a house but I can still see the outside of it and after trying the script on the Unity3D wiki and replacing target with my model’s name, which is Basehuman01b, I still can’t get it to work. I’ll put a copy of the script here so hopefully someone can point out where I’ve gone wrong :slight_smile:

The C# script:

using UnityEngine;
using System.Collections;

public class SmoothCameraWithBumper : MonoBehaviour
{
[SerializeField] private Transform target = null;
[SerializeField] private float distance = 3.0f;
[SerializeField] private float height = 1.0f;
[SerializeField] private float damping = 5.0f;
[SerializeField] private bool smoothRotation = true;
[SerializeField] private float rotationDamping = 10.0f;

[SerializeField] private Vector3 targetLookAtOffset; // allows offsetting of camera lookAt, very useful for low bumper heights

[SerializeField] private float bumperDistanceCheck = 5f; // length of bumper ray
[SerializeField] private float bumperCameraHeight = 1.0f; // adjust camera height while bumping
[SerializeField] private Vector3 bumperRayOffset; // allows offset of the bumper ray from target origin

/// <Summary>
/// If the target moves, the camera should child the target to allow for smoother movement. DR
/// </Summary>
private void Awake()
{
	GetComponent<Camera>().transform.parent = Basehuman01b;
}

private void FixedUpdate() 
{
	Vector3 wantedPosition = Basehuman01b.TransformPoint(0, height, -distance);

	// check to see if there is anything behind the target
	RaycastHit hit;
	Vector3 back = Basehuman01b.transform.TransformDirection(-1 * Vector3.forward); 

	// cast the bumper ray out from rear and check to see if there is anything behind
	if (Physics.Raycast(Basehuman01b.TransformPoint(bumperRayOffset), back, out hit, bumperDistanceCheck)
		&& hit.transform != target) // ignore ray-casts that hit the user. DR
	{
		// clamp wanted position to hit position
		wantedPosition.x = hit.point.x;
		wantedPosition.z = hit.point.z;
		wantedPosition.y = Mathf.Lerp(hit.point.y + bumperCameraHeight, wantedPosition.y, Time.deltaTime * damping);
	} 

	transform.position = Vector3.Lerp(transform.position, wantedPosition, Time.deltaTime * damping);

	Vector3 lookPosition = Basehuman01b.TransformPoint(targetLookAtOffset);

	if (smoothRotation)
	{
		Quaternion wantedRotation = Quaternion.LookRotation(lookPosition - transform.position, Basehuman01b.up);
		transform.rotation = Quaternion.Slerp(transform.rotation, wantedRotation, Time.deltaTime * rotationDamping);
	} 
	else 
		transform.rotation = Quaternion.LookRotation(lookPosition - Basehuman01b.position, target.up);
}

}

I have also tried putting colliders and rigidbody on it with no effect. I even tried the same thing but on a cube, put it so the camera was inside it(with colliders and rigidbody on the cube) and still no luck :confused:

Again I’m really stuck here and I would love some advice, so if you see what the issue is please don’t hesitate to point it out :slight_smile:

I suspect that your raycasts are hitting the player. You have presumably spotted this problem since you have a condition to ignore rays that hit the player…but if ALL your raycasts hit the player then you will never detect any obstruction.
Better to put the player on a Layer and ensure the raycast excludes that Layer.

Also your wantedPosition is raised slightly in the Y, but your raycast is firing straight along the local -Z axis. That might also cause inaccurate collision detection. I’m not sure what the lerp on wantedPosition.y is for, as you are resetting wantedPosition.y every frame at the top of the function…

I found out what was wrong thanks to a friend.

The script was supposed to be like this:

using UnityEngine; using System.Collections;

public class SmoothCameraWithBumper : MonoBehaviour {
  [SerializeField] private Transform target = null;
  [SerializeField] private float distance = 3.0f;
  [SerializeField] private float height = 1.0f;
  [SerializeField] private float damping = 5.0f;
  [SerializeField] private bool smoothRotation = true;
  [SerializeField] private float rotationDamping = 10.0f;

 [SerializeField] private Vector3 targetLookAtOffset; // allows offsetting of camera lookAt, very useful for low bumper heights
 [SerializeField] private float bumperDistanceCheck = 5f; // length of bumper ray
 [SerializeField] private float bumperCameraHeight = 1.0f; // adjust camera height while bumping
 [SerializeField] private Vector3 bumperRayOffset; // allows offset of the bumper ray from target origin
 /// 
 /// If the target moves, the camera should child the target to allow for smoother movement. DR
 /// 
 private void Awake()
 {
     GetComponent<Camera>().transform.parent = targetb;
 }
 private void FixedUpdate() 
 {
     Vector3 wantedPosition = target.TransformPoint(0, height, -distance);
     // check to see if there is anything behind the target
     RaycastHit hit;
     Vector3 back = target.transform.TransformDirection(-1 * Vector3.forward); 
     // cast the bumper ray out from rear and check to see if there is anything behind
     if (Physics.Raycast(target.TransformPoint(bumperRayOffset), back, out hit, bumperDistanceCheck)
         && hit.transform != target) // ignore ray-casts that hit the user. DR
     {
         // clamp wanted position to hit position
         wantedPosition.x = hit.point.x;
         wantedPosition.z = hit.point.z;
         wantedPosition.y = Mathf.Lerp(hit.point.y + bumperCameraHeight, wantedPosition.y, Time.deltaTime * damping);
     } 
     transform.position = Vector3.Lerp(transform.position, wantedPosition, Time.deltaTime * damping);
     Vector3 lookPosition = target.TransformPoint(targetLookAtOffset);
     if (smoothRotation)
     {
         Quaternion wantedRotation = Quaternion.LookRotation(lookPosition - transform.position, target.up);
         transform.rotation = Quaternion.Slerp(transform.rotation, wantedRotation, Time.deltaTime * rotationDamping);
     } 
     else 
         transform.rotation = Quaternion.LookRotation(lookPosition - target.position, target.up);
 }
}

When you put this script in Unity, there’s some fields in the inspector that you’re supposed to fill out. That and make sure the rotation of your model is set up properly(mine wasn’t)

Now, in the inspector, one of the fields will say “Bumper Distance Check” This is how close an object has to be before the camera will be moved. If you go into isometric view, there will be some squares. So if you put in 15 in the “Bumper Distance Check” the camera will move away when something within 15 squares collides with it, if that makes sense.

Also this is important, make sure you name your script SmoothCameraWithBumper otherwise you might get some errors.

I found it useful, and wanna share with you guys,
Original code [http://wiki.unity3d.com/index.php?title=SmoothFollowWithCameraBumper][1],
Improvement: you need to add your target tag or target transform and ignored object tag (if necessary). C#

//(Created CSharp Version) 10/2010: Daniel P. Rossi (DR9885) 
using UnityEngine;

public class SmoothCameraWithBumper : MonoBehaviour
{
    [Header("[TARGET]")]
    [SerializeField]
    private Transform target = null; // manually assign target transform 
    [SerializeField] private string targetTag; //Or just insert your target tag
    [SerializeField] private string[] ignoreTag; //List of ignored tags so the raycast can pass through on them
    [Range(0, 5.0f)]
    [SerializeField]
    private float invokeUpdateRate = 0.3f;
    [Header("[ADJUSTMENT]")]
    [SerializeField] private float distance = 4.0f;
    [SerializeField] private float height = 0.35f;
    [SerializeField] private float damping = 2.0f;
    [SerializeField] private bool smoothRotation = true;
    [SerializeField] private float rotationDamping = 3.0f;

    [SerializeField] private Vector3 targetLookAtOffset; // allows offsetting of camera lookAt, very useful for low bumper heights

    [SerializeField] private float bumperDistanceCheck = 2.5f; // length of bumper ray
    [SerializeField] private float bumperCameraHeight = 1.0f; // adjust camera height while bumping
    [SerializeField] private Vector3 bumperRayOffset; // allows offset of the bumper ray from target origin

    private void Start()
    {
        if (target == null) InvokeRepeating("FindTarget", 0.5f, invokeUpdateRate);
    }

    private void FindTarget()
    {
        if (target == null)
        {
            GameObject camTarget = GameObject.FindGameObjectWithTag(targetTag);
            if (camTarget != null)
            {
                target = camTarget.transform;
            }
        }
    }

    private void LateUpdate()
    {
        if (target != null)
        {
            Vector3 wantedPosition = target.TransformPoint(0, height, -distance);

            // check to see if there is anything behind the target
            RaycastHit hit;
            Vector3 back = target.transform.TransformDirection(-1 * Vector3.forward);

            // cast the bumper ray out from rear and check to see if there is anything behind
            if (Physics.Raycast(target.TransformPoint(bumperRayOffset), back, out hit, bumperDistanceCheck)
                && hit.transform != target) // ignore ray-casts that hit the user. DR
            {
                if (ignoreTag.Length > 0)
                {
                    for (int i = 0; i < ignoreTag.Length; i++)
                    {
                        if (hit.transform.CompareTag(ignoreTag*))*

{
return;
}
}
}
wantedPosition.x = hit.point.x;
wantedPosition.z = hit.point.z;
wantedPosition.y = Mathf.Lerp(hit.point.y + bumperCameraHeight, wantedPosition.y, Time.deltaTime * damping);
}

transform.position = Vector3.Lerp(transform.position, wantedPosition, Time.deltaTime * damping);

Vector3 lookPosition = target.TransformPoint(targetLookAtOffset);

if (smoothRotation)
{
Quaternion wantedRotation = Quaternion.LookRotation(lookPosition - transform.position, target.up);
transform.rotation = Quaternion.Slerp(transform.rotation, wantedRotation, Time.deltaTime * rotationDamping);
}
else
{
transform.rotation = Quaternion.LookRotation(lookPosition - transform.position, target.up);
}
}
}
}
[1]: http://wiki.unity3d.com/index.php?title=SmoothFollowWithCameraBumper
*