通过 Three.js 实现天空盒:两种常见的实现方式
在3D图形渲染中,天空盒(Skybox)被用来模拟一个虚拟世界的背景。它通过包裹整个场景的方式,让用户有一种身处于无尽虚拟环境中的感觉。常见的天空盒实现方式包括使用球体(Sphere Map)和立方体(Cube Map)。今天,我们将通过 Three.js 这两个常见的实现方式来创建天空盒。
一. 球形天空盒(Sphere Map)
概述
球形天空盒通过将一张全景图(360°)应用到球体的内表面来创建天空背景。这种方式特别适用于需要展示全景图像或360°视频的场景。与立方体映射不同,球形天空盒避免了接缝和拼接问题,给人一种自然的沉浸感。
实现原理
我们使用 THREE.SphereGeometry 创建一个球体,并将纹理(通常为一张360°全景图)贴在球体的内表面。为了让用户可以看到整个球体,我们需要将其反转(通过设置 scale.set(1, 1, -1) 来实现),使得纹理显示在内部。
优点
-
无缝效果:没有拼接线,视觉效果更加自然。
-
适合全景图像:非常适合展示360°全景图或视频,特别是在虚拟现实(VR)应用中。
缺点
-
性能要求较高:特别是当全景图的分辨率较高时,可能对性能产生一定影响。
-
灵活性差:与立方体天空盒不同,球形天空盒无法通过多张图片自定义不同方向的图像。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> body { margin: 0; padding: 0; } </style> </head> <body> <script type="module"> import * as THREE from 'three'; import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'; // 创建场景 const scene = new THREE.Scene(); scene.background = new THREE.Color('pink'); // 创建相机 const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); camera.position.set(0, 0, 1); camera.lookAt(0, 0, 0); // 创建渲染管线 const renderer = new THREE.WebGLRenderer(); renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); //加载图片 const loader = new THREE.TextureLoader(); const map = loader.load('./images/panorama/mirrored_hall.webp') // 创建一个物体 const geometry = new THREE.SphereGeometry(16, 32, 32); const material = new THREE.MeshBasicMaterial({ map: map }); const cube = new THREE.Mesh(geometry, material); cube.geometry.scale(1, 1, -1) scene.add(cube); // 创建一个轨道控制器 const controls = new OrbitControls(camera, renderer.domElement); controls.enableDamping = true; function animate() { requestAnimationFrame(animate); controls.update(); renderer.render(scene, camera); } animate(); </script> </body> </html>
二. 立方体天空盒(Cube Map)
概述
立方体天空盒是另一种常见的实现方式,它通过六张图像来模拟天空背景。每张图像代表天空盒的一个面:前、后、左、右、上和下。这六张图片被应用到一个立方体的内表面,构成一个完整的背景环境。
实现原理
在 Three.js 中,我们可以使用 THREE.TextureLoader 来加载这六张图片,并将其作为场景的背景贴图。通过这种方式,用户可以看到立方体的六个面,从而形成一个包围他们的环境。
优点
-
性能较好:立方体映射适用于大多数设备,并且可以高效地渲染。
-
灵活性:可以自定义每个面上的图像,适用于多种环境效果。
缺点
-
拼接问题:由于使用的是六张图像,若图片之间的拼接不准确,可能会出现接缝。
-
不适合全景图像:对于全景图像来说,使用立方体天空盒可能不如球形天空盒那样自然。
立方体天空盒图片的顺序
为了正确渲染立方体天空盒,必须确保六张图片按照以下顺序排列,并与 Three.js 中的六个面一一对应:
-
右面(Right):映射到立方体的右侧面。
-
左面(Left):映射到立方体的左侧面。
-
上面(Up):映射到立方体的顶部面。
-
下面(Down):映射到立方体的底部面。
-
前面(Front):映射到立方体的前面。
-
后面(Back):映射到立方体的背面。
正确的图片顺序确保每个面都有正确的纹理,从而生成一个完整的天空盒。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> body { margin: 0; padding: 0; } </style> </head> <body> <script type="module"> import * as THREE from 'three'; import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'; let isTrue = false; // 创建场景 const scene = new THREE.Scene(); scene.background = new THREE.Color('pink'); // 创建相机 const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); camera.position.set(0, 0, 1); camera.lookAt(0, 0, 1); //渲染器 const renderer = new THREE.WebGLRenderer(); renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); //加载图片 const loader = new THREE.TextureLoader(); //加载图片的数组 const images = [ './images/360vr/mobile_r.jpg', // right './images/360vr/mobile_l.jpg', // left './images/360vr/mobile_u.jpg', // up './images/360vr/mobile_d.jpg', // down './images/360vr/mobile_f.jpg', // front './images/360vr/mobile_b.jpg' // back (注意:你可能需要提供正确的 back 图片) ]; let materialsList = []; images.forEach((image, index) => { const texture = loader.load(image); const material = new THREE.MeshBasicMaterial({ map: texture }); materialsList.push(material) }); // 创建一个物体 const geometry = new THREE.BoxGeometry(20, 20, 20); geometry.scale(1, 1, -1); const material = new THREE.MeshBasicMaterial(); const cube = new THREE.Mesh(geometry, materialsList); scene.add(cube); // 创建一个轨道控制器 const controls = new OrbitControls(camera, renderer.domElement); controls.enableDamping = true; function animate() { requestAnimationFrame(animate); controls.update(); renderer.render(scene, camera); } animate(); </script> </body> </html>
三. 比较:球形天空盒与立方体天空盒
| 特性 | 球形天空盒 | 立方体天空盒 |
|---|---|---|
| 实现难度 | 较简单,仅需一张全景图像 | 需要六张不同的图像,稍微复杂 |
| 纹理映射 | 映射到球体的内表面 | 映射到立方体的六个面 |
| 性能 | 较高的性能消耗,尤其在高分辨率图像时 | 性能较高,适合大多数设备 |
| 拼接问题 | 无拼接问题,效果自然 | 可能会遇到接缝或接触不良的问题 |
| 适用场景 | 适合全景图像和VR应用 | 适合多种场景,可以自定义每个面的图像 |
四、总结
球形天空盒和立方体天空盒是两种常见的实现方式,各自有其优缺点。球形天空盒适合展示全景图像,具有较为自然的效果,但对性能要求较高;而立方体天空盒则提供了更好的性能和灵活性,适用于需要多种方向图像的场景。
根据具体的项目需求,可以选择适合的天空盒方式来优化渲染效果和性能。
效果展示:


浙公网安备 33010602011771号