void FrustumFieldMapping::setTransforms(float t, const M44d &ssToWs, const M44d &csToWs) { if (m_defaultState) { clearCurves(); m_defaultState = false; } // Construct local-to-world transform from ssToWs M44d lsToSs, scale, translation; scale.setScale(V3d(2.0, 2.0, 1.0)); translation.setTranslation(V3d(-1.0, -1.0, 0.0)); lsToSs = scale * translation; M44d lpsToWs = lsToSs * ssToWs; // Add samples to Curves m_ssToWsCurve.addSample(t, ssToWs); m_lpsToWsCurve.addSample(t, lpsToWs); m_csToWsCurve.addSample(t, csToWs); // Compute near and far planes --- // Because the frustum may be skewed we can't just measure distance from // the apex of the frustum to the world-space center point of the frustum. // Instead, we transform into camera space and measure z depth there. V3d lsNearP(0.5, 0.5, 0.0), lsFarP(0.5, 0.5, 1.0); V3d wsNearP, wsFarP, csNearP, csFarP; lpsToWs.multVecMatrix(lsNearP, wsNearP); lpsToWs.multVecMatrix(lsFarP, wsFarP); M44d wsToCs = csToWs.inverse(); wsToCs.multVecMatrix(wsNearP, csNearP); wsToCs.multVecMatrix(wsFarP, csFarP); double near = -csNearP.z; double far = -csFarP.z; // Catch NaN here if (isnan(near) || isnan(far)) { throw BadPerspectiveMatrix("FrustumFieldMapping::setTransforms " "received bad screen-to-world matrix"); } m_nearCurve.addSample(t, near); m_farCurve.addSample(t, far); computeVoxelSize(); }
/// Guess position in 3D corresponding to a 2D click /// /// `clickPos` - 2D position in viewport, as from a mouse event. Imath::V3d View3D::guessClickPosition(const QPoint& clickPos) { // Get new point in the projected coordinate system using the click // position x,y and the z of a reference position. Take the reference point // of interest to be between the camera rotation center and the camera // position, as a rough guess of the depth the user is interested in. // // This works pretty well, except when there are noise points intervening // between the reference position and the user's actual point of interest. V3d refPos = 0.3*m_camera.position() + 0.7*m_camera.center(); M44d mat = m_camera.viewMatrix()*m_camera.projectionMatrix()*m_camera.viewportMatrix(); double refZ = (refPos * mat).z; V3d newPointProj(clickPos.x(), clickPos.y(), refZ); // Map projected point back into model coordinates return newPointProj * mat.inverse(); }
void FrustumFieldMapping::reset() { // Default camera to world --- M44d csToWs; csToWs.makeIdentity(); // Default screen to world --- double near = 1; double far = 2; double fovRadians = 45.0 * M_PI / 180.0; double invTan = 1.0 / std::tan(fovRadians / 2.0); double imageAspectRatio = 1.0; M44d perspective(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, (far) / (far - near), 1, 0, 0, (- far * near) / (far - near), 0); M44d fov; fov.setScale(V3d(invTan / imageAspectRatio, invTan, 1.0)); M44d flipZ; flipZ.setScale(V3d(1.0, 1.0, -1.0)); M44d csToSs = flipZ * perspective * fov; M44d standardSsToWs = csToSs.inverse() * csToWs; // Set default state --- clearCurves(); setTransforms(standardSsToWs, csToWs); m_defaultState = true; computeVoxelSize(); }
void MatrixFieldMapping::updateTransform() { typedef MatrixCurve::SampleVec::const_iterator SampleIter; // Build the voxel to world space transforms --- M44d lsToVs; getLocalToVoxelMatrix(lsToVs); M44d vsToLs = lsToVs.inverse(); // Loop over all samples in lsToWs, append vsToLs and create new curve // Also handle the special case where lsToWs has no samples. In that // case m_vsToWsCurve still has to have one sample. const MatrixCurve::SampleVec &lsToWs = m_lsToWsCurve.samples(); m_vsToWsCurve.clear(); for (SampleIter i = lsToWs.begin(), end = lsToWs.end(); i != end; i++) { m_vsToWsCurve.addSample(i->first, vsToLs * i->second); } // See if the curve has more than just a single sample m_isTimeVarying = m_lsToWsCurve.numSamples() > 1; // Sample the time-varying transforms at time=0.0 m_lsToWs = m_lsToWsCurve.linear(0.0); m_wsToLs = m_lsToWs.inverse(); m_vsToWs = vsToLs * m_lsToWs; m_wsToVs = m_vsToWs.inverse(); // Precompute the voxel size V3d voxelOrigin, nextVoxel; m_vsToWs.multVecMatrix(V3d(0, 0, 0), voxelOrigin); m_vsToWs.multVecMatrix(V3d(1, 0, 0), nextVoxel); m_wsVoxelSize.x = (nextVoxel - voxelOrigin).length(); m_vsToWs.multVecMatrix(V3d(0, 1, 0), nextVoxel); m_wsVoxelSize.y = (nextVoxel - voxelOrigin).length(); m_vsToWs.multVecMatrix(V3d(0, 0, 1), nextVoxel); m_wsVoxelSize.z = (nextVoxel - voxelOrigin).length(); }