当前位置: 首页 > news >正文

Three.js 模型导航教程

模型导航 ·Model Nav· ▶ 在线运行案例

  • 案例合集:三维可视化功能案例(threehub.cn)
  • 开源仓库github地址:https://github.com/z2586300277/three-cesium-examples
  • 400个案例代码:网盘链接

你将学到什么

  • OrbitControls 相机轨道交互
  • glTF/Draco 模型加载与优化
  • GSAP 时间轴与补间动画
  • requestAnimationFrame渲染循环与resize自适应

效果说明

本案例演示模型导航效果:基于 WebGL 实现「模型导航」可视化效果,附完整可运行源码;核心用到 OrbitControls、glTF/Draco、GSAP。建议先打开文首在线案例查看动态画面,再对照下方源码逐步理解。

核心概念

  • Scene / Camera / WebGLRenderer构成最小渲染闭环;大场景可开logarithmicDepthBuffer缓解 Z-fighting。
  • OrbitControls提供轨道旋转/缩放;开启enableDamping后需在 animate 中controls.update()
  • 阅读下方完整源码时,建议从init/load/animate三条主线入手,再深入 shader 与工具函数。

实现步骤

  • 搭建灯光与环境(如有)
  • requestAnimationFrame 循环 update + render
  • 代码要点

    // 模型导航 从0,0,0自动寻路至56,0,0 改变坐标即可重新计算(version:0.1:导航错误等未处理)

    import * as THREE from "three"; import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js"; import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js"; import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader.js"; const box = document.getElementById("box");

    const scene = new THREE.Scene();

    const camera = new THREE.PerspectiveCamera( 75, box.clientWidth / box.clientHeight, 0.1, 1000 );

    camera.position.set(20, 50, 0);

    const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true, logarithmicDepthBuffer: true, });

    renderer.setSize(box.clientWidth, box.clientHeight);

    scene.add(new THREE.AxesHelper(10)) scene.add(new THREE.GridHelper(100, 100)) box.appendChild(renderer.domElement);

    new OrbitControls(camera, renderer.domElement);

    window.onresize = () => { renderer.setSize(box.clientWidth, box.clientHeight);

    camera.aspect = box.clientWidth / box.clientHeight; camera.updateProjectionMatrix(); };

    animate();

    function animate() { requestAnimationFrame(animate); TWEEN.update() renderer.render(scene, camera); }

    scene.add(new THREE.AmbientLight(0xfff, 4)); // 加载模型 gltf/ glb draco解码器 const loader = new GLTFLoader();

    loader.setDRACOLoader( new DRACOLoader().setDecoderPath( FILE_HOST + "js/three/draco/" ) );

    import { init } from "@recast-navigation/core"; import * as TRR from "@recast-navigation/three"; let path; const add_nav_mesh = async () => { console.log(init); await init(); loader.load( FILE_HOST + "files/model/navmesh02.glb", (gltf) => { scene.add(gltf.scene); let navMesh = TRR.threeToSoloNavMesh(gltf.scene.children); console.log(navMesh); // navmesh helper // const helper = new TRR.NavMeshHelper(navMesh); // scene.add(helper); gltf.scene.traverse((mesh) => { if (mesh.isMesh) { mesh.material.side = THREE.DoubleSide; } }); let pathResult = compute_route(navMesh.navMesh); // 实例化路径 path = pathResult.path draw_path(pathResult.path); } ); }; import { NavMeshQuery } from "@recast-navigation/core"; import { Vector3 } from "three"; const compute_route = (navMesh) => { const navMeshQuery = new NavMeshQuery(navMesh); const startPosition = new Vector3(0, 0, 0); const endPosition = new Vector3(56, 0, 0); let route = navMeshQuery.computePath(startPosition, endPosition); return route; }; import * as Path from "three.path"; import { StaticDrawUsage, Mesh, MeshPhongMaterial, DoubleSide } from "three"; const draw_path = (path) => { const points = new Path.PathPointList(); points.set(path, 0.1, 10, new Vector3(0, 1, 0)); const geo = new Path.PathGeometry( { pathPointList: points, options: { width: 0.1, // default is 0.1 arrow: true, // default is true progress: 1, // default is 1 side: "both", // "left"/"right"/"both", default is "both" }, usage: StaticDrawUsage, // geometry usage }, false ); var material = new MeshPhongMaterial({ color: 0x58dede, depthWrite: true, transparent: true, opacity: 0.9, side: DoubleSide, }); var mesh = new Mesh(geo, material); scene.add(mesh); through_path(path) }; const computeDistance = (vec1, vec2) => { return Math.sqrt( Math.pow(vec1.x - vec2.x, 2) + Math.pow(vec1.y - vec2.y, 2) + Math.pow(vec1.z - vec2.z, 2) ); }; // 运动路径示意 import * as TWEEN from "@tweenjs/tween.js"; const add_box = () => { const geometry = new THREE.BoxGeometry(1, 1, 1); //几何体 const material = new THREE.MeshBasicMaterial({ color: 0xff0000 }); //材质 const mesh = new THREE.Mesh(geometry, material); //网格模型 // mesh.position.set(0, 10, 0); //网格模型位置 scene.add(mesh); //场景添加网格模型 return mesh; }; let i = 0; const through_path = () => { const distance = computeDistance(path[i], path[i + 1]); const tween = new TWEEN.Tween(path[i]); let box = add_box(); const time = Math.round(distance / 2); tween .to(path[i + 1], time * 1000) .onUpdate((item) => { box.position.copy(item); }) .onComplete(() => { if (i + 2 < path.length) { i = i + 1; through_path(); } }); tween.start(); }; await add_nav_mesh();

    完整源码:GitHub

    小结

    • 本文提供模型导航完整 Three.js 源码与在线 Demo,建议先运行案例再改 uniform/参数做二次实验
    • 更多 Three.js 实战案例见 three-cesium-examples 合集 与 GitHub 开源仓库
http://www.jsqmd.com/news/1085380/

相关文章:

  • 终极GTA5线上小助手完全指南:5个核心功能助你轻松玩转洛圣都
  • 前几天用AI搜自己产品,搜出来的全是竞品
  • 从USB2514i HUB芯片选型到稳定量产:硬件工程师的实战避坑指南
  • MTK芯片BROM模式完全指南:深度解密联发科设备底层通信机制
  • Windows Cleaner:3步解决C盘爆红问题的终极系统优化指南
  • 免费开源风扇控制神器:FanControl终极配置指南
  • PartKeepr开源库存管理系统:电子元件管理的最佳实践指南
  • WindowsCleaner:拯救爆满C盘,让你的Windows系统重获流畅体验
  • 3分钟解决TranslucentTB安装难题:Windows任务栏透明化终极指南
  • Beyond Standard Cells: A Practical Guide to Spare Cell, GDCAP, and DCAP in Advanced Node Tapeouts
  • Apache Tomcat CVE-2025-24813漏洞复现与安全加固实战
  • 《数电:绪论》1
  • 如何在Windows、Linux和macOS上高效部署MAA明日方舟助手?
  • 开源飞控实战(五):基于Java MAVLink库构建地面站应用
  • Themida 3.1.8.0反调试机制深度解析与Python绕过实战
  • 从规范到实践:MAAB 5.0在Simulink/Stateflow建模中的关键应用
  • 高考后60天,我从零搭建了第一个AI应用(附工具清单)
  • 制造业 AI Agent 本地化部署落地实录:3 个工厂的真实 ROI 拆解
  • 7nm芯片顶层规划实战:从NDM创建到Pin Assignment的完整流程
  • 如何高效使用B站会员购抢票工具:5个简单步骤告别抢票失败
  • 7-Zip终极指南:免费开源压缩神器,轻松管理海量文件
  • 绩效考核体系设计:MBA论文高分模板+企业案例
  • MAA跨平台部署实战指南:从开发环境到生产环境的全链路配置
  • ESP-Drone:从零构建开源无人机飞控系统的5个关键步骤
  • Android进阶-基于ViewPager2与ExoPlayer打造沉浸式短视频滑动播放体验
  • 【软考改革权威解读】:2024年起一年一考的5大影响与3类考生应对策略
  • Solidworks曲面造型进阶——巧用基准面在复杂曲面上精准绘制特征的实战解析
  • VHD/VHDX虚拟磁盘玩转多系统:从Win7到Win11的极速备份与还原实战
  • 数据结构(一):数据结构与算法复杂度基础:从核心原理到实战推导的深度解析
  • 5分钟解决Windows老游戏兼容性问题:dxwrapper完整使用指南