这是关于在 Unity 中让一个对象朝向另一个对象的两个教程中的第一个。在本教程中,我们将学习如何让监控摄像机的 3D 模型自动朝向 Player,并在场景中跟随其移动。


本教程不提供中文配音。您可以在下方观看英语配音的视频,并选择中文、英文或其他语言的字幕。视频下方提供了翻译成中文的文字稿。


视频文字稿

大家好!

这是关于在 Unity 中让一个对象朝向另一个对象的两个教程中的第一个。在本教程中,我们将学习如何让监控摄像机的 3D 模型自动朝向 Player,并在场景中跟随其移动。

本教程使用 Unity 2022 制作,分为两个部分。

在第一部分中,我们将分析问题,并使用 Rotate 方法实现摄像机的即时旋转。

在第二部分中,我们将使用 四元数 和 Slerp 方法,实现更加平滑和渐进的旋转效果。

在进入实现之前,先分析一下要解决的问题。

摄像机只能围绕其 本地 垂直轴旋转,因此我们可以将问题简化为二维平面问题。为了更清楚地说明这一点,我将场景切换到 TOP 视角,并使用 Orthogonal 模式。

监控摄像机的 3D 模型和 Player 一样,都具有 XYZ Position 坐标,用于标识它们在场景中的位置。

我们不关心 position.y 坐标,因为摄像机只能围绕该 本地 轴旋转。因此我们只考虑 x 和 z 坐标,就好像两个对象位于同一个平面,并且具有相同的 y 值。

此外,在本例中,我们可以将监控摄像机视为参考系的原点,也就是笛卡尔坐标系中的 0,0 点。

不仅如此,我们还可以将摄像机当前朝向的方向,在本例中为其 负的 LOCAL Y 轴,视为笛卡尔坐标系中的一条坐标轴。

接下来,我们可以确定连接虚拟摄像机与 Player 在场景中位置的方向。这本质上是一个向量,在这里我们同样只在二维中考虑它,也就是 GLOBAL X 和 Z。

因此,我们要对监控摄像机应用的旋转角度,就是该资源当前朝向,也就是它的负本地 Y 轴,与连接监控摄像机和 Player 的理想向量之间的夹角。找到这个角度后,我们就得到了需要围绕其本地垂直轴应用到 3D 模型上的旋转量。

幸运的是,有一个数学函数叫做双参数反正切函数,在 Mathf 中通过 Atan2 方法实现。它可以根据方向向量,也就是两个点坐标之差,精确计算这个角度。

具体来说,Atan2 计算的是笛卡尔平面中 X 轴与从原点指向目标点的方向向量之间的夹角。

在我们的例子中,原点是监控摄像机 3D 模型的 X 和 Z 坐标,因此目标坐标 x 和 y 将由监控摄像机与 Player 之间的坐标差值给出,而 X 轴则对应于监控摄像机的负本地 Y 轴。

函数的两个参数顺序是反的。在笛卡尔平面中,我们写作 atan2(y, x)。在本例中,考虑 Unity 的坐标系统,其中 x 轴是左右方向,z 轴是前后方向,y 轴是垂直方向,在这里不参与计算,因此我们将写作 atan2(x, z)。

Unity 的在线文档指出,Mathf.Atan2 接收 y 和 x 坐标,在我们的例子中分别对应 x 和 z,并返回一个 float 类型的值,表示其正切为 y/x 的弧度角。

Unity 中的 Rotate 函数需要使用 角度制,因此在编写代码时,我们需要注意单位的不同,并进行必要的弧度到角度的转换。

现在我们已经分析了问题及其解决方案,接下来进入第一个实现:使用 Rotate 实现即时旋转。

首先,新建一个名为 LookAtObject 的 C# 脚本,并将其关联到实际的监控摄像机对象上。我之所以说“实际的监控摄像机”,是因为这个资源实际上由三个元素组成:固定在墙上的底座,一个 pivot 元素,以及摄像机本体。

我们希望摄像机围绕它自己的垂直轴旋转,也就是围绕它的 本地 垂直轴。

在 Unity 的虚拟世界中,全局垂直轴是 y 轴,但每个对象都有自己的 本地 坐标系。在这个监控摄像机 3D 模型中,本地垂直轴实际上是 LOCAL Z 轴。通过在 Unity 编辑器中切换到 LOCAL 显示模式可以看到这一点。

这个区别为项目增加了一点复杂性。我们需要在场景的全局平面上,使用对象的 X 和 Z 坐标计算旋转角度,然后围绕资源的本地垂直轴执行旋转。

首先,创建一个要跟随对象的引用。创建一个名为 objectA 的 Transform 变量,并在 Inspector 中将其关联到 Player。

[SerializeField] private Transform objectA;

完成之后,进入 Update 方法,实现之前讨论的解决方案。提醒一下,摄像机的 本地 垂直轴是它的 Z 轴。

我们只需要三行代码。

第一行,用于计算摄像机当前朝向与目标朝向之间的角度差,也就是它需要指向目标对象所需的角度。

第二行,计算需要围绕摄像机本地 Z 轴执行的旋转角度。

第三行,使用 Rotate 方法执行实际旋转。该方法需要两个参数:本地垂直向量,以及围绕该向量旋转的角度值。

首先计算摄像机当前朝向与目标朝向之间的角度,使用 Mathf 的 Atan2 函数。该函数返回弧度值,我们需要将其转换为角度。

我们已经知道,在二维平面中,Atan2 接收两个参数:目标点与观察者之间 Y 坐标的差值,以及 X 坐标的差值。

在本例中,使用 Unity 的全局坐标系统,其中 X 和 Z 构成二维平面,而 GLOBAL Y 表示场景的垂直轴,因此我们需要写成:

float theta = Mathf.Atan2((objectA.transform.position.x - transform.position.x), (objectA.transform.position.z - transform.position.z)) * Mathf.Rad2Deg;

这样我们就完成了角度的计算与单位转换。

接下来进行第二步,计算需要执行的旋转角度,单位为度。可以使用:

float deltaAngle = Mathf.DeltaAngle(transform.eulerAngles.z, theta);

其中 transform.eulerAngles.z 表示监控摄像机当前的朝向角度,而 theta 表示它应该达到的目标朝向角度。

第三行代码执行旋转:

transform.Rotate(Vector3.forward, deltaAngle);

注意,这里使用的是 Vector3.forward,它表示对象的 本地 Z 轴。之所以这样做,是因为在这个 3D 模型中,本地 Z 轴并不是表示前后方向,而是表示对象的本地垂直轴。

保存脚本,切换回 Unity 编辑器,点击 Play 查看最终效果。

注意,如果发现监控摄像机没有正确指向目标,请在 Inspector 中检查其初始 XYZ Rotation 是否全部设置为 0,然后再次尝试。

总结一下:在本教程的第一部分中,我们分析了问题,并学习了如何将两个对象视为位于同一平面,如何计算方向向量,以及如何将其应用到监控摄像机的具体情况中,同时考虑其本地参考系。

随后,我们使用 Rotate 函数,在游戏的每一帧中对对象进行即时旋转,使其始终指向 Player。

在下一部分中,我们将学习如何计算旋转四元数,并使用 Slerp 函数让对象以更缓慢、更平滑的方式进行旋转。

搜索教程

输入短语,或输入多个用逗号分隔的关键词进行搜索。

本站提供 Francesco Milanese 制作的 3D 模型、教程及计算机图形相关资源。3D 模型的使用许可可通过各模型页面上的链接前往第三方商店购买,并须遵守适用的许可条款。 Francesco Milanese — 意大利增值税号:06321250877。 联系方式:info@francescomilanese.com


高级隐私策略信息和cookie文件的使用