unprojectOnTbSurface method

dynamic unprojectOnTbSurface(
  1. dynamic camera,
  2. dynamic cursorX,
  3. dynamic cursorY,
  4. dynamic canvas,
  5. dynamic tbRadius,
)

Unproject the cursor on the trackball surface @param {Camera} camera The virtual camera @param {Number} cursorX Cursor horizontal coordinate on screen @param {Number} cursorY Cursor vertical coordinate on screen @param {HTMLElement} canvas The canvas where the renderer draws its output @param {number} tbRadius The trackball radius @returns {Vector3} The unprojected point on the trackball surface

Implementation

unprojectOnTbSurface(camera, cursorX, cursorY, canvas, tbRadius) {
  if (camera.type == 'OrthographicCamera') {
    _v2_1.copy(getCursorPosition(cursorX, cursorY, canvas));
    _v3_1.set(_v2_1.x, _v2_1.y, 0);

    var x2 = Math.pow(_v2_1.x, 2);
    var y2 = Math.pow(_v2_1.y, 2);
    var 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.type == 'PerspectiveCamera') {
    //unproject cursor on the near plane
    _v2_1.copy(getCursorNDC(cursorX, cursorY, canvas));

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

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

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

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

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

    var m = h / l;
    var 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
			 */
    var a = Math.pow(m, 2) + 1;
    var b = 2 * m * q;
    var c = Math.pow(q, 2) - radius2;
    var 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);

      var 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

        var rayLength = Math.sqrt(Math.pow(_v2_1.x, 2) + Math.pow((cameraGizmoDistance - _v2_1.y), 2));
        rayDir.multiplyScalar(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);

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

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