unprojectOnTbSurface method
Vector3
unprojectOnTbSurface(
- Camera camera,
- double cursorX,
- double cursorY,
- 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();
}