Unity Shader : Ghost(残影) v1
前阵子组长给我提了个需求,要实现角色人物的残影。我百度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的更多相关文章
- unity制作人物残影-绘制的方法
这里是利用skinnedMeshRenderer原理做的 所以脚本需要挂在带这个组件的模型上 模型shader 必须要有个_Color参数属性,并且这个值可以调节颜色,会改变人物整体的透明度 [代码下 ...
- Unity运动残影技能
残影实现: 1.List<DrawMesh> list,此list中包含某一帧动画模型网格.材质 2.每过一段时间就将运动物体的模型add到list中(优化:未实现,网格合并) 3.Lat ...
- cocos2dx - shader实现任意动画的残影效果
本节主要讲利用cocos2dx机制实现opengl es shader脚本的绘制 这里先看下最终效果: 这里分别实现了灰度效果及残影的效果. 一.绘制基类 这 ...
- Unity角色残影特效
残影特效在网上有很多例子,比如这个,我参考着自己整合了一下,算是整合了一个比较完整且特别简单易用的出来,只需要一个脚本挂上去无需任何设定就能用. 这里只针对SkinnedMeshRenderer的网格 ...
- 【Unity Shader】从NDC(归一化的设备坐标)坐标转换到世界坐标的数学原理
从NDC(归一化的设备坐标)坐标转换到世界坐标要点 参考资料 How to go from device coordinates back to worldspace http://feepingcr ...
- Unity3D手游开发日记(8) - 运动残影效果
2D游戏的残影很简单,美术做序列帧图片就行了,那么3D游戏的残影美术做不了,得靠程序员动态创建模型来处理. 实现原理也很简单: 1.间隔一定时间创建一个残影模型 GameObject go = Gam ...
- Unity3D-Shader-人物残影效果
[旧博客转移 - 2016年1月7日 00:24 ] 前面的话 上一篇讲了一下人物边缘发光效果,链接: Unity-ShaderLab-实现X光效果,这次我们利用这个Shader来实现人物残影效果 先 ...
- Unity Shader - 消融效果原理与变体
基本原理与实现 主要使用噪声和透明度测试,从噪声图中读取某个通道的值,然后使用该值进行透明度测试. 主要代码如下: fixed cutout = tex2D(_NoiseTex, i.uvNoiseT ...
- Unity Shader 玻璃效果
一个玻璃效果主要分为两个部分,一部分是折射效果的计算,另一部分则是反射.下面分类进行讨论: 折射: 1.利用Grass Pass对当前屏幕的渲染图像进行采样 2.得到法线贴图对折射的影响 3.对采集的 ...
随机推荐
- 使用laravel的Eloquent模型获取数据库的指定列
使用laravel的Eloquent模型获取数据库的指定列 使用Laravel的ORM——Eloquent时,时常遇到的一个操作是取模型中的其中一些属性,对应的就是在数据库中取表的特定列. 如果使 ...
- C#委托和事件讲解
委托 和 事件在 .Net Framework中的应用非常广泛,然而,较好地理解委托和事件对很多接触C#时间不长的人来说并不容易.它们就像是一道槛儿,过了这个槛的人,觉得真是太容易了,而没有过去的人每 ...
- M2的来源很简单
http://bbs.tianya.cn/post-develop-412703-1.shtml M2的来源很简单,一部分是外汇占款,这个是我们国家的缺陷,如果外汇不管制,其实是不会发生增长人民币的 ...
- elasticsearch2
简单认为是可以在命令行下访问url的一个工具 curl是利用URL语法在命令行方式下工作的开源文件传输工具,使用curl可以简单实现常见的get/post请求. curl -x 指定http请求的方法 ...
- (VS) TFS lost mapping suddenly.
家里的网络不是很稳定.今天突然发现 TFS 上所有的 mapping都突然没有了. 尝试去remapping,在Source Control Explorer 中右击源文件,然后选择 Advanced ...
- 【Android】源码external/目录中在编译过程中生成的文件列表
=> external/eyes-free: accessibilityvalidator.jar (host,share) => external/mesa3d: libMesa ...
- Java利用MessageDigest提供的MD5算法加密字符串或文件
MD5是常用的加密算法,也经常用于校验信息完整,如文件的完整性.用术语讲,MD5是一种消息摘要算法(Message Digest Algorithm).另外还有一种常用的消息摘要算法SHA1.如果想了 ...
- BestCoder Round #84 Bellovin
Bellovin 题意: 给个中文链接:戳戳戳 题解: 这个题其实就是让你求每一位的最长公共子序列,之后输出就好了,求这个有2个算法,一个是n方,另一个nlogn,所以显然是nlogn的算法,其实这就 ...
- mysql 正则
mysql 正则学习 基本字符匹配 select desk from dealer_info where desk regexp "82107777"; . 表示匹配任意一个字符 ...
- @Autowired失效
今天发现了一个使用@Autowired但是注入失败的问题. 后来发现原来是一个Validator中有@Autowired , 并试图注入一个service , 但是这个service始终是null , ...