美文网首页unity-shader
Unity武器拖尾插件:X-WeaponTrail

Unity武器拖尾插件:X-WeaponTrail

作者: 忆中异 | 来源:发表于2022-05-17 16:20 被阅读0次

    X-WeaponTrail是一个很古老的程序化刀光插件,很早以前买了一直放在仓库没用上。最近不知道特效同学抽什么疯,突然不肯自己做刀光特效了,所以就把这个插件丢给他了。

    image

    用法

    该插件的用法很简单,找到你的武器,把X-WeaponTrail预设拖到武器节点下,调整StartPointEndPoint,使其和武器对齐即可。

    image image image

    查看X Weapon Trail脚本,参数都比较直观,不过美术比较难理解的是Max FrameGranularity这2个参数,作者在他的主页给了如下说明:

    image

    MaxFrame可以理解为刀光拖尾的生命周期(长度),MaxFrame越大,拖尾越长。
    Granularity可以理解为拖尾Mesh的顶点粒度,Granularity越大,顶点数越多,越平滑。


    实现细节

    趁着给美术介绍参数,我把这个刀光的实现代码看了一遍,有一些地方还是值得说一下。

    首先,作者维护了一个队列mSnapshotList,用来保存刀光拖尾的位置信息。队列的index越小,则越接近当前武器的位置,index越大则越接近刀光的尾部,队列的长度由MaxFrame决定。

      void RecordCurElem() 
      {
        //TODO: use element pool to avoid gc alloc.
        //Element elem = new Element(PointStart.position, PointEnd.position);
    
        Element elem = mElemPool.Get();
        elem.PointStart = PointStart.position;
        elem.PointEnd = PointEnd.position;
    
        if (mSnapshotList.Count < MaxFrame) 
        {
          mSnapshotList.Insert(1, elem);
        }
        else 
        {
          mElemPool.Release(mSnapshotList[mSnapshotList.Count - 1]);
          mSnapshotList.RemoveAt(mSnapshotList.Count - 1);
          mSnapshotList.Insert(1, elem);
        }
      }
    
    

    上面代码中的Element记录了一帧的位置信息,包括一开始我们设置的StartPointEndPoint,以及中间位置Pos

      public class Element 
      {
        public Vector3 PointStart;
        public Vector3 PointEnd;
    
        public Vector3 Pos 
        {
          get 
          {
            return (PointStart + PointEnd) / 2f;
          }
        }
    
        public Element(Vector3 start, Vector3 end) 
        {
          PointStart = start;
          PointEnd = end;
        }
    
        public Element() 
        {
        }
      }
    
    

    有了MaxFrame帧的位置信息后,我们就可以生成Mesh了。假设我们没有做任何平滑处理,只是简单的根据每一帧的位置(StartPoint,Pos,EndPoint)补充顶点,已经可以生成刀光的Mesh了,但是会出现明显的折痕:

    image

    这个时候,插值平滑就非常必要了。作者采用的插值方式是CatmullRom,关于CatmullRom的说明,网上很多,这里直接贴代码:

            public static Vector3 CatmulRom(Vector3 T0, Vector3 P0, Vector3 P1, Vector3 T1, float f)
            {
                double DT1 = -0.5; 
                double DT2 = 1.5; 
                double DT3 = -1.5; 
                double DT4 = 0.5;
    
                double DE2 = -2.5; 
                double DE3 = 2; 
                double DE4 = -0.5;
    
                double DV1 = -0.5;
                double DV3 = 0.5;
    
                double FAX = DT1 * T0.x + DT2 * P0.x + DT3 * P1.x + DT4 * T1.x;
                double FBX = T0.x + DE2 * P0.x + DE3 * P1.x + DE4 * T1.x;
                double FCX = DV1 * T0.x + DV3 * P1.x;
                double FDX = P0.x;
    
                double FAY = DT1 * T0.y + DT2 * P0.y + DT3 * P1.y + DT4 * T1.y;
                double FBY = T0.y + DE2 * P0.y + DE3 * P1.y + DE4 * T1.y;
                double FCY = DV1 * T0.y + DV3 * P1.y;
                double FDY = P0.y;
    
                double FAZ = DT1 * T0.z + DT2 * P0.z + DT3 * P1.z + DT4 * T1.z;
                double FBZ = T0.z + DE2 * P0.z + DE3 * P1.z + DE4 * T1.z;
                double FCZ = DV1 * T0.z + DV3 * P1.z;
                double FDZ = P0.z;
    
                float FX = (float)(((FAX * f + FBX) * f + FCX) * f + FDX);
                float FY = (float)(((FAY * f + FBY) * f + FCY) * f + FDY);
                float FZ = (float)(((FAZ * f + FBZ) * f + FCZ) * f + FDZ);
    
                return new Vector3(FX, FY, FZ);
            }
    
    

    调大Granularity后,之前的折痕平滑了很多。

    image

    关于顶点的UV映射

    最后想再说一下顶点的UV映射问题。如果不考虑特效贴图,单纯的看顶点生成,效果如下:

    image image

    注意上图的红色射线,射线的原点即StartPointEndPoint的中间点Pos,射线方向从StartPoint指向EndPoint

    查看顶点更新的代码,我们发现顶点的UV设定如下:StartPoint的U是1,EndPoint的U是0,Pos的U是0.5。越接近刀光尾部的顶点,V越接近1。

                    Vector3 pos = mSpline.InterpolateByLen(fadeT);
                    Vector3 up = mSpline.InterpolateNormalByLen(fadeT);
                    Vector3 pos0 = pos + (up.normalized * mTrailWidth * 0.5f);
                    Vector3 pos1 = pos - (up.normalized * mTrailWidth * 0.5f);
    
                    Debug.DrawRay(pos, up * 3, Color.red);
    
                    // pos0
                    pool.Vertices[baseIdx] = pos0;
                    pool.Colors[baseIdx] = MyColor;
                    uvCoord.x = 0f;
                    uvCoord.y = uvSegment;
                    pool.UVs[baseIdx] = uvCoord;
    
                    //pos
                    pool.Vertices[baseIdx + 1] = pos;
                    pool.Colors[baseIdx + 1] = MyColor;
                    uvCoord.x = 0.5f;
                    uvCoord.y = uvSegment;
                    pool.UVs[baseIdx + 1] = uvCoord;
    
                    //pos1
                    pool.Vertices[baseIdx + 2] = pos1;
                    pool.Colors[baseIdx + 2] = MyColor;
                    uvCoord.x = 1f;
                    uvCoord.y = uvSegment;
                    pool.UVs[baseIdx + 2] = uvCoord;
    
    

    结合特效贴图

    image

    越接近刀光头部(武器)的顶点,其UV映射的区域越接近贴图的底部:

    image

    越接近刀光尾部的顶点,其UV映射的区域越接近贴图的上部:

    image

    结合实际效果查看刀光的强弱,就更清晰了:

    image

    相关文章

      网友评论

        本文标题:Unity武器拖尾插件:X-WeaponTrail

        本文链接:https://www.haomeiwen.com/subject/iisnurtx.html