向量密碼本:Threejs 用加減乘除馴服 3D 空間

向量是具有方向和大小的量,在數(shù)學中,向量通常表示為有向線段,由起點和終點確定,起點到終點的距離就是向量的大小,向量之間的夾角就是向量的方向。

向量

//獲取相機的方向向量
let endPoint = new THREE.Vector3(0, 0, 0);
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);

//之前效果
camera.position.set(0, 0, 10);
camera.lookAt(endPoint);

//之后效果
camera.position.set(0, 5, 10);
camera.lookAt(endPoint);

const direction = new THREE.Vector3(0, 0, 0);
camera.getWorldDirection(direction);
console.log(direction);

getWorldDirection() 方法會返回一個三維向量,表示相機的方向向量,這個向量的大小為 1,方向為相機的方向。

  • 參數(shù): 調用該函數(shù)的結果將復制給該 Vector3 對象
camera-direction.png

如何計算

思路: 相機位置到目標點的向量就是相機的方向向量,所以我們可以通過目標點減去相機位置得到相機的方向向量。

1. 向量相減

向量相減就是對應分量相減,例如向量 a = (x1, y1, z1),向量 b = (x2, y2, z2),那么 a - b = (x1 - x2, y1 - y2, z1 - z2)。

2. 向量大小

向量的長度就是向量的模,向量的模可以通過勾股定理計算,例如向量 a = (x, y, z),那么 a 的模就是 sqrt(x2 + y2 + z2)。

3. 向量方向

向量的方向就是向量的單位向量,向量的單位向量可以通過將向量的每個分量除以向量的模得到,例如向量 a = (x, y, z),那么 a 的單位向量就是 (x / a 的模, y / a 的模, z / a 的模)。

let endPoint = new THREE.Vector3(0, 0, 0);
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);

camera.position.set(0, 0, 10);
camera.lookAt(endPoint);

//自動計算
const direction = new THREE.Vector3(0, 0, 0);
camera.getWorldDirection(direction);
console.log("自動計算", direction);

//手動計算
//1. 獲取向量==相當于原點(0,0,0)到相機位置(0,0,10)的向量
//公式:a - b = (x1 - x2, y1 - y2, z1 - z2)
const minus = endPoint.clone().sub(camera.position);
getDirection(minus);
function getDirection(vector) {
  //2. 計算向量的大小
  //公式:sqrt(x^2 + y^2 + z^2)
  const sqrt = Math.sqrt(vector.x * vector.x + vector.y * vector.y + vector.z * vector.z);
  //3. 計算向量的單位向量
  //公式:(x / sqrt, y / sqrt, z / sqrt)
  const unitVector = new THREE.Vector3(vector.x / sqrt, vector.y / sqrt, vector.z / sqrt);
  console.log("手動計算", unitVector);
}

sub(): 方法會返回一個新的向量,表示向量 a 減去向量 b 的結果。

clone(): 克隆方法會返回一個新的向量。

注意: 向量相減的結果會改變原向量的值,所以我們需要先復制原向量,然后再進行相減操作。

camera-calc.png

向量方法

  • add(vector): 向量相加,會改變原向量的值。

例如:a = (1, 2, 3),b = (4, 5, 6),那么 a.add(b) = (1+4, 2+5, 3+6) = (5, 7, 9)。

  • addScalarVector(vector, scalar): 用于將一個標量和一個向量的乘積加到原向量上,會改變原向量的值。

例如:a= (1, 2, 3),那么 a.addScalarVector(a, 2) = (1*2+1, 2*2+2, 3*2+3) = (3, 6, 9)。

  • sub(vector): 向量相減,會改變原向量的值。

例如:a = (1, 2, 3),b = (4, 5, 6),那么 a.sub(b) = (1-4, 2-5, 3-6) = (-3, -3, -3)。

  • multiply(vector): 向量相乘,會改變原向量的值。

例如:a = (1, 2, 3),b = (4, 5, 6),那么 a.multiply(b) = (1*4, 2*5, 3*6) = (4, 10, 18)。

  • multiplyScalar(scalar): 向量乘以一個標量,會改變原向量的值。

例如:a = (1, 2, 3),那么 a.multiplyScalar(2) = (1*2, 2*2, 3*2) = (2, 4, 6)。

  • divide(vector): 向量相除,會改變原向量的值。

例如:a = (1, 2, 3),b = (4, 5, 6),那么 a.divide(b) = (1/4, 2/5, 3/6)。

  • length(): 向量長度,即向量的模。

例如:a = (1, 2, 3),那么 a.length() = sqrt(1^2 + 2^2 + 3^2) = sqrt(14)。

//創(chuàng)建圓柱體
const cylinder = new THREE.Mesh(
  new THREE.CylinderGeometry(0.1, 0.1, 1, 32),
  new THREE.MeshBasicMaterial({ color: 0xff1ff1 })
);
cylinder.position.set(0, 0.5, 0);
scene.add(cylinder);
// 定義一個常量keyEnum,其中包含一個鍵W,其值為false
const keyEnum = {
  W: false,
};
// 監(jiān)聽鍵盤按下事件,當按下W鍵時,將keyEnum.W的值設為true
window.addEventListener("keydown", (event) => {
  let keyCode = event.key.toUpperCase();
  if (keyEnum.hasOwnProperty(keyCode)) {
    keyEnum[keyCode] = true;
  }
});
// 監(jiān)聽鍵盤松開事件,當松開W鍵時,將keyEnum.W的值設為false
window.addEventListener("keyup", (event) => {
  let keyCode = event.key.toUpperCase();
  if (keyEnum.hasOwnProperty(keyCode)) {
    keyEnum[keyCode] = false;
  }
});

// 第一段動畫,圓柱移動較快
let velocity = new THREE.Vector3(0, 0, 3);
function animate() {
  if (keyEnum.W) {
    cylinder.position.add(velocity);
  }
  requestAnimationFrame(animate);
  renderer.render(scene, camera);
}

//第二段動畫,圓柱移動較慢
let velocity = new THREE.Vector3(0, 0, 3);
velocity.multiplyScalar(0.01); // 將速度向量乘以0.01,使其速度變慢
function animate() {
  if (keyEnum.W) {
    cylinder.position.add(velocity);
  }
  requestAnimationFrame(animate);
  renderer.render(scene, camera);
}

//第三段動畫,等價與前兩種合并
let velocity = new THREE.Vector3(0, 0, 3);
function animate() {
  if (keyEnum.W) {
    cylinder.position.addScaledVector(velocity, 0.01);
  }
  requestAnimationFrame(animate);
  renderer.render(scene, camera);
}
camera-fun.gif

書洞筆記

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 4個高精度的關鍵位置是t的表示,t均是上一位留下來的值,遵從大的在前,小的在后 加法:上一位留下來的整除后的進位數(shù)...
    得力小泡泡閱讀 432評論 0 0
  • 向量是2D、3D數(shù)學研究的標準工具,在3D游戲中向量是基礎。 一、向量 1、向量的數(shù)學定義 向量就是一個數(shù)字列表,...
    passiony閱讀 2,058評論 0 1
  • 今天在刷到這道題,《劍指offer》上實現(xiàn)了兩數(shù)相加,想了一下兩數(shù)相減的思路 設被減數(shù)x=10,減數(shù)y=7,那么一...
    Two口吃成大胖子閱讀 758評論 0 0
  • 先闡述一下向量的概念和公式,再結合例子去驗證這些公式1、向量的模:向量的大小就是向量各分量平方和的平方根。 向量...
    佳_saly閱讀 14,484評論 0 3
  • 1.0 坐標與坐標系 1.1 坐標及坐標系的概念 在3D世界中,為了確定不同頂點所在的位置,需要使用坐標表示,二坐...
    莫忘初心_倒霉熊閱讀 1,607評論 0 2

友情鏈接更多精彩內容