//-------------------------------------------------------------------------------------------------- /// Walk forward backward along the current camera direction /// /// \return Returns true if input caused changes to the camera an false if no changes occurred /// /// \remarks As this function moves the camera, it will have no effect when projection is orthographic /// \todo Needs better control over movement when camera position gets close to the rotation point. //-------------------------------------------------------------------------------------------------- bool ManipulatorTrackball::walk(int posX, int posY) { if (m_camera.isNull()) return false; if (posX == m_lastPosX && posY == m_lastPosY) return false; const double vpPixSizeY = m_camera->viewport()->height(); if (vpPixSizeY <= 0) return false; // !!!! // Should be a member variable, settable as a ratio of the model bounding box/sphere const double minWalkTargetDistance = 1.0; const double ty = (m_lastPosY - posY)/vpPixSizeY; // Determine target distance to travel along camera direction // This is the distance that we will move the camera in response to a full (whole viewport) movement of the mouse const Vec3d camDir = m_camera->direction(); const Vec3d vDiff = m_rotationPoint - m_walkStartCameraPos; double targetDist = Math::abs(camDir*vDiff); if (targetDist < minWalkTargetDistance) targetDist = minWalkTargetDistance; // Figure out movement to append double moveDist = ty*targetDist*m_walkSensitivity; Vec3d moveVec = camDir*moveDist; Mat4d viewMat = m_camera->viewMatrix(); viewMat.translatePostMultiply(moveVec); m_camera->setViewMatrix(viewMat); m_lastPosX = posX; m_lastPosY = posY; return true; }
//-------------------------------------------------------------------------------------------------- /// Pan the camera up/down and left/right /// /// \return Returns true if input caused changes to the camera an false if no changes occurred //-------------------------------------------------------------------------------------------------- bool ManipulatorTrackball::pan(int posX, int posY) { if (m_camera.isNull()) return false; if (posX == m_lastPosX && posY == m_lastPosY) return false; const double vpPixSizeX = m_camera->viewport()->width(); const double vpPixSizeY = m_camera->viewport()->height(); if (vpPixSizeX <= 0 || vpPixSizeY <= 0) return false; // Normalized movement in screen plane double tx = (posX - m_lastPosX)/vpPixSizeX; double ty = (posY - m_lastPosY)/vpPixSizeY; // Viewport size in world coordinates const double aspect = m_camera->aspectRatio(); const double vpWorldSizeY = m_camera->frontPlaneFrustumHeight(); const double vpWorldSizeX = vpWorldSizeY*aspect; const Vec3d camUp = m_camera->up(); const Vec3d camRight = m_camera->right(); Vec3d translation(0, 0, 0); Camera::ProjectionType projType = m_camera->projection(); if (projType == Camera::PERSPECTIVE) { const Vec3d camPos = m_camera->position(); const Vec3d camDir = m_camera->direction(); const double nearPlane = m_camera->nearPlane(); // Compute distance from camera to rotation point projected onto camera forward direction const Vec3d vDiff = m_rotationPoint - camPos; const double camRotPointDist = Math::abs(camDir*vDiff); Vec3d vX = camRight*((tx*vpWorldSizeX)/nearPlane)*camRotPointDist; Vec3d vY = camUp*((ty*vpWorldSizeY)/nearPlane)*camRotPointDist; translation = vX + vY; } else if (projType == Camera::ORTHO) { Vec3d vX = camRight*tx*vpWorldSizeX; Vec3d vY = camUp*ty*vpWorldSizeY; translation = vX + vY; } Mat4d viewMat = m_camera->viewMatrix(); viewMat.translatePostMultiply(translation); m_camera->setViewMatrix(viewMat); m_lastPosX = posX; m_lastPosY = posY; return true; }
//-------------------------------------------------------------------------------------------------- /// Rotate /// /// \return Returns true if input caused changes to the camera an false if no changes occurred //-------------------------------------------------------------------------------------------------- bool ManipulatorTrackball::rotate(int posX, int posY) { if (m_camera.isNull()) return false; if (posX == m_lastPosX && posY == m_lastPosY) return false; const double vpPixSizeX = m_camera->viewport()->width(); const double vpPixSizeY = m_camera->viewport()->height(); if (vpPixSizeX <= 0 || vpPixSizeY <= 0) return false; const double vpPosX = posX - static_cast<int>(m_camera->viewport()->x()); const double vpPosY = posY - static_cast<int>(m_camera->viewport()->y()); const double vpLastPosX = m_lastPosX - static_cast<int>(m_camera->viewport()->x()); const double vpLastPosY = m_lastPosY - static_cast<int>(m_camera->viewport()->y()); // Scale the new/last positions to the range [-1.0, 1.0] double newPosX = 2.0*(vpPosX/vpPixSizeX) - 1.0; double newPosY = 2.0*(vpPosY/vpPixSizeY) - 1.0; double lastPosX = 2.0*(vpLastPosX/vpPixSizeX) - 1.0; double lastPosY = 2.0*(vpLastPosY/vpPixSizeY) - 1.0; Mat4d viewMat = m_camera->viewMatrix(); // Compute rotation quaternion Quatd rotQuat = trackballRotation(lastPosX, lastPosY, newPosX, newPosY, viewMat, m_rotateSensitivity); // Update navigation by modifying the view matrix Mat4d rotMatr = rotQuat.toMatrix4(); rotMatr.translatePostMultiply(-m_rotationPoint); rotMatr.translatePreMultiply(m_rotationPoint); viewMat = viewMat*rotMatr; m_camera->setViewMatrix(viewMat); m_lastPosX = posX; m_lastPosY = posY; return true; }