【玩转three.js】带你加载一个宵宫-天空盒与模型的下载与加载

2,226 阅读3分钟

一、引言

本文旨在帮助初学者快速掌握使用Three.js创建和配置天空盒,以及下载、加载常用3D模型的基本流程。

二、天空盒基础与实现

概念

天空盒是Three.js中一种用于模拟无限远环境的图形技术,它为3D场景创造出一种包围整个可视空间的背景效果。天空盒不仅能够提供视觉上的沉浸感,还能够影响场景中物体的光照和反射,从而增强场景的整体真实感与沉浸感。

qjt.gif

类型

介绍常见的天空盒类型,包括基于六张纹理的立方体贴图天空盒和基于单张全景图的天空盒。

  1. 六张纹理图的天空盒实现
  • 原理:由六张纹理图片组成,分别代表三维空间中六个正交方向(前后左右上下)的景象。这些图片被映射到一个包围整个场景的隐形立方体(天空盒)的六个面上,形成一个无缝衔接的360°全景背景。当相机在场景中移动时,根据相机视角计算出对应的立方体贴图采样坐标,从而呈现出与相机视向匹配的天空背景。
  • 加载方法:THREE.CubeTextureLoader
const urls = [
    import("/src/assets/img/skybox/px.png"),
    import("/src/assets/img/skybox/nx.png"),
    import("/src/assets/img/skybox/py.png"),
    import("/src/assets/img/skybox/ny.png"),
    import("/src/assets/img/skybox/pz.png"),
    import("/src/assets/img/skybox/nz.png"),
];
async function loadSkyBoxTextures() {
    const texturePromises = urls.map(url => url.then(res => res.default));
    const textures = await Promise.all(texturePromises);
    const cubeTexture = new THREE.CubeTextureLoader()
      .setPath("")
      .load(textures);
    scene.background = cubeTexture;
}
loadSkyBoxTextures();

sky.gif 2. 单张全景图的天空盒实现

  • 原理:由单张全景图片组成。
  • 加载方法:(暂不做讲解统一使用6张纹理图实现)
  • 转换方法:全景图转6张立方体纹理图方法,使用HDRI to CubeMap工具切割并保存 skyboxCut1.gif

下载

  • Poly Haven 中有各种室外室内的全景图提供下载,实际开发中我们也可以用客户提供的全景图

poly.gif

Snipaste_2024-04-25_11-21-04.png 选择合适的全景图下载后使用HDRI to CubeMap工具切割使用即可

三、3D模型下载与导入

3d模型下载

  • sketchfab:里面有许多免费与付费的3d建模提供下载

Snipaste_2024-04-25_13-42-32.png

Snipaste_2024-04-25_14-03-07.png

Snipaste_2024-04-25_14-04-30.png 选择合适的模型下载即可

常用3d模型格式

常用的3d模型有 fbx、gltf、glb、pmx。

3d模型加载

fbx模型

使用three.js内置FBXLoader加载器,解析加载返回的对象,并添加至场景

import { FBXLoader } from "three/examples/jsm/loaders/FBXLoader"; 

function loadFile(md, url) {
    return new Promise((resolve, reject) => {
      md.load(
        url,
        gltf => {
          scene.add(gltf);
          resolve(gltf);
        },
        undefined,
        function (error) {
          console.error(error);
        }
      );
    });
}
// fbx人体模型加载
let human = new FBXLoader();
let mixer = null; //声明一个混合器变量
let p1 = await loadFile(human, "/public/model/human/Walking.fbx");
// 设置模型p1的缩放比例,使其在x、y、z三个轴向均缩小为原来的0.1倍
p1.scale.set(0.1, 0.1, 0.1);
// 将p1的位置设置为三维空间原点(0, 0, 0)
p1.position.set(0, 0, 0);

human.gif

gltf模型

使用three.js内置GLTFLoader加载器

import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader"; 

function loadGLTF(md, url) {
    return new Promise((resolve, reject) => {
      md.load(
        url,
        gltf => {
          scene.add(gltf.scene);
          resolve(gltf.scene);
        },
        undefined,
        function (error) {
          console.error(error);
        }
      );
    });
  }
  // 加载海鸟战车
  let sea_bird_car = new GLTFLoader();
  let p2 = await loadGLTF(
    sea_bird_car,
    "/public/model/sea_bird_car/scene.gltf"
  );
  p2.scale.set(10, 10, 10);
  p2.position.set(20, 0, 0);

sb_car.gif

glb模型

同上使用GLTFLoader加载器

// 加载没牙仔
let meme = new GLTFLoader();
let p3 = await loadGLTF(meme,"/public/model/free_rigged_toothless_meme.glb");
p3.scale.set(10, 10, 10);
p3.position.set(-20, 0, 0);

meme.gif

pmx模型

使用three.js内置MMDLoader加载器

开始整活(烟花来咯!) 17141821092123de6eba861bb39282948eccecba16862d496.jpg

import { MMDLoader } from "three/examples/jsm/loaders/MMDLoader.js";
// 加载宵宫
let xiaogong = new MMDLoader();
let p4 = await loadFile(
xiaogong,
"/public/model/xiaogong/xiaogong.pmx"
);
p4.scale.set(1, 1, 1);
p4.position.set(0, 0, 20);

xiaogong.gif

四、结语

还有许多其他格式3d模型的加载本文并未涉及到,但是上述列举模型基本够用,其次如果你加载出来的模型和官网预览的模型相差较大可能是光照和材质因素导致,需要具体情况具体分析。

最后文章若有错误之处,还请评论区斧正,感谢! img-171418237449022679ce6ed08847b56ec37d8915abd64.jpg