Unity角色殘影特效

殘影特效在網上有很多例子,比如這個,我參考着自己整合了一下,算是整合了一個比較完整且特別簡單易用的出來,只需要一個腳本掛上去無需任何設定就能用。

這裏只針對SkinnedMeshRenderer的網格(也就是帶蒙皮的網格)殘影,主要原理是根據設定的間隔時間連續的截取當前SkinnedMeshRenderer的網格數據並使用Graphics.DrawMesh畫出網格。


一、首先是我們的殘影類,爲了能及時的Destroy,所以它最好派生至Object:

  1. class AfterImage : Object
  2. {
  3. //殘影網格
  4. public Mesh _Mesh;
  5. //殘影紋理
  6. public Material _Material;
  7. //殘影位置
  8. public Matrix4x4 _Matrix;
  9. //殘影透明度
  10. public float _Alpha;
  11. //殘影啓動時間
  12. public float _StartTime;
  13. //殘影保留時間
  14. public float _Duration;
  15. public AfterImage(Mesh mesh, Material material, Matrix4x4 matrix4x4, float alpha, float startTime, float duration)
  16. {
  17. _Mesh = mesh;
  18. _Material = material;
  19. _Matrix = matrix4x4;
  20. _Alpha = alpha;
  21. _StartTime = startTime;
  22. _Duration = duration;
  23. }
  24. }


屬性描述:殘影從創建之時起便記錄《殘影啓動時間》,當其生命週期達到或者超過了設定的《殘影保留時間》時,該殘影即被清除;《殘影網格》爲殘影創建之時從SkinnedMeshRenderer截取而來,保留有當前SkinnedMeshRenderer的網格數據,並依據設定的《殘影紋理》在《殘影位置》以《殘影透明度》DrawMesh。


二、我們再定義一個殘影特效類來管理殘影:

  1. using UnityEngine;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. /// <summary>
  5. /// 殘影特效
  6. /// </summary>
  7. public class AfterImageEffects : MonoBehaviour {
  8. //開啓殘影
  9. public bool _OpenAfterImage;
  10. //殘影顏色
  11. public Color _AfterImageColor = Color.black;
  12. //殘影的生存時間
  13. public float _SurvivalTime = 1;
  14. //生成殘影的間隔時間
  15. public float _IntervalTime = 0.2f;
  16. private float _Time = 0;
  17. //殘影初始透明度
  18. [Range(0.1f, 1.0f)]
  19. public float _InitialAlpha = 1.0f;
  20. private List<AfterImage> _AfterImageList;
  21. private SkinnedMeshRenderer _SkinnedMeshRenderer;
  22. void Awake () {
  23. _AfterImageList = new List<AfterImage>();
  24. _SkinnedMeshRenderer = GetComponent<SkinnedMeshRenderer>();
  25. }
  26. void Update () {
  27. if (_OpenAfterImage && _AfterImageList != null)
  28. {
  29. if (_SkinnedMeshRenderer == null)
  30. {
  31. _OpenAfterImage = false;
  32. return;
  33. }
  34. _Time += Time.deltaTime;
  35. //生成殘影
  36. CreateAfterImage();
  37. //刷新殘影
  38. UpdateAfterImage();
  39. }
  40. }
  41. }

屬性描述:《殘影的生存時間》爲每個殘影從創建開始到銷燬經歷的時間,《生成殘影的間隔時間》爲殘影創建後到下一個殘影創建的時間,每個殘影都會從《初始透明度》逐漸變化到0透明度並銷燬。


生成殘影:

  1. /// <summary>
  2. /// 生成殘影
  3. /// </summary>
  4. void CreateAfterImage()
  5. {
  6. //生成殘影
  7. if (_Time >= _IntervalTime)
  8. {
  9. _Time = 0;
  10. Mesh mesh = new Mesh();
  11. _SkinnedMeshRenderer.BakeMesh(mesh);
  12. Material material = new Material(_SkinnedMeshRenderer.material);
  13. SetMaterialRenderingMode(material, RenderingMode.Fade);
  14. _AfterImageList.Add(new AfterImage(
  15. mesh,
  16. material,
  17. transform.localToWorldMatrix,
  18. _InitialAlpha,
  19. Time.realtimeSinceStartup,
  20. _SurvivalTime));
  21. }
  22. }

刷新殘影:

  1. /// <summary>
  2. /// 刷新殘影
  3. /// </summary>
  4. void UpdateAfterImage()
  5. {
  6. //刷新殘影,根據生存時間銷燬已過時的殘影
  7. for (int i = 0; i < _AfterImageList.Count; i++)
  8. {
  9. float _PassingTime = Time.realtimeSinceStartup - _AfterImageList[i]._StartTime;
  10. if (_PassingTime > _AfterImageList[i]._Duration)
  11. {
  12. _AfterImageList.Remove(_AfterImageList[i]);
  13. Destroy(_AfterImageList[i]);
  14. continue;
  15. }
  16. if (_AfterImageList[i]._Material.HasProperty("_Color"))
  17. {
  18. _AfterImageList[i]._Alpha *= (1 - _PassingTime / _AfterImageList[i]._Duration);
  19. _AfterImageColor.a = _AfterImageList[i]._Alpha;
  20. _AfterImageList[i]._Material.SetColor("_Color", _AfterImageColor);
  21. }
  22. Graphics.DrawMesh(_AfterImageList[i]._Mesh, _AfterImageList[i]._Matrix, _AfterImageList[i]._Material, gameObject.layer);
  23. }
  24. }

殘影存在透明通道,所以必須要設置紋理的渲染模式爲fade模式:

  1. /// <summary>
  2. /// 設置紋理渲染模式
  3. /// </summary>
  4. void SetMaterialRenderingMode(Material material, RenderingMode renderingMode)
  5. {
  6. switch (renderingMode)
  7. {
  8. case RenderingMode.Opaque:
  9. material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
  10. material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
  11. material.SetInt("_ZWrite", 1);
  12. material.DisableKeyword("_ALPHATEST_ON");
  13. material.DisableKeyword("_ALPHABLEND_ON");
  14. material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
  15. material.renderQueue = -1;
  16. break;
  17. case RenderingMode.Cutout:
  18. material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
  19. material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
  20. material.SetInt("_ZWrite", 1);
  21. material.EnableKeyword("_ALPHATEST_ON");
  22. material.DisableKeyword("_ALPHABLEND_ON");
  23. material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
  24. material.renderQueue = 2450;
  25. break;
  26. case RenderingMode.Fade:
  27. material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
  28. material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
  29. material.SetInt("_ZWrite", 0);
  30. material.DisableKeyword("_ALPHATEST_ON");
  31. material.EnableKeyword("_ALPHABLEND_ON");
  32. material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
  33. material.renderQueue = 3000;
  34. break;
  35. case RenderingMode.Transparent:
  36. material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
  37. material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
  38. material.SetInt("_ZWrite", 0);
  39. material.DisableKeyword("_ALPHATEST_ON");
  40. material.DisableKeyword("_ALPHABLEND_ON");
  41. material.EnableKeyword("_ALPHAPREMULTIPLY_ON");
  42. material.renderQueue = 3000;
  43. break;
  44. }
  45. }

三、效果圖如下:







四、我將完整的源碼貼一遍,只需要新建一個腳本AfterImageEffects,複製以下源碼到其中,然後掛在有SkinnedMeshRenderer組件的模型上,並勾選OpenAfterImage,運行便可以看到效果:

  1. using UnityEngine;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. /// <summary>
  5. /// 殘影特效
  6. /// </summary>
  7. public class AfterImageEffects : MonoBehaviour {
  8. //開啓殘影
  9. public bool _OpenAfterImage;
  10. //殘影顏色
  11. public Color _AfterImageColor = Color.black;
  12. //殘影的生存時間
  13. public float _SurvivalTime = 1;
  14. //生成殘影的間隔時間
  15. public float _IntervalTime = 0.2f;
  16. private float _Time = 0;
  17. //殘影初始透明度
  18. [Range(0.1f, 1.0f)]
  19. public float _InitialAlpha = 1.0f;
  20. private List<AfterImage> _AfterImageList;
  21. private SkinnedMeshRenderer _SkinnedMeshRenderer;
  22. void Awake () {
  23. _AfterImageList = new List<AfterImage>();
  24. _SkinnedMeshRenderer = GetComponent<SkinnedMeshRenderer>();
  25. }
  26. void Update () {
  27. if (_OpenAfterImage && _AfterImageList != null)
  28. {
  29. if (_SkinnedMeshRenderer == null)
  30. {
  31. _OpenAfterImage = false;
  32. return;
  33. }
  34. _Time += Time.deltaTime;
  35. //生成殘影
  36. CreateAfterImage();
  37. //刷新殘影
  38. UpdateAfterImage();
  39. }
  40. }
  41. /// <summary>
  42. /// 生成殘影
  43. /// </summary>
  44. void CreateAfterImage()
  45. {
  46. //生成殘影
  47. if (_Time >= _IntervalTime)
  48. {
  49. _Time = 0;
  50. Mesh mesh = new Mesh();
  51. _SkinnedMeshRenderer.BakeMesh(mesh);
  52. Material material = new Material(_SkinnedMeshRenderer.material);
  53. SetMaterialRenderingMode(material, RenderingMode.Fade);
  54. _AfterImageList.Add(new AfterImage(
  55. mesh,
  56. material,
  57. transform.localToWorldMatrix,
  58. _InitialAlpha,
  59. Time.realtimeSinceStartup,
  60. _SurvivalTime));
  61. }
  62. }
  63. /// <summary>
  64. /// 刷新殘影
  65. /// </summary>
  66. void UpdateAfterImage()
  67. {
  68. //刷新殘影,根據生存時間銷燬已過時的殘影
  69. for (int i = 0; i < _AfterImageList.Count; i++)
  70. {
  71. float _PassingTime = Time.realtimeSinceStartup - _AfterImageList[i]._StartTime;
  72. if (_PassingTime > _AfterImageList[i]._Duration)
  73. {
  74. _AfterImageList.Remove(_AfterImageList[i]);
  75. Destroy(_AfterImageList[i]);
  76. continue;
  77. }
  78. if (_AfterImageList[i]._Material.HasProperty("_Color"))
  79. {
  80. _AfterImageList[i]._Alpha *= (1 - _PassingTime / _AfterImageList[i]._Duration);
  81. _AfterImageColor.a = _AfterImageList[i]._Alpha;
  82. _AfterImageList[i]._Material.SetColor("_Color", _AfterImageColor);
  83. }
  84. Graphics.DrawMesh(_AfterImageList[i]._Mesh, _AfterImageList[i]._Matrix, _AfterImageList[i]._Material, gameObject.layer);
  85. }
  86. }
  87. /// <summary>
  88. /// 設置紋理渲染模式
  89. /// </summary>
  90. void SetMaterialRenderingMode(Material material, RenderingMode renderingMode)
  91. {
  92. switch (renderingMode)
  93. {
  94. case RenderingMode.Opaque:
  95. material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
  96. material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
  97. material.SetInt("_ZWrite", 1);
  98. material.DisableKeyword("_ALPHATEST_ON");
  99. material.DisableKeyword("_ALPHABLEND_ON");
  100. material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
  101. material.renderQueue = -1;
  102. break;
  103. case RenderingMode.Cutout:
  104. material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
  105. material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
  106. material.SetInt("_ZWrite", 1);
  107. material.EnableKeyword("_ALPHATEST_ON");
  108. material.DisableKeyword("_ALPHABLEND_ON");
  109. material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
  110. material.renderQueue = 2450;
  111. break;
  112. case RenderingMode.Fade:
  113. material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
  114. material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
  115. material.SetInt("_ZWrite", 0);
  116. material.DisableKeyword("_ALPHATEST_ON");
  117. material.EnableKeyword("_ALPHABLEND_ON");
  118. material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
  119. material.renderQueue = 3000;
  120. break;
  121. case RenderingMode.Transparent:
  122. material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
  123. material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
  124. material.SetInt("_ZWrite", 0);
  125. material.DisableKeyword("_ALPHATEST_ON");
  126. material.DisableKeyword("_ALPHABLEND_ON");
  127. material.EnableKeyword("_ALPHAPREMULTIPLY_ON");
  128. material.renderQueue = 3000;
  129. break;
  130. }
  131. }
  132. }
  133. public enum RenderingMode
  134. {
  135. Opaque,
  136. Cutout,
  137. Fade,
  138. Transparent,
  139. }
  140. class AfterImage : Object
  141. {
  142. //殘影網格
  143. public Mesh _Mesh;
  144. //殘影紋理
  145. public Material _Material;
  146. //殘影位置
  147. public Matrix4x4 _Matrix;
  148. //殘影透明度
  149. public float _Alpha;
  150. //殘影啓動時間
  151. public float _StartTime;
  152. //殘影保留時間
  153. public float _Duration;
  154. public AfterImage(Mesh mesh, Material material, Matrix4x4 matrix4x4, float alpha, float startTime, float duration)
  155. {
  156. _Mesh = mesh;
  157. _Material = material;
  158. _Matrix = matrix4x4;
  159. _Alpha = alpha;
  160. _StartTime = startTime;
  161. _Duration = duration;
  162. }
  163. }


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章