threejs系列之:几何变换(上)🍺

这里是 4. threejs系列之:几何变换(上):

往期回顾:

  1. # threejs系列:相机与投影 📷
  2. # threejs系列:光源与光照🪀
  3. # threejs系列:自定义几何体🎃

threejs 变换

物体变换通常代表物体的平移、旋转、缩放。在学习如何变换之前,我们来熟悉一下一些预备知识。

坐标轴

threejs 的坐标轴是遵循 openGL 的右手坐标系。如右图所示,四根手指的方向是Y 轴的正方向,大拇指指向的是X轴的正方向,手臂朝向身体的方向是Z轴的正方向。

threejs封装了一个坐标系辅助对象,展示三个轴的方向,红色代表 X 轴. 绿色代表 Y 轴. 蓝色代表 Z 轴。

向量 Vector3

在 Three.js 中,三维向量是具有三个分量的数字数组。这些分量通常表示在三维空间中的 x、y 和 z 坐标。

向量可以用来表示许多事物,例如:

  • 位置
  • 方向
  • 速度

在前面的文章中,我们接触到了很多的关于向量的东西,如上篇文章给BufferGeometry设置法向量就是方向 ,如给灯光设置位置就是位置 ,如给物体的位置每秒添加一个向量,这个向量就是速度

用法

js 复制代码
new THREE.Vector3(x, y, z);

用法非常简单,就是设置 3 个标量。标量是什么? 标量是没有方向的具体的大小数值。

向量相加

js 复制代码
const a = new THREE.Vector3(2, 3, 4);
const b = new THREE.Vector3(3, 4, 5);

// console.log(a.add(b));                              // 5,7,9
// console.log(new THREE.Vector3().addVectors(a, b))   // 5,7,9
// console.log(a.addScalar(2))                         // 4,5,6

当向量OA + 向量AC首尾相连时遵循三角形法则:

当向量OB + 向量OA起点相同时,遵循平行四边形法则

向量相减

js 复制代码
// a.sub(b);                              // -1,-1, -1
// new THREE.Vector3().subVectors(a, b)   // -1, -1, -1
// a.subScalar(2)                         // 0, 1, 2

如下图,AC - AB,因为 AC = AB + BC,所以 AC - AB = AB + BC -AB = BC; 此处的AB、AC、BC都为向量。

向量相减通常用来计算两点的距离。

也可使用distanceTo方法计算(推荐)

js 复制代码
a.distanceTo(b); 

向量相乘

js 复制代码
// a.multiply(b);                              // 6,12, 20
// new THREE.Vector3().multiplyVectors(a, b)   // 6,12, 20
// a.multiplyScalar(2)                         // 4, 6, 8

向量点乘

js 复制代码
a.dot(b);

点乘是什么?点乘是两个向量 xyz 相乘再相加的结果,可以用来判断两个向量的空间关系。

  • 如结果大于0,则方向基本相同,夹角在0°到90°之间

  • 如结果等于0,则正交,相互垂直

  • 如效果小于0,则方向基本相反,夹角在90°到180°之间

单位向量的点乘可以用来计算两个向量之间的夹角。

js 复制代码
// a、b完全反方向
const a = new THREE.Vector3(5, 5, 0);
const b = new THREE.Vector3(-5, 5, 0);

let aUnit = a.normalize();
let bUnit = b.normalize();

const cos = aUnit.dot(bUnit); // 计算点积
const radian = Math.acos(cos); // 计算弧度
console.log(THREE.MathUtils.radToDeg(radian)); // 转角度 = 90

也可以使用angleTo 求两向量的夹角 (推荐)

js 复制代码
a.angleTo(b)

向量叉乘

js 复制代码
a.cross(b);
  • 向量叉乘的结果是一个向量,该向量垂直于输入的两个向量。
  • 向量叉乘的结果的大小等于两个向量所围成的平行四边形的面积。
  • 向量叉乘的结果的方向可以使用右手螺旋定则来确定。

通常用来计算法向量,在上篇文章中有使用到。

平移

平移是指物体往X、Y、Z的方向上进行移动,可通过修改物体的position属性实现,position属性是向量,所以看下下列情景。

  1. 设置物体往前 2 个距离
js 复制代码
mesh.position.add(new THREE.Vector3(0, 0, 2));

js 复制代码
mesh.position.addVectors(mesh.position, new THREE.Vector3(0, 0, 2));
  1. 判断物体距离坐标(5, 6, 7)有多远
js 复制代码
mesh.position.distanceTo(new THREE.Vector(5, 6, 7))
  1. 求物体与坐标(5,6,7)的角度
js 复制代码
THREE.MathUtils.radToDeg(mesh.position.angleTo(new THREE.Vector3(5, 6, 7)));

...

向量展示告一段落,还有很多没有介绍,后面用到会补充。

旋转

three.js 提供了两种表示三维旋转的方式:欧拉角(Euler angles)和四元数(Quaternions),以及两者之间的转换方法。

欧拉角 Euler

欧拉角是三维旋转的一种常用表示方式,它使用三个角度来描述物体绕XYZ轴的旋转。

js 复制代码
new THREE.Euler(x, y, z , order)

前三个参数表示旋转的角度值,以弧度单位。第四个参数是旋转顺序,默认'XYZ',正常不变。

弧度与角度

弧度是什么?在初中学习三角函数的时候大家肯定都背的滚瓜烂熟,弧度的定义是

等于半径长的圆弧所对的圆心角叫做1弧度的角。

知乎上有一篇三角函数动态详解,详细讲解了弧度和角度的关系,感兴趣的可前往了解。

总之记得弧度角度互换公式就行

  • 角度转弧度:角度 / 180 * Math.PI
  • 弧度转角度: 弧度 * 180 / Math.PI

在threejs中基本是以弧度为单位,所以用到角度弧度互转的地方有很多,threejs封装了数学方法类 THREE.MathUtils ,里面封装了很多繁琐的数学方法。

弧度转角度:THREE.MathUtils.radToDeg(),角度转弧度:THREE.MathUtils.degToRad();

例子:绕x轴做匀速旋转运动

js 复制代码
let cube = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), new THREE.MeshStandardMaterial({ color: 0xCCCCCC }));

let animate = () => {
    requestAnimationFrame(animate);
    renderer.render(scene, camera);

    const euler = new THREE.Euler(0, THREE.MathUtils.degToRad(1), 0, 'XYZ');
    cube.position.applyEuler(euler);
}

我们定义了一个cube物体,然后定义了一个欧拉角,x参数为1角度,因为要使用弧度单位,所以我们使用了THREE.MathUtils.degToRad 转成弧度,最后物体应用了欧拉角。

物体(Object3D)的rotation属性是欧拉角,他会绕中心点旋转,通过.set方法来设置旋转角度

js 复制代码
// 局部x方向上旋转
cube.rotation.x += 0.01;

我们可以使用物体的geometry.translate修改中心点

js 复制代码
cube.geometry.translate(0, 0, 1);

缩放

缩放是指修改物体某一维度的大小,物体(Object3D)中属性叫做scale,也是一个向量,所以使用向量的所有方法进行花式缩放。

开发中常用于模型缩放、各种物体缩放等等

js 复制代码
cube.scale.set(0.33, 0.33, 0.33);

很简单,这里就不展开叙述了

相关推荐
袁煦丞5 分钟前
【局域网秒传神器】LocalSend:cpolar内网穿透实验室第418个成功挑战
前端·程序员·远程工作
江城开朗的豌豆6 分钟前
Vuex数据突然消失?六招教你轻松找回来!
前端·javascript·vue.js
好奇心笔记16 分钟前
ai写代码随机拉大的,所以我准备给AI出一个设计规范
前端·javascript
江城开朗的豌豆16 分钟前
Vue状态管理进阶:数据到底是怎么"跑"的?
前端·javascript·vue.js
用户214118326360217 分钟前
dify案例分享-Dify v1.6.0 重磅升级:双向 MCP 协议引爆 AI 生态互联革命
前端
程序员海军18 分钟前
AI领域又新增协议: AG-UI
前端·openai·agent
我想说一句20 分钟前
React待办事项开发记:Hook魔法与组件间的悄悄话
前端·javascript·前端框架
真夜20 分钟前
CommonJS与ESM
前端·javascript
LaoZhangAI20 分钟前
GPT-image-1 API如何传多图:开发者完全指南
前端·后端
G等你下课22 分钟前
从点击到执行:如何优雅地控制高频事件触发频率
前端·javascript·面试