Unity角色残影特效

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/qq992817263/article/details/52994907

残影特效在网上有很多例子,比如这个,我参考着自己整合了一下,算是整合了一个比较完整且特别简单易用的出来,只需要一个脚本挂上去无需任何设定就能用。

这里只针对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. }


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值