UnityMesh:使用程序绘制一个带有UV坐标的Plane面

在游戏开发过程中,模型一般由美术提供,程序一般只负责使用,以及优化。一般的优化手段就是mesh的合批,高低摸的转换之类,以及捏脸系统等等。但是大家要知道一点,Unity不仅可以处理模型,还可以创建模型,只是在正常的商业游戏开发中并不需要程序去用代码制作模型。但是知道Unity中模型是怎么构建的,非常有利于我们对开发的深入理解。

1.Unity中模型是怎么显示的

(1)简单来说,模型都是用三角面构成。在理解模型的时候,可以直接将模型认作为Mesh网格。所以Mesh网格就是由三角面片组成,如下:图1-1
这是一个我绘制的一个最简单的正方形面片,他由两个三角形组成,三角形124,和三角形234,注意一下这里的顺序,我们在设置点的时候,必须按照顺时针,因为通常情况下我们只绘制一面,另外一面不需要绘制,当然你也可以,只是会消耗更多的性能。
(2)看到上面,其实Mesh的原理就已经很清楚了,通过顶点,连接线组成三角形,然后由三角形构成面,最后得到各种各种的模型。当然,上面的例子只是为了让同学们知道Mesh组成原理是什么,因为哪怕是最简单的内建Plane面,也有着一百多个顶点。我们来建一个Plane,看看它的构成
在这里插入图片描述
我们可以看到,Unity内建的Plane大小为10x10,有着121个顶点。更丰富的顶点意味着我们可以做丰富的动画,扭曲,折叠等等操作。但是通常也意味着更多的计算量消耗。下面我们就来手动创建一个可以任意设置长宽的Plane面吧

准备工作

(1)Mesh,MeshFilter,MeshRender
Mesh:模型的顶点坐标、法线、uv坐标、三角面信息均包含在Mesh中
MeshFilter:掌管一个Mesh对象,并从中取得数据处理,最后交给MeshRender绘制
MeshRender:得到处理后的Mesh信息,并且绘制在空间中。
(2)我们的工作
创建一组顶点,按照规则写出三角形序列,然后将接受这个顶点和三角形序列的Mesh交给MeshFIlter即可。

代码部分

我会写的比较详细,因此可能会有一部分重复代码
(1)初始类

//如果添加的对象上没有MeshFilter,则给对象添加一个MeshFilter
[RequireComponent(typeof(MeshFilter))]
//如果添加的对象上没有MeshRenderer,则给对象添加一个MeshRenderer
[RequireComponent(typeof(MeshRenderer))]
public class DrawPlane{
	//实际操作的MeshFilter 
	private MeshFilter filter;
	//实际的Mesh
	private Mesh mesh;
	//记录顶点信息
	private List<Vector3> vts = new List<Vector3>();
	//自身的uv坐标
	private int[] uvs;
	//三角形数组
	private int[] tris;
	//x轴单位
	public int xSize;
	//y轴单位
	public int ySize;
	//x轴每单位大小,用于计算坐标
	public float xSeg;
	//y轴每单位大小,用于计算坐标
	public float ySeg;
	//x轴顶点个数 ==== xSize+1
	private int xCount;
	//y轴顶点个数 ==== ySize+1
	private int yCount;
	
	//初始化
	private void Start(){
		filter = GetComponent<MeshFilter>();
		xCount = xSize + 1;
		yCount = ySize + 1;
		//得到每个顶点的坐标
		vts = CalVts();
		//设置Mesh
		SetMesh();
	}
	

	
	//计算顶点信息,多少个顶点,每个顶点的坐标等
	private List<Vector3> CalVts(){
		//我们以挂载对象的位置作为起始点
		Vector3 pos = =tranform.position;
		
		List<Vector3> vals = new List<Vector3>();
		for(int i = 0 ; i < xCount ; i++){
			for(int j = 0 ; j < yCount ; j++){
				Vector3 vector =pos + new Vector3(i*xSeg,j*ySeg,0);
				vals.Add(vector);
			}
		}
		return vals;
	}

	//对Mesh进行设置
	private void SetMesh(){
		mesh = new Mesh();
		//因为每个有效点我们需要绘制两个三角形,共计六个顶点,所以对tris数组初始大小为
		tris = new int[xSize*ySize*6];
		//记录每个有效点的三角形起始下标,每个有效点需要画两个三角形,六个顶点,因此每次迭代triCount +=6
		int triCount = 0 ;
		for(int i = 0 ; i < ySize ; i++){
			for(int j = 0 ; j < xSize ; j++){
				//每个有效点绘制两个三角形
				//每个顶点,在vts中的下标索引
				int startIndex = i * xCount + j; 
				//第一个三角形,三个顶点
				tris[triCount] = startIndex ;
				//第一个三角形第二个点为初始点的正上方相邻点
				tris[triCount+1] = startIndex + xCount ;
				//第一个三角形第三个点为右边相邻的点
				tris[triCount+2] = startIndex + 1;
				
				//绘制第二个三角形,
				//第二个三角形第一个点为初始点的正上方相邻的点
				tris[triCount+3] = startIndex + xCount ;
				//第二个三角形第二个点为初始点右上方的点
				tris[triCount+4] = startIndex + xCount + 1;
				//第二个三角形第三个点为初始点的右边相邻的点
				tris[triCount+5] = startIndex + 1;
				
				triCount += 6;
			}
		}
		
		//将顶点传给mesh
		mesh.vertices = vts.ToArray();
		//将三角形的绘制序列传给mesh
		mesh.triangles = tris;
		
		//至此我们的三角形其实已经绘制成功了,但是面并没有uv坐标,如果了解uv的同学值得,纹理就是通过顶点之间uv坐标的插值来计算颜色值的。
		//因此我们还需要计算一下uv坐标
		//有多少个顶点,就有多少个uv坐标
		//uv坐标的范围在0-1之间,其实就相当于给顶点坐标做一个归一化处理
		uvs = new int[vts.Count];
		float xOffset = 1.0f / xCount;
		float yOffset = 1.0f / yCount;
		for(int i = 0 ; i < yCount ; i++){
			for(int j = 0 ; j < xCount; j++){
				//设置每个顶点的uv坐标
				//这里我们也可以做一些小巧思,比如y轴翻转,或者x轴翻转,大家能想到怎么做吗
				uvs[i * xCount+ j] = new Vector2(j * xOffset , i * yOffset );
			}
		}
		//将uv设置给mesh
		mesh.uv = uvs;
		//这三个方法是相当于对mesh用新数据进行重置
		mesh.RecalculateBounds();
        mesh.RecalculateNormals();
        mesh.RecalculateTangents();
        //将mesh交给filter
        filter.mesh = mesh;
	}
}

(2)将脚本挂载在一个空物体上,设置xSize,ySize,xSeg,ySeg即可,比如我们现在得到一个5x7,x,y轴单位长度为1的plane面

在这里插入图片描述
当然我们也可以将这个Plane导出作为一个模型,或者对这个Plane添加一些顶点动画,还是开头说的,学会用程序制作模型,对实际开发的意义并不大。但是能帮助我们更好的理解模型构建的流程,对模型的优化,使用有很大的帮助。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值