unprojectOnTbSurface method
dynamic
unprojectOnTbSurface(
- dynamic camera,
- dynamic cursorX,
- dynamic cursorY,
- dynamic canvas,
- 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;
}
}