前阵子组长给我提了个需求,要实现角色人物的残影。我百度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. 提示“应用程序无法启动,因为应用程序的并行配置不正确”不能加载 System.Data.SQLite.dll

    新版本SQLITE,如果下载Precompiled Binaries版会出现提示“应用程序无法启动,因为应用程序的并行配置不正确”不能加载 System.Data.SQLite.dll. 下载Prec ...

  2. hyper-v 中 安装 Centos 7.0 设置网络 教程

    安装环境是: 系统:win server 2012 r2 DataCenter hyper-v版本:6.3.9600.16384 centos版本:7.0 从网上下载的 centos 7.0  如果找 ...

  3. 【Java编程进阶-1】enum枚举的使用

    枚举主要用于枚举常量,下面举个简单的应用. 比如一个公司有如下几个部门: 研发部: 销售部: 财务部: (其他部门暂时不列举) 部门的某些信息相对固定,此时可以考虑使用枚举来说明: 枚举类 Depts ...

  4. Django数据库设计中字段为空的方式

    今天在做数据库设计的时候,设计了如下User表,其中我把email和phone字段设置为允许为空: class User(models.Model): username = models.CharFi ...

  5. RDA 编译器的搭建

    apt-get install subversion apt-get install make atp-get install gcc sudo vim /etc/profile export PAT ...

  6. (C/C++ interview) Static 详解

    C Static http://stackoverflow.com/questions/572547/what-does-static-mean-in-a-c-program Static could ...

  7. (C/C++) Interview in English - Threading

    Q. What's the process and threads and what's the difference between them? A.  A process is an execut ...

  8. spark MapOutputTrackerMaster

    最近用了一个RowNumber() over()函数 进行三张4000万数据的关联筛选,建表语句如下: create table CiCustomerPortrait2 as SELECT ROW_N ...

  9. DBA_VMware虚拟机安装和简介(案例)

    2014-08-08 Created By BaoXinjian

  10. Report_客制化Excel报表中的XLS标记(案例)

    2014-06-06 Created By BaoXinjian