Unity中判斷一個點在自身的哪一側

如果你還不是很理解矩陣的含義那麼請轉到 https://blog.csdn.net/qq_39426265/article/details/101373494

問題起源

在Unity自帶的函數中並沒有判斷一個點在自身的左邊還是右邊的方法。但是有的時候我們在項目中又不得不去判斷,Unity自帶的有一個方法 Vector3.SignedAngle 這個方法也可以判斷出目標在自身的哪一側,因爲用過這個方法的同學應該都知道,當物體在自身左側或者右側時,他所返回的角度值是帶有符號的,所以也可以判斷這個角度值是否大於0,來達到我們的目的,但是缺點就是,當我們只想判斷出這個目標點位於自身的哪一側時,再使用跟這個方法,就會造成性能的浪費,因爲它用多餘的計算,計算出了一個角度值,再返回給我們,我不清楚他的內部實現,因爲Unity是不開源的,所以我只能判定,這個方法是一個比較耗時,浪費計算量的方法,當然我只限於在當前要解決的問題的基礎上來說的。所以我才寫了相應的算法,來解決這個問題,如果你想理解我的方法,那麼你就要有一些3D數學的基礎,否則你會很難理解我爲什麼這麼做。

原理

下面讓我們來分析下2D世界中位於世界西邊或者東邊的物體有什麼特點(判斷不需要豎直維度的值)
比如這就是我們Unity中的世界俯視視角:
在這裏插入圖片描述
我這裏忽略Y軸,因爲只是判斷物體在自己的哪一側,XZ平面就夠了。
我們以Z軸爲正方向,也就是分割線,規定Z軸以左爲東側(X正半軸),反之爲西側(X負半軸)。
下面我們在世界中隨機創建一個物體:
在這裏插入圖片描述 如果把世界作爲一個人物,Z軸爲人物的朝向,那麼很顯然,我們所創建的物體就位於人物的右側,也就是世界的東側,此時,它位於X的正半軸上,反之就在X的負半軸上。

到這裏就很明瞭了,就拿我們剛纔的舉例來說,如果世界就是一個人物,而Z軸就是人物的正方向,那麼,如果某一物體在人物的右側,則該物體處於該人物的相對座標系下的X分量就爲正值,否則就爲負值。

解決方法

我們在上面已經瞭解了判斷的原理是什麼,接下來我們的工作就簡單了,只需要把要判斷物體的座標系轉化到自身的座標系下就可以了,那麼怎麼做呢?
如果自身的朝向正好和世界座標的朝向一致,也就是自身相對於世界座標沒有發生任何旋轉,那麼我們就直接可以判斷目標物體的X分類的正負。但這畢竟是一種特殊情況,大多數情況下自身的座標是不可能不發生旋轉的。所以我們就要把這個個方法擴展到任意情況都成立!
我們假設,自身(任何你要控制的遊戲物體)繞Y軸旋轉了theta度:
在這裏插入圖片描述self_Z代表當前自身的朝向,也就是Z軸方向;
然後在選取一個要判斷的目標點:
在這裏插入圖片描述
比如說這個點是A。
接下來我們要做的就是把A點轉化到世界座標下去,就可以了。
那麼我們怎麼轉換呢?
再次觀察上圖,self_Z旋轉了Theta度纔到達現在的方向,也就是說如果我們把self_Z和A點都反過來旋轉theta度,那麼我們就把這個任意的隨機的情況轉化爲了一個特殊的情況,也就是自身相對於世界沒有做任何的旋轉,這個時候只需要判斷A點的X的分量就可以了。

所以我們可以得到下圖:
在這裏插入圖片描述
我用虛線來表示原本的狀態,實線是經過上述操作得到的狀態。

A`

是旋轉後的A,也是我們需要計算的向量;
此時我們已經把任意情況轉化爲特殊情況,接下來我們要做的就是用數學計算,計算出A`

我們如果想要得到A`就必須得到一個旋轉矩陣,這個旋轉矩陣就是self_Z實際中的矩陣,也就是轉化爲特殊情況時的矩陣,構建該矩陣的方法我不必多說,讀者可以看我在開頭的鏈接裏找到方法。
假設我們得到了矩陣B,我們就可以列得方程:

A` * B = A
當然,我們要用已知求未知,又因爲矩陣不滿足乘法的交換律,所以我們不能將B消掉,所以我們同時給兩邊乘上B^-1(表示-1在B的右上角,表示B的逆矩陣)


A` * B * B^-1 = A * B^-1

又因爲B一定是一個單位正交陣,所以B*B^-1 == 1,T(B) == B^-1
所以我們可以得到
A * T(B) = A`

這樣,我們就求出了特殊情況下的A`,然後只需要判斷X分量即可判斷出目標物到底在自身的哪一側了。
下面我貼出實現代碼(當然,你可以不使用unity自帶的Matrix,用一個二維數組去替代它,但是你需要要對“*”運算符進行重載):

int GetTargetIsRightOrLeft(Transform self, Vector3 targetPos)
{
	Matrix4x4 matrix = 
	new Matrix4x4(target.right, target.up, target.forward, new Vector4(0, 0, 0, 1));//構建一個旋轉矩陣
	targetPos = Vector3.Normalize(targetPos - self.position);

	return matrix.inversion * targetPos ? -1 : 1
}

這裏要知道矩陣乘法的原則:當乘號左邊的矩陣的行數等於右邊的矩陣的列數時兩個矩陣才能相乘,由於在Unity中Vector3可以隱式轉化爲Vector3,所以這個乘法才成立。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章