Last active
October 16, 2021 22:01
-
-
Save michaelybecker/dd13f558b5bb0ff64d13f3e8f0678dc5 to your computer and use it in GitHub Desktop.
DoF AutoFocus for Unity's new postprocessing stack
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// An adaptaion of Frank Otto's AutoFocus script for Unity's new PostProcessing Stack | |
// Original at: http://wiki.unity3d.com/index.php?title=DoFAutoFocus | |
// Adapted by Michael Hazani | |
// For more info see: http://www.michaelhazani.com/autofocus-on-whats-important | |
using UnityEngine; | |
using System.Collections; | |
using System; | |
using UnityEngine.PostProcessing; | |
[RequireComponent(typeof(Camera))] | |
public class StackDoFAutoFocus : MonoBehaviour | |
{ | |
private GameObject doFFocusTarget; | |
private Vector3 lastDoFPoint; | |
private PostProcessingProfile m_Profile; | |
public DoFAFocusQuality focusQuality = StackDoFAutoFocus.DoFAFocusQuality.NORMAL; | |
public LayerMask hitLayer = 1; | |
public float maxDistance = 100.0f; | |
public bool interpolateFocus = false; | |
public float interpolationTime = 0.7f; | |
public enum DoFAFocusQuality | |
{ | |
NORMAL, | |
HIGH | |
} | |
void Start() | |
{ | |
doFFocusTarget = new GameObject("DoFFocusTarget"); | |
var behaviour = GetComponent<PostProcessingBehaviour>(); | |
m_Profile = behaviour.profile; | |
} | |
void Update() | |
{ | |
// switch between Modes Test Focus every Frame | |
if (focusQuality == StackDoFAutoFocus.DoFAFocusQuality.HIGH) | |
{ | |
Focus(); | |
} | |
} | |
void FixedUpdate() | |
{ | |
// switch between modes Test Focus like the Physicsupdate | |
if (focusQuality == StackDoFAutoFocus.DoFAFocusQuality.NORMAL) | |
{ | |
Focus(); | |
} | |
} | |
IEnumerator InterpolateFocus(Vector3 targetPosition) | |
{ | |
Vector3 start = this.doFFocusTarget.transform.position; | |
Vector3 end = targetPosition; | |
float dTime = 0; | |
// Debug.DrawLine(start, end, Color.green); | |
var depthOfField = m_Profile.depthOfField.settings; | |
while (dTime < 1) | |
{ | |
yield return new WaitForEndOfFrame(); | |
dTime += Time.deltaTime / this.interpolationTime; | |
this.doFFocusTarget.transform.position = Vector3.Lerp(start, end, dTime); | |
depthOfField.focusDistance = Vector3.Distance(doFFocusTarget.transform.position, transform.position); | |
m_Profile.depthOfField.settings = depthOfField; | |
} | |
this.doFFocusTarget.transform.position = end; | |
} | |
void Focus() | |
{ | |
// our ray | |
Ray ray = transform.GetComponent<Camera>().ScreenPointToRay(Input.mousePosition); | |
RaycastHit hit; | |
if (Physics.Raycast(ray, out hit, this.maxDistance, this.hitLayer)) | |
{ | |
Debug.DrawLine(ray.origin, hit.point); | |
// do we have a new point? | |
if (this.lastDoFPoint == hit.point) | |
{ | |
return; | |
// No, do nothing | |
} | |
else if (this.interpolateFocus) | |
{ // Do we interpolate from last point to the new Focus Point ? | |
// stop the Coroutine | |
StopCoroutine("InterpolateFocus"); | |
// start new Coroutine | |
StartCoroutine(InterpolateFocus(hit.point)); | |
} | |
else | |
{ | |
this.doFFocusTarget.transform.position = hit.point; | |
var depthOfField = m_Profile.depthOfField.settings; | |
depthOfField.focusDistance = Vector3.Distance(doFFocusTarget.transform.position, transform.position); | |
// print(depthOfField.focusDistance); | |
m_Profile.depthOfField.settings = depthOfField; | |
} | |
// asign the last hit | |
this.lastDoFPoint = hit.point; | |
} | |
} | |
} |
@petru23 Do you have the post processing stack installed from Unity?
This is great, but works for interiors only.
For outdoor distant autofocus you need to place a big quad with renderer=false in front of your camera, as a child, to catch the raycast.
Or edit the code to track the situation where hit.point is not obtained, and set the focus distance to some const (say, 100-200m).
Also interpolation jumps in some situations, maybe it's better not to stop the coroutine, but constantly interpolate to hit.point.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I need to ask a question: using UnityEngine.PostProcessing is not recognized so what could be a substitute?