Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 Jun 22
sparklines
Close Help
  • 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
1
Question by ridlr · Jan 04, 2021 at 10:17 PM · physicslagbug-perhapsblurry

Camera Lag/Blurriness when Moving and Rotating At the Same Time

In the FPS game that I am currently working on, when moving the rigidbody attached to the player and turning the camera at the same time, a lot of lag/blurriness occurs. I am setting the position and rotation of the camera (it is not parented to the player) in Update() and adding forces to the rigidbody in FixedUpdate(). I have interpolation enabled on the rigidbody, but it doesn't seem to fix the issue. When moving the rigidbody or rotating the camera independently of one another, everything works fine. Only when doing both at the same time does the issue occur. As I increase the frequency of the physics timestep the blurriness is reduced (at 0.05 it is EXTREMELY noticeable and at 0.005 it is barely noticeable, for example). This is not a very good solution since it can tank the frame rate, so I would love to be able to avoid it. Any suggestions?

Here is my code currently:

 using System.Collections;
 using System.Collections.Generic;
 using UnityEngine;
 using TMPro;
 
 public class BackupPlayerController : MonoBehaviour
 {
     public static BackupPlayerController Instance;
     
     [Header("References")]
     public LayerMask groundMask;
     public Transform cameraController;
     public Transform playerCamera;
     public TextMeshProUGUI fpsCounter;
     
     [Header("Movement Settings")]
     public float groundAccelerate;
     public float airAccelerate;
     public float groundSpeed;
     public float airSpeed;
     public float maxSpeed;
     public float friction;
     public Vector3 gravity;
     public float jumpHeight;
     
     [Header("Player Settings")]
     public float crouchHeight;
     public float crouchDuration;
     public float mouseSensitivity;
     public float skinWidth;
     public float skinPadding;
 
     [Header("Camera Settings")]
     public float bobSpeed;
     public float bobMagnitudeX;
     public float bobMagnitudeY;
     public float bobResetSpeed;
     public float breathingSpeed;
     public float breathingMagnitude;
     public float swayMagnitude;
 
     new Rigidbody rigidbody;
     new CapsuleCollider collider;
 
     RaycastHit hit;
     
     Vector3 defaultGravity;
     Vector3 wishdir;
     Vector3 cameraRotation;
     Vector3 cameraOffset;
     Vector3 bob;
     Vector3 breathing;
     Vector3 sway;
     Vector3 stretch;
     Vector3 shakePosition;
     Vector3 shakeRotation;
 
     float defaultHeight;
     float crouchOffset;
     float bobTime;
     float breathingTime;
     float maxAirSpeed;
     float airTime;
 
     bool grounded;
     bool wishjump = false;
     bool wishcrouch = false;
     bool crouching = false;
     bool justAirborne = false;
     bool justGrounded = true;
     bool onSlope = false;
     bool dead = false;
 
     // ==================== UNITY METHODS ====================
     
     void Awake()
     {
         Instance = this;
         
         rigidbody = GetComponent<Rigidbody>();
         collider = GetComponent<CapsuleCollider>();
 
         defaultHeight = collider.height;
         crouchOffset = crouchHeight - defaultHeight;
         defaultGravity = gravity;
         cameraRotation = cameraController.rotation.eulerAngles;
 
         Cursor.lockState = CursorLockMode.Locked;
     }
 
     void Update()
     {
         CheckGround();
         GetInput();
         CameraMotion();
         ShowFPSCounter();
     }
 
     void FixedUpdate()
     {
         if (grounded)
         {
             Accelerate(wishdir, crouching ? groundSpeed / 2f : groundSpeed, groundAccelerate);
 
             if (Input.GetKey(KeyCode.Space))
             {
                 rigidbody.velocity = new Vector3(rigidbody.velocity.x, 0f, rigidbody.velocity.z);
                 rigidbody.AddForce(Vector3.up * Mathf.Sqrt(jumpHeight * 2f * -defaultGravity.y), ForceMode.VelocityChange);
                 wishjump = false;
             }
             else
             {
                 ApplyFriction();
             }
         }
         else
         {
             Accelerate(wishdir, airSpeed, airAccelerate);
             rigidbody.AddForce(gravity * Time.fixedDeltaTime, ForceMode.VelocityChange);
         }
     }
 
     void OnTriggerEnter(Collider other)
     {
         SlidingDoor slidingDoor = other.GetComponent<SlidingDoor>();
         if (slidingDoor != null) StartCoroutine(slidingDoor.Open());
     }
 
     // ==================== MOVEMENT METHODS ====================
 
     void Accelerate(Vector3 wishdir, float wishspeed, float accel)
     {
         float addspeed, accelspeed, currentspeed;
 
         currentspeed = Vector3.Dot(rigidbody.velocity, wishdir);
         addspeed = wishspeed - currentspeed;
 
         if (addspeed <= 0) return;
 
         accelspeed = accel * Time.deltaTime;
         if (accelspeed > addspeed) accelspeed = addspeed;
 
         rigidbody.AddForce(accelspeed * wishdir, ForceMode.VelocityChange);
 
         if (grounded) return;
         
         Vector3 horizontal = new Vector3(rigidbody.velocity.x, 0f, rigidbody.velocity.z);
         if (horizontal.magnitude > maxSpeed)
         {
             horizontal *= maxSpeed / horizontal.magnitude;
             rigidbody.velocity = new Vector3(horizontal.x, rigidbody.velocity.y, horizontal.z);
         }
     }
 
     void ApplyFriction()
     {
         float speed = rigidbody.velocity.magnitude;
 
         if (speed == 0) return;
 
         float drop = friction * Time.deltaTime;
         float newSpeed = speed - drop;
 
         if (newSpeed < 0) newSpeed = 0;
 
         rigidbody.velocity *= newSpeed / speed;
     }
 
     public void Explode(Vector3 point, float force)
     {
         rigidbody.AddExplosionForce(force, point, 4f, 1f, ForceMode.VelocityChange);
     }
 
     IEnumerator QueueCrouch()
     {
         wishcrouch = true;
         yield return new WaitForSeconds(0.1f);
         wishcrouch = false;
     }
 
     IEnumerator Crouch()
     {
         wishcrouch = false;
         crouching = true;
         collider.height = crouchHeight;
         collider.center = new Vector3(0f, (crouchHeight - defaultHeight) / 2f, 0f);
 
         float timePassed = 0f;
         while (timePassed < crouchDuration)
         {
             float t = timePassed / crouchDuration;
             t = t * t * (3f - 2f * t);
             cameraOffset.y = Mathf.Lerp(0f, crouchOffset, t);
 
             timePassed += Time.deltaTime;
             yield return null;
         }
 
         cameraOffset.y = crouchOffset;
     }
 
     IEnumerator Uncrouch()
     {
         crouching = false;
         collider.height = defaultHeight;
         collider.center = Vector3.zero;
 
         float timePassed = 0f;
         while (timePassed < crouchDuration)
         {
             float t = timePassed / crouchDuration;
             t = t * t * (3f - 2f * t);
             cameraOffset.y = Mathf.Lerp(crouchOffset, 0f, t);
 
             timePassed += Time.deltaTime;
             yield return null;
         }
 
         cameraOffset.y = 0f;
     }
 
     // ==================== MISCELLANEOUS ====================
 
     void CheckGround()
     {
         grounded = Physics.SphereCast(collider.bounds.center + Vector3.down * (collider.height / 2f - collider.radius), collider.radius - skinWidth * 2f, Vector3.down, out hit, skinWidth + skinPadding, groundMask);
 
         if (grounded)
         {
             float angle = Vector3.Angle(hit.normal, Vector3.up);
 
             if (angle > 45f)
             {
                 grounded = false;
                 onSlope = false;
             }
             else if (angle != 0f)
             {
                 onSlope = true;
             }
             else
             {
                 onSlope = false;
             }
         }
 
         if (grounded)
         {
             justGrounded = true;
 
             if (justAirborne)
             {
                 justAirborne = false;
 
                 if (airTime > 0.25f)
                 {
                     StartCoroutine(StretchCamera(0.4f, Vector3.down, 0.25f));
                 }
             }
 
             // gravity = onSlope ? hit.normal * -6000f : defaultGravity;
         }
         else
         {
             justAirborne = true;
 
             if (justGrounded)
             {
                 justGrounded = false;
                 airTime = 0f;
             }
 
             // gravity = defaultGravity;
 
             airTime += Time.deltaTime;
         }
     }
     
     void GetInput()
     {
         cameraRotation += new Vector3(-Input.GetAxisRaw("Mouse Y") * mouseSensitivity * Time.deltaTime, Input.GetAxisRaw("Mouse X") * mouseSensitivity * Time.deltaTime, 0f);
         cameraRotation.x = Mathf.Clamp(cameraRotation.x, -90f, 90f);
         Vector3 horizontal = new Vector3(0f, cameraRotation.y, 0f);
         transform.rotation = Quaternion.Euler(horizontal);
         cameraController.rotation = Quaternion.Euler(cameraRotation);
 
         wishdir = transform.right * Input.GetAxisRaw("Horizontal") + transform.forward * Input.GetAxisRaw("Vertical");
         wishdir.Normalize();
 
         if (Input.GetKeyDown(KeyCode.LeftShift) && !crouching)
         {
             StartCoroutine(QueueCrouch());
         }
 
         if (wishcrouch && grounded) StartCoroutine(Crouch());
         
         if ((Input.GetKeyDown(KeyCode.Space) || Input.GetKeyUp(KeyCode.LeftShift)) && crouching)
         {
             StartCoroutine(Uncrouch());
         }
 
         if (Input.GetKeyDown(KeyCode.T)) StartCoroutine(ShakeCamera(1f, 10f, 1.3f, 1f));
     }
 
     // ==================== CAMERA MOTION ====================
 
     void CameraMotion()
     {
         if (grounded) breathingTime += Time.deltaTime;
 
         if (grounded && !crouching && rigidbody.velocity.magnitude > 1f)
         {
             bobTime += bobSpeed * Time.deltaTime;
         }
         else
         {
             int bobs = (int)(bobTime / Mathf.PI + 0.4999f);
 
             float targetbobTime = bobs * Mathf.PI;
             bobTime = Mathf.Lerp(bobTime, targetbobTime, bobResetSpeed * Time.deltaTime);
         }
 
         bob.x = -Mathf.Cos(bobTime) * bobMagnitudeX;
         bob.y = Mathf.Sin(bobTime * 2f) * bobMagnitudeY;
         breathing = new Vector3(Mathf.PerlinNoise(breathingTime * breathingSpeed, 0f) * 2f - 1, Mathf.PerlinNoise(0f, breathingTime * breathingSpeed) * 2f - 1, 0f) * breathingMagnitude;
         sway.z = -transform.InverseTransformPoint(rigidbody.velocity).x * swayMagnitude;
 
         playerCamera.localPosition = bob + stretch + shakePosition;
         playerCamera.localRotation = Quaternion.Euler(breathing + sway + shakeRotation);
         cameraController.position = transform.position + Vector3.up * 0.5f + cameraOffset;
     }
 
     IEnumerator StretchCamera(float duration, Vector3 direction, float distance)
     {
         float timePassed = 0f;
 
         while (timePassed < duration)
         {
             stretch = direction * Mathf.Sin(timePassed / duration * Mathf.PI) * distance;
 
             timePassed += Time.deltaTime;
             yield return null;
         }
         
         stretch = Vector3.zero;
     }
 
     IEnumerator ShakeCamera(float duration, float speed, float positionalMagnitude, float rotationalMagnitude)
     {
         float timePassed = 0f;
         float pmag = positionalMagnitude;
         float rmag = rotationalMagnitude;
         
         while (timePassed < duration)
         {
             shakePosition = new Vector3(Mathf.PerlinNoise(Time.time * speed, 0f) * 2f - 1, Mathf.PerlinNoise(0f, Time.time * speed) * 2f - 1, 0f) * pmag;
             shakeRotation = new Vector3(Mathf.PerlinNoise(Time.time * speed, 0f) * 2f - 1, Mathf.PerlinNoise(0f, Time.time * speed) * 2f - 1, 0f) * rmag;
 
             pmag = positionalMagnitude * (duration - timePassed);
             rmag = rotationalMagnitude * (duration - timePassed);
 
             timePassed += Time.deltaTime;
             yield return null;
         }
 
         shakePosition = Vector3.zero;
         shakeRotation = Vector3.zero;
     }
 
     // ==================== OTHER ====================
 
     void ShowFPSCounter()
     {
         fpsCounter.text = (int)(1f / Time.deltaTime) + "";
     }
 }

And here are my rigidbody settings: alt text

EDIT: After discussing with people on other forums, I have discovered that the issue was that I was setting the transform.rotation of the object with the rigidbody on it. I wanted the player's capsule to face the camera, but setting the rotation of the rigidbody directly like this interrupted its interpolation and caused the jitter. The solution I found was to create a child of the player which had the actual visible mesh, while the main object kept the script, capsule collider, and rigidbody. Then I set the camera to be a child of the mesh, and voila, everything works!

rigidbody-settings.png (16.7 kB)
Comment
Add comment
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.

Follow this Question

Answers Answers and Comments

185 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 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 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 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 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 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 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 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 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

Gfx.waitForPresent causing massive lag spikes in editor 8 Answers

Cloth disappears (occludes?) in scene view when zoomed in too far. Is there a fix? 2 Answers

Slow Motion Physics Lag Spikes 0 Answers

Moving kinematic rigidbody causing strange physics behaviour, is this a bug? 0 Answers

Box Collider on Spring Joint Randomly Stops Working in Editor and Builds 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