基础学习
什么是Mesh?
Mesh是指的模型的网格,3D模型是由多边形拼接而成,而多边形实际上又是由多个三角形拼接而成的。即一个3D模型的表面其实是由多个彼此相连的三角面构成。三维空间中,构成这些三角形的点和边的集合就是Mesh。
原理
即动态创建一个Mesh,设置三角形和顶点数据,然后赋值给MeshFilter(增加mesh属性),通过MeshRenderer(增加材质并渲染出Mesh)绘制出来
理论基础:
1、左手坐标系和右手坐标系
我们的三维坐标系,在3dmax里是右手坐标系,而在Unity里是左手坐标系。
左手坐标系和右手坐标系的区别 http://www.cnblogs.com/mythou/p/3327046.html
、
2、三边面如何组成四边面
如图,左边是Unity里的左手坐标系,右边是在此坐标系里生成的一个面以及它的各个点坐标。
012和230这两个三边面就组成了一个四边面。
如果我问这个四边面有几个顶点,想必大家都会回答4个,实际上是6个,012和230这是6个顶点,不同面的顶点不公用。
要组成2个三边面可以有很多种顺序,例如012和320、012和032、023和012等等等
但是我们一般都是按照4个点的顺序来画2个三边面组成四边面,所以可选的只有【012和230、230和012】,以及【032和210、210和032】这两大类
这两类画法有什么区别呢?细心的童鞋应该已经发现,这两种方式前者是逆时针,后者是顺时针。
这种循环的方向会导致面的法线方向不同,而这个法线方向会决定这个面的朝向。
我们要确定这个法线方向其实很简单,上面说了,Unity里是左手坐标系,拿出左手,伸直,拇指与其他四个指头垂直,然后四指弯曲,指尖朝向循环的方向,拇指就指向法线的方向。
由此我们得出结论,要想生成正确的面(法线指向我们),我们只能用【032和210、210和032】
这里需要注意的一点是,我们确定4个点的循环方向,和生成三边面时的循环方向无关,只要生成三边面时,用到的前4个点的index顺序没错就行了。
Mesh的组成部分
1.vertices(顶点数据数组Vector3[])
2.triangles(三角形顶点索引数组,int[])
3.normals(法线向量数组,Vector3[])
4.uv(纹理坐标数组,Vector2[])
顶点坐标:顶点坐标数组存放Mesh的每个顶点的空间坐标,假设某mesh有n个顶点,则vertex的size为n
法线:法线数组存放mesh每个顶点的法线,大小与顶点坐标对应,normal[i]对应顶点vertex[i]的法线
法线详解:
法线就是垂直于面的一条线,它有方向,没有大小。
法线的方向就是面朝外的方向。比如我们现在盯着显示器看,从显示器的正中心会有一条法线垂直于屏幕指向我们。
法线向外的面就是正面,相反的就是背面,一般来讲,从正面看才能看到面,背面看面是看不到的。
纹理坐标:它定义了图片上每个点的位置的信息. 这些点与3D模型是相互联系的, 以决定表面纹理贴图的位置. UV就是将图像上每一个点精确对应到模型物体的表面. uv[i]对应vertex[i]
三角形序列:每个mesh都由多个三角面组成,而三角面的三个点就是顶点坐标里的点,三角形的数组的size = 三角形个数 * 3
三边面和四边面:
三边面就是三条边组成的面,四边面就是四条边组成的面。
三边面在三维空间中是不可扭曲的,而四边面在三维空间中可以扭曲。所以Unity里只支持三边面。其他支持四边面的软件例如3dmax在导出fbx的时候,会把四边面转换成三边面。
坐标系
unity采用左手坐标系
使用到的类
Quaternion类
Quaternion(四元数)用于计算Unity旋转。它们计算紧凑高效,不受万向节锁的困扰,并且可以很方便快速地进行球
面插值。 Unity内部使用四元数来表示所有的旋转。
Quaternion是基于复数,并不容易直观地理解。 不过你几乎不需要访问或修改单个四元数参数(x,y,z,w);
大多数情况下,你只需要获取和使用现有的旋转(例如来自“Transform”),或者用四元数来构造新的旋转(例如,在两次旋转之间平滑插入)。
大部分情况下,可能会使用到这些函数:
Quaternion.LookRotation,
Quaternion.Angle
Quaternion.Euler
Quaternion.Slerp
Quaternion.FromToRotation
Quaternion.identity。
Quaternion 是一个结构体,本身成员变量相对简单,可以作为函数参数高效传递。
Matrix4x4类
Matrix4x4代表着一个转换,包括位移,旋转,缩放,所以如果给我们提供一个已有的matrix,就可以提取它的这些信息:
//旋转
Quaternion rotation = matrix4X4.rotation;
//缩放
Vector3 scale = matrix4X4.lossyScale;
//位置
Vector3 pos = matrix4X4.GetColumn(3);
需要注意的是,Matrix4x4的相乘顺序是从右往左的(右乘向量),这点需要记住。
作为一个矩阵,它也提供一般对于矩阵的操作:
//转置
public Matrix4x4 transpose { get; }
//是否为单位矩阵
public bool isIdentity { get; }
//行列式
public float determinant { get; }
//逆
public Matrix4x4 inverse { get; }
又提供了一些非常有用的方法:
//一个带有由所传递的平面坐标定义的视锥截面的投影矩阵
public static Matrix4x4 Frustum(float left, float right, float bottom, float top, float zNear, float zFar);
//构造正交矩阵(这个在之前的贴花着色器脚本代码中用到过)
public static Matrix4x4 Ortho(float left, float right, float bottom, float top, float zNear, float zFar);
//构造透视投影矩阵
public static Matrix4x4 Perspective(float fov, float aspect, float zNear, float zFar);
//构造旋转矩阵
public static Matrix4x4 LookAt(Vector3 from, Vector3 to, Vector3 up);
public static Matrix4x4 Rotate(Quaternion q);
//构造缩放矩阵
public static Matrix4x4 Scale(Vector3 vector);
//从位置,旋转,缩放构建矩阵
public static Matrix4x4 TRS(Vector3 pos, Quaternion q, Vector3 s);
awake和start
从文档中我们看到他俩的区别是: Awake()是在脚本对象实例化时被调用的,而Start()是在对象的第一帧时被调用的,而且是在Update()之前。
unity中的yield return
相当于延迟进行
yield return 语句更有用的地方体现在 事件延时 上,以下
还有其他几种参数,官方文档如下(中文为个人翻译):
yield return null; The coroutine will continue after all Update functions have been called on the next frame.
该Cotoutine 会在下一帧所有的Update()函数调用过之后继续