这是效果
附上源码 我的csdn博客是http://blog.csdn.net/zhong1213/article/details/76904263
using UnityEngine; using System.Collections; using System.Collections.Generic; public class TerrainManager : MonoBehaviour { Mesh mesh; //材质 public Material diffuseMap; //顶点、uv、索引信息 private Vector3[] vertives; private Vector2[] uvs; private int[] triangles; private ushort[] blockData; //生成信息 private Vector3 chunkSize;//长宽高 private int groundHeight;//地面高度 //区块主体 private GameObject terrain; void Start() { SetTerrain(10, 10, 10, 5); } // 通过参数生成地形 public void SetTerrain(float width, float height, float length, int groundH) { Init(width, height, length, groundH);//初始化数据 GetVertives(); DrawMesh(); terrain.AddComponent<MeshCollider>(); } /// 初始化计算某些值 private void Init(float width, float height, float length, int groundH) { chunkSize = new Vector3(width, height, length);//初始化区块尺寸并赋值 groundHeight = groundH;//给地面高度赋值 if (terrain != null) { Destroy(terrain); } terrain = new GameObject();//初始化区间 terrain.name = "plane";//设置chunk名字 terrain.layer = 8;//设置区间所在层数。只有这一层内的碰撞体才会被射线检测到 blockData = new ushort[(int)(chunkSize.x * chunkSize.y * chunkSize.z)];//初始化方块数据,方括号内是该区间内所容纳方块数,该数组的容量 //该循环遍历0,0,0 到 (chunksize-1,chunksize-1,chunksize-1)的方块位置。并根据地面高度。分配方块对应的数字。0是空,1是有方块 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 <= groundH) { blockData[getBlockIndex(x, y, z)] = 1; } else { blockData[getBlockIndex(x, y, z)] = 0; } } } } //用于测试 blockData[getBlockIndex(5, 1, 5)] = 0; blockData[getBlockIndex(5, 2, 5)] = 0; blockData[getBlockIndex(5, 3, 5)] = 0; blockData[getBlockIndex(5, 4, 5)] = 0; blockData[getBlockIndex(5, 5, 5)] = 0; blockData[getBlockIndex(5, 5, 6)] = 0; blockData[getBlockIndex(5, 5, 7)] = 0; blockData[getBlockIndex(6, 5, 5)] = 0; blockData[getBlockIndex(7, 5, 5)] = 0; } public void BuildBlock(float px, float py, float pz, int blockID) { //获取对应的方块并且赋值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; } /// <summary> /// 绘制网格 /// </summary> private void DrawMesh() { mesh = terrain.AddComponent<MeshFilter>().mesh;//添加网格组件,并且添加到本地mesh变量里 terrain.AddComponent<MeshRenderer>();//添加网格渲染 if (diffuseMap == null) { Debug.LogWarning("No material,Create diffuse!!"); diffuseMap = new Material(Shader.Find("Diffuse")); } terrain.GetComponent<Renderer>().material = diffuseMap; mesh.Clear(); //给mesh 赋值 mesh.vertices = vertives;//,pos); mesh.uv = uvs; mesh.triangles = triangles; //重置法线 mesh.RecalculateNormals(); //重置范围 mesh.RecalculateBounds(); } /// <summary> /// 生成顶点信息 /// </summary> /// <returns></returns> private Vector3[] GetVertives() { int index = 0;//顶点初始序号 //GetUV(); vertives = new Vector3[(int)((chunkSize.x + 1) * (chunkSize.y + 1) * (chunkSize.z + 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; } //这个包含方块序号和坐标的对应规则,可以直接通过方块坐标获得方块序号 private int getBlockIndex(int x, int y, int z) { return (z + y * ((int)chunkSize.z) + (x * (int)(chunkSize.y) * (int)(chunkSize.z))); } //这部分是为了接下来多区块准备的,就是避开绘制周围一圈方块,因为周围一圈方块的绘制需要根据相邻chunk里的方块来绘制 private bool ifIsSide(int x, int y, int z, int VorT) //v =0 t=1 { if (VorT == 0)//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//1是给三角形遍历用的 { 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; } } } //这部分是顶点遍历的时候。判断顶点周围八个方块是不是一样。只有不一样的情况。这个顶点才会被加载 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; } /// <summary> /// 生成UV信息 /// </summary> /// <returns></returns> /*private Vector2[] GetUV() { int sum = Mathf.FloorToInt((segment.x + 1) * (segment.y + 1)); uvs = new Vector2[sum]; float u = 1.0F / segment.x; float v = 1.0F / segment.y; uint index = 0; for (int i = 0; i < segment.y + 1; i++) { for (int j = 0; j < segment.x + 1; j++) { uvs[index] = new Vector2(j * u, i * v); index++; } } return uvs; }*/ /// <summary> /// 生成三角形信息 /// </summary> /// <returns></returns> 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 (blockData[z + (y * (int)chunkSize.z) + (x * (int)chunkSize.y * (int)chunkSize.z)] != 0){ 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; } }*/ 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)))); 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; } } } } } } } return triangles; } }
相关推荐
通过此脚本可以使地形跟网格贴合,通过此脚本可以使地形跟网格贴合
Unity引擎开发:地形生成与编辑_(10).地形LOD技术.docx Unity引擎开发:地形生成与编辑_(11).地形碰撞与导航.docx Unity引擎开发:地形生成与编辑_(12)....Unity引擎开发:地形生成与编辑_(8
1. **地形编辑器(Terrain Editor)**:Unity内置的地形编辑器提供了一套工具,用于绘制、平滑、升高或降低地形。开发者可以调整高度图,添加纹理贴图,以及种植树木和植被。 2. **脚本(Scripts)**:为了实现动态...
这份名为"Unity地形制作共27页.pdf.zip"的压缩包很可能包含了一份详细的教程或指南,教授如何在Unity中高效、精美地创建和编辑地形。 首先,我们要了解Unity中的地形系统。Unity的地形系统允许开发者通过一个集成的...
Unity地形改变插件 Curve World .unitypackage,能够将平面地形直接渲染成为上下坡道,或者左右弯道
用于将使用3dmax,Terragen或任何其他编辑器创建的3D地形模型快速转换为Unity Terrain的组件。 特征: •支持Unity v5.2 - Unity 2018.x •组件中使用的模型和地形数量无限; •地形在网格的相同位置创建; •将模型的...
1.在Unity中制作好地形; 2.选中场景中的地形,点击Tools菜单下的地形导出即可; 3.导出的地形是obj格式。
unity3d 游戏插件 terrainComposer 地形编辑 5A级别 地貌 制作 工具.zip模型资源unity模型资unity3d 游戏插件 terrainComposer 地形编辑 5A级别 地貌 制作 工具.zip模型资源unity模型资unity3d 游戏插件 terrain...
Unity3D内置了强大的地形编辑器,允许开发者通过简单的操作创建复杂的地形地貌。它支持绘制高度图、添加纹理、种植植被、雕刻山体等,为游戏设计师提供了极大的创作自由度。在这个素材包中,你可以找到各种预设的...
通过这个文件,你可以学习到如何使用Unity地形编辑器进行实际项目开发,了解其各项特性和操作流程。 总之,Unity地形编辑器是一个强大的工具,它提供了丰富的功能,帮助开发者快速创建出令人惊叹的3D环境,同时保持...
Unity的Terrain组件允许开发者通过编辑器的地形编辑器绘制高度图,添加细节(如草、树木等),并设置地形的纹理贴图。这些操作都是基于数据驱动的,而不是生成一个实际的Mesh。这种设计使得大型地形的渲染变得高效,...
第 5 章Unity编辑器 35 第 6 章创建基本的3D游戏场景 79 第 7 章创建基本的2D游戏场景 115 第 8 章资源导入导出流程 147 第 9 章游戏对象、组件和Prefabs 193 第 10 章Shuriken粒子系统 213 第 11 章Mecanim动画系统...
总结来说,Unity3D中的网格合并是优化场景性能的重要手段,特别是在处理复杂的角色模型或地形时。理解网格、材质、骨骼和子网格之间的关系以及如何正确地使用`CombineMeshes`函数,是实现这一技术的关键。通过合理地...
Unity协程(Coroutine)原理深入剖析.pdf Unity协程(Coroutine)原理深入剖析.pdf Unity协程(Coroutine)原理深入剖析.pdf Unity协程(Coroutine)原理深入剖析.pdf Unity协程(Coroutine)原理深入剖析.pdf
# 基于Unity的六边形网格地图生成系统 ## 项目简介 本项目是一个基于Unity引擎的六边形网格地图生成系统,旨在提供一个灵活且功能丰富的工具,用于创建和管理六边形网格地图。该系统涵盖了从地图生成、地形编辑到...
使用Unity制作的网格建造系统,请参看文章和效果视频。相关文章参见:https://blog.csdn.net/sdhexu/article/details/129767967
Unity3d_实现地形上挖洞 Unity3d_实现地形上挖洞 Unity3d_实现地形上挖洞
Unity Mesh网格编程万能网格几何形体 本文分享了一个使用 Unity 的 Mesh 网格编程实现万能网格几何形体的代码,通过设置不同的参数,可以生成各种锥、柱、管状体的网格。下面是我们从代码中总结出的知识点: 1. ...