babylonjs天空盒

更新时间: 2025-08-19 14:14:23

项目中写到了白天黑夜变换,其实原理就是将天空盒换了一下,然后把路灯的自发光强度调高,利用GlowLayer实现路灯的光晕,先来看下效果:

# 实现

  1. 天空纹理对象:储存日夜贴图
const skyTexture = {
  day:null,
  night:null
}
1
2
3
4
  1. 创建天空盒并加载HDR纹理
function createSky() {
  // 自动创建天空盒和环境光照
  skyTexture.day = new HDRCubeTexture(
      "/models/sky/qwantani_afternoon_puresky_2k.hdr", // HDR 文件路径(需放在 public 目录)
      scene,
      1024, // 贴图尺寸(512/1024/2048)
      false, // 不生成多级渐远纹理(设为 true 可优化性能)
      true, // 启用伽马校正(使颜色更自然)
      false // 不反转 Y 轴
  );

  skyTexture.night = new HDRCubeTexture(
      "/models/sky/kloppenheim2_4k.hdr", // HDR 文件路径(需放在 public 目录)
      scene,
      1024, // 贴图尺寸(512/1024/2048)
      false, // 不生成多级渐远纹理(设为 true 可优化性能)
      true, // 启用伽马校正
      false // 不反转 Y 轴
  );

// 设置曝光度(影响整体亮度)
  skyTexture.day.exposure = 1.1;
  skyTexture.night.exposure = 0.5;

  // 创建天空盒(巨大的立方体)
  skybox = Mesh.CreateBox("skyBox", 8000.0, scene);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

什么是HDR天空盒?

HDR (High Dynamic Range):高动态范围图像,能够显示比普通图像更广泛的亮度范围,更接近人眼对真实世界的感知。在3D场景中,HDR天空盒可以创建出逼真的天空、光照和反射效果。

  • 天空盒原理:
    创建一个非常大的立方体(代码中尺寸为8000)
    将相机放置在立方体中心
    立方体的内表面贴上全景天空纹理
    由于立方体足够大,观察者会感觉被天空包围
  • HDRCubeTexture API详解
    HDRCubeTexture是Babylon.js中专门用于加载HDR立方体贴图的类,构造函数参数如下:
参数 作用 示例值
url HDR文件路径 "/models/sky/afternoon.hdr"
scene 当前场景对象 scene
size 纹理尺寸(分辨率) 1024(常用值:512/1024/2048)
noMipmap 是否禁用多级渐远纹理 false(天空盒通常不需要)
gammaSpace 是否启用伽马校正 true(使颜色更自然)
invertY 是否反转Y轴 false(根据纹理导出设置)

注意

HDR文件需要放在项目的public目录下,确保路径正确,否则会出现404错误。

  1. 日夜切换
function switchDayNight(isDay) {
  // 切换天空盒纹理
  skyboxMaterial = new StandardMaterial("skyBox", scene); 
  // 关键设置:禁用背面剔除  
  skyboxMaterial.backFaceCulling = false;  
  // 设置反射纹理:根据日夜状态选择不同纹理  
  skyboxMaterial.reflectionTexture =  isDay ? skyTexture.day : skyTexture.night;  
  // 设置纹理坐标模式为天空盒模式  
  skyboxMaterial.reflectionTexture.coordinatesMode = Texture.SKYBOX_MODE;
  // 禁用材质自身颜色(使用反射纹理作为唯一颜色来源)
  skyboxMaterial.diffuseColor = new Color3(0, 0, 0);
  skyboxMaterial.specularColor = new Color3(0, 0, 0);
  // 天空盒不受场景灯光影响
  skyboxMaterial.disableLighting = true;
  // 应用材质到天空盒
  skybox.material = skyboxMaterial;
  // 切换光源颜色
  if (isDay) {
    // 白天光源:白色,高强度
    light.diffuseColor = new Color3(1, 1, 1);
    light.groundColor = new Color3(0, 0, 0);
    light.intensity = 1;
    toggleRoadLight(false)
  } else {
    // 夜晚光源:蓝调,低强度
    light.diffuseColor = new Color3(0.1, 0.15, 0.3); // 夜晚蓝色调
    light.groundColor = new Color3(0.05, 0.05, 0.1);
    light.intensity = 0.3;
    toggleRoadLight(true)
  }
}

// 道路灯光控制  
function toggleRoadLight(isOpen) {

  const material = roadLight.material;

  if (isOpen) {
    // 打开道路灯:设置白色自发光
    material.emissiveColor = new Color3(1, 1, 1);
    material.emissiveIntensity = 5;
  } else {
    // 关闭道路灯:关闭自发光
      material.emissiveColor = new Color3(0, 0, 0);
      material.emissiveIntensity = 0;
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47