【问题标题】:Three.js : Box3 from an object not in sceneThree.js:来自不在场景中的对象的 Box3
【发布时间】:2022-01-24 16:15:21
【问题描述】:

我在从不同模块中的对象添加边界框时遇到问题。现在,只要我在我的主函数中编写所有内容,它就可以正常工作,但是一旦我在另一个文件中创建我的函数并导入到主文件中,它就不再工作了。

我得到的错误代码:

Uncaught TypeError: Cannot read properties of undefined (reading 'updateWorldMatrix')
    at Box3.expandByObject (three.module.js:4934:10)
    at Box3.setFromObject (three.module.js:4852:15)
    at camCollision (camColliders.js:68:37)
    at HTMLDocument.<anonymous> (World.js:355:7)

camColliders.js 是我试图将函数放入的文件,World.js 是我的主文件。

这里是函数:

function camCollision() {
      const camBB = new Box3().setFromObject(camSphereDetector);

      const boule1BB = new Box3().setFromObject(boule1Obj);
      boule1BB.name = 'first';
      const boule2BB = new Box3().setFromObject(boule2Obj);
      boule2BB.name = 'second';
      const boule3BB = new Box3().setFromObject(boule3Obj);
      boule3BB.name = 'third';

      const boulesBB = [boule1BB, boule2BB, boule3BB];

      boulesBB.forEach((bbs) => {
        if (bbs.intersectsBox(camBB)) {
          console.log('got it');
        }
      });
    }

    document.addEventListener('mouseup', () => {
      camCollision();
    });

当我在单独的文件中执行此操作时,我首先从另一个文件导入对象,它们都是网格。

我认为问题在于我无法在单独的文件中创建边界框,因为它需要先添加到场景中,而我只是将它们添加到 World.js 中的场景中。然而,错误导致我进入第 68 行,即“boule1BB”的变量,这很奇怪,因为“camBB”应该首先出现问题?

这是我创建 Box3 的方式(这些只是复制一些 GLTF 对象的位置和大小,因为我无法从中获取 Box3):

const boule1Obj = new Mesh(
    new SphereGeometry(2, 32, 16),
    new MeshBasicMaterial({ color: 'red', transparent: true, opacity: 0 }),
  );
  boule1Obj.position.set(10, -3.5, 0);

然后,我想知道,如果我的问题是正确的:有没有办法在不同的 js 文件中创建一个 Box3,从一个尚未添加到场景中的对象(即使它应该在函数被调用)?可能采用与“setFromObject”不同的方式?还是我不了解真正的问题。

对于一些上下文,目的是在用户单击每个模型时提供有关每个模型的一些信息,我计划将这些信息作为与模型对应的每个网格的“.name”。所以我不想把所有这些东西都写在主文件中,而是写在一个单独的文件中。

我希望这足够清楚,并且我已经提供了足够的内容来找到解决方案。我找不到其他人有这个问题。如果您还需要什么,请告诉我!

已经感谢您的帮助!

【问题讨论】:

    标签: javascript three.js collision-detection bounding-box gltf


    【解决方案1】:

    我认为问题在于我无法在单独的文件中创建边界框,因为它需要在 World.js 中添加到场景中。

    并非如此。由于构造的THREE.Mesh 具有带有范围(来自其几何形状)和变换(默认情况下,转换为原点,没有缩放或旋转)的形状,Three.js 可以并且将根据该信息确定边界框,就好像网格在场景中。我已经在 CodePen 上发布了 demo

    也不应该在一个文件中定义对象并在另一个文件中引用它有任何区别,只要对象在范围内并在其绑定时初始化

    在这里,我怀疑您在 World.js 中分配 boule1Obj、boule2Obj 和 boule3Obj。在这种情况下,导入的函数在分配变量之前被提升,并且函数看到绑定到它们为未分配 undefined.

    尝试更改 camCollision() 以接受 bouleXObjs 作为参数。

    function camCollision(...objs) {
      const camBB = new Box3().setFromObject(camSphereDetector);
    
      for(let i = 0; i < objs.length; i++) {
        const objBB = new Box3().setFromGeometry(objs[i]);
        objBB.name = `Bounding Box ${i + 1}`;
        if(objBB.intersectsBox(camBB)) {
          console.log("Got it!");
        }
      }
    }
    

    然后称它为

    document.addEventListener("mouseup", () => {
      camCollision(boule1Obj, boule2Obj, boule3Obj);
    });
    

    【讨论】:

    • 使用.add()camShpereDetectorlocal 位置总是 将保持在 (0, 0, 0)。 (这有点过于简单了,但是对象的位置是本地的并且相对于其父对象。对于添加到场景中的对象,父对象是场景,并且本地位置与对象的世界位置相同。对于添加到另一个对象的对象,父对象是另一个对象;子对象的位置(此处为 (0, 0, 0))成为父对象位置的平移,并且它的 .position 属性不会更新以反映其(或父级的)世界位置。)
    • 为了克服这个问题,在const camBB = new Box3()...之后,添加camBB.translate(camSphereDetector.getWorldPosition(new Vector3());
    • CodePen here 证明了这一点。
    • 你仍然可以使用camera.add;只需与getWorldPosition 结合使用即可。控制台出现什么错误?
    • 另外,请注意,我在第二个演示中使用的BoxHelper 只是展示边界框的最快方式。 Three.js 中的所有...Helper 类都存在为通常没有视觉效果的事物(边界框、灯光、轴等)提供视觉代理。您的代码中不需要它。
    猜你喜欢
    • 1970-01-01
    • 2015-10-12
    • 1970-01-01
    • 2022-09-27
    • 1970-01-01
    • 1970-01-01
    • 2017-07-29
    • 2016-02-03
    • 2023-03-03
    相关资源
    最近更新 更多