Hi there,

It's my first time posting on here, so apologies in advance if I'm breaking like a thousand rules here.

So over the past few days, I've been watching and following the (rather old now, but still useful) video tutorials on creating a custom third-person character and camera system with C#: (http://www.3dbuzz.com/training/view/...aracter-system). Of course, I had to make a few tweaks here and there to fit my game's needs, but everything more or less worked flawlessly until I reached the part about implementing the handling of camera occlusion, specifically this video: (http://www.3dbuzz.com/training/view/...implementation).

To be brief, the issue I'm experiencing is that as soon as I run the game, the camera zooms in extremely close to my character. It has not done this before I implemented occlusion handling, and if I commented out the occlusion handling, it would work just fine (except of course for the fact that it did not handle occlusion) - the camera would start a fair distance away from the character, and everything would work as normal. Furthermore, when I have the code for occlusion active, I cannot zoom out. The camera will instantly snap back to being up close to my character.

I have spent a considerable amount of time attempting to debug this, and I'm fairly certain that I've followed everything in the tutorial to a T, so I'm completely stumped as to what could have gone wrong. To be clear, I am not using the character or the level used in the tutorial - my character is a simple cylinder and my level is a flat surface. These should not be contributing factors to the problem as far as I know, especially since everything else has functioned perfectly up until this point.

Something strange I have noticed though is that the linecasts for detecting occlusion seem to penetrate through my character in an unexpected way, as pictured here: (Click image for larger version. 

Name:	974e89bc96284c9c8582a7e1d46576bc.png 
Views:	45 
Size:	279.6 KB 
ID:	74666). As is depicted here additionally, my camera is extremely close to the avatar. This does not seem to happen in the tutorial videos, and did not happen until I finished implementing the CheckIfOccluded(count: int) method.

Here's the relevant problematic code, although it probably is a far deeper rooted problem, I figured I'd give this as a starting point:

CheckIfOccluded(count: int)
bool CheckIfOccluded (int count) {
		var isOccluded = false;

		var nearestDistance = CheckCameraPoints (TargetLookAt.position, desiredPosition);

		if (nearestDistance != -1) {
			if (count < maxOcclusionChecks) {
				// If we still have not reached the max occlusion checks, move the camera in increments.
				isOccluded = true;
				distance -= occlusionDistanceStep;
				// Ensure that distance never reaches 0 because we do not support first-person.
				if (distance < 0.25f) {
					distance = 0.25f;
		} else {
			// If we have exceeded the max occlusion checks, immediately snap the camera to the proper position.
			distance = nearestDistance - Camera.main.nearClipPlane;

		desiredDistance = distance;
		preDistanceSmooth = distanceResumeSmooth;

		return isOccluded;
CheckCameraPoints(from: Vector3, to: Vector3)
float CheckCameraPoints (Vector3 from, Vector3 to) {
		var nearestDistance = -1.0f;	// Return anything but -1 and there has been a collision.

		RaycastHit hitInfo;

		TP_CameraHelper.ClipPlanePoints cpps = TP_CameraHelper.ClipPlaneAtNear (to);

		// Debug code to draw lines in the editor to make it easier to visualize whether or not occlusion has occurred.
		Debug.DrawLine(from, to + (transform.forward * -Camera.main.nearClipPlane), Color.red);
		Debug.DrawLine (from, cpps.upperLeft);
		Debug.DrawLine (from, cpps.upperRight);
		Debug.DrawLine (from, cpps.lowerLeft);
		Debug.DrawLine (from, cpps.lowerRight);
		// The box drawn by these lines represents the player's FOV.
		Debug.DrawLine (cpps.upperLeft, cpps.upperRight);
		Debug.DrawLine (cpps.upperRight, cpps.lowerRight);
		Debug.DrawLine (cpps.lowerRight, cpps.lowerLeft);
		Debug.DrawLine (cpps.lowerLeft, cpps.upperLeft);

		if (Physics.Linecast (from, cpps.upperLeft, out hitInfo) && hitInfo.collider.tag != "Player") {
			nearestDistance = hitInfo.distance;
		if (Physics.Linecast (from, cpps.lowerLeft, out hitInfo) && hitInfo.collider.tag != "Player") {
			if (hitInfo.distance < nearestDistance || nearestDistance == -1) {
				nearestDistance = hitInfo.distance;
		if (Physics.Linecast (from, cpps.upperRight, out hitInfo) && hitInfo.collider.tag != "Player") {
			if (hitInfo.distance < nearestDistance || nearestDistance == -1) {
				nearestDistance = hitInfo.distance;
		if (Physics.Linecast (from, cpps.lowerRight, out hitInfo) && hitInfo.collider.tag != "Player") {
			if (hitInfo.distance < nearestDistance || nearestDistance == -1) {
				nearestDistance = hitInfo.distance;
		if (Physics.Linecast (from, to + (transform.forward * -Camera.main.nearClipPlane), out hitInfo) && hitInfo.collider.tag != "Player") {
			if (hitInfo.distance < nearestDistance || nearestDistance == -1) {
				nearestDistance = hitInfo.distance;

		return nearestDistance;
ClipPlanePoints(position: Vector3)
public static ClipPlanePoints ClipPlaneAtNear (Vector3 position) {
		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;

		clipPlanePoints.upperLeft = position - (transform.right * width);
		clipPlanePoints.upperLeft += transform.up * height;
		clipPlanePoints.upperLeft += transform.forward * distance;

		clipPlanePoints.upperRight = position + (transform.right * width);
		clipPlanePoints.upperRight += transform.up * height;
		clipPlanePoints.upperRight += transform.forward * distance;

		clipPlanePoints.lowerLeft = position - (transform.right * width);
		clipPlanePoints.lowerLeft -= transform.up * height;
		clipPlanePoints.lowerLeft += transform.forward * distance;

		clipPlanePoints.lowerRight = position + (transform.right * width);
		clipPlanePoints.lowerRight -= transform.up * height;
		clipPlanePoints.lowerRight += transform.forward * distance;

		return clipPlanePoints;
Lastly, to eliminate any common problem points, I have ensured that the avatar, and all of its children, except targetLookAt, have been tagged as a "Player" with "Ignore Raycast". I have quadruple checked that the signs in ClipPlanePoints are correct, so unless I'm being extremely silly, there shouldn't be a problem there. I have tried setting the distance check in CheckIfOccluded to 5.0f, but all that does is kick me out to 5.0f - if I even touch the scroll wheel, it will instantly kick me back to being up against the avatar.

In all honestly, this probably has a very simple solution that I'm overlooking, but I just can't seem to see it right now. I'd really appreciate if I had another set of eyes to look over this. You're a champion if you've read this far, by the way.

Thanks a bunch.