Anonymous
CameraRig смещается в неправильное положение при переключении с вида от первого лица на вид от третьего после движения
Сообщение
Anonymous » 17 ноя 2025, 00:07
Код: Выделить всё
using System.Collections;
using Unity.Mathematics;
using Unity.Mathematics.Geometry;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.UIElements;
public class CameraController : MonoBehaviour
{
PlayerStats playerStats;
CharacterRagdollController characterRagdollController;
[SerializeField]
private Transform target; // right eye of character
[SerializeField]
private Camera TPCamera;
[SerializeField]
private Camera FPCamera;
[SerializeField]
private Transform CameraRig;
private Camera enabledCamera;
public Camera EnabledCamera =\> enabledCamera;
private new Renderer[] renderer;
private Color[] color;
private MaterialPropertyBlock propBlock;
private static readonly int colorPropertyID = Shader.PropertyToID("\_BaseColor");
[SerializeField]
private float FPFOV = 60;
[SerializeField]
private float FOVChangeSpeed = 5f;
[SerializeField]
private float cameraPositionSmoothSpeed = 10f;
[SerializeField]
private Vector3 TPOffset = new Vector3(0, 0, -6);
[SerializeField]
private Vector3 FPOffset = new Vector3(0, 0.4f, 0);
[SerializeField]
private float sensitivity = 3f;
[SerializeField]
private float minYAngle = -85f;
[SerializeField]
private float maxYAngle = 85f;
[SerializeField]
private float cameraCollisionBuffer = 0.2f;
private float currentX = 0f;
private float currentY = 20f;
Vector3 lastLookTarget;
private bool scopeMode;
public bool ScopeMode =\> scopeMode;
[SerializeField]
private GameObject crosshairUI;
[SerializeField]
private GameObject scopeUI;
private PlayerController playerController;
[SerializeField]
private LayerMask layerMask;
[SerializeField]
private LayerMask playerLayerMask;
RaycastHit hit;
float distance;
Vector3 aimPoint;
private void Awake()
{
playerStats = GetComponent\
();
characterRagdollController = GetComponent\();
propBlock = new MaterialPropertyBlock();
TPCamera.fieldOfView = playerStats.baseFOV;
FPCamera.fieldOfView = FPFOV;
playerController = GetComponent\();
renderer = GetComponentsInChildren\();
color = new Color[renderer.Length];
for (int i = 0; i \< renderer.Length; i++)
{
if (renderer[i].material.HasProperty(colorPropertyID))
{
color[i] = renderer[i].material.color;
}
else
{
color[i] = Color.white;
}
}
TPCamera.depth = 1;
FPCamera.depth = 0;
scopeUI.SetActive(false);
enabledCamera = TPCamera;
}
void LateUpdate()
{
if (Input.GetMouseButtonDown(1))
{
EnterScopeMode();
}
if (Input.GetMouseButtonUp(1))
{
ExitScopeMode();
}
HandleCameraRotation();
HandleCameraRigPosition();
if (!scopeMode)
{
UpdateThirdPersonCameraPosition();
}
UpdateTPFOV();
}
private void EnterScopeMode()
{
lastLookTarget = GetAimPoint();
scopeMode = true;
scopeUI.SetActive(true);
crosshairUI.SetActive(false);
HandleFirstPersonCamera();
Vector3 direction = (lastLookTarget - CameraRig.position).normalized;
currentX = Mathf.Atan2(direction.x, direction.z) * Mathf.Rad2Deg;
currentY = -Mathf.Asin(direction.y) * Mathf.Rad2Deg;
CameraRig.rotation = Quaternion.Euler(currentY, currentX, 0f);
TPCamera.depth = 0;
FPCamera.depth = 1;
enabledCamera = FPCamera;
SetPlayerRenderers(false);
}
private void ExitScopeMode()
{
lastLookTarget = GetAimPoint();
scopeMode = false;
scopeUI.SetActive(false);
crosshairUI.SetActive(true);
CorrectAimAfterFPtoTP();
TPCamera.depth = 1;
FPCamera.depth = 0;
enabledCamera = TPCamera;
SetPlayerRenderers(true);
}
private void HandleCameraRotation()
{
currentX += Input.GetAxis("Mouse X") * sensitivity;
currentY -= Input.GetAxis("Mouse Y") * sensitivity;
currentY = Mathf.Clamp(currentY, minYAngle, maxYAngle);
CameraRig.rotation = Quaternion.Euler(currentY, currentX, 0f);
}
private void HandleFirstPersonCamera()
{
CameraRig.position = transform.position + FPOffset;
}
private void HandleCameraRigPosition()
{
if (scopeMode)
{
CameraRig.position = transform.position + FPOffset;
}
else if (playerController.DevMode)
{
CameraRig.position = target.position;
}
else
{
distance = (target.position - CameraRig.position).magnitude;
CameraRig.position = Vector3.MoveTowards(CameraRig.position, target.position, cameraPositionSmoothSpeed * Time.deltaTime * distance);
}
}
private void UpdateThirdPersonCameraPosition()
{
Vector3 desiredTPCamPosX = CameraRig.position + Quaternion.Euler(0, currentX, 0) * new Vector3(TPOffset.x + math.sign(TPOffset.x) * cameraCollisionBuffer, 0, 0);
if (Physics.Raycast(CameraRig.position, (desiredTPCamPosX - CameraRig.position).normalized, out hit, (desiredTPCamPosX - CameraRig.position).magnitude, layerMask))
{
desiredTPCamPosX = hit.point - (desiredTPCamPosX - CameraRig.position).normalized * cameraCollisionBuffer;
}
else
{
desiredTPCamPosX -= (desiredTPCamPosX - CameraRig.position).normalized * cameraCollisionBuffer;
}
Vector3 desiredTPCamPosXY = desiredTPCamPosX + Quaternion.Euler(0, currentX, 0) * new Vector3(0, TPOffset.y + math.sign(TPOffset.y) * cameraCollisionBuffer, 0);
if (Physics.Raycast(desiredTPCamPosX, (desiredTPCamPosXY - desiredTPCamPosX).normalized, out hit, (desiredTPCamPosXY - desiredTPCamPosX).magnitude, layerMask))
{
desiredTPCamPosXY = hit.point - (desiredTPCamPosXY - desiredTPCamPosX).normalized * cameraCollisionBuffer;
}
else
{
desiredTPCamPosXY -= (desiredTPCamPosXY - desiredTPCamPosX).normalized * cameraCollisionBuffer;
}
Vector3 desiredTPCamPosXYZ = desiredTPCamPosXY + Quaternion.Euler(currentY, currentX, 0) * new Vector3(0, 0, TPOffset.z + math.sign(TPOffset.z) * cameraCollisionBuffer);
if (Physics.Raycast(desiredTPCamPosXY, (desiredTPCamPosXYZ - desiredTPCamPosXY).normalized, out hit, (desiredTPCamPosXYZ - desiredTPCamPosXY).magnitude, layerMask))
{
desiredTPCamPosXYZ = hit.point - (desiredTPCamPosXYZ - desiredTPCamPosXY).normalized * cameraCollisionBuffer;
}
else
{
desiredTPCamPosXYZ -= (desiredTPCamPosXYZ - desiredTPCamPosXY).normalized * cameraCollisionBuffer;
}
TPCamera.transform.position = desiredTPCamPosXYZ;
}
private void SetPlayerRenderers(bool isEnabled)
{
for (int i = 0; i \< renderer.Length; i++)
{
renderer[i].enabled = isEnabled;
}
}
private float NormalizeAngle(float angle)
{
if (angle \> 180) angle -= 360f;
return angle;
}
public Vector3 GetAimPoint()
{
if (Physics.Raycast(enabledCamera.transform.position, enabledCamera.transform.forward, out hit, 1000, layerMask))
{
return hit.point;
}
else
{
return enabledCamera.transform.position + enabledCamera.transform.forward * 1000f;
}
}
private void CorrectAimAfterFPtoTP()
{
HandleCameraRigPosition();
for (int i = 0; i \< 10; i++)
{
UpdateThirdPersonCameraPosition();
Vector3 currentCameraDirection = TPCamera.transform.rotation * Vector3.forward;
Vector3 directionToTarget = (lastLookTarget - TPCamera.transform.position).normalized;
Quaternion errorRotation = Quaternion.FromToRotation(currentCameraDirection, directionToTarget);
CameraRig.rotation = errorRotation * CameraRig.rotation;
Vector3 direction = CameraRig.rotation * Vector3.forward;
currentX = Mathf.Atan2(direction.x, direction.z) * Mathf.Rad2Deg;
currentY = -Mathf.Asin(direction.y) * Mathf.Rad2Deg;
}
}
public void UpdateTPFOV()
{
if (playerStats.currentFOV != TPCamera.fieldOfView)
{
TPCamera.fieldOfView = Mathf.Lerp(TPCamera.fieldOfView, playerStats.currentFOV, FOVChangeSpeed * Time.deltaTime);
if (Mathf.Abs(playerStats.currentFOV - TPCamera.fieldOfView) \< 0.1f)
{
TPCamera.fieldOfView = playerStats.currentFOV;
}
}
}
}
Когда я перемещаю персонажа в режиме от первого лица (прицел), а затем переключаюсь обратно на вид от третьего лица, CameraRig фиксируется в странном положении далеко от персонажа. В результате коррекция прицеливания также не работает должным образом. Если персонаж стоит на месте, переключение между видом от первого и третьего лица работает совершенно нормально.
Подробнее здесь:
https://stackoverflow.com/questions/798 ... n-to-third
1763327250
Anonymous
[code]using System.Collections; using Unity.Mathematics; using Unity.Mathematics.Geometry; using Unity.VisualScripting; using UnityEngine; using UnityEngine.UIElements; public class CameraController : MonoBehaviour { PlayerStats playerStats; CharacterRagdollController characterRagdollController; [SerializeField] private Transform target; // right eye of character [SerializeField] private Camera TPCamera; [SerializeField] private Camera FPCamera; [SerializeField] private Transform CameraRig; private Camera enabledCamera; public Camera EnabledCamera =\> enabledCamera; private new Renderer[] renderer; private Color[] color; private MaterialPropertyBlock propBlock; private static readonly int colorPropertyID = Shader.PropertyToID("\_BaseColor"); [SerializeField] private float FPFOV = 60; [SerializeField] private float FOVChangeSpeed = 5f; [SerializeField] private float cameraPositionSmoothSpeed = 10f; [SerializeField] private Vector3 TPOffset = new Vector3(0, 0, -6); [SerializeField] private Vector3 FPOffset = new Vector3(0, 0.4f, 0); [SerializeField] private float sensitivity = 3f; [SerializeField] private float minYAngle = -85f; [SerializeField] private float maxYAngle = 85f; [SerializeField] private float cameraCollisionBuffer = 0.2f; private float currentX = 0f; private float currentY = 20f; Vector3 lastLookTarget; private bool scopeMode; public bool ScopeMode =\> scopeMode; [SerializeField] private GameObject crosshairUI; [SerializeField] private GameObject scopeUI; private PlayerController playerController; [SerializeField] private LayerMask layerMask; [SerializeField] private LayerMask playerLayerMask; RaycastHit hit; float distance; Vector3 aimPoint; private void Awake() { playerStats = GetComponent\ (); characterRagdollController = GetComponent\(); propBlock = new MaterialPropertyBlock(); TPCamera.fieldOfView = playerStats.baseFOV; FPCamera.fieldOfView = FPFOV; playerController = GetComponent\(); renderer = GetComponentsInChildren\(); color = new Color[renderer.Length]; for (int i = 0; i \< renderer.Length; i++) { if (renderer[i].material.HasProperty(colorPropertyID)) { color[i] = renderer[i].material.color; } else { color[i] = Color.white; } } TPCamera.depth = 1; FPCamera.depth = 0; scopeUI.SetActive(false); enabledCamera = TPCamera; } void LateUpdate() { if (Input.GetMouseButtonDown(1)) { EnterScopeMode(); } if (Input.GetMouseButtonUp(1)) { ExitScopeMode(); } HandleCameraRotation(); HandleCameraRigPosition(); if (!scopeMode) { UpdateThirdPersonCameraPosition(); } UpdateTPFOV(); } private void EnterScopeMode() { lastLookTarget = GetAimPoint(); scopeMode = true; scopeUI.SetActive(true); crosshairUI.SetActive(false); HandleFirstPersonCamera(); Vector3 direction = (lastLookTarget - CameraRig.position).normalized; currentX = Mathf.Atan2(direction.x, direction.z) * Mathf.Rad2Deg; currentY = -Mathf.Asin(direction.y) * Mathf.Rad2Deg; CameraRig.rotation = Quaternion.Euler(currentY, currentX, 0f); TPCamera.depth = 0; FPCamera.depth = 1; enabledCamera = FPCamera; SetPlayerRenderers(false); } private void ExitScopeMode() { lastLookTarget = GetAimPoint(); scopeMode = false; scopeUI.SetActive(false); crosshairUI.SetActive(true); CorrectAimAfterFPtoTP(); TPCamera.depth = 1; FPCamera.depth = 0; enabledCamera = TPCamera; SetPlayerRenderers(true); } private void HandleCameraRotation() { currentX += Input.GetAxis("Mouse X") * sensitivity; currentY -= Input.GetAxis("Mouse Y") * sensitivity; currentY = Mathf.Clamp(currentY, minYAngle, maxYAngle); CameraRig.rotation = Quaternion.Euler(currentY, currentX, 0f); } private void HandleFirstPersonCamera() { CameraRig.position = transform.position + FPOffset; } private void HandleCameraRigPosition() { if (scopeMode) { CameraRig.position = transform.position + FPOffset; } else if (playerController.DevMode) { CameraRig.position = target.position; } else { distance = (target.position - CameraRig.position).magnitude; CameraRig.position = Vector3.MoveTowards(CameraRig.position, target.position, cameraPositionSmoothSpeed * Time.deltaTime * distance); } } private void UpdateThirdPersonCameraPosition() { Vector3 desiredTPCamPosX = CameraRig.position + Quaternion.Euler(0, currentX, 0) * new Vector3(TPOffset.x + math.sign(TPOffset.x) * cameraCollisionBuffer, 0, 0); if (Physics.Raycast(CameraRig.position, (desiredTPCamPosX - CameraRig.position).normalized, out hit, (desiredTPCamPosX - CameraRig.position).magnitude, layerMask)) { desiredTPCamPosX = hit.point - (desiredTPCamPosX - CameraRig.position).normalized * cameraCollisionBuffer; } else { desiredTPCamPosX -= (desiredTPCamPosX - CameraRig.position).normalized * cameraCollisionBuffer; } Vector3 desiredTPCamPosXY = desiredTPCamPosX + Quaternion.Euler(0, currentX, 0) * new Vector3(0, TPOffset.y + math.sign(TPOffset.y) * cameraCollisionBuffer, 0); if (Physics.Raycast(desiredTPCamPosX, (desiredTPCamPosXY - desiredTPCamPosX).normalized, out hit, (desiredTPCamPosXY - desiredTPCamPosX).magnitude, layerMask)) { desiredTPCamPosXY = hit.point - (desiredTPCamPosXY - desiredTPCamPosX).normalized * cameraCollisionBuffer; } else { desiredTPCamPosXY -= (desiredTPCamPosXY - desiredTPCamPosX).normalized * cameraCollisionBuffer; } Vector3 desiredTPCamPosXYZ = desiredTPCamPosXY + Quaternion.Euler(currentY, currentX, 0) * new Vector3(0, 0, TPOffset.z + math.sign(TPOffset.z) * cameraCollisionBuffer); if (Physics.Raycast(desiredTPCamPosXY, (desiredTPCamPosXYZ - desiredTPCamPosXY).normalized, out hit, (desiredTPCamPosXYZ - desiredTPCamPosXY).magnitude, layerMask)) { desiredTPCamPosXYZ = hit.point - (desiredTPCamPosXYZ - desiredTPCamPosXY).normalized * cameraCollisionBuffer; } else { desiredTPCamPosXYZ -= (desiredTPCamPosXYZ - desiredTPCamPosXY).normalized * cameraCollisionBuffer; } TPCamera.transform.position = desiredTPCamPosXYZ; } private void SetPlayerRenderers(bool isEnabled) { for (int i = 0; i \< renderer.Length; i++) { renderer[i].enabled = isEnabled; } } private float NormalizeAngle(float angle) { if (angle \> 180) angle -= 360f; return angle; } public Vector3 GetAimPoint() { if (Physics.Raycast(enabledCamera.transform.position, enabledCamera.transform.forward, out hit, 1000, layerMask)) { return hit.point; } else { return enabledCamera.transform.position + enabledCamera.transform.forward * 1000f; } } private void CorrectAimAfterFPtoTP() { HandleCameraRigPosition(); for (int i = 0; i \< 10; i++) { UpdateThirdPersonCameraPosition(); Vector3 currentCameraDirection = TPCamera.transform.rotation * Vector3.forward; Vector3 directionToTarget = (lastLookTarget - TPCamera.transform.position).normalized; Quaternion errorRotation = Quaternion.FromToRotation(currentCameraDirection, directionToTarget); CameraRig.rotation = errorRotation * CameraRig.rotation; Vector3 direction = CameraRig.rotation * Vector3.forward; currentX = Mathf.Atan2(direction.x, direction.z) * Mathf.Rad2Deg; currentY = -Mathf.Asin(direction.y) * Mathf.Rad2Deg; } } public void UpdateTPFOV() { if (playerStats.currentFOV != TPCamera.fieldOfView) { TPCamera.fieldOfView = Mathf.Lerp(TPCamera.fieldOfView, playerStats.currentFOV, FOVChangeSpeed * Time.deltaTime); if (Mathf.Abs(playerStats.currentFOV - TPCamera.fieldOfView) \< 0.1f) { TPCamera.fieldOfView = playerStats.currentFOV; } } } } [/code] Когда я перемещаю персонажа в режиме от первого лица (прицел), а затем переключаюсь обратно на вид от третьего лица, CameraRig фиксируется в странном положении далеко от персонажа. В результате коррекция прицеливания также не работает должным образом. Если персонаж стоит на месте, переключение между видом от первого и третьего лица работает совершенно нормально. Подробнее здесь: [url]https://stackoverflow.com/questions/79821752/camerarig-shifts-to-incorrect-position-when-switching-from-first-person-to-third[/url]