Effect(一)—— fyRibbonTrail

目录为: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");
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值