Three.js 开发快速入门

概述

本文档将介绍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开发中的多个重要概念:

  1. 控制器和辅助工具:轨道控制器帮助我们更好地浏览3D场景,辅助坐标系帮助我们理解空间关系
  2. 物体变换:位置、旋转、缩放以及父子层级关系的处理
  3. 响应式设计:适配不同屏幕尺寸和全屏功能的实现
  4. 调试工具:使用lil-gui方便地调整参数
  5. 几何体:BufferGeometry的使用方法和优势
  6. 材质和纹理:如何为3D对象添加丰富的视觉效果
  7. 雾效:增强场景深度感的技术
  8. 模型加载:加载外部3D模型的方法
  9. 交互:光线投射实现用户与3D对象的交互
  10. 动画:使用Tween.js创建流畅的补间动画

这些知识为深入学习Three.js奠定了坚实的基础,接下来可以继续学习光照、阴影、后期处理等更高级的特性。

相关推荐
全栈王校长4 小时前
Three.js 环境搭建与开发初识
three.js
DaMu12 小时前
Dreamcore3D ARPG IDE “手搓”游戏引擎,轻量级实时3D创作工具,丝滑操作,即使小白也能轻松愉快的创作出属于你自己的游戏世界!
前端·架构·three.js
烛阴2 天前
从“无”到“有”:手动实现一个 3D 渲染循环全过程
前端·webgl·three.js
烛阴3 天前
拒绝配置地狱!5 分钟搭建 Three.js + Parcel 完美开发环境
前端·webgl·three.js
XiaoYu20026 天前
第9章 Three.js载入模型GLTF
前端·javascript·three.js
XiaoYu20027 天前
第8章 Three.js入门
前端·javascript·three.js
AlanHou16 天前
Three.js:Web 最重要的 3D 渲染引擎的技术综述
前端·webgl·three.js
一颗烂土豆19 天前
🚴‍♂️ Vue3 + Three.js 实战:如何写一个“不晕车”的沉浸式骑行播放器 🎥
vue.js·游戏·three.js
Elaine33620 天前
Gemini生成的3D交互圣诞树(娱乐版)
3d·交互·three.js·前端可视化