概述
本文档将介绍Three.js开发中的快速入门知识点,包括控制器使用、物体变换、材质纹理、雾效、模型加载等内容。通过这些实例,您将掌握Three.js的核心概念和实用技巧。
第一部分:控制器和辅助坐标系
1. 轨道控制器(OrbitControls)
轨道控制器允许用户通过鼠标拖拽、滚轮缩放等方式来改变相机视角,这对于3D场景的浏览非常有用。
javascript
// 导入轨道控制器
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
// 添加轨道控制器
const controls = new OrbitControls(camera, document.body);
// 设置带阻尼的惯性
controls.enableDamping = true;
// 设置阻尼系数
controls.dampingFactor = 0.05;
// 设置自动旋转(可选)
controls.autoRotate = true;
2. 辅助坐标系(AxesHelper)
辅助坐标系可以帮助开发者可视化场景中的坐标轴方向:
javascript
// 添加世界坐标辅助器
const axesHelper = new THREE.AxesHelper(5);
scene.add(axesHelper);
3. 动画循环中更新控制器
为了使控制器的阻尼效果生效,需要在动画循环中调用controls.update():
javascript
function animate() {
controls.update(); // 必须在动画循环中调用
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
animate();
第二部分:物体变换和层级关系
1. 物体位移
Three.js中每个对象都有position属性,用于控制物体的位置:
javascript
// 设置物体位置
cube.position.x = 2;
cube.position.set(3, 0, 0); // 同时设置xyz坐标
2. 父子层级关系
在Three.js中,可以建立物体间的父子关系,子物体的变换会受到父物体的影响:
javascript
// 创建父物体
let parentCube = new THREE.Mesh(geometry, parentMaterial);
// 创建子物体
const cube = new THREE.Mesh(geometry, material);
// 将子物体添加到父物体上
parentCube.add(cube);
// 设置父物体位置
parentCube.position.set(-3, 0, 0);
// 设置子物体位置(相对于父物体)
cube.position.set(3, 0, 0);
3. 旋转和缩放
除了位置变换,还可以对物体进行旋转和缩放:
javascript
// 旋转 - 使用弧度制
cube.rotation.x = Math.PI / 4; // 绕X轴旋转45度
// 缩放
cube.scale.set(2, 2, 2); // 在xyz轴上都放大2倍
第三部分:响应式画布与全屏控制
1. 响应式设计
为了让Three.js应用在窗口大小改变时自适应,需要监听resize事件:
javascript
// 监听窗口变化
window.addEventListener("resize", () => {
// 重置渲染器宽高比
renderer.setSize(window.innerWidth, window.innerHeight);
// 重置相机宽高比
camera.aspect = window.innerWidth / window.innerHeight;
// 更新相机投影矩阵
camera.updateProjectionMatrix();
});
2. 全屏功能
可以通过浏览器API实现全屏功能:
javascript
// 全屏
document.body.requestFullscreen();
// 退出全屏
document.exitFullscreen();
3. 自定义全屏按钮
javascript
var btn = document.createElement("button");
btn.innerHTML = "点击全屏";
btn.style.position = "absolute";
btn.style.top = "10px";
btn.style.left = "10px";
btn.style.zIndex = "999";
btn.onclick = function () {
document.body.requestFullscreen();
console.log("全屏");
};
document.body.appendChild(btn);
第四部分:使用lil-gui进行调试
lil-gui是一个轻量级的图形界面库,非常适合用于Three.js开发过程中的参数调试。
1. 基本使用
javascript
// 导入lil-gui
import { GUI } from "three/examples/jsm/libs/lil-gui.module.min.js";
// 创建GUI实例
const gui = new GUI();
2. 添加控件
javascript
// 添加按钮
gui.add(eventObj, "Fullscreen").name("全屏");
// 添加范围滑块
gui.add(cube.position, "x", -5, 5).name("立方体x轴位置");
// 创建文件夹组织控件
let folder = gui.addFolder("立方体位置");
folder
.add(cube.position, "x")
.min(-10)
.max(10)
.step(1)
.name("立方体x轴位置");
// 添加颜色选择器
gui.addColor(colorParams, "cubeColor")
.name("立方体颜色")
.onChange((val) => {
cube.material.color.set(val);
});
第五部分:BufferGeometry详解
1. BufferGeometry vs Geometry
BufferGeometry是Three.js中更高效的几何体表示方式,它直接使用缓冲区存储顶点数据。
javascript
// 创建BufferGeometry
const geometry = new THREE.BufferGeometry();
// 创建顶点数据(每三个数值代表一个顶点的xyz坐标)
const vertices = new Float32Array([
-1.0, -1.0, 0.0, // 第一个顶点
1.0, -1.0, 0.0, // 第二个顶点
1.0, 1.0, 0.0, // 第三个顶点
-1.0, 1.0, 0.0 // 第四个顶点
]);
// 设置顶点属性
geometry.setAttribute("position", new THREE.BufferAttribute(vertices, 3));
2. 使用索引绘制
通过索引可以减少重复顶点数据:
javascript
// 创建索引
const indices = new Uint16Array([0, 1, 2, 2, 3, 0]);
// 设置索引属性
geometry.setIndex(new THREE.BufferAttribute(indices, 1));
第六部分:顶点组与材质
1. 多材质网格
一个网格可以使用多个材质:
javascript
// 创建多种材质
const cubematerial0 = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
const cubematerial1 = new THREE.MeshBasicMaterial({ color: 0xff0000 });
// ... 更多材质
// 将多个材质传递给网格
const cube = new THREE.Mesh(cubegeometry, [
cubematerial0,
cubematerial1,
// ... 其他材质
]);
2. 顶点组
通过顶点组可以指定哪些面使用哪个材质:
javascript
// 设置2个顶点组,形成2个材质区域
geometry.addGroup(0, 3, 0); // 从索引0开始的3个面使用第0个材质
geometry.addGroup(3, 3, 1); // 从索引3开始的3个面使用第1个材质
第七部分:材质与纹理
1. 纹理加载
Three.js提供了多种纹理类型,可以为材质添加丰富的视觉效果:
javascript
// 创建纹理加载器
let textureLoader = new THREE.TextureLoader();
// 加载纹理
let texture = textureLoader.load("./texture/image.png");
2. 不同类型的纹理映射
javascript
// 基础颜色贴图
planeMaterial.map = texture;
// AO贴图(环境遮挡)
planeMaterial.aoMap = aoMap;
planeMaterial.aoMapIntensity = 1;
// 透明度贴图
planeMaterial.alphaMap = alphaMap;
// 高光贴图
planeMaterial.specularMap = specularMap;
3. 纹理颜色空间
不同的纹理应使用适当的颜色空间:
javascript
// 设置颜色空间
texture.colorSpace = THREE.SRGBColorSpace; // 颜色贴图
// texture.colorSpace = THREE.LinearSRGBColorSpace; // 法线贴图等
第八部分:雾效(Fog)
Three.js提供了两种雾效类型:线性雾和指数雾。
1. 线性雾
javascript
// 线性雾:在指定距离范围内逐渐显现雾效
scene.fog = new THREE.Fog(0x999999, 0.1, 50); // 颜色, 近距离, 远距离
2. 指数雾
javascript
// 指数雾:随距离呈指数增长的雾效
scene.fog = new THREE.FogExp2(0x999999, 0.1); // 颜色, 密度
第九部分:GLTF模型加载
GLTF是一种通用的3D模型格式,Three.js提供了专门的加载器。
1. 基本GLTF加载
javascript
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
// 实例化加载器
const gltfLoader = new GLTFLoader();
// 加载模型
gltfLoader.load(
"./model/model.glb", // 模型路径
(gltf) => { // 加载完成回调
console.log(gltf);
scene.add(gltf.scene);
}
);
2. 使用DRACO压缩
DRACO是一种3D几何压缩技术,可以显著减小模型文件大小:
javascript
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader.js";
// 实例化DRACO加载器
const dracoLoader = new DRACOLoader();
// 设置DRACO解码器路径
dracoLoader.setDecoderPath("./draco/");
// 设置GLTF加载器使用DRACO解码器
gltfLoader.setDRACOLoader(dracoLoader);
第十部分:光线投射与物体交互
光线投射(Raycasting)是检测鼠标与3D物体交互的重要技术。
1. 基本光线投射
javascript
// 创建射线
const raycaster = new THREE.Raycaster();
// 创建鼠标向量
const mouse = new THREE.Vector2();
// 监听鼠标点击事件
window.addEventListener("click", (event) => {
// 设置鼠标向量的x,y值(转换为标准化设备坐标)
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -((event.clientY / window.innerHeight) * 2 - 1);
// 通过相机和鼠标位置更新射线
raycaster.setFromCamera(mouse, camera);
// 计算物体和射线的交点
const intersects = raycaster.intersectObjects([sphere1, sphere2, sphere3]);
if (intersects.length > 0) {
// 处理交点
console.log(intersects[0].object);
}
});
第十一部分:Tween补间动画
Tween.js提供了一种简单的方式来创建平滑的动画效果。
1. 基本补间动画
javascript
import * as TWEEN from "three/examples/jsm/libs/tween.module.js";
// 创建补间动画
const tween = new TWEEN.Tween(sphere1.position);
tween.to({ x: 4 }, 1000); // 在1000毫秒内移动到x=4的位置
// 启动动画
tween.start();
2. 动画回调和链式调用
javascript
// 添加回调函数
tween
.onStart(() => console.log("开始"))
.onComplete(() => console.log("结束"))
.onUpdate(() => console.log("更新"));
// 链式动画
let tween2 = new TWEEN.Tween(sphere1.position);
tween2.to({ x: -4 }, 1000);
tween.chain(tween2); // tween完成后执行tween2
tween2.chain(tween); // tween2完成后执行tween
3. 在动画循环中更新
javascript
function animate() {
controls.update();
requestAnimationFrame(animate);
renderer.render(scene, camera);
// 更新tween动画
TWEEN.update();
}
animate();
总结
通过本教程,我们学习了Three.js开发中的多个重要概念:
- 控制器和辅助工具:轨道控制器帮助我们更好地浏览3D场景,辅助坐标系帮助我们理解空间关系
- 物体变换:位置、旋转、缩放以及父子层级关系的处理
- 响应式设计:适配不同屏幕尺寸和全屏功能的实现
- 调试工具:使用lil-gui方便地调整参数
- 几何体:BufferGeometry的使用方法和优势
- 材质和纹理:如何为3D对象添加丰富的视觉效果
- 雾效:增强场景深度感的技术
- 模型加载:加载外部3D模型的方法
- 交互:光线投射实现用户与3D对象的交互
- 动画:使用Tween.js创建流畅的补间动画
这些知识为深入学习Three.js奠定了坚实的基础,接下来可以继续学习光照、阴影、后期处理等更高级的特性。