找回密码
 立即注册
楼主: cez1230

[常见问题] 刀光剑影特效

[复制链接]
发表于 2013-4-1 18:11 | 显示全部楼层 |阅读模式
Description

Alright, this is my last trail renderer I will post (wink). This trail renderer is designed specifically with melee trails in mind. It will track the path of its parent object and create a fluid arc between its saved points. You can set the distance between saved points, which gives you control over the accuracy of the interpolation. Increasing distance will produce more smoothed out arcs, where reducing distance will increase accuracy to the actual path.

Features
  • Set the fade out time (lifetime) when the trail is done emitting
  • Control when its done by simply turning off the "emit" property
  • Set any number of colors
  • Set any number of widths
  • Autodestructs when faded out
  • Set the interpolation distance
  • Set whether it always faces the camera
  • Set the number of segments to place between each interpolation distance
One-Time Use

This trail renderer is designed to be a one-time use component. There are several reasons for this, based on the way it is designed for optimization. When emitting is set to false, the trail renderer will stop adding new segments and fade out. The fade out time is set to the lifetime.

Image
C# - TrailArc.cs
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 + ":\n";
        for(int i = 0; i < savedCnt; i++)
            s += "Index: " + i + "\tPos: " + saved + "\n";
        print(s);
    }

    void printAllPoints()
    {
        if(pointCnt == 0)
            return;
        string s = "Points at time " + Time.time + ":\n";
        for(int i = 0; i < pointCnt; i++)
            s += "Index: " + i + "\tPos: " + points + "\n";
        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);
        }
    }
}



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×

评分

参与人数 1鲜花 +1 收起 理由
aa1287537617 + 1

查看全部评分

发表于 2013-4-26 10:03 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
发表于 2013-4-26 11:11 | 显示全部楼层
带带 有问题 弄就去就报编译错误
发表于 2013-5-4 09:08 | 显示全部楼层
看不懂呢?
发表于 2017-5-22 19:52 | 显示全部楼层
楼主是超人
发表于 2017-5-22 20:07 | 显示全部楼层
好帖就是要顶
发表于 2017-5-22 19:59 | 显示全部楼层
顶顶多好
发表于 2017-5-22 20:06 | 显示全部楼层
真心顶
发表于 2017-5-22 19:17 | 显示全部楼层
难得一见的好帖
发表于 2017-5-27 18:57 | 显示全部楼层
楼主是超人
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-11-23 19:44 , Processed in 0.073159 second(s), 23 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表