unity中,实现摄像机绕物体a旋转和俯仰角控制
·
应用场景:共三个物体,a是飞行物体,b是固定物体,c是摄像机,需要实现a飞行过程中,c可以动态移动位置(改变位置和旋转),使得始终可以拍到物体a和b(除极端情况)
思路:计算a飞行过程中,在xz平面中相对于物体b的旋转角angle,在xz平面上的俯仰角x,使得物体c也相对b有旋转角angle,自身俯仰角调整x度
using UnityEngine;
public class CameraController : MonoBehaviour
{
[Header("物体b位置")]
public Transform attackTrans;
[Header("物体a")]
public Transform targetTrans;
private Camera _camera;
private bool _isView = false;//记录a是否被看见,当a进入视野,才开始打击和摄像机跟踪
private bool _isTrack = false;//记录是否开启摄像机跟踪,开启条件是viewPos==0.7
private Vector3 _line1;//b和a的上一帧向量
private Vector3 _prevVector;
private float _currentPitch; // 当前俯仰角度值
// Start is called once before the first execution of Update after the MonoBehaviour is created
void Start()
{
_camera = this.GetComponent<Camera>();
}
// Update is called once per frame
void Update()
{
if(attackTrans != null)
{
Vector3 viewPos = _camera.WorldToViewportPoint(attackTrans.position);
//Debug.Log($"viewPos:{viewPos}");
if (_isView == false)
{
if ((viewPos.x > 0 && viewPos.x < 1) || (viewPos.y > 0 && viewPos.y < 1) || (viewPos.z > 0 && viewPos.z < 1))
_isView = true;
}
else
{
//当a被看见后才判断是否需要摄像机跟踪
if(_isTrack == false)
{
_isTrack = true;
_prevVector = GetXZVector(targetTrans.position - attackTrans.position);
_line1 = targetTrans.position - attackTrans.position;
_currentPitch = this.transform.eulerAngles.x;
}
else
{
Track();
}
}
}
}
/// <summary>
/// 摄像机跟踪目标
/// </summary>
void Track()
{
//计算摄像机绕b旋转
// 1. 计算当前a相对于b的向量(XZ平面)
Vector3 currentVector = GetXZVector(targetTrans.position - attackTrans.position);
// 2. 计算a绕b在XZ平面的旋转角度
float rotationAngle = Vector3.SignedAngle(_prevVector, currentVector, Vector3.up);
// 3. 若存在有效旋转,则让摄像机绕b旋转相同角度
if (Mathf.Abs(rotationAngle) > 0.001f)
{
// 核心:绕b旋转摄像机(同时更新位置和朝向)
this.transform.RotateAround(attackTrans.position, Vector3.up, rotationAngle);
}
// 4. 更新上一帧向量
_prevVector = currentVector;
//计算摄像机的俯仰角
Vector3 line2 = targetTrans.position - attackTrans.position;
//计算在a绕b在YZ面上的旋转向量
Vector3 line1YZ = new Vector3(0, _line1.y, _line1.z).normalized;
Vector3 line2YZ = new Vector3(0, line2.y, line2.z).normalized;
// 计算俯仰角度变化量(绕X轴旋转)
float pitchDelta = Vector3.SignedAngle(line1YZ, line2YZ, Vector3.right);
// 更新并限制俯仰角度范围
_currentPitch += pitchDelta;
_currentPitch = Mathf.Clamp(_currentPitch, -45f, 10f); // 限制俯仰角范围
Debug.Log($"pitchDelta:{pitchDelta}");
// 应用俯仰旋转(只修改X轴)
Vector3 euler = transform.eulerAngles;
euler.x = _currentPitch;
transform.eulerAngles = euler;
_line1 = line2;
}
// 辅助方法:提取XZ平面向量(忽略Y轴)
private Vector3 GetXZVector(Vector3 vec)
{
return new Vector3(vec.x, 0, vec.z).normalized;//为什么要标准化
}
}
更多推荐

所有评论(0)