【unity 5学习记录】 可编辑地形 网格 原理讲解 17.8.8
2017-08-08 14:38
711 查看
本篇为上一篇的原理讲解,我觉得我的表达能力很差,看上一篇的源代码以及边上的注释可能理解到会容易一些
先说ray.cs
射线探测 鼠标按键的探测也写在这里面
0是左键 1右键 2中间滚轮键 px,py,pz是射线所碰到的方块面提供的坐标
C# Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | if (Input.GetMouseButtonDown(0)) { terraManager.BuildBlock(px, py - 1, pz, 0); } else if (Input.GetMouseButtonDown(1)) { terraManager.BuildBlock(px, py, pz, 1); } else if (Input.GetMouseButtonDown(2)) { terraManager.SetTerrain(10, 10, 10, 5); } else { //没有碰撞时 } |
思路是获取鼠标指针射线碰撞的坐标,转化成要操作的方块坐标。
目前是操作一个区块里的方块。
private Vector3 chunkSize;//区块的长宽高
private int groundHeight;//地面高度
private ushort[] blockData;//方块数组
方块数组初始化对象的时候元素数([]里面要表示的)就是 区块 长*宽*高,代码如下
C# Code
1 | blockData = new ushort[(int)(chunkSize.x * chunkSize.y * chunkSize.z) + 1]; |
C# Code
1 2 3 4 | private int getBlockIndex(int x, int y, int z) { return (z + y * ((int)chunkSize.z) + (x * (int)(chunkSize.y) * (int)(chunkSize.z))); } |
先来说顶点绘制。由于顶点比方块多 我们for循环的范围需要+1。比方说2*2*2的方块需要遍历的顶点数就是3*3*3,首先我们要通过函数bool ifIsSide(int x, int y, int z,int VorT)来判断当前遍历是不是周围方块。如果是的话先暂时避开。因为他们并不是上下左右前后6个面都能获取到方块数据。这个函数还有一个参数来区分是顶点的避开还是三角形面的避开,如果是顶点遍历那VorT取0
如果是三角形遍历那 VorT取1
下面附上该函数代码
C# Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | private bool ifIsSide(int x, int y, int z, int VorT) //v =0 t=1 { //检测是否在边界 if (VorT == 0) { if (x == 0 || y == 0 || z == 0 || x >= (int)chunkSize.x || y >= (int)chunkSize.y || z >= (int)chunkSize.z) { return true; } else { return false; } } else { if (x == 0 || y == 0 || z == 0 || x >= (int)chunkSize.x - 1 || y >= (int)chunkSize.y - 1 || z >= (int)chunkSize.z - 1) { return true; } else { return false; } } } |
C# Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | private bool ifDifFromAround(int x, int y, int z) { //检测是否和周围的方块不同 存在或不存在 if (blockData[getBlockIndex(x, y, z)] == 0) { if (blockData[getBlockIndex(x - 1, y, z)] > 0 || blockData[getBlockIndex(x, y - 1, z)] > 0 || blockData[getBlockIndex(x, y, z - 1)] > 0 || blockData[getBlockIndex(x - 1, y - 1, z)] > 0 || blockData[getBlockIndex(x, y - 1, z - 1)] > 0 || blockData[getBlockIndex(x - 1, y, z - 1)] > 0 || blockData[getBlockIndex(x - 1, y - 1, z - 1)] > 0) { return true; } else { return false; } } else { if (blockData[getBlockIndex(x - 1, y, z)] == 0 || blockData[getBlockIndex(x, y - 1, z)] == 0 || blockData[getBlockIndex(x, y, z - 1)] == 0 || blockData[getBlockIndex(x - 1, y - 1, z)] == 0 || blockData[getBlockIndex(x, y - 1, z - 1)] == 0 || blockData[getBlockIndex(x - 1, y, z - 1)] == 0 || blockData[getBlockIndex(x - 1, y - 1, z - 1)] == 0) { return true; } else { return false; } } return false; } |
C# Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | private Vector3[] GetVertives() { int sum; int index = 0; //GetUV(); vertives = new Vector3[(int)((chunkSize.x + 1) * (chunkSize.y + 1) * (chunkSize.z + 1) + 1)]; for (int x = 0; x < chunkSize.x + 1; x++) { for (int y = 0; y < chunkSize.y + 1; y++) { for (int z = 0; z < chunkSize.z + 1; z++) { if (y == 0) { vertives[index] = new Vector3(x, y, z); } else { if (!ifIsSide(x, y, z, 0)) { if (ifDifFromAround(x, y, z)) { vertives[index] = new Vector3(x, y, z); } } } index++; } } } GetTriangles(); return vertives; } |
上下左右前后的方块是不是空的。如果是空的。就需要吧这两个方块之间的面通过添加三角形的方式绘制出来。以下是代码
C# Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 | private int[] GetTriangles() { int sum = Mathf.FloorToInt(chunkSize.x * chunkSize.y * chunkSize.z * 6); triangles = new int[sum]; uint index = 0; for (int x = 0; x < chunkSize.x; x++) { for (int y = 0; y < chunkSize.y; y++) { for (int z = 0; z < chunkSize.z; z++) { if (y == 0) { int self = z + y * ((int)chunkSize.z + 1) + (x * (int)(chunkSize.y + 1) * (int)(chunkSize.z + 1)); int next = z + (y * (int)(chunkSize.z + 1) + ((x + 1) * (int)((chunkSize.y + 1) * (chunkSize.z + 1)))); triangles[index] = self; triangles[index + 1] = self + 1; triangles[index + 2] = next + 1; triangles[index + 3] = self; triangles[index + 4] = next + 1; triangles[index + 5] = next; index += 6; } else { if (!ifIsSide(x, y, z, 1)) { if (blockData[getBlockIndex(x, y, z)] == 0) { //check up and draw triangle if (blockData[getBlockIndex(x, y + 1, z)] != 0) { int self = z + (y + 1) * ((int)chunkSize.z + 1) + (x * (int)(chunkSize.y + 1) * (int)(chunkSize.z + 1)); int next = z + ((y + 1) * (int)(chunkSize.z + 1) + ((x + 1) * (int)((chunkSize.y + 1) * (chunkSize.z + 1)))); < 233e4 wbr> triangles[index] = self; triangles[index + 1] = next + 1; triangles[index + 2] = self + 1; triangles[index + 3] = self; triangles[index + 4] = next; triangles[index + 5] = next + 1; index += 6; } //check doawn and draw triangle if (blockData[getBlockIndex(x, y - 1, z)] != 0) { int self = z + (y) * ((int)chunkSize.z + 1) + (x * (int)(chunkSize.y + 1) * (int)(chunkSize.z + 1)); int next = z + ((y) * (int)(chunkSize.z + 1) + ((x + 1) * (int)((chunkSize.y + 1) * (chunkSize.z + 1)))); triangles[index] = self; triangles[index + 1] = self + 1; triangles[index + 2] = next + 1; triangles[index + 3] = self; triangles[index + 4] = next + 1; triangles[index + 5] = next; index += 6; } //side if (blockData[getBlockIndex(x, y , z - 1)] != 0) { int self = z + (y) * ((int)chunkSize.z + 1) + (x * (int)(chunkSize.y + 1) * (int)(chunkSize.z + 1)); int next = z + ((y) * (int)(chunkSize.z + 1) + ((x + 1) * (int)((chunkSize.y + 1) * (chunkSize.z + 1)))); int sup = self + (int)chunkSize.z + 1; int nup = next + (int)chunkSize.z + 1; triangles[index] = self; triangles[index + 1] = nup; triangles[index + 2] = sup; triangles[index + 3] = self; triangles[index + 4] = next; triangles[index + 5] = nup; index += 6; } if (blockData[getBlockIndex(x, y , z + 1)] != 0) { int self = z + 1 + (y) * ((int)chunkSize.z + 1) + (x * (int)(chunkSize.y + 1) * (int)(chunkSize.z + 1)); int next = z + 1 + ((y) * (int)(chunkSize.z + 1) + ((x + 1) * (int)((chunkSize.y + 1) * (chunkSize.z + 1)))); int sup = self + (int)chunkSize.z + 1; int nup = next + (int)chunkSize.z + 1; triangles[index] = self; triangles[index + 1] = sup; triangles[index + 2] = nup; triangles[index + 3] = self; triangles[index + 4] = nup; triangles[index + 5] = next; index += 6; } if (blockData[getBlockIndex(x - 1, y, z)] != 0) { int self = z + (y) * ((int)chunkSize.z + 1) + (x * (int)(chunkSize.y + 1) * (int)(chunkSize.z + 1)); int next = z + ((y) * (int)(chunkSize.z + 1) + ((x + 1) * (int)((chunkSize.y + 1) * (chunkSize.z + 1)))); int sup = self + (int)chunkSize.z + 1; int nup = next + (int)chunkSize.z + 1; triangles[index] = self; triangles[index + 1] = sup; triangles[index + 2] = sup + 1; triangles[index + 3] = self; triangles[index + 4] = sup + 1; triangles[index + 5] = self + 1; index += 6; } if (blockData[getBlockIndex(x + 1, y , z)] != 0) { int self = z + (y) * ((int)chunkSize.z + 1) + ((x + 1) * (int)(chunkSize.y + 1) * (int)(chunkSize.z + 1)); int next = z + ((y) * (int)(chunkSize.z + 1) + ((x + 2) * (int)((chunkSize.y + 1) * (chunkSize.z + 1)))); int sup = self + (int)chunkSize.z + 1; int nup = next + (int)chunkSize.z + 1; triangles[index] = self; triangles[index + 1] = sup + 1; triangles[index + 2] = sup; triangles[index + 3] = self; triangles[index + 4] = self + 1; triangles[index + 5] = sup + 1; index += 6; } //vertives[index] = new Vector3(x, y, z); } //check dawn and draw } //index++; } } } } return triangles; } |
接下来是执行方块的放置和破坏的函数。表面上是放置和破坏。实际上是把整个地形重新绘制一遍,所以我们要引入区块的思想。不然绘制的太多。会导致运算量过大
C# Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | public void BuildBlock(float px, float py, float pz, int blockID) { blockData[(int)((pz + py * ((int)chunkSize.z) + (px * (int)(chunkSize.y) * (int)(chunkSize.z))))] = (ushort)blockID; GetVertives(); //给mesh 赋值 mesh.Clear(); mesh.vertices = vertives;//,pos); mesh.uv = uvs; mesh.triangles = triangles; //重置法线 mesh.RecalculateNormals(); //重置范围 mesh.RecalculateBounds(); terrain.GetComponent<MeshCollider>().sharedMesh = mesh; } |
相关文章推荐
- 【unity 5学习记录】 可编辑地形 网格(类似minecraft)17.8.8
- WebRTC学习记录(1):采集microphone到文件原理实践&讲解【转】
- WebRTC学习记录(1):采集microphone到文件原理实践&讲解
- Unity学习日常问题记录五--3dMax导入模型的一些问题
- Flask学习记录之MarkDown编辑文本
- unity实现可编辑网格
- [学习记录]Unity界面入门---(一)
- 转载Unity地形编辑
- unity地形编辑扩展插件Landspace Auto Material介绍
- 【Numpy学习记录】np.transpose讲解
- ASP.net中的AJAX学习记录六 无刷新的数据编辑(GridView和DetailsView结合实例)
- Unity学习疑问记录之将图切割保存
- ArcGIS学习记录—属性表的编辑与修改
- Unity学习疑问记录之脚本生命周期
- [AaronYang风格]微软Unity2.X系统学习笔记,记录
- AR 学习记录 unity+vuforia+ android 初次搭建
- Unity学习疑问记录之保卫伦敦塔学习体会
- unity学习记录
- Unity学习日常问题记录九-关于Lookat与模型坐标系的相关的问题以及父子物体的刚体
- 微信小程序 运行机制 框架原理(自我学习记录)