Search code examples
three.jsaframe

Aframe: size of model


When using a model as a source to an entity, say gltf, is there a way we know the original size? Since the scale attribute works on relative size, it seems to be a trial an error to fit the model to our desired size. I tried using the geometry.getComputingBox() of the mesh of the model but it returns null. Wondering if there is a component that is available that lets us specify the scale in absolute terms.


Solution

  • (This would have come as a comment but as I don't have enough rep points this is coming as an answer.)

    I found that the model doesn't have a size directly after the model-loaded event listener so I trigger the rescale from the update method. Funnily enough though if you don't have the model-loaded event listener then the size of the model will be 0 even after the first update is fired. This is my variant of the above code with the difference being that the dimension is set in meters:

    /**
     * Scales the object proportionally to a set value given in meters.
     */
    
    AFRAME.registerComponent("natural-size", {
      schema: {
        width: {
          type: "number",
          default: undefined, // meters
        },
        height: {
          type: "number",
          default: undefined, // meters
        },
        depth: {
          type: "number",
          default: undefined, // meters
        },
      },
    
      init() {
        this.el.addEventListener("model-loaded", this.rescale.bind(this));
      },
    
      update() {
        this.rescale();
      },
    
      rescale() {
        const el = this.el;
        const data = this.data;
        const model = el.object3D;
    
        const box = new THREE.Box3().setFromObject(model);
        const size = box.getSize();
    
        if (!size.x && !size.y && !size.z) {
          return;
        }
    
        let scale = 1;
    
        if (data.width) {
          scale = data.width / size.x;
        } else if (data.height) {
          scale = data.height(size.y);
        } else if (data.depth) {
          scale = data.depth / size.y;
        }
    
        el.setAttribute("scale", `${scale} ${scale} ${scale}`);
      },
    
      remove() {
        this.el.removeEventListener("model-loaded", this.rescale);
      },
    });
    

    Then:

    <a-entity natural-size='width:0.72' gltf-model='#model`></a-entity>