Unity创建模型并让模型动态运动

发表于2018-08-16
评论0 3.7k浏览
项目需要实现一个做正弦运动的线条,最先想到的办法是改变模型的顶点,利用函数y=aSin(bx+C) 让模型顶点的Y坐标,根据X坐标运动,这样就实现如下图的运动:


效果图如下:

实现方法

首先新建一个物体,为物体加上必要的组件。
        GameObject cube = this.gameObject;//or new GameObject();
        MeshFilter meshFilter = cube.AddComponent<MeshFilter>();
        MeshRenderer renderer = cube.AddComponent<MeshRenderer>();
        renderer.material = Resources.Load<Material>("Material/line");
        renderer.shadowCastingMode = ShadowCastingMode.Off;
        mesh = new Mesh();
        mesh.name = "LangCube";

下面就是头牌,对Mesh的创建了,创建模型网上也有很多的资料,其主要的难点在于,顶点的创建,和三角形的建立,这里我们创建一个长方体,这个长方体在X轴上有很多的顶点,这里分享一些我的理解,抛砖迎玉。首先我们以一个正方体为例来讲讲顶点的创建和三角形的构建,正方体有六个面每个面4个点,则一共就有24个顶点,有人肯定要说“为啥是24个,明明是8个点,你当我数学没学好啊!”,因为我们这里不考虑顶点的公用情况,这样能更方便处理构建顶点,构建三角形。当然你考虑顶点公用也是可行的,在构建三角形的时候,注意相应赋值也可以。这里就简单粗暴的处理。

三角形的构建

正方体每一面有2个三角形,每个三角形有3个顶点,则共用36个顶点,同理不考虑顶点的公用,Mesh的triangles是一个int数字,这个int数组的每个数就是对顶点的一个索引,每3个数构成一个三角形,所以这个数组的大小一定是3的倍数。当你构建三角形的时候,需要考虑三角形的正反面,即法线的朝向。这里有一个左手定则,四指的指向为顶点的顺序,大拇指的方向就是三角形法线的朝向,即0—>1—>2,3—>2—>1。

网上也有很多正方体的构建,也可以参考,弄明白了这个之后我们就来创建多顶点的长方体。

创建顶点,我这里采用的方式毕竟简单粗暴了,直接就是每个面的顶点进行列举。
 Vector3[] vecs = new Vector3[4 + 2 * xNum * 4 + 4];
        int index = 0;
        for (int i = 0; i < xNum; i++) //前
        {
            vecs[i * 2] = new Vector3(-xNum / 4f + i * 0.5f, -0.5f, -0.5f);
            vecs[i * 2 + 1] = new Vector3(-xNum / 4f + i * 0.5f, 0.5f, -0.5f);
        }
        index = xNum * 2;
        for (int i = 0; i < xNum; i++) //上
        {
            vecs[index + i * 2] = new Vector3(-xNum / 4f + i * 0.5f, 0.5f, -0.5f);
            vecs[index + i * 2 + 1] = new Vector3(-xNum / 4f + i * 0.5f, 0.5f, 0.5f);
        }
        index = xNum * 4;
        for (int i = 0; i < xNum; i++)//后
        {
            vecs[index + i * 2] = new Vector3(-xNum / 4f + i * 0.5f, 0.5f, 0.5f);
            vecs[index + i * 2 + 1] = new Vector3(-xNum / 4f + i * 0.5f, -0.5f, 0.5f);
        }
        index = xNum * 6;
        for (int i = 0; i < xNum; i++)//下
        {
            vecs[index + i * 2] = new Vector3(-xNum / 4f + i * 0.5f, -0.5f, 0.5f);
            vecs[index + i * 2 + 1] = new Vector3(-xNum / 4f + i * 0.5f, -0.5f, -0.5f);
        }
        index = xNum * 8;
        vecs[index++] = vecs[1];//底
        vecs[index++] = vecs[0];  
        vecs[index++] = vecs[4 * xNum];
        vecs[index++] = vecs[4 * xNum + 1];
        vecs[index++] = vecs[2 * xNum - 1];//顶
        vecs[index++] = vecs[6 * xNum - 2];
        vecs[index++] = vecs[2 * xNum - 2];
        vecs[index++] = vecs[6 * xNum - 1];

贴个图解释下方向,这个更加清晰易懂:

只要你写了第一个面,后面的按着顺序来就是了。接下里就是构建三角形,同理按着顺序来
        int triangles_cout = 2 * (xNum - 1) * 4 * 3 + 4 * 3;
        int side_triangles_count = (xNum - 1) * 3 * 2;
        int[] triangles = new int[triangles_cout];
        for (int i = 0; i < 4; i++)
        {
            int vi = i * xNum * 2; //上一个面后2个顶点不与下一个面前两个顶点构成面,这里要注意。
            for (int j = 0; j < side_triangles_count; vi += 2)
            {
            //两个三角形组成一个面
                triangles[i * side_triangles_count + j++] = vi;
                triangles[i * side_triangles_count + j++] = vi + 1;
                triangles[i * side_triangles_count + j++] = vi + 2;
                triangles[i * side_triangles_count + j++] = vi + 3;
                triangles[i * side_triangles_count + j++] = vi + 2;
                triangles[i * side_triangles_count + j++] = vi + 1;
            }
        }
        //底面和顶面的三角形
        for (int i = side_triangles_count * 4, vi = 8 * xNum; i < triangles_cout; i += 6, vi += 4)
        {
            triangles[i] = vi;
            triangles[i + 1] = vi + 1;
            triangles[i + 2] = vi + 2;
            triangles[i + 3] = vi + 3;
            triangles[i + 4] = vi + 2;
            triangles[i + 5] = vi + 1;
        }

把上面创建的赋值给mesh的vectors,triangles就完成了创建。
        mesh.vertices = vecs;
        mesh.triangles = triangles;
        //最后要记得重新计算一下法线,避免法线不对引起光照不对等等问题
        mesh.RecalculateNormals();
        //更新包围盒  摄像需要获取bounds,如果不重新计算那么会存在边界时不被渲染的问题
        mesh.RecalculateBounds();

接下来就就是如何将将模型做正弦运动了。
    void MarginWaveEntityXY()
    {
        Vector3[] vertices = vects.Clone() as Vector3[];
        for (int i = 0; i < vertices.Length; i++)
        {
        //遍历所有顶点,改变y的值,使其值跟随x的值变化。
            vertices[i].y += Mathf.Sin(vertices[i].x + delta);
        }
        mesh.vertices = vertices;
    }

在Update中改变delta的值就可以实现开始图中的效果了……
是不是还是很简单的。这里就不贴全部的代码了,相信大家在看完本篇文章对创建模型并让模型动态运动的介绍以后,要实现这效果也是手到擒来的事。

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引