ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

如何用 three.js 的 GLTFLoader 加载 .glb/.gltf 模型并渲染?

如何用 three.js 的 GLTFLoader 加载 .glb/.gltf 模型并渲染? 如何用 three.js 的 GLTFLoader 加载 .glb/.gltf 模型并渲染【免费下载链接】three.jsJavaScript 3D Library.项目地址: https://gitcode.com/GitHub_Trending/th/three.js任务是在网页应用里把 glTF 2.0 格式的模型.glb或.gltf加载进 three.js 场景并渲染出来。three.js 官方手册明确推荐 glTF 作为运行时模型格式.GLB和.GLTF两种版本都得到了良好的支持见 Loading 3D Models。本文按「搭好本地环境 → 导入加载器 → 加载并渲染 → 验证结果」的路径展开代码来自官方 API 文档与 manual 教程。准备条件项目结构与本地服务器three.js 项目至少需要一个 HTML 文件和一个 JavaScript 文件纹理、音频和 3D 模型通常放在public/或叫 static目录下这些文件会原样推送到网站见 Installation 手册。官方手册给出两种搭建方式任选其一即可方式一npm Vite手册推荐的默认方式安装 Node.js然后在项目目录执行npm install --save three npm install --save-dev vite运行本地开发服务器npx vite终端出现类似http://localhost:5173的地址在浏览器打开它。此时页面是空白的说明环境就绪。方式二CDN import map可选分支不装构建工具时需要在index.html的head中加入 import mapversion需替换为真实版本号手册示例用的是v0.149.0最新版本号以 npm 列表为准script typeimportmap { imports: { three: https://cdn.jsdelivr.net/npm/threeversion/build/three.module.js, three/addons/: https://cdn.jsdelivr.net/npm/threeversion/examples/jsm/ } } /script然后装 Node.js 并运行npx serve .启动本地服务器打开终端给出的http://localhost:3000。两种方式都有一个硬性前提不能直接双击 HTML 文件打开。手册说明出于安全原因直接以本地文件方式打开页面时后面要用到的功能无法正常工作很多加载 3D 模型时的常见错误都是因为没有正确托管文件。另外如果用 CDN所有依赖必须来自同一版本的 three.js 和同一个 CDN混用不同来源可能导致代码重复加载甚至应用损坏。导入 GLTFLoaderthree.js 默认只内置了少数几个加载器如ObjectLoader其余组件——包括GLTFLoader——属于 addons不需要单独安装但必须显式导入见 GLTFLoader API 文档import * as THREE from three; import { GLTFLoader } from three/addons/loaders/GLTFLoader.js;在 Vite 项目中three/addons/由构建工具解析在 CDN 方式中它由上面的 import map 映射到examples/jsm/目录。加载模型并加入场景GLTFLoader的.load( url, onLoad, onProgress, onError )从给定 URL 开始加载完成后把结果传给onLoad回调。官方 Loading 3D Models 给出的基本用法const loader new GLTFLoader(); loader.load( path/to/model.glb, function ( gltf ) { scene.add( gltf.scene ); }, undefined, function ( error ) { console.error( error ); } );其中path/to/model.glb是文档中的占位路径必须替换成你的模型的实际路径或 URL——url参数也支持 data URI。想拿现成模型做验证时仓库里的 duck.glb 可以直接复制到你的public/目录作为测试模型。onLoad收到的gltf对象API 文档中的LoadObject包含这些字段gltf.sceneGroup类型默认场景加入场景的就是它gltf.scenesGroup数组glTF 资产可能定义多个场景gltf.animationsAnimationClip数组模型里的动画剪辑gltf.asset资产元数据gltf.userData附加数据。加载完成后还需要渲染循环。下面是与手册示例 load-gltf 一致的最小可运行结构main.jsimport * as THREE from three; import { OrbitControls } from three/addons/controls/OrbitControls.js; import { GLTFLoader } from three/addons/loaders/GLTFLoader.js; const renderer new THREE.WebGLRenderer( { antialias: true } ); document.body.appendChild( renderer.domElement ); const camera new THREE.PerspectiveCamera( 45, 2, 0.1, 100 ); camera.position.set( 0, 10, 20 ); const controls new OrbitControls( camera, renderer.domElement ); controls.target.set( 0, 5, 0 ); controls.update(); const scene new THREE.Scene(); scene.background new THREE.Color( black ); // 场景需要光源否则模型可能不可见 const hemiLight new THREE.HemisphereLight( 0xB1E1FF, 0xB97A20, 2 ); scene.add( hemiLight ); const dirLight new THREE.DirectionalLight( 0xFFFFFF, 2.5 ); dirLight.position.set( 5, 10, 2 ); scene.add( dirLight ); scene.add( dirLight.target ); // 模型 URL替换成你的实际路径例如放在 public/ 下的 duck.glb const MODEL_URL path/to/model.glb; { const gltfLoader new GLTFLoader(); gltfLoader.load( MODEL_URL, ( gltf ) { const root gltf.scene; scene.add( root ); // 计算包围盒并自动把相机框住模型见下文「验证结果」 const box new THREE.Box3().setFromObject( root ); const boxSize box.getSize( new THREE.Vector3() ).length(); const boxCenter box.getCenter( new THREE.Vector3() ); frameArea( boxSize * 0.5, boxSize, boxCenter, camera ); controls.maxDistance boxSize * 10; controls.target.copy( boxCenter ); controls.update(); }, undefined, ( error ) { console.error( error ); } ); } function frameArea( sizeToFitOnScreen, boxSize, boxCenter, camera ) { const halfSizeToFitOnScreen sizeToFitOnScreen * 0.5; const halfFovY THREE.MathUtils.degToRad( camera.fov * .5 ); const distance halfSizeToFitOnScreen / Math.tan( halfFovY ); const direction ( new THREE.Vector3() ) .subVectors( camera.position, boxCenter ) .multiply( new THREE.Vector3( 1, 0, 1 ) ) .normalize(); camera.position.copy( direction.multiplyScalar( distance ).add( boxCenter ) ); camera.near boxSize / 100; camera.far boxSize * 100; camera.updateProjectionMatrix(); camera.lookAt( boxCenter.x, boxCenter.y, boxCenter.z ); } function resizeRendererToDisplaySize( renderer ) { const canvas renderer.domElement; const width canvas.clientWidth; const height canvas.clientHeight; const needResize canvas.width ! width || canvas.height ! height; if ( needResize ) { renderer.setSize( width, height, false ); } return needResize; } function render() { if ( resizeRendererToDisplaySize( renderer ) ) { camera.aspect renderer.domElement.clientWidth / renderer.domElement.clientHeight; camera.updateProjectionMatrix(); } renderer.render( scene, camera ); requestAnimationFrame( render ); } requestAnimationFrame( render );这段代码里相机自动取景frameArea与包围盒计算和渲染循环都取自 manual 的 GLTF 示例页面。它的作用是在模型加载后根据包围盒调整相机距离与 near/far避免模型太小或相机位于模型内部而看不到内容——这正是官方排查清单里提到的一个常见现象。OrbitControls也是 addon导入方式与GLTFLoader相同。验证结果浏览器里能看到模型打开 Vite或 serve给出的本地地址模型连同纹理一起渲染出来。manual 教程 Loading a .GLTF File 演示的就是这条流程——替换掉 OBJ 加载代码、导入GLTFLoader、scene.add( gltf.scene )后textures and all 直接出画面。检查加载出的场景结构manual 教程在onLoad回调里调用打印函数输出场景图scenegraph确认节点是否按预期组织例如定位某个命名节点gltfLoader.load( MODEL_URL, ( gltf ) { const root gltf.scene; scene.add( root ); console.log( dumpObject( root ).join( \n ) ); } );dumpObject是 manual 教程给出的完整工具函数递归打印每个节点的名称、类型与层级形如RootNode [Object3D]/SomeMesh [Mesh]可原样取自 manual/pages/load-gltf.html。拿到场景图后就可以用root.getObjectByName( 节点名 )找出后续要操作的子对象教程用它找到了名为Cars的节点。模型不显示、变形或颜色不对时怎么排查官方 Loading 3D Models 给出了五条排查步骤按顺序执行查控制台报错检查 JavaScript 控制台并确保调用.load()时传了onError回调来记录错误上文代码已包含。在别的应用里打开模型先用其他支持 glTF 的查看器打开模型。如果模型在别的软件里显示正常向 three.js 提交 bug如果在任何软件里都显示不出来向制作模型的工具提交 bug。把模型放大或缩小 1000 倍试试很多模型的缩放各不相同相机位于大模型内部时模型不会显示。添加并摆放一个光源模型可能只是藏在黑暗里。在网络面板里找失败的纹理请求比如出现C:\Path\To\Model\texture.jpg这种绝对路径。应改用相对于模型的路径如images/texture.jpg——这可能需要用文本编辑器修改模型文件。.gltf本质是 JSON 文件可以直接打开查看内容模型引用了绝对路径纹理时纹理请求就会失败。可选分支加载 Draco 压缩的模型如果模型用KHR_draco_mesh_compression扩展压缩过网格数据必须给GLTFLoader设置DRACOLoadersetDRACOLoader方法即为此用途。GLTFLoader API 文档 的示例const loader new GLTFLoader(); // Optional: Provide a DRACOLoader instance to decode compressed mesh data const dracoLoader new DRACOLoader(); dracoLoader.setDecoderPath( /examples/jsm/libs/draco/ ); loader.setDRACOLoader( dracoLoader ); const gltf await loader.loadAsync( models/gltf/duck/duck.gltf ); scene.add( gltf.scene );注意示例中的setDecoderPath路径与模型 URL 对应的是 three.js 仓库自身的目录结构解码器文件draco_decoder.js、draco_decoder.wasm等位于仓库的examples/jsm/libs/draco/目录模型 URL 需替换为你自己的资产。在自己的项目中把解码器文件放到可访问的目录后将setDecoderPath指向该目录即可。另外两点来自 DRACOLoader 文档建议创建并复用同一个DRACOLoader实例避免加载多个解码器DRACOLoader会根据浏览器能力自动选择 JS 或 WASM 解码库。同理KTX2 压缩纹理需要setKTX2LoaderEXT_meshopt_compression压缩的资产需要setMeshoptDecoder均见 GLTFLoader API 文档 的方法说明。限制与注意事项GLTFLoader支持一长串 glTF 2.0 扩展KHR_draco_mesh_compression、KHR_materials_transmission、KHR_mesh_quantization、EXT_texture_webp等完整列表以 API 文档为准部分扩展如KHR_gaussian_splatting、MSFT_texture_dds需要另行注册插件才能支持。glTF 中的位图纹理不会在失去引用后被浏览器自动垃圾回收需要在销毁disposal流程中做特殊处理——模型会频繁切换的应用要留意这一点。手动教程在实践里还提醒了两点边界glTF 无法覆盖所有情况例如.blend里的灯光加载进来后可能不再是灯光用于实时 3D 的资产其节点的原点位置和缩放最好在导出前就整理好运行时再修会很麻烦。这些经验来自 Loading a .GLTF File 的完整过程。模型加载成功且gltf.animations非空时数组里的AnimationClip可以直接接入 three.js 的动画系统AnimationMixer/AnimationAction见 docs/pages 对应文档这就是加载完成后自然的下一步。【免费下载链接】three.jsJavaScript 3D Library.项目地址: https://gitcode.com/GitHub_Trending/th/three.js创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表