摄像机在任何3D场景中都是至关重要的元素,尤其是在游戏和实时应用中。它定义了玩家和用户如何“看到”虚拟世界。Unity中的Camera类提供了一系列强大的工具,让开发者可以精细地控制渲染和视图。在本文中,我们将深入探索这个核心类的使用方式。
Camera.allCamerasCount
: 返回场景中当前存在的摄像机数量。
Camera.allCameras
: 返回场景中所有当前存在的摄像机的数组。
Camera.current
: 返回当前渲染中的摄像机。
Camera.main
: 返回标记为“MainCamera”的摄像机。
定义:
allCamerasCount 返回场景中当前存在的摄像机数量。
用途:
这个属性对于快速检查场景中摄像机的数量很有用,尤其是在某些摄像机可能在运行时被动态创建或销毁的场景。
示例:
int cameraCount = Camera.allCamerasCount;
Debug.Log("当前场景中的摄像机数量: " + cameraCount);
定义:
allCameras 返回场景中所有当前存在的摄像机的数组。
用途:
这个属性在你需要对场景中的所有摄像机进行迭代或操作时非常有用。
注意:
数组的长度由 allCamerasCount 决定。
为了提高性能和减少垃圾回收,Unity不会为你创建一个新的摄像机数组。你需要先创建一个足够大的摄像机数组,然后将其传递给此属性,以填充所有的摄像机。
示例:
Camera[] cameras = new Camera[Camera.allCamerasCount];
Camera.allCameras.CopyTo(cameras, 0);
for(int i = 0; i < cameras.Length; i++)
{
Debug.Log("摄像机名称: " + cameras[i].name);
}
这里首先创建了一个摄像机数组,大小为场景中摄像机的数量。然后使用 CopyTo 方法将所有的摄像机填充到我们的数组中。最后,我们迭代数组,打印出每个摄像机的名称。
在这个示例中,可以不用Camera.allCameras.CopyTo(cameras, 0),直接使用 cameras.Length,因为我们已经知道 cameras 数组的大小正好等于 Camera.allCamerasCount。
但在某些情境下,当你使用一个预先定义的、可能比实际摄像机数量大的数组时,知道实际填充了多少摄像机就很重要了。在这种情况下,使用返回的摄像机数量是有用的,以确保你只迭代了数组中实际存在的摄像机,避免出现null引用。
在大多数场景中,这是当前帧正在渲染的摄像机,但在执行某些特定的渲染函数(如 OnPreRender、OnPostRender)时,这是执行这些函数的摄像机。
用途: 在摄像机的特定渲染事件中,如 OnPreRender 和 OnPostRender,您可能需要知道哪个摄像机正在渲染,这时可以使用 Camera.current。
注意: 在大多数其他情况下,如果你尝试在常规的 Update() 或 Start() 函数中访问 Camera.current,它可能会返回 null,因为在这些函数中可能没有摄像机正在渲染。
示例:
void OnPostRender()
{
// 当某个摄像机完成渲染后,输出其名称
Debug.Log("刚刚完成渲染的摄像机: " + Camera.current.name);
}
总结,Camera.main 通常用于快速访问主摄像机,而 Camera.current 更多地用于特定的渲染上下文,以确定哪个摄像机正在进行渲染。
用途: 当您需要引用场景中的主摄像机时,Camera.main 是一个快捷方式。
注意事项: Camera.main 会查找带有 “MainCamera” 标签的摄像机,这会导致每次调用时都执行查找操作,这可能不是最高效的方式,特别是在频繁调用它的情况下。对于需要频繁访问主摄像机的情况,建议在初始化时缓存对该摄像机的引用。
示例:
// 获取主摄像机并设置其背景颜色为红色
Camera.main.backgroundColor = Color.red;
Camera.CalculateProjectionMatrixFromPhysicalProperties
: 为物理基础的摄像机制作投影矩阵
Camera.FieldOfViewToFocalLength
: 将摄像机的视场(FOV)转换为焦距。
Camera.FocalLengthToFieldOfView
: 将摄像机的焦距转换为视场。
Camera.HorizontalToVerticalFieldOfView
: 将水平视场转换为垂直视场。
Camera.VerticalToHorizontalFieldOfView
: 将垂直视场转换为水平视场。
Camera.GetAllCameras
: 返回场景中所有激活的摄像机。
Camera.SetupCurrent
: 用于设置当前的主摄像机。
定义:
public static void CalculateProjectionMatrixFromPhysicalProperties(out Matrix4x4 output, float focalLength, Vector2 sensorSize, Vector2 lensShift, float nearClip, float farClip, GateFitParameters gateFitParameters = default(GateFitParameters));
参数说明:
示例:
假设您正在为一个 AR 应用程序创建一个摄像机模型,并且您有关于该摄像机的物理属性的数据。您可以使用这些数据和 CalculateProjectionMatrixFromPhysicalProperties 方法来生成一个更准确的投影矩阵,如下所示:
Camera cam = GetComponent<Camera>();
float focalLength = 50f; // 50mm
Vector2 sensorSize = new Vector2(36, 24); // 35mm全画幅传感器
Vector2 lensShift = new Vector2(0, 0); // 无偏移
float nearClip = 0.1f;
float farClip = 1000f;
Matrix4x4 projMatrix;
Camera.CalculateProjectionMatrixFromPhysicalProperties(out projMatrix, focalLength, sensorSize, lensShift, nearClip, farClip);
cam.projectionMatrix = projMatrix;
在这个示例中,摄像机的投影矩阵现在是基于其物理属性,为特定应用提供了更真实的摄像机模拟。
当你深入摄影和计算机图形学时,焦距和视场(Field of View,简称FOV)之间的关系变得至关重要。它们之间的关系定义了摄像机如何看待世界。在Unity中,FieldOfViewToFocalLength
和 FocalLengthToFieldOfView
这两个方法就是为了转换这两个值。
定义:
public static extern float FieldOfViewToFocalLength(float fieldOfView, float sensorSize);
参数说明:
示例:
如果我们知道我们想要一个45度的视场,我们可以找出需要的焦距:
float desiredFOV = 45f;
float sensorHeight = 24f; // 35mm全画幅传感器的尺寸为36x24,这里只使用高度24mm。
float focalLengthRequired = Camera.FieldOfViewToFocalLength(desiredFOV, sensorHeight);
Debug.Log("所需焦距:" + focalLengthRequired + "mm");
定义:
public static extern float FocalLengthToFieldOfView(float focalLength, float sensorSize);
参数说明:
示例:
假设我们有一个50mm的镜头和一个35mm的全幅传感器,我们想知道这个组合的视场是多少:
float focalLength = 50f; // 50mm焦距
float sensorHeight = 24f; // 35mm的全幅传感器的高度为24mm
float fov = Camera.FocalLengthToFieldOfView(focalLength, sensorHeight);
Debug.Log("视场: " + fov + " 度");
我们通常使用垂直视场(Vertical Field of View)来描述摄像机的视场。但在某些情况下,基于摄像机的长宽比(Aspect Ratio),我们可能需要转换为水平视场(Horizontal Field of View)。这就是Camera.HorizontalToVerticalFieldOfView和Camera.VerticalToHorizontalFieldOfView这两个方法的应用场景。
定义:
public static extern float HorizontalToVerticalFieldOfView(float horizontalFieldOfView, float aspectRatio);
参数说明:
示例:
float hFOV = 60.0f;
float aspect = 16.0f/9.0f; //假设16:9的宽高比
float vFOV = Camera.HorizontalToVerticalFieldOfView(hFOV, aspect);
Debug.Log("垂直视场:" + vFOV);
定义:
public static extern float VerticalToHorizontalFieldOfView(float verticalFieldOfView, float aspectRatio);
参数说明:
示例:
float vFOV = 45.0f;
float aspect = 16.0f/9.0f;
float hFOV = Camera.VerticalToHorizontalFieldOfView(vFOV, aspect);
Debug.Log("水平视场: " + hFOV);
定义:
public static int GetAllCameras(Camera[] cameras)
cameras: 这是一个摄像机数组,用于存储场景中所有当前激活的摄像机。
返回值是实际填入数组的摄像机数。需要注意的是,提供的数组大小应该至少等于Camera.allCamerasCount,否则不会存储所有摄像机。
示例:
Camera[] allCameras = new Camera[Camera.allCamerasCount];
int filledCount = Camera.GetAllCameras(allCameras);
foreach(Camera cam in allCameras)
{
Debug.Log(cam.name);
}
定义:
public static extern void SetupCurrent(Camera cur);
cur: 要设置为当前摄像机的摄像机实例。
这个方法对于动态切换主摄像机非常有用,例如在游戏中从一个摄像机视角切换到另一个摄像机视角。
示例:
public Camera alternateCamera; // 假设定义一个分配的Camera
void SwitchToAlternateCamera()
{
Camera.SetupCurrent(alternateCamera);
}
在这个示例中,SwitchToAlternateCamera 方法会将主摄像机从当前摄像机切换到alternateCamera。
Camera.onPostRender
: 当摄像机完成渲染后会触发此事件。
Camera.onPreRender
: 在摄像机开始渲染场景内容之前被触发的事件。
Camera.onPreCull
: 它在摄像机开始裁剪阶段之前被触发的事件。
这在一些特定的应用场景中是非常有用的,比如当你想在摄像机渲染的结果上添加一些后处理效果或执行某些额外的绘图操作。
使用方式:
示例:
假设你想在每次摄像机渲染后在控制台打印一条消息:
void OnEnable()
{
Camera.onPostRender += PostRenderAction;
}
void OnDisable()
{
Camera.onPostRender -= PostRenderAction;
}
void PostRenderAction(Camera cam)
{
Debug.Log("相机完成渲染: "+ cam.name);
}
在上述示例中:
该事件在摄像机开始渲染场景内容之前被触发。它允许开发者在摄像机开始渲染前执行一些预先的操作或调整。例如,你可能想要修改摄像机的参数、改变物体的位置或状态、或执行其他任何需要在渲染前完成的任务。
此事件在某些特定的应用场景中非常有用,比如你想动态调整摄像机的参数或在渲染开始之前应用某些效果。
使用方式:
示例:
假设你在渲染开始前想要在控制台打印一条消息:
void OnEnable()
{
Camera.onPreRender += PreRenderAction;
}
void OnDisable()
{
Camera.onPreRender -= PreRenderAction;
}
void PreRenderAction(Camera cam)
{
Debug.Log("即将开始用的相机渲染:"+ cam.name);
}
在上述示例中:
它在摄像机开始裁剪阶段之前被触发。裁剪(culling)阶段是一个渲染流水线的部分,其中引擎决定哪些对象不在摄像机的视野内,因此可以被安全地忽略或“裁剪”掉,不参与后续的渲染过程。这是一个性能优化步骤,确保引擎仅渲染对玩家可见的对象。
通过使用 Camera.onPreCull 事件,开发者可以在裁剪过程开始之前进行一些操作或调整。
使用方式与用法可以参考上述两个事件
,这里就不举例了,基本一致的。
在下一篇文章,我们会继续深度解析剩下的内容,包括Camera中枚举的使用等等。
希望你在这篇文章中对Unity的Camera类有了更深入的了解。如有任何疑问或需要进一步探讨,请在评论区留言,我会很乐意帮助!