關於 Threejs 模型旋轉問題(筆記)

用到一個基礎的 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 旋轉以後會移動到什麼位置, 仍是要基於該平面進行計算:

clipboard.png

四元數能夠表示成 (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 的三維空間旋轉了,
繞過了複雜的計算, 並且顯得比較直觀, 斜方向的鼠標拖動也比較天然的.
我直接用了這個代碼.

Webpack 打包 Loader

另外關於 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...再複雜一些的空間的轉換, 應該就須要手動基於四元數或者空間向量計算, 太難, 再看了...

相關文章
相關標籤/搜索