Unity创建模型并让模型动态运动
发表于2018-08-16
项目需要实现一个做正弦运动的线条,最先想到的办法是改变模型的顶点,利用函数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的值就可以实现开始图中的效果了……
是不是还是很简单的。这里就不贴全部的代码了,相信大家在看完本篇文章对创建模型并让模型动态运动的介绍以后,要实现这效果也是手到擒来的事。