当前位置: 首页 > news >正文

Three.js 快速入门教程【十一】天空盒的多种实现方式

请添加图片描述

系列文章目录

Three.js 快速入门教程【一】开启你的 3D Web 开发之旅
Three.js 快速入门教程【二】透视投影相机
Three.js 快速入门教程【三】渲染器
Three.js 快速入门教程【四】三维坐标系
Three.js 快速入门教程【五】动画渲染循环
Three.js 快速入门教程【六】相机控件 OrbitControls
Three.js 快速入门教程【七】常见几何体类型
Three.js 快速入门教程【八】常见材质类型
Three.js 快速入门教程【九】光源类型
Three.js 快速入门教程【十】常见的纹理类型
Three.js 快速入门教程【十一】天空盒的多种实现方式
Three.js 快速入门教程【十二】外部模型加载(一)


文章目录

  • 系列文章目录
  • 一、前言
  • 二、认识天空盒
  • 二、实现方案对比
    • 2.1 立方体贴图法
    • 2.2 等距圆柱投影法
    • 2.3对比总结
  • 三、具体实现
    • 3.1立方体贴图法
    • 3.2 等距圆柱投影法
    • 3.2.1 jpg或png格式图片
    • 3.2.2 hdr格式图片
    • 3.2.3 exr格式图片
  • 四、免费全景图片资源下载
  • 五、总结


一、前言

      在使用 Three.js 构建 3D 场景时,天空盒是一个非常重要的元素。它可以为场景提供一个广阔的背景,增强场景的真实感和沉浸感。本文将介绍多种方法实现天空盒。


二、认识天空盒

       天空盒(Skybox) 是3D图形学中用于模拟环境背景的核心技术,本质是一个包裹整个场景的立方体或球体。通过在其表面映射环境贴图,创造出无限延伸的空间视觉假象。它能有效提升场景真实感,常用于:

  • 营造自然氛围(天空、宇宙、建筑内部)
  • 提供环境反射源
  • 创建沉浸式体验
  • 优化性能(替代复杂几何体)

天空盒示例


二、实现方案对比

      天空盒子实现方案细分可以通过多种形式实现,大体可以归类为2种分别为 立方体贴图法(准备6张图片)、等距圆柱投影(准备一张全景图片)。

2.1 立方体贴图法

立方体贴图法是通过创建一个尺寸很大的立方体,分别在立方体内部6个面贴上6张不同的纹理图片,把所有元素包括相机、网格对象、灯光放在立方体内部,使得立方体包围着场景中的所有物体。因此需要准备6张纹理图片。

2.2 等距圆柱投影法

等距圆柱投影(Equirectangular Projection) 是一种将球面全景图展开为2D平面图像的标准方法,需要准备一张全景图

2.3对比总结

方法对比性能表现适用场景
立方体贴图(六面)6张宽高一样的图片静态高清环境
等距圆柱投影1张全景图动态天空、全景图

三、具体实现

3.1立方体贴图法

需要注意的是图片的宽高必须一样也就是正方形图片,不然加载会报错

方法一:
创建一个虚拟大立方体放置场景

import * as THREE from "three";
//引入相机控制器
import { OrbitControls } from "three/addons/controls/OrbitControls.js";

// 创建场景
const scene = new THREE.Scene();

// 创建相机
const camera = new THREE.PerspectiveCamera(
  75,
  window.innerWidth / window.innerHeight,
  0.1,
  3000
);
camera.position.z = 5;

//添加平行光
const light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(-1, 2, 4);
scene.add(light)

// 创建渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

// 创建纹理加载器
const cubeTextureLoader = new THREE.CubeTextureLoader();
//设置图片目录路径,换成真实路径
cubeTextureLoader.setPath("textures/");
/// 定义天空盒纹理的路径
const skyboxTexturePaths = [
        'px.jpg', // 右面
        'nx.jpg', // 左 面
        'py.jpg', // 上 面
        'ny.jpg', // 下 面
        'pz.jpg', // 前 面
        'nz.jpg'  // 后 面
      ];
//加载纹理
const skyboxTexture = cubeTextureLoader.load(skyboxTexturePaths);
// 设置纹理的映射方式
skyboxTexture.mapping = THREE.CubeReflectionMapping;

// 创建大立方体
const geometry = new THREE.BoxGeometry(2000, 2000, 2000);
//创建材质
const material = new THREE.MeshBasicMaterial({
  envMap: skyboxTexture, //环境贴图
  side: THREE.BackSide, //渲染立方体内部
});

const cube = new THREE.Mesh(geometry, material);
scene.add(cube);

  // 创建一个球体几何体
    const geometry2 = new THREE.SphereGeometry(1, 32, 32);
    // 创建一个标准材质
    const material2 = new THREE.MeshStandardMaterial({
        metalness: 1,//金属性
        roughness: 0.05, //粗糙度
        envMap:cubeTexture//环境贴图
    });
    // 创建球体网格
    const sphere = new THREE.Mesh(geometry2, material2);
    scene.add(sphere);

// 创建 OrbitControls 控件
const controls = new OrbitControls(camera, renderer.domElement);
// 渲染循环
function animate() {
  requestAnimationFrame(animate);
  controls.update();
  renderer.render(scene, camera);
}

animate();

运行效果:

天空盒示例2

方法二:
设置虚拟场景背景为立方体纹理,虚拟场景可以近视看成一个无限大的立方体,它的background支持设置为纹理。

import * as THREE from "three";
//引入相机控制器
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
// 创建场景
const scene = new THREE.Scene();
// 创建相机
const camera = new THREE.PerspectiveCamera(
  75,
  window.innerWidth / window.innerHeight,
  0.1,
  3000
);
camera.position.z = 5;

//添加平行光
const light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(-1, 2, 4);
scene.add(light);

// 创建渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

// 创建纹理加载器
const cubeTextureLoader = new THREE.CubeTextureLoader();
//设置图片目录路径,换成真实路径
cubeTextureLoader.setPath("textures/");
/// 定义天空盒纹理的路径
const skyboxTexturePaths = [
  "px.jpg", // 右面
  "nx.jpg", // 左 面
  "py.jpg", // 上 面
  "ny.jpg", // 下 面
  "pz.jpg", // 前 面
  "nz.jpg", // 后 面
];

//加载纹理
const skyboxTexture = cubeTextureLoader.load(skyboxTexturePaths);
// 设置纹理的映射方式
skyboxTexture.mapping = THREE.CubeReflectionMapping;

//设置场景的背景为立方体纹理
scene.background = skyboxTexture;

// 创建一个小立方体
const geometry = new THREE.BoxGeometry(1, 1, 1);
// 创建一个材质
const material = new THREE.MeshPhongMaterial({
  color: 0x44aa88,
});
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);

// 创建 OrbitControls 控件
const controls = new OrbitControls(camera, renderer.domElement);
// 渲染循环
function animate() {
  cube.rotation.x += 0.01;
  cube.rotation.y += 0.01;
  requestAnimationFrame(animate);
  controls.update();
  renderer.render(scene, camera);
}

animate();

通过上述示例,可以看出方法二实现简单很多,无须在创建一个模拟环境的立方体,直接设置场景背景即可实现天空盒效果,如果采用立方体贴图法推荐优先使用方法二。


3.2 等距圆柱投影法

需要准备一张360度全景图片

3.2.1 jpg或png格式图片

import * as THREE from "three";
//引入相机控制器
import { OrbitControls } from "three/addons/controls/OrbitControls.js";

// 创建场景
const scene = new THREE.Scene();

// 创建相机
const camera = new THREE.PerspectiveCamera(
  75,
  window.innerWidth / window.innerHeight,
  0.1,
  3000
);
camera.position.z = 5;

//添加平行光
const light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(-1, 2, 4);
scene.add(light);

// 创建渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

// 创建纹理加载器
const loader = new THREE.TextureLoader();
// 加载全景图片文件
const texture = loader.load(
  "demo.jpg",
  () => {
    // 将纹理转换为适合环境映射的格式
    texture.mapping = THREE.EquirectangularReflectionMapping;
    //设置sRGB 颜色空间
    texture.colorSpace = THREE.SRGBColorSpace;
    // 将纹理设置为场景的背景
    scene.background = texture;
  }
);

// 创建一个小立方体
const geometry = new THREE.BoxGeometry(1, 1, 1);
// 创建一个材质
const material = new THREE.MeshPhongMaterial({
  color: 0x44aa88,
});
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);

// 创建 OrbitControls 控件
const controls = new OrbitControls(camera, renderer.domElement);
// 渲染循环
function animate() {
  cube.rotation.x += 0.01;
  cube.rotation.y += 0.01;
  requestAnimationFrame(animate);
  controls.update();
  renderer.render(scene, camera);
}

animate();

在这里插入图片描述

3.2.2 hdr格式图片

HDR 是一种图像技术,它能够记录和显示比传统标准动态范围(SDR)图像更广泛的亮度值范围。HDR 格式全景图片结合了 HDR 技术和全景图像的特点,不仅具有广阔的视角,还能呈现出更丰富的亮度层次和细节,常用于虚拟现实(VR)、建筑可视化、虚拟旅游等领域,以提供更加真实和沉浸式的视觉体验。常见的 HDR 全景图片格式有.hdr、.exr等。

通过RGBELoader 加载器加载图片

import * as THREE from "three";
//引入相机控制器
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader.js';

// 创建场景
const scene = new THREE.Scene();

// 创建相机
const camera = new THREE.PerspectiveCamera(
  75,
  window.innerWidth / window.innerHeight,
  0.1,
  3000
);
camera.position.z = 5;

//添加平行光
const light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(-1, 2, 4);
scene.add(light);

// 创建渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

// 创建RGBELoader实例
const rgbeLoader =new RGBELoader();
// 加载hdr格式图片文件
rgbeLoader.load('demo_4k.hdr', (texture)=> {
    // 将HDR纹理转换为适合环境映射的格式
    texture.mapping = THREE.EquirectangularReflectionMapping;
    // 设置场景的背景为HDR纹理
    scene.background = texture;
});

// 创建一个小立方体
const geometry = new THREE.BoxGeometry(1, 1, 1);
// 创建一个材质
const material = new THREE.MeshPhongMaterial({
  color: 0x44aa88,
});
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);

// 创建 OrbitControls 控件
const controls = new OrbitControls(camera, renderer.domElement);
// 渲染循环
function animate() {
  cube.rotation.x += 0.01;
  cube.rotation.y += 0.01;
  requestAnimationFrame(animate);
  controls.update();
  renderer.render(scene, camera);
}

animate();

在这里插入图片描述

3.2.3 exr格式图片

通过EXRLoader加载器加载图片

import * as THREE from "three";
//引入相机控制器
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
import { EXRLoader } from 'three/examples/jsm/loaders/EXRLoader.js';

// 创建场景
const scene = new THREE.Scene();

// 创建相机
const camera = new THREE.PerspectiveCamera(
  75,
  window.innerWidth / window.innerHeight,
  0.1,
  3000
);
camera.position.z = 5;

//添加平行光
const light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(-1, 2, 4);
scene.add(light);

// 创建渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

// 创建RGBELoader实例
const exrLoader =new EXRLoader();
// 加载EXR文件
exrLoader.load('demo.exr', (texture)=> {
    // 将EXR纹理转换为适合环境映射的格式
    texture.mapping = THREE.EquirectangularReflectionMapping;
    // 设置场景的背景为纹理
    scene.background = texture;
});

// 创建一个小立方体
const geometry = new THREE.BoxGeometry(1, 1, 1);
// 创建一个材质
const material = new THREE.MeshPhongMaterial({
  color: 0x44aa88,
});
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);

// 创建 OrbitControls 控件
const controls = new OrbitControls(camera, renderer.domElement);
// 渲染循环
function animate() {
  cube.rotation.x += 0.01;
  cube.rotation.y += 0.01;
  requestAnimationFrame(animate);
  controls.update();
  renderer.render(scene, camera);
}

animate();

在这里插入图片描述


四、免费全景图片资源下载

免费的全景图片资源可以访问Poly Haven网站,该网站不仅有免费纹理资源还有3d模型和全景图片提供下载调试


五、总结

       通过以上介绍,我们学会了使用多种方式在 Three.js 中创建一个天空盒。天空盒为 3D 场景增添了真实感和氛围感。在实际应用中,可以根据场景的主题和风格选择合适的纹理图片,进一步优化天空盒的效果。

更多three.js入门知识点请关注该系列教程后续的更新。

相关文章:

  • C#学生管理系统 进阶(通过接口,继承接口的类,实现接口约束_对List中存储的数据进行排列)
  • 什么是requestIdleCallback?
  • Hue Docker镜像构建异常:gnutls_handshake() failed
  • 第15届 蓝桥杯 C++编程青少组中/高级选拔赛 202403 真题答案及解析
  • Win32 C++ 电源计划操作
  • 第三百七十二节 JavaFX教程 - JavaFX HTMLEditor
  • spring事件
  • 【推荐项目】023-游泳俱乐部管理系统
  • 优博讯,蓝禾,三七互娱,顺丰,oppo,游卡,汤臣倍健,康冠科技,作业帮,高途教育25届春招内推
  • 基于 Python 深度学习的电影评论情感分析可视化系统(2.0 全新升级)
  • 算法日常刷题笔记(3)
  • 【Java项目】基于SpringBoot的藏区特产销售平台
  • 目标检测算法——YOLOV11——算法详解
  • 【考试大纲】中级网络工程师考试大纲(最新版与旧版对比)
  • 斐波那契数列的可视化
  • Linux tar命令
  • DOM HTML:深入理解与高效运用
  • 基于Spring Boot + Vue的常规应急物资管理系统设计与实现
  • C++ 循环结构练习题目集
  • 计算机面试项目经历描述技巧
  • 乌克兰官员与法德英美四国官员举行会谈
  • 上海“城市文明开放麦”全城总动员,樊振东担任首位上海城市文明大使
  • 陕西旱情实探:大型灌区农业供水有保障,大旱之年无旱象
  • 七部门:进一步增强资本市场对于科技创新企业的支持力度
  • 【社论】个人破产探索,要守住“诚实而不幸”的底线
  • 山东省市监局“你点我检”专项抽检:一批次“无抗”鸡蛋农兽药残留超标