第9章 Three.js载入模型GLTF

9.1 初始化载入模型

GLTF(GL Transmission Format)是一种专为Web和实时应用设计的高效3D模型文件格式,被称为"3D领域的JPEG"。它采用JSON结构描述场景层级、材质、动画等元数据,并将纹理、几何体等资源以二进制或独立文件形式存储,从而实现小体积、快速解析和完整功能支持。

在Three.js中,通常使用GLTFLoader加载GLTF文件,加载后的模型以场景图形式呈现,可直接融入现有三维场景并进行动画控制、交互调整等操作,成为连接专业建模工具(如Blender)与WebGL应用的关键桥梁。

我们载入一个车的模型,需要对应的文件scene.gltf可以找我获取。

Three.js使用模型依旧需要通过场景,步骤如下3步:

(1)创建场景。

(2)加载GLTF文件(模型)。

(3)将加载后的模型放入场景中。

载入的GLTF模型,可以简单的理解为是一个物品,即被观察对象。因此像相机、渲染器以及轨道控制器依旧是需要的。GLTF模型只是场景中的一部分,而非全部。以下示例是载入一辆汽车,如果需要的话,可以载入更多的模型或者与网格混合去使用。

ts 复制代码
import * as THREE from "three"
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'

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

// 2. 加载GLTF文件(模型)
const loader = new GLTFLoader();
loader.load('./car/scene.gltf', (gltf) => {
  // 3. 将加载后的模型放入场景中
  scene.add(gltf.scene)
})

//创建相机
const camera = new THREE.PerspectiveCamera(30, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 0, 20);
scene.add(camera);

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

//创建轨道控制器

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

const animate = () => {
  requestAnimationFrame(animate);
  controls.update();
  renderer.render(scene, camera);
}
animate();

GLTF模型-车模型展示如图9-1所示,可见的只有车灯部分,车模型其余位置乌漆嘛黑的,这意味着所载入的模型的材质也是受光照影响的。

图9-1 GLTF模型-车模型展示

9.2 添加灯光

受光照影响其实对于车模型来说是一件正常的事情,因为光照对GLTF车模的塑造优势非常明显,当平行光以低角度掠过车身时,钣金件上连续的高光会沿特征线精确流动;而聚光灯从侧前方投射时,不仅能在轮毂辐条间雕琢出复杂的镂空阴影,更能让前格栅的立体造型与保险杠的进气口结构产生戏剧性的深浅对比,将静态模型转化为具有视觉叙率的动态展示。

从技术实现层面,专业导出的GLTF模型通常内嵌基于物理的渲染材质,能与Three.js的光照系统深度互动。金属漆材质在环境光遮蔽下会呈现细腻的颗粒层次,车窗玻璃的菲涅尔反射会随观察角度动态变化;通过搭配HDR环境贴图,车体表面不仅能反射模拟天空盒的柔光,更能精准呈现周围虚拟环境的倒影,使烤漆表面产生深邃的镜面质感与色彩饱和度。这种光照与材质的协同作用,让模型摆脱了"玩具感",在网页中还原出接近影视级的真实材质表现与空间沉浸感。

ts 复制代码
//添加环境光
const light = new THREE.DirectionalLight(0xffffff, 100);    
light.position.set(100, 100, 100);
scene.add(light);

我们在相机创建之前添加环境光,然后加入场景中。车模型光照展示如图9-2所示。可以看见车的完整结构,随着鼠标的拖拽,可以看到不同角度下的车模型和对应反光,通过鼠标滚轮更是可以拉近或者远离视角。

图9-2 GLTF模型-车模型光照展示

当我们通过loader.load()加载GLTF模型时,可以拿到回调参数gltf,回调参数gltf是一个结构化的对象,它是我们操作整个加载模型的入口。最常用的是gltf.scene,这是整个加载模型的根场景对象,类型为 THREE.Group 或 THREE.Scene。需要将它加入主场景中才能显示。

除此之外还有gltf.scenes和gltf.animations,分别如下:

(1)gltf.scenes:多场景情况,一个包含所有场景的数组。大多数GLTF文件只有一个场景,此时 gltf.scenes[0] 等价于 gltf.scene。如图9-3的scenes为[Group]就等同于scene字段里的内容。

(2)gltf.animations:包含模型所有动画剪辑的数组。若模型有动画(如角色行走、机械运动),需配合THREE.AnimationMixer 使用。

其他的是额外信息,例如asset元信息中,包含了该模型从哪个网站下载的以及该GLTF模型的版本。cameras是内置相机,这个模型没有,所以是空数组。parser是GLTF的解析器,不需要去管,调用oader.load()方法时,方法内部会自动调用解析器去解析。userData是可以自定义的部分。回调参数gltf信息如图9-3所示。

图9-3 回调参数gltf信息

目前我们的车模型是银白色的,如果想把车染成绿的,也是可以做到的。车模型也是通过各种材质去拼接而成的,所以只要找到车模型的材质,就可以调整车外表的样式。

而网格等于几何体加材质,这意味着需要我们去找到车模型的网格,找到网格就基本上找到材质了。从回调参数gltf中去找。位置如下:scenes[0].children[0].children[0].children(直接从scene开始也可以)。回调参数gltf信息的网格参数如图9-4所示。可以看到一共有59个网格,因此车模型实际是由59个网格拼接起来的。

图9-4 回调参数gltf信息的网格参数

9.3 修改车模型颜色

找到了网格,我们就可以拿网格里面的材质去修改颜色。但网格有那么多,怎么知道要修改哪一个网格里的材质颜色?

想要精细化的去修改颜色需要对车模型是怎么拼起来的,知道每一个网格对应的位置才行。通常情况下,我们可以读取网格的名称(child.name)就能知道对应的哪一部分,但我们这个案例的车模型网格不太规范,网格的名称是Object_1~59,所以并不清楚哪一块网格对应车的哪个位置。这比较麻烦,我们如果只是单纯想给车变个色,可以直接遍历childs变量,拿到所有的网格,然后从网格中拿到material材质,直接修改颜色为0x00ff00(绿色)。

ts 复制代码
const loader = new GLTFLoader();
loader.load('./car/scene.gltf', (gltf) => {
  console.log(gltf)
  const childs = gltf.scene.children[0].children[0].children
  console.log(childs)
  for (const child of childs) {
    console.log(child.name)
    if (child instanceof THREE.Mesh) {
      child.material.color.set(0x00ff00);
    }
  }
  scene.add(gltf.scene);
});

车模型-绿色如图9-5所示。可以看到几乎所有的颜色除了车窗之外全变绿色的了。说明是可以拿到车模型的网格,而拿到网格就可以对几何体或者材质去针对性的修改,从而使车模型变成我们真正想要的效果。

图9-5 车模型-绿色

相关推荐
.又是新的一天.1 天前
【前端Web开发HTML5+CSS3+移动web视频教程】01 html- 标签之文字排版、图片、链接、音视频
前端·css3·html5
神奇的程序员1 天前
开发了一个nginx日志分析面板
前端
pas1361 天前
19-mini-vue setup $el $data $props
javascript·vue.js·ecmascript
阿拉丁的梦1 天前
【C4D实用脚本】清除废点及删除了面的选择tag和材质tag及材质--AI编程
服务器·前端·材质
傅里叶1 天前
Flutter移动端获取相机内参
前端·flutter
哒哒哒5285201 天前
React useMemo 大白话用法文档(含注意项)
前端
xkxnq1 天前
第一阶段:Vue 基础入门(第 10 天)
前端·javascript·vue.js
智商偏低1 天前
abp PermissionDefinitionManager源码解析
开发语言·前端·javascript
RaidenLiu1 天前
Offstage / Visibility:不可见真的就不消耗性能吗
前端·flutter·性能优化