using UnityEngine; using System; #if CINEMACHINE_HDRP || CINEMACHINE_URP #if CINEMACHINE_HDRP_7_3_1 using UnityEngine.Rendering.HighDefinition; #else #if CINEMACHINE_URP using UnityEngine.Rendering.Universal; #else using UnityEngine.Experimental.Rendering.HDPipeline; #endif #endif #endif namespace Cinemachine { /// /// Describes the FOV and clip planes for a camera. This generally mirrors the Unity Camera's /// lens settings, and will be used to drive the Unity camera when the vcam is active. /// [Serializable] [DocumentationSorting(DocumentationSortingAttribute.Level.UserRef)] public struct LensSettings { /// Default Lens Settings public static LensSettings Default = new LensSettings(40f, 10f, 0.1f, 5000f, 0); /// /// This is the camera view in degrees. For cinematic people, a 50mm lens /// on a super-35mm sensor would equal a 19.6 degree FOV /// [Range(1f, 179f)] [Tooltip("This is the camera view in degrees. Display will be in vertical degress, unless the " + "associated camera has its FOV axis setting set to Horizontal, in which case display will " + "be in horizontal degress. Internally, it is always vertical degrees. " + "For cinematic people, a 50mm lens on a super-35mm sensor would equal a 19.6 degree FOV")] public float FieldOfView; /// /// When using an orthographic camera, this defines the half-height, in world /// co-ordinates, of the camera view. /// [Tooltip("When using an orthographic camera, this defines the half-height, in world " + "coordinates, of the camera view.")] public float OrthographicSize; /// /// The near clip plane for this LensSettings /// [Tooltip("This defines the near region in the renderable range of the camera frustum. " + "Raising this value will stop the game from drawing things near the camera, which " + "can sometimes come in handy. Larger values will also increase your shadow resolution.")] public float NearClipPlane; /// /// The far clip plane for this LensSettings /// [Tooltip("This defines the far region of the renderable range of the camera frustum. Typically " + "you want to set this value as low as possible without cutting off desired distant objects")] public float FarClipPlane; /// /// The dutch (tilt) to be applied to the camera. In degrees /// [Range(-180f, 180f)] [Tooltip("Camera Z roll, or tilt, in degrees.")] public float Dutch; /// /// This enum controls how the Camera seetings are driven. Some settings /// can be pulled from the main camera, or pushed to it, depending on these values. /// public enum OverrideModes { /// Perspective/Ortho, IsPhysical /// will not be changed in Unity Camera. This is the default setting. None = 0, /// Orthographic projection mode will be pushed to the Unity Camera Orthographic, /// Perspective projection mode will be pushed to the Unity Camera Perspective, /// A physically-modeled Perspective projection type will be pushed /// to the Unity Camera Physical } /// /// Allows you to select a different camera mode to apply to the Camera component /// when Cinemachine activates this Virtual Camera. The changes applied to the Camera /// component through this setting will remain after the Virtual Camera deactivation. /// [Tooltip("Allows you to select a different camera mode to apply to the Camera component " + "when Cinemachine activates this Virtual Camera. The changes applied to the Camera " + "component through this setting will remain after the Virtual Camera deactivation.")] public OverrideModes ModeOverride; /// /// This is set every frame by the virtual camera, based on the value found in the /// currently associated Unity camera. /// Do not set this property. Instead, use the ModeOverride field to set orthographic mode. /// public bool Orthographic { get => ModeOverride == OverrideModes.Orthographic || ModeOverride == OverrideModes.None && m_OrthoFromCamera; /// Obsolete: do not use set { m_OrthoFromCamera = value; ModeOverride = value ? OverrideModes.Orthographic : OverrideModes.Perspective; } } /// /// For physical cameras, this is the actual size of the image sensor (in mm); it is used to /// convert between focal length and field of vue. For nonphysical cameras, it is the aspect ratio. /// public Vector2 SensorSize { get { return m_SensorSize; } set { m_SensorSize = value; } } /// /// Sensor aspect, not screen aspect. For nonphysical cameras, this is the same thing. /// public float Aspect { get { return SensorSize.y == 0 ? 1f : (SensorSize.x / SensorSize.y); } } /// /// This property will be true if the camera mode is set, either directly or /// indirectly, to Physical Camera /// Do not set this property. Instead, use the ModeOverride field to set physical mode. /// public bool IsPhysicalCamera { get { return ModeOverride == OverrideModes.Physical || ModeOverride == OverrideModes.None && m_PhysicalFromCamera; } /// Obsolete: do not use set { m_PhysicalFromCamera = value; ModeOverride = value ? OverrideModes.Physical : OverrideModes.Perspective; } } /// For physical cameras only: position of the gate relative to /// the film back public Vector2 LensShift; /// For physical cameras only: how the image is fitted to the sensor /// if the aspect ratios differ public Camera.GateFitMode GateFit; #if UNITY_2022_2_OR_NEWER /// For physical cameras only: how far from the camera to the point /// of sharpest focus public float FocusDistance; #endif [SerializeField] Vector2 m_SensorSize; bool m_OrthoFromCamera; bool m_PhysicalFromCamera; #if CINEMACHINE_HDRP public int Iso; public float ShutterSpeed; #if CINEMACHINE_HDRP_14 [Range(Camera.kMinAperture, Camera.kMaxAperture)] public float Aperture; [Range(Camera.kMinBladeCount, Camera.kMaxBladeCount)] #else [Range(HDPhysicalCamera.kMinAperture, HDPhysicalCamera.kMaxAperture)] public float Aperture; [Range(HDPhysicalCamera.kMinBladeCount, HDPhysicalCamera.kMaxBladeCount)] #endif public int BladeCount; public Vector2 Curvature; [Range(0, 1)] public float BarrelClipping; [Range(-1, 1)] public float Anamorphism; #endif /// /// Creates a new LensSettings, copying the values from the /// supplied Camera /// /// The Camera from which the FoV, near /// and far clip planes will be copied. /// The LensSettings as extracted from the supplied Camera public static LensSettings FromCamera(Camera fromCamera) { LensSettings lens = Default; if (fromCamera != null) { lens.FieldOfView = fromCamera.fieldOfView; lens.OrthographicSize = fromCamera.orthographicSize; lens.NearClipPlane = fromCamera.nearClipPlane; lens.FarClipPlane = fromCamera.farClipPlane; lens.LensShift = fromCamera.lensShift; lens.GateFit = fromCamera.gateFit; #if UNITY_2022_2_OR_NEWER lens.FocusDistance = fromCamera.focusDistance; #endif lens.SnapshotCameraReadOnlyProperties(fromCamera); #if CINEMACHINE_HDRP if (lens.IsPhysicalCamera) { #if CINEMACHINE_HDRP_14 lens.Iso = fromCamera.iso; lens.ShutterSpeed = fromCamera.shutterSpeed; lens.Aperture = fromCamera.aperture; lens.BladeCount = fromCamera.bladeCount; lens.Curvature = fromCamera.curvature; lens.BarrelClipping = fromCamera.barrelClipping; lens.Anamorphism = fromCamera.anamorphism; #else var pc = new HDPhysicalCamera(); #if UNITY_2019_2_OR_NEWER fromCamera.TryGetComponent(out var hda); #else var hda = fromCamera.GetComponent(); #endif if (hda != null) pc = hda.physicalParameters; lens.Iso = pc.iso; lens.ShutterSpeed = pc.shutterSpeed; lens.Aperture = pc.aperture; lens.BladeCount = pc.bladeCount; lens.Curvature = pc.curvature; lens.BarrelClipping = pc.barrelClipping; lens.Anamorphism = pc.anamorphism; #endif } #endif } return lens; } /// /// Snapshot the properties that are read-only in the Camera /// /// The Camera from which we will take the info public void SnapshotCameraReadOnlyProperties(Camera camera) { m_OrthoFromCamera = false; m_PhysicalFromCamera = false; if (camera != null && ModeOverride == OverrideModes.None) { m_OrthoFromCamera = camera.orthographic; m_PhysicalFromCamera = camera.usePhysicalProperties; m_SensorSize = camera.sensorSize; GateFit = camera.gateFit; } if (IsPhysicalCamera) { // If uninitialized, do an initial pull from the camera if (camera != null && m_SensorSize == Vector2.zero) { m_SensorSize = camera.sensorSize; GateFit = camera.gateFit; } } else { if (camera != null) m_SensorSize = new Vector2(camera.aspect, 1f); LensShift = Vector2.zero; } } /// /// Snapshot the properties that are read-only in the Camera /// /// The LensSettings from which we will take the info public void SnapshotCameraReadOnlyProperties(ref LensSettings lens) { if (ModeOverride == OverrideModes.None) { m_OrthoFromCamera = lens.Orthographic; m_SensorSize = lens.m_SensorSize; m_PhysicalFromCamera = lens.IsPhysicalCamera; } if (!IsPhysicalCamera) LensShift = Vector2.zero; } /// /// Explicit constructor for this LensSettings /// /// The Vertical field of view /// If orthographic, this is the half-height of the screen /// The near clip plane /// The far clip plane /// Camera roll, in degrees. This is applied at the end /// after shot composition. public LensSettings( float verticalFOV, float orthographicSize, float nearClip, float farClip, float dutch) : this() { FieldOfView = verticalFOV; OrthographicSize = orthographicSize; NearClipPlane = nearClip; FarClipPlane = farClip; Dutch = dutch; m_SensorSize = new Vector2(1, 1); GateFit = Camera.GateFitMode.Horizontal; #if UNITY_2022_2_OR_NEWER FocusDistance = 10; #endif #if CINEMACHINE_HDRP Iso = 200; ShutterSpeed = 0.005f; Aperture = 16; BladeCount = 5; Curvature = new Vector2(2, 11); BarrelClipping = 0.25f; Anamorphism = 0; #endif } /// /// Linearly blends the fields of two LensSettings and returns the result /// /// The LensSettings to blend from /// The LensSettings to blend to /// The interpolation value. Internally clamped to the range [0,1] /// Interpolated settings public static LensSettings Lerp(LensSettings lensA, LensSettings lensB, float t) { t = Mathf.Clamp01(t); LensSettings blendedLens = t < 0.5f ? lensA : lensB; // non-lerpable settings taken care of here blendedLens.FarClipPlane = Mathf.Lerp(lensA.FarClipPlane, lensB.FarClipPlane, t); blendedLens.NearClipPlane = Mathf.Lerp(lensA.NearClipPlane, lensB.NearClipPlane, t); blendedLens.FieldOfView = Mathf.Lerp(lensA.FieldOfView, lensB.FieldOfView, t); blendedLens.OrthographicSize = Mathf.Lerp(lensA.OrthographicSize, lensB.OrthographicSize, t); blendedLens.Dutch = Mathf.Lerp(lensA.Dutch, lensB.Dutch, t); blendedLens.m_SensorSize = Vector2.Lerp(lensA.m_SensorSize, lensB.m_SensorSize, t); blendedLens.LensShift = Vector2.Lerp(lensA.LensShift, lensB.LensShift, t); #if UNITY_2022_2_OR_NEWER blendedLens.FocusDistance = Mathf.Lerp(lensA.FocusDistance, lensB.FocusDistance, t); #endif #if CINEMACHINE_HDRP blendedLens.Iso = Mathf.RoundToInt(Mathf.Lerp((float)lensA.Iso, (float)lensB.Iso, t)); blendedLens.ShutterSpeed = Mathf.Lerp(lensA.ShutterSpeed, lensB.ShutterSpeed, t); blendedLens.Aperture = Mathf.Lerp(lensA.Aperture, lensB.Aperture, t); blendedLens.BladeCount = Mathf.RoundToInt(Mathf.Lerp(lensA.BladeCount, lensB.BladeCount, t));; blendedLens.Curvature = Vector2.Lerp(lensA.Curvature, lensB.Curvature, t); blendedLens.BarrelClipping = Mathf.Lerp(lensA.BarrelClipping, lensB.BarrelClipping, t); blendedLens.Anamorphism = Mathf.Lerp(lensA.Anamorphism, lensB.Anamorphism, t); #endif return blendedLens; } /// Make sure lens settings are sane. Call this from OnValidate(). public void Validate() { FarClipPlane = Mathf.Max(FarClipPlane, NearClipPlane + 0.001f); FieldOfView = Mathf.Clamp(FieldOfView, 0.01f, 179f); m_SensorSize.x = Mathf.Max(m_SensorSize.x, 0.1f); m_SensorSize.y = Mathf.Max(m_SensorSize.y, 0.1f); #if UNITY_2022_2_OR_NEWER FocusDistance = Mathf.Max(FocusDistance, 0.01f); #endif #if CINEMACHINE_HDRP #if CINEMACHINE_HDRP_14 ShutterSpeed = Mathf.Max(0, ShutterSpeed); Aperture = Mathf.Clamp(Aperture, Camera.kMinAperture, Camera.kMaxAperture); BladeCount = Mathf.Clamp(BladeCount, Camera.kMinBladeCount, Camera.kMaxBladeCount); BarrelClipping = Mathf.Clamp01(BarrelClipping); Curvature.x = Mathf.Clamp(Curvature.x, Camera.kMinAperture, Camera.kMaxAperture); Curvature.y = Mathf.Clamp(Curvature.y, Curvature.x, Camera.kMaxAperture); Anamorphism = Mathf.Clamp(Anamorphism, -1, 1); #else ShutterSpeed = Mathf.Max(0, ShutterSpeed); Aperture = Mathf.Clamp(Aperture, HDPhysicalCamera.kMinAperture, HDPhysicalCamera.kMaxAperture); BladeCount = Mathf.Clamp(BladeCount, HDPhysicalCamera.kMinBladeCount, HDPhysicalCamera.kMaxBladeCount); BarrelClipping = Mathf.Clamp01(BarrelClipping); Curvature.x = Mathf.Clamp(Curvature.x, HDPhysicalCamera.kMinAperture, HDPhysicalCamera.kMaxAperture); Curvature.y = Mathf.Clamp(Curvature.y, Curvature.x, HDPhysicalCamera.kMaxAperture); Anamorphism = Mathf.Clamp(Anamorphism, -1, 1); #endif #endif } } }