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

这里先介绍方法1,先看效果:

残影用了alpha混合的方法,将它们变得透明。

先列出shader代码:

Shader "Custom/Ghost" {
Properties {
_MainTex ("Main Tex", 2D) = "white" {}
_Offset0 ("Offset 0", vector) = (, , , ) // 这里只显示4个残影,所以传入4个偏移值
_Offset1 ("Offset 1", vector) = (, , , )
_Offset2 ("Offset 2", vector) = (, , , )
_Offset3 ("Offset 3", vector) = (, , , )
} CGINCLUDE
#include "UnityCG.cginc" sampler2D _MainTex; float4 _Offset0;
float4 _Offset1;
float4 _Offset2;
float4 _Offset3; struct v2f {
float4 pos : POSITION;
float2 uv : TEXCOORD0;
};

    // 在shader中要渲染自身,以及4个残影,所以要定义5个不同的vert函数
v2f vert_normal(appdata_base v) { // 渲染自身的vert函数
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
o.uv = v.texcoord;
return o;
}
    // 渲染4个残影的vert函数
v2f vert_offset_1(appdata_base v) {
v2f o;
float4 pos = mul(_Object2World, v.vertex);
o.pos = mul(UNITY_MATRIX_VP, pos + _Offset0);
o.uv = v.texcoord;
return o;
} v2f vert_offset_2(appdata_base v) {
v2f o;
float4 pos = mul(_Object2World, v.vertex);
o.pos = mul(UNITY_MATRIX_VP, pos + _Offset1);
o.uv = v.texcoord;
return o;
} v2f vert_offset_3(appdata_base v) {
v2f o;
float4 pos = mul(_Object2World, v.vertex);
o.pos = mul(UNITY_MATRIX_VP, pos + _Offset2);
o.uv = v.texcoord;
return o;
} v2f vert_offset_4(appdata_base v) {
v2f o;
float4 pos = mul(_Object2World, v.vertex);
o.pos = mul(UNITY_MATRIX_VP, pos + _Offset3);
o.uv = v.texcoord;
return o;
}
    
     
    // 这里只定义了两个frag函数,分别是渲染自身,以及残影的
float4 frag_normal(v2f i) : COLOR {
return tex2D(_MainTex, i.uv);
} float4 frag_color(v2f i) : COLOR { // 将残影的alpha值设为0.5
float4 c;
c = tex2D(_MainTex, i.uv);
c.w = 0.5;
return c;
}
ENDCG SubShader { // 这里用4个pass来渲染残影,第5个pass渲染自身
Pass { // 从最远的开始渲染
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha CGPROGRAM
#pragma vertex vert_offset_4
#pragma fragment frag_color
ENDCG
} Pass {
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha CGPROGRAM
#pragma vertex vert_offset_3
#pragma fragment frag_color
ENDCG
} Pass {
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha CGPROGRAM
#pragma vertex vert_offset_2
#pragma fragment frag_color
ENDCG
} Pass {
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha CGPROGRAM
#pragma vertex vert_offset_1
#pragma fragment frag_color
ENDCG
} Pass { // 渲染自身,这时要开启 ZWrite
Blend SrcAlpha OneMinusSrcAlpha CGPROGRAM
#pragma vertex vert_normal
#pragma fragment frag_normal
ENDCG
}
}
FallBack "Diffuse"
}

看上去挺简单的。这里要注意的一点是,从c#脚本获取的offset值,是在世界坐标中获取的,所以在计算偏移时,要先将坐标转到世界坐标。

float4 pos = mul(_Object2World, v.vertex);
o.pos = mul(UNITY_MATRIX_VP, pos + _Offset0);

接着显示C#脚本:

using UnityEngine;
using System.Collections;
using System.Collections.Generic; [ExecuteInEditMode]
public class Ghost : MonoBehaviour {
public Shader curShader;
private List<Vector3> offsets = new List<Vector3>(); // 存储前几帧的坐标
private List<Material> mats = new List<Material>(); // 存储人物的材质,用于给shader传参数
// Use this for initialization
void Start ()
{
offsets.Add(transform.position);
offsets.Add(transform.position);
offsets.Add(transform.position);
offsets.Add(transform.position); var skinMeshRenderer = gameObject.GetComponentsInChildren<SkinnedMeshRenderer>();
foreach (var mr in skinMeshRenderer)
mats.Add(mr.material); var meshRenderer = gameObject.GetComponentsInChildren<MeshRenderer>();
foreach (var mr in meshRenderer)
mats.Add(mr.material); foreach (var mat in mats)
mat.shader = curShader;
} // Update is called once per frame
void Update () {
foreach (var mat in mats) // 每帧将之前的位置传入shader中
{
mat.SetVector("_Offset0", offsets[] - transform.position);
mat.SetVector("_Offset1", offsets[] - transform.position);
mat.SetVector("_Offset2", offsets[] - transform.position);
mat.SetVector("_Offset3", offsets[] - transform.position);
} offsets.Add(transform.position);
offsets.RemoveAt();
}
}

就这样,将C#脚本拖到GameObject身上就可以了

总结:

这个方法相对简单,问题就是,残影是和自身动作是一样的。如果要做成残影保留之前的动作,就需要记录动作参数,或者是直接保存前几帧的RenderTexture。

Unity Shader : Ghost(残影) v1的更多相关文章

  1. unity制作人物残影-绘制的方法

    这里是利用skinnedMeshRenderer原理做的 所以脚本需要挂在带这个组件的模型上 模型shader 必须要有个_Color参数属性,并且这个值可以调节颜色,会改变人物整体的透明度 [代码下 ...

  2. Unity运动残影技能

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

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

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

  4. Unity角色残影特效

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

  5. 【Unity Shader】从NDC(归一化的设备坐标)坐标转换到世界坐标的数学原理

    从NDC(归一化的设备坐标)坐标转换到世界坐标要点 参考资料 How to go from device coordinates back to worldspace http://feepingcr ...

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

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

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

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

  8. Unity Shader - 消融效果原理与变体

    基本原理与实现 主要使用噪声和透明度测试,从噪声图中读取某个通道的值,然后使用该值进行透明度测试. 主要代码如下: fixed cutout = tex2D(_NoiseTex, i.uvNoiseT ...

  9. Unity Shader 玻璃效果

    一个玻璃效果主要分为两个部分,一部分是折射效果的计算,另一部分则是反射.下面分类进行讨论: 折射: 1.利用Grass Pass对当前屏幕的渲染图像进行采样 2.得到法线贴图对折射的影响 3.对采集的 ...

随机推荐

  1. IntelliJ IDEA自动去掉行尾空格

    Settings→Editor→General 先选中Allow placement of caret after end of line 再修改Strip trailing spaces on Sa ...

  2. 拿nodejs快速搭建简单Oauth认证和restful API server攻略

    拿nodejs快速搭建简单Oauth认证和restful API server攻略:http://blog.csdn.net/zhaoweitco/article/details/21708955 最 ...

  3. FrameWork启动流程

    Android启动过程包含从Linux内核加载到Home应用程序启动的整个过程.整体流程如下: Android是基于Linux内核的系统平台.启动时,首先通过bootloader(系统加载器),加载L ...

  4. 黄聪:如何用Jquery或者插件解除网页禁用右键复制的限制(转)

    1.随便打开一个网址,放到收藏夹中. 2.复制下面的代码,替换原来网址的URL 选中复制以下代码 javascript:(function(){var doc=document;var bd=doc. ...

  5. NeHe OpenGL教程 第三十五课:播放AVI

    转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...

  6. [MySQL] 同步一张表、复制过滤设置

    一.缘由 据测试要求,需要把线上一张股票信息的表实时同步到测试环境,那么干吧,这次不复制库,单独复制表. 二.解决办法 可以按照同步(复制)库的方法来,在salve端设置 my.cnf,replica ...

  7. Java中类的加载、连接和初始化

    Java中类的加载.连接和初始化 类的加载.连接和初始化 先介绍一下JVM和类 JVM和类: 当我们调用Java命令运行某个Java程序时,该命令将会启动一个Java虚拟机进程,不管该Java程序有多 ...

  8. Ubuntu Server如何配置SFTP

    SH File Transfer Protocol是一个比普通FTP更为安全的文件传输协议.(参考资料:http://en.wikipedia.org/wiki/SSH_File_Transfer_P ...

  9. python 读取文本

    将文本转换到NumPy 数组中,做机器学习或其他任何任务,文本处理的技能必不可少.python 实现实现了很精简强大的文本处理功能: 假设 文件 traindata.csv 中有数据 1000行,3列 ...

  10. eclipse设置svn代理

    共2个步骤: 1. 找到C:\Documents and Settings\用户名\Application Data\Subversion的servers文件, 将#http-proxy-host和# ...