转载出处: 李嘉的博客 - http://www.cnblogs.com/lijiajia
先看一下效果:
大概的原理
- 创建残影:拷贝人物当前Mesh数据作为残影,用MeshFilter+MeshRenderer渲染出来
- 残影有生命周期、创建间隔:残影从创建到慢慢消失的过程,这里采用透明度淡出
- 使用X光Shader
Mesh mesh = new Mesh (); meshRender[i].BakeMesh(mesh);
BakeMesh拷贝网格
拷贝网格很简单,调用SkinnedMeshRenderer的BakeMesh方法
用MeshFilter跟MeshRenderer渲染网格
MeshFilter filter = go.AddComponent<MeshFilter>(); filter.mesh = mesh; MeshRenderer meshRen = go.AddComponent<MeshRenderer>(); meshRen.material = meshRender[i].material; meshRen.material.shader = ghostShader;//设置xray效果
MeshFilter:网格过滤器用于从你的资源中获取网格信息(Mesh)并将其传递到用于将其渲染到屏幕的网格渲染器当中
MeshRenderer:但是想要渲染出网格,还需要用到MeshRenderer哦。
完整代码
using UnityEngine; using System.Collections; using System.Collections.Generic; public class GhostShadow : MonoBehaviour { //持续时间 public float duration = 2f; //创建新残影间隔 public float interval = 0.1f; //边缘颜色强度 [Range(-1, 2)] public float Intension = 1; //网格数据 SkinnedMeshRenderer[] meshRender; //X-ray Shader ghostShader; void Start() { //获取身上所有的Mesh meshRender = this.gameObject.GetComponentsInChildren<SkinnedMeshRenderer>(); ghostShader = Shader.Find("lijia/Xray"); } private float lastTime = 0; private Vector3 lastPos = Vector3.zero; void Update() { //人物有位移才创建残影 if (lastPos == this.transform.position) { return; } lastPos = this.transform.position; if (Time.time - lastTime < interval) {//残影间隔时间 return; } lastTime = Time.time; if (meshRender == null) return; for (int i = 0; i < meshRender.Length; i++) { Mesh mesh = new Mesh(); meshRender[i].BakeMesh(mesh); GameObject go = new GameObject(); go.hideFlags = HideFlags.HideAndDontSave; GhostItem item = go.AddComponent<GhostItem>();//控制残影消失 item.duration = duration; item.deleteTime = Time.time + duration; MeshFilter filter = go.AddComponent<MeshFilter>(); filter.mesh = mesh; MeshRenderer meshRen = go.AddComponent<MeshRenderer>(); meshRen.material = meshRender[i].material; meshRen.material.shader = ghostShader;//设置xray效果 meshRen.material.SetFloat("_Intension", Intension);//颜色强度传入shader中 go.transform.localScale = meshRender[i].transform.localScale; go.transform.position = meshRender[i].transform.position; go.transform.rotation = meshRender[i].transform.rotation; item.meshRenderer = meshRen; } } }
GhostItem
using System; using UnityEngine; public class GhostItem : MonoBehaviour { //持续时间 public float duration; //销毁时间 public float deleteTime; public MeshRenderer meshRenderer; void Update() { float tempTime = deleteTime - Time.time; if (tempTime <= 0) {//到时间就销毁 GameObject.Destroy(this.gameObject); } else if (meshRenderer.material) { float rate = tempTime / duration;//计算生命周期的比例 Color cal = meshRenderer.material.GetColor("_RimColor"); cal.a *= rate;//设置透明通道 meshRenderer.material.SetColor("_RimColor", cal); } } }
shader:
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)' Shader "lijia/Xray" { Properties { _RimColor("RimColor", Color) = (0, 0, 1, 1) _RimIntensity("Intensity", Range(0, 2)) = 1 } SubShader { Tags {"Queue" = "Transparent" "RenderType" = "Opaque" } LOD 200 Pass { Blend SrcAlpha One//打开混合模式 ZWrite off Lighting off CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float3 normal:Normal; }; struct v2f { float4 pos : SV_POSITION; fixed4 color : COLOR; }; fixed4 _RimColor; float _RimIntensity; v2f vert(appdata v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); float3 viewDir = normalize(ObjSpaceViewDir(v.vertex));//计算出顶点到相机的向量 float val = 1 - saturate(dot(v.normal, viewDir));//计算点乘值 o.color = _RimColor * val * (1 + _RimIntensity);//计算强度 return o; } fixed4 frag(v2f i) : COLOR { return i.color; } ENDCG } } }
缺点是比较消耗性能,频繁创建网格,相当于要多渲染那么多个人物。