Hey Peeps,
In this thread I posted all the code for the tutorial with the same name. If you find mistakes, serious performance issues or need any help whatsoever please post your comments here and we will try to get back to you ASAP.
LICENCE wrote: Feel free to use this code in any Unity project. However, if you want to use this in a commercial plugin please let us know first.
ManagerMeshFade.cs
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using deVoid;
public class ManagerMeshFade : MonoBehaviour
{
private readonly Dictionary<Collider, List<MeshFade>> _registry = new Dictionary<Collider, List<MeshFade>>{};
public static ManagerMeshFade Instance { get; private set; }
public bool Ready { get; private set; }
private void Awake()
{
Instance = this;
}
private void Start()
{
Ready = true;
}
public List<MeshFade> GetMeshFade(Collider collider, string[] groups = null)
{
var result = new List<MeshFade>{};
if(_registry.ContainsKey(collider))
{
var meshFades = _registry[collider];
if(meshFades != null && meshFades.Count > 0)
{
foreach(var meshFade in meshFades)
{
if(groups.Any(x => x == meshFade.FadeGroup))
{ result.Add(meshFade); }
}
}
}
return result;
}
public void Register(Collider[] colliders, MeshFade meshFade)
{
if(colliders == null || meshFade == null || colliders.Length == 0)
{ return; }
foreach(var c in colliders)
{ Register(c, meshFade); }
}
public void Register(Collider collider, MeshFade meshFade)
{
if(collider == null || meshFade == null)
{ return; }
if(!_registry.ContainsKey(collider))
{ _registry.Add(collider, new List<MeshFade>{}); }
else if( _registry.ContainsKey(collider) && _registry[collider] == null)
{ _registry[collider] = new List<MeshFade>{}; }
if(!_registry[collider].Contains(meshFade))
{ _registry[collider].Add(meshFade); }
}
public void Unregister(Collider[] colliders)
{
if(colliders == null || colliders.Length == 0)
{ return; }
foreach(var c in colliders)
{ Unregister(c); }
}
public void Unregister(Collider collider)
{
if(collider == null || !_registry.ContainsKey(collider))
{ return; }
_registry.Remove(collider);
}
public void ClearRegistry()
{
_registry.Clear();
}
}
MeshFadeCameraController.cs
using System.Collections.Generic;
using UnityEngine;
namespace deVoid
{
[RequireComponent(typeof(Camera))]
public class MeshFadeCameraController : MonoBehaviour
{
public Transform Target;
public string[] FadeGroups = new string[] { "Default" };
public Shader Shader;
public float FadeInSpeed = 1F;
public float FadeOutAmount = 0F;
public float FadeOutSpeed = 1F;
public Vector3 RaycastDirection { get; private set; }
private Transform _cachedTransform;
private ManagerMeshFade _manager;
private readonly HashSet<MeshFade> _lastFrameHits = new HashSet<MeshFade>{};
private readonly HashSet<MeshFade> _currentFrameHits = new HashSet<MeshFade>{};
private void Start()
{
_cachedTransform = transform;
}
private void Update()
{
if(!camera.enabled)
{ return; }
if(Shader == null)
{
Debug.LogError("MeshFadeCameraController.Update > Shader is null.");
return;
}
_manager = ManagerMeshFade.Instance;
if(_manager == null)
{
Debug.LogError("MeshFadeCameraController.Update > MeshFadeManager is null.");
return;
}
RaycastDirection = Target.position - _cachedTransform.position;
// Raycast to target or infinity
var hits = Target != null
? Physics.RaycastAll(_cachedTransform.position, RaycastDirection, RaycastDirection.magnitude)
: Physics.RaycastAll(_cachedTransform.position, RaycastDirection);
// Check colliders against registry and fade out meshes that were hit
_currentFrameHits.Clear();
foreach(var hit in hits)
{
var meshFades = _manager.GetMeshFade(hit.collider, FadeGroups);
if(meshFades == null || meshFades.Count == 0)
{ continue; }
foreach(var meshFade in meshFades)
{
_currentFrameHits.Add(meshFade);
if(_lastFrameHits.Contains(meshFade))
{
_lastFrameHits.Remove(meshFade);
}
else
{
meshFade.FadeOut(FadeOutAmount, FadeOutSpeed, Shader);
}
}
}
// Fade in meshes that were not hit this frame
foreach(var lastFrameMeshFade in _lastFrameHits)
{ lastFrameMeshFade.FadeIn(FadeInSpeed); }
_lastFrameHits.Clear();
_lastFrameHits.UnionWith(_currentFrameHits);
}
}
}
MeshFade.cs
using System;
using UnityEngine;
using deVoid.Extensions;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace deVoid
{
public class MeshFade : MonoBehaviour
{
public string FadeGroup = "Default";
public GameObject[] Colliders;
private Collider[] _colliders;
// /// <summary>
// /// Gets or sets the sync context.
// /// </summary>
// /// <value>The sync context used by this component to make sure that it will not be faded in if the parent MeshFade component is currently fading or is already faded out.</value>
// public MeshFadeSync SyncContext { get; set; }
public Renderer[] Renderers;
public GameObject[] ShadowCasters;
public event Action<MeshFade> FadingOut;
public event Action<MeshFade> FadingIn;
public bool IsFadingOut { get; private set; }
public bool IsFadingIn { get; private set; }
public bool IsFadedIn { get { return CurrentFadeAmount >= 1; } }
public bool IsFadedOut { get { return CurrentFadeAmount <= TargetFadeAmount; } }
public float TargetFadeAmount { get; private set; }
public float CurrentFadeAmount { get; private set; }
public float FadeOutSpeed { get; private set; }
public float FadeInSpeed { get; private set; }
public Shader FadeShader { get; private set; }
private float _fadeVelocity;
private bool _stopFadeOut = false;
private bool _stopFadeIn = false;
private readonly Dictionary<Renderer, Shader> _originalShaders = new Dictionary<Renderer, Shader>{};
private void Start ()
{
StartCoroutine(StartCR());
}
private IEnumerator StartCR()
{
while(!ManagerMeshFade.Instance.Ready)
{
#if _DEBUG
Debug.Log("MeshFade.StartCR > Waiting for MeshFadeManager to finish loading.");
#endif
yield return new WaitForEndOfFrame();
}
if(Renderers == null || Renderers.Any())
{
Debug.LogWarning("MeshFade.Start > Renderers are null or empty.");
yield return 0;
}
if(Colliders == null || Colliders.Length == 0)
{
Debug.LogWarning("MeshFade.Start > Colliders are null or empty.");
yield return 0;
}
RefreshColliders();
// Gather shaders for swap collection
foreach(var renderer in Renderers)
{
// We need to keep a list of original shaders keyed by renderer. This will let us swap out the shaders after fade in / out operations.
if(!_originalShaders.ContainsKey(renderer))
{
var shader = Shader.Find(renderer.material.shader.name);
Debug.Log(shader);
_originalShaders.Add(renderer, shader);
}
}
// Register this instance with the manager
ManagerMeshFade.Instance.Register(_colliders, this);
// Disable all shadow casters
if(ShadowCasters != null && ShadowCasters.Length > 0)
{
foreach(var sc in ShadowCasters)
{ sc.SetActive(false); }
}
// Init
CurrentFadeAmount = 1;
}
public void FadeOut(float targetFadeOutAmount, float fadeOutSpeed, Shader shader)
{
if(shader == null)
{
Debug.LogError("MeshFade.FadeOut > Shader is null.");
return;
}
// Ignore call if we are already fading out
if(IsFadingOut || IsFadedOut)
{ return; }
// Stop fade in if in progress
StopFadeIn();
FadeShader = shader;
TargetFadeAmount = targetFadeOutAmount.CapMinMax(0F, 1F);
FadeOutSpeed = fadeOutSpeed.CapMin(0F);
// Set flags
_stopFadeOut = false;
IsFadingOut = true;
// Show shadow casters
foreach(var sc in ShadowCasters)
{ sc.SetActive(true); }
// Fade out meshes
StartCoroutine(FadeOut_CR());
// Notify listners
if(FadingOut != null)
{ FadingOut(this); }
}
private IEnumerator FadeOut_CR()
{
while(!_stopFadeOut)
{
if(CurrentFadeAmount <= TargetFadeAmount)
{
StopFadeOut();
break;
}
CurrentFadeAmount = Mathf.SmoothDamp(CurrentFadeAmount, TargetFadeAmount, ref _fadeVelocity, FadeOutSpeed);
foreach(var renderer in Renderers)
{
if(renderer.material.shader.name != FadeShader.name)
{ renderer.material.shader = FadeShader; }
var color = renderer.material.color;
renderer.material.color = new Color(color.r, color.g, color.b, CurrentFadeAmount);
}
yield return 0;
}
}
public void FadeIn()
{
FadeIn(FadeInSpeed);
}
public void FadeIn(float fadeInSpeed)
{
// Ignore call if we are fading in already
if(IsFadingIn || IsFadedIn)
{ return; }
// Stop fade out if in progress
StopFadeOut();
FadeInSpeed = fadeInSpeed.CapMin(0);
// Set flags
_stopFadeIn = false;
IsFadingIn = true;
StartCoroutine(FadeIn_CR());
// Notify listners
if(FadingIn != null)
{ FadingIn(this); }
}
private IEnumerator FadeIn_CR()
{
while(!_stopFadeIn)
{
if(CurrentFadeAmount >= 1F)
{
StopFadeIn();
break;
}
CurrentFadeAmount = Mathf.SmoothDamp(CurrentFadeAmount, 1.1F, ref _fadeVelocity, FadeInSpeed);
// Fade renderer material
foreach(var renderer in Renderers)
{
if(renderer.material.shader.name != FadeShader.name)
{ renderer.material.shader = FadeShader; }
var color = renderer.material.color;
renderer.material.color = new Color(color.r, color.g, color.b, CurrentFadeAmount);
}
yield return 0;
}
// Swap fade shaders with originals
foreach(var renderer in Renderers)
{
var originalShader = (Shader)null;
_originalShaders.TryGetValue(renderer, out originalShader);
if(originalShader == null)
{
Debug.LogError("MeshFade.FadeIn_CR > OriginalShader is null.");
continue;
}
renderer.material.shader = originalShader;
}
// Hide shadow casters
foreach(var sc in ShadowCasters)
{ sc.SetActive(false); }
}
public void StopFadeIn()
{
IsFadingIn = false;
_stopFadeIn = true;
_fadeVelocity = 1F;
CurrentFadeAmount = 1F;
}
public void StopFadeOut()
{
IsFadingOut = false;
_stopFadeOut = true;
_fadeVelocity = 0F;
CurrentFadeAmount = 0F;
}
/// <summary>
/// Refreshes the internal colliders collection. Call this method every time the Colliders field is updated at runtime.
/// </summary>
public void RefreshColliders()
{
_colliders = Colliders.GetComponentsInHierarchy<Collider>().ToArray();
}
}
}
MeshFadeSync.cs
using System;
using UnityEngine;
using System.Collections.Generic;
using deVoid.Extensions;
namespace deVoid
{
public class MeshFadeSync : MonoBehaviour
{
public MeshFade Parent;
public MeshFade[] Children;
private void Start()
{
if(Parent == null)
{
Debug.LogWarning("MeshFadeSync.Start > Parent is null.");
return;
}
Parent.FadingIn += OnParentFadingIn;
Parent.FadingOut += OnParentFadingOut;
// If no child object were assigned check if this game object has any MeshFade components.
if(Children == null || Children.Length == 0)
{ Children = gameObject.GetComponents<MeshFade>(); }
}
private void OnParentFadingIn(MeshFade meshFade)
{
if(Children == null || Children.Length == 0)
{ Children = gameObject.GetComponents<MeshFade>(); }
foreach(var c in Children)
{ FadeInChild(c); }
}
private void FadeInChild(MeshFade meshFade)
{
if(meshFade == null || meshFade.IsFadingIn)
{ return; }
meshFade.FadeIn();
}
private void OnParentFadingOut(MeshFade meshFade)
{
if(Children == null || Children.Length == 0)
{ Children = gameObject.GetComponents<MeshFade>(); }
foreach(var c in Children)
{ FadeOutChild(c, meshFade.FadeShader); }
}
private void FadeOutChild(MeshFade meshFade, Shader parentFadeShader)
{
if(meshFade == null || meshFade.IsFadingOut)
{ return; }
meshFade.FadeOut(meshFade.TargetFadeAmount, meshFade.FadeOutSpeed, parentFadeShader);
}
private void OnDestroy()
{
if(Parent != null)
{
Parent.FadingIn -= OnParentFadingIn;
Parent.FadingOut -= OnParentFadingOut;
}
}
}
}
Extensions.cs
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
using System.Xml.Linq;
using UnityEditor;
using UnityEngine;
namespace deVoid.Extensions
{
public static partial class Extensions
{
public static T GetComponentFromAncestors<T> (this GameObject input)
where T : Component
{
var result = default(T);
if(input == null)
{ return result; }
var parentTransform = input.transform.parent;
while(true)
{
if(parentTransform == null)
{ break; }
var parentComponent = parentTransform.GetComponent<T>();
if(parentComponent != null)
{
result = parentComponent;
break;
}
parentTransform = parentTransform.parent;
}
return result;
}
public static List<T> GetComponentsInHierarchy<T> (this GameObject[] input)
where T : Component
{
var result = new List<T>{};
if(input == null)
{ return result; }
foreach(var item in input)
{
var components = item.GetComponentsInHierarchy<T>();
if(components.Count > 0)
{ result.AddRange(components); }
}
return result;
}
public static List<T> GetComponentsInHierarchy<T> (this GameObject input)
where T : Component
{
var result = new List<T>{};
if(input == null)
{ return result; }
var selfComponents = input.GetComponents<T>();
var childComponents = input.GetComponentsInChildren<T>();
if(selfComponents != null && selfComponents.Length > 0)
{ result.AddRange(selfComponents); }
if(childComponents != null && childComponents.Length > 0)
{ result.AddRange(childComponents); }
return result;
}
public static T GetComponentInHierarchy<T> (this GameObject input)
where T : Component
{
var result = default(T);
if(input == null)
{ return result; }
var selfComponents = input.GetComponents<T>();
if(selfComponents != null && selfComponents.Length > 0)
{ result = selfComponents[0]; }
var childComponents = input.GetComponentsInChildren<T>();
if(childComponents != null && childComponents.Length > 0)
{ result = childComponents[0]; }
return result;
}
}
}
Edited by: alexfeature