当前位置:   article > 正文

ThreeJs 学习之旅(十七)—Imported models(导入模型)_import models

import models

初始代码:

  1. import './style.css'
  2. import * as THREE from 'three'
  3. import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
  4. import * as dat from 'dat.gui'
  5. import {GLTFLoader} from 'three/examples/jsm/loaders/GLTFLoader'
  6. import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader'
  7. /**
  8. * Base
  9. */
  10. // Debug
  11. const gui = new dat.GUI()
  12. const gltfLoader=new GLTFLoader()
  13. const dracoLoader=new DRACOLoader()
  14. dracoLoader.setDecoderPath('/draco/')
  15. // Canvas
  16. const canvas = document.querySelector('canvas.webgl')
  17. gltfLoader.setDRACOLoader(dracoLoader)
  18. // Scene
  19. const scene = new THREE.Scene()
  20. const floor=new THREE.Mesh(new THREE.PlaneBufferGeometry(10,10),new THREE.MeshStandardMaterial({
  21. metalness:0.4,
  22. roughness:0.5
  23. }))
  24. floor.rotation.x=-Math.PI*0.5
  25. scene.add(floor)
  26. /**
  27. * Lights
  28. */
  29. const ambientLight=new THREE.AmbientLight( 0x404040)
  30. scene.add(ambientLight)
  31. const directionalLight = new THREE.DirectionalLight(0xffffff, 0.6)
  32. directionalLight.castShadow = true
  33. directionalLight.shadow.mapSize.set(1024, 1024)
  34. directionalLight.shadow.camera.far = 15
  35. directionalLight.shadow.camera.left = - 7
  36. directionalLight.shadow.camera.top = 7
  37. directionalLight.shadow.camera.right = 7
  38. directionalLight.shadow.camera.bottom = - 7
  39. directionalLight.position.set(5, 5, 5)
  40. scene.add(directionalLight)
  41. /**
  42. * Sizes
  43. */
  44. const sizes = {
  45. width: window.innerWidth,
  46. height: window.innerHeight
  47. }
  48. window.addEventListener('resize', () =>
  49. {
  50. // Update sizes
  51. sizes.width = window.innerWidth
  52. sizes.height = window.innerHeight
  53. // Update camera
  54. camera.aspect = sizes.width / sizes.height
  55. camera.updateProjectionMatrix()
  56. // Update renderer
  57. renderer.setSize(sizes.width, sizes.height)
  58. renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
  59. })
  60. /**
  61. * Camera
  62. */
  63. // Base camera
  64. const camera = new THREE.PerspectiveCamera(75, sizes.width / sizes.height, 0.1, 100)
  65. camera.position.set(2, 2, 2)
  66. scene.add(camera)
  67. // Controls
  68. const controls = new OrbitControls(camera, canvas)
  69. controls.target.set(0, 0.75, 0)
  70. controls.enableDamping = true
  71. /**
  72. * Renderer
  73. */
  74. const renderer = new THREE.WebGLRenderer({
  75. canvas: canvas
  76. })
  77. renderer.shadowMap.enabled = true
  78. renderer.shadowMap.type = THREE.PCFSoftShadowMap
  79. renderer.setSize(sizes.width, sizes.height)
  80. renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
  81. /**
  82. * Animate
  83. */
  84. const clock = new THREE.Clock()
  85. let previousTime = 0
  86. const tick = () =>
  87. {
  88. const elapsedTime = clock.getElapsedTime()
  89. const deltaTime = elapsedTime - previousTime
  90. previousTime = elapsedTime
  91. // Update controls
  92. controls.update()
  93. // Render
  94. renderer.render(scene, camera)
  95. // Call tick again on the next frame
  96. window.requestAnimationFrame(tick)
  97. }
  98. tick()

效果

 一、GLTF加载器(GLTFLoader)

用于载入glTF 2.0资源的加载器。

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

构造函数

GLTFLoader( manager : LoadingManager )

manager — 该加载器将要使用的 loadingManager 。默认为 THREE.DefaultLoadingManager。

创建一个新的GLTFLoader。

属性

共有属性请参见其基类Loader。

方法

共有方法请参见其基类Loader。

.load ( url : String, onLoad : Function, onProgress : Function, onError : Function ) : null

url — 包含有.gltf/.glb文件路径/URL的字符串。
onLoad — 加载成功完成后将会被调用的函数。该函数接收parse所返回的已加载的JSON响应。
onProgress — (可选)加载正在进行过程中会被调用的函数。其参数将会是XMLHttpRequest实例,包含有总字节数.total与已加载的字节数.loaded。
onError — (可选)若在加载过程发生错误,将被调用的函数。该函数接收error来作为参数。

开始从url加载,并使用解析过的响应内容调用回调函数。

 

二、 引入gltf

  1. import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
  2. const gltfLoader=new GLTFLoader()
  3. const scene = new THREE.Scene()
  4. gltfLoader.load('models/Duck/glTF/Duck.gltf',(gltf)=>{
  5. console.log(gltf)
  6. })

 效果

  1. import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
  2. const gltfLoader=new GLTFLoader()
  3. const scene = new THREE.Scene()
  4. gltfLoader.load('models/Duck/glTF/Duck.gltf',(gltf)=>{
  5. scene.add(gltf.scene.children[0])
  6. })

效果

三、 引入复杂纹理

如果我们像之前的一样引入则会只出现一个眼睛

所以我们需要加载全部的children

如果我们这么写

  1. gltfLoader.load('/models/FlightHelmet/glTF/FlightHelmet.gltf', gltf => {
  2. console.log(gltf)
  3. gltf.scene.children.forEach(element => {
  4. scene.add(element)
  5. });
  6. })

 

 

 可以发现循环后的结果虽然可以看到有更多的模型元素,但一样不是完整的模型,而且更糟糕的是每当我们刷新页面,都会得到模型的不同部分。
问题出在于当我们把scene.children数组中的子元素从一个场景移到另一个场景的时候,它会自动从被移除的场景中删除掉,意味着我们循环的数组长度变小了。
当我们添加第一个对象时,它会从原来的场景中移除,然后第二个对象便会移动到替补上去。因此这里我们可以采用while循环来添加模型网格

  1. gltfLoader.load('/models/FlightHelmet/glTF/FlightHelmet.gltf', gltf => {
  2. while (gltf.scene.children.length) {
  3. scene.add(gltf.scene.children[0])
  4. }
  5. })

 当然我们有最简单粗暴的方法 加载整个场景

  1. gltfLoader.load('/models/FlightHelmet/glTF/FlightHelmet.gltf', gltf => {
  2. scene.add(gltf.scene)
  3. })

四 Draco 使用

  1. Draco版本glTF文件比默认的glTF文件体积更小
  2. 用于压缩缓冲区数据(通常是几何体)
  1. import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js'
  2. const dracoLoader=new DRACOLoader();
  3. dracoLoader.setDecoderPath('/draco/')
  4. gltfLoader.setDRACOLoader(dracoLoader)
  5. gltfLoader.load('/models/Duck/glTF-Draco/Duck.gltf', gltf => {
  6. const duck = gltf.scene.children[0]
  7. scene.add(duck)
  8. })

 

什么时候使用Draco压缩 

虽然我们可能会觉得使用Draco压缩是个双赢局面,但实际上并非如此。
确实它会让几何体更轻量,但首先要使用的时候必须加载DracoLoader类和解码器。其次,我们计算机解码一个压缩文件需要时间和资源,这可能会导致页面打开时有短暂冻结,即便我们使用了worker和WebAssembly。
因此我们必须根据实际来决定使用什么解决方案。如果一个模型具有100kb的几何体,那么则不需要Draco压缩,但是如果我们有MB大小的模型要加载,并且不关心在开始运行时有些许页面冻结,那么便可能需要用到Draco压缩。

五 动画

1.初始化狐狸模型

  1. gltfLoader.load('/models/Fox/glTF/Fox.gltf', gltf => {
  2. const fox = gltf.scene
  3. fox.scale.set(0.025, 0.025, 0.025)
  4. scene.add(fox)
  5. })

创建动画混合器

关于AnimationAction

  1. let mixer = null
  2. gltfLoader.load('/models/Fox/glTF/Fox.gltf', gltf => {
  3. // 创建混合器并传入gltf.scene
  4. mixer = new THREE.AnimationMixer(gltf.scene)
  5. // 使用clipAction()方法将索引为0的AnimationClip添加到混合器中
  6. // 这个方法会返回一个AnimationAction
  7. const action = mixer.clipAction(gltf.animations[0])
  8. // 使用play()方法调用这个AnimationAction
  9. action.play()
  10. gltf.scene.scale.set(0.025, 0.025, 0.025)
  11. scene.add(gltf.scene)
  12. })

 在tick中更新动画

  1. const tick = () =>
  2. {
  3. const elapsedTime = clock.getElapsedTime()
  4. const deltaTime = elapsedTime - previousTime
  5. previousTime = elapsedTime
  6. if(mixer) {
  7. mixer.update(deltaTime)
  8. }
  9. // Update controls
  10. controls.update()
  11. // Render
  12. renderer.render(scene, camera)
  13. // Call tick again on the next frame
  14. window.requestAnimationFrame(tick)
  15. }

效果:

 

 六 Three.js Editor

Three.js编辑器editor使用详解_zhr_superNiu的博客-CSDN博客_three.js编辑器 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/95878
推荐阅读
相关标签
  

闽ICP备14008679号