Files
2024-11-20 15:21:28 +01:00

412 lines
13 KiB
C#

using UnityEngine;
#if UNITY_POST_PROCESSING_STACK_V2
using UnityEngine.Rendering.PostProcessing;
using System;
#endif
#if HDPipeline
using UnityEngine.Rendering.HighDefinition;
#endif
using UnityEngine.Rendering;
namespace Gaia
{
/// <summary>
/// A script to handle auto focus for Gaia
/// </summary
public class AutoDepthOfField : MonoBehaviour
{
#region Variables
public bool m_interactWithPlayer = true;
public GaiaConstants.EnvironmentRenderer m_renderPipeLine = GaiaConstants.EnvironmentRenderer.BuiltIn;
public GaiaConstants.DOFTrackingType m_trackingType = GaiaConstants.DOFTrackingType.FollowScreen;
public float m_focusOffset = 0f;
public Camera m_sourceCamera;
public GameObject m_targetObject;
public LayerMask m_targetLayer = 3585;
public float m_maxFocusDistance = 100f;
public float m_actualFocusDistance = 1f;
public float m_dofAperture = 7.5f;
public float m_dofFocalLength = 30f;
public bool m_debug = false;
private bool m_maxDistanceExceeded = false;
private GameObject m_debugSphere;
#if UNITY_POST_PROCESSING_STACK_V2
private UnityEngine.Rendering.PostProcessing.DepthOfField m_dof;
#endif
/// <summary>
/// Our last hit point
/// </summary>
private Vector3 m_dofTrackingPoint = Vector3.negativeInfinity;
#endregion
#region Unity Function
/// <summary>
/// Get the main camera if it doesnt exist
/// </summary>
private void Start()
{
SetupAutoFocus();
GetCurrentDepthOfFieldSettings();
}
/// <summary>
/// Apply on disable
/// </summary>
private void OnDisable()
{
if (GaiaUtils.CheckIfSceneProfileExists())
{
GaiaGlobal.Instance.SceneProfile.m_depthOfFieldFocusDistance = m_actualFocusDistance;
}
SetEditorDepthOfFieldSettings();
}
private void OnDestroy()
{
SetEditorDepthOfFieldSettings();
SetDOFStatus(false);
}
/// <summary>
/// Process DOF update
/// </summary>
private void Update()
{
if (m_renderPipeLine != GaiaConstants.EnvironmentRenderer.BuiltIn)
{
return;
}
#if UNITY_POST_PROCESSING_STACK_V2
if (m_sourceCamera == null || m_dof == null)
{
return;
}
#endif
//Update the focus target
UpdateDofTrackingPoint();
}
#endregion
#region Depth Of Field Functions
public void SetDOFMainSettings(float aperture, float focalLength)
{
#if UNITY_POST_PROCESSING_STACK_V2
if (m_dof == null)
{
GetDepthOfFieldComponent();
}
m_dof.aperture.value = aperture;
m_dof.focalLength.value = focalLength;
#endif
}
/// <summary>
/// Do a raycast to update the focus target
/// </summary>
private void UpdateDofTrackingPoint()
{
switch (m_trackingType)
{
case GaiaConstants.DOFTrackingType.LeftMouseClick:
{
if (Input.GetMouseButton(0))
{
Ray ray = m_sourceCamera.ScreenPointToRay(Input.mousePosition);
FocusOnRayCast(ray);
}
break;
}
case GaiaConstants.DOFTrackingType.RightMouseClick:
{
if (Input.GetMouseButton(1))
{
Ray ray = m_sourceCamera.ScreenPointToRay(Input.mousePosition);
FocusOnRayCast(ray);
}
break;
}
case GaiaConstants.DOFTrackingType.FollowScreen:
{
Ray ray = new Ray(m_sourceCamera.transform.position, m_sourceCamera.transform.forward);
FocusOnRayCast(ray);
break;
}
case GaiaConstants.DOFTrackingType.FollowTarget:
{
m_dofTrackingPoint = m_targetObject.transform.position;
break;
}
case GaiaConstants.DOFTrackingType.FixedOffset:
{
if (m_debug)
{
m_debug = false;
Debug.Log("Debug mode is not available in Fixed Offset Tracking Mode. We have turned off Debug Mode for you.");
}
#if UNITY_POST_PROCESSING_STACK_V2
m_dof.focusDistance.value = m_focusOffset;
#endif
break;
}
}
if (m_debug)
{
if (!Vector3.Equals(m_dofTrackingPoint,Vector3.negativeInfinity) && (m_debugSphere == null || m_debugSphere.transform.position != m_dofTrackingPoint))
{
if (m_debugSphere != null)
{
Destroy(m_debugSphere);
}
m_debugSphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);
Destroy(m_debugSphere.GetComponent<Collider>());
m_debugSphere.transform.position = m_dofTrackingPoint;
m_debugSphere.transform.localScale = new Vector3(0.5f, 0.5f, 0.5f);
}
}
#if UNITY_POST_PROCESSING_STACK_V2
if (m_trackingType != GaiaConstants.DOFTrackingType.FixedOffset)
{
SetNewDOFValue(m_dof.focusDistance.value);
}
m_actualFocusDistance = m_dof.focusDistance.value;
#endif
if (GaiaUtils.CheckIfSceneProfileExists())
{
GaiaGlobal.Instance.SceneProfile.m_depthOfFieldFocusDistance = m_actualFocusDistance;
}
}
private void FocusOnRayCast(Ray ray)
{
if (Physics.Raycast(ray, out var hit, m_maxFocusDistance, m_targetLayer))
{
if (m_debug)
{
Debug.Log("Auto DOF Ray collided with: " + hit.collider.name);
}
if (m_interactWithPlayer)
{
if (hit.transform.gameObject.tag != "Player")
{
m_maxDistanceExceeded = false;
m_dofTrackingPoint = hit.point;
}
else
{
m_maxDistanceExceeded = true;
}
}
else
{
m_maxDistanceExceeded = false;
m_dofTrackingPoint = hit.point;
}
}
else
{
m_maxDistanceExceeded = true;
}
}
public void RemoveDebugSphere()
{
if (m_debugSphere != null)
{
DestroyImmediate(m_debugSphere);
}
}
private void SetNewDOFValue(float startValue, float timeMultiplier = 3.5f)
{
if (m_sourceCamera == null)
{
return;
}
#if UNITY_POST_PROCESSING_STACK_V2
if (m_dof == null)
{
GetDepthOfFieldComponent();
}
else
{
if (m_maxDistanceExceeded)
{
m_dof.focusDistance.value = m_maxFocusDistance;
}
else
{
m_dof.focusDistance.value = Mathf.Lerp(startValue, Vector3.Distance(m_sourceCamera.transform.position ,m_dofTrackingPoint) + m_focusOffset, Time.deltaTime * timeMultiplier);
}
}
#endif
}
/// <summary>
/// Setup autofocus object
/// </summary>
public void SetupAutoFocus()
{
m_renderPipeLine = GaiaUtils.GetActivePipeline();
if (m_dofTrackingPoint.x > 0)
{
//Removes warning
}
if (m_maxDistanceExceeded)
{
//Removes warning
}
//Set up main camera
if (m_sourceCamera == null)
{
m_sourceCamera = GaiaUtils.GetCamera();
if (m_sourceCamera == null)
{
Debug.Log("DOF Autofocus exiting, unable to find main camera!");
enabled = false;
return;
}
}
//Determine tracking type
if (m_trackingType == GaiaConstants.DOFTrackingType.FollowTarget && m_targetObject == null)
{
Debug.Log("Tracking target is missing, falling back to follow screen!");
m_trackingType = GaiaConstants.DOFTrackingType.FollowScreen;
}
#if UNITY_POST_PROCESSING_STACK_V2
//Gets DOF component
if (m_dof == null)
{
GetDepthOfFieldComponent();
}
if (m_dof != null)
{
m_dof.focusDistance.value = m_maxFocusDistance;
}
#endif
}
private void GetDepthOfFieldComponent()
{
if (m_renderPipeLine != GaiaConstants.EnvironmentRenderer.BuiltIn)
{
return;
}
#if UNITY_POST_PROCESSING_STACK_V2
//Find our DOF component
if (m_dof == null)
{
GameObject ppObj = GameObject.Find("Global Post Processing");
if (ppObj == null)
{
Debug.Log("DOF Autofocus exiting, unable to global post processing object!");
enabled = false;
return;
}
PostProcessVolume ppVolume = ppObj.GetComponent<PostProcessVolume>();
{
if (ppVolume == null)
{
Debug.Log("DOF Autofocus exiting, unable to global post processing volume!");
enabled = false;
return;
}
}
PostProcessProfile ppProfile = ppVolume.sharedProfile;
if (ppProfile == null)
{
Debug.Log("DOF Autofocus exiting, unable to global post processing profile!");
enabled = false;
return;
}
if (!ppProfile.HasSettings<UnityEngine.Rendering.PostProcessing.DepthOfField>())
{
Debug.Log("DOF Autofocus exiting, unable to find dof settings!");
enabled = false;
return;
}
if (!ppProfile.TryGetSettings<UnityEngine.Rendering.PostProcessing.DepthOfField>(out m_dof))
{
Debug.Log("DOF Autofocus exiting, unable to find dof settings!");
m_dof = null;
enabled = false;
}
}
if (m_dof != null)
{
m_dof.active = true;
m_dof.enabled.value = true;
m_dof.focusDistance.overrideState = true;
m_maxDistanceExceeded = true;
}
#endif
}
/// <summary>
/// Sets the focus distance on the DOF component based on camera distance divided by 4
/// </summary>
/// <param name="enabled"></param>
public void SetDOFStatus(bool enabled)
{
if (!enabled)
{
#if UNITY_POST_PROCESSING_STACK_V2
if (m_dof != null && m_sourceCamera != null)
{
m_dof.focusDistance.value = m_sourceCamera.farClipPlane / 4f;
}
#endif
}
}
/// <summary>
/// Grabs the DOF aperture and focal length and updates the systems values to use these
/// </summary>
public void GetCurrentDepthOfFieldSettings()
{
#if UNITY_POST_PROCESSING_STACK_V2
if (m_dof != null)
{
m_dofAperture = m_dof.aperture.value;
m_dofFocalLength = m_dof.focalLength.value;
}
#endif
}
/// <summary>
/// Sets the depth of field focus distance to 100 if it's less than 20
/// This should remove a blury game view when not in play mode
/// </summary>
private void SetEditorDepthOfFieldSettings()
{
#if UNITY_POST_PROCESSING_STACK_V2
if (m_dof == null)
{
return;
}
if (m_dof.focusDistance.value < 20f)
{
m_dof.focusDistance.value = 100f;
}
#endif
}
#endregion
}
}