Three.js场景GLTF模型碰撞检测及资源链接问题咨询
解决方案
1. 解决PointerLockControls穿模问题(结合DRACO压缩与物理碰撞检测)
DRACO是用来压缩GLTF/GLB模型、优化加载速度的工具,碰撞检测核心得靠物理引擎(比如Cannon.js)实现,具体步骤如下:
步骤1:用DRACOLoader加载压缩模型
先在项目中引入DRACOLoader,加载带DRACO压缩的GLB模型:
import * as THREE from 'three'; import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'; import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js'; const dracoLoader = new DRACOLoader(); dracoLoader.setDecoderPath('/examples/jsm/libs/draco/'); // 对应DRACO解码器的文件路径 const gltfLoader = new GLTFLoader(); gltfLoader.setDRACOLoader(dracoLoader); gltfLoader.load('your-model.glb', (gltf) => { const model = gltf.scene; scene.add(model); // 为模型创建碰撞体 createCollisionBody(model); });
步骤2:用Cannon.js生成模型碰撞体
先引入Cannon.js,根据模型复杂度选择碰撞体类型:
- 简单模型:用
Cannon.Box或Cannon.Sphere(基于模型的包围盒/包围球生成) - 复杂模型:用
Cannon.ConvexPolyhedron(提取模型顶点生成)
示例代码:
import * as CANNON from 'cannon-es'; // 初始化物理世界 const world = new CANNON.World(); world.gravity.set(0, 0, 0); // 第一人称场景可关闭重力 function createCollisionBody(model) { // 计算模型包围盒 const box = new THREE.Box3().setFromObject(model); const size = box.getSize(new THREE.Vector3()); const center = box.getCenter(new THREE.Vector3()); // 创建Cannon碰撞体 const shape = new CANNON.Box(new CANNON.Vec3(size.x/2, size.y/2, size.z/2)); const body = new CANNON.Body({ mass: 0, // 静态物体质量设为0,不会被外力推动 position: new CANNON.Vec3(center.x, center.y, center.z), shape: shape }); // 同步模型与碰撞体的旋转角度 body.quaternion.copy(model.quaternion); world.addBody(body); }
步骤3:结合PointerLockControls做碰撞检测
在动画循环中,根据Controls的移动方向计算相机目标位置,通过物理引擎检测是否会碰撞,若碰撞则限制相机移动:
let cameraPosition = new CANNON.Vec3(); let cameraQuaternion = new CANNON.Quaternion(); function animate() { requestAnimationFrame(animate); // 同步相机位置到物理测试体 cameraPosition.copy(camera.position); cameraQuaternion.copy(camera.quaternion); // 计算Controls想要移动的方向 const direction = new THREE.Vector3(); controls.getDirection(direction); direction.multiplyScalar(0.1); // 控制移动步长 // 测试目标位置是否会触发碰撞 const targetPos = cameraPosition.clone().add(new CANNON.Vec3(direction.x, direction.y, direction.z)); const result = world.raycastClosest(cameraPosition, targetPos); // 无碰撞时才更新相机位置 if (!result.hasHit) { camera.position.add(direction); } renderer.render(scene, camera); }
2. 解决JS、CSS文件关联HTML错误
从路径和标签写法两方面排查:
CSS文件引入
在HTML的<head>标签内添加:
<!-- 注意路径:若CSS在css/style.css,HTML在examples/index.html,需回退一级目录 --> <link rel="stylesheet" href="../css/style.css">
- 打开浏览器控制台(F12)查看Network面板,若出现404错误,说明路径错误,调整路径即可
- 不要遗漏
rel="stylesheet"属性
JS文件引入
在HTML的<body>标签末尾添加(避免阻塞页面加载):
<!-- 先引入Three.js核心库,再加载自定义脚本 --> <script src="../js/three.min.js"></script> <script src="../js/GLTFLoader.js"></script> <script src="../js/your-script.js"></script>
- 如果使用ES6模块,需添加
type="module"属性:
<script type="module" src="../js/your-module-script.js"></script>
- 同样通过控制台的404错误,确认文件名和路径拼写正确
3. 场景响应式适配思路(后续处理)
监听window.resize事件,更新相机和渲染器参数:
window.addEventListener('resize', () => { // 更新相机宽高比 camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); // 更新渲染器尺寸 renderer.setSize(window.innerWidth, window.innerHeight); });
若适配移动端,还可调整相机FOV、限制场景元素最小尺寸,或根据屏幕精度加载对应模型。
内容的提问来源于stack exchange,提问作者ambaamba
相关产品推荐
相关产品推荐

