用到一個基礎的 three.js 的拖拽旋轉, 梳理了一下資料,webpack
定義的話看 Wiki, 數學描述太晦澀, 沒細看 https://zh.wikipedia.org/wiki...git
簡單的描述就是定義了沿着 X Y Z 方向的依次旋轉, 來模擬空間當中的任何一個旋轉,github
可是用歐拉角描述旋轉有問題, 就是一個空間旋轉這裏是拆成三個旋轉來描述的,
存在問題, 就是不一樣的多個旋轉合併是可能獲得一個旋轉的, 因此這種描述並不精確,
實際當中就致使一些問題了, 數學上有一些問題, 而後就是 three.js 使用當中有問題,web
好比這個例子, 鼠標在 X Y 方向的拖拽, 分別對應到地面的水平渲染, 和視角在縱向的旋轉,api
https://threejs.org/examples/...ide
在拖到俯瞰地面的狀況下, 再 X 方向拖動, 地面旋轉的效果就很邪門了.. 就不是直觀的旋轉.spa
並且, 即使看一點點疊加的旋轉的效果, 也是比較奇怪的,
好比這個例子, 嘗試修改 X Y 不一樣的數值, 結果旋轉的效果很是怪異:.net
https://codepen.io/jonnybonif...翻譯
function animate() { requestAnimationFrame(animate); mesh.rotation.x += 0.04; mesh.rotation.y += 0.04; renderer.render(scene, camera); }
三維空間的當中旋轉的疊加和順序的不一樣存在着關係, 因此處理起來不簡單,
用歐拉角描述旋轉應該是原本就有問題的, 具體的描述看知乎, 數學上的關係太複雜了,
知乎: 通俗的解釋歐拉角,以後爲什麼要引入四元數?code
關於四元數, 有同窗寫了一個比較詳細的文檔(惋惜 HTTPS 有點問題, 等他修吧):
Understanding Quaternions 中文翻譯《理解四元數》
或者參考知乎: 如何形象地理解四元數?
數學歸數學. 我看懂個大概, 按照空間向量去理解, 這個算式是很複雜了,
不過旋轉自己仍是發生在一個與旋轉軸垂直的二維平面上的,
好比點 P 旋轉以後會移動到什麼位置, 仍是要基於該平面進行計算:
四元數能夠表示成 (x, y, z, w)
, 其中 X Y Z 是空間的向量, 而 W 是標量,
對比平面複數的 (x, y)
, 其中 X 是標量, Y 是向量.
而向量的正交和縮放的一些特性, 正好用來計算獲得於旋轉軸正交的那種平面,
最後能夠獲得一個通用的旋轉的座標計算公式...
理解是這樣的理解, 具體計算過程還有獲得的公式仍是挺玄乎的, 看具體的推導吧.
(別來問我具體的推導是怎麼回事, 我解釋不清楚的, 隨便看看吧...)
https://gist.github.com/jiyin...
https://gist.github.com/cheny...
three.js 提供了四元數(Quaternion) API 用於完成四元數計算:
https://threejs.org/docs/#api...
效果仍是不錯的, 找到很多例子, 麻煩的地方是使用的 API 感受挺難懂了.
好比這個徹底看不懂矩陣怎麼算的: https://codepen.io/OpherV/pen...
也找到一些基於角度進行計算的例子, 大體意思好比:
http://projects.defmech.com/T...
function rotateMatrix(rotateStart, rotateEnd) { var axis = new THREE.Vector3(), quaternion = new THREE.Quaternion(); var angle = Math.acos( rotateStart.dot(rotateEnd) / rotateStart.length() / rotateEnd.length() ); if (angle) { axis.crossVectors(rotateStart, rotateEnd).normalize(); angle *= rotationSpeed; quaternion.setFromAxisAngle(axis, angle); } return quaternion; }
還找到一個基於歐拉角換算(setFromEuler
)的 API 的例子, 這個就是最容易理解的了:
https://jsfiddle.net/MadLittl...
var deltaRotationQuaternion = new three.Quaternion() .setFromEuler(new three.Euler( toRadians(deltaMove.y * 1), toRadians(deltaMove.x * 1), 0, 'XYZ' )); cube.quaternion.multiplyQuaternions(deltaRotationQuaternion, cube.quaternion);
用這個例子, deltaMove
的座標就能夠很容易轉化到 cube
的三維空間旋轉了,
繞過了複雜的計算, 並且顯得比較直觀, 斜方向的鼠標拖動也比較天然的.
我直接用了這個代碼.
另外關於 threejs 加載用於旋轉的模型, 有個坑是 Webpack 打包 Loader, 直接看連接了:
https://gist.github.com/cecil...
plugins:[ new webpack.ProvidePlugin({ 'THREE': 'three' }), //... ]
import "three/examples/js/loaders/GLTFLoader.js";
上面找到的代碼能夠解決拖拽和旋轉, 可能之後還會涉及到旋轉以後拖放的問題,
找到個例子還能夠, 可是已經很複雜了 https://codepen.io/kaolay/pen...再複雜一些的空間的轉換, 應該就須要手動基於四元數或者空間向量計算, 太難, 再看了...