Three.js 天空盒教程
天空盒 ·Sky And Env· ▶ 在线运行案例案例合集三维可视化功能案例threehub.cn开源仓库github地址https://github.com/z2586300277/three-cesium-examples400个案例代码:网盘链接你将学到什么CubeTexture六面体天空盒的加载与贴图顺序scene.background与material.envMap的分工PBR 材质metalness / roughness如何影响环境反射天空盒不等同于在场景里放一个 Box 网格效果说明场景背景是一圈全景天空六张 PNG 拼成的立方体环境中央有一个高反光金属立方体表面映出天空颜色。拖动 OrbitControls 时背景随相机旋转立方体反射也会变化。核心概念天空盒是什么天空盒不是场景里的一个大盒子模型而是无穷远处的背景相机始终在立方体内部六面贴图永远「包住」整个场景。Y (top)│ ┌─────┼─────┐ │ │ │ -X ┼─────O─────X ← 相机在中心看六面内壁 │ │ │ └─────┼─────┘ -Y (bottom) Z / -Z 为前后CubeTextureLoader 贴图顺序Three.js 要求6 张图按固定顺序传入与 OpenGL 立方体贴图一致| 索引 | 面 | |------|-----| | 0 | X (右) | | 1 | -X (左) | | 2 | Y (上) | | 3 | -Y (下) | | 4 | Z (前) | | 5 | -Z (后) |const urls [1, 2, 3, 4, 5, 6].map(i basePath i .png);const textureCube new THREE.CubeTextureLoader().load(urls);贴图顺序错了会出现「接缝错位、天空拼接混乱」——这是天空盒最常见的问题。background vs envMap vs environment| 属性 | 作用对象 | 本案例 | |------|---------|--------| |scene.background cubeTexture|相机看到的远景背景| ✅ 已设置 | |material.envMap cubeTexture|单个材质的反射/折射采样 | ✅ 立方体材质 | |scene.environment cubeTexture| 场景内所有 PBR 材质的 IBL 环境光 | ❌ 未设置 |本案例只给立方体设置了envMap未设scene.environment也未加 DirectionalLight / AmbientLight。立方体靠高 metalness 低 roughness几乎变成「环境镜」主要显示 envMap 反射所以仍然可见。::: tip 现代推荐写法 加载 cubemap 后通常同时写scene.background textureCube;scene.environment textureCube; // 所有 MeshStandardMaterial 自动 IBL不必每个材质手动envMap textureCube。 :::PBR 参数在本案例中的含义new THREE.MeshStandardMaterial({color: 0xffffff, envMap: textureCube, metalness: 1, // 完全金属 → 反射为主 roughness: 0, // 完全光滑 → 清晰倒影 });| 参数 | 值 | 视觉效果 | |------|-----|---------| |metalness: 1| 纯金属 | 颜色主要来自反射而非漫反射 | |roughness: 0| 镜面 | 反射清晰像抛光金属 | |roughness: 0.5| 可尝试 | 反射变模糊更像磨砂金属 |实现步骤Scene / Camera / Renderer / OrbitControls rAF与 创建场景 相同骨架CubeTextureLoader.load(urls)加载六面 PNGscene.background textureCube设背景天空创建立方体MeshStandardMaterialenvMap: textureCubescene.add(boxMesh)无额外光源代码要点import * as THREE from threeimport { OrbitControls } from three/examples/jsm/controls/OrbitControls.jsconst box document.getElementById(box)const scene new THREE.Scene()const camera new THREE.PerspectiveCamera(50, box.clientWidth / box.clientHeight, 0.1, 1000)camera.position.set(0, 10, 10)const renderer new THREE.WebGLRenderer({ antialias: true, alpha: true, logarithmicDepthBuffer: true })renderer.setSize(box.clientWidth, box.clientHeight)box.appendChild(renderer.domElement)const controls new OrbitControls(camera, renderer.domElement)controls.enableDamping trueanimate()function animate() {requestAnimationFrame(animate)controls.update()renderer.render(scene, camera)}window.onresize () {renderer.setSize(box.clientWidth, box.clientHeight)camera.aspect box.clientWidth / box.clientHeightcamera.updateProjectionMatrix()}// 文件地址 const urls [0, 1, 2, 3, 4, 5].map(k (FILE_HOST files/sky/skyBox0/ (k 1) .png));const textureCube new THREE.CubeTextureLoader().load(urls);scene.background textureCube;// 环境贴图 const boxGeometry new THREE.BoxGeometry(10, 10, 10);const boxMaterial new THREE.MeshStandardMaterial({ color: 0xffffff, envMap: textureCube, metalness: 1, roughness: 0 });const boxMesh new THREE.Mesh(boxGeometry, boxMaterial);scene.add(boxMesh);完整源码GitHub小结天空盒 CubeTexture scene.background相机永远在盒内物体映天空 MeshStandardMaterial.envMap或scene.environment全局生效HDR 全景图方案见 模型天空、工具 hdr 天空盒