目录为:Assets/Scripts/Effect/fyParticleSystem/目录下
fyRibbonTrail.cs
这个类是所有丝带特效的基类,
在这里面用代码生成丝带mesh,并控制颜色.
代码如下:
using UnityEngine;
using System.Collections.Generic;
[System.Serializable]
public class ColorKey
{
public Color color;
public float time;
//构造函数
public ColorKey()
{
time = 1.0f;
color = new Color (1.0f, 1.0f, 1.0f, 1.0f);
}
//构造函数
public ColorKey (Color color, float time)
{
this.color = color;
this.time = time;
}
}
//继承Mono
public class fyRibbonTrail: MonoBehaviour
{
//最大Ribbon段数
public int maxElement = 10;
//Ribbon每段的宽度
public float segWidth = 2.0f;
//Ribbon每段的长度
public float segLength = 1.0f;
//对象Transform
public Transform source = null;
//对象
public GameObject renderObj = null;
//UV重复长度
public float mUVLength = 1.0f;
//Mesh
protected Mesh mMesh = null;
//MeshRederer
protected MeshRenderer mMeshRender = null;
//纹理旋转矩阵
protected Matrix4x4 mMatrix = Matrix4x4.identity;
//偏移位置
public Vector2 mOffset = new Vector2 (0, 0);
//旋转位置
public float mOffRot = 0;
//平移
public Vector2 mTranslate = new Vector2 (0, 0);
//缩放
public Vector2 mScale = new Vector2 (1, 1);
//旋转
public float mRotate = 0.0f;
//设置周期时间
public float mColorPeriodTime = 0.0f;
public float mColorCurTime = 0;
//颜色渐变
//这颜色估计要自己指定
public ColorKey[] colorKey = new ColorKey[5];
//保存对应的shader
public Shader mShader = null;
//保存对应的Texture2D
public Texture2D mTexture = null;
//朝向类型
public enum OrientType
{
World_Type,
BillBoard_Type
}
//纹理寻址类型
public enum MaterialAddressType
{
Common_Type, //普通纹理寻址
Sequence_Type, //序列帧寻址
Repeat_Type, //重复寻址
}
//Blend类型
public enum BlendType
{
Replace_Type,
Alpha_Type,
Additive_Type,
Distort_Additive,
}
//朝向
public OrientType mOrientType = OrientType.World_Type;
//纹理寻址类型
public MaterialAddressType mMaterialType = MaterialAddressType.Common_Type;
//blend type
public BlendType mBlendType = BlendType.Additive_Type;
public Vector3 mNormal = new Vector3 (0, 1, 0);
//Ribbon Segment列表
protected Vector3[] elemPosPool;
protected Vector2[] elemUVPool;
protected Color[] elemColorPool;
//是否创建完成
protected bool bCreated = false;
void Start()
{
//从这里看来这个脚本要挂到Object上去
renderObj = this.gameObject;
source = renderObj.transform;
//运行状态,已经有Mesh数据,不需要重新创建
ReCreate ();
//初始变换矩阵
InitMatrix ();
}
//Matrix初始化
public void InitMatrix()
{
//初始偏移
//单位矩阵
Matrix4x4 xlate = Matrix4x4.identity;
if (mOffset.x != 0 || mOffset.y != 0)
{
//x
xlate.m03 = mOffset.x;
//y
xlate.m13 = mOffset.y;
}
//初始旋转
Matrix4x4 rotMatrix = Matrix4x4.identity;
if (mOffRot != 0)
{
//把度数转为弧度
float theta = mOffRot * Mathf.Deg2Rad;
float cosTheta = Mathf.Cos (theta);
float sinTheta = Mathf.Sin (theta);
//绕Z轴旋转---------------------------
//cos -sin 0 0
//sin cos 0 0
//0 0 1 0
//0 0 0 1
//填充旋转矩阵
rotMatrix.m00 = cosTheta;
rotMatrix.m01 = -sinTheta;
rotMatrix.m10 = sinTheta;
rotMatrix.m11 = cosTheta;
//-----------------------------------
// Offset center of rotation to center of texture
//x translate
rotMatrix.m03 = 0.5f + ((-0.5f * cosTheta) - (-0.5f * sinTheta));
//y translate
rotMatrix.m13 = 0.5f + ((-0.5f * sinTheta) + (-0.5f * cosTheta));
}
//旋转和平移联结起来
mMatrix = xlate * rotMatrix;
//设置旋转效果
if (mMeshRender != null)
{
//编辑模式
if (!Application.isPlaying)
{
//sharedMaterial:得到原始的material,任何改变都会影响到引用这个material的其他物体
if (mMeshRender.sharedMaterial != null)
{
//设置旋转效果
mMeshRender.sharedMaterial.SetMatrix ("_TransMatrix", mMatrix);
}
}
//运行模式
else
{
//material:得到一个副本,这个material改变,并不影响其他引用改变之前的material的物体
if (mMeshRender.material != null)
{
//把transfom传到shader里面去
mMeshRender.material.SetMatrix ("_TransMatrix", mMatrix);
}
}
}
}
//Update is called once per frame
void Update()
{
//更新颜色
UpdateColor (Time.deltaTime);
//更新Ribbon
//由子类实现
UpdateRibbon (Time.deltaTime);
//更新变换矩阵
UpdateMatrix ();
}
//创建Ribbon
virtual public void ReCreate()
{
//检测源物体
if (maxElement < 1)
{
Debug.LogError ("the ribbon max element must be more than 0!");
return;
}
renderObj.name = "fyRibbon";
//获取MeshFilter,准获取Mesh
MeshFilter mf = gameObject.GetComponent<MeshFilter> ();
//没有就创建
if (mf == null)
{
mf = renderObj.AddComponent<MeshFilter> ();
//在面板中不可编辑
mf.hideFlags = HideFlags.NotEditable;
}
//获取MeshRenderer
MeshRenderer mr = gameObject.GetComponent<MeshRenderer> ();
//没有就创建
if (mr == null)
{
mr = renderObj.AddComponent<MeshRenderer> ();
//关闭投影
mr.castShadows = false;
//关闭接收阴影
mr.receiveShadows = false;
//设置不可编辑状态
mr.hideFlags = HideFlags.NotEditable;
}
mMeshRender = mr;
//创建mesh
if (mf.sharedMesh == null)
{
mf.sharedMesh = new Mesh ();
}
mMesh = mf.sharedMesh;
//组件不可见
//mf.hideFlags = HideFlags.HideInInspector;
//创建RibbonMesh
CreateRibbonMesh (mf.sharedMesh);
//编辑状态
if (!Application.isPlaying)
{
//第一次创建
if (mMeshRender.sharedMaterial == null)
{
Texture2D defaultTex = Resources.Load ("effect/test/flare") as Texture2D;
//设置默认shader
if (mShader == null)
{
//修改为默认材质以及贴图
Shader shader = Shader.Find ("fyShader/Additive");
mShader = shader;
mMeshRender.sharedMaterial = new Material (shader);
}
//设置默认texture
if (mTexture == null)
{
mTexture = defaultTex;
mMeshRender.sharedMaterial.SetTexture ("_MainTex", defaultTex);
}
}
if (mShader != null)
{
mMeshRender.sharedMaterial = new Material (mShader);
if (mTexture != null)
{
mMeshRender.sharedMaterial.SetTexture ("_MainTex", mTexture);
}
}
}
//运行状态
else
{
if (mShader != null)
{
mMeshRender.material = new Material (mShader);
if (mTexture != null)
{
mMeshRender.material.SetTexture ("_MainTex", mTexture);
}
}
}
bCreated = true;
}
//改变贴图
public void ChangeTexture(Texture2D tex)
{
//保存贴图
mTexture = tex;
if (mMeshRender != null && mMeshRender.sharedMaterial != null)
{
mMeshRender.sharedMaterial.SetTexture ("_MainTex", tex);
}
}
//其实就是创建mesh
//创建RibbonMesh
void CreateRibbonMesh(Mesh mesh)
{
//局部坐标系 法线方向
//指向y轴正半轴
Vector3 normal = new Vector3 (0, 1, 0);
Vector3 sourcePos = new Vector3 (0, 0, 0);
Debug.Log ("source pos " + sourcePos.ToString ());
//初始RibbonElement Pool
elemPosPool = new Vector3[(maxElement + 1) * 2];
elemUVPool = new Vector2[(maxElement + 1) * 2];
elemColorPool = new Color[(maxElement + 1) * 2];
//初始方向
//指向z轴正半轴
Vector3 dir = new Vector3 (0, 0, 1);
//这里Normalize没什么意义
dir.Normalize ();
mesh.Clear ();
//默认初始长度,编辑时候需要处理
float length = 0.0001f;
//默认maxElement = 10
//segLength = 1
//length = 10
length = maxElement * segLength;
//这里很奇怪
//deltaLength = 1
float deltaLength = length / maxElement;
//默认结束位置
Vector3 endPos = sourcePos + dir * length;
//数据点
//i表示element段数
for (int i = 0; i < elemPosPool.Length / 2.0f; i++)
{
//距离起始点的距离 i * deltaLengh
float vLength = i * deltaLength;
//当前段的起始pos
Vector3 vPos = endPos - dir * vLength;
//垂直法向
//dir(0, 0, 1)
//normal(0, 1, 0)
//vDir = (-1, 0, 0);
Vector3 vDir = Vector3.Cross (dir, normal);
//当前段的中心点坐标
Vector3 p1 = vPos + vDir * segWidth / 2.0f;
//上一段的中心店坐标,不过上一段存不存在无所谓,只是算距离得出的
Vector3 p2 = vPos - vDir * segWidth / 2.0f;
//保存顶点数据
//存储当前段的中心点
elemPosPool [i * 2] = p1;
elemColorPool [i * 2] = new Color (1, 1, 1, 1);
//存储上一段的中心点
elemPosPool [i * 2 + 1] = p2;
elemColorPool [i * 2 + 1] = new Color (1, 1, 1, 1);
//对UV没那么了解,这里看着有点迷
//Repeat_Type
if (mMaterialType == MaterialAddressType.Repeat_Type)
{
//默认mUVLength = 1
//vLength几乎等于当前i
float uv = vLength / mUVLength;
elemUVPool [i * 2] = new Vector2 (-uv, 1.0f);
elemUVPool [i * 2 + 1] = new Vector2 (-uv, 0.0f);
}
else
{
//根据UV类型
//跟上面相比,少了1
elemUVPool [i * 2] = new Vector2 (1.0f - vLength / length, 1.0f);
elemUVPool [i * 2 + 1] = new Vector2 (1.0f - vLength / length, 0.0f);
}
}
//这里定义三角形index
int[] index = new int[maxElement * 2 * 3];
for (int i = 0; i < maxElement; i++)
{
int index0 = i * 2;
int index1 = i * 2 + 1;
//其实就是 i * 2 + 2
int index2 = (i + 1) * 2;
int index3 = (i + 1) * 2 + 1;
//三角形条带
// 0 ---- 1
// /
// 2 ----- 3
index [i * 6 + 0] = index0;
index [i * 6 + 1] = index1;
index [i * 6 + 2] = index2;
index [i * 6 + 3] = index3;
index [i * 6 + 4] = index2;
index [i * 6 + 5] = index1;
}
//顶点
mesh.vertices = elemPosPool;
//UV
mesh.uv = elemUVPool;
//Color
mesh.colors = elemColorPool;
//三角形index
mesh.triangles = index;
//重新计算法线
mesh.RecalculateNormals ();
//重新计算边界体积
mesh.RecalculateBounds ();
//Mesh优化,运行时会变快,不过这函数只在自己代码生成mesh时用
mesh.Optimize ();
}
//更新变换矩阵
public virtual void UpdateMatrix()
{
if (mMeshRender != null)
{
bool updateMatrix = false;
//先缩放再平移再旋转
//缩放
if (mScale.x != 1 || mScale.y != 1)
{
//Offset to center of texture
//缩放
mMatrix.m00 /= mScale.x;
mMatrix.m11 /= mScale.y;
//Skip matrix concat since first matrix update
//x translate
mMatrix.m03 = (-0.5f * mMatrix.m00) + 0.5f;
//y translate
mMatrix.m13 = (-0.5f * mMatrix.m11) + 0.5f;
updateMatrix = true;
}
//平移
if (mTranslate.x != 0 || mTranslate.y != 0)
{
Matrix4x4 xlate = Matrix4x4.identity;
xlate.m03 = mTranslate.x;
xlate.m13 = mTranslate.y;
//联结
mMatrix = xlate * mMatrix;
updateMatrix = true;
}
//旋转
if (mRotate != 0)
{
Matrix4x4 rotMatrix = Matrix4x4.identity;
float theta = mRotate * Mathf.Deg2Rad;
float cosTheta = Mathf.Cos (theta);
float sinTheta = Mathf.Sin (theta);
rotMatrix.m00 = cosTheta;
rotMatrix.m01 = -sinTheta;
rotMatrix.m10 = sinTheta;
rotMatrix.m11 = cosTheta;
//Offset center of rotation to center of texture
rotMatrix.m03 = 0.5f + ((-0.5f * cosTheta) - (-0.5f * sinTheta));
rotMatrix.m13 = 0.5f + ((-0.5f * sinTheta) + (-0.5f * cosTheta));
mMatrix = rotMatrix * mMatrix;
updateMatrix = true;
}
//设置旋转效果
//只要改变了,updateMatrix这个标志就会为true
if (updateMatrix)
{
//编辑模式
if (!Application.isPlaying)
{
if (mMeshRender.sharedMaterial != null)
{
//设置效果
mMeshRender.sharedMaterial.SetMatrix ("_TransMatrix", mMatrix);
}
}
//运行模式
else
{
if (mMeshRender.material != null)
{
mMeshRender.material.SetMatrix ("_TransMatrix", mMatrix);
}
}
}
}
}
//更新颜色
public virtual void UpdateColor(float deltaTime)
{
if (mColorPeriodTime == 0)
{
return;
}
//计算颜色值,颜色有效
Color gColor = new Color ();
mColorCurTime += deltaTime;
//计算当前颜色时间
if (mColorCurTime > mColorPeriodTime)
{
mColorCurTime = 0;
}
//计算颜色
gColor = GetGradientColor ();
//Debug.Log("color" + gColor.ToString());
//遍历修改数据点
//改变颜色
for (int i = 0; i < elemPosPool.Length / 2.0f; i++)
{
elemColorPool [i * 2] = gColor;
elemColorPool [i * 2 + 1] = gColor;
}
mMesh.colors = elemColorPool;
}
//根据当前时间计算颜色
public virtual Color GetGradientColor()
{
Color gcolor = new Color ();
//计算比例值
float factor = mColorCurTime / mColorPeriodTime;
//计算color值
//colorKey数组长度默认等于5
int colorLength = colorKey.Length;
for (int i = 0; i < colorLength - 1; i++)
{
//当前
ColorKey key1 = colorKey [i % colorLength];
//下一个
ColorKey key2 = colorKey [(i + 1) % colorLength];
//计算距离
float dist = key2.time - key1.time;
//其实这里就是在按线性插值来混合颜色
if (factor >= key1.time && factor <= key2.time)
{
float ff = (factor - key1.time) / dist;
// key1 --------------------------key2
// factor
gcolor = key1.color * (1 - ff) + key2.color * ff;
break;
}
}
return gcolor;
}
//更新Ribbon
//由子类继承
public virtual void UpdateRibbon(float deltaTime)
{
}
//重置
public virtual void Reset()
{
if (mMesh == null)
{
return;
}
//重置位置
Vector3 sourcePos = source.position;
//初始RibbonElement Pool
elemPosPool = new Vector3[(maxElement + 1) * 2];
elemUVPool = new Vector2[(maxElement + 1) * 2];
//初始方向
Vector3 dir = new Vector3 (0, 0, 1);
//仍然的无意义
dir.Normalize ();
//默认初始长度
float length = maxElement * segLength;
float deltaLength = length / maxElement;
//默认结束位置
Vector3 endPos = sourcePos + dir * length;
float totalElemLength = maxElement * segLength;
//真实最大长度
float realLength = totalElemLength > length ? length : totalElemLength;
//遍历修改数据点
for (int i = 0; i < elemPosPool.Length / 2.0f; i++)
{
float vLength;
if (i * segLength > length)
{
vLength = length;
}
else
{
vLength = i * segLength;
}
Vector3 vPos = endPos - dir * vLength;
//垂直法向
Vector3 vDir = Vector3.Cross (dir, mNormal);
Vector3 p1 = vPos + vDir * segWidth / 2.0f;
Vector3 p2 = vPos - vDir * segWidth / 2.0f;
//转为局部坐标
p1 -= sourcePos;
p2 -= sourcePos;
//重置顶点数据
elemPosPool [i * 2] = p1;
elemUVPool [i * 2] = new Vector2 (1.0f - vLength / realLength, 1.0f);
elemColorPool [i * 2] = new Color (1, 1, 1, 1);
elemPosPool [i * 2 + 1] = p2;
elemUVPool [i * 2 + 1] = new Vector2 (1.0f - vLength / realLength, 0.0f);
elemColorPool [i * 2 + 1] = new Color (1, 1, 1, 1);
}
mMesh.vertices = elemPosPool;
mMesh.uv = elemUVPool;
mMesh.RecalculateNormals ();
mMesh.RecalculateBounds ();
mMesh.Optimize ();
//刷新矩阵数据
mMatrix = Matrix4x4.identity;
InitMatrix ();
mColorCurTime = 0;
Debug.Log ("reset");
}
}