Unity实时运动残影特效
来源:互联网 发布:c语言证明哥德巴赫猜想 编辑:程序博客网 时间:2024/05/03 15:58
效果图:
实现原理:
复制模型当前时间点的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
阅读全文
0 0
- Unity实时运动残影特效
- Unity运动残影技能
- Unity几个有用的游戏运动特效
- Unity几个有用的游戏运动特效
- Unity几个有用的游戏运动特效
- Unity实现残影特效
- Unity角色残影特效
- Unity几个有用的游戏运动特效介绍
- jQuery 运动特效展示
- 彩色运动轨迹特效
- JQuery运动特效
- Unity 半圆抛物线运动
- unity抛物线的运动
- Unity往返运动
- Unity声音特效
- unity爆炸特效
- Unity Shader 闪光特效
- Unity新版粒子特效
- iOS10.3新特性之动态更换APP图标
- phpStudy里面访问www目录里面的某些文件很慢,以至于出现错误
- 树莓派——目录
- 欢迎使用CSDN-markdown编辑器
- lombok在Eclipse无法编译的解决方法
- Unity实时运动残影特效
- 1.Java并发编程实战--第一章
- 关于MD5验签失败 同一字符串 调用相同的加密方法 出现加密的值不一样的问题
- word用快捷键插入日期和时间
- 【javascript】2017-9-12 腾讯笔试小Q升序算法
- Oracle的column命令详解
- 使用FlyMcu将hex文件下载到智芯一号步骤
- caffe初始化-Xavier
- 排序算法(一)