从零开始学习three.js(10):场景Scene深度解析,从基础到高级应用

316 阅读2分钟

Three.js作为WebGL的高效封装库,其核心场景(Scene)对象是构建3D应用的起点。本文将从场景的基础创建到高级应用,结合代码实践与设计思想,全面解析场景的奥秘。

一、场景基础:三维世界的容器

1.1 场景的创建与基本结构

import * as THREE from 'three';

// 创建基础场景
const scene = new THREE.Scene();
scene.name = "MainScene"; // 可命名便于调试

// 典型场景构成
const elements = {
  meshes: [],    // 网格对象
  lights: [],    // 光源系统
  cameras: [],   // 观察视角
  helpers: [],   // 辅助工具
  environment: null // 环境设置
};

1.2 场景图(Scene Graph)体系

Three.js 采用树状结构管理场景元素:

// 创建层级结构
const parentGroup = new THREE.Group();
parentGroup.name = "Building";

const wallMesh = new THREE.Mesh(geometry, material);
const roofMesh = new THREE.Mesh(geometry, material);

parentGroup.add(wallMesh, roofMesh);
scene.add(parentGroup);

// 遍历场景元素
scene.traverse((obj) => {
  if (obj instanceof THREE.Mesh) {
    obj.material.needsUpdate = true;
  }
});

二、场景环境配置

2.1 光源系统搭建

// 环境光
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(ambientLight);

// 方向光
const dirLight = new THREE.DirectionalLight(0xffffff, 1);
dirLight.position.set(5, 5, 5);
scene.add(dirLight);

// 点光源矩阵
const pointLight = new THREE.PointLight(0xff0000, 10, 5);
pointLight.position.set(5, 5, 5);
scene.add(lightsGrid);

2.2 背景与环境贴图

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

// 全景环境贴图
new THREE.CubeTextureLoader()
  .setPath('textures/skybox/')
  .load(['px.jpg', 'nx.jpg', 'py.jpg', 'ny.jpg', 'pz.jpg', 'nz.jpg'], 
    (texture) => {
      scene.background = texture;
      scene.environment = texture; // 物理材质反射
    });

2.3 雾效实现

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

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

// 在材质中启用雾效
material = new THREE.MeshStandardMaterial({
  color: 0xff0000,
  fog: true
});

三、高级场景管理

3.1 多场景渲染

// 创建多个场景
const mainScene = new THREE.Scene();
const uiScene = new THREE.Scene();

function render() {
  renderer.clear();
  
  // 主场景渲染
  renderer.setViewport(0, 0, window.innerWidth, window.innerHeight);
  renderer.render(mainScene, mainCamera);
  
  // UI场景渲染
  renderer.setScissorTest(true);
  renderer.setScissor(10, 10, 200, 100);
  renderer.render(uiScene, uiCamera);
  renderer.setScissorTest(false);
}

3.2 分屏实现

function render() {
    // 左半屏
    renderer.setScissor(0, 0, sliderPos, height);
    renderer.render(sceneLeft, camera);
    
    // 右半屏 
    renderer.setScissor(sliderPos, 0, width-sliderPos, height);
    renderer.render(sceneRight, camera);
}

四、性能优化策略

  • 视锥剔除:自动跳过视锥体外物体
  • LOD系统:根据距离切换模型精度
  • 空间分区:八叉树/四叉树管理

4.1 可见性裁剪

// 使用视锥体剔除
const frustum = new THREE.Frustum();
const matrix = new THREE.Matrix4().multiplyMatrices(
  camera.projectionMatrix,
  camera.matrixWorldInverse
);
frustum.setFromProjectionMatrix(matrix);

scene.traverse((obj) => {
  if (obj.geometry) {
    const inView = frustum.intersectsSphere(obj.geometry.boundingSphere);
    obj.visible = inView;
  }
});

4.2 几何体合并

const mergeGeometry = (geometries, material) => {
  const merged = new THREE.BufferGeometry();
  const positions = [];
  const colors = [];
  
  geometries.forEach(geo => {
    positions.push(...geo.attributes.position.array);
    colors.push(...geo.attributes.color.array);
  });
  
  merged.setAttribute('position', 
    new THREE.BufferAttribute(new Float32Array(positions), 3));
  merged.setAttribute('color',
    new THREE.BufferAttribute(new Float32Array(colors), 3));
  
  return new THREE.Mesh(merged, material);
};

4.3 调试工具

  • 场景浏览器scene-explorer库可视化场景树
  • 坐标系辅助器
scene.add(new THREE.AxesHelper(10)); 
  • 性能监控stats.js监控FPS/内存

5.2 性能指标

优化方向典型措施性能提升
Draw Call合并几何体30-50%
纹理内存压缩纹理+Mipmap20-40%
着色器复杂度简化光照计算15-25%
动画更新分帧更新不同物体10-30%

更多three.js、cesium.js开源案例,请移至gitee.com/giser2017/t…