3
\$\begingroup\$

Hi I'm trying to do a basic Camera Collision in unity, for convenience, here's the entire script (I actually got most of it from someone else who wrote the comments, if that's necessary to know):

/// /// /// CameraControllercs.cs /// Camera Controller in CSharp v2.1 /// using UnityEngine; using System.Collections; using UnityEngine.EventSystems; public class CameraController : MonoBehaviour { public GameObject target; // Target to follow public float targetHeight = 1.7f; // Vertical offset adjustment public float distance = 12.0f; // Default Distance public float offsetFromWall = 0.7f; // Bring camera away from any colliding objects public float maxDistance = 20f; // Maximum zoom Distance public float minDistance = 0.6f; // Minimum zoom Distance public float xSpeed = 200.0f; // Orbit speed (Left/Right) public float ySpeed = 200.0f; // Orbit speed (Up/Down) public float yMinLimit = -80f; // Looking up limit public float yMaxLimit = 80f; // Looking down limit public float zoomRate = 40f; // Zoom Speed public float rotationDampening = 3.0f; // Auto Rotation speed (higher = faster) public float zoomDampening = 5.0f; // Auto Zoom speed (Higher = faster) public int collisionLayers; // What the camera will collide with public bool lockToRearOfTarget = false; // Lock camera to rear of target public bool allowMouseInputX = true; // Allow player to control camera angle on the X axis (Left/Right) public bool allowMouseInputY = true; // Allow player to control camera angle on the Y axis (Up/Down) private float xDeg = 0.0f; private float yDeg = 0.0f; private float currentDistance; private float desiredDistance; private float correctedDistance; private bool rotateBehind = false; private bool mouseSideButton = false; private float pbuffer = 0.0f; //Cooldownpuffer for SideButtons private float coolDown = 0.5f; //Cooldowntime for SideButtons GameObject main; void Start() { collisionLayers = LayerMask.GetMask("Default"); var temp = GameObject.Find("main"); if(temp != null) { main = temp; } Vector3 angles = transform.eulerAngles; xDeg = angles.x; yDeg = angles.y; currentDistance = distance; desiredDistance = distance; correctedDistance = distance; Camera.main.nearClipPlane = 0.001f; if (lockToRearOfTarget) rotateBehind = true; } void Update() { if (target == null) { target = GameObject.FindGameObjectWithTag("Player") as GameObject; Debug.Log("Looking for Player"); } } //Only Move camera after everything else has been updated void FixedUpdate() { // Don't do anything if target is not defined if (target == null) return; //pushbuffer if (pbuffer > 0) pbuffer -= Time.deltaTime; if (pbuffer currentDistance ? Mathf.Lerp(currentDistance, correctedDistance, Time.deltaTime * zoomDampening) : Mathf.Lerp(currentDistance, correctedDistance, Time.deltaTime * zoomDampening * 3); // Keep within limits currentDistance = Mathf.Clamp(currentDistance, minDistance, maxDistance); // Recalculate position based on the new currentDistance position = target.transform.position - (rotation * Vector3.forward * currentDistance + vTargetOffset); //Finally Set rotation and position of camera transform.rotation = rotation; transform.position = position; } private void RotateBehindTarget() { float targetRotationAngle = target.transform.eulerAngles.y; float currentRotationAngle = transform.eulerAngles.y; xDeg = Mathf.LerpAngle(currentRotationAngle, targetRotationAngle, rotationDampening * Time.deltaTime); // Stop rotating behind if not completed if (targetRotationAngle == currentRotationAngle) { if (!lockToRearOfTarget) rotateBehind = false; } else rotateBehind = true; } private float ClampAngle(float angle, float min, float max) { if (angle 360f) angle -= 360f; return Mathf.Clamp(angle, min, max); } }

As you can see in the start function, I also set the near clipping to a low value (the camera has a MainCamera tag BTW).

The problem: as you can see in this picture enter image description here

even with the low nearClipping value, and the high offsetFromWall value (0.7f when it's normally 0.1f), the camera is still clipping the ground when moving it with the mouse semi-fast (when it's moved kind of slow it's not a problem).

I have no idea how to fix this, if I make the nearClipping lower the whole render gets messed up, and even then it doesn't work, so what else can I do to ensure that the user never sees underneath the ground?

\$\endgroup\$
8
  • \$\begingroup\$ Is your camera under the terrain? if then, the problem is "backface culling" and not the near/far plane. \$\endgroup\$ Commented Aug 10, 2018 at 18:31
  • \$\begingroup\$ @Nick no it's moveable with the mouse arrow keys. Try testing out the code if you want, just give the player a "Player" tag it can even be a cube \$\endgroup\$ Commented Aug 10, 2018 at 18:33
  • \$\begingroup\$ I can't even compile your script, there are many symbols missing. Also, what is UIHandler? You have this line "ui = GameObject.Find("main").GetComponent();" GetComponent what? please edit your question. \$\endgroup\$ Commented Aug 10, 2018 at 18:45
  • \$\begingroup\$ @Nick sry forgot to remove that, should be fixed now \$\endgroup\$ Commented Aug 10, 2018 at 19:04
  • \$\begingroup\$ Its still not compiling! Many symbols are missing! Also by what logic you are multiplying arbitrary variable rotation by vector (from this we know that rotation is not a vector variable) and then assigning it to transform.rotation? Please, copy script you have posted here, start a new unity project, paste it there, fix all the errors and then post it again. \$\endgroup\$ Commented Aug 11, 2018 at 8:00

2 Answers 2

2
\$\begingroup\$

Near Clip Plane

It sounds like you've misunderstood what a camera's near clip plane is. The official unity scripting manual describes the clip planes as:

  • Clipping Planes: Distances from the camera to start and stop rendering.
  • Near Plane: The closest point relative to the camera that drawing will occur.

These planes create the camera's view frustum. The view frustum is essentially a box in front of the camera's position which lets the camera know what to render. Anything inside that frustum gets displayed to the screen. So when you set camera.nearClipPlane your adjusting how close to the camera's position that box is.

Picture of a view frustum

The frustum only controls what the camera sees, NOT how it moves. If you want to prevent the camera from moving through solid objects you would need to set up some kind of collision between the camera and anything you want to avoid tunneling into (in this case the ground).

Fixed Update

Unity has several update functions which each do different things. Fixed update occurs at a fixed rate. This update is normally used for physics and math updates which require a fixed timestep. According to your comment //Only Move camera after everything else has been updated, you want the camera to update last. I would recommend using LateUpdate() instead of FixedUpdate(). Unity3D's update order is described as:

  • Fixed Update is often called more frequently than Update. It can be called multiple times per frame, if the frame rate is low and it may not be called between frames at all if the frame rate is high. All physics calculations and updates occur immediately after FixedUpdate. When applying movement calculations inside FixedUpdate, you do not need to multiply your values by Time.deltaTime. This is because FixedUpdate is called on a reliable timer, independent of the frame rate.
  • Late Update is called once per frame, after Update has finished. Any calculations that are performed in Update will have completed when LateUpdate begins. A common use for LateUpdate would be a following third-person camera. If you make your character move and turn inside Update, you can perform all camera movement and rotation calculations in LateUpdate. This will ensure that the character has moved completely before the camera tracks its position.
\$\endgroup\$
1
\$\begingroup\$

You can just cast a ray from, say, knees of the player model to the camera POV. If it intersects terrain - constrain the camera's vertical movement to current level.

\$\endgroup\$
4
  • \$\begingroup\$ I'm just trying to picture this in my head: If you cast a ray from the knees to the camera, and the camera can rotate any direction, then the camera can still be literally on the ground (and clip off the view) while stil having no intersections between the ray and the ground \$\endgroup\$ Commented Feb 22, 2019 at 6:39
  • \$\begingroup\$ @bluejayke Yes, usually you'd use a spherecast with some radius, or raycast in the direction of the camera, then position the camera at least some minimum distance in front of the intersection found, so the near plane doesn't clip the surface. \$\endgroup\$ Commented Feb 22, 2019 at 13:56
  • \$\begingroup\$ @DMGregory I tried the second approahc and I had some problems when dragging it on the ground over objects, it seemed to jump a little.. do you have any code examples? \$\endgroup\$ Commented Feb 24, 2019 at 4:50
  • \$\begingroup\$ Sounds like you might want to apply some smoothing, and/or a wider check. \$\endgroup\$ Commented Feb 24, 2019 at 5:36

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.