通过 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 中的六个面一一对应:

  1. 右面(Right):映射到立方体的右侧面。

  2. 左面(Left):映射到立方体的左侧面。

  3. 上面(Up):映射到立方体的顶部面。

  4. 下面(Down):映射到立方体的底部面。

  5. 前面(Front):映射到立方体的前面。

  6. 后面(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应用 适合多种场景,可以自定义每个面的图像

四、总结

球形天空盒和立方体天空盒是两种常见的实现方式,各自有其优缺点。球形天空盒适合展示全景图像,具有较为自然的效果,但对性能要求较高;而立方体天空盒则提供了更好的性能和灵活性,适用于需要多种方向图像的场景。

根据具体的项目需求,可以选择适合的天空盒方式来优化渲染效果和性能。

效果展示:

P`0AYF$QLFDBB(T3}[9T9(P

posted @ 2025-06-04 00:10  雪旭  阅读(358)  评论(0)    收藏  举报