⚡Three.js-在场景中导入3D动画模型

简介: ⚡Three.js-在场景中导入3D动画模型

1、格式


关于3D模型有很多格式

微信截图_20221207172412.png


2、常见的格式


  • OBJ
  • FBX
  • STL
  • COLLADA
  • 3DS
  • GLTF


3、GLTF


glTF(gl传输格式)是一种开放格式的规范 (open format specification), 用于更高效地传输、加载3D内容。该类文件以JSON(.gltf)格式或二进制(.glb)格式提供, 外部文件存储贴图(.jpg、.png)和额外的二进制数据(.bin)。一个glTF组件可传输一个或多个场景, 包括网格、材质、贴图、蒙皮、骨架、变形目标、动画、灯光以及摄像机。


  • GL Transmission Format
  • Khronos Group团队创造
  • 这几年变得特别流行
  • 支持不同的数据集,像geometries,materials,cameras,lights...
  • 支持多种导出格式像json,binary,embed textures
  • 逐渐成为标准,很多3D软件,3D引擎,3D库都支持该格式。


不应该在任何场景为了使用GLTF格式而使用GLTF格式,比如你需要粒子效果时,没必要使用GLTF。


4、哪里可以找到模型


这里贴出一个仓库,里面有许多模型可供我们学习


glTF-Sample-Models


微信截图_20221207165734.png


5、GLTF Format


一个 GLTF 文件可以包含多个格式.


  • glTF
  • glTF-Binary
  • glTF-Draco
  • glTF-Embedded


请注意,你的操作系统可能隐藏某些格式,尽量使用编辑器打开。


5.1 GLTF


├── Duck/                     # Duck模型
│   ├── glTF/                  
│   │   ├── Duck.gltf         # JSON格式的文件
│   │   └── Duck0.bin         # 二进制格式的文件
│   │   └── DuckCM.png        # 纹理  
复制代码


  • 默认格式
  • 包含多个文件
  • Duck.gltf是一个JSON格式的文件,包含了cameras, lights, scenes, materials, objects transformstions, 但是不包含geometries和textures。
  • Duck0.bin是一个二进制文件,包含geometries(vertices positions, UV coordinates, normals, colors, etc.)
  • DuckCM.png是纹理


我们加载Duck.gltf时,其他文件会自动加载。


5.2 GLTF-BINARY


├── Duck/                     # Duck模型
│   ├── glTF-Binary/                  
│   │   ├── Duck.glb        # 二进制格式的文件 
复制代码


  • 只有一个文件
  • 包含上面我们讨论的所有数据
  • 二进制格式
  • 通常更轻量
  • 因为只有一个文件所以容易加载
  • 很难改变其中的数据


5.3 GLTF-DRACO


├── Duck/                    # Duck模型
│   ├── glTF-Draco/                  
│   │   ├── 0.bin         
│   │   └── Duck.bin       
│   │   └── Duck.gltf 
│   │   └── DuckCM.png   
复制代码


  • 像gltf格式,但是其中的数据经过Draco算法压缩处理


  • 更轻量


5.4 GLTF-Embedded


├── Duck/                     # Duck模型
│   ├── glTF-Embedded/                  
│   │   ├── Duck.gltf        # 二进制格式的文件 
复制代码


  • 只有一个文件
  • JSON格式
  • 更重


6、在Three.js中加载模型


6.1 导入GLTFLoader


import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
复制代码


6.2 初始化loader


const gltfLoader = new GLTFLoader()
复制代码


6.3 使用loader


gltfLoader.load(
  "/models/Duck/glTF/Duck.gltf",
  (gltf) => {
    console.log("success");
    console.log(gltf);
  },
  () => {
    console.log("progress");
  },
  () => {
    console.log("error");
  }
);
复制代码


6.4 在场景中添加模型


模型在哪?


微信截图_20221207165815.png


  • 这里的Mesh就是我们的模型
  • 我们不需要PerspectiveCamera
  • camera和duck继承自Object3D
  • Object3D被缩放(scale)地很小


多种方法将模型添加到场景中


  • Add the whole scene in our scene
  • Add the children of the scene to our scene and ignore the PerspectiveCamera
  • Filter the children before adding to the scene
  • Add only the Mesh and end up with a duck with wrong scale , position and rotation
  • Open the file in a 3D software, clean it and export it again


const gltfLoader = new GLTFLoader();
gltfLoader.load(
  "/models/Duck/glTF/Duck.gltf",
  (gltf) => {
    console.log("success");
    scene.add(gltf.scene.children[0]);
  }
);
复制代码


导入其它格式的模型(glTF-Draco不生效)


gltfLoader.load(
  "/models/Duck/glTF-Binary/Duck.glb", // glTF-Binary
gltfLoader.load(
  "/models/Duck/glTF-Embedded/Duck.gltf", // glTF-Embedded
复制代码


添加一个稍微复杂的模型(飞行头盔)


如果以上面的方式导入模型,我们只会得到模型的一部分, 我们尝试循环它们,并将它们添加到场景中


for (const child of gltf.scene.children) {
      scene.add(child);
    }
复制代码


由于我们在循环过程中,从场景1中的一部分移动的场景2中,场景1中的模型就会减少,这样就会导致我们的循环出现问题。


  1. 尝试使用while


while (gltf.scene.children.length) {
      scene.add(gltf.scene.children[0]);
}
复制代码


  1. 使用 扩展运算符 ...
const children = [...gltf.scene.children];
    for (const child of children) {
      scene.add(child);
    }
复制代码


  1. 更简单的方式就是直接将模型中的scene添加到我们的场景中
scene.add(gltf.scene);
复制代码


6.5 Draco Compression(Draco压缩)


Draco Compression can be usualy helpful.

  • Draco 压缩这种格式会更轻量
  • Draco压缩会针对于Buffer 数据
  • 我们可以在其他格式中使用Draco压缩,并非只用GLTF格式的模型
  • 由Google开源的


如何将Draco压缩过后的模型导入到我们的场景中呢?


使用DracoLoader


import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader.js";
const dracoLoader = new DRACOLoader();
复制代码


在Web Assembly中使用会更快,Three.js 提供了相应的文件夹在 /node_modules/three/examples/js/libs文件夹下的draco文件夹 将该文件夹移动的static文件夹下


dracoLoader.setDecoderPath("/draco/");
复制代码


gltfLoader.setDRACOLoader(dracoLoader);
复制代码


这样我们也可以使用glTF-Loader文件导入模型啦,它更轻量!!


image.png


6.6 什么时候使用Draco 压缩格式


不应该什么时候都用,因为还需要加载DRACOLoader类以及Decoder。


如果模型很大,建议使用Draco格式,取决于你加载的模型大小,可以通过网站加载体验选择,做出正确的选择。


6.7 在场景中添加动画模型


gltfLoader.load("/models/Fox/glTF/Fox.gltf",
复制代码


直接导入不做处理,它会很大,我们需要缩放一下


gltfLoader.load("/models/Fox/glTF/Fox.gltf", (gltf) => {
  gltf.scene.scale.set(0.025, 0.025, 0.025);
  scene.add(gltf.scene);
  console.log("success");
});
复制代码


image.png


接下来就是处理模型的动画了


我们导入的gltf对象包含了一个animations 属性,它是AnimationClip的实例。


微信截图_20221207165840.png


我们需要创建AnimationMixer,它就像音乐播放器一样,帮助我们播放动画。


const mixer = new THREE.AnimationMixer(gltf.scene);
复制代码


使用clipAction方法将AnimationClips添加到mixer中


const action = mixer.clipAction(gltf.animations[0]);
  action.play()
复制代码


处理完了,为什么还是没有动画呢,最重要的一步还不做,那就是在每一帧中更新mixer。 这里出现了作用域的问题,需要处理一下


let mixer = null;
gltfLoader.load("/models/Fox/glTF/Fox.gltf", (gltf) => {
  mixer = new THREE.AnimationMixer(gltf.scene);
  const action = mixer.clipAction(gltf.animations[0]);
  action.play();
  gltf.scene.scale.set(0.025, 0.025, 0.025);
  scene.add(gltf.scene);
  console.log("success");
});
复制代码
const tick = () => {
  const elapsedTime = clock.getElapsedTime();
  const deltaTime = elapsedTime - previousTime;
  previousTime = elapsedTime;
  // Update mixer
  if (mixer) {
    mixer.update(deltaTime);
  }
  // Update controls
  controls.update();
  // Render
  renderer.render(scene, camera);
  // Call tick again on the next frame
  window.requestAnimationFrame(tick);
};
tick();
复制代码


image.png


看,完美,我们成功导入了动画模型!


6.8 使用Three.js editor


Three.js 提供了一个可视化在线编辑器-Three.js editor,在其中你可以调整场景,灯光,材质等,因此我们可以先在该平台调试,感觉合适了之后再编码。


image.png


最后


看,我们成功的导入了3D模型,并且它们还带有动画,还是蛮酷的勒!

Demo地址

⚾如果你对本专栏感兴趣欢迎点赞关注+收藏,后面会持续更新,更多精彩知识正在等你!😘

🏉此外笔者还有其他专栏,欢迎阅读~

相关文章
|
1月前
|
前端开发 JavaScript API
js实现promise常用场景使用示例
本文介绍JavaScript中Promise的6种常用场景:异步请求、定时器封装、并行执行、竞速操作、任务队列及与async/await结合使用,通过实用示例展示如何优雅处理异步逻辑,避免回调地狱,提升代码可读性与维护性。
214 10
|
7月前
|
编解码 JavaScript 前端开发
【Java进阶】详解JavaScript的BOM(浏览器对象模型)
总的来说,BOM提供了一种方式来与浏览器进行交互。通过BOM,你可以操作窗口、获取URL、操作历史、访问HTML文档、获取浏览器信息和屏幕信息等。虽然BOM并没有正式的标准,但大多数现代浏览器都实现了相似的功能,因此,你可以放心地在你的JavaScript代码中使用BOM。
235 23
|
6月前
|
JavaScript 数据可视化 前端开发
three.js简单实现一个3D三角函数学习理解
1.Three.js简介 Three.js是一个基于JavaScript编写的开源3D图形库,利用WebGL技术在网页上渲染3D图形。它提供了许多高级功能,如几何体、纹理、光照、阴影等,以便开发者能够快速地创建复杂且逼真的3D场景。同时,Three.js还具有很好的跨平台和跨浏览器兼容性,让用户无需安装任何插件就可以在现代浏览器上观看3D内容。
231 0
|
JavaScript 前端开发
CSS3 动画和 JavaScript 动画的性能比较
具体的性能表现还会受到许多因素的影响,如动画的复杂程度、浏览器的性能、设备的硬件条件等。在实际应用中,需要根据具体情况选择合适的动画技术。
|
JavaScript 前端开发
如何使用时间切片来优化JavaScript动画的性能?
如何使用时间切片来优化JavaScript动画的性能?
|
8月前
|
缓存 自然语言处理 JavaScript
JavaScript中闭包详解+举例,闭包的各种实践场景:高级技巧与实用指南
闭包是JavaScript中不可或缺的部分,它不仅可以增强代码的可维护性,还能在模块化、回调处理等场景中发挥巨大作用。然而,闭包的强大也意味着需要谨慎使用,避免潜在的性能问题和内存泄漏。通过对闭包原理的深入理解以及在实际项目中的灵活应用,你将能够更加高效地编写出简洁且功能强大的代码。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
8月前
|
JavaScript 前端开发 Java
详解js柯里化原理及用法,探究柯里化在Redux Selector 的场景模拟、构建复杂的数据流管道、优化深度嵌套函数中的精妙应用
柯里化是一种强大的函数式编程技术,它通过将函数分解为单参数形式,实现了灵活性与可复用性的统一。无论是参数复用、延迟执行,还是函数组合,柯里化都为现代编程提供了极大的便利。 从 Redux 的选择器优化到复杂的数据流处理,再到深度嵌套的函数优化,柯里化在实际开发中展现出了非凡的价值。如果你希望编写更简洁、更优雅的代码,柯里化无疑是一个值得深入学习和实践的工具。从简单的实现到复杂的应用,希望这篇博客能为你揭开柯里化的奥秘,助力你的开发之旅! 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一
|
10月前
|
存储 NoSQL JavaScript
Node.js导入MongoDB具体操作指南
通过本文,您已经学会了如何在Node.js中导入MongoDB并执行基本的CRUD操作。Node.js与MongoDB的结合使得构建高效、可扩展的后端服务变得更加容易。通过遵循本文的步骤,您可以快速设置并运行一个强大的数据存储和处理系统。希望这篇指南能为您的开发工作提供实用的帮助。
279 13
|
前端开发 API 开发者
Next.js 实战 (五):添加路由 Transition 过渡效果和 Loading 动画
这篇文章介绍了Framer Motion,一个为React设计的动画库,提供了声明式API处理动画和页面转换,适合创建响应式用户界面。文章包括首屏加载动画、路由加载Loading、路由进场和退场动画等主题,并提供了使用Framer Motion和next.js实现这些动画的示例代码。最后,文章总结了这些效果,并邀请读者探讨更好的实现方案。
328 0
Next.js 实战 (五):添加路由 Transition 过渡效果和 Loading 动画
|
11月前
纸屑飘落生日蛋糕场景js+css3动画特效
纸屑飘落生日蛋糕CSS3动画特效是一款js+css3制作的全屏纸屑飘落,生日蛋糕点亮庆祝动画特效。
148 3

热门文章

最新文章