您的位置:首页 > 移动开发 > Unity3D

Unity残影

2016-01-29 21:59 507 查看
可以用两种方式实现残影: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,要同时存在几种效果的时候会变得很麻烦
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: