override public bool UpdateCapture(InputEvent e) { if (in_drag) { float fRayT = 0.0f; if (RayIntersection.Sphere(e.ray.Origin, e.ray.Direction, hitFrame.Origin, IndicatorDistance, out fRayT) == false) { return(true); // should not happen, but I guess it could if user } // had arms out in some crazy position... Vector3f v = e.ray.Origin + fRayT * e.ray.Direction; Vector3f vToHit = (v - hitFrame.Origin).Normalized; Vector3f vToStart = (startHitPos - hitFrame.Origin).Normalized; float deltaUp = -VRUtil.PlaneAngleSigned(vToHit, vToStart, hitFrame.X); cockpit.TiltAngle = MathUtil.Clamp(start_tilt + deltaUp, -30.0f, 20.0f); float deltaLR = -VRUtil.PlaneAngleSigned(vToHit, vToStart, hitFrame.Y); cockpit.ShiftAngle = start_shift + deltaLR; //if ( tracker.IsLocked == false ) cockpit.ShiftAngle = MathUtil.Clamp(cockpit.ShiftAngle, -10.0f, 10.0f); } return(true); }
public Capture Update_TransformCamera(InputState input, CaptureData data) { // need both controllers to have valid positions if (input.bLeftControllerActive == false || input.bRightControllerActive == false) { return(Capture.Continue); } float fSceneScale = cockpit.Scene.GetSceneScale(); HandInfo hi = (HandInfo)data.custom_data; // deadzones and scaling factors const float fZoomDeadzoneInM = 0.1f; const float fZoomScale = 25.0f; const float fPanDeadzoneInM = 0.05f; const float fPanScale = 25.0f; const float fAzimuthDeadzoneInDeg = 10.0f; const float fAltitudeDeadzoneInDeg = 15.0f; const float fTrackAlpha = 0.1f; // larger == faster tracking // zoom is indicated by moving hands together/apart. But we want to get rid of // influence from other gestures (like rotate below) so we project to camera-right axis first. Frame3f camFrame = cockpit.ActiveCamera.GetWorldFrame(); Vector3 right = camFrame.X; float fOrig = Vector3.Dot((hi.rightStartF.Origin - hi.leftStartF.Origin), hi.camRight); float fCur = Vector3.Dot((input.RightHandFrame.Origin - input.LeftHandFrame.Origin), right); float deltaZAbs = fCur - fOrig; float deltaZ = (hi.bInZoomDeadzone) ? ApplyDeadzone(deltaZAbs, fZoomDeadzoneInM) : deltaZAbs - hi.fZoomShift; if (Math.Abs(deltaZ) > 0 && hi.bInZoomDeadzone) { hi.bInZoomDeadzone = false; hi.fZoomShift = deltaZAbs - deltaZ; } hi.runningZ = Mathf.Lerp(hi.runningZ, deltaZ, fTrackAlpha); float tz = hi.runningZ * fZoomScale; if (tz != 0.0f && hi.activeXForm == TransformType.NoTransform) { hi.activeXForm = TransformType.Zoom; } // translation is done by moving both hands in unison. We find the midpoint // of the start and current pairs, delta is translate Vector3f cOrig = 0.5f * (hi.leftStartF.Origin + hi.rightStartF.Origin); Vector3f cCur = 0.5f * (input.LeftHandFrame.Origin + input.RightHandFrame.Origin); Vector3f translateO = cCur - cOrig; Vector3f translate = (hi.bInPanDeadzone) ? ApplyDeadzone(translateO, fPanDeadzoneInM) : translateO - hi.vPanShift; if (translate.LengthSquared > 0 && hi.bInPanDeadzone) { hi.bInPanDeadzone = false; hi.vPanShift = translateO - translate; } hi.runningT = Vector3.Lerp(hi.runningT, translate, fTrackAlpha); Vector3f tx = hi.runningT * fPanScale * fSceneScale; if (tx.Length != 0.0f && hi.activeXForm == TransformType.NoTransform) { hi.activeXForm = TransformType.Pan; } // azimuth (left/right rotate) is specified by making a spin-the-wheel gesture, // where one hand slides forward and the other back. We guess a center-of-rotation // as the midpoint of the start and current frames, and then average the two rotation // angles in the XZ plane (by the vectors on the left and right sides). // *But* if there is also a translation, this goes wonky, so we have to subtract // of the translation first! // (above only applies if we permit simultaneous rotate & translate, which is currently disabled...) //Vector3 rotTranslate = translate; Vector3f rotTranslate = Vector3.zero; Vector3f origCenterXY = new Vector3(cOrig[0], 0, cOrig[2]); Vector3f shiftLeftO = input.LeftHandFrame.Origin - rotTranslate; Vector3f shiftRightO = input.RightHandFrame.Origin - rotTranslate; Vector3f shiftCenter = 0.5f * (shiftLeftO + shiftRightO); Vector3f curCenterXY = new Vector3(shiftCenter[0], 0, shiftCenter[2]); Vector3f sharedC = 0.5f * (origCenterXY + curCenterXY); float aLeft = VRUtil.PlaneAngleSigned(hi.leftStartF.Origin - sharedC, shiftLeftO - sharedC, 1); float aRight = VRUtil.PlaneAngleSigned(hi.rightStartF.Origin - sharedC, shiftRightO - sharedC, 1); float azO = -(aLeft + aRight) * 0.5f; float az = (hi.bInAzimuthDeadzone) ? ApplyDeadzone(azO, fAzimuthDeadzoneInDeg) : azO - hi.fAzimuthShift; if (Math.Abs(az) > 0 && hi.bInAzimuthDeadzone) { hi.bInAzimuthDeadzone = false; hi.fAzimuthShift = azO - az; } hi.runningAz = Mathf.Lerp(hi.runningAz, az, fTrackAlpha); float fAzimuth = hi.runningAz; if (fAzimuth != 0.0f && hi.activeXForm == TransformType.NoTransform) { hi.activeXForm = TransformType.Rotate; } // altitude (up/down rotate) is specified by tilting controllers up or down. // This is the trickiest one as hands tend to tilt up/down during the other actions. // We compute an average tilt up/down angle at the start, and then the per-hand delta // each frame, as well as the average delta, and use the smallest of these. // mean hand-tilt at start frame float o1 = VRUtil.PlaneAngleSigned(hi.leftStartF.Rotation * Vector3.forward, hi.camForward, hi.camRight); float o2 = VRUtil.PlaneAngleSigned(hi.rightStartF.Rotation * Vector3.forward, hi.camForward, hi.camRight); float oa = (o1 + o2) * 0.5f; // per-frame hand tilt Vector3 camfw = camFrame.Z, camright = camFrame.X; float c1 = VRUtil.PlaneAngleSigned(input.LeftHandFrame.Rotation * Vector3.forward, camfw, camright); float c2 = VRUtil.PlaneAngleSigned(input.RightHandFrame.Rotation * Vector3.forward, camfw, camright); // use the smallest per-hand tilt delta, to prevent one-hand tilting from having an effect float d1 = oa - c1, d2 = oa - c2; float altO = (Mathf.Abs(d1) < Mathf.Abs(d2)) ? d1 : d2; // also consider the average, to reduce crazy popping from each hand tilting in opposite direction float dm = 0.5f * (d1 + d2); altO = (Mathf.Abs(altO) < Mathf.Abs(dm)) ? altO : dm; // deadzone and smoothing float alt = (hi.bInAltitudeDeadzone) ? ApplyDeadzone(altO, fAltitudeDeadzoneInDeg) : altO - hi.fAltitudeShift; if (Math.Abs(alt) > 0 && hi.bInAltitudeDeadzone) { hi.bInAltitudeDeadzone = false; hi.fAltitudeShift = altO - alt; } hi.runningAlt = Mathf.Lerp(hi.runningAlt, alt, fTrackAlpha); float fAltitude = hi.runningAlt; if (fAltitude != 0.0f && hi.activeXForm == TransformType.NoTransform) { hi.activeXForm = TransformType.Rotate; } // reset view to state when we started, then apply the accumulated rotate/zoom/translate cockpit.ActiveCamera.Manipulator().SetCurrentSceneState(cockpit.Scene, hi.camState); if (hi.activeXForm == TransformType.Rotate) { cockpit.ActiveCamera.Manipulator().SceneOrbit(cockpit.Scene, cockpit.ActiveCamera, fAzimuth, fAltitude); } else if (hi.activeXForm == TransformType.Pan) { cockpit.ActiveCamera.Manipulator().SceneTranslate(cockpit.Scene, tx, false); } else if (hi.activeXForm == TransformType.Zoom) { cockpit.ActiveCamera.Manipulator().SceneZoom(cockpit.Scene, cockpit.ActiveCamera, tz); } return(Capture.Continue); }