Mesh网格对象
网格由几何体+材质组成,形成可视化3D物体,是Three.js中最基础的可视化对象。可控制移动(position)、旋转(rotation)、缩放(scale)。
网格中,最基本的构建是三角形,三角形是最简单的多边形,少于3个顶点就不能成为一个表面;
- 三角形必然是平坦的,含4个或以上的顶点的多边形,不一定平坦,三个点确定一个平面,多余的点可能在这个面之上或者之下;
- 三角形经多种转换之后,仍然是三角形,这对于仿射转换和透视转换也成立。最坏的情况下,从三角形的边去看,三角形会退化为线段。在其它角度观察,仍能维持是三角形;
- 几乎所有商用图形加速硬件都是为三角形光栅化而设计的;
Three.js渲染结构图
-
WebGLRenderer将场景绘制到画布上 -
WebGLRenderTarget缓冲,后台渲染 -
WebGLMultipleRenderTargets高级渲染器,常用于后期处理等 -
所有的物体, 灯光, 纹理都要经过render才能看到, 也就是说 render 用来呈现结果, render 通过算法把 3D 场景投影成2D画面绘制到画布上
-
Mesh, Light 是单个对象, 而 Object3D, Group 可以添加n个子对象, 也就是可以对对象进行分组, 创建集合.
-
所有的物体, 灯光, 纹理等3D对象都要放到场景中才能被查看, 也就是说 Scene 是最底层的容器, 而且Scene 是树结构的对象. 也就是说可以通过遍历拿到所有的子集
-
相机在场景内, 也在场景外, 说明 Camera 比较特殊, 可以看向场景, 但看不到自己, 也可以不看向场景, 此时就是'黑屏', 可以对物体样式产生影响, 光线照到物体上与物体的材质产生反应, 比如变亮变暗, 变色等
-
Mesh(网格)继承自Object3D, 其自身包含两个部分, Geometry(几何体)和Material(材质)
-
Geometry(几何体)相当于HTML中的布局, 用来描述物体的形状, 具有物体顶点的相关信息, 比如顶点坐标, 索引等
-
Material(材质)相当于css, 用来描述物体的样式, 对应了webgl 中着色功能, 存储了物体的颜色, 阴影, 光泽度, 漫反射等, 这些效果可以通过 Texture 贴图来实现.
-
Texture(纹理)是种特殊的图像, 可以是png, img等格式, 也可以是canvas画布, 视频等形式
-
隐含信息:
相机也可以包含在Group中, 跟随物体移动
对 Group 应用缩放移动等方法, 内部的3D对象会同时被操作, 不用单独给每个3D对象应用变换
每个对象的变换都是相对于父级做相对运动, 如 #_5-3-正交相机 俯视视角
正交相机没有近大远小的效果,呈现类似2d平面
场景发生了移动, 观察者本地坐标不变, 但世界坐标发生了变化
Geometry Material Texture 均可复用, 用于性能优化
threejs 内置了丰富的 Geometry/Material, 也可以通过建模创建自定义几何体/材质
-
three.js中没有单位,都是向量
-
position.set 也可写为:position.x = 2,position.y = 2,position = 3;
-
因为都是向量,所以向量长度:mesh.position.length()
-
mesh.position.distanceTo(camera.position)可以得到两个向量坐标的距离
-
.lookAt(new THREE.Vector3(2, 2, 3))可以让3D物体自动旋转朝向某个坐标
立方体中,6个顶点原因:
三角形是构成一个面的基本单位,因此一个面有6个顶点。查看代码:
// 创建立方体的基础材质
const material = new THREE.MeshLambertMaterial({
color: 0x1890ff,
wireframe: true, //开启网格透视效果
})
渲染6个面不同的颜色:
// 创建立方体的几何体
const geometry = new THREE.BoxGeometry(1, 1, 1)
console.log(geometry);
let faces = []
for ( let i=0; i<geometry.groups.length; i++) {
// 重新生成新的材质
const material = new THREE.MeshBasicMaterial({
color: Math.random() * 0xffffff
})
faces.push(material)
}
// 创建3D物体对象
const mesh = new THREE.Mesh(geometry, faces)
OrbitControls轨道控制
OrbitControls轨道控制对象,可用鼠标控制缩放、旋转。canvas更新画布内容时,需要重新绘制整个画布,是three.js中动画的必要条件。实际控制的是,相机的位移。
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
// 创建轨道控制器
const orbitControls = new OrbitControls(camera, canvas)
orbitControls.enableDamping = true; //开启惯性
let timer;
// 优化前
const tick = ()=>{
clearTimeout(timer)
timer = setTimeout(()=>{
orbitControls.update()
renderer.render(scene, camera)
tick()
})
}
tick()
// 优化后
const tick = ()=>{
// 更新
orbitControls.update()
renderer.render(scene, camera)
window.requestAnimationFrame(tick)
}
tick()
Clock时间对象
匀速直线运动公式:s=vt;
mesh.rotation.set(Math.PI / 4, 0, 0, 'XYZ'); // 'XYZ' 表示旋转顺序的字符串 默认为 xyz
mesh.scale.set(3, 1, 1); // 物体缩放
let timestamp = Date.now();
const tick = () => {
const currentTime = Date.now();
const deltaTime = currentTime - timestamp; // 两次渲染时间间隔
timestamp = currentTime;
mesh.rotation.y += 0.001 * deltaTime; // 可以保持匀速
renderer.render(scene, camera);
window.requestAnimationFrame(tick);
}
变速运动公式:s=v0*t+at²/2;
const clock = new THREE.Clock();
const tick = () => {
const elapsedTime = clock.getElapsedTime(); // 获取时钟运行的总时长
// clock.getDelta(); 两次渲染时间间隔
// update objects
mesh.rotation.y += 0.005 * elapsedTime; // 加速
// 重新渲染整个场景
renderer.render(scene, camera);
// 调用下次更新函数
window.requestAnimationFrame(tick);
}
实现旋转、位移、缩放动画:
const clock = new THREE.Clock()
const tick = ()=>{
// 保留多为小数的秒级
const elapsedTime = clock.getElapsedTime();
// 旋转
// mesh.rotation.y += elapsedTime / 1000;
// 位移
// mesh.position.x += elapsedTime / 1000;
// 缩放
// mesh.scale.x += elapsedTime / 1000;
// 围绕坐标系原点 圆周运动
// mesh.position.x = Math.cos(elapsedTime)
// mesh.position.y = Math.sin(elapsedTime)
// 镜头看向物体 圆周运动
// camera.position.x = Math.cos(elapsedTime)
// camera.position.y = Math.sin(elapsedTime)
// 更新
orbitControls.update()
renderer.render(scene, camera)
window.requestAnimationFrame(tick)
}