首页 > 其他分享 >Unity角色残影特效

Unity角色残影特效

时间:2022-12-13 14:33:25浏览次数:88  
标签:特效 AfterImageList float material 残影 SetInt Unity public


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

这里只针对SkinnedMeshRenderer的网格(也就是带蒙皮的网格)残影,主要原理是根据设定的间隔时间连续的截取当前SkinnedMeshRenderer的网格数据并使用Graphics.DrawMesh画出网格。


一、首先是我们的残影类,为了能及时的Destroy,所以它最好派生至Object:

class AfterImage : Object
{
//残影网格
public Mesh _Mesh;
//残影纹理
public Material _Material;
//残影位置
public Matrix4x4 _Matrix;
//残影透明度
public float _Alpha;
//残影启动时间
public float _StartTime;
//残影保留时间
public float _Duration;

public AfterImage(Mesh mesh, Material material, Matrix4x4 matrix4x4, float alpha, float startTime, float duration)
{
_Mesh = mesh;
_Material = material;
_Matrix = matrix4x4;
_Alpha = alpha;
_StartTime = startTime;
_Duration = duration;
}
}


属性描述:残影从创建之时起便记录《残影启动时间》,当其生命周期达到或者超过了设定的《残影保留时间》时,该残影即被清除;《残影网格》为残影创建之时从SkinnedMeshRenderer截取而来,保留有当前SkinnedMeshRenderer的网格数据,并依据设定的《残影纹理》在《残影位置》以《残影透明度》DrawMesh。


二、我们再定义一个残影特效类来管理残影:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
/// <summary>
/// 残影特效
/// </summary>
public class AfterImageEffects : MonoBehaviour {

//开启残影
public bool _OpenAfterImage;

//残影颜色
public Color _AfterImageColor = Color.black;
//残影的生存时间
public float _SurvivalTime = 1;
//生成残影的间隔时间
public float _IntervalTime = 0.2f;
private float _Time = 0;
//残影初始透明度
[Range(0.1f, 1.0f)]
public float _InitialAlpha = 1.0f;

private List<AfterImage> _AfterImageList;
private SkinnedMeshRenderer _SkinnedMeshRenderer;

void Awake () {
_AfterImageList = new List<AfterImage>();
_SkinnedMeshRenderer = GetComponent<SkinnedMeshRenderer>();
}
void Update () {
if (_OpenAfterImage && _AfterImageList != null)
{
if (_SkinnedMeshRenderer == null)
{
_OpenAfterImage = false;
return;
}

_Time += Time.deltaTime;
//生成残影
CreateAfterImage();
//刷新残影
UpdateAfterImage();
}
}
}


属性描述:《残影的生存时间》为每个残影从创建开始到销毁经历的时间,《生成残影的间隔时间》为残影创建后到下一个残影创建的时间,每个残影都会从《初始透明度》逐渐变化到0透明度并销毁。


生成残影:

/// <summary>
/// 生成残影
/// </summary>
void CreateAfterImage()
{
//生成残影
if (_Time >= _IntervalTime)
{
_Time = 0;

Mesh mesh = new Mesh();
_SkinnedMeshRenderer.BakeMesh(mesh);

Material material = new Material(_SkinnedMeshRenderer.material);
SetMaterialRenderingMode(material, RenderingMode.Fade);

_AfterImageList.Add(new AfterImage(
mesh,
material,
transform.localToWorldMatrix,
_InitialAlpha,
Time.realtimeSinceStartup,
_SurvivalTime));
}
}


刷新残影:

/// <summary>
/// 刷新残影
/// </summary>
void UpdateAfterImage()
{
//刷新残影,根据生存时间销毁已过时的残影
for (int i = 0; i < _AfterImageList.Count; i++)
{
float _PassingTime = Time.realtimeSinceStartup - _AfterImageList[i]._StartTime;

if (_PassingTime > _AfterImageList[i]._Duration)
{
_AfterImageList.Remove(_AfterImageList[i]);
Destroy(_AfterImageList[i]);
continue;
}

if (_AfterImageList[i]._Material.HasProperty("_Color"))
{
_AfterImageList[i]._Alpha *= (1 - _PassingTime / _AfterImageList[i]._Duration);
_AfterImageColor.a = _AfterImageList[i]._Alpha;
_AfterImageList[i]._Material.SetColor("_Color", _AfterImageColor);
}

Graphics.DrawMesh(_AfterImageList[i]._Mesh, _AfterImageList[i]._Matrix, _AfterImageList[i]._Material, gameObject.layer);
}
}


残影存在透明通道,所以必须要设置纹理的渲染模式为fade模式:

/// <summary>
/// 设置纹理渲染模式
/// </summary>
void SetMaterialRenderingMode(Material material, RenderingMode renderingMode)
{
switch (renderingMode)
{
case RenderingMode.Opaque:
material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
material.SetInt("_ZWrite", 1);
material.DisableKeyword("_ALPHATEST_ON");
material.DisableKeyword("_ALPHABLEND_ON");
material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
material.renderQueue = -1;
break;
case RenderingMode.Cutout:
material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
material.SetInt("_ZWrite", 1);
material.EnableKeyword("_ALPHATEST_ON");
material.DisableKeyword("_ALPHABLEND_ON");
material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
material.renderQueue = 2450;
break;
case RenderingMode.Fade:
material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
material.SetInt("_ZWrite", 0);
material.DisableKeyword("_ALPHATEST_ON");
material.EnableKeyword("_ALPHABLEND_ON");
material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
material.renderQueue = 3000;
break;
case RenderingMode.Transparent:
material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
material.SetInt("_ZWrite", 0);
material.DisableKeyword("_ALPHATEST_ON");
material.DisableKeyword("_ALPHABLEND_ON");
material.EnableKeyword("_ALPHAPREMULTIPLY_ON");
material.renderQueue = 3000;
break;
}
}


三、效果图如下:

Unity角色残影特效_Time


Unity角色残影特效_unity_02


Unity角色残影特效_网格_03


四、我将完整的源码贴一遍,只需要新建一个脚本AfterImageEffects,复制以下源码到其中,然后挂在有SkinnedMeshRenderer组件的模型上,并勾选OpenAfterImage,运行便可以看到效果:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
/// <summary>
/// 残影特效
/// </summary>
public class AfterImageEffects : MonoBehaviour {

//开启残影
public bool _OpenAfterImage;

//残影颜色
public Color _AfterImageColor = Color.black;
//残影的生存时间
public float _SurvivalTime = 1;
//生成残影的间隔时间
public float _IntervalTime = 0.2f;
private float _Time = 0;
//残影初始透明度
[Range(0.1f, 1.0f)]
public float _InitialAlpha = 1.0f;

private List<AfterImage> _AfterImageList;
private SkinnedMeshRenderer _SkinnedMeshRenderer;

void Awake () {
_AfterImageList = new List<AfterImage>();
_SkinnedMeshRenderer = GetComponent<SkinnedMeshRenderer>();
}
void Update () {
if (_OpenAfterImage && _AfterImageList != null)
{
if (_SkinnedMeshRenderer == null)
{
_OpenAfterImage = false;
return;
}

_Time += Time.deltaTime;
//生成残影
CreateAfterImage();
//刷新残影
UpdateAfterImage();
}
}
/// <summary>
/// 生成残影
/// </summary>
void CreateAfterImage()
{
//生成残影
if (_Time >= _IntervalTime)
{
_Time = 0;

Mesh mesh = new Mesh();
_SkinnedMeshRenderer.BakeMesh(mesh);

Material material = new Material(_SkinnedMeshRenderer.material);
SetMaterialRenderingMode(material, RenderingMode.Fade);

_AfterImageList.Add(new AfterImage(
mesh,
material,
transform.localToWorldMatrix,
_InitialAlpha,
Time.realtimeSinceStartup,
_SurvivalTime));
}
}
/// <summary>
/// 刷新残影
/// </summary>
void UpdateAfterImage()
{
//刷新残影,根据生存时间销毁已过时的残影
for (int i = 0; i < _AfterImageList.Count; i++)
{
float _PassingTime = Time.realtimeSinceStartup - _AfterImageList[i]._StartTime;

if (_PassingTime > _AfterImageList[i]._Duration)
{
_AfterImageList.Remove(_AfterImageList[i]);
Destroy(_AfterImageList[i]);
continue;
}

if (_AfterImageList[i]._Material.HasProperty("_Color"))
{
_AfterImageList[i]._Alpha *= (1 - _PassingTime / _AfterImageList[i]._Duration);
_AfterImageColor.a = _AfterImageList[i]._Alpha;
_AfterImageList[i]._Material.SetColor("_Color", _AfterImageColor);
}

Graphics.DrawMesh(_AfterImageList[i]._Mesh, _AfterImageList[i]._Matrix, _AfterImageList[i]._Material, gameObject.layer);
}
}
/// <summary>
/// 设置纹理渲染模式
/// </summary>
void SetMaterialRenderingMode(Material material, RenderingMode renderingMode)
{
switch (renderingMode)
{
case RenderingMode.Opaque:
material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
material.SetInt("_ZWrite", 1);
material.DisableKeyword("_ALPHATEST_ON");
material.DisableKeyword("_ALPHABLEND_ON");
material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
material.renderQueue = -1;
break;
case RenderingMode.Cutout:
material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
material.SetInt("_ZWrite", 1);
material.EnableKeyword("_ALPHATEST_ON");
material.DisableKeyword("_ALPHABLEND_ON");
material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
material.renderQueue = 2450;
break;
case RenderingMode.Fade:
material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
material.SetInt("_ZWrite", 0);
material.DisableKeyword("_ALPHATEST_ON");
material.EnableKeyword("_ALPHABLEND_ON");
material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
material.renderQueue = 3000;
break;
case RenderingMode.Transparent:
material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
material.SetInt("_ZWrite", 0);
material.DisableKeyword("_ALPHATEST_ON");
material.DisableKeyword("_ALPHABLEND_ON");
material.EnableKeyword("_ALPHAPREMULTIPLY_ON");
material.renderQueue = 3000;
break;
}
}
}
public enum RenderingMode
{
Opaque,
Cutout,
Fade,
Transparent,
}
class AfterImage : Object
{
//残影网格
public Mesh _Mesh;
//残影纹理
public Material _Material;
//残影位置
public Matrix4x4 _Matrix;
//残影透明度
public float _Alpha;
//残影启动时间
public float _StartTime;
//残影保留时间
public float _Duration;

public AfterImage(Mesh mesh, Material material, Matrix4x4 matrix4x4, float alpha, float startTime, float duration)
{
_Mesh = mesh;
_Material = material;
_Matrix = matrix4x4;
_Alpha = alpha;
_StartTime = startTime;
_Duration = duration;
}
}



标签:特效,AfterImageList,float,material,残影,SetInt,Unity,public
From: https://blog.51cto.com/u_15911199/5934054

相关文章

  • 【Unity】 HTFramework框架(三十四)框架实用特性
    更新日期:2020年11月6日。Github源码:​​​[点我获取源码]​​​Gitee源码:​​[点我获取源码]​​索引​​框架实用特性​​​​LnkTools特性(快捷工具)​​​​CSDNBlogURL......
  • Unity 资源管理插件
    之所以写这个插件呢,就是为了方便整理项目中的资源文件,我记得之前好像也用了这么一个插件,但是也没去找,还是自己动手写一个吧,需要什么功能就看自己的需求。在项目的过程中呢,已......
  • 【Unity】 HTFramework框架(三十三)XLua热更新
    更新日期:2020年3月20日。Github源码:​​​[点我获取源码]​​​Gitee源码:​​[点我获取源码]​​索引​​XLua热更新简介​​​​使用XLua热更新​​​​创建XLua开发环境......
  • 【Unity】 HTFramework框架(三十二)授权验证
    更新日期:2020年3月2日。Github源码:​​​[点我获取源码]​​​Gitee源码:​​[点我获取源码]​​索引​​授权验证简介​​​​使用授权验证​​​​取消永久授权​​​​......
  • Unity插件 - MeshEditor(八)模型镜像特效
    将静态模型(带MeshFilter)按指定轴向、指定距离克隆一个镜像物体出来,思路很简单,将模型的顶点坐标按指定轴取反,并累加上设定的距离值,然后就完毕了!不过,因为镜像体的顶点镜像于之......
  • 【Unity】 HTFramework框架(三十一)全局设置
    更新日期:2020年3月2日。Github源码:​​​[点我获取源码]​​​Gitee源码:​​[点我获取源码]​​索引​​全局设置简介​​​​使用全局设置​​​​打开全局设置面板​​......
  • unity使用ugui自制调色面板
    突然想实现一个调色面板,然后开工...首先找找有没有什么接口可调,木有找到,找到一些调用win32实现的本地颜色面板的调用,感觉不科学,反正多平台肯定是搞不定的。既然没找到,还是老......
  • Unity 自定义创建脚本模板
    Unity自定义创建脚本模板原理:以模板代码为底板,通过关键字替换来实现代码创建两种实现方案方案11.先准备好对应的代码模板,放到Assets\ScriptTemplates目录下usingSys......
  • Unity中实现A*寻路
    前言:最近没事儿没工作,计划每天写一篇博客,防止对Unity生疏,也可以记录学习的点点滴滴。A*寻路在很多面试里都会问到,但实际工作中根本用不着自己写,网上有成熟的插件,不容易错......
  • Unity 脚本基础
    Unity官方手册是最好的教程书,只是偶尔限于冗长ScriptingconceptsAlthoughUnityusesanimplementationofthestandardMonoruntimeforscripting,itstillh......