Unity实时运动残影特效
2017-09-13 15:26
441 查看
效果图:
没有动画的通过MeshFilter获取Mesh
我是偷懒用Shader Forge拖的shader
Shader比较简单,主要算法只有法线与观察向量的点乘,然后用1减去点乘结果。最后叠加一个颜色就得到了边缘发光的效果。
Shader代码:
残影有透明效果,所以是不需要抛阴影和接收阴影的,Shader Forge默认FallBack到Diffuse,Diffuse对阴影进行了处理。所以需要把FallBack删掉或改为没有处理阴影的Shader
实现原理:
复制模型当前时间点的Mesh,然后将Mesh全部绘制出来,并修改Shader的Alpha通道实现淡出的效果方法一:
由于骨骼蒙皮动画的Mesh是随着动画改变的,要捕捉人物变化的形态需要实时获取人物Mesh并渲染出来。1.获取当前Game Object节点下的所有Mesh:
带有蒙皮的需要通过SkinnedMeshRenderer组件,调用SkinnedMeshRenderer.BakeMesh(Mesh)获取当前动画的实时Mesh。没有动画的通过MeshFilter获取Mesh
2.创建GameObject将Mesh渲染出来
代码:using System.Collections; using System.Collections.Generic; using UnityEngine; public class ShadowTail : MonoBehaviour { private MeshFilter[] meshFilter = null; private SkinnedMeshRenderer[] skinMeshRender = null; private Animator animt = null; [Range(1f, 10f)] public float createSpeed = 5f;//创建残影的时间间隔 public float fadeOutSpeed = 1.5f;//淡出的速率 private float previousTime = 0;//用于纪录上次创建残影的时间点 private void Awake() { animt = GetComponent<Animator>(); meshFilter = GetComponentsInChildren<MeshFilter>(); skinMeshRender = GetComponentsInChildren<SkinnedMeshRenderer>(); } void Update() { if (animt.GetFloat("speed") > 0.1 && (animt.GetBool("b_walk") || animt.GetBool("b_walkback")))//疾跑时显示残影 { if (Time.time - previousTime >= createSpeed * Time.deltaTime) { //每隔时段创建一个幻影 GameObject shadowObj = new GameObject("Shadow"); foreach (MeshFilter tempMF in meshFilter) { GameObject obj = new GameObject("Mesh"); obj.transform.SetPositionAndRotation(tempMF.transform.position, tempMF.transform.rotation); MeshFilter mf = obj.AddComponent<MeshFilter>(); MeshRenderer mr = obj.AddComponent<MeshRenderer>(); //禁止投射阴影和接收阴影 mr.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off; mr.receiveShadows = false; mf.mesh = tempMF.mesh; mr.material.shader = Shader.Find("Shader Forge/XRay"); obj.transform.SetParent(shadowObj.transform); StartCoroutine(FadeOut(mr)); } foreach (SkinnedMeshRenderer tempMR in skinMeshRender) { GameObject obj = new GameObject("SkinMesh"); obj.transform.SetPositionAndRotation(tempMR.transform.position, tempMR.transform.rotation); MeshFilter mf = obj.AddComponent<MeshFilter>(); MeshRenderer mr = obj.AddComponent<MeshRenderer>(); mr.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off; mr.receiveShadows = false; tempMR.BakeMesh(mf.mesh); mr.material.shader = Shader.Find("Shader Forge/XRay");//残影Shader obj.transform.SetParent(shadowObj.transform); StartCoroutine(FadeOut(mr)); } previousTime = Time.time; } } } IEnumerator FadeOut(MeshRenderer mr)//淡出效果 { var mat = mr.material; float alpha = 0; while (mat.GetFloat("_Alpha") > 0) { alpha = mat.GetFloat("_Alpha") - fadeOutSpeed * Time.deltaTime; mat.SetFloat("_Alpha", alpha > 0 ? alpha : 0); yield return 0; } Destroy(mr.transform.parent.gameObject); } }
方法二:
方法一的代码过于复杂,实时复制Mesh本就很消耗性能,又加上GameObject的不停创建销毁,效率很低。1.获取当前Game Object节点下的所有Mesh放入List
2.通过Graphics.DrawMesh()将所有Mesh绘制出来
代码:using System.Collections; using System.Collections.Generic; using UnityEngine; public class ShadowTail : MonoBehaviour { private MeshFilter[] meshFilter = null; private SkinnedMeshRenderer[] skinMeshRender = null; private Animator animt = null; [Range(1f, 10f)] public float createSpeed = 5f;//创建残影的时间间隔 public float fadeOutSpeed = 1.5f;//淡出的速率 private float previousTime = 0;//用于纪录上次创建残影的时间点 private void Awake() { animt = GetComponent<Animator>(); meshFilter = GetComponentsInChildren<MeshFilter>(); skinMeshRender = GetComponentsInChildren<SkinnedMeshRenderer>(); } private struct MeshInfo { public Mesh _mesh; public Matrix4x4 _matrix;//用于确定对应mesh绘制的位置 public Material _material; }; private List<MeshInfo> meshList = new List<MeshInfo>(); private void Update() { for (int i = 0; i < meshList.Count; i++) { Graphics.DrawMesh(meshList[i]._mesh, meshList[i]._matrix, meshList[i]._material, gameObject.layer); float alpha = 0; if (meshList[i]._material.GetFloat("_Alpha") > 0) { alpha = meshList[i]._material.GetFloat("_Alpha") - fadeOutSpeed * Time.deltaTime; meshList[i]._material.SetFloat("_Alpha", alpha > 0 ? alpha : 0); } else { meshList.Remove(meshList[i]); } } if (animt.GetFloat("speed") > 0.1 && (animt.GetBool("b_walk") || animt.GetBool("b_walkback"))) { if (Time.time - previousTime >= createSpeed * Time.deltaTime) { foreach (var mf in meshFilter) { MeshInfo info = new MeshInfo(); info._mesh = mf.mesh; info._matrix = mf.transform.localToWorldMatrix; info._material = new Material(Shader.Find("Shader Forge/XRay")); meshList.Add(info); } foreach (var mr in skinMeshRender) { Mesh m = new Mesh(); MeshInfo info = new MeshInfo(); mr.BakeMesh(m); info._mesh = m; info._matrix = mr.transform.localToWorldMatrix; info._material = new Material(Shader.Find("Shader Forge/XRay")); meshList.Add(info); } previousTime = Time.time; } } } }残影Shader的实现:
我是偷懒用Shader Forge拖的shader
Shader比较简单,主要算法只有法线与观察向量的点乘,然后用1减去点乘结果。最后叠加一个颜色就得到了边缘发光的效果。
Shader代码:
Shader "Shader Forge/XRay" { Properties { [HideInInspector]_node_3777 ("node_3777", Float ) = 1 _RayPower ("RayPower", Range(1, 10)) = 1.196581 _RayColor ("RayColor", Color) = (0,0,0,1) _LightPower ("LightPower", Range(1, 10)) = 1.8 _Alpha ("Alpha", Range(0, 1)) = 0.6324787 [HideInInspector]_Cutoff ("Alpha cutoff", Range(0,1)) = 0.5 } SubShader { Tags { "IgnoreProjector"="True" "Queue"="Transparent" "RenderType"="Transparent" } Pass { Name "FORWARD" Tags { "LightMode"="ForwardBase" } Blend SrcAlpha OneMinusSrcAlpha ZWrite Off CGPROGRAM #pragma vertex vert #pragma fragment frag #define UNITY_PASS_FORWARDBASE #include "UnityCG.cginc" #pragma multi_compile_fwdbase #pragma only_renderers d3d9 d3d11 glcore gles #pragma target 3.0 uniform float _node_3777; uniform float _RayPower; uniform float4 _RayColor; uniform float _LightPower; uniform float _Alpha; struct VertexInput { float4 vertex : POSITION; float3 normal : NORMAL; }; struct VertexOutput { float4 pos : SV_POSITION; float4 posWorld : TEXCOORD0; float3 normalDir : TEXCOORD1; }; VertexOutput vert (VertexInput v) { VertexOutput o = (VertexOutput)0; o.normalDir = UnityObjectToWorldNormal(v.normal); o.posWorld = mul(unity_ObjectToWorld, v.vertex); o.pos = UnityObjectToClipPos( v.vertex ); return o; } float4 frag(VertexOutput i) : COLOR { i.normalDir = normalize(i.normalDir); float3 viewDirection = normalize(_WorldSpaceCameraPos.xyz - i.posWorld.xyz); float3 normalDirection = i.normalDir; ////// Lighting: ////// Emissive: float node_543 = pow((_node_3777-saturate(dot(i.normalDir,viewDirection))),_RayPower); float3 emissive = ((node_543*_RayColor.rgb)*_LightPower); float3 finalColor = emissive; return fixed4(finalColor,(node_543*_Alpha)); } ENDCG } } FallBack "Unlit/Texture" CustomEditor "ShaderForgeMaterialInspector" }
残影有透明效果,所以是不需要抛阴影和接收阴影的,Shader Forge默认FallBack到Diffuse,Diffuse对阴影进行了处理。所以需要把FallBack删掉或改为没有处理阴影的Shader
相关文章推荐
- Unity角色残影特效
- Unity几个有用的游戏运动特效
- Unity角色残影特效
- Unity几个有用的游戏运动特效
- Unity几个有用的游戏运动特效介绍
- Unity几个有用的游戏运动特效
- Unity实现残影特效
- Unity几个有用的游戏运动特效
- Unity几个有用的游戏运动特效
- Unity运动残影技能
- 使用Unity制作的一个望远镜特效
- unity自动获取特效的播放时间,并自动删除特效
- flash 小特效:粒子向上运动
- 【Unity Shaders】使用Unity Render Textures实现画面特效——建立画面特效脚本系统
- Unity游戏开发的数学与物理 4 ( 在物体运动中加入重力 )
- 【Unity Shader编程】之十五 屏幕高斯模糊(Gaussian Blur)后期特效的实现
- Unity 5.6 雾特效开启
- 如何实现最佳的跨平台游戏体验?Unity成亮解密实时渲染
- 实时渲染的水特效
- unity射击游戏:超萌射手(2)射击特效和EasyButton使用