做網(wǎng)站有發(fā)票嗎站外推廣怎么做
這里介紹一個(gè)小TIPS,很久沒有這么有成就感了。我以前在學(xué)3D數(shù)學(xué)的時(shí)候,書上就有一句話,說你把矢量這些東西用久了,就應(yīng)該形成一種“直覺”,仿佛這些東西就是你的左右手一樣。而這次,我居然真的用“直覺”來解決問題了,可以說是“瞎貓碰到死耗子”式的解決問題方法:
(一)問題起因
我現(xiàn)在在寫的是一個(gè)軟件光柵化的引擎。在軟件光柵化的階段,有兩個(gè)地方可以進(jìn)行光照渲染,一個(gè)是在世界空間下進(jìn)行,一個(gè)是在相機(jī)空間下進(jìn)行。在世界空間下進(jìn)行會(huì)很方便,因?yàn)楣庹詹⒉簧婕靶D(zhuǎn),而只是涉及平移。但是,因?yàn)榫仃嚦朔梢越Y(jié)合,所以從物體空間變換到世界空間再變換到相機(jī)空間,這兩個(gè)矩陣可以合二為一,因?yàn)槲沂菍戃浖鈻呕?#xff0c;所以節(jié)約一些算力是有必要的。
?(二)矢量旋轉(zhuǎn)的問題
我有一個(gè)平行光。平行光是沒有距離的,只有方向,這個(gè)方向用一個(gè)矢量(像Vector3(1,1,1)這樣)。但在旋轉(zhuǎn)中有兩個(gè)問題:
1、矢量的旋轉(zhuǎn)不像點(diǎn)的旋轉(zhuǎn)。頂點(diǎn)是可以通過矩陣進(jìn)行旋轉(zhuǎn)的,但是矢量不行。雖然在數(shù)學(xué)上矢量和點(diǎn)都是等價(jià)的。但是因?yàn)樾D(zhuǎn)屬于非線性變換,所以最終在數(shù)學(xué)上的結(jié)果(歸一化)之后,這個(gè)矢量方向其實(shí)不是你想要的矢量。
2、從世界空間到相機(jī)空間的旋轉(zhuǎn),其實(shí)是一個(gè)旋轉(zhuǎn)的逆運(yùn)算。也就是說,相機(jī)的Rotation,不是將世界空間按這個(gè)Rotation旋轉(zhuǎn),而是要做逆旋轉(zhuǎn)。
(三)解決的過程
當(dāng)時(shí)我想了一些歪門邪道。開始的時(shí)候我嘗試用兩個(gè)點(diǎn)記錄位置。比如將矢量轉(zhuǎn)化為P1和P2。然后使用這P1和P2進(jìn)行相機(jī)旋轉(zhuǎn),因?yàn)镻1和P2就是兩個(gè)點(diǎn),點(diǎn)旋轉(zhuǎn)之后,之間的位置關(guān)系是不變的。在旋轉(zhuǎn)之后,再取這兩個(gè)點(diǎn)計(jì)算矢量方向。理論上應(yīng)該可行,但不知道為什么失敗了。
后來我將角度反轉(zhuǎn),然后進(jìn)行四元數(shù)的矢量旋轉(zhuǎn)乘法,四元數(shù)的矢量乘法公式如下:
V=要變換的矢量(要進(jìn)行齊次變化,W設(shè)置為0),Q=旋轉(zhuǎn)的四元數(shù),Q-1=四元數(shù)的逆
V = Q * V * (Q-1)
沒到想居然成功了。這樣得到的矢量居然是可以用的。光照計(jì)算沒有問題。但是為什么我說瞎貓碰到死耗子?因?yàn)樵谖业淖儞Q矩陣中有一個(gè)BUG。相機(jī)變換矩陣是按照XYZ三個(gè)軸進(jìn)行變換的。我使用的是Unity的規(guī)則,按照Z-X-Y(Roll-Pitch-Yaw)的順序變換。我在寫相機(jī)變換矩陣的時(shí)候,也是這么寫的。但是我忘記了,相機(jī)變換是一個(gè)逆變換,其實(shí)應(yīng)該寫成Y-X-Z變換的。其實(shí)先后順序只是規(guī)則的問題,你怎么寫,實(shí)際變換上也不會(huì)出錯(cuò)。所以我一開始沒看出這個(gè)BUG。
但是后來我在進(jìn)行相機(jī)的旋轉(zhuǎn)控制的時(shí)候,我發(fā)現(xiàn)我的旋轉(zhuǎn)控制有問題:在進(jìn)行了Yaw的旋轉(zhuǎn)之后,再使用Pitch會(huì)沿Y軸旋轉(zhuǎn),而不是在地平線旋轉(zhuǎn)。雖然在數(shù)學(xué)上這沒有問題,但做為玩家控制來說有大問題。這也是為什么Unity使用Z-X-Y旋轉(zhuǎn)順序的原因。
然后查出BUG之后,才知道是我的旋轉(zhuǎn)搞錯(cuò)了。我就把旋轉(zhuǎn)改了。但這樣一改,原來那個(gè)我將角度反轉(zhuǎn)之后,再利用四元數(shù)旋轉(zhuǎn)的方法就失靈了,得到的是一個(gè)錯(cuò)誤的結(jié)果。
(四)解決方法
這里就是靠“直覺”解決問題了。如果將角度反轉(zhuǎn)沒有作用,那么,將四元數(shù)的運(yùn)算反轉(zhuǎn)呢?這是一個(gè)突發(fā)奇想,我在教程,書里面都沒有見過這種說法,所以我說“瞎貓碰到死耗子”,當(dāng)然,這應(yīng)該也有其它書里面說,只是我沒看到而已。但總之這個(gè)思路解決了問題。只需要將四元數(shù)旋轉(zhuǎn)的運(yùn)算改變,就能夠得到一個(gè)能成功變換到相機(jī)空間的矢量:
使用逆運(yùn)算公式:V = (Q-1) * V * Q
// 旋轉(zhuǎn)矢量
Vector3 RotateDirection(Vector direction, Quaternion rotation)
{Quaternion re(rotation.GetEular());Vector3 transDirection = re.RotateMulInverse(direction);return transDirection.Normalize();
}// 求四元數(shù)的逆
Quaternion Quaternion::GetInverse(void) const {// 這是四元數(shù)的長度// 因?yàn)樗脑獢?shù)長度始終是單位1,所以其實(shí)這一步可以省,只要你確保它沒發(fā)生蠕變float len = Magnitude(); return Quaternion(-x / len, -y / len, -z / len, w / len);
}// 四元數(shù)的乘法(正常)
Vector3 Quaternion::RotateMul(const Vector3& v) const {Quaternion vq(v.x, v.y, v.z, 0.0);Quaternion r = *this * vq * this->GetInverse();return Vector3(r.x, r.y, r.z);
}// 四元數(shù)的乘法(逆向)
Vector3 Quaternion::RotateMulInverse(const Vector3& v) const {Quaternion vq(v.x, v.y, v.z, 0.0);Quaternion r = this->GetInverse() * vq * (*this);return Vector3(r.x, r.y, r.z);
}
OK。以上就是解決方案了。