Trackball.cpp
From Immersive Visualization Lab Wiki
/** Applies a rotation to a matrix according to a fictitious trackball, placed in the middle of the window. The trackball coordinate system is: x=right, y=up, z=to viewer<BR> The origin of the mouse coordinates zero (0,0) is considered to be top left. @param width, height window size in pixels @param fromX, fromY mouse starting position in pixels @param toX, toY mouse end position in pixels */ Matrix trackballRotation(int width, int height, int fromX, int fromY, int toX, int toY) { const float TRACKBALL_SIZE = 1.3f; // virtual trackball size Matrix mInv; // inverse of ObjectView matrix Vector3 v1, v2; // mouse drag positions in normalized 3D space float smallSize; // smaller window size between width and height float halfWidth, halfHeight; // half window sizes float angle; // rotational angle float d; // distance // Compute mouse coordinates in window and normalize to -1..1 // ((0,0) = window center, (-1,-1) = bottom left, (1,1) = top right) halfWidth = (float)width / 2.0; halfHeight = (float)height / 2.0; smallSize = (halfWidth < halfHeight) ? halfWidth : halfHeight; v1.x = ((float)fromX - halfWidth) / smallSize; v1.y = ((float)(height-fromY) - halfHeight) / smallSize; v2.x = ((float)toX - halfWidth) / smallSize; v2.y = ((float)(height-toY) - halfHeight) / smallSize; // Compute z-coordinates on trackball: d = sqrtf(v1.x * v1.x + v1.y * v1.y); v1.z = expf(-TRACKBALL_SIZE * d * d); d = sqrtf(v2.x * v2.x + v2.y * v2.y); v2.z = expf(-TRACKBALL_SIZE * d * d); // Compute rotational angle: angle = v1.angle(v2); // angle between v1 and v2 // Compute rotational axis: v2.cross(v1); // v2 = v2 x v1 (cross product) // Convert axis coordinates (v2) from world coordinates to object coordinates: mInv.identity(); mInv.copyRot(this); // copy rotational part of mv to mInv mInv.invertOrtho(); // invert orthogonal matrix mInv v2.multiply(mInv); // v2 = v2 x mInv (matrix multiplication) v2.normalize(); // normalize v2 before rotation // Perform matrix modification: return rotate(-angle, v2.x, v2.y, v2.z); }