热门标签 | HotTags
当前位置:  开发笔记 > 开放平台 > 正文

Unity3D绘制地形的实现方法

这篇文章主要为大家详细介绍了Unity3D绘制地形的实现方法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

项目中肯定会遇到需要用户自己绘制地形的需求,然后根据地形自动生成房间。下面说说我在绘制地形的实现方法。

我们百度可以看到很多关于自己创建mesh的博客,mesh的生成需要三角面顶点坐标以及顶点序列。所以,想要创建我们想要的mesh,首先要获取到绘制mesh的顶点。我们用户在绘制自己想创建的地形时会有很大的自由性。他是随心所欲想怎么画就怎么画。这也造就了很大的错误风险性,要求程序更加智能。好了,下面说下我们给自己程序设定的一些规则。

首先我们设置在绘制的时候摄像头的forward朝向Y轴向上,即我们可以俯视到的就是xz轴组成的平面。其次我们要使用linerenderer来画线,linerenderer组合起来必须是一个封闭的区间,否则有无限种可能。

而画房间不仅有最外层的墙,还有内部一个个小房间,他们也组成了闭合区间。而我们在画地形时需要抓取的是最外层闭合区间的顶点。本文画复杂多边形使用的算法是耳切法分割多边形,所以我们选择操作的方向是逆时针方向。算法链接。下面就说下在做项目时遇到的核心问题处理。还是老套路,先放效果图吸睛。

一、选取第一个处理的顶点

如上我们指定的规则是摄像机沿Y轴向下俯视。所以我们获取所有顶点,然后选取这些定点中x值最小的,选取出X值最小的点,有可能有一个,也有可能有多个,所以我们要接着筛选。在获取的这些点中我们设置筛选的条件是z值最小,这样就能获取到唯一的一个点。此时,该点即为凸点。代码如下:

 Vector3 firstValue=Vector3.zero;
 for (int i=0;i firstValue.z)
  {
  return;
  }
 }
 firstValue = plist[i].transform.position;
 }
 }

二、获取逆时针方向的第二个点

我们获取到所有与第一个点连线的线段的斜率,因为是闭合区间,所以至少会有两条线段与第一个点连接,由于第一个点为凸点且x值为所有点里最小,所以我们比较与第一个点连接的线段斜率。会有如下两种情况:斜率存在和斜率不存在。当斜率存在时,我们可以想象,k为最小值时即为逆时针的第二个点,k为最大值时线段连接的另一个端点为逆时针方向的最后一个点。当斜率不存在时即线段是平行于x轴的,所以我们要比较线段的斜率最小值是否小于0,如果小于0则这个线段连接的另一个端点为第二个点。如果斜率大于0,则这条斜率不存在的线段连接的端点为第二个点。同理可获取最后一个端点。

 /// 
 /// 返回第二个顶点坐标
 /// 
 /// 
 /// 
 private Vector3 returnSecondValue(Vector3 v)
 {
 //Debug.Log("v+" + v);
 List lrst = new List();
 for (int i=0;i= 2)
 {
 float k1 = 0; //斜率最大
 float k2 = 0; //斜率最小
 Vector3 v1=Vector3.zero;
 Vector3 v2 = Vector3.zero;
 LineRenderer llrr=new LineRenderer();
 for (int i=0;i= 0)
  {
  v2 = vvv;
  llrr = lrst[i]._lr;
  continue;
  }
 }
 float k= (vvv.z - v.z) / (vvv.x - v.x);
 if (i == 0)
 {
  k1 = k;
  v1 = vvv;
  lastLineRenderer = lrst[i]._lr;
  k2 = k;
  v2 = vvv;
  llrr = lrst[i]._lr;
 }
 else
 {
  if (k1  k)
  {
  k2 = k;
  v2 = vvv;
  llrr = lrst[i]._lr;
  }
 }
 
 }
 
 VertexList.Add(new VertexStruct(1,v2));
 lrlist.Remove(llrr);
 Debug.Log("VertexList[1]._vec+" + VertexList[1]._vec);
 return VertexList[1]._vec;
 }
 else
 {
 Debug.LogError("此处有错误");
 isCOntinue= false;
 if (lrst.Count <2)
 {
 _Warning.SetActive(true);
 StartCoroutine(Globle.InvokeDelay(()=> { _Warning.SetActive(false); }, fadeTime));
 }
 
 return Vector3.zero;
 } 
 }

三、处理其他顶点

处理其他顶点我们就比较复杂,因为一个顶点会有很多线段与之相连,而我们要获取的是最外围的顶点。所以我们在获取到第二个顶点以及与第二个顶点连接的线段后(去除连接第一个顶点和第二个顶点的线段),如下图:三条线段OA,OB,OC.OD.

我们自己分析会知道我们要得到OD,但是程序没有我们直观的分析能力。程序只能依靠计算来作为“视觉”依靠。所以接下来就是我们的处理。首先我们要判断凹凸角。因为毋庸置疑凹角肯定是最外层的闭合回路。如图角EOD.所以接下来我们要进行计算筛选。首先我们要计算各个闭合回路的点是凸角还是凹角。如判断角EOA,角EOB,角EOB,角EOC,角EOD。判断的方法就是向量的叉乘。

3.1判断凹凸角

我们知道第一个点为凸角,所以我们先根据第一个顶点的两条边叉乘得到凸角的方向。即向量o2o1xo1E,这里我们一定要记住判断凹凸角的向量叉乘一定要选取同一走向的向量,即都沿着逆时针方向或者都顺时针方向。而unity的坐标系是右手坐标系,所以叉乘的结果和我们右手定则得到的方向相反。即沿Y轴向下。我们得到标准凸角的叉乘方向,在用其他角的叉乘结果和标准方向比较。如果同向即为凸角,否则为凹角。代码如下:

 private float crossValue(Vector3 v1,Vector3 v2)
 {
 v1 = new Vector3(v1.x,0,v1.z);//把顶点坐标处理下
 v2 = new Vector3(v2.x,0,v2.z);//把顶点坐标处理下
 return Vector3.Dot(Vector3.up, Vector3.Cross(v1.normalized, v2.normalized));
 }

根据float值判断,当为负值即超Y轴向下,为凸角。当为正值时朝Y轴向上,为凹角。
判断结果一般会出现如下三种情况:1.全是凸角2.全是凹角3既有凸角也有凹角。在程序中我们需要加入if判断。第一种情况全是凸角:我们就需要计算组成角的两边向量点积,点积越小,夹角越大,也就是最外围线段。第二种情况和第三种情况处理情况相同,筛选出来凹角,然后根向量点积公式,点积越大,夹角越大。即可求出最外围线段。代码如下:

private void dealOtherPoint(Vector3 sv)
 {
 int num = lrlist.Count;
 int _addIndex;
 
 //后续还要添加
 List TemporaryList;
 while (true)
 {
 TemporaryList = new List();
 num--;
 if (num<-1)
 {
 isCOntinue= false;
 Debug.Log("重新智能处理,若处理不了,则警告用户重新操作");
 _Warning.SetActive(true);
 StartCoroutine(Globle.InvokeDelay(() => { _Warning.SetActive(false); }, fadeTime));
 //Debug.LogError("死循环1");
 return;
 }
 //Debug.Log("sv+" + sv);
 //在剩下的所有定点中找按顺序排列的下一个顶点
 for (int i = 0; i 1)
 {
 List AoList =new List();//记录凹角个数
 for (int i = 0; i  GetdotValue(vc, vm) &#63; GetdotValue(vc, vm) : dotValue;//取余弦值最小值
  dotValueIndex = dotValue > GetdotValue(vc, vm) &#63; i : dotValueIndex;
  }
  VertexList.Add(new VertexStruct(_addIndex, TemporaryList[dotValueIndex]._vec));
 }
 //全是凹角
 else //if (AoList.Count == 1)
 {
  float dotValue = 1;
  int dotValueIndex = 0;
  for (int i = 0; i  temporarylrList = new List();
 for (int i=0;i

好了以上我们就可以筛选出最外围顶点了并把他们添加到数组中。

四、划分三角形

耳切法分割三角形算法。点击打开链接。按照文章的讲解就可以明白解决方法。然后将自己想法用程序表达出来。

五、创建mesh

接下来也是最后一步,我们根据顶点来创建mesh。我们在分割多边形时会得到多个三角形以及对应三角形的顶点索引,在创建mesh时将顶点以及对应的索引数组赋值给mesh.vertices和mesh.triangles。代码如下:

//处理下得到的list数组
 
 int[] ints = new int[verticeList.Count * 3];
 for (int i = 0; i ().material= myPlaneMaterial;
 g.transform.tag = "House";
 g.transform.SetParent(_House.transform);
 
 Mesh mesh = new Mesh();
 mesh.vertices = vecs;
 mesh.triangles = ints;
 g.AddComponent().mesh = mesh;
 g.AddComponent().sharedMesh=mesh;

里面的处理代码很繁琐,要不断判断凹凸角的问题以及最大夹角。重要的是理解耳切法算法原理以及他的一些判断标准,就能很好的理解以及完成我们的需求了。希望本博客对你有帮助。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


推荐阅读
  • 本文由编程笔记#小编为大家整理,主要介绍了logistic回归(线性和非线性)相关的知识,包括线性logistic回归的代码和数据集的分布情况。希望对你有一定的参考价值。 ... [详细]
  • 本文详细解析了JavaScript中相称性推断的知识点,包括严厉相称和宽松相称的区别,以及范例转换的规则。针对不同类型的范例值,如差别范例值、统一类的原始范例值和统一类的复合范例值,都给出了具体的比较方法。对于宽松相称的情况,也解释了原始范例值和对象之间的比较规则。通过本文的学习,读者可以更好地理解JavaScript中相称性推断的概念和应用。 ... [详细]
  • 一、Hadoop来历Hadoop的思想来源于Google在做搜索引擎的时候出现一个很大的问题就是这么多网页我如何才能以最快的速度来搜索到,由于这个问题Google发明 ... [详细]
  • 本文介绍了闭包的定义和运转机制,重点解释了闭包如何能够接触外部函数的作用域中的变量。通过词法作用域的查找规则,闭包可以访问外部函数的作用域。同时还提到了闭包的作用和影响。 ... [详细]
  • Linux服务器密码过期策略、登录次数限制、私钥登录等配置方法
    本文介绍了在Linux服务器上进行密码过期策略、登录次数限制、私钥登录等配置的方法。通过修改配置文件中的参数,可以设置密码的有效期、最小间隔时间、最小长度,并在密码过期前进行提示。同时还介绍了如何进行公钥登录和修改默认账户用户名的操作。详细步骤和注意事项可参考本文内容。 ... [详细]
  • 学习SLAM的女生,很酷
    本文介绍了学习SLAM的女生的故事,她们选择SLAM作为研究方向,面临各种学习挑战,但坚持不懈,最终获得成功。文章鼓励未来想走科研道路的女生勇敢追求自己的梦想,同时提到了一位正在英国攻读硕士学位的女生与SLAM结缘的经历。 ... [详细]
  • 生成式对抗网络模型综述摘要生成式对抗网络模型(GAN)是基于深度学习的一种强大的生成模型,可以应用于计算机视觉、自然语言处理、半监督学习等重要领域。生成式对抗网络 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 云原生边缘计算之KubeEdge简介及功能特点
    本文介绍了云原生边缘计算中的KubeEdge系统,该系统是一个开源系统,用于将容器化应用程序编排功能扩展到Edge的主机。它基于Kubernetes构建,并为网络应用程序提供基础架构支持。同时,KubeEdge具有离线模式、基于Kubernetes的节点、群集、应用程序和设备管理、资源优化等特点。此外,KubeEdge还支持跨平台工作,在私有、公共和混合云中都可以运行。同时,KubeEdge还提供数据管理和数据分析管道引擎的支持。最后,本文还介绍了KubeEdge系统生成证书的方法。 ... [详细]
  • 近年来,大数据成为互联网世界的新宠儿,被列入阿里巴巴、谷歌等公司的战略规划中,也在政府报告中频繁提及。据《大数据人才报告》显示,目前全国大数据人才仅46万,未来3-5年将出现高达150万的人才缺口。根据领英报告,数据剖析人才供应指数最低,且跳槽速度最快。中国商业结合会数据剖析专业委员会统计显示,未来中国基础性数据剖析人才缺口将高达1400万。目前BAT企业中,60%以上的招聘职位都是针对大数据人才的。 ... [详细]
  • 本文讨论了同事工资打听的话题,包括同工不同酬现象、打探工资的途径、为什么打听别人的工资、职业的本质、商业价值与工资的关系,以及如何面对同事工资比自己高的情况和凸显自己的商业价值。故事中的阿巧发现同事的工资比自己高后感到不满,通过与老公、闺蜜交流和搜索相关关键词来寻求解决办法。 ... [详细]
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • 本文介绍了C#中生成随机数的三种方法,并分析了其中存在的问题。首先介绍了使用Random类生成随机数的默认方法,但在高并发情况下可能会出现重复的情况。接着通过循环生成了一系列随机数,进一步突显了这个问题。文章指出,随机数生成在任何编程语言中都是必备的功能,但Random类生成的随机数并不可靠。最后,提出了需要寻找其他可靠的随机数生成方法的建议。 ... [详细]
author-avatar
风信子的春天R
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有