/** * Update the camera position along the path based on the specified distance from the beginning. * * @param fNormalizedDist normalized distance from the beginning of the path for the location of * the camera for viewing */ private void setPathDist(float fNormalizedDist) { // Make sure the distance is in the [0,1] range. fNormalizedDist = clampNormalizedPathDistance(fNormalizedDist); // Compute the actual distance along the curve. float fDist = fNormalizedDist * getPathLength(); // Save the current distance. m_kBranchState.m_fNormalizedPathDist = fNormalizedDist; // Get the path point (position and tangent) based on distance. // It needs to be double precision for the view to use. Curve3f kCurve = m_kBranchState.m_kBranchCurve; float fTime = kCurve.GetTime(fDist, 100, 1e-02f); Vector3f kViewPoint = kCurve.GetPosition(fTime); // If the gaze distance is zero, then use the tangent vector // to the curve. // If the path is being followed in the reverse direction, // then the direction of looking down the path needs to // be reversed (negated). Vector3f kLookatVector = new Vector3f(); boolean bLookatVectorUseTangent = true; if (m_fGazeDist > 0.0f) { float fTimeGazeDist = m_kBranchState.getForwardNormalizedTime(m_fGazeDist); if (fTime != fTimeGazeDist) { Vector3f kVec = kCurve.GetPosition(fTimeGazeDist); kLookatVector.Sub(kVec, kViewPoint); kLookatVector.Normalize(); bLookatVectorUseTangent = false; } } if (bLookatVectorUseTangent) { kLookatVector = kCurve.GetTangent(fTime); if (!m_kBranchState.m_bMoveForward) { kLookatVector.Neg(); } } // Update the view given the view position, view direction, // and a hint for the view up vector. setView(kViewPoint, kLookatVector); // Notify listener that we are updated. notifyCallback(EVENT_CHANGE_POSITION); }
/** * Set the camera to the specified be located at the specified view point and looking in the * specified direction. * * @param kViewPoint coordinates of the camera view point * @param kViewdirVector coordinates of the camera view direction vector. This vector must be * normalized. */ private void setView(Vector3f kViewPoint, Vector3f kViewdirVector) { // Use the view direction vector to create positive weights where more // weight is given to an axis that has less of a component in the // direction vector. Use the weights to create an average of // two desired (orthogonal axis) up vectors. Normalize this average // vector to create a combined view up vector to use. Vector3f kV = new Vector3f(kViewdirVector); kV.Set(Math.abs(kV.X), Math.abs(kV.Y), Math.abs(kV.Z)); kV.Sub(Vector3f.ONE, kV); Vector3f kViewupVector = new Vector3f(0.0f, 0.0f, 0.0f); kViewupVector.ScaleAdd(m_kViewup1.Dot(kV), m_kViewup1, kViewupVector); kViewupVector.ScaleAdd(m_kViewup2.Dot(kV), m_kViewup2, kViewupVector); kViewupVector.Normalize(); // Project the view-up vector onto the plane which is // perpendicular to the view direction vector. By getting to // this point, we know that the view-up vector and the view // direction vectors are not aligned. This projected vector is // normalized and becomes the new view-up vector. Vector3f kViewdirProjection = new Vector3f(); kViewdirProjection.Scale(kViewdirVector.Dot(kViewupVector), kViewdirVector); kViewupVector.Sub(kViewdirProjection); kViewupVector.Normalize(); Vector3f kViewleftVector = new Vector3f(); kViewleftVector.Cross(kViewupVector, kViewdirVector); m_kViewPoint.Copy(kViewPoint); m_kViewDirection.Copy(kViewdirVector); m_kViewUp.Copy(kViewupVector); }
/** * Loop through all of the possible branch choices and select the one that is the closest to the * current view direction vector. Take a vector from the current view point to a point along each * choice branch. Compute the dot-product between the current view direction vector and each of * these branch direction vectors and take the one with the largest positive value, i.e., most in * alignment. */ private void setClosestChoiceBranch() { // Retrieve the current combined viewing direction vector. // Note that the sign of the view direction vector is negated // for the reasons described in the setView method. // Matrix4f kMatrixView = parentScene.getWVMatrix(); // Vector3f kViewDirection = new Vector3f(-kMatrixView.M02, -kMatrixView.M12, -kMatrixView.M22); Vector3f kViewDirection = new Vector3f(parentScene.getCameraDirection()); // Record the current view position and combined view orientation. // Vector3f kP0 = new Vector3f(kMatrixView.M03, kMatrixView.M13, kMatrixView.M23); Vector3f kP0 = new Vector3f(getViewPoint()); // Check point down path which is maximum of the step distance // and the gaze distance. float fPointDist = Math.max(m_fGazeDist, m_fPathStep); float fBestAlign = -1.0f; int iBestAlignBranchChoiceIndex = -1; for (int iBranch = 0; iBranch < m_akBranchChoice.length; iBranch++) { // Get vector from current view point to point down branch path. BranchState kBranch = m_akBranchChoice[iBranch]; Vector3f kV = new Vector3f(); kV.Sub(kBranch.getForwardNormalizedPosition(fPointDist), kP0); kV.Normalize(); // Only accept the best aligned branches we can supposedly see. float fAlign = kV.Dot(kViewDirection); if ((fAlign > 0.0f) && (fAlign > fBestAlign)) { fBestAlign = fAlign; iBestAlignBranchChoiceIndex = iBranch; } } // Select the "nearest" branch. if (iBestAlignBranchChoiceIndex >= 0) { // Select the new branch. m_iBranchChoiceIndex = iBestAlignBranchChoiceIndex; m_bChooseBranch = false; setBranch(m_akBranchChoice[m_iBranchChoiceIndex]); } else { beep(); } }