threejs 学习笔记

threeJS 是一个用于创建 3D 图形的 JavaScript 库。它提供了许多概念和功能,包括:

  • 场景(Scene):threeJS 中所有的 3D 对象都存在于场景中。场景是一个容器,可以添加和删除对象,控制相机和光源等。

  • 相机(Camera):相机定义了场景中可见区域的位置和大小。通过移动和旋转相机,可以改变场景中的视角。

  • 渲染器(Renderer):渲染器将场景和相机中的所有对象渲染成 2D 图像,以显示在屏幕上。

  • 材质(Material):材质定义了 3D 对象的外观,包括颜色、纹理、透明度等。

  • 几何体(Geometry):几何体定义了 3D 对象的形状,包括点、线、面等。

  • 网格(Mesh):网格是几何体和材质的组合,是场景中显示的对象。

  • 光源(Light):光源用于照亮场景中的对象,包括环境光、点光源、聚光灯和方向光等。

  • 控制器(Controller):控制器可以用于交互式地控制相机和场景中的对象,包括鼠标控制器、触摸控制器和 VR 控制器等。

场景 (Scene)

在 Three.js 中,场景(Scene)是所有 3D 对象的容器,包括相机、灯光、物体等。可以通过创建一个场景对象来添加和管理所有的 3D 对象。

以下是创建和使用场景的基本步骤:

  1. 创建场景对象:
var scene = new THREE.Scene();
  1. 添加相机到场景中:
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
scene.add(camera);
  1. 添加渲染器到页面中:
var renderer = new THREE.WebGLRenderer();
document.body.appendChild(renderer.domElement);
  1. 创建一个立方体对象,并添加到场景中:
var geometry = new THREE.BoxGeometry();
var material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
var cube = new THREE.Mesh(geometry, material);
scene.add(cube);
  1. 渲染场景:
function animate() {
  requestAnimationFrame(animate);
  renderer.render(scene, camera);
}
animate();

在上述代码中,我们创建了一个场景对象,并添加了一个透视相机和一个绿色的立方体对象到场景中。然后,我们创建了一个渲染器对象,并将其添加到页面中。最后,我们使用 requestAnimationFrame 函数来循环渲染场景。

通过添加和移除不同的 3D 对象,以及调整相机和灯光等参数,我们可以创建出各种独特的 3D 场景效果。

常用 API

以下是 Three.js 中场景(Scene)对象的一些常用 API:

  • add(object):向场景中添加一个 3D 对象,参数 object 可以是 Mesh、Camera、Light、Group 等 Three.js 中的对象。

  • remove(object):从场景中移除一个 3D 对象,参数 object 必须是已经添加到场景中的对象。

  • getObjectById(id):根据对象的 ID 获取场景中的对象,返回值为该对象,如果不存在则返回 undefined

  • getObjectByName(name):根据对象的名称获取场景中的对象,返回值为该对象,如果不存在则返回 undefined

  • traverse(callback):遍历场景中的所有子对象,并对每个子对象调用指定的回调函数 callback

  • dispose():释放场景中所有子对象及其占用的内存空间。

  • background:设置或获取场景的背景颜色或背景纹理。可以使用颜色值、图片路径或 CubeTexture 对象来设置背景。

  • fog:设置或获取场景的雾效果。可以使用 Fog 或 FogExp2 对象来设置雾效果。

以上是一些常用的场景 API,通过使用这些 API,开发者可以方便地向场景中添加、移除、获取和管理各种 3D 对象,以及设置背景和雾效果等场景属性。

相机

在 Three.js 中,常用的相机类型有透视投影相机(PerspectiveCamera)和正交投影相机(OrthographicCamera)。

透视投影相机用于模拟人眼观察物体时的透视效果,可以让远处的物体看起来比近处的物体更小。创建透视投影相机时需要指定相机的垂直视角(fov)、宽高比(aspect)、近截面(near)和远截面(far)等参数。

正交投影相机则不会产生透视效果,它会将场景中的所有物体等比例缩放到屏幕上,从而保持它们的大小不变。创建正交投影相机时需要指定相机的左、右、上、下边界、近截面和远截面等参数。

除了常用的透视投影相机(PerspectiveCamera)和正交投影相机(OrthographicCamera)之外,还有以下一些特殊的相机类型:

  • CubeCamera:用于创建立方体贴图,可以从不同方向渲染场景,并将渲染结果保存到一个立方体贴图中。

  • ArrayCamera:用于创建多相机视角,可以同时渲染多个视角的场景,并将渲染结果合并到一个屏幕上。

  • StereoCamera:用于创建立体视觉效果,可以同时渲染左右两个视角的场景,并将渲染结果合并到一个屏幕上。

  • PerspectiveCameraWithCubemap:用于创建基于立方体贴图的全景相机,可以将场景渲染到一个立方体贴图中,并使用该贴图作为全景相机的背景。

  • CombinedCamera:用于创建组合相机,可以同时使用透视投影和正交投影两种投影方式,实现更加灵活的视角控制。

相机常用 api

以下是相机常用 API 的详细内容:

  • position:相机的位置,是一个 Vector3 对象,可以通过设置其 x、y、z 坐标来改变相机的位置。例如,可以使用 camera.position.set(0, 0, 10) 将相机设置在场景原点后方 10 个单位处。

  • lookAt(target):设置相机的视点,使其朝向目标点,参数 target 是一个 Vector3 对象,表示相机要朝向的目标点。例如,可以使用 camera.lookAt(new THREE.Vector3(0, 0, 0)) 将相机的视点设置为场景原点。

  • up:相机的上方向,是一个 Vector3 对象,表示相机的上方向。默认情况下,相机的上方向是 y 轴正方向。可以通过设置 camera.up 属性来改变相机的上方向,例如,可以使用 camera.up.set(0, 1, 0) 将相机的上方向设置为 y 轴正方向。

  • near:相机的近截面,即相机到视锥体近端的距离。默认值为 0.1 单位,可以通过设置 camera.near 属性来改变近截面的距离。例如,可以使用 camera.near = 1 将近截面距离设置为 1。

  • far:相机的远截面,即相机到视锥体远端的距离。默认值为 2000 单位,可以通过设置 camera.far 属性来改变远截面的距离。例如,可以使用 camera.far = 5000 将远截面距离设置为 5000。

  • aspect:相机的宽高比,即视锥体的宽度与高度之比。默认值为窗口的宽高比,可以通过设置 camera.aspect 属性来改变宽高比。例如,可以使用 camera.aspect = 16 / 9 将宽高比设置为 16:9。

  • fov:相机的垂直视角,即视锥体的顶面和底面之间的夹角。默认值为 50 度,可以通过设置 camera.fov 属性来改变视角大小。例如,可以使用 camera.fov = 60 将视角大小设置为 60 度。

  • zoom:相机的缩放比例,可以用于调整场景中物体的大小。默认值为 1,表示物体大小不变。可以通过设置 camera.zoom 属性来改变缩放比例。例如,可以使用 camera.zoom = 2 将物体放大两倍。

  • projectionMatrix:相机的投影矩阵,该矩阵用于将场景中的 3D 坐标转换为屏幕上的 2D 坐标。可以通过访问 camera.projectionMatrix 属性来获取相机的投影矩阵。

  • updateProjectionMatrix():更新相机的投影矩阵,当相机参数发生变化时需要调用该方法来更新投影矩阵。例如,当改变相机的宽高比、近截面或远截面时,需要调用 camera.updateProjectionMatrix() 来更新投影矩阵。

  • clone():克隆相机对象,返回一个新的相机对象,可以用于创建多个相同参数的相机。例如,可以使用 var camera2 = camera.clone() 克隆一个和原相机参数相同的新相机对象。

// 创建场景
var scene = new THREE.Scene();

// 创建透视相机
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 5; // 将相机位置设置为 (0, 0, 5),使其朝向场景中心

// 创建渲染器
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

// 创建一个立方体
var geometry = new THREE.BoxGeometry();
var material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
var cube = new THREE.Mesh(geometry, material);
scene.add(cube);

// 创建相机控制器
var controls = new THREE.OrbitControls(camera, renderer.domElement);

// 渲染场景
function render() {
    requestAnimationFrame(render);
    // 旋转立方体
    cube.rotation.x += 0.01;
    cube.rotation.y += 0.01;
    // 更新相机控制器
    controls.update();
    renderer.render(scene, camera);
}
render();

渲染器(Renderer)

渲染器是 Three.js 中负责将 3D 场景渲染到 2D 屏幕上的核心组件。最常用的是 WebGLRenderer,它使用 WebGL API 进行硬件加速渲染。

创建渲染器

// 创建 WebGL 渲染器
var renderer = new THREE.WebGLRenderer({
    antialias: true,        // 开启抗锯齿
    alpha: true,            // 开启透明背景
    powerPreference: "high-performance"  // 使用高性能 GPU
});

// 设置渲染器尺寸
renderer.setSize(window.innerWidth, window.innerHeight);

// 设置像素比(用于高清屏幕)
renderer.setPixelRatio(window.devicePixelRatio);

// 将渲染器添加到页面
document.body.appendChild(renderer.domElement);

渲染器常用 API

  • setSize(width, height):设置渲染器的输出尺寸
  • setPixelRatio(ratio):设置像素比,用于适配高分辨率屏幕
  • setClearColor(color, alpha):设置清除颜色(背景色)
  • render(scene, camera):渲染场景和相机
  • dispose():释放渲染器资源
  • shadowMap:阴影贴图相关设置
    • shadowMap.enabled:启用阴影
    • shadowMap.type:阴影类型(THREE.BasicShadowMap、THREE.PCFShadowMap、THREE.PCFSoftShadowMap)

渲染器配置示例

var renderer = new THREE.WebGLRenderer({
    antialias: true,
    alpha: true
});

renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
renderer.setClearColor(0x000000, 1);  // 黑色背景

// 启用阴影
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;

// 启用色调映射
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = 1;

document.body.appendChild(renderer.domElement);

几何体(Geometry)

几何体定义了 3D 对象的形状和结构,包括顶点、面、法线等数据。Three.js 提供了多种内置几何体,也支持自定义几何体。

内置几何体

基础几何体

// 立方体
var boxGeometry = new THREE.BoxGeometry(1, 1, 1);  // 宽、高、深

// 球体
var sphereGeometry = new THREE.SphereGeometry(1, 32, 32);  // 半径、水平分段、垂直分段

// 平面
var planeGeometry = new THREE.PlaneGeometry(1, 1);  // 宽、高

// 圆环
var torusGeometry = new THREE.TorusGeometry(1, 0.4, 16, 100);  // 半径、管道半径、径向分段、管状分段

// 圆柱体
var cylinderGeometry = new THREE.CylinderGeometry(1, 1, 2, 32);  // 顶部半径、底部半径、高度、分段

// 圆锥体
var coneGeometry = new THREE.ConeGeometry(1, 2, 32);  // 底部半径、高度、分段

// 圆环扭结
var torusKnotGeometry = new THREE.TorusKnotGeometry(1, 0.3, 100, 16);  // 半径、管道半径、管状分段、径向分段

高级几何体

// 八面体
var octahedronGeometry = new THREE.OctahedronGeometry(1, 0);

// 四面体
var tetrahedronGeometry = new THREE.TetrahedronGeometry(1, 0);

// 二十面体
var icosahedronGeometry = new THREE.IcosahedronGeometry(1, 0);

// 十二面体
var dodecahedronGeometry = new THREE.DodecahedronGeometry(1, 0);

自定义几何体

// 使用 BufferGeometry 创建自定义几何体
var geometry = new THREE.BufferGeometry();

// 定义顶点位置
var vertices = new Float32Array([
    -1, -1,  1,  // 顶点 0
     1, -1,  1,  // 顶点 1
     1,  1,  1,  // 顶点 2
    -1,  1,  1   // 顶点 3
]);

// 定义面(索引)
var indices = new Uint16Array([
    0, 1, 2,  // 第一个三角形
    0, 2, 3   // 第二个三角形
]);

// 定义 UV 坐标(用于纹理映射)
var uvs = new Float32Array([
    0, 0,  // 顶点 0 的 UV
    1, 0,  // 顶点 1 的 UV
    1, 1,  // 顶点 2 的 UV
    0, 1   // 顶点 3 的 UV
]);

geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3));
geometry.setIndex(new THREE.BufferAttribute(indices, 1));
geometry.setAttribute('uv', new THREE.BufferAttribute(uvs, 2));

// 计算法线(用于光照)
geometry.computeVertexNormals();

几何体常用 API

  • dispose():释放几何体占用的内存
  • computeVertexNormals():计算顶点法线
  • computeFaceNormals():计算面法线
  • center():将几何体居中
  • translate(x, y, z):平移几何体
  • rotateX/Y/Z(angle):旋转几何体
  • scale(x, y, z):缩放几何体

材质(Material)

材质定义了 3D 对象的外观,包括颜色、纹理、透明度、光照响应等属性。Three.js 提供了多种材质类型。

基础材质

MeshBasicMaterial(基础网格材质)

不受光照影响,始终显示为设定的颜色:

var material = new THREE.MeshBasicMaterial({
    color: 0x00ff00,        // 颜色
    wireframe: false,       // 是否显示为线框
    transparent: true,      // 是否透明
    opacity: 0.5,          // 透明度(0-1)
    side: THREE.FrontSide  // 渲染面(FrontSide、BackSide、DoubleSide)
});

MeshStandardMaterial(标准网格材质)

基于物理的渲染(PBR)材质,对光照有真实响应:

var material = new THREE.MeshStandardMaterial({
    color: 0xffffff,
    metalness: 0.5,        // 金属度(0-1)
    roughness: 0.5,       // 粗糙度(0-1)
    map: texture,         // 颜色贴图
    normalMap: normalMap, // 法线贴图
    roughnessMap: roughnessMap,  // 粗糙度贴图
    metalnessMap: metalnessMap,    // 金属度贴图
    envMap: envMap       // 环境贴图
});

MeshPhongMaterial(Phong 材质)

具有高光反射效果:

var material = new THREE.MeshPhongMaterial({
    color: 0xffffff,
    shininess: 100,       // 高光强度
    specular: 0x111111,   // 高光颜色
    map: texture
});

MeshLambertMaterial(Lambert 材质)

漫反射材质,对光照有响应但无高光:

var material = new THREE.MeshLambertMaterial({
    color: 0xffffff,
    map: texture
});

特殊材质

// 点材质(用于点云)
var pointsMaterial = new THREE.PointsMaterial({
    color: 0xffffff,
    size: 0.1,
    sizeAttenuation: true
});

// 线材质
var lineMaterial = new THREE.LineBasicMaterial({
    color: 0xffffff,
    linewidth: 1
});

// 精灵材质(始终面向相机)
var spriteMaterial = new THREE.SpriteMaterial({
    color: 0xffffff,
    map: texture
});

材质常用属性

  • color:材质颜色
  • map:颜色贴图(纹理)
  • normalMap:法线贴图
  • roughnessMap:粗糙度贴图
  • metalnessMap:金属度贴图
  • emissive:自发光颜色
  • emissiveMap:自发光贴图
  • aoMap:环境光遮蔽贴图
  • transparent:是否透明
  • opacity:透明度
  • side:渲染面
  • wireframe:线框模式
  • flatShading:平面着色

网格(Mesh)

网格是几何体和材质的组合,是场景中实际显示的对象。

创建网格

var geometry = new THREE.BoxGeometry(1, 1, 1);
var material = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
var mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);

网格常用属性和方法

位置、旋转、缩放

// 位置
mesh.position.set(0, 1, 0);
mesh.position.x = 1;
mesh.position.y = 2;
mesh.position.z = 3;

// 旋转(弧度制)
mesh.rotation.set(0, Math.PI / 4, 0);
mesh.rotation.x = Math.PI / 2;

// 缩放
mesh.scale.set(2, 2, 2);
mesh.scale.x = 1.5;

// 使用 lookAt 让网格朝向某个点
mesh.lookAt(new THREE.Vector3(0, 0, 0));

其他常用属性

// 可见性
mesh.visible = true;

// 是否接收阴影
mesh.receiveShadow = true;

// 是否投射阴影
mesh.castShadow = true;

// 用户数据(可存储自定义数据)
mesh.userData.customProperty = "value";

// 名称(用于查找)
mesh.name = "myCube";

网格组(Group)

可以将多个网格组合在一起:

var group = new THREE.Group();

var cube1 = new THREE.Mesh(geometry1, material1);
var cube2 = new THREE.Mesh(geometry2, material2);

group.add(cube1);
group.add(cube2);

// 可以整体操作组
group.position.set(0, 0, 0);
group.rotation.y = Math.PI / 4;
scene.add(group);

光源(Light)

光源用于照亮场景中的对象,不同的光源类型会产生不同的光照效果。

环境光(AmbientLight)

均匀照亮场景中的所有对象,无方向性:

var ambientLight = new THREE.AmbientLight(0xffffff, 0.5);  // 颜色、强度
scene.add(ambientLight);

方向光(DirectionalLight)

平行光,模拟太阳光:

var directionalLight = new THREE.DirectionalLight(0xffffff, 1);
directionalLight.position.set(5, 10, 5);
directionalLight.castShadow = true;  // 启用阴影

// 阴影相关设置
directionalLight.shadow.mapSize.width = 2048;
directionalLight.shadow.mapSize.height = 2048;
directionalLight.shadow.camera.near = 0.5;
directionalLight.shadow.camera.far = 50;

scene.add(directionalLight);

点光源(PointLight)

从一点向所有方向发射光线:

var pointLight = new THREE.PointLight(0xffffff, 1, 100);  // 颜色、强度、距离
pointLight.position.set(0, 10, 0);
pointLight.castShadow = true;
scene.add(pointLight);

聚光灯(SpotLight)

锥形光束,有方向和角度:

var spotLight = new THREE.SpotLight(0xffffff, 1, 100, Math.PI / 4, 0.5, 1);
// 颜色、强度、距离、角度、衰减、半影
spotLight.position.set(0, 10, 0);
spotLight.target.position.set(0, 0, 0);
spotLight.castShadow = true;
scene.add(spotLight);
scene.add(spotLight.target);

半球光(HemisphereLight)

模拟天空和地面的环境光:

var hemisphereLight = new THREE.HemisphereLight(0xffffbb, 0x080820, 1);
// 天空颜色、地面颜色、强度
scene.add(hemisphereLight);

矩形区域光(RectAreaLight)

矩形光源,适合模拟窗户、显示器等:

var rectAreaLight = new THREE.RectAreaLight(0xffffff, 1, 5, 5);
rectAreaLight.position.set(0, 5, 0);
rectAreaLight.lookAt(0, 0, 0);
scene.add(rectAreaLight);

纹理(Texture)

纹理用于给材质添加细节,如颜色、法线、粗糙度等信息。

加载纹理

// 使用 TextureLoader 加载图片
var textureLoader = new THREE.TextureLoader();

var texture = textureLoader.load('path/to/image.jpg', 
    // 加载成功回调
    function(texture) {
        console.log('Texture loaded');
    },
    // 加载进度回调
    function(progress) {
        console.log('Loading progress:', progress);
    },
    // 加载错误回调
    function(error) {
        console.error('Error loading texture:', error);
    }
);

// 应用到材质
var material = new THREE.MeshStandardMaterial({
    map: texture
});

纹理常用属性

// 重复模式
texture.wrapS = THREE.RepeatWrapping;  // 水平重复
texture.wrapT = THREE.RepeatWrapping;  // 垂直重复
texture.repeat.set(2, 2);  // 重复次数

// 过滤模式
texture.magFilter = THREE.LinearFilter;  // 放大过滤
texture.minFilter = THREE.LinearMipmapLinearFilter;  // 缩小过滤

// 翻转
texture.flipY = false;

// 偏移
texture.offset.set(0.1, 0.1);

// 旋转
texture.rotation = Math.PI / 4;
texture.center.set(0.5, 0.5);  // 旋转中心

立方体贴图(CubeTexture)

用于环境映射、天空盒等:

var cubeTextureLoader = new THREE.CubeTextureLoader();
var envMap = cubeTextureLoader.load([
    'px.jpg',  // 右
    'nx.jpg',  // 左
    'py.jpg',  // 上
    'ny.jpg',  // 下
    'pz.jpg',  // 前
    'nz.jpg'   // 后
]);

scene.background = envMap;  // 作为背景

// 应用到材质
material.envMap = envMap;

控制器(Controller)

控制器用于交互式地控制相机和场景中的对象。

OrbitControls(轨道控制器)

最常用的相机控制器,允许围绕目标点旋转、缩放、平移:

// 需要引入 OrbitControls
// import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';

var controls = new THREE.OrbitControls(camera, renderer.domElement);

// 配置选项
controls.enableDamping = true;  // 启用阻尼(惯性)
controls.dampingFactor = 0.05;  // 阻尼系数
controls.enableZoom = true;     // 启用缩放
controls.enableRotate = true;  // 启用旋转
controls.enablePan = true;     // 启用平移

// 限制
controls.minDistance = 5;      // 最小距离
controls.maxDistance = 50;     // 最大距离
controls.minPolarAngle = 0;    // 最小垂直角度
controls.maxPolarAngle = Math.PI;  // 最大垂直角度

// 目标点
controls.target.set(0, 0, 0);

// 在动画循环中更新
function animate() {
    requestAnimationFrame(animate);
    controls.update();  // 必须调用
    renderer.render(scene, camera);
}

FlyControls(飞行控制器)

第一人称视角控制器:

var flyControls = new THREE.FlyControls(camera, renderer.domElement);
flyControls.movementSpeed = 100;
flyControls.domElement = renderer.domElement;
flyControls.rollSpeed = Math.PI / 24;
flyControls.autoForward = false;
flyControls.dragToLook = false;

FirstPersonControls(第一人称控制器)

var firstPersonControls = new THREE.FirstPersonControls(camera, renderer.domElement);
firstPersonControls.movementSpeed = 50;
firstPersonControls.lookSpeed = 0.1;

TrackballControls(轨迹球控制器)

类似 OrbitControls,但使用轨迹球算法:

var trackballControls = new THREE.TrackballControls(camera, renderer.domElement);
trackballControls.rotateSpeed = 1.0;
trackballControls.zoomSpeed = 1.2;
trackballControls.panSpeed = 0.8;

动画(Animation)

Three.js 中的动画可以通过多种方式实现。

使用 requestAnimationFrame

最基础的动画方式:

function animate() {
    requestAnimationFrame(animate);
    
    // 更新对象
    cube.rotation.x += 0.01;
    cube.rotation.y += 0.01;
    
    // 渲染
    renderer.render(scene, camera);
}
animate();

使用 Clock 计算时间差

更精确的动画控制:

var clock = new THREE.Clock();

function animate() {
    requestAnimationFrame(animate);
    
    var elapsedTime = clock.getElapsedTime();
    
    // 基于时间旋转
    cube.rotation.y = elapsedTime;
    
    // 上下浮动
    cube.position.y = Math.sin(elapsedTime) * 0.5;
    
    renderer.render(scene, camera);
}
animate();

使用 GSAP 动画库

// 需要引入 GSAP
// import { gsap } from 'gsap';

gsap.to(cube.rotation, {
    y: Math.PI * 2,
    duration: 2,
    repeat: -1,
    ease: "power1.inOut"
});

gsap.to(cube.position, {
    y: 2,
    duration: 1,
    yoyo: true,
    repeat: -1
});

使用 AnimationMixer(模型动画)

用于加载的 3D 模型动画:

var mixer = new THREE.AnimationMixer(model);

// 获取动画剪辑
var clips = model.animations;
var action = mixer.clipAction(clips[0]);

// 播放动画
action.play();

// 在动画循环中更新
function animate() {
    requestAnimationFrame(animate);
    
    var delta = clock.getDelta();
    mixer.update(delta);
    
    renderer.render(scene, camera);
}

加载器(Loader)

Three.js 提供了多种加载器用于加载 3D 模型、纹理等资源。

GLTFLoader(推荐)

加载 GLTF/GLB 格式的 3D 模型:

// import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';

var gltfLoader = new THREE.GLTFLoader();

gltfLoader.load('model.gltf', function(gltf) {
    var model = gltf.scene;
    scene.add(model);
    
    // 处理动画
    if (gltf.animations && gltf.animations.length) {
        var mixer = new THREE.AnimationMixer(model);
        gltf.animations.forEach(function(clip) {
            mixer.clipAction(clip).play();
        });
    }
});

OBJLoader

加载 OBJ 格式模型:

// import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader.js';

var objLoader = new THREE.OBJLoader();
objLoader.load('model.obj', function(object) {
    scene.add(object);
});

FBXLoader

加载 FBX 格式模型:

// import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader.js';

var fbxLoader = new THREE.FBXLoader();
fbxLoader.load('model.fbx', function(object) {
    scene.add(object);
});

其他常用加载器

// 纹理加载器
var textureLoader = new THREE.TextureLoader();

// 立方体贴图加载器
var cubeTextureLoader = new THREE.CubeTextureLoader();

// HDR 纹理加载器(需要引入)
// import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader.js';
var rgbeLoader = new THREE.RGBELoader();

辅助对象(Helpers)

辅助对象用于调试和可视化,不会影响最终渲染。

常用辅助对象

// 坐标轴辅助器
var axesHelper = new THREE.AxesHelper(5);
scene.add(axesHelper);

// 网格辅助器
var gridHelper = new THREE.GridHelper(10, 10);
scene.add(gridHelper);

// 光源辅助器
var lightHelper = new THREE.DirectionalLightHelper(directionalLight, 5);
scene.add(lightHelper);

// 点光源辅助器
var pointLightHelper = new THREE.PointLightHelper(pointLight, 1);
scene.add(pointLightHelper);

// 相机辅助器
var cameraHelper = new THREE.CameraHelper(camera);
scene.add(cameraHelper);

// 包围盒辅助器
var boxHelper = new THREE.BoxHelper(mesh);
scene.add(boxHelper);

// 法线辅助器
var normalHelper = new THREE.VertexNormalsHelper(mesh, 1, 0xff0000);
scene.add(normalHelper);

性能优化建议

  1. 几何体合并:使用 BufferGeometryUtils.mergeBufferGeometries() 合并相同材质的几何体
  2. 实例化渲染:使用 InstancedMesh 渲染大量相同对象
  3. LOD(细节层次):根据距离使用不同精度的模型
  4. 纹理压缩:使用压缩纹理格式(如 KTX2)
  5. 视锥剔除:Three.js 自动进行,但可以手动控制
  6. 阴影优化:合理设置阴影贴图大小和范围
  7. 材质复用:相同材质尽量复用
  8. 几何体复用:相同几何体尽量复用

完整示例

// 创建场景
var scene = new THREE.Scene();
scene.background = new THREE.Color(0x222222);

// 创建相机
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 5, 10);
camera.lookAt(0, 0, 0);

// 创建渲染器
var renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
document.body.appendChild(renderer.domElement);

// 添加光源
var ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(ambientLight);

var directionalLight = new THREE.DirectionalLight(0xffffff, 1);
directionalLight.position.set(5, 10, 5);
directionalLight.castShadow = true;
scene.add(directionalLight);

// 创建地面
var planeGeometry = new THREE.PlaneGeometry(20, 20);
var planeMaterial = new THREE.MeshStandardMaterial({ color: 0x808080 });
var plane = new THREE.Mesh(planeGeometry, planeMaterial);
plane.rotation.x = -Math.PI / 2;
plane.receiveShadow = true;
scene.add(plane);

// 创建立方体
var boxGeometry = new THREE.BoxGeometry(1, 1, 1);
var boxMaterial = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
var box = new THREE.Mesh(boxGeometry, boxMaterial);
box.position.set(0, 0.5, 0);
box.castShadow = true;
scene.add(box);

// 添加辅助器
var axesHelper = new THREE.AxesHelper(5);
scene.add(axesHelper);

var gridHelper = new THREE.GridHelper(20, 20);
scene.add(gridHelper);

// 创建控制器
var controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;

// 动画循环
var clock = new THREE.Clock();

function animate() {
    requestAnimationFrame(animate);
    
    var elapsedTime = clock.getElapsedTime();
    
    // 旋转立方体
    box.rotation.y = elapsedTime;
    
    // 更新控制器
    controls.update();
    
    // 渲染
    renderer.render(scene, camera);
}

animate();

// 响应窗口大小变化
window.addEventListener('resize', function() {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);
});

这就是 Three.js 的核心概念和基本用法。通过组合这些概念,你可以创建出各种复杂的 3D 场景和交互效果。