欧美大屁股bbbbxxxx,狼人大香伊蕉国产www亚洲,男ji大巴进入女人的视频小说,男人把ji大巴放进女人免费视频,免费情侣作爱视频

歡迎來到入門教程網(wǎng)!

C#教程

當前位置:主頁 > 軟件編程 > C#教程 >

Unity3D繪制地形的實現(xiàn)方法

來源:本站原創(chuàng)|時間:2020-01-10|欄目:C#教程|點擊: 次

項目中肯定會遇到需要用戶自己繪制地形的需求,然后根據(jù)地形自動生成房間。下面說說我在繪制地形的實現(xiàn)方法。

我們百度可以看到很多關于自己創(chuàng)建mesh的博客,mesh的生成需要三角面頂點坐標以及頂點序列。所以,想要創(chuàng)建我們想要的mesh,首先要獲取到繪制mesh的頂點。我們用戶在繪制自己想創(chuàng)建的地形時會有很大的自由性。他是隨心所欲想怎么畫就怎么畫。這也造就了很大的錯誤風險性,要求程序更加智能。好了,下面說下我們給自己程序設定的一些規(guī)則。

首先我們設置在繪制的時候攝像頭的forward朝向Y軸向上,即我們可以俯視到的就是xz軸組成的平面。其次我們要使用linerenderer來畫線,linerenderer組合起來必須是一個封閉的區(qū)間,否則有無限種可能。

而畫房間不僅有最外層的墻,還有內(nèi)部一個個小房間,他們也組成了閉合區(qū)間。而我們在畫地形時需要抓取的是最外層閉合區(qū)間的頂點。本文畫復雜多邊形使用的算法是耳切法分割多邊形,所以我們選擇操作的方向是逆時針方向。算法鏈接。下面就說下在做項目時遇到的核心問題處理。還是老 ,先放效果圖吸睛。

一、選取第一個處理的頂點

如上我們指定的規(guī)則是攝像機沿Y軸向下俯視。所以我們獲取所有頂點,然后選取這些定點中x值最小的,選取出X值最小的點,有可能有一個,也有可能有多個,所以我們要接著篩選。在獲取的這些點中我們設置篩選的條件是z值最小,這樣就能獲取到唯一的一個點。此時,該點即為凸點。代碼如下:

 Vector3 firstValue=Vector3.zero;
 for (int i=0;i<plist.Count;i++)
 {
  if (plist[i].position.x<= firstValue.x)
  {
  if (plist[i].position.x == firstValue.x)
  {
   if (plist[i].position.z > firstValue.z)
   {
   return;
   }
  }
  firstValue = plist[i].transform.position;
  }
 }

二、獲取逆時針方向的第二個點

我們獲取到所有與第一個點連線的線段的斜率,因為是閉合區(qū)間,所以至少會有兩條線段與第一個點連接,由于第一個點為凸點且x值為所有點里最小,所以我們比較與第一個點連接的線段斜率。會有如下兩種情況:斜率存在和斜率不存在。當斜率存在時,我們可以想象,k為最小值時即為逆時針的第二個點,k為最大值時線段連接的另一個端點為逆時針方向的最后一個點。當斜率不存在時即線段是平行于x軸的,所以我們要比較線段的斜率最小值是否小于0,如果小于0則這個線段連接的另一個端點為第二個點。如果斜率大于0,則這條斜率不存在的線段連接的端點為第二個點。同理可獲取最后一個端點。

 /// <summary>
 /// 返回第二個頂點坐標
 /// </summary>
 /// <param name="v"></param>
 /// <returns></returns>
 private Vector3 returnSecondValue(Vector3 v)
 {
 //Debug.Log("v+" + v);
 List<LineRendererStruct> lrst = new List<LineRendererStruct>();
 for (int i=0;i<lrlist.Count;i++)
 {
  if (Vector3.Distance(lrlist[i].GetPosition(0),v)<0.1f)
  {
  lrst.Add(new LineRendererStruct(0, lrlist[i]));
  }
  else if (Vector3.Distance(lrlist[i].GetPosition(1), v) < 0.1f)
  {
  lrst.Add(new LineRendererStruct(1, lrlist[i]));
  }
 }
 //Debug.Log("lrst.Count+"+lrst.Count);
 if (lrst.Count >= 2)
 {
  float k1 = 0; //斜率最大
  float k2 = 0; //斜率最小
  Vector3 v1=Vector3.zero;
  Vector3 v2 = Vector3.zero;
  LineRenderer llrr=new LineRenderer();
  for (int i=0;i< lrst.Count;i++)//選取斜率最大和最小的兩個點
  {
  Vector3 vvv= lrst[i]._lr.GetPosition(lrst[i]._index == 0 ? 1 : 0);
  if (vvv.x-v.x==0)//此處斜率不存在 就是平行x軸狀態(tài)
  {
   if (k1 <= 0)
   {
   v1 = vvv;
   llrr = lrst[i]._lr;
   lastLineRenderer = lrst[i]._lr;
   continue;
   }
   if (k2 >= 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)
   {
   k1 = k;
   v1 = vvv;
   lastLineRenderer = lrst[i]._lr;
   }
   if (k2 > 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判斷凹凸角

我們知道第一個點為凸角,所以我們先根據(jù)第一個頂點的兩條邊叉乘得到凸角的方向。即向量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));
 }

根據(jù)float值判斷,當為負值即超Y軸向下,為凸角。當為正值時朝Y軸向上,為凹角。
判斷結果一般會出現(xiàn)如下三種情況:1.全是凸角2.全是凹角3既有凸角也有凹角。在程序中我們需要加入if判斷。第一種情況全是凸角:我們就需要計算組成角的兩邊向量點積,點積越小,夾角越大,也就是最外圍線段。第二種情況和第三種情況處理情況相同,篩選出來凹角,然后根向量點積公式,點積越大,夾角越大。即可求出最外圍線段。代碼如下:

private void dealOtherPoint(Vector3 sv)
 {
 int num = lrlist.Count;
 int _addIndex;
 
 //后續(xù)還要添加
 List<VertexStruct> TemporaryList;
 while (true)
 {
  TemporaryList = new List<VertexStruct>();
  num--;
  if (num<-1)
  {
  isContinue = false;
  Debug.Log("重新智能處理,若處理不了,則警告用戶重新操作");
  _Warning.SetActive(true);
  StartCoroutine(Globle.InvokeDelay(() => { _Warning.SetActive(false); }, fadeTime));
  //Debug.LogError("死循環(huán)1");
  return;
  }
  //Debug.Log("sv+" + sv);
  //在剩下的所有定點中找按順序排列的下一個頂點
  for (int i = 0; i < lrlist.Count; i++)
  {
  if (Vector3.Distance(lrlist[i].GetPosition(0),sv)<0.1f)
  {
   if (lastLineRenderer == lrlist[i])
   {
   //Debug.Log("LastKinerenderer1");
   return;
   }
   _addIndex = VertexList.Count;
   TemporaryList.Add(new VertexStruct(i, lrlist[i].GetPosition(1)));
   continue;
  }
  else if (Vector3.Distance(lrlist[i].GetPosition(1), sv) < 0.1f)
  { 
   if (lastLineRenderer == lrlist[i])
   {
   Debug.Log("LastKinerenderer2");
   Debug.Log(lrlist.Count);
   return;
   }
   _addIndex = VertexList.Count;
   TemporaryList.Add(new VertexStruct(i, lrlist[i].GetPosition(0)));
   continue;
  }
  }
  _addIndex = VertexList.Count;
  if (TemporaryList.Count== 1)//一個頂點只有兩個linerenderer連接時
  {
  VertexList.Add(new VertexStruct(_addIndex, TemporaryList[0]._vec));
  lrlist.RemoveAt(TemporaryList[0]._num);
  }
  else if (TemporaryList.Count>1)
  {
  List<int> AoList =new List<int>();//記錄凹角個數(shù)
  for (int i = 0; i < TemporaryList.Count; i++)
  {
   if (!ISTuAngle(sv, TemporaryList[i]._vec))
   AoList.Add(i);
  }
  //初始邊向量
  Vector3 vc = sv - VertexList[VertexList.Count - 1]._vec;
  //全是凸角
  if (AoList.Count == 0)
  {
   float dotValue=1;
   int dotValueIndex = 0;
   for (int i=0;i< TemporaryList.Count; i++)
   {
   Vector3 vm = TemporaryList[i]._vec - sv;
   dotValue = dotValue > GetdotValue(vc, vm) ? GetdotValue(vc, vm) : dotValue;//取余弦值最小值
   dotValueIndex = dotValue > GetdotValue(vc, vm) ? 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 < TemporaryList.Count; i++)
   {
   Vector3 vm = TemporaryList[AoList[i]]._vec - sv;
   dotValue = dotValue < GetdotValue(vc, vm) ? GetdotValue(vc, vm) : dotValue;//取余弦值最大值
   dotValueIndex = dotValue < GetdotValue(vc, vm) ? i : dotValueIndex;
   }
   VertexList.Add(new VertexStruct(_addIndex, TemporaryList[dotValueIndex]._vec));
  }
  List<LineRenderer> temporarylrList = new List<LineRenderer>();
  for (int i=0;i< TemporaryList.Count;i++)
  {
   temporarylrList.Add(lrlist[TemporaryList[i]._num]);
  }
  for (int i=0;i< temporarylrList.Count;i++)
  {
   if (lrlist.Contains(temporarylrList[i]))
   {
   lrlist.Remove(temporarylrList[i]);
   }
   else
   Debug.Log("有錯誤");
  }
  }
  sv = VertexList[VertexList.Count - 1]._vec;
 }
 }

好了以上我們就可以篩選出最外圍頂點了并把他們添加到數(shù)組中。

四、劃分三角形

耳切法分割三角形算法。點擊打開鏈接。按照文章的講解就可以明白解決方法。然后將自己想法用程序表達出來。

五、創(chuàng)建mesh

接下來也是最后一步,我們根據(jù)頂點來創(chuàng)建mesh。我們在分割多邊形時會得到多個三角形以及對應三角形的頂點索引,在創(chuàng)建mesh時將頂點以及對應的索引數(shù)組賦值給mesh.vertices和mesh.triangles。代碼如下:

//處理下得到的list數(shù)組
 
 int[] ints = new int[verticeList.Count * 3];
 for (int i = 0; i < verticeList.Count; i++)
 {
  ints[3 * i + 0] = verticeList[i][0];
  ints[3 * i + 1] = verticeList[i][2];
  ints[3 * i + 2] = verticeList[i][1];
 }
 
 GameObject g = new GameObject("MyPlane");
 g.AddComponent<MeshRenderer>().material= myPlaneMaterial;
 g.transform.tag = "House";
 g.transform.SetParent(_House.transform);
 
 Mesh mesh = new Mesh();
 mesh.vertices = vecs;
 mesh.triangles = ints;
 g.AddComponent<MeshFilter>().mesh = mesh;
 g.AddComponent<MeshCollider>().sharedMesh=mesh;

里面的處理代碼很繁瑣,要不斷判斷凹凸角的問題以及最大夾角。重要的是理解耳切法算法原理以及他的一些判斷標準,就能很好的理解以及完成我們的需求了。希望本博客對你有幫助。

以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持我們。

上一篇:C#比較日期的方法總結

欄    目:C#教程

下一篇:Unity實現(xiàn)卡牌翻動效果

本文標題:Unity3D繪制地形的實現(xiàn)方法

本文地址:http://mengdiqiu.com.cn/a1/C_jiaocheng/4864.html

網(wǎng)頁制作CMS教程網(wǎng)絡編程軟件編程腳本語言數(shù)據(jù)庫服務器

如果侵犯了您的權利,請與我們聯(lián)系,我們將在24小時內(nèi)進行處理、任何非本站因素導致的法律后果,本站均不負任何責任。

聯(lián)系QQ:835971066 | 郵箱:835971066#qq.com(#換成@)

Copyright © 2002-2020 腳本教程網(wǎng) 版權所有