背景
原创内容
搞懂 Three.js 环境贴图
Threejs
前端开发
2025-05-29
14分钟
118
头像
Dean
Threejs

在使用 Three.js 创建逼真的 3D 场景时,环境贴图(Environment Map)背景(Background) 是必不可少的两个关键因素。它们可以显著增强渲染效果,特别是在光照、反射和折射方面。

本文将带你系统了解 Three.js 中关于环境贴图与背景的使用方案、类型,并通过 TypeScript 示例一文掌握核心技能。

一、什么是环境贴图?

环境贴图(Environment Map)是一个用来模拟物体反射周围环境的贴图,通常配合 MeshStandardMaterialMeshPhysicalMaterial 来使用。它不仅可以作为反射来源,也能影响材质的高光与镜面反射。

二、背景 vs 环境贴图

在 Three.js 中,scene.backgroundscene.environment 分别控制:

  • scene.background: 设置场景的背景图像或颜色;
  • scene.environment: 设置用于物体反射的环境贴图,影响材质的物理光照效果。

这两个可以相同也可以不同。

三、环境贴图类型

Three.js 支持以下几种主要类型的环境贴图:

1. CubeTexture(立方体贴图)

由六张面图组成的立方体贴图(通常用于天空盒和反射):

ts 复制代码
const loader = new THREE.CubeTextureLoader();
const cubeTexture = loader.load([
  'px.jpg', 'nx.jpg',
  'py.jpg', 'ny.jpg',
  'pz.jpg', 'nz.jpg'
]);
scene.environment = cubeTexture;
scene.background = cubeTexture;

2. HDR Environment Map(高动态范围贴图)

通过 RGBELoader 加载 .hdr 文件,效果更逼真,适用于 PBR 材质:

ts 复制代码
import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader';

const rgbeLoader = new RGBELoader();
rgbeLoader.load('/env.hdr', (hdrTexture) => {
  hdrTexture.mapping = THREE.EquirectangularReflectionMapping;
  scene.environment = hdrTexture;
  scene.background = hdrTexture;
});

注意:HDR 贴图需要开启 PMREM(预过滤的环境贴图)以获得更真实的反射效果,详见下节。

3. Equirectangular Texture(等距矩形贴图)

常见于 PNG 或 JPEG 格式的全景图:

ts 复制代码
const textureLoader = new THREE.TextureLoader();
textureLoader.load('/env.jpg', (texture) => {
  texture.mapping = THREE.EquirectangularReflectionMapping;
  scene.environment = texture;
  scene.background = texture;
});

四、PMREM 处理(预过滤环境贴图)

Three.js 推荐使用 PMREMGenerator 来处理环境贴图以提升 PBR 材质效果:

ts 复制代码
const pmremGenerator = new THREE.PMREMGenerator(renderer);
pmremGenerator.compileEquirectangularShader();

const rgbeLoader = new RGBELoader();
rgbeLoader.load('/env.hdr', (hdrTexture) => {
  const envMap = pmremGenerator.fromEquirectangular(hdrTexture).texture;
  scene.environment = envMap;
  scene.background = envMap;

  hdrTexture.dispose();
  pmremGenerator.dispose();
});

五、TypeScript 示例

以下是一个完整的 Three.js TypeScript 环境贴图示例:

ts 复制代码
// src/main.ts
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader';

const canvas = document.getElementById('webgl') as HTMLCanvasElement;
const renderer = new THREE.WebGLRenderer({ canvas });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.outputColorSpace = THREE.SRGBColorSpace;

const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 100);
camera.position.set(0, 1, 3);

const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;

// 加载 HDR 贴图作为背景与环境贴图
const pmremGenerator = new THREE.PMREMGenerator(renderer);
new RGBELoader().load('/env.hdr', (hdrTexture) => {
  const envMap = pmremGenerator.fromEquirectangular(hdrTexture).texture;
  scene.environment = envMap;
  scene.background = envMap;
  hdrTexture.dispose();
  pmremGenerator.dispose();
});

// 添加一个反光球体
const material = new THREE.MeshStandardMaterial({ metalness: 1, roughness: 0 });
const geometry = new THREE.SphereGeometry(1, 64, 64);
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);

// 添加光照(可选)
const light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(5, 10, 7.5);
scene.add(light);

function animate() {
  requestAnimationFrame(animate);
  controls.update();
  renderer.render(scene, camera);
}
animate();

确保 /env.hdr 是一张 Equirectangular 格式的 HDR 图片。

六、小贴士

  • scene.environment 主要影响 MeshStandardMaterialMeshPhysicalMaterial
  • 如果只想设置背景图像而不影响材质反射,设置 scene.background 而不设置 scene.environment
  • 推荐使用 HDR 格式贴图搭配 PMREMGenerator 获取最佳渲染质量;
  • 可以使用工具如 Poly Haven 获取免费 HDR 贴图。

七、总结

类型 用途 优点 适用
CubeTexture 天空盒、基本反射 加载简单 游戏、低端设备
Equirectangular 简单 PBR 场景 使用广泛 全景背景
HDR + PMREM 高质量 PBR 材质反射 效果逼真 写实渲染