游戲開發中的進階向量數學

      網友投稿 688 2022-05-30

      游戲開發中的進階向量數學

      飛機

      到飛機的距離

      遠離原點

      以2D方式構建平面

      飛機的一些例子

      3D碰撞檢測

      更多信息

      飛機

      點積具有帶有單位向量的另一個有趣的屬性。想象一下,垂直于該矢量(并通過原點)的平面通過了一個平面。平面將整個空間分為正數(在平面上)和負數(在平面下),并且(與流行的看法相反),您還可以在2D中使用其數學運算:

      垂直于曲面的單位向量(因此,它們描述了曲面的方向)稱為單位法向向量。雖然,通常他們只是簡稱為法線。法線出現在飛機,3D幾何(以確定其中每一個面或頂點板壁)等。通常 是一個單位矢量,但它被稱為正常 ,因為它的用法。(就像我們將(0,0)稱為原點)。

      看起來很簡單。平面經過原點,并且其表面垂直于單位矢量(或法線)。指向向量的一側為正半空間,而另一側為負半空間。在3D中,這是完全相同的,除了平面是一個無限的表面(想象一個可以定向并固定到原點的無限的平紙)而不是一條線。

      到飛機的距離

      現在很清楚飛機是什么,讓我們回到點積。單位矢量和空間中任何點之間的點積 (是的,這次我們進行矢量和位置之間的點積),返回從點到平面的距離:

      var distance = normal.Dot(point);

      1

      但是不僅是絕對距離,如果點在負半空間中,則距離也將為負:

      這使我們能夠知道一個點在平面的哪一側。

      遠離原點

      我知道你在想什么!到目前為止,這還不錯,但是真實的飛機在空間中無處不在,不僅經過原點。你想真正的飛機的行動,你想它現在。

      請記住,平面不僅將空間分成兩部分,而且還具有極性。這意味著可以有完全重疊的平面,但是它們的負半空間和正半空間會互換。

      考慮到這一點,讓我們將整個平面描述為法線 N和距原點標量D的 距離。因此,我們的平面由N和D表示。例如:

      對于3D數學,Godot提供了Plane 內置類型來處理。

      基本上,N和D可以表示空間中的任何平面,無論是2D還是3D(取決于N的維數),并且兩者的數學公式相同。與以前相同,但是D是從原點到平面的距離,沿N方向行進。例如,假設您想到達飛機上的某個點,您將執行以下操作:

      var pointInPlane = N * D;

      這將拉伸(調整大小)法線向量并使之接觸平面。這個數學運算看起來似乎很混亂,但是實際上比看起來要簡單得多。如果我們想再次說出點到平面的距離,我們可以做同樣的事情,只是要調整距離:

      var distance = N.Dot(point) - D;

      1

      使用內置函數的相同操作:

      var distance = plane.DistanceTo(point);

      1

      這將再次返回正或負距離。

      可以通過使N和D都為負值來翻轉平面的極性。這將導致平面處于相同的位置,但是具有負半角和正半角的反轉:

      N = -N; D = -D;

      1

      2

      當然,Godot也可以在Plane中實現此運算符,因此請執行以下操作:

      var invertedPlane = -plane;

      1

      將按預期工作。

      因此,請記住,飛機就是這樣,它的主要實際用途是計算到它的距離。那么,為什么計算點到平面的距離有用呢?這非常有用!讓我們看一些簡單的例子。

      以2D方式構建平面

      平面顯然不會從任何地方冒出來,因此必須進行構建。以2D方式構建它們很容易,可以從法線(單位矢量)和一個點,也可以從空間中的兩個點完成。

      對于法線和點,由于已經計算了法線,因此大部分工作都已完成,因此只需根據法線和點的點積計算D。

      var N = normal; var D = normal.Dot(point);

      1

      2

      對于空間中的兩個點,實際上有兩個平面穿過它們,它們共享相同的空間,但法線指向相反的方向。要從兩點計算法線,必須首先獲取方向矢量,然后將其向任一側旋轉90°度:

      // Calculate vector from `a` to `b`. var dvec = (pointB - pointA).Normalized(); // Rotate 90 degrees. var normal = new Vector2(dvec.y, -dvec.x); // Alternatively (depending the desired side of the normal): // var normal = new Vector2(-dvec.y, dvec.x);

      1

      2

      3

      4

      5

      6

      其余部分與前面的示例相同,因為point_a或point_b都在同一平面上,所以它們都可以工作:

      var N = normal; var D = normal.Dot(pointA); // this works the same // var D = normal.Dot(pointB);

      1

      2

      3

      4

      在3D模式下執行相同的操作會稍微復雜一些,將在后面進行詳細說明。

      飛機的一些例子

      這是平面有用的簡單示例。假設您有一個凸 多邊形。例如,矩形,梯形,三角形或沒有面向內彎曲的任何多邊形。

      對于多邊形的每個片段,我們都會計算經過該片段的平面。一旦有了平面列表,我們就可以做整齊的事情,例如檢查點是否在多邊形內。

      我們遍歷所有平面,如果可以找到到該點的距離為正的平面,則該點在多邊形之外。如果我們做不到,那么重點就在里面。

      代碼應該是這樣的:

      var inside = true; foreach (var p in planes) { // check if distance to plane is positive if (p.DistanceTo(point) > 0) { inside = false; break; // with one that fails, it's enough } }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      太酷了吧?但這會變得更好!稍加努力,當兩個凸多邊形也重疊時,類似的邏輯就會讓我們知道。這稱為分離軸定理(或SAT),大多數物理引擎都使用它來檢測碰撞。

      對于一個點,僅檢查飛機是否返回正距離就足以確定該點是否在外面。對于另一個多邊形,我們必須找到一個平面,在該平面上所有 其他多邊形點都將 返回一個正距離。該檢查是使用A的平面相對于B的點進行的,然后使用B的平面相對于A的點進行的:

      代碼應該是這樣的:

      var overlapping = true; foreach (Plane plane in planesOfA) { var allOut = true; foreach (Vector3 point in pointsOfB) { if (plane.DistanceTo(point) < 0) { allOut = false; break; } } if (allOut) { // a separating plane was found // do not continue testing overlapping = false; break; } } if (overlapping) { // only do this check if no separating plane // was found in planes of A foreach (Plane plane in planesOfB) { var allOut = true; foreach (Vector3 point in pointsOfA) { if (plane.DistanceTo(point) < 0) { allOut = false; break; } } if (allOut) { overlapping = false; break; } } } if (overlapping) { GD.Print("Polygons Collided!"); }

      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

      如您所見,飛機非常有用,這是冰山一角。您可能想知道非凸多邊形會發生什么。通常可以通過將凹面多邊形拆分為較小的凸面多邊形,或使用諸如BSP(如今已不多使用)之類的技術來處理。

      3D碰撞檢測

      這是另外一個獎勵,是對耐心和遵守本篇教程的獎勵。這是另一個智慧。這可能不是直接用例(Godot已經很好地進行了碰撞檢測),但是幾乎所有物理引擎和碰撞檢測庫都在使用它:)

      還記得將2D中的凸形轉換為2D平面數組對于碰撞檢測很有用嗎?您可以檢測點是否在任何凸形形狀內,或者兩個2D凸形形狀是否重疊。

      好吧,這也適用于3D,如果兩個3D多面體形狀發生碰撞,您將無法找到分離平面。如果找到分離平面,則形狀絕對不會碰撞。

      要稍微刷新一點,一個分離平面意味著多邊形A的所有頂點都在該平面的一側,而多邊形B的所有頂點都在另一側。該平面始終是面A或面B的端面之一。

      但是在3D中,這種方法存在問題,因為在某些情況下可能找不到分離平面。這是這種情況的一個示例:

      為了避免這種情況,需要測試一些額外的平面作為分隔符,這些平面是面A的邊與面B的邊之間的叉積。

      所以最終的算法是這樣的:

      var overlapping = true; foreach (Plane plane in planesOfA) { var allOut = true; foreach (Vector3 point in pointsOfB) { if (plane.DistanceTo(point) < 0) { allOut = false; break; } } if (allOut) { // a separating plane was found // do not continue testing overlapping = false; break; } } if (overlapping) { // only do this check if no separating plane // was found in planes of A foreach (Plane plane in planesOfB) { var allOut = true; foreach (Vector3 point in pointsOfA) { if (plane.DistanceTo(point) < 0) { allOut = false; break; } } if (allOut) { overlapping = false; break; } } } if (overlapping) { foreach (Vector3 edgeA in edgesOfA) { foreach (Vector3 edgeB in edgesOfB) { var normal = edgeA.Cross(edgeB); if (normal.Length() == 0) { continue; } var maxA = float.MinValue; // tiny number var minA = float.MaxValue; // huge number // we are using the dot product directly // so we can map a maximum and minimum range // for each polygon, then check if they // overlap. foreach (Vector3 point in pointsOfA) { var distance = normal.Dot(point); maxA = Mathf.Max(maxA, distance); minA = Mathf.Min(minA, distance); } var maxB = float.MinValue; // tiny number var minB = float.MaxValue; // huge number foreach (Vector3 point in pointsOfB) { var distance = normal.Dot(point); maxB = Mathf.Max(maxB, distance); minB = Mathf.Min(minB, distance); } if (minA > maxB || minB > maxA) { // not overlapping! overlapping = false; break; } } if (!overlapping) { break; } } } if (overlapping) { GD.Print("Polygons Collided!"); }

      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

      更多信息

      有關在Godot中使用向量數學的更多信息,請參見以下文章:

      矩陣與變換

      如果您需要其他說明,請查看3Blue1Brown的精彩視頻系列“線性代數的本質”:https://www.youtube.com/watch?v=fNk_zzaMoSs&list=PLZHQObOWTQDPD3MizzM2xVFitgF8hE_ab

      5G游戲

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:高性能實踐IO之Reactor模式
      下一篇:Docker核心技術之容器詳解
      相關文章
      欧美亚洲国产SUV| 亚洲乱码日产精品一二三| 亚洲M码 欧洲S码SSS222| 亚洲情A成黄在线观看动漫软件| 亚洲午夜在线电影| 亚洲精品午夜无码专区| 亚洲自偷自偷在线制服| 亚洲精品无码久久一线| 亚洲色欲久久久综合网东京热| 亚洲裸男gv网站| 亚洲综合最新无码专区| 亚洲精品无码久久久| 亚洲一区二区三区乱码A| 亚洲最大激情中文字幕| 亚洲精品高清国产一线久久| 亚洲精品成人网站在线观看| 亚洲av无码潮喷在线观看| 亚洲欧洲日韩国产综合在线二区| 亚洲激情中文字幕| 亚洲视频一区二区三区| 亚洲人成在线免费观看| 一本色道久久88—综合亚洲精品 | 久久精品亚洲综合| 亚洲av日韩av无码| 亚洲福利一区二区三区| 亚洲成在人线电影天堂色| 亚洲男人天堂2022| 国产精品亚洲一区二区在线观看| 国产偷国产偷亚洲清高APP| 亚洲欧洲日本在线| 亚洲国产精品一区二区久久hs| 久久久久亚洲AV无码专区首| 亚洲欧洲在线播放| 亚洲性无码一区二区三区| 色偷偷亚洲男人天堂| 国产亚洲大尺度无码无码专线| 精品亚洲综合久久中文字幕| 一区二区三区亚洲| 亚洲高清中文字幕免费| 欧美色欧美亚洲另类二区| 国产亚洲精品拍拍拍拍拍|