转载说明:http://www.unitymanual.com/blog-2265-716.html
知识点 Mesh
实现方式基本与技能冷却雷同
不同的是拖尾需要的不是定义固定数量的顶点去改变位置
而是动态的生成若干组顶点 每帧根据各顶点位置去描绘出需要的效果
定义一个效果顶点列表L
定义拖尾效果时间 T
定义一个拖尾光效的高度 H
在武器上附加一个空的gameObj 并修改其方向Y轴与武器平行 设其为点A
每帧记录当前点A的坐标 以及Y周方向偏移H的点坐标 并记录当前时间点
将此帧记录信息存入L
遍历L列表 根据相邻两两个记录的4个顶点进行填充
在需要有拖尾效果的武器上附加一个空的GameObj 其位置最好在武器柄与刃交汇处 或者刃中心
Y轴与武器方向一致
并为其添加
MeshFilter、MeshRenderer组件 附加材质选择shader为Particles/Additive
创建拖尾脚本附加在GameObj上
原理篇有描述 就是在每帧记录当前帧的武器位置 朝向信息 并根据效果持续时间来记录消失时间点
如下图所示
图中为 武器挥出的三帧中 武器的位置状态 实体红线连接起来的区域为拖尾效果
绿色线条为设置的拖尾效果高度 1 2 3 4 5 6点为根据每帧拖尾组件所在的点 朝向 及高度计算的各个顶点位置
按照虚线绘制三角形 形成拖尾效果
当然了 拖尾效果 并不是时时刻刻都需要 所以我们需要在攻击动作的时候告知拖尾组件 需要绘制 这个时候才进行绘制
伪代码如下
其有内部成员变量
是否绘制状态 draw
信息记录列表 list
开始绘制{
draw=true
}
Update{
if(!draw)return;//当非描绘状态的时候直接跳出
记录当前位置 方向 持续时间信息 插入列表
根据列表算出顶点位置
设置Mesh顶点数组
设置Mesh各个顶点插值颜色
设置Mesh三角形数组
}
停止绘制{
draw=false;
清空Mesh信息
清空记录列表
}
注释比较清晰 就不做多的解释了
[code]csharpcode:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
//内部类 用于存储每帧光效点信息
class Wp
{
public Vector3 point;
public Vector3 upDir;
public float time;
public Wp() {
}
public Wp(Vector3 p, float t) {
point = p;
time = t;
}
}
public class MyWeapon : MonoBehaviour {
private List<Wp> sections = new List<Wp>();//光效点列表
private Mesh mesh;
public float time = 2.0f;
public Color startColor = Color.white;
public Color endColor = new Color(1, 1, 1, 0);
private MeshRenderer meshRenderer;
private Material trailMaterial;
public float height = 2.0f;
private bool isPlay = false;
void Awake() {
MeshFilter meshF = GetComponent(typeof(MeshFilter)) as MeshFilter;
mesh = meshF.mesh;
meshRenderer = GetComponent(typeof(MeshRenderer)) as MeshRenderer;
trailMaterial = meshRenderer.material;
}
void Start () {
}
// 每帧进行显示更新
void FixedUpdate()
{
if (isPlay)
{
Itterate(Time.time);
UpdateTrail(Time.time);
}
}
public void weStart() {
isPlay = true;
}
public void weStop() {
isPlay = false;
ClearTrail();
}
public void Itterate(float itterateTime) { //记录拖尾点信息
Vector3 position = transform.position;
float now = itterateTime;
// 将当前信息添加进列表
if (sections.Count == 0 || (sections[0].point - position).sqrMagnitude > 0) {
Wp section = new Wp();
section.point = position;
section.upDir = transform.TransformDirection(Vector3.up);//存入世界方向
section.time = now;
sections.Insert(0, section);
}
}
public void UpdateTrail(float currentTime) { // ** call once a frame **
// 清空mesh显示
mesh.Clear();
//
// 将超时点从列表移除
while (sections.Count > 0 && currentTime > sections[sections.Count - 1].time + time) {
sections.RemoveAt(sections.Count - 1);
}
// 两个点才能形成一个光效
if (sections.Count < 2)
return;
//顶点 颜色 UV数组定义
Vector3[] vertices = new Vector3[sections.Count * 2];
Color[] colors = new Color[sections.Count * 2];
Vector2[] uv = new Vector2[sections.Count * 2];
//获取列表第一个点
Wp currentSection = sections[0];
//
// 用矩阵代替transform 性能较高
Matrix4x4 localSpaceTransform = transform.worldToLocalMatrix;
// 设置 顶点 颜色 UV信息
for (var i = 0; i < sections.Count; i++) {
currentSection = sections[i];
float u = 0.0f;
if (i != 0)
u = Mathf.Clamp01((currentTime - currentSection.time) / time);
//
// 获取朝向
Vector3 upDir = currentSection.upDir;
// 根据记录点 创建两个顶点
vertices[i * 2 + 0] = localSpaceTransform.MultiplyPoint(currentSection.point);
vertices[i * 2 + 1] = localSpaceTransform.MultiplyPoint(currentSection.point + upDir * height);
uv[i * 2 + 0] = new Vector2(u, 0);
uv[i * 2 + 1] = new Vector2(u, 1);
// 计算插值颜色
Color interpolatedColor = Color.Lerp(startColor, endColor, u);
colors[i * 2 + 0] = interpolatedColor;
colors[i * 2 + 1] = interpolatedColor;
}
// 创建三角形信息
// 1---3---5
// |\ |\ |
// | \ | \ |
// | \| \|
// 0---2---4
int[] triangles = new int[(sections.Count - 1) * 2 * 3];
for (int i = 0; i < triangles.Length / 6; i++) {
triangles[i * 6 + 0] = i * 2;
triangles[i * 6 + 1] = i * 2 + 1;
triangles[i * 6 + 2] = i * 2 + 2;
triangles[i * 6 + 3] = i * 2 + 2;
triangles[i * 6 + 4] = i * 2 + 1;
triangles[i * 6 + 5] = i * 2 + 3;
}
// 对mesh赋值
mesh.vertices = vertices;
mesh.colors = colors;
mesh.uv = uv;
mesh.triangles = triangles;
}
public void ClearTrail() {
//清空显示对象
if (mesh != null) {
mesh.Clear();
sections.Clear();
}
}
}