歡迎關注微信公號【三維網(wǎng)格3D】,第一時間獲取最新文章
OrbitControls是THREEJS中最常用的一個控制器叫胖,可以幫助我們實現(xiàn)以目標為焦點的旋轉縮放,同時平移相機觀察場景的操作牺勾,看上去是物體在進行變換青柄,實際上所有的變化都是相機的相對位置在發(fā)生改變。今天就給大家講解該空間實現(xiàn)的核心源碼以及實現(xiàn)原理映胁。
ps:以下代碼非完整代碼段木羹,僅為關鍵實現(xiàn)代碼
如何設置焦點
以焦點作為中心旋轉
// 獲取相機位置varposition=scope.object.position;// 用當前相機位置減去焦點位置,獲得向量offset.copy(position).sub(scope.target);// 通過獲得的向量建立球坐標系spherical.setFromVector3(offset);// 對球坐標系做旋轉,可以理解相機位置所對應的球上的點在運動spherical.theta+=sphericalDelta.theta;spherical.phi+=sphericalDelta.phi;// 控制球坐標系極坐標上下限解孙,避免變換到phi的極點spherical.makeSafe();// 再將球坐標轉換為向量offset.setFromSpherical(spherical);// 相機的位置也就是焦點位置加上球坐標的偏移量position.copy(scope.target).add(offset);// 保證焦點始終不變scope.object.lookAt(scope.target);
這里先把旋轉思路整理一下
相機圍繞目標y軸以及x軸旋轉坑填,其運動軌跡所構成的其實就是一個球,而目標點則是其球心弛姜,焦點到相機自身的距離則為球的半徑脐瑰。
所以我們可以以?target?(焦點)作為球心,?offset?作為半徑廷臼,通過?setFromVector3()?構建一個球坐標系苍在,構成球坐標時的?theta?和?phi?也就是相機在球上的位置。
接下來所有的變換只需要在球坐標上完成荠商,再通過?setFromSpherical()?轉換為世界坐標寂恬,如此反復,就實現(xiàn)了以焦點為中心的旋轉莱没。
而旋轉的操作自然是通過鼠標在屏幕上的移動距離來改變球坐標中的?theta?和?phi?初肉。
大家在閱讀源碼的時候會發(fā)現(xiàn),在構建球坐標系時還有這么幾句代碼
這是因為在?threejs中饰躲,相機默認的?up?軸是?y?軸牙咏,所以其實去掉該代碼也不影響實際的使用,但是當你改變相機的?up?軸時嘹裂,就需要獲取他們之間的變換量妄壶。setFromUnitVectors()?方法能夠獲取兩個向量之間的四元數(shù)變換,也即是無論相機?up?軸是否為?y?軸焦蘑,該方法都能獲取它們之間的變換并應用盯拱,以達到同步世界坐標?y?軸的目的。
縮放功能
大家都知道例嘱,PerspectiveCamera?和?OrthographicCamera?具有不同的投影屬性狡逢,所以在進行縮放的時候,PerspectiveCamera?通過控制相機的距離的遠近是更好的做法拼卵,當然?OrthographicCamera?相機就沒有這個顧慮奢浑,可以直接使用?zoom?,通過控制?zoom?的大小來控制相機縮放腋腮。
整個代碼都是很簡單的縮放論滾雀彼,同步相機?zoom?或者距離壤蚜,其中值得注意的點是update函數(shù)中更新的兩句代碼
spherical.radius *= scale;
scale = 1;
剛才我們說了構建球坐標系,改變半徑就是控制相機的遠近徊哑,自然可以理解袜刷,但是將縮放系數(shù)變?yōu)?,會不會使得縮放滾輪時控制失效呢莺丑,答案是肯定不會啦著蟹,我們在每次縮放滾輪時進行的變換,都是根據(jù)當前的狀態(tài)來進行梢莽,而不是以一開始的狀態(tài)來進行萧豆,也就是說無論什么時候,滾輪縮放了多少次昏名,當前的狀態(tài)永遠可以看作單位一來進行計算涮雷。
移動操作
移動操作中偏移量的計算方法和旋轉操作上的計算方法整體上來說是一致的,這里就不再贅述轻局。