0评论

Unity网格的应用—骰子的制作和技能冷却效果

文章来自CSDN博客 2018-10-11 53浏览

想免费获取内部独家PPT资料库?观看行业大牛直播?点击加入腾讯游戏学院游戏开发行业精英群711501594

这篇给大家介绍个比较简单的网格的应用,其实网格的作用其实很大的,网格直接关联的渲染的问题,我们知道做一个ui需要网格,在unity显示一张图片同样需要网格。我们知道当我们拖一张sprite把它放进我scence视图的时候,这张sprite的网格其实并不像我们想象的那么简单,它的网格并不是一个长方形,而是由很多三角形组成不规则的网格的,当然这很显然是不够优化的,因为它让我们多绘制了一些三角形,我们明明可以2个三角形解决的问题。他反而用了10几个或者更多个三角形的。如果我们每个sprite都去减少它们的网格结构。

scence中100个sprite 原来需要1000个三角形的面来进行渲染,如果我们每个sprite用2个三角形就可以搞定的话,那么我们现在就需要200个三角形来搞定。相比前者而言,我们感觉性能会很大似得。然并卵啊。但是这点提高对于GPU来说 那都不是事,同样这跟GPU的并发性还有一定关系的。我们会发现我们同时处理100个sprite,总共需要处理1000个三角形的面和处理一个1000个面的模型的时候我们会发现后者会比前者慢。这就比如我们在写shder的时候应该尽量去避免数据之间的依赖一样,绘制一个拥有1000个面的模型他们顶点数据之间是会存在某种依赖关系,而我们同时处理100个sprite,第一个sprite和第二个sprite他们之间连半毛钱的关系都没有。还是先上一波图。我们先绘制一个cube

骰子的制作重点在于贴uv,至于这长方体的网格的生成就比较简单,我们知道绘制一个长方体只需要8个顶点就可以轻松的搞定了,但是8个顶点的uv信息我们该怎么填充呢。8个顶点那么就只存在8个uv信息,但是我们看看每个角都存在3个uv信息,所以如果要完成一个骰子的制作我们的顶点应该是24个而不是8个。每一个面四个点,这样会存在很多点重复问题,但是没有关系的。

每个面我们只需给出顶点信息 绘制顺序和uv信息,每个面都是独立不会像8个点组成的一个长方体,顶点之间存在某种关系。所以实现起来会比较简单。所以我就不仔细讲了。
[RequireComponent(typeof(MeshFilter),typeof(MeshRenderer))]
public class CreateCube : MonoBehaviour
{
    private List<Vector3> verticles=new List<Vector3>(); 
    private List<int>  indicats=new List<int>();
    private List<Vector2> _uvList=new List<Vector2>(); 
	private void Start ()
	{
	    this.GetComponent<MeshFilter>().mesh = CreateMesh();
	}
    private Mesh CreateMesh()
    {
       Mesh mesh=new Mesh();
       verticles.Add(new Vector3(0, 0, 0)); verticles.Add(new Vector3(0, 1, 0));
       verticles.Add(new Vector3(1, 1, 0)); verticles.Add(new Vector3(1, 0, 0));
       indicats.Add(0); indicats.Add(1); indicats.Add(2);
       indicats.Add(0); indicats.Add(2); indicats.Add(3);
       _uvList.Add(new Vector2(0, 0)); _uvList.Add(new Vector2(0, 1));
       _uvList.Add(new Vector2(0.16f, 1)); _uvList.Add(new Vector2(0.16f, 0));
       verticles.Add(new Vector3(0, 0, 1)); verticles.Add(new Vector3(0, 1, 1));
       verticles.Add(new Vector3(1, 1, 1)); verticles.Add(new Vector3(1, 0, 1));
       indicats.Add(2+4); indicats.Add(1+4); indicats.Add(0+4);
       indicats.Add(3+4); indicats.Add(2+4); indicats.Add(0+4);
       _uvList.Add(new Vector2(0.17f * 3, 0)); _uvList.Add(new Vector2(0.17f * 3, 1));
       _uvList.Add(new Vector2(0.172f * 4, 1)); _uvList.Add(new Vector2(0.172f * 4, 0));
       verticles.Add(new Vector3(1, 0, 0)); verticles.Add(new Vector3(1, 1, 0));
       verticles.Add(new Vector3(1, 1, 1)); verticles.Add(new Vector3(1, 0, 1));
       indicats.Add(0 + 4 * 2); indicats.Add(1 + 4 * 2); indicats.Add(2 + 4 * 2);
       indicats.Add(0 + 4 * 2); indicats.Add(2 + 4 * 2); indicats.Add(3 + 4 * 2);
       _uvList.Add(new Vector2(0.172f * 2, 0)); _uvList.Add(new Vector2(0.172f * 2, 1));
       _uvList.Add(new Vector2(0.171f * 3, 1)); _uvList.Add(new Vector2(0.171f * 3, 0));
       verticles.Add(new Vector3(0, 0, 0)); verticles.Add(new Vector3(0, 1, 0));
       verticles.Add(new Vector3(0, 1, 1)); verticles.Add(new Vector3(0, 0, 1));
       indicats.Add(2 + 4 * 3); indicats.Add(1 + 4 * 3); indicats.Add(0 + 4 * 3);
       indicats.Add(3 + 4 * 3); indicats.Add(2 + 4 * 3); indicats.Add(0 + 4 * 3);
       _uvList.Add(new Vector2(0.167f * 1, 0)); _uvList.Add(new Vector2(0.167f * 1, 1));
       _uvList.Add(new Vector2(0.167f * 2, 1)); _uvList.Add(new Vector2(0.167f * 2, 0));
       verticles.Add(new Vector3(0, 1, 0)); verticles.Add(new Vector3(0, 1, 1));
       verticles.Add(new Vector3(1, 1, 1)); verticles.Add(new Vector3(1, 1, 0));
       indicats.Add(0 + 4 * 4); indicats.Add(1 + 0 + 4 * 4); indicats.Add(2 + 0 + 4 * 4);
       indicats.Add(0 + 4 * 4); indicats.Add(2 + 0 + 4 * 4); indicats.Add(3 + 0 + 4 * 4);
       _uvList.Add(new Vector2(0.16f * 5, 0)); _uvList.Add(new Vector2(0.16f * 5, 1));
       _uvList.Add(new Vector2(1, 1)); _uvList.Add(new Vector2(1, 0));
       verticles.Add(new Vector3(0, 0, 0)); verticles.Add(new Vector3(0, 0, 1));
       verticles.Add(new Vector3(1, 0, 1)); verticles.Add(new Vector3(1, 0, 0));
       indicats.Add(2 + 4 * 5); indicats.Add(1 + 4 * 5); indicats.Add(0 + 4 * 5);
       indicats.Add(3 + 4 * 5); indicats.Add(2 + 4 * 5); indicats.Add(0 + 4 * 5);
       _uvList.Add(new Vector2(0.17f * 4, 0.15f)); _uvList.Add(new Vector2(0.17f * 4, 0.8f));
       _uvList.Add(new Vector2(0.16f * 5, 0.8f)); _uvList.Add(new Vector2(0.16f * 5, 0.15f));
       mesh.vertices = verticles.ToArray();
       mesh.triangles = indicats.ToArray();
        mesh.uv = _uvList.ToArray();
       return mesh;
    }
}
代码看起来很臃肿但是没办法。大家有兴趣的可以看看如何简化代码结构。

接下来我们做一个技能冷却效果,当然做一个冷却效果我们同样也可以通过shader来解决。当然还有ui(ngui或者ugui)都可以轻松的实现,大家如果需要用到冷去效果,直接用ui解决吧。

首先我们得先建一个脚本:
public class CoolScript : MonoBehaviour
{
    [SerializeField] private float _width;
    [SerializeField] private float _angle; 	 
}

先定义一下我们生成的网格初始的大下,即在scale=new vector3(1,1,1)的时候的默认大下。然后给出一个角度,通过angle/360就是经过了多长时间,这是一个简单的换算过程。接下来我们就得定义一个长方形网格所需要的4个点,通过角度和这个四个点来求得我们最终网格应该是几个点。我们还得定义一下该物体的scale。还有我们的中心点。
    [SerializeField] private float _angle;
  <span style="background-color: rgb(255, 153, 0);">  private float _scalex;
    private float _scaley;
    private Vector3 _topleft;
    private Vector3 _topright;
    private Vector3 _bottomleft;
    private Vector3 _bottomright;
    private Vector3 _center;
    private Vector3 _inter;
    private List<Vector3> _originList;
    private MeshFilter _coolMeshFilter; </span>

然后定义生成网格的方法。private Mesh CreateCoolMesh(float angle)

现在我们假如我们生成的网格都是以一个正方形为基础的。如果现在是0度的时候,绘制的应该是整个正方形,如果是45度的时候我们应该绘制如下图的一张图。


因为正方形是一种特殊情况。所以我们应该求出一般情况。右边这个图就是一般情况,我们发现多绘制了一个角。所以我们的做法应该是。有中心点为射点,方向为Quaternion.Euler(0,0,-angle)*Vector3.left。然后和这个四边形检测交点。然后求得交点再哪2个点中间,然后添加对应的点就行了。先给出射线和直线的交点,对于这个方法如果自己去写还是蛮简单的,这里我们就自己去写了,我们还是借助别人写的数学库吧。
   private Point GetIntersects(float angle, out Vector3 endvalue)
    {
        int index = 100;
        endvalue = Vector3.zero;
        Point pos=new Point(0,0);
        for (int i = 0; i < _originList.Count; i++)
        {
            Vector3 start = _originList[i];
            Vector3 end = _originList[(i + 1)%_originList.Count];
            Line2 line=new Line2(start,(end-start).normalized);
            Ray2 ray=new Ray2(_center,Quaternion.Euler(0,0,-angle)*Vector3.left);
            Line2Ray2Intr intr;
            bool isfind= Intersection.FindLine2Ray2(ref line, ref ray, out intr);
            if (isfind)
            {
                if (JudegeBetween(i,intr.Point, start, end, ref pos))
                {
                    endvalue = intr.Point;
                    pos.Y = pos.Y % _originList.Count;
                    return pos;
                }
            }
        }
        return new Point(0,0);
    }

虽然求出了射线和直线的交点,但是我们还得判断交点是否在线段之间。对于点是否在线段之间我们得自己去写了,当然这个也还是蛮简单的,我们只需判断判断点减去初始点向量和结尾点减去判断点向量它们叉乘的结果如果为正表示在2者之间为负值表示不在,为0表示在线段上2个端点上。 
   private bool JudegeBetween(int index,Vector3 tocheck,Vector3 start,Vector3 end,ref Point pos)
    {
        bool b1 = Vector3.SqrMagnitude(tocheck - start) < 0.001f;
        bool b2 = Vector3.SqrMagnitude(tocheck - end) < 0.001f;
        if (b2 || b1)
        {
            if (b1)
                pos = new Point(index, index);
            if(b2)
                pos = new Point(index+1, index+1);
            return true;
        }
        bool b3 = Vector3.Dot(tocheck - start, end - tocheck)>0;
        if(b3)
            pos=new Point(index,index+1);
        return b3;
    }

最后添加我们的创建网格的方法。
   private Mesh CreateCoolMesh(float angle)
    {
        Vector3 endVector3;
        Point point;
        List<Vector3> veritcles=new List<Vector3>();
        List<int> indicats=new List<int>();
        List<Vector2> uvlist=new List<Vector2>();
        Mesh mesh=new Mesh();
        mesh.vertices = veritcles.ToArray();
        mesh.triangles = indicats.ToArray();
        mesh.uv = uvlist.ToArray();
        return mesh;
    }

然后计算出交点在哪2个点之间。然后添加所有的节点。
        Mesh mesh=new Mesh();
      <span style="background-color: rgb(255, 153, 0);">  point= GetIntersects(angle, out endVector3);
        veritcles.Add(_center);
        veritcles.Add(endVector3);
        if (point.Y == 0 && point.X == _originList.Count-1)
        {
            veritcles.Add(_originList[0]);
        }
        else
        {
            if (point.Y < _originList.Count)
            {
                for (int i = point.Y; i <= _originList.Count; i++)
                {
                    veritcles.Add(_originList[i % _originList.Count]);
                }
            }
        }</span>

然后根据节点来添加顶点的uv信息和顶点的绘制顺序。
     <span style="background-color: rgb(255, 153, 0);">  for (int i = 1; i < veritcles.Count-1; i++)
        {
            indicats.Add(0);
            indicats.Add(i);
            indicats.Add(i+1);
        }
        for (int i = 0; i < veritcles.Count; i++)
        {
            uvlist.Add(new Vector2(veritcles[i].x / (_width * _scalex), veritcles[i].y / (_width * _scaley)));
        }</span>
        mesh.vertices = veritcles.ToArray();

最后添加一下start方法和update方法即可了。  
      private void Start ()
	{
	    _coolMeshFilter = this.GetComponent<MeshFilter>();
        _originList=new List<Vector3>();
	    Vector3 scale = transform.localScale;
	    _scalex = scale.x;
	    _scaley = scale.y;
        _originList.Add(new Vector3(0, _scaley * _width / 2, 0));
        _originList.Add(new Vector3(0, _width * _scaley, 0)); 
        _originList.Add(new Vector3(_width * _scalex, _width * _scaley, 0));
        _originList.Add(new Vector3(_width * _scalex, 0, 0));
        _originList.Add(new Vector3(0, 0, 0));
        _center = new Vector3(_width * _scalex / 2, _width * _scaley / 2);
	}
    private void Update()
    {
        _coolMeshFilter.mesh = CreateCoolMesh(_angle);
    }
来自:https://blog.csdn.net/u012565990/article/details/51972322