第一部分-Three.js基础入门——02. 场景
02. 场景(Scene)
1. 概述
场景(Scene)是 Three.js 中所有 3D 对象的容器,类似于电影拍摄中的舞台。所有物体、光源、辅助对象都需要添加到场景中才能被渲染。
┌─────────────────────────────────────────────────────────────┐ │ 场景 (Scene) │ ├─────────────────────────────────────────────────────────────┤ │ │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ 网格 │ │ 光源 │ │ 相机 │ │ │ │ (Mesh) │ │ (Light) │ │ (Camera) │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │ │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ 辅助对象 │ │ 粒子系统 │ │ 组 │ │ │ │ (Helper) │ │ (Points) │ │ (Group) │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │ │ │ 场景属性 │ │ ├── background: 背景色/纹理 │ │ ├── fog: 雾效 │ │ ├── environment: 环境贴图 │ │ └── children: 子对象列表 │ │ │ └─────────────────────────────────────────────────────────────┘2. 创建场景
2.1 基础场景
import*asTHREEfrom'three';// 创建场景constscene=newTHREE.Scene();// 设置背景颜色scene.background=newTHREE.Color(0x111122);// 设置背景纹理consttextureLoader=newTHREE.TextureLoader();constbgTexture=textureLoader.load('path/to/texture.jpg');scene.background=bgTexture;2.2 场景属性
// 场景名称(用于调试)scene.name='MainScene';// 场景可见性scene.visible=true;// 场景中的对象列表console.log(scene.children);// 场景中的对象数量console.log(scene.children.length);// 自动更新矩阵scene.matrixAutoUpdate=true;3. 添加与移除对象
3.1 添加对象
import*asTHREEfrom'three';constscene=newTHREE.Scene();// 创建立方体constgeometry=newTHREE.BoxGeometry(1,1,1);constmaterial=newTHREE.MeshStandardMaterial({color:0x44aa88});constcube=newTHREE.Mesh(geometry,material);// 添加到场景scene.add(cube);// 添加多个对象constsphereGeometry=newTHREE.SphereGeometry(0.5,32,32);constsphereMaterial=newTHREE.MeshStandardMaterial({color:0xff6600});constsphere=newTHREE.Mesh(sphereGeometry,sphereMaterial);sphere.position.set(1.5,0,0);scene.add(sphere);constcylinderGeometry=newTHREE.CylinderGeometry(0.5,0.5,1,32);constcylinderMaterial=newTHREE.MeshStandardMaterial({color:0x44aaff});constcylinder=newTHREE.Mesh(cylinderGeometry,cylinderMaterial);cylinder.position.set(-1.5,0,0);scene.add(cylinder);3.2 移除对象
// 通过引用移除scene.remove(cube);// 通过名称查找并移除cube.name='myCube';constfoundCube=scene.getObjectByName('myCube');if(foundCube){scene.remove(foundCube);}// 移除所有对象while(scene.children.length>0){scene.remove(scene.children[0]);}// 清理内存(重要!)cube.geometry.dispose();cube.material.dispose();scene.remove(cube);3.3 查找对象
// 按名称查找constobject=scene.getObjectByName('myCube');// 按类型查找constcubes=scene.children.filter(child=>child.isMesh);// 按位置查找constobjectsAtPosition=scene.children.filter(obj=>obj.position.x===0&&obj.position.y===0);4. 场景背景
4.1 纯色背景
// 十六进制颜色scene.background=newTHREE.Color(0x000000);// RGB 颜色scene.background=newTHREE.Color(0.1,0.2,0.3);// 颜色名称scene.background=newTHREE.Color('skyblue');4.2 纹理背景
// 单张纹理consttextureLoader=newTHREE.TextureLoader();constbgTexture=textureLoader.load('path/to/background.jpg');scene.background=bgTexture;// 立方纹理(天空盒)constcubeTextureLoader=newTHREE.CubeTextureLoader();constskyboxTexture=cubeTextureLoader.load(['px.jpg','nx.jpg',// 右、左'py.jpg','ny.jpg',// 上、下'pz.jpg','nz.jpg'// 前、后]);scene.background=skyboxTexture;scene.environment=skyboxTexture;// 环境反射4.3 渐变色背景
// 使用 CanvasTexture 实现渐变背景constcanvas=document.createElement('canvas');canvas.width=512;canvas.height=512;constctx=canvas.getContext('2d');// 创建渐变constgradient=ctx.createLinearGradient(0,0,canvas.width,canvas.height);gradient.addColorStop(0,'#1a1a2e');gradient.addColorStop(0.5,'#16213e');gradient.addColorStop(1,'#0f3460');ctx.fillStyle=gradient;ctx.fillRect(0,0,canvas.width,canvas.height);constgradientTexture=newTHREE.CanvasTexture(canvas);scene.background=gradientTexture;5. 雾效
5.1 线性雾
// 线性雾:距离越远越模糊// 参数:颜色、开始距离、结束距离scene.fog=newTHREE.Fog(0x111122,10,30);// 动态更新scene.fog.color.setHex(0x223344);scene.fog.near=5;scene.fog.far=25;5.2 指数雾
// 指数雾:密度指数增长// 参数:颜色、密度scene.fog=newTHREE.FogExp2(0x111122,0.05);// 密度越大,雾越浓scene.fog.density=0.08;5.3 移除雾效
// 设置为 null 移除雾scene.fog=null;6. 场景组织
6.1 使用 Group 分组
// 创建组constgroup=newTHREE.Group();// 添加物体到组constcube1=newTHREE.Mesh(geometry,material);cube1.position.set(-1,0,0);constcube2=newTHREE.Mesh(geometry,material);cube2.position.set(1,0,0);group.add(cube1,cube2);scene.add(group);// 移动整个组group.position.y=1;group.rotation.y=Math.PI/4;// 遍历组内对象group.children.forEach(child=>{console.log(child.position);});6.2 对象层级
// 父子关系constparent=newTHREE.Object3D();constchild=newTHREE.Object3D();parent.add(child);// 子对象的位置是相对于父对象的parent.position.set(1,0,0);child.position.set(1,0,0);// child 的世界坐标是 (2, 0, 0)// 获取世界坐标constworldPosition=child.getWorldPosition(newTHREE.Vector3());6.3 辅助对象
// 坐标轴辅助器constaxesHelper=newTHREE.AxesHelper(5);scene.add(axesHelper);// 网格辅助器constgridHelper=newTHREE.GridHelper(20,20,0x888888,0x444444);scene.add(gridHelper);// 平面辅助器constplaneHelper=newTHREE.PlaneHelper(newTHREE.Plane(newTHREE.Vector3(0,1,0),0),5,0xff0000);scene.add(planeHelper);// 相机辅助器constcameraHelper=newTHREE.CameraHelper(camera);scene.add(cameraHelper);// 光源辅助器constlight=newTHREE.DirectionalLight(0xffffff,1);light.position.set(5,5,5);scene.add(light);constlightHelper=newTHREE.DirectionalLightHelper(light,0.5);scene.add(lightHelper);7. 场景遍历与优化
7.1 遍历所有对象
// 递归遍历场景functiontraverseScene(object,callback){callback(object);object.children.forEach(child=>{traverseScene(child,callback);});}traverseScene(scene,(obj)=>{if(obj.isMesh){console.log('Mesh:',obj.name,obj.position);}});// 使用 Three.js 内置方法scene.traverse((obj)=>{if(obj.isMesh){obj.material.color.setHex(0xff0000);}});7.2 性能优化
// 隐藏/显示对象(不渲染,但仍在场景中)cube.visible=false;// 禁用阴影cube.castShadow=false;cube.receiveShadow=false;// 批量添加(避免多次渲染)constobjects=[cube,sphere,cylinder];scene.add(...objects);// 清理场景functionclearScene(){scene.traverse((obj)=>{if(obj.isMesh){obj.geometry.dispose();if(obj.material){if(Array.isArray(obj.material)){obj.material.forEach(m=>m.dispose());}else{obj.material.dispose();}}}});while(scene.children.length>0){scene.remove(scene.children[0]);}}8. 完整示例:多物体场景
import*asTHREEfrom'three';import{OrbitControls}from'three/examples/jsm/controls/OrbitControls.js';// 创建场景constscene=newTHREE.Scene();scene.background=newTHREE.Color(0x0a0a2a);scene.fog=newTHREE.FogExp2(0x0a0a2a,0.01);// 创建相机constcamera=newTHREE.PerspectiveCamera(45,window.innerWidth/window.innerHeight,0.1,1000);camera.position.set(5,5,10);camera.lookAt(0,0,0);// 创建渲染器constrenderer=newTHREE.WebGLRenderer({antialias:true});renderer.setSize(window.innerWidth,window.innerHeight);renderer.shadowMap.enabled=true;document.body.appendChild(renderer.domElement);// 轨道控制constcontrols=newOrbitControls(camera,renderer.domElement);controls.enableDamping=true;// 添加物体constgeometry=newTHREE.BoxGeometry(1,1,1);constmaterial=newTHREE.MeshStandardMaterial({color:0x44aa88,metalness:0.5,roughness:0.3});constcube=newTHREE.Mesh(geometry,material);cube.castShadow=true;cube.receiveShadow=true;scene.add(cube);constsphereGeometry=newTHREE.SphereGeometry(0.8,32,32);constsphereMaterial=newTHREE.MeshStandardMaterial({color:0xff6600,metalness:0.2,roughness:0.4});constsphere=newTHREE.Mesh(sphereGeometry,sphereMaterial);sphere.position.set(2,0,0);sphere.castShadow=true;scene.add(sphere);// 添加地面constplaneGeometry=newTHREE.PlaneGeometry(10,10);constplaneMaterial=newTHREE.MeshStandardMaterial({color:0x336699,side:THREE.DoubleSide});constplane=newTHREE.Mesh(planeGeometry,planeMaterial);plane.rotation.x=-Math.PI/2;plane.position.y=-1;plane.receiveShadow=true;scene.add(plane);// 添加光源constambientLight=newTHREE.AmbientLight(0x404040);scene.add(ambientLight);constdirectionalLight=newTHREE.DirectionalLight(0xffffff,1);directionalLight.position.set(5,10,7);directionalLight.castShadow=true;scene.add(directionalLight);constfillLight=newTHREE.PointLight(0x4466cc,0.5);fillLight.position.set(-2,2,3);scene.add(fillLight);// 辅助对象constaxesHelper=newTHREE.AxesHelper(5);scene.add(axesHelper);constgridHelper=newTHREE.GridHelper(20,20);scene.add(gridHelper);// 动画functionanimate(){requestAnimationFrame(animate);// 旋转物体cube.rotation.x+=0.005;cube.rotation.y+=0.01;sphere.rotation.x+=0.008;sphere.rotation.y+=0.008;controls.update();renderer.render(scene,camera);}animate();// 窗口适配window.addEventListener('resize',onWindowResize,false);functiononWindowResize(){camera.aspect=window.innerWidth/window.innerHeight;camera.updateProjectionMatrix();renderer.setSize(window.innerWidth,window.innerHeight);}9. 总结
| 要点 | 说明 |
|---|---|
| 场景创建 | new THREE.Scene() |
| 背景设置 | scene.background |
| 雾效 | scene.fog |
| 添加对象 | scene.add(object) |
| 移除对象 | scene.remove(object) |
| 查找对象 | scene.getObjectByName() |
| 对象分组 | Group类 |
| 场景遍历 | scene.traverse() |
| 内存清理 | dispose()方法 |
