可以用两种方式实现残影:1. 新建一个Mesh,记录前几帧的人物的影像,然后通过后处理混合上去。2.记录前几帧的人物位置,将其传入shader中,对每个位置进行一个pass渲染。
第一方式
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class AfterImage : MonoBehaviour
{
List<List<GameObject>> _meshGoList = new List<List<GameObject>>();
List<SkinnedMeshRenderer> _renderList= new List<SkinnedMeshRenderer>();
Shader _curShader;
Shader CurShader
{
get
{
if(_curShader == null)
{
_curShader = Shader.Find("Custom/AfterImage");
}
return _curShader;
}
}
// Use this for initialization
void Start ()
{
var renders = gameObject.GetComponentsInChildren<SkinnedMeshRenderer>();
_renderList.AddRange(renders);
}
int num = 1;
int max = 5;
float interval = 0.1f;
float deltaTime = 0;
private void DeEffect()
{
List<GameObject> meshList = new List<GameObject>();
for(int i = 0; i < _renderList.Count; ++i)
{
string meshName = string.Format("meshName_{0}_{1}", num, i);
GameObject meshGo = new GameObject(meshName);
meshGo.transform.position = _renderList[i].gameObject.transform.position;
meshGo.transform.localRotation = _renderList[i].gameObject.transform.localRotation;
Mesh mesh = new Mesh();
_renderList[i].BakeMesh(mesh);
MeshFilter meshFilter = meshGo.AddComponent<MeshFilter>();
meshFilter.mesh = mesh;
MeshRenderer skin = meshGo.AddComponent<MeshRenderer>();
skin.material = GetMaterial(_renderList[i].material);
// skin.material = _renderList[i].material;
meshList.Add(meshGo);
}
_meshGoList.Add(meshList);
num += 1;
}
private Material GetMaterial(Material mat)
{
Material nMat = new Material(CurShader);
nMat.SetTexture("_MainTex", mat.mainTexture);
return nMat;
}
// Update is called once per frame
void Update ()
{
if (deltaTime >= interval)
{
DeEffect();
deltaTime = 0f;
}
else
{
deltaTime += Time.deltaTime;
}
if(_meshGoList.Count > 5)
{
for(int i = 0; i < _meshGoList.Count - max; ++i)
{
if(_meshGoList[i] != null)
{
for(int j = 0; j < _meshGoList[i].Count; ++j)
{
if(_meshGoList[i][j] != null)
{
DestroyImmediate(_meshGoList[i][j]);
}
}
}
}
for(int i = 0; i < _meshGoList.Count - max; ++i)
{
_meshGoList.RemoveAt(0);
}
}
}
}
Shader "Custom/AfterImage"
{
Properties
{
_Color ("Color", Color) = (1,0.8,1,0.5)
_MainTex ("Albedo (RGB)", 2D) = "white" {}
}
SubShader {
Tags {"Queue" = "Transparent" "LightMode" = "Always" "RenderType"="Opaque"}
Pass
{
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
sampler2D _MainTex;
fixed4 _Color;
struct v2f
{
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
};
v2f vert( appdata_base v)
{
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
o.uv = v.texcoord;
return o;
}
fixed4 frag(v2f i) : COLOR
{
float4 c;
c = tex2D(_MainTex, i.uv);
c = c * _Color;
return c;
}
ENDCG
}
}
FallBack "Diffuse"
}
把这个脚本挂到要产生残影的物体上就可以看到残影了
第二种方法(主要参考http://www.cnblogs.com/foxianmo/p/4946116.html?utm_source=tuicool&utm_medium=referral)
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class Ghost : MonoBehaviour {
public Shader curShader;
private List<Vector3> offsets = new List<Vector3>();
private List<Material> mats = new List<Material>();
// 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);
}
foreach(var mat in mats)
{
mat.shader = curShader;
}
}
// Update is called once per frame
void Update ()
{
foreach(var mat in mats)
{
mat.SetVector("_Offset0", offsets[3] - transform.position);
mat.SetVector("_Offset1", offsets[2] - transform.position);
mat.SetVector("_Offset2", offsets[1] - transform.position);
mat.SetVector("_Offset3", offsets[0] - transform.position);
}
offsets.Add(transform.position);
offsets.RemoveAt(0);
}
}
Shader "Custom/Ghosh" {
Properties {
_MainTex ("Albedo (RGB)", 2D) = "white" {}
_Offset0("Offset 0", vector) = (0, 0, 0, 0)
_Offset1("Offset 1", vector) = (0, 0, 0, 0)
_Offset2("Offset 2", vector) = (0, 0, 0, 0)
_Offset3("Offset 3", vector) = (0, 0, 0, 0)
}
CGINCLUDE
#include "UnityCG.cginc"
sampler2D _MainTex;
float4 _Offset0;
float4 _Offset1;
float4 _Offset2;
float4 _Offset3;
struct v2f
{
float4 pos : POSITION;
float2 uv : TEXCOORD0;
};
v2f vert_normal( appdata_base v)
{
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
o.uv = v.texcoord;
return o;
}
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;
}
float4 frag_normal(v2f i) : COLOR
{
return tex2D(_MainTex, i.uv);
}
float4 frag_color(v2f i) : COLOR
{
float4 c;
c = tex2D(_MainTex, i.uv);
c.w = 0.5;
return c;
}
ENDCG
SubShader
{
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
{
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert_normal
#pragma fragment frag_normal
ENDCG
}
}
FallBack "Diffuse"
}
同样是把脚本挂到要产生残影的物体上就可以看到残影
个人比较喜欢第一种方法,第二种方法要更改原物体的shader,要同时存在几种效果的时候会变得很麻烦