updateMatrixWorld method

  1. @override
void updateMatrixWorld([
  1. bool force = false
])
override

Implementation

@override
updateMatrixWorld([bool force = false]) {
  var space = (mode == 'scale') ? 'local' : this.space; // scale always oriented to local rotation

  var quaternion = (space == 'local') ? worldQuaternion : _identityQuaternion;

  // Show only gizmos for current transform mode

  gizmo['translate'].visible = mode == 'translate';
  gizmo['rotate'].visible = mode == 'rotate';
  gizmo['scale'].visible = mode == 'scale';

  helper['translate'].visible = mode == 'translate';
  helper['rotate'].visible = mode == 'rotate';
  helper['scale'].visible = mode == 'scale';

  var handles = [];
  handles.addAll(picker[mode].children);
  handles.addAll(gizmo[mode].children);
  handles.addAll(helper[mode].children);

  // print("TransformControlsGizmo cameraQuaternion ${this.cameraQuaternion.toJSON()} ");

  // print("TransformControlsGizmo updateMatrixWorld mode: ${this.mode} handles: ${handles.length}  ");

  for (var i = 0; i < handles.length; i++) {
    var handle = handles[i];

    // hide aligned to camera

    handle.visible = true;
    handle.rotation.set(0.0, 0.0, 0.0);
    handle.position.copy(worldPosition);

    var factor;

    if (camera! is OrthographicCamera) {
      factor = (camera!.top - camera!.bottom) / camera!.zoom;
    } else {
      factor = worldPosition.distanceTo(cameraPosition) *
          Math.min(1.9 * Math.tan(Math.pi * camera!.fov / 360) / camera!.zoom, 7);
    }

    handle.scale.set(1.0, 1.0, 1.0).multiplyScalar(factor * size / 4);

    // TODO: simplify helpers and consider decoupling from gizmo

    if (handle.tag == 'helper') {
      handle.visible = false;

      if (handle.name == 'AXIS') {
        handle.position.copy(worldPositionStart);
        handle.visible = axis != null;

        if (axis == 'X') {
          _tempQuaternion.setFromEuler(_tempEuler.set(0, 0, 0), false);
          handle.quaternion.copy(quaternion).multiply(_tempQuaternion);

          if (Math.abs(_alignVector.copy(_unitX).applyQuaternion(quaternion).dot(eye)) > 0.9) {
            handle.visible = false;
          }
        }

        if (axis == 'Y') {
          _tempQuaternion.setFromEuler(_tempEuler.set(0, 0, Math.pi / 2), false);
          handle.quaternion.copy(quaternion).multiply(_tempQuaternion);

          if (Math.abs(_alignVector.copy(_unitY).applyQuaternion(quaternion).dot(eye)) > 0.9) {
            handle.visible = false;
          }
        }

        if (axis == 'Z') {
          _tempQuaternion.setFromEuler(_tempEuler.set(0, Math.pi / 2, 0), false);
          handle.quaternion.copy(quaternion).multiply(_tempQuaternion);

          if (Math.abs(_alignVector.copy(_unitZ).applyQuaternion(quaternion).dot(eye)) > 0.9) {
            handle.visible = false;
          }
        }

        if (axis == 'XYZE') {
          _tempQuaternion.setFromEuler(_tempEuler.set(0, Math.pi / 2, 0), false);
          _alignVector.copy(rotationAxis);
          handle.quaternion.setFromRotationMatrix(_lookAtMatrix.lookAt(_zeroVector, _alignVector, _unitY));
          handle.quaternion.multiply(_tempQuaternion);
          handle.visible = dragging;
        }

        if (axis == 'E') {
          handle.visible = false;
        }
      } else if (handle.name == 'START') {
        handle.position.copy(worldPositionStart);
        handle.visible = dragging;
      } else if (handle.name == 'END') {
        handle.position.copy(worldPosition);
        handle.visible = dragging;
      } else if (handle.name == 'DELTA') {
        handle.position.copy(worldPositionStart);
        handle.quaternion.copy(worldQuaternionStart);
        _tempVector.set(1e-10, 1e-10, 1e-10).add(worldPositionStart).sub(worldPosition).multiplyScalar(-1);
        _tempVector.applyQuaternion(worldQuaternionStart.clone().invert());
        handle.scale.copy(_tempVector);
        handle.visible = dragging;
      } else {
        handle.quaternion.copy(quaternion);

        if (dragging) {
          handle.position.copy(worldPositionStart);
        } else {
          handle.position.copy(worldPosition);
        }

        if (axis != null) {
          handle.visible = axis!.contains(handle.name);
        }
      }

      // If updating helper, skip rest of the loop
      continue;
    }

    // Align handles to current local or world rotation

    handle.quaternion.copy(quaternion);

    if (mode == 'translate' || mode == 'scale') {
      // Hide translate and scale axis facing the camera

      var axisHideThreshold = 0.99;
      var planeHideThreshold = 0.2;

      if (handle.name == 'X') {
        if (Math.abs(_alignVector.copy(_unitX).applyQuaternion(quaternion).dot(eye)) > axisHideThreshold) {
          handle.scale.set(1e-10, 1e-10, 1e-10);
          handle.visible = false;
        }
      }

      if (handle.name == 'Y') {
        if (Math.abs(_alignVector.copy(_unitY).applyQuaternion(quaternion).dot(eye)) > axisHideThreshold) {
          handle.scale.set(1e-10, 1e-10, 1e-10);
          handle.visible = false;
        }
      }

      if (handle.name == 'Z') {
        if (Math.abs(_alignVector.copy(_unitZ).applyQuaternion(quaternion).dot(eye)) > axisHideThreshold) {
          handle.scale.set(1e-10, 1e-10, 1e-10);
          handle.visible = false;
        }
      }

      if (handle.name == 'XY') {
        var ll = Math.abs(_alignVector.copy(_unitZ).applyQuaternion(quaternion).dot(eye));

        if (ll < planeHideThreshold) {
          handle.scale.set(1e-10, 1e-10, 1e-10);
          handle.visible = false;
        }
      }

      if (handle.name == 'YZ') {
        if (Math.abs(_alignVector.copy(_unitX).applyQuaternion(quaternion).dot(eye)) < planeHideThreshold) {
          handle.scale.set(1e-10, 1e-10, 1e-10);
          handle.visible = false;
        }
      }

      if (handle.name == 'XZ') {
        if (Math.abs(_alignVector.copy(_unitY).applyQuaternion(quaternion).dot(eye)) < planeHideThreshold) {
          handle.scale.set(1e-10, 1e-10, 1e-10);
          handle.visible = false;
        }
      }
    } else if (mode == 'rotate') {
      // Align handles to current local or world rotation

      _tempQuaternion2.copy(quaternion);
      _alignVector.copy(eye).applyQuaternion(_tempQuaternion.copy(quaternion).invert());

      if (handle.name.indexOf('E') != -1) {
        handle.quaternion.setFromRotationMatrix(_lookAtMatrix.lookAt(eye, _zeroVector, _unitY));
      }

      if (handle.name == 'X') {
        _tempQuaternion.setFromAxisAngle(_unitX, Math.atan2(-_alignVector.y, _alignVector.z));
        _tempQuaternion.multiplyQuaternions(_tempQuaternion2, _tempQuaternion);
        handle.quaternion.copy(_tempQuaternion);
      }

      if (handle.name == 'Y') {
        _tempQuaternion.setFromAxisAngle(_unitY, Math.atan2(_alignVector.x, _alignVector.z));
        _tempQuaternion.multiplyQuaternions(_tempQuaternion2, _tempQuaternion);
        handle.quaternion.copy(_tempQuaternion);
      }

      if (handle.name == 'Z') {
        _tempQuaternion.setFromAxisAngle(_unitZ, Math.atan2(_alignVector.y, _alignVector.x));
        _tempQuaternion.multiplyQuaternions(_tempQuaternion2, _tempQuaternion);
        handle.quaternion.copy(_tempQuaternion);
      }
    }

    // Hide disabled axes
    handle.visible = handle.visible && (handle.name.indexOf('X') == -1 || showX);
    handle.visible = handle.visible && (handle.name.indexOf('Y') == -1 || showY);
    handle.visible = handle.visible && (handle.name.indexOf('Z') == -1 || showZ);
    handle.visible = handle.visible && (handle.name.indexOf('E') == -1 || (showX && showY && showZ));

    // highlight selected axis

    handle.material.userData["_color"] = handle.material.userData["_color"] ?? handle.material.color.clone();
    handle.material.userData["_opacity"] = handle.material.userData["_opacity"] ?? handle.material.opacity;

    handle.material.color.copy(handle.material.userData["_color"]);
    handle.material.opacity = handle.material.userData["_opacity"];

    if (enabled && axis != null) {
      if (handle.name == axis) {
        handle.material.color.setHex(0xffff00);
        handle.material.opacity = 1.0;
      } else if (axis?.split('').where((a) => handle.name == a).toList().isNotEmpty == true) {
        handle.material.color.setHex(0xffff00);
        handle.material.opacity = 1.0;
      }
    }
  }

  super.updateMatrixWorld(force);
}