Unity角色残影特效
残影特效在网上有很多例子,比如这个,我参考着自己整合了一下,算是整合了一个比较完整且特别简单易用的出来,只需要一个脚本挂上去无需任何设定就能用。
这里只针对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角色残影特效的更多相关文章
- Unity运动残影技能
残影实现: 1.List<DrawMesh> list,此list中包含某一帧动画模型网格.材质 2.每过一段时间就将运动物体的模型add到list中(优化:未实现,网格合并) 3.Lat ...
- cocos2dx - shader实现任意动画的残影效果
本节主要讲利用cocos2dx机制实现opengl es shader脚本的绘制 这里先看下最终效果: 这里分别实现了灰度效果及残影的效果. 一.绘制基类 这 ...
- Unity3d 残影效果(狂拽炫酷叼炸天)
效果图,真的很叼啊 我根据别人的改进了一版,支持MeshFilter上的Mesh(需要确保Mesh的Read/Write是开启的否则不能正常工作) 非常感谢原作者给提供思路.http://blog.c ...
- Unity Shader : Ghost(残影) v1
前阵子组长给我提了个需求,要实现角色人物的残影.我百度google了一下,发现可以用两种方式实现这个效果:1.记录前几帧的人物位置,将其传入shader中,对每个位置进行一个pass渲染.2. 通过相 ...
- Win7去除桌面残影的方法
用户升级到Win7系统后使用正常,就是系统桌面会留有残影,怎么样也去不掉,影响用户的使用,那么要如何将这些残影去掉呢?可从计算机属性中进行相关配置. 解决方法 一.在计算机面板上,右键点击“计算机”, ...
- as3如何做出残影效果
在页游中,时不时能看到人物做一些快速移动动作如冲刺时,有残影效果,强化了画面表现.实际人肉眼之所以能看到残影的效果,是因为观察到的物体会在人视线中残留几十毫秒时间,当运动物体运动太快时,人肉眼所见未能 ...
- Unity3D手游开发日记(8) - 运动残影效果
2D游戏的残影很简单,美术做序列帧图片就行了,那么3D游戏的残影美术做不了,得靠程序员动态创建模型来处理. 实现原理也很简单: 1.间隔一定时间创建一个残影模型 GameObject go = Gam ...
- HDOJ(HDU) 2153 仙人球的残影(谜一样的题、、、)
Problem Description 在美丽的HDU,有一名大三的同学,他的速度是众所周知的,跑100米仅仅用了2秒47,在他跑步过程中会留下残影的哎,大家很想知道他是谁了吧,他叫仙人球,既然名字这 ...
- Unity3D-Shader-人物残影效果
[旧博客转移 - 2016年1月7日 00:24 ] 前面的话 上一篇讲了一下人物边缘发光效果,链接: Unity-ShaderLab-实现X光效果,这次我们利用这个Shader来实现人物残影效果 先 ...
随机推荐
- [NOIp 2016]换教室
Description 对于刚上大学的牛牛来说,他面临的第一个问题是如何根据实际情况申请合适的课程. 在可以选择的课程中,有 $2n$ 节课程安排在 $n$ 个时间段上.在第 $i$($1 \leq ...
- UVA - 11468:Substring
随机生成一个字符可以看成在AC自动机里面向前走一个节点,那么ans就是0向前走L步并且不经过单词节点, 由概率知识可得,f[p][L]=∑f[nxt[p][i]][L-1]*g[i] 其中p表示位于p ...
- SAM维护的在线LCS
题目大意: 给定两个字符串,存在三种操作,分别是在a,b串末尾加一个字符串,和询问两串的LCS 题解: Get新套路:把两串建在同一SAM上,将重合的位置合并为同一节点,再加个标记数组,如果两者的LC ...
- bzoj3224Tyvj 1728 普通平衡树 treap
3224: Tyvj 1728 普通平衡树 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 17706 Solved: 7764[Submit][St ...
- Go实现海量日志收集系统(三)
再次整理了一下这个日志收集系统的框,如下图 这次要实现的代码的整体逻辑为: 完整代码地址为: https://github.com/pythonsite/logagent etcd介绍 高可用的分布式 ...
- PHP Laravel框架入门心得 | How to study PHP Laravel Framework
PHP有不少开发框架,其中比较出名的有Symfony和Laravel. 我说说我最近入门Laravel的感受和学习方法吧. 1.第一个感受是Laravel的社区讨论和学习资源真的是太棒了,中文化也做得 ...
- UDA机器学习基础—误差原因
1.模型误差产生的原因 (1)模型无法表示基本数据的复杂度,而造成偏差. (2)因模型对训练它所用到的数据过度敏感造成的方差. 2.由偏差造成的误差--准确率和欠拟合 有足够数据表示模型,但是由于模型 ...
- MFC 程序入口和执行流程
MFC(微软基础类库)以C++类的形式封装了Windows API,给开发者提供了便利,但是初学者常常会疑惑MFC程序的入口在哪里?下面给大家简单介绍一下MFC 程序入口和执行流程. 一 MFC程序执 ...
- python2.7练习小例子(二)
2):题目:企业发放的奖金根据利润提成.利润(I)低于或等于10万元时,奖金可提10%:利润高于10万元,低于20万元时,低于10万元的部分按10%提成,高于10万元的部分,可提成7.5%:2 ...
- 构建纯TypeScript应用
构建纯TypeScript应用 现在只有命令行应用的例子. 前言 现在,应用开发的趋势是命令行接口应用和Web应用. node.js 和 typescript的崛起所以,这里讨论如何创建纯的TypeS ...