Unity3D实战之残影技术
Posted 海洋_
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity3D实战之残影技术相关的知识,希望对你有一定的参考价值。
我们使用Unity3D开发动作类游戏或者RPG游戏时,为了增加战斗的效果,经常会使用残影技术,该技术可以使角色的动作更具有观赏性,可以使游戏品质更上一个台阶。本章实现了游戏中经常使用的残影技术,从原理到技术实现,完整的一个残影架构系统,方便移植到各种类型游戏开发中去。下面先给大家展示一下阴影实现的效果如下图所示。
3D残影与2D残影技术实现是截然不同的,2D残影的实现直接可以做成序列帧,然后放在程序里播放动画即可。而3D残影需要实现Mesh的克隆,克隆Mesh时需要注意的是残影每一帧都要去渲染,大家不要担心其帧数,在手机上跑没有任何问题,因为它只是生成几个Mesh,Mesh 的数量可以控制,Mesh身上的材质渲染也可以通过Shader去改变。它的原理就是在设定的时间内克隆出几个Mesh,因为残影需要一个淡入淡出效果,需要设置一个消失时间间隔,如果超出规定的时间就将其破坏掉,运行效果给人的感觉就好像一个人的速度快的只看到一个影子一样。这种效果在武侠小说里面经常会看到,它的实现跟以前实现的刀光拖尾原理非常类似,下面开始讲解残影的技术实现。
残影实现原理搞清楚了,接下来需要设计编码实现了,首先的问题是克隆出Mesh,这个需要每帧进行的,因为在实现残影的过程中,动作是一直播放的,这样才更具有观赏性,下面开始代码的编写,我们代码的名字是Canying.cs,先把完整的代码展示如下所示:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class CanYing : MonoBehaviour
public float interval = 0.1f;
public float lifeCycle = 2.0f;
float lastCombinedTime = 0.0f;
MeshFilter[] meshFilters = null;
MeshRenderer[] meshRenderers = null;
SkinnedMeshRenderer[] skinedMeshRenderers = null;
List<GameObject> objs = new List<GameObject>();
// Use this for initialization
void Start ()
meshFilters = gameObject.GetComponentsInChildren<MeshFilter>();
skinedMeshRenderers = gameObject.GetComponentsInChildren<SkinnedMeshRenderer>();
void OnDisable()
foreach (GameObject go in objs)
DestroyImmediate(go);
objs.Clear();
objs = null;
// 每帧更新
void Update ()
if (Time.time - lastCombinedTime > interval)
lastCombinedTime = Time.time;
for (int i = 0; skinedMeshRenderers != null && i < skinedMeshRenderers.Length; ++i)
Mesh mesh = new Mesh();
skinedMeshRenderers[i].BakeMesh(mesh);
GameObject go = new GameObject();
go.hideFlags = HideFlags.HideAndDontSave;
MeshFilter meshFilter = go.AddComponent<MeshFilter>();
meshFilter.mesh = mesh;
MeshRenderer meshRenderer = go.AddComponent<MeshRenderer>();
meshRenderer.material = skinedMeshRenderers[i].material;
InitFadeInObj(go, skinedMeshRenderers[i].transform.position,
skinedMeshRenderers[i].transform.rotation, lifeCycle);
for (int i = 0; meshFilters != null && i < meshFilters.Length; ++i)
GameObject go = Instantiate(meshFilters[i].gameObject) as GameObject;
InitFadeInObj(go, meshFilters[i].transform.position, meshFilters[i].transform.rotation, lifeCycle);
private void InitFadeInObj(GameObject go, Vector3 position, Quaternion rotation, float lifeCycle)
go.hideFlags = HideFlags.HideAndDontSave;
go.transform.position = position;
go.transform.rotation = rotation;
FadInOut fi = go.AddComponent<FadInOut>();
fi.lifeCycle = lifeCycle;
objs.Add(go);
说一下代码编写思路,在代码中声明了几个数组变量:
MeshFilter[] meshFilters = null;
SkinnedMeshRenderer[] skinedMeshRenderers = null;
用于存放已有对象子类的meshFilters组件网格和SkinnedMeshRender组件蒙皮网格渲染,这个可以在Start初始化函数中有对其赋值,函数代码如下所示:
void Start ()
meshFilters = gameObject.GetComponentsInChildren<MeshFilter>();
skinedMeshRenderers = gameObject.GetComponentsInChildren<SkinnedMeshRenderer>();
残影的生成是在Update函数中,残影是有生命周期的,加了一个时间条件判断语句如下:
Time.time - lastCombinedTime > interval
接下来遍历蒙皮网格渲染组件SkinnedMeshRender,因为残影的生成是根据动作而变化的,每帧都要获取到角色动作,遍历skinedMeshRenderers组件代码如下:
for (int i = 0; skinedMeshRenderers != null && i < skinedMeshRenderers.Length; ++i)
{}
在遍历的过程中要自己创建生成网格,而且要把对应的网格根据SkinnedMeshRender组件的函数BaekMesh把动作蒙皮实现出来,再通过new GameObject重新生成一个对象,把其对应的组件逐步赋值给它也包括材质,这样就完成了残影的绘制,核心代码如下:
Mesh mesh = new Mesh();
skinedMeshRenderers[i].BakeMesh(mesh);
GameObject go = new GameObject();
go.hideFlags = HideFlags.HideAndDontSave;
MeshFilter meshFilter = go.AddComponent<MeshFilter>();
meshFilter.mesh = mesh;
MeshRenderer meshRenderer = go.AddComponent<MeshRenderer>();
meshRenderer.material = skinedMeshRenderers[i].material;
在代码的最后调用了函数:
InitFadeInObj(go, skinedMeshRenderers[i].transform.position,
skinedMeshRenderers[i].transform.rotation, lifeCycle);
该函数主要作用是实现残影的淡入淡出效果。因为角色的生成的残影位置和旋转都是不同的,而且它们都有自己的生命周期,函数内容如下:
go.hideFlags = HideFlags.HideAndDontSave;
go.transform.position = position;
go.transform.rotation = rotation;
FadInOut fi = go.AddComponent<FadInOut>();
fi.lifeCycle = lifeCycle;
objs.Add(go);
在上面语句中增加了组件FadInOut用于淡入淡出效果,这个在后面会把代码给出。下面再把思路总结一下:在Update函数里面主要的作用是每一帧生成MeshFilter,同时捕捉每一帧的动作实时绘制Mesh。InitFadeInObj函数主要的作用是处理绘制出来的Mesh,并且按照一定的时间间隔将其销毁掉,同时为了表现出好的效果,可以用自己的Shader替换原有角色的Shader,详情查看笔者已出版书籍《Unity3D实战核心技术详解》一书。实现的效果:
效果非常绚丽,该技术可以运行在移动端游戏中,目前该技术已应用到了项目开发中,其中残影的效果可以通过参数进行调整,比如残影绘制的时间间隔,残影的材质设置等。
作者简介:姜雪伟个人网页
以上是关于Unity3D实战之残影技术的主要内容,如果未能解决你的问题,请参考以下文章
Unity3d VFX 采用skinned mesh sampling(蒙皮采样)发射粒子效果时fbx模型是否优化(Optimized)带来的问题记录
Unity3D OpenVR 虚拟现实 保龄球打砖块游戏开发
Unity3D OpenVR 虚拟现实 保龄球打砖块游戏开发