javascriptthree.jsaframe

A-Frame getObject3D('mesh') returns undefined with multiple tries


I am trying to get a bounding box for an obj-model in A-frame. I hereby will refer to these two useful links I have found on stackoverflow: How to get bounding box information from a 3D object in aframe? Any way to get a bounding box from a three.js Object3D? But after I tried with those code below,

AFRAME.registerComponent('bounding-box', {
            init: function(){
                var el = this.el;
                var obj = el.getObject3D('mesh');
                console.log(obj);
                var bbox = new THREE.Box3().setFromObject(obj);
                console.log(bbox.min, bbox.max);    
            }
        })

I got "undefined" from console.log(obj);, and then I tried the method that is mentioned in the above link,

AFRAME.registerComponent('bounding-box', {
    init: function(){
        var el = this.el;
        console.log(el);
        el.setAttribute('obj-model', {obj: 'obj5/1026/1026outside.obj'});
        var obj = el.getObject3D('mesh');
        console.log(obj);
        var bbox = new THREE.Box3().setFromObject(obj);
        console.log(bbox.min, bbox.max);    
    }
})

But still with no luck. Only if I put the code just above the closing tag, sometimes it works and log the correct information of the bounding box.

<script>
    var el = document.querySelector('#b-model');
    console.log(el);
    var obj = el.getObject3D('mesh');
    console.log(obj);

    var bbox = new THREE.Box3().setFromObject(obj);
    console.log(bbox.min, bbox.max);    
</script>
</body>

I think it is related to loading sequence but I am not understanding the discussion in this post: How to load 3D object at runtime in aframe? Like I tried above, this method is not working. Or maybe I used el.setAttribute in a wrong way? I also noticed that Felix said that using three.objLoader can solve the problem and I tried as well but still with no luck. I know in theory that the reason to register a component is because it executes only after the attached entity is initialized. So I am very confused here. Can anyone let me know how to do this by registering a component rather than a loose javascript at the end? Thanks in advance!


Solution

  • Provided your model is loading properly, You probably are trying to get the mesh (as well as the bounding box) before the model is loaded.

    If you wait for the model-loaded event:

    modelElement.addEventListener('model-loaded', (e) => {
      var obj = modelElement.getObject3D('mesh');
      var bbox = new THREE.Box3().setFromObject(obj);
      console.log(bbox)
    })
    

    It should be working fine. Check it out on this glitch, or this fiddle, with a gltf model.


    For primitives, you can just listen for the loaded event:

    <script src="https://aframe.io/releases/1.4.0/aframe.min.js"></script>
    <script>
      AFRAME.registerComponent("foo", {
        init: function() {
          this.el.addEventListener("loaded", (e) => {
            var obj = this.el.getObject3D('mesh');
            var bbox = new THREE.Box3().setFromObject(obj);
            const boxHelper = new THREE.Box3Helper(bbox, 0xff0000);
            this.el.object3D.add(boxHelper)
          })
        }
      })
    </script>
    
    <a-scene>
      <a-sphere foo color="blue" position="0 1 -4">  </a-sphere>
    </a-scene>