2018年5月18日 星期五

2 線段形成夾角之弧線 / 扇形表示法

去年離開模具然後跑去三角洲
後來在三角洲浪費將近半年時光
最後在去年底我才正式回到正常用腦工作的環境
一眨眼又是一年過去了

自從2017/ 12月下旬開始
我的 Indie 之路又中斷了 (又? 根本沒開始才對 XD
為了做好正職, 根本沒時間經營自己的 Indie 事業RRRRR

回到正題來聊一聊過去一個禮拜讓我頭痛好幾天的功能開發

3D 空間中對任意相連的 2 線段形成之夾角
產生對應的弧線或扇形來做視覺化表示

對我來說對這個問題我算是有相關經驗
但動手前我隱約可以感覺到
數學沒學好的我會感到很棘手

首先定義 input,
從 2 線段找到相連的點, 由相連點出發計算出形成夾角的 2 向量,
然後從內積結果來判斷誰是 lhs(left-hand-sided vector)與 rhs(right-hand-sided vector)
接著我的痛苦旅程開始

Unity 可以輕鬆幫我算出 2 個向量之間的夾角 Vector3.Angle()
透過角度代入公式我可以輕鬆計算出正確的弧線或扇形
Mathf.Cos(radian) * axisX + .Sin(radian) * axisZ;
(#這裡要特別感謝 周明倫 大神教學文章的 carry)
但頭痛的問題來了, 我要如何將那個扇形剛好放置在夾角的定位上?

第一次分析後扇形的圓心就是 2 線段相連點 ( <== 正確)
但還有扇形物件的旋轉矩陣要解
於是我天真的想把其中一個線段當成 transform.right,
把 angle = 0 的方向旋轉到 transform.right,
然後再把扇形的 normal 方向旋轉到 2 線段形成平面之法向量 ( Vector3.Cross(lhs, rhs) )
(我計算了 2 個旋轉 quaternion在相乘後找出旋轉矩陣)

經過這樣試驗一整晚, 我的旋轉怎麼 debug 怎麼錯
那幾天剛好狀況不好, 身體疲累, 最後頭痛到受不了只好收工去睡
睡醒後, 不知我是不是在睡夢中夢到解法 XD 突然豁然開朗
我想要解的旋轉矩陣就是 Transform.LookAt() 幫我做好的功能R

於是回頭 debug, 發現我的 lhs 和 rhs 就找錯了
if ( Vector3.Dot( lhs , rhs ) < 0 )
       swap(lhs, rhs);

確定有正確的 lhs, rhs 接下來就是要計算 forward,
up = Vector3.Cross(lhs, rhs); // 2 線段所在平面的法向量
right = rhs; // 定義 right-hand-sided vector為 transform.right
forward = Vector3.Cross(right, up); // transform.forward
// transform.position = 線段相連點位置
剩下的就是交給 Transform.LookAt(transform.position + forward, up);

打完, 收工
最後心得是, 這種感覺只是初等幾何問題還困擾我這麼久
我果然是個銅牌R