向量密码本:Threejs 用加减乘除驯服 3D 空间

向量是具有方向和大小的量,在数学中,向量通常表示为有向线段,由起点和终点确定,起点到终点的距离就是向量的大小,向量之间的夹角就是向量的方向。

向量

js 复制代码
//获取相机的方向向量
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,方向为相机的方向。

  • 参数: 调用该函数的结果将复制给该 Vector3 对象

如何计算

思路: 相机位置到目标点的向量就是相机的方向向量,所以我们可以通过目标点减去相机位置得到相机的方向向量。

1. 向量相减

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

2. 向量大小

向量的长度就是向量的模,向量的模可以通过勾股定理计算,例如向量 a = (x, y, z),那么 a 的模就是 sqrt(x^2^ + y^2^ + z^2^)。

3. 向量方向

向量的方向就是向量的单位向量,向量的单位向量可以通过将向量的每个分量除以向量的模得到,例如向量 a = (x, y, z),那么 a 的单位向量就是 (x / a 的模, y / a 的模, z / a 的模)。

js 复制代码
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(): 克隆方法会返回一个新的向量。

注意: 向量相减的结果会改变原向量的值,所以我们需要先复制原向量,然后再进行相减操作。

向量方法

  • 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)。

js 复制代码
//创建圆柱体
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,
};
// 监听键盘按下事件,当按下W键时,将keyEnum.W的值设为true
window.addEventListener("keydown", (event) => {
  let keyCode = event.key.toUpperCase();
  if (keyEnum.hasOwnProperty(keyCode)) {
    keyEnum[keyCode] = true;
  }
});
// 监听键盘松开事件,当松开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);
}

书洞笔记

相关推荐
XiaoYu20022 天前
第9章 Three.js载入模型GLTF
前端·javascript·three.js
XiaoYu20023 天前
第8章 Three.js入门
前端·javascript·three.js
ThreePointsHeat3 天前
Unity WebGL打包后启动方法,部署本地服务器
unity·游戏引擎·webgl
林枫依依5 天前
电脑配置流程(WebGL项目)
webgl
冥界摄政王6 天前
CesiumJS学习第四章 替换指定3D建筑模型
3d·vue·html·webgl·js·cesium
温宇飞8 天前
高效的线性采样高斯模糊
javascript·webgl
冥界摄政王9 天前
Cesium学习第一章 安装下载 基于vue3引入Cesium项目开发
vue·vue3·html5·webgl·cesium
光影少年12 天前
三维前端需要会哪些东西
前端·webgl
nnsix12 天前
Unity WebGL jslib 通信时,传入字符串,变成数值 问题
webgl
二狗哈12 天前
Cesium快速入门34:3dTile高级样式设置
前端·javascript·算法·3d·webgl·cesium·地图可视化