没有 rolling/banking 的 Unity 相机 Quaternion.RotateTowards
Unity Camera Quaternion.RotateTowards without rolling/banking
我有一个面向地面的相机,我想向上平移以查看远处的目标 object。
目前,我通过以下方式实现了这一点:
Vector3 dir = targetPoint - transform.position;
Quaternion lookRotation = Quaternion.LookRotation(dir);
Quaternion newRotation = Quaternion.RotateTowards(transform.rotation, lookRotation, rotationDamping * Time.deltaTime);
transform.rotation = newRotation;
相机执行旋转并最终正确指向目标 object,但当相机向上平移时它会向一侧倾斜,使我的游戏世界与观看者成一定角度,这很漂亮迷失方向:
如何以某种方式限制相机角度,使 horizon 始终与相机保持平直?
谢谢!
更新
添加下面@Isaac 建议的行会产生相对于 horizon 的正确旋转,但它在开始时突然捕捉到 z=0,这仍然不是我正在寻找的。
transform.localEulerAngles = new Vector3 (transform.localEulerAngles.x, transform.localEulerAngles.y, 0);
经过实验,我根据您的需要找到了 2 种可能的解决方案。
如果您只是想跟随目标,我建议您使用 LookAt
,它会自动与世界对齐。在您的代码中(在更新中)transform.LookAt(dir);
.
如果 need/want 平移效果在更新旋转后设置 localEulerAngles。这就是我所做的工作:
//this is your code
Vector3 dir = targetPoint - transform.position;
Quaternion lookRotation = Quaternion.LookRotation(dir);
Quaternion newRotation = Quaternion.RotateTowards(transform.rotation, lookRotation, rotationDamping * Time.deltaTime);
transform.rotation = newRotation;
//this is what I added
transform.localEulerAngles = new Vector3 (transform.localEulerAngles.x, transform.localEulerAngles.y, 0);
在使用四元数更新旋转并将 z 旋转设置为零后,添加简单地采用相机所面对的方式。
如果您有任何问题,请告诉我:)
////////////////////////////////////////// //////////////////////////////////////////////// /////////////////////////////////////////////////
新 information/edits:
我相信我已经找到了解决方案,但它很丑陋,我希望得到有关它是否卡顿等方面的反馈。
此代码与以前基本相同,但现在它会检查 z 角度并使用我称为 zDamping
的变量更手动地对其进行编辑,该变量会影响相机围绕 z 旋转的速度仅限访问。
我在更新之外添加了:
public float zDamping; //public only for testing, it's convenient for finding an optimal value
private bool rotationCheck = false;
然后在里面 update()
:
//This is your code (unchanged)
Vector3 targetPoint = target.transform.position;
Vector3 dir = targetPoint - transform.position;
Quaternion lookRotation = Quaternion.LookRotation (dir);
Quaternion newRotation = Quaternion.RotateTowards (transform.rotation, lookRotation, rotationDamping * Time.deltaTime);
//This is what is new (remove my addition from before edits or it won't work)
if (transform.localEulerAngles.z >= 180f && transform.localEulerAngles.z <= 359f && !rotationCheck) {
transform.localEulerAngles = new Vector3 (transform.localEulerAngles.x, transform.localEulerAngles.y, transform.localEulerAngles.z + (rotationDamping * zDamping));
transform.rotation = newRotation;
}
else if (transform.localEulerAngles.z <= -180f && transform.localEulerAngles.z >= 1f && !rotationCheck) {
transform.localEulerAngles = new Vector3 (transform.localEulerAngles.x, transform.localEulerAngles.y, transform.localEulerAngles.z - (rotationDamping * zDamping));
transform.rotation = newRotation;
}
else {
transform.rotation = newRotation;
transform.localEulerAngles = new Vector3 (transform.localEulerAngles.x, transform.localEulerAngles.y, 0);
rotationCheck = true;
}
正如我所说,这个解决方案非常丑陋,但它可能会奏效。您必须查看哪些 zDamping
值能让您的速度看起来自然(我建议从 .01 开始)。一旦你接近该值,也会有一个小的 "jump",但是你越接近 359f
到 360 和 1f
到 0,跳跃就会越小。将它设置得太小的危险是如果你过冲,但即使它过冲它也应该工作,但它会花费少量时间。
测试一下,让我知道你的想法,抱歉,我现在找不到更优雅的东西。我还尝试添加一个单独的四元数来专门旋转 z 轴,但它没有用;随意尝试一下,如果你愿意,我可以提供更多关于我所做的细节。
再次祝你好运,对于草率的解决方案感到抱歉。
有一篇关于这个主题的优秀文章Q/A on gamedev.stackexchange。您应该尝试那里建议的 pitch/yaw 系统。
另一个建议是在旋转过程中校正相机的滚动。
public float rollCorrectionSpeed;
public void Update()
{
float roll = Vector3.Dot(transform.right, Vector3.up);
transform.Rotate(0, 0, -roll * rollCorrectionSpeed);
Vector3 dir = targetPoint.position - transform.position;
Quaternion lookRotation = Quaternion.LookRotation(dir);
Quaternion newRotation = Quaternion.RotateTowards(transform.rotation, lookRotation, rotationDamping * Time.deltaTime);
transform.rotation = newRotation;
}
编辑:
有一个更简单的解决方案:只需将要旋转的四元数的 z
旋转保持为 0。
public void Update()
{
Vector3 angles = transform.rotation.eulerAngles;
Quaternion from = Quaternion.Euler(angles.x, angles.y, 0);
Vector3 dir = targetPoint.position - transform.position;
Quaternion to = Quaternion.LookRotation(dir);
transform.rotation = Quaternion.RotateTowards(from, to, rotationDamping * Time.deltaTime);
}
在您的行中添加了代码,希望它能解决问题。
Vector3 dir = targetPoint - transform.position;
Quaternion lookRotation = Quaternion.LookRotation(dir);
Quaternion newRotation = Quaternion.RotateTowards(transform.rotation, lookRotation, rotationDamping * Time.deltaTime);
newRotation.eulerAngles = new Vector3(newRotation.eulerAngles.x,newRotation.eulerAngles.y,transform.rotation.eulerAngles.z);
transform.rotation = newRotation;
我有一个面向地面的相机,我想向上平移以查看远处的目标 object。
目前,我通过以下方式实现了这一点:
Vector3 dir = targetPoint - transform.position;
Quaternion lookRotation = Quaternion.LookRotation(dir);
Quaternion newRotation = Quaternion.RotateTowards(transform.rotation, lookRotation, rotationDamping * Time.deltaTime);
transform.rotation = newRotation;
相机执行旋转并最终正确指向目标 object,但当相机向上平移时它会向一侧倾斜,使我的游戏世界与观看者成一定角度,这很漂亮迷失方向:
如何以某种方式限制相机角度,使 horizon 始终与相机保持平直?
谢谢!
更新
添加下面@Isaac 建议的行会产生相对于 horizon 的正确旋转,但它在开始时突然捕捉到 z=0,这仍然不是我正在寻找的。
transform.localEulerAngles = new Vector3 (transform.localEulerAngles.x, transform.localEulerAngles.y, 0);
经过实验,我根据您的需要找到了 2 种可能的解决方案。
如果您只是想跟随目标,我建议您使用 LookAt
,它会自动与世界对齐。在您的代码中(在更新中)transform.LookAt(dir);
.
如果 need/want 平移效果在更新旋转后设置 localEulerAngles。这就是我所做的工作:
//this is your code
Vector3 dir = targetPoint - transform.position;
Quaternion lookRotation = Quaternion.LookRotation(dir);
Quaternion newRotation = Quaternion.RotateTowards(transform.rotation, lookRotation, rotationDamping * Time.deltaTime);
transform.rotation = newRotation;
//this is what I added
transform.localEulerAngles = new Vector3 (transform.localEulerAngles.x, transform.localEulerAngles.y, 0);
在使用四元数更新旋转并将 z 旋转设置为零后,添加简单地采用相机所面对的方式。
如果您有任何问题,请告诉我:)
////////////////////////////////////////// //////////////////////////////////////////////// /////////////////////////////////////////////////
新 information/edits:
我相信我已经找到了解决方案,但它很丑陋,我希望得到有关它是否卡顿等方面的反馈。
此代码与以前基本相同,但现在它会检查 z 角度并使用我称为 zDamping
的变量更手动地对其进行编辑,该变量会影响相机围绕 z 旋转的速度仅限访问。
我在更新之外添加了:
public float zDamping; //public only for testing, it's convenient for finding an optimal value
private bool rotationCheck = false;
然后在里面 update()
:
//This is your code (unchanged)
Vector3 targetPoint = target.transform.position;
Vector3 dir = targetPoint - transform.position;
Quaternion lookRotation = Quaternion.LookRotation (dir);
Quaternion newRotation = Quaternion.RotateTowards (transform.rotation, lookRotation, rotationDamping * Time.deltaTime);
//This is what is new (remove my addition from before edits or it won't work)
if (transform.localEulerAngles.z >= 180f && transform.localEulerAngles.z <= 359f && !rotationCheck) {
transform.localEulerAngles = new Vector3 (transform.localEulerAngles.x, transform.localEulerAngles.y, transform.localEulerAngles.z + (rotationDamping * zDamping));
transform.rotation = newRotation;
}
else if (transform.localEulerAngles.z <= -180f && transform.localEulerAngles.z >= 1f && !rotationCheck) {
transform.localEulerAngles = new Vector3 (transform.localEulerAngles.x, transform.localEulerAngles.y, transform.localEulerAngles.z - (rotationDamping * zDamping));
transform.rotation = newRotation;
}
else {
transform.rotation = newRotation;
transform.localEulerAngles = new Vector3 (transform.localEulerAngles.x, transform.localEulerAngles.y, 0);
rotationCheck = true;
}
正如我所说,这个解决方案非常丑陋,但它可能会奏效。您必须查看哪些 zDamping
值能让您的速度看起来自然(我建议从 .01 开始)。一旦你接近该值,也会有一个小的 "jump",但是你越接近 359f
到 360 和 1f
到 0,跳跃就会越小。将它设置得太小的危险是如果你过冲,但即使它过冲它也应该工作,但它会花费少量时间。
测试一下,让我知道你的想法,抱歉,我现在找不到更优雅的东西。我还尝试添加一个单独的四元数来专门旋转 z 轴,但它没有用;随意尝试一下,如果你愿意,我可以提供更多关于我所做的细节。
再次祝你好运,对于草率的解决方案感到抱歉。
有一篇关于这个主题的优秀文章Q/A on gamedev.stackexchange。您应该尝试那里建议的 pitch/yaw 系统。
另一个建议是在旋转过程中校正相机的滚动。
public float rollCorrectionSpeed;
public void Update()
{
float roll = Vector3.Dot(transform.right, Vector3.up);
transform.Rotate(0, 0, -roll * rollCorrectionSpeed);
Vector3 dir = targetPoint.position - transform.position;
Quaternion lookRotation = Quaternion.LookRotation(dir);
Quaternion newRotation = Quaternion.RotateTowards(transform.rotation, lookRotation, rotationDamping * Time.deltaTime);
transform.rotation = newRotation;
}
编辑:
有一个更简单的解决方案:只需将要旋转的四元数的 z
旋转保持为 0。
public void Update()
{
Vector3 angles = transform.rotation.eulerAngles;
Quaternion from = Quaternion.Euler(angles.x, angles.y, 0);
Vector3 dir = targetPoint.position - transform.position;
Quaternion to = Quaternion.LookRotation(dir);
transform.rotation = Quaternion.RotateTowards(from, to, rotationDamping * Time.deltaTime);
}
在您的行中添加了代码,希望它能解决问题。
Vector3 dir = targetPoint - transform.position;
Quaternion lookRotation = Quaternion.LookRotation(dir);
Quaternion newRotation = Quaternion.RotateTowards(transform.rotation, lookRotation, rotationDamping * Time.deltaTime);
newRotation.eulerAngles = new Vector3(newRotation.eulerAngles.x,newRotation.eulerAngles.y,transform.rotation.eulerAngles.z);
transform.rotation = newRotation;