一些图形学中的数学应用
包圍體是一個簡單的幾何空間,里面包含著復雜形狀的物體。為物體添加包圍體的目的是快速的進行碰撞檢測或者進行精確的碰撞檢測之前進行過濾(即當包圍體碰撞,才進行精確碰撞檢測和處理)。包圍體類型包括球體、軸對齊包圍盒(AABB)、有向包圍盒(OBB)、8-DOP以及凸殼。如圖1所示。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?圖1 依次是球體、AABB、OBB
可以看到圖1是3D包圍體,在2D包圍體如圖2所示:
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 圖2 依次是球體、AABB、OBB
?
OBB
方向包圍盒(Oriented bounding box),簡稱OBB。方向包圍盒類似于AABB,但是具有方向性、可以旋轉,AABB不能旋轉。如圖3所示。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 圖3 矩形和矩形投影檢測的四條軸
要計算兩個OBB是否碰撞,只需要計算他們在圖3上的4個坐標軸上的投影是否都發生重疊,如果是,則兩多邊形有接觸。這也可以擴展到任意多邊形,如圖4所示。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 圖4 矩形和三角形投影檢測的五條軸
投影軸來自于多邊形自身邊的垂線。
判定方式:兩個多邊形在所有軸上的投影都發生重疊,則判定為碰撞;否則,沒有發生碰撞。
OBB存在多種的表達方式,這里使用最常用的一種:一個中心點、2個矩形的邊長、兩個旋轉軸(該軸垂直于多邊形自身的邊,用于投影計算)。代碼如下所示:
(function (window) {var OBB = function (centerPoint, width, height, rotation) {this.centerPoint = centerPoint;this.extents = [width / 2, height / 2];this.axes = [new Vector2(Math.cos(rotation), Math.sin(rotation)), new Vector2(-1 * Math.sin(rotation), Math.cos(rotation))];this._width = width;this._height = height;this._rotation = rotation;}window.OBB = OBB; })(window);其所依賴的Vector2這個類如下所示:
(function (window) {Vector2 = function (x, y) {this.x = x || 0;this.y = y || 0;};Vector2.prototype = {sub: function (v) {return new Vector2(this.x - v.x, this.y - v.y)},dot: function (v) {return this.x * v.x + this.y * v.y;}};window.Vector2 = Vector2; } (window))然后基于這個數據結構,進行OBB之間的相交測試。為OBB擴展一個方法,即或者在任意軸上的投影半徑:
OBB.prototype = {getProjectionRadius: function (axis) {returnthis.extents[0] * Math.abs(axis.dot(this.axes[0])) + this.extents[1] * Math.abs(axis.dot(this.axes[1]));} }這里你可能需要讀者了解Vector2.dot的幾何意義:若b為單位矢量,則a與b的點積即為a在方向b的投影。
有了這些,就可以進行相交檢測。由上面的判定方式,可以得出,兩個矩形之間的碰撞檢測需要判斷四次(每個投影軸一次)。完整檢測代碼如下所示:
(function (window) {var CollisionDetector = {detectorOBBvsOBB: function (OBB1, OBB2) {var nv = OBB1.centerPoint.sub(OBB2.centerPoint);var axisA1 = OBB1.axes[0];if (OBB1.getProjectionRadius(axisA1) + OBB2.getProjectionRadius(axisA1) <= Math.abs(nv.dot(axisA1))) return false;var axisA2 = OBB1.axes[1];if (OBB1.getProjectionRadius(axisA2) + OBB2.getProjectionRadius(axisA2) <= Math.abs(nv.dot(axisA2))) return false;var axisB1 = OBB2.axes[0];if (OBB1.getProjectionRadius(axisB1) + OBB2.getProjectionRadius(axisB1) <= Math.abs(nv.dot(axisB1))) return false;var axisB2 = OBB2.axes[1];if (OBB1.getProjectionRadius(axisB2) + OBB2.getProjectionRadius(axisB2) <= Math.abs(nv.dot(axisB2))) return false;return true;}}window.CollisionDetector = CollisionDetector; })(window)這里拿兩個OBB的中心點連線在坐標軸上的投影長度和兩個矩形投影半徑之和進行對比,如果半徑之后都小于或者等于中心連線之后才判定為碰撞,否則判定為分離狀態。
?
怎樣判斷平面上一個矩形和一個圓形是否有重疊?
設c為矩形中心,h為矩形半長,p為圓心,r為半徑。
計算方法是先找到矩形上離圓形最短距離u,然后再比較u是否小于圓形的半徑r
1. 首先利用絕對值把 p - c 轉移到第一象限,下圖顯示不同象限的圓心也能映射至第一象限,這不影響相交測試的結果:
?
?
2. 然后,把 v 減去 h,負數的分量設置為0,就得到圓心與矩形最短距離的矢量 u。下圖展示了4種情況,紅色的u是結果。
?3. 最后要比較?u?和?r?的長度,若距離少于?r,則兩者相交。可以只求?u?的長度平方是否小于?r?的平方。
?
轉自知乎https://www.zhihu.com/question/24251545
方向包圍盒碰撞檢測
https://www.cnblogs.com/iamzhanglei/archive/2012/06/07/2539751.html
射線與平面的相交檢測(Ray-Plane intersection test)
https://www.cnblogs.com/graphics/archive/2009/10/17/1585281.html
?
判斷點是否在三角形內
https://www.cnblogs.com/graphics/archive/2010/08/05/1793393.html
?
射線和三角形的相交檢測(ray triangle intersection test)
https://www.cnblogs.com/graphics/archive/2010/08/09/1795348.html
?
?
?
總結
以上是生活随笔為你收集整理的一些图形学中的数学应用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux命令——mount、umoun
- 下一篇: 配置EPON家庭网关接入中国电信电话交换