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

如何在Three.js中结合DragControls实现物体碰撞检测与阻挡

Three.js 拖拽碰撞检测问题

描述

我正在尝试实现两个物体的碰撞效果,通过计算它们的Box3(包围盒),再使用.intersectsBox()方法返回布尔值,以此判断物体是否接触/相交。

由于使用了DragControls,物理引擎无法正常工作(DragControls不会更新刚体位置),期望实现拖拽物体时,遇到另一个物体无法穿透,停在碰撞前的安全位置。

示例代码

以下代码中,obj1和obj2均为BoxGeometry网格,当两者相交时,.intersectsBox()会返回布尔值true。

const obj1 = new THREE.Mesh(new THREE.BoxGeometry(1,1,1), new THREE.MeshBasicMaterial());
const obj2 = new THREE.Mesh(new THREE.BoxGeometry(2,5,2), new THREE.MeshBasicMaterial());

const obj1Box = new THREE.Box3().setFromObject(obj1);
const obj2Box = new THREE.Box3().setFromObject(obj2);

box1.intersectsBox(obj2);

已尝试方案

尝试保存obj1的上一位置,当检测到相交时将其位置重置为未碰撞的上一位置,但该逻辑未能正常运行。

需求

提供相关的Codesandbox示例,若能给出React Three的实现方案更佳,原生Three.js方案也可接受。

当前代码

import * as THREE from "three";
import { DragControls } from "three/addons/controls/DragControls.js";
import { OrbitControls } from "three/addons/controls/OrbitControls.js";

let renderer, scene, camera, dragcontrols, controls;
let objects, boxMesh1, boxMesh2;

function init() {
  const bgColor = 0x263238;
  renderer = new THREE.WebGLRenderer({ antialias: false });
  renderer.setPixelRatio(window.devicePixelRatio);
  renderer.setSize(window.innerWidth, window.innerHeight);
  renderer.setClearColor(bgColor, 1);
  renderer.outputColorSpace = THREE.SRGBColorSpace;
  document.body.appendChild(renderer.domElement);

  scene = new THREE.Scene();
  scene.fog = new THREE.Fog(0x263238, 20, 60);

  camera = new THREE.PerspectiveCamera(
    75,
    window.innerWidth / window.innerHeight,
    0.1,
    1000
  );
  camera.far = 100;
  camera.updateProjectionMatrix();
  camera.position.set(1, 1, -5);

  controls = new OrbitControls(camera, renderer.domElement);

  boxMesh1 = new THREE.Mesh(
    new THREE.BoxGeometry(1, 1, 1),
    new THREE.MeshBasicMaterial({ color: 0x00ff00 })
  );
  scene.add(boxMesh1);
  
  boxMesh2 = new THREE.Mesh(
    new THREE.BoxGeometry(2, 5, 2),
    new THREE.MeshBasicMaterial({ color: 0xff0000 })
  );
  boxMesh2.position.set(2,2,0);
  scene.add(boxMesh2);

  dragcontrols = new DragControls([boxMesh1], camera, renderer.domElement);
  
  let lastSafePosition = boxMesh1.position.clone();
  
  dragcontrols.addEventListener("dragstart", (event) => {
    controls.enabled = false;
    lastSafePosition.copy(event.object.position);
  });
  
  dragcontrols.addEventListener("dragend", () => {
    controls.enabled = true;
    console.log(controls.enabled);
  });
  
  dragcontrols.addEventListener('drag', () => {  
    boxMesh1.position.y = 0;
  const box1Mesh = event.object; // The mesh being dragged
  const box1BoundingBox = new THREE.Box3().setFromObject(box1Mesh);
  const box2BoundingBox = new THREE.Box3().setFromObject(boxMesh2);

  if (box1BoundingBox.intersectsBox(box2BoundingBox)) {
    box1Mesh.position.copy(lastSafePosition);
  } else {
    lastSafePosition.copy(box1Mesh.position);
  }
  })
  const metreSize = 10.0;
  const metreDivisions = 40.0;
  const decimetreSize = 10.0;
  const decimetreDivisions = 400.0;

  const gridHelper = new THREE.GridHelper(
    metreSize,
    metreDivisions,
    0x8fc8df,
    0x8fc8df
  );
  scene.add(gridHelper);

  const gridHelper2 = new THREE.GridHelper(
    decimetreSize,
    decimetreDivisions,
    0xd7eef5,
    0xd7eef5
  );
  scene.add(gridHelper2);
  
  gridHelper.position.set(0,-0.5,0)
  gridHelper2.position.set(0,-0.5,0)
  
}

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

init();
render();

内容的提问来源于stack exchange,提问作者AshhadDevLab

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 01:45:07