查看: 4807|回复: 6
打印 上一主题 下一主题

【转】unity3d光影拖尾效果实现

[复制链接]

1023

主题

3

听众

359

积分

设计实习生

Rank: 2

纳金币
335582
精华
0

最佳新人

跳转到指定楼层
楼主
发表于 2011-8-9 07:57:50 |只看该作者 |倒序浏览
非常有用的一种效果实现,可以做一引动游戏特效。







using UnityEngine;
using System.Collections;


public class TrailArc : MonoBehaviour
{


    int savedIndex;
    int pointIndex;
    // Material - Particle Shader with "Tint Color" property
    public Material material;


    // Emit
    public bool emit
    {
        get { return Emit; }
        set { Emit = value; }
    }
    bool Emit = true;
    bool emittingDone = false;


    //Minimum velocity (script terminates)
    public float minVel = 10;


    // Facing
    public bool faceCamera = true;


    // Lifetime of each segment
    public float lifetime = 1;
    float lifeTimeRatio = 1;
    float fadeOutRatio;
    // Colors
    public Color[] colors;


    // Widths
    public float[] widths;


    // Optimization
    public float pointDistance = 0.5f;
    float pointSqrDistance = 0;
    public int segmentsPerPoint = 4;
    float tRatio;

    // Print Output
    public bool printResults = false;
    public bool printSavedPoints = false;
    public bool printSegmentPoints = false;


    // Objects
    GameObject trail = null;
    Mesh mesh = null;
    Material trailMaterial = null;


    // Points
    Vector3[] saved;
    Vector3[] savedUp;
    int savedCnt = 0;
    Vector3[] points;
    Vector3[] pointsUp;
    int pointCnt = 0;


    // Segment Appearance Normalization
    int displayCnt = 0;
    float lastPointCreationTime = 0;
    float averageCreationTime = 0;
    float averageInsertionTime = 0;
    float elapsedInsertionTime = 0;

    // Initialization
    bool initialized = false;


    void Start ()
    {
    if(gameObject.rigidbody.velocity.magnitude < minVel)
            Destroy(this);


        // Data Inititialization
        saved = new Vector3[60];
        savedUp = new Vector3[saved.Length];
        points = new Vector3[saved.Length * segmentsPerPoint];
        pointsUp = new Vector3[points.Length];
        tRatio = 1f / (segmentsPerPoint);
        pointSqrDistance = pointDistance * pointDistance;


        // Create the mesh object
        trail = new GameObject("Trail");
        trail.transform.position = Vector3.zero;
        trail.transform.rotation = Quaternion.identity;
        trail.transform.localScale = Vector3.one;
        MeshFilter meshFilter = (MeshFilter) trail.AddComponent(typeof(MeshFilter));
        mesh = meshFilter.mesh;
        trail.AddComponent(typeof(MeshRenderer));
        trailMaterial = new Material(material);
        fadeOutRatio = trailMaterial.GetColor("_TintColor").a;
        trail.renderer.material = trailMaterial;
    }
   
    void printPoints()
    {
        if(savedCnt == 0)
            return;
        string s = "Saved Points at time " + Time.time + ":
";
        for(int i = 0; i < savedCnt; i++)
            s += "Index: " + i + "        Pos: " + saved + "
";
        print(s);
    }


    void printAllPoints()
    {
        if(pointCnt == 0)
            return;
        string s = "oints at time " + Time.time + ":
";
        for(int i = 0; i < pointCnt; i++)
            s += "Index: " + i + "        Pos: " + points + "
";
        print(s);
    }
    void findCoordinates(int index)
    {
        if(index == 0 || index >= savedCnt-2)
            return;
        Vector3 P0 = saved[index-1];
        Vector3 P1 = saved[index];
        Vector3 P2 = saved[index+1];
        Vector3 P3 = saved[index+2];
        Vector3 T1 = 0.5f * (P2 - P0);
        Vector3 T2 = 0.5f * (P3 - P1);
        int pointIndex = index * segmentsPerPoint;
        for(int i = pointIndex; i < pointIndex+segmentsPerPoint; i++)
        {
            float t = (i-pointIndex) * tRatio;
            float t2 = t*t;
            float t3 = t2*t;
            float blend1 = 2*t3 - 3*t2 + 1;
            float blend2 = 3*t2 - 2*t3;
            float blend3 = t3 - 2*t2  + t;
            float blend4 = t3 - t2;
            int pntInd = i - segmentsPerPoint;
            points[pntInd] = blend1*P1 + blend2*P2 + blend3*T1 + blend4*T2;
            pointsUp[pntInd] = Vector3.Lerp(savedUp[index], savedUp[index+1], t);
        }
        pointCnt = pointIndex;
    }


    void Update ()
    {
        try
        {
            Vector3 position = transform.position;
            // Wait till the object is active (update called) and emitting
            if( ! initialized && Emit)
            {
                // Place the first point behind this as a starter projected point
                saved[savedCnt] = transform.TransformPoint(0,0,-pointDistance);
                savedUp[savedCnt] = transform.up;
                savedCnt++;
                // Place the second point at the current position
                saved[savedCnt] = position;
                savedUp[savedCnt] = transform.up;
                savedCnt++;
                // Begin tracking the saved point creation time
                lastPointCreationTime = Time.time;
                initialized = true;
            }


            if(printSavedPoints)
                printPoints();
            if(printSegmentPoints)
                printAllPoints();


            // Emitting - Designed for one-time use
            if( ! Emit )
            {
                if( ! emittingDone && pointCnt > 0 )
                {
                    // Save two final points projected from the ending point
                    saved[savedCnt] = transform.TransformPoint(0,0,pointDistance);
                    savedUp[savedCnt] = transform.up;
                    savedCnt++;
                    findCoordinates(savedCnt-3);
                    // This makes the trail fill the actual entire path
                    saved[savedCnt] = transform.TransformPoint(0,0,pointDistance*2);
                    savedUp[savedCnt] = transform.up;
                    savedCnt++;
                    findCoordinates(savedCnt-3);
                }
                emittingDone = true;
            }
            if(emittingDone)
                Emit = false;


            if(Emit)
            {


                // Do we save a new point?
                if( (saved[savedCnt-1] - position).sqrMagnitude > pointSqrDistance)
                {
                    saved[savedCnt] = position;
                    savedUp[savedCnt] = transform.up;
                    savedCnt++;
                    // Calc the average point display time
                    if(averageCreationTime == 0)
                        averageCreationTime = Time.time - lastPointCreationTime;
                    else
                    {
                        float elapsedTime = Time.time - lastPointCreationTime;
                        averageCreationTime = (averageCreationTime + elapsedTime) * 0.5f;
                    }
                    averageInsertionTime = averageCreationTime * tRatio;
                    lastPointCreationTime = Time.time;
                    // Calc the last saved segment coordinates
                    if(savedCnt > 3)
                        findCoordinates(savedCnt-3);
                }
            }
            // Do we fade it out?
            if( ! Emit && displayCnt == pointCnt)
            {
                Color color = trailMaterial.GetColor("_TintColor");
                color.a -= fadeOutRatio * lifeTimeRatio * Time.deltaTime;
                if(color.a > 0)
                    trailMaterial.SetColor("_TintColor", color);
                else
                {
                    if(printResults)
                        print("Trail effect ending with a segment count of: " + pointCnt);
                    Destroy(trail);
                    Destroy(gameObject);
                }
                return;
            }


            // Do we display any new points?
            if(displayCnt < pointCnt)
            {
                elapsedInsertionTime += Time.deltaTime;
                while(elapsedInsertionTime > averageInsertionTime)
                {
                    if(displayCnt < pointCnt)
                        displayCnt++;
                    elapsedInsertionTime -= averageInsertionTime;
                }
            }
            // Do we render this?
            if(displayCnt < 2)
            {
                trail.renderer.enabled = false;
                return;
            }
            trail.renderer.enabled = true;         
            // Common data
            lifeTimeRatio = 1f / lifetime;
            Color[] meshColors;


            // Rebuild the mesh
            Vector3[] vertices = new Vector3[displayCnt * 2];
            Vector2[] uvs = new Vector2[displayCnt * 2];
            int[] triangles = new int[(displayCnt-1) * 6];
            meshColors = new Color[displayCnt * 2];


            float pointRatio = 1f / (displayCnt-1);
            Vector3 cameraPos = Camera.main.transform.position;
            for(int i = 0; i < displayCnt; i++)
            {
                Vector3 point = points;
                float ratio = i * pointRatio;


                // Color
                Color color;
                if(colors.Length == 0)
                    color = Color.Lerp(Color.clear, Color.white, ratio);
                else if(colors.Length == 1)
                    color = Color.Lerp(Color.clear, colors[0], ratio);
                else if(colors.Length == 2)
                    color = Color.Lerp(colors[1], colors[0], ratio);
                else
                {
                    float colorRatio = colors.Length - 1 - ratio * (colors.Length-1);
                    if(colorRatio == colors.Length-1)
                        color = colors[colors.Length-1];
                    else
                    {
                        int min = (int) Mathf.Floor(colorRatio);
                        float lerp = colorRatio - min;
                        color = Color.Lerp(colors[min+0], colors[min+1], lerp);
                    }
                }
                meshColors[i * 2] = color;
                meshColors[(i * 2) + 1] = color;


                // Width
                float width;
                if(widths.Length == 0)
                    width = 1;
                else if(widths.Length == 1)
                    width = widths[0];
                else if(widths.Length == 2)
                    width = Mathf.Lerp(widths[1], widths[0], ratio);
                else
                {
                    float widthRatio = widths.Length - 1 - ratio * (widths.Length-1);
                    if(widthRatio == widths.Length-1)
                        width = widths[widths.Length-1];
                    else
                    {
                        int min = (int) Mathf.Floor(widthRatio);
                        float lerp = widthRatio - min;
                        width = Mathf.Lerp(widths[min+0], widths[min+1], lerp);
                    }
                }
                // Vertices
                if(faceCamera)
                {
                    Vector3 from = i == displayCnt-1 ?  points[i-1]   : point;
                    Vector3 to = i == displayCnt-1 ?    point    : points[i+1];
                    Vector3 pointDir = to - from;
                    Vector3 vectorToCamera = cameraPos - point;
                    Vector3 perpendicular = Vector3.Cross(pointDir, vectorToCamera).normalized;
                    vertices[i * 2 + 0] = point + perpendicular * width * 0.5f;
                    vertices[i * 2 + 1] = point - perpendicular * width * 0.5f;
                }
                else
                {
                    vertices[i * 2 + 0] = point + pointsUp * width * 0.5f;
                    vertices[i * 2 + 1] = point - pointsUp * width * 0.5f;
                }


                // UVs
                uvs[i * 2 + 0] = new Vector2(ratio , 0);
                uvs[i * 2 + 1] = new Vector2(ratio, 1);


                if(i > 0)
                {
                    // Triangles
                    int triIndex = (i - 1) * 6;
                    int vertIndex = i * 2;
                    triangles[triIndex+0] = vertIndex - 2;
                    triangles[triIndex+1] = vertIndex - 1;
                    triangles[triIndex+2] = vertIndex - 0;


                    triangles[triIndex+3] = vertIndex + 0;
                    triangles[triIndex+4] = vertIndex - 1;
                    triangles[triIndex+5] = vertIndex + 1;
                }
            }
            trail.transform.position = Vector3.zero;
            trail.transform.rotation = Quaternion.identity;
            mesh.Clear();
            mesh.vertices = vertices;
            mesh.colors = meshColors;
            mesh.uv = uvs;
            mesh.triangles = triangles;
        }
        catch(System.Exception e)
        {
            print(e);
        }
    }
}
分享到: QQ好友和群QQ好友和群 腾讯微博腾讯微博 腾讯朋友腾讯朋友 微信微信
转播转播0 分享淘帖0 收藏收藏0 支持支持0 反对反对0
回复

使用道具 举报

1023

主题

3

听众

359

积分

设计实习生

Rank: 2

纳金币
335582
精华
0

最佳新人

沙发
发表于 2012-2-13 23:30:32 |只看该作者
水。。。
回复

使用道具 举报

1023

主题

3

听众

359

积分

设计实习生

Rank: 2

纳金币
335582
精华
0

最佳新人

板凳
发表于 2012-4-8 23:21:40 |只看该作者
好`我顶``顶顶
回复

使用道具 举报

462

主题

1

听众

31万

积分

首席设计师

Rank: 8Rank: 8

纳金币
2
精华
0

最佳新人 活跃会员 热心会员 灌水之王 突出贡献

地板
发表于 2012-6-12 23:25:56 |只看该作者
都闪开,介个帖子,偶来顶
回复

使用道具 举报

462

主题

1

听众

31万

积分

首席设计师

Rank: 8Rank: 8

纳金币
2
精华
0

最佳新人 活跃会员 热心会员 灌水之王 突出贡献

5#
发表于 2012-8-18 23:44:15 |只看该作者
很经典,很实用,学习了!
回复

使用道具 举报

tc    

5089

主题

1

听众

33万

积分

首席设计师

Rank: 8Rank: 8

纳金币
-1
精华
0

最佳新人 活跃会员 热心会员 灌水之王 突出贡献

6#
发表于 2012-8-20 23:29:47 |只看该作者
佩服,好多阿 ,哈哈
回复

使用道具 举报

462

主题

1

听众

31万

积分

首席设计师

Rank: 8Rank: 8

纳金币
2
精华
0

最佳新人 活跃会员 热心会员 灌水之王 突出贡献

7#
发表于 2012-10-25 23:18:18 |只看该作者
心中有爱,爱咋咋地
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

手机版|纳金网 ( 闽ICP备2021016425号-2/3

GMT+8, 2024-11-13 18:09 , Processed in 0.397111 second(s), 29 queries .

Powered by Discuz!-创意设计 X2.5

© 2008-2019 Narkii Inc.

回顶部