unprojectOnTbSurface method

Vector3 unprojectOnTbSurface(
  1. Camera camera,
  2. double cursorX,
  3. double cursorY,
  4. double tbRadius,
)
  • Unproject the cursor on the trackball surface
  • camera The virtual camera
  • cursorX Cursor horizontal coordinate on screen
  • cursorY Cursor vertical coordinate on screen
  • tbRadius The trackball radius
  • returns Vector3 The unprojected point on the trackball surface

Implementation

Vector3 unprojectOnTbSurface(Camera camera, double cursorX, double cursorY, double tbRadius) {
    if (camera is OrthographicCamera) {
      _v2_1.setFrom(getCursorPosition(cursorX, cursorY));
      _v3_1.setValues(_v2_1.x, _v2_1.y, 0);

      final x2 = math.pow(_v2_1.x, 2);
      final y2 = math.pow(_v2_1.y, 2);
      final r2 = math.pow(_tbRadius, 2);

      if (x2 + y2 <= r2 * 0.5) {
        //intersection with sphere
        _v3_1.setZ(math.sqrt(r2 - (x2 + y2)));
      } else {
        //intersection with hyperboloid
        _v3_1.setZ((r2 * 0.5) / (math.sqrt(x2 + y2)));
      }

      return _v3_1;
    }
    else if (camera is PerspectiveCamera) {
      //unproject cursor on the near plane
      _v2_1.setFrom(getCursorNDC(cursorX, cursorY));

      _v3_1.setValues(_v2_1.x, _v2_1.y, -1);
      _v3_1.applyMatrix4(camera.projectionMatrixInverse);

      final rayDir = _v3_1.clone().normalize(); //unprojected ray direction
      final cameraGizmoDistance =
          camera.position.distanceTo(_gizmos.position);
      final radius2 = math.pow(tbRadius, 2);

      //	  camera
      //		|\
      //		| \
      //		|  \
      //	h	|	\
      //		| 	 \
      //		| 	  \
      //	_ _ | _ _ _\ _ _  near plane
      //			l

      final h = _v3_1.z;
      final l = math.sqrt(math.pow(_v3_1.x, 2) + math.pow(_v3_1.y, 2));

      if (l == 0) {
        //ray aligned with camera
        rayDir.setValues(_v3_1.x, _v3_1.y, tbRadius);
        return rayDir;
      }

      final m = h / l;
      final q = cameraGizmoDistance;

      /*
		 * calculate intersection point between unprojected ray and trackball surface
		 *|y = m * x + q
		 *|x^2 + y^2 = r^2
		 *
		 * (m^2 + 1) * x^2 + (2 * m * q) * x + q^2 - r^2 = 0
		 */
      num a = math.pow(m, 2) + 1;
      num b = 2 * m * q;
      num c = math.pow(q, 2) - radius2;
      num delta = math.pow(b, 2) - (4 * a * c);

      if (delta >= 0) {
        //intersection with sphere
        _v2_1.setX((-b - math.sqrt(delta)) / (2 * a));
        _v2_1.setY(m * _v2_1.x + q);

        final angle = MathUtils.rad2deg * _v2_1.angle();

        if (angle >= 45) {
          //if angle between intersection point and X' axis is >= 45°, return that point
          //otherwise, calculate intersection point with hyperboloid

          final rayLength = math.sqrt(math.pow(_v2_1.x, 2) +
              math.pow((cameraGizmoDistance - _v2_1.y), 2));
          rayDir.scale(rayLength);
          rayDir.z += cameraGizmoDistance;
          return rayDir;
        }
      }

      //intersection with hyperboloid
      /*
		 *|y = m * x + q
		 *|y = (1 / x) * (r^2 / 2)
		 *
		 * m * x^2 + q * x - r^2 / 2 = 0
		 */

      a = m;
      b = q;
      c = -radius2 * 0.5;
      delta = math.pow(b, 2) - (4 * a * c);
      _v2_1.setX((-b - math.sqrt(delta)) / (2 * a));
      _v2_1.setY(m * _v2_1.x + q);

      final rayLength = math.sqrt(math.pow(_v2_1.x, 2) +
          math.pow((cameraGizmoDistance - _v2_1.y), 2));

      rayDir.scale(rayLength);
      rayDir.z += cameraGizmoDistance;
      return rayDir;
    }

    return Vector3();
  }