• Register

Game about a washed-up Space Marine, science babes and slimy aliens...and of course zombies! <...insert mutants if you hate zombies...>

Forum Thread
  Posts  
UNITY - Mesh Fading (without using Layers) (Games : Double Barrelled : Blake Killem vs Mars : Forum : Tutorials & Resources : UNITY - Mesh Fading (without using Layers)) Locked
Thread Options
Apr 11 2014 Anchor

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 &amp;&amp; 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) &amp;&amp; _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 &amp;&amp; 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 &amp;&amp; selfComponents.Length > 0)
			{ result.AddRange(selfComponents); }
			
			if(childComponents != null &amp;&amp; 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 &amp;&amp; selfComponents.Length > 0)
			{ result = selfComponents[0]; }
			
			var childComponents = input.GetComponentsInChildren<T>();
			
			if(childComponents != null &amp;&amp; childComponents.Length > 0)
			{ result = childComponents[0]; }
			
			return result;
		}
		}
}

Edited by: alexfeature

Reply to thread
click to sign in and post

Only registered members can share their thoughts. So come on! Join the community today (totally free - or sign in with your social account on the right) and join in the conversation.