computeBounds top-level property

Function computeBounds
getter/setter pair

@param {BufferGeometry} geometry @param {GLTF.Primitive} primitiveDef @param {GLTFParser} parser

Implementation

Function computeBounds =
    (geometry, Map<String, dynamic> primitiveDef, GLTFParser parser) {
  Map<String, dynamic> attributes = primitiveDef["attributes"];

  var box = new Box3(null, null);

  if (attributes["POSITION"] != null) {
    var accessor = parser.json["accessors"][attributes["POSITION"]];

    var min = accessor["min"];
    var max = accessor["max"];

    // glTF requires 'min' and 'max', but VRM (which extends glTF) currently ignores that requirement.

    if (min != null && max != null) {
      box.set(new Vector3(min[0].toDouble(), min[1].toDouble(), min[2].toDouble()),
          new Vector3(max[0].toDouble(), max[1].toDouble(), max[2].toDouble()));

      // todo normalized is bool ? int ?
      if (accessor["normalized"] != null &&
          accessor["normalized"] != false &&
          accessor["normalized"] != 0) {
        var boxScale = getNormalizedComponentScale(
            WEBGL_COMPONENT_TYPES[accessor.componentType]);
        box.min.multiplyScalar(boxScale);
        box.max.multiplyScalar(boxScale);
      }
    } else {
      print(
          'THREE.GLTFLoader: Missing min/max properties for accessor POSITION.');

      return;
    }
  } else {
    return;
  }

  var targets = primitiveDef["targets"];

  if (targets != null) {
    var maxDisplacement = new Vector3();
    var vector = new Vector3();

    for (var i = 0, il = targets.length; i < il; i++) {
      var target = targets[i];

      if (target["POSITION"] != null) {
        var accessor = parser.json["accessors"][target["POSITION"]];
        var min = accessor["min"];
        var max = accessor["max"];

        // glTF requires 'min' and 'max', but VRM (which extends glTF) currently ignores that requirement.

        if (min != null && max != null) {
          // we need to get max of absolute components because target weight is [-1,1]
          vector.setX(Math.max(Math.abs(min[0]).toDouble(), Math.abs(max[0])).toDouble());
          vector.setY(Math.max(Math.abs(min[1]).toDouble(), Math.abs(max[1])).toDouble());
          vector.setZ(Math.max(Math.abs(min[2]).toDouble(), Math.abs(max[2])).toDouble());

          if (accessor["normalized"] == true) {
            var boxScale = getNormalizedComponentScale(
                WEBGL_COMPONENT_TYPES[accessor.componentType]);
            vector.multiplyScalar(boxScale);
          }

          // Note: this assumes that the sum of all weights is at most 1. This isn't quite correct - it's more conservative
          // to assume that each target can have a max weight of 1. However, for some use cases - notably, when morph targets
          // are used to implement key-frame animations and as such only two are active at a time - this results in very large
          // boxes. So for now we make a box that's sometimes a touch too small but is hopefully mostly of reasonable size.
          maxDisplacement.max(vector);
        } else {
          print(
              'THREE.GLTFLoader: Missing min/max properties for accessor POSITION.');
        }
      }
    }

    // As per comment above this box isn't conservative, but has a reasonable size for a very large number of morph targets.
    box.expandByVector(maxDisplacement);
  }

  geometry.boundingBox = box;

  var sphere = new Sphere(null, null);

  box.getCenter(sphere.center);
  sphere.radius = box.min.distanceTo(box.max) / 2;

  geometry.boundingSphere = sphere;
};