1. Three.js 三大核心组件详解

1.1. 概述

Three.js的三大核心组件构成了3D渲染的基本架构,它们之间的关系可以概括为:场景(Scene) 包含所有3D对象和光源,相机(Camera) 决定观察视角,渲染器(Renderer) 负责将场景通过相机视角渲染到HTML元素中。

javascript

// 基本使用流程
const scene = new THREE.Scene();          // 1. 创建场景
const camera = new THREE.PerspectiveCamera(); // 2. 创建相机【此处为最常用的透视相机】

const renderer = new THREE.WebGLRenderer(); // 3. 创建渲染器

// 设置渲染器
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

// 将场景和相机传递给渲染器
renderer.render(scene, camera);

1.2. 场景(Scene)

1.2.1. 核心概念

场景是所有3D对象的容器,它本身是一个树形结构,可以添加各种对象(网格、灯光、摄像机等),并提供统一的坐标空间。

1.2.2. 主要功能

添加和管理对象

javascript

const scene = new THREE.Scene();

// 创建几何体和材质
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
const cube = new THREE.Mesh(geometry, material);

// 添加到场景
scene.add(cube);

// 检查对象
console.log(scene.children); // 查看所有子对象
console.log(scene.getObjectByName('myCube')); // 按名称获取对象

// 移除对象
scene.remove(cube);

// 清空场景
scene.clear();

1.2.3. 场景图(Scene Graph)

场景使用场景图管理对象,允许父子关系:

javascript

const group = new THREE.Group();
const cube1 = new THREE.Mesh(geometry, material);
const cube2 = new THREE.Mesh(geometry, material);

cube1.position.x = -2;
cube2.position.x = 2;

group.add(cube1, cube2);
group.position.y = 1;
scene.add(group); // 移动group会影响所有子对象

1.2.4. 雾效(Fog)

javascript

// 线性雾
scene.fog = new THREE.Fog(0xcccccc, 10, 50);

// 指数雾
scene.fog = new THREE.FogExp2(0xcccccc, 0.1);

1.2.5. 背景设置

javascript

// 纯色背景
scene.background = new THREE.Color(0x87CEEB);

// 纹理背景
const loader = new THREE.TextureLoader();
loader.load('sky.jpg', function(texture) {
    scene.background = texture;
});

// 立方体贴图(天空盒)
const cubeTextureLoader = new THREE.CubeTextureLoader();
scene.background = cubeTextureLoader.load([
    'px.png', 'nx.png', // 左右
    'py.png', 'ny.png', // 上下
    'pz.png', 'nz.png'  // 前后
]);

1.3. 3. 重要属性和方法

场景的重要属性和方法

1.4. 相机(Camera)

1.4.1. 相机类型

透视相机(PerspectiveCamera) - 最常用

模拟人眼视角,有近大远小的透视效果。

javascript

// 参数:视野角(FOV), 宽高比, 近平面, 远平面
const camera = new THREE.PerspectiveCamera(
    75, // 视野角度 (degrees)
    window.innerWidth / window.innerHeight, // 宽高比
    0.1, // 近平面 (任何比这更近的对象不可见)
    1000  // 远平面 (任何比这更远的对象不可见)
);

// 设置相机位置
camera.position.set(0, 0, 5);
camera.lookAt(0, 0, 0); // 看向原点

1.4.2. 正交相机(OrthographicCamera)

没有透视效果,所有尺寸保持相同,适合2D游戏或工程图。

javascript

// 参数:左、右、上、下、近、远
const camera = new THREE.OrthographicCamera(
    -5, 5, // 左右
    5, -5, // 上下 (注意顺序)
    0.1, 1000 // 近远平面
);

1.4.3. 其他相机类型

javascript

// 立方体相机(用于立方体贴图)
const cubeCamera = new THREE.CubeCamera(0.1, 1000, 256);

// 阵列相机(多视角)
const camera = new THREE.ArrayCamera([
    new THREE.PerspectiveCamera(),
    new THREE.PerspectiveCamera()
]);

1.5. 相机控制和操作

1.5.1. 基础变换

javascript

// 位置
camera.position.set(0, 2, 5);

// 旋转
camera.rotation.set(0, Math.PI/4, 0);

// 看向目标
camera.lookAt(new THREE.Vector3(0, 0, 0));

// 使用目标点
const target = new THREE.Vector3(1, 0, 0);
camera.lookAt(target);

1.5.2. 相机辅助工具

javascript

// 1. CameraHelper - 可视化相机范围
const helper = new THREE.CameraHelper(camera);
scene.add(helper);

// 2. 轨道控制器(需要引入OrbitControls)
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true; // 平滑阻尼效果
controls.dampingFactor = 0.05;

// 3. 飞行控制器
import { FlyControls } from 'three/addons/controls/FlyControls.js';
const controls = new FlyControls(camera, renderer.domElement);
controls.movementSpeed = 100;
controls.rollSpeed = Math.PI / 24;

1.5.3. 相机投影矩阵

javascript

// 更新投影矩阵(当窗口大小变化时)
window.addEventListener('resize', () => {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix(); // 必须调用!
    renderer.setSize(window.innerWidth, window.innerHeight);
});

1.6. 渲染器(Renderer)

1.6.1. 渲染器类型

WebGLRenderer(最常用)

javascript

const renderer = new THREE.WebGLRenderer({
    antialias: true,      // 抗锯齿
    alpha: true,          // 透明背景
    precision: 'highp',   // 精度
    powerPreference: 'high-performance', // 性能偏好
    stencil: false,       // 禁用模板缓冲区
    depth: true,          // 启用深度缓冲区
    logarithmicDepthBuffer: true // 解决z-fighting
});

// 设置大小和像素比
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); // 防止性能问题

// 添加到DOM
document.body.appendChild(renderer.domElement);

1.6.2. 其他渲染器

javascript

// WebGL 1.0 渲染器(兼容旧设备)
const renderer = new THREE.WebGL1Renderer();

// CSS3D渲染器(用于HTML元素的3D变换)
const renderer = new THREE.CSS3DRenderer();

// SVG渲染器(矢量图形)
const renderer = new THREE.SVGRenderer();

1.6.3. 渲染器配置

输出设置

javascript

// 设置背景颜色和透明度
renderer.setClearColor(0x000000, 1); // 颜色, 透明度

// 设置渲染尺寸
renderer.setSize(width, height);

// 设置像素比
renderer.setPixelRatio(window.devicePixelRatio);

// 自动清除颜色、深度、模板缓冲区
renderer.autoClear = true;

// 阴影支持
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap; // 柔和阴影

1.6.4. 性能优化

javascript

// 启用物理正确光照
renderer.physicallyCorrectLights = true;

// 色调映射
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = 1.0;

// 输出编码
renderer.outputEncoding = THREE.sRGBEncoding;

// 开启抗锯齿
renderer.antialias = true;

// 性能监视
const stats = new Stats();
document.body.appendChild(stats.dom);

function animate() {
    requestAnimationFrame(animate);
    renderer.render(scene, camera);
    stats.update(); // 更新性能监视器
}

1.6.5. 渲染循环

javascript

// 基本渲染循环
function animate() {
    requestAnimationFrame(animate);

    // 更新场景对象
    cube.rotation.x += 0.01;
    cube.rotation.y += 0.01;

    // 渲染场景
    renderer.render(scene, camera);
}

animate();

// 带控制的渲染循环
let clock = new THREE.Clock();
let delta = 0;

function animate() {
    requestAnimationFrame(animate);

    delta = clock.getDelta(); // 获取时间差

    // 更新控制器
    if (controls) controls.update(delta);

    // 更新动画
    updateAnimations(delta);

    // 渲染
    renderer.render(scene, camera);
}

1.7. 三者协同工作示例

javascript

// 完整示例
function init() {
    // 1. 创建场景
    const scene = new THREE.Scene();
    scene.background = new THREE.Color(0x87CEEB);
    scene.fog = new THREE.Fog(0x87CEEB, 10, 100);

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

    // 3. 创建渲染器
    const renderer = new THREE.WebGLRenderer({
        antialias: true,
        alpha: true
    });
    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
    renderer.shadowMap.enabled = true;
    renderer.shadowMap.type = THREE.PCFSoftShadowMap;
    document.body.appendChild(renderer.domElement);

    // 4. 添加内容
    const geometry = new THREE.BoxGeometry(1, 1, 1);
    const material = new THREE.MeshStandardMaterial({ 
        color: 0x00ff00,
        roughness: 0.5,
        metalness: 0.5
    });
    const cube = new THREE.Mesh(geometry, material);
    cube.castShadow = true;
    scene.add(cube);

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

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

    // 5. 添加控制器
    const controls = new OrbitControls(camera, renderer.domElement);
    controls.enableDamping = true;
    controls.dampingFactor = 0.05;

    // 6. 处理窗口大小变化
    window.addEventListener('resize', () => {
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize(window.innerWidth, window.innerHeight);
    });

    // 7. 动画循环
    function animate() {
        requestAnimationFrame(animate);

        // 更新对象
        cube.rotation.x += 0.01;
        cube.rotation.y += 0.005;

        // 更新控制器
        controls.update();

        // 渲染场景
        renderer.render(scene, camera);
    }

    animate();
}

init();

1.8. 最佳实践和注意事项

1.8.1. 性能优化

1.8.2. 内存管理

javascript

// 清理资源
function disposeObject(object) {
    if (object.geometry) object.geometry.dispose();
    if (object.material) {
        if (Array.isArray(object.material)) {
            object.material.forEach(material => material.dispose());
        } else {
            object.material.dispose();
        }
    }
}

// 清理场景
function clearScene(scene) {
    scene.traverse(disposeObject);
    scene.clear();
}

1.9. 响应式设计

javascript

// 处理响应式
function onWindowResize() {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);
}
window.addEventListener('resize', onWindowResize);

1.10. 总结

Three.js的三大核心组件构成了3D渲染的基础框架:

理解这三者如何协同工作是掌握Three.js的关键。通过合理的配置和优化,可以创建出高性能、视觉效果出色的3D应用。