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

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

三、效果图如下:

四、我将完整的源码贴一遍,只需要新建一个脚本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;
}
}

Unity角色残影特效的更多相关文章

  1. Unity运动残影技能

    残影实现: 1.List<DrawMesh> list,此list中包含某一帧动画模型网格.材质 2.每过一段时间就将运动物体的模型add到list中(优化:未实现,网格合并) 3.Lat ...

  2. cocos2dx - shader实现任意动画的残影效果

    本节主要讲利用cocos2dx机制实现opengl es shader脚本的绘制 这里先看下最终效果:                      这里分别实现了灰度效果及残影的效果. 一.绘制基类 这 ...

  3. Unity3d 残影效果(狂拽炫酷叼炸天)

    效果图,真的很叼啊 我根据别人的改进了一版,支持MeshFilter上的Mesh(需要确保Mesh的Read/Write是开启的否则不能正常工作) 非常感谢原作者给提供思路.http://blog.c ...

  4. Unity Shader : Ghost(残影) v1

    前阵子组长给我提了个需求,要实现角色人物的残影.我百度google了一下,发现可以用两种方式实现这个效果:1.记录前几帧的人物位置,将其传入shader中,对每个位置进行一个pass渲染.2. 通过相 ...

  5. Win7去除桌面残影的方法

    用户升级到Win7系统后使用正常,就是系统桌面会留有残影,怎么样也去不掉,影响用户的使用,那么要如何将这些残影去掉呢?可从计算机属性中进行相关配置. 解决方法 一.在计算机面板上,右键点击“计算机”, ...

  6. as3如何做出残影效果

    在页游中,时不时能看到人物做一些快速移动动作如冲刺时,有残影效果,强化了画面表现.实际人肉眼之所以能看到残影的效果,是因为观察到的物体会在人视线中残留几十毫秒时间,当运动物体运动太快时,人肉眼所见未能 ...

  7. Unity3D手游开发日记(8) - 运动残影效果

    2D游戏的残影很简单,美术做序列帧图片就行了,那么3D游戏的残影美术做不了,得靠程序员动态创建模型来处理. 实现原理也很简单: 1.间隔一定时间创建一个残影模型 GameObject go = Gam ...

  8. HDOJ(HDU) 2153 仙人球的残影(谜一样的题、、、)

    Problem Description 在美丽的HDU,有一名大三的同学,他的速度是众所周知的,跑100米仅仅用了2秒47,在他跑步过程中会留下残影的哎,大家很想知道他是谁了吧,他叫仙人球,既然名字这 ...

  9. Unity3D-Shader-人物残影效果

    [旧博客转移 - 2016年1月7日 00:24 ] 前面的话 上一篇讲了一下人物边缘发光效果,链接: Unity-ShaderLab-实现X光效果,这次我们利用这个Shader来实现人物残影效果 先 ...

随机推荐

  1. JS随机数不重复

    方法一 思路:首先创建一个1到3000的数组,每次取一个数,然后去除数组中取出的这个数, 这样就可以实现永不重复. var count=3000; var originalArray=new Arra ...

  2. 如何设计一款APP,才能吸引用户眼球

    有APP分析机构研究表明,人们每天耗费在手机和平板上的平均时长为158分钟,其中127分钟是耗费在各类APP中,而仅有31分钟是花费在浏览网页上.随着人们对互联网的依赖性越来越强,移动APP发展迅速已 ...

  3. [C#]设计模式-单例模式-创建型模式

    单例模式用于在整个软件系统当中保持唯一实例,在 C# 当中最能够体现此概念的就是静态类,静态类的生命周期是跟随整个程序,并且在整个程序中仅保有一个实例. 不过在这里我们不再详细阐述单例模式与静态类有什 ...

  4. git中的merge与rebase

    之前一直对git的merge与rebase很困惑,而且一般也只使用merge而不是使用rebase.今天受高人指点理清了两者的区别. 首先对于两者而言,他们的结果是一样的,差异在于合并的方式(产生的结 ...

  5. ML笔记:Classification: Logistic Regression

  6. 机器学习基石:16 Three Learning Principles

    三个理论上界: 三个线性模型: 三个关键工具: 三条学习规则: 1.奥卡姆剃刀定律 先从简单模型开始, 训练后出现欠拟合, 再尝试复杂点模型. 2.采样误差 训练.验证.测试数据尽量同分布. 3.数据 ...

  7. [SCOI 2016]背单词

    Description Lweb 面对如山的英语单词,陷入了深深的沉思,“我怎么样才能快点学完,然后去玩三国杀呢?”.这时候睿智 的凤老师从远处飘来,他送给了 Lweb 一本计划册和一大缸泡椒,他的计 ...

  8. sdut 2878 圆圈

    [ 题目描述]现在有一个圆圈, 顺时针标号分别从 0 到 n-1, 每次等概率顺时针走一步或者逆时针走一步,即如果你在 i 号点,你有 1/2 概率走到((i-1)mod n)号点,1/2 概率走到( ...

  9. C++Primer学习——未定义行为

    定义: 主要是求值顺序的问题 int i = f1() + f2();          //我们无法知道是f1 还是 f2先被调用 而且求值顺序和优先级和结合律无关,比如: f() + g()*h( ...

  10. 一起来Fit TDMA over WiFi(3)

    4 TDMA调度者 TDMA调度者为Fit-TDMA的决策功能体,属于新开发功能模块,分调度员和被调度者2种角色,其中前者运行在AP等汇聚设备上,后者运行在CPE等接入类设备上:后者必须与前者配合才能 ...