前阵子组长给我提了个需求,要实现角色人物的残影。我百度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. bzoj2618: [Cqoi2006]凸多边形

    Description 逆时针给出n个凸多边形的顶点坐标,求它们交的面积.例如n=2时,两个凸多边形如下图: 则相交部分的面积为5.233. Input 第一行有一个整数n,表示凸多边形的个数,以下依 ...

  2. Config Advisor

    Description: Config Advisor Overview Config Advisor is a configuration validation and health check t ...

  3. pgsql 9.4修改数据库只读

    先进入psql 切换到目标数据库 \c mydb 对于老表 grant usage on schema public to $read_only_user; grant select on all t ...

  4. gcc链接参数--whole-archive的作用

    // a.h extern void foo(); // a.cpp #include <stdio.h> void foo() { printf("foo\n"); ...

  5. 【转】页面跳转Transfer与Redirect的区别你知道吗?

    一 前言 关于页面跳转的方式常用的应该就是,链接跳转,js跳转,Server.Tranfser和Response.Redirect 这几种,可是在Tranfser与Redirect之间用哪种更好(本文 ...

  6. JavaScript中回调函数的使用

    在JavaScript中,回调函数具体的定义为:函数A作为参数(函数引用)传递到另一个函数B中,并且这个函数B执行函数A.我们就说函数A叫做回调函数.如果没有名称(函数表达式),就叫做匿名回调函数. ...

  7. Tomcat远程调试catalina.sh的配置

    #!/bin/sh # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license ...

  8. Android流量统计TrafficStats类

    对于Android流量统计来说在2.2版中新加入了TrafficStats类可以轻松获取,其实本身TrafficStats类也是读取Linux提供的文件对象系统类型的文本进行解析. android.n ...

  9. spring学习笔记2(转)

    1.在Java开发领域,spring相对于EJB来说是一种轻量级的,非侵入性的Java开发框架,曾经有两本很畅销的书<Expert one-on-one J2EE Design and Deve ...

  10. Top 6 Programming Languages for Mobile App Development

    Mobile application development industry in the last five years have multiplied in leaps and bounds, ...