You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 01:27:47