protected override void StartHaptics(HumanBodyBones bodyPart, BodyCoordinateHit hitLocation, float intensity)
        {
            int hitIndex = affectedBodyPart.BodyCoordinateHitIndex(bodyPart, hitLocation);

            // If -1 is returned, then the hitLocation is not in the CoordinateSpace that the device is attached to
            if (hitIndex == -1)
            {
                return;
            }

            // Assign the intensity value for each of the mapped effector
            for (int n = 0; n < bhapticsMapping.mapping[hitIndex].indexMapping.Length; n++)
            {
                // The intensity needs to be between 0 and 100, so convert the intensity to that range
                hapticBytes[bhapticsMapping.mapping[hitIndex].indexMapping[n]] = (byte)(intensity * 100);
            }

            // Assign the intensity values and play
#if VRTK_DEFINE_SDK_BHAPTICS
            tactSource.DotPoints = hapticBytes;
            tactSource.Play();
#endif

            // Clear the array since it will need different values on the next frame
            hapticBytes = new byte[HAPTIC_ACTUATOR_COUNT];
        }
        /// <summary>
        /// Provides the hit location (angle and height) values for all the curve values in the pattern for a specified time
        /// </summary>
        /// <param name="currentTime">The timing information</param>
        /// <returns>An array of BodyCoordinateHit value for each curve in the pattern</returns>
        public BodyCoordinateHit[] GetHitLocationsAtCurrentTime(float currentTime)
        {
            // Get the hit location for each curve
            for (int n = 0; n < curveList.Count; n++)
            {
                BodyCoordinateHit hitLocation = curveList[n].GetHitLocationAtTime(currentTime);

                // Adjust the hitLocation based on the offset
                switch (offsetUse)
                {
                case OffsetUse.SetAtFirstPoint:
                    // Get the difference between the offset and the first point
                    float heightDifference = hitOffset.hitHeight - curveList[n].heightCurve[0].value;
                    float angleDifference  = hitOffset.hitAngle - curveList[n].angleCurve[0].value;

                    // Apply the difference to the current hit location
                    hitLocation.hitHeight += heightDifference;
                    hitLocation.hitAngle  += angleDifference;

                    break;
                }

                // Adjust the hitLocation based on the overshoot resolution for the height
                hitLocation.hitHeight = AdjustHitLocation(hitLocation.hitHeight, 0.0f, 1.0f, heightOvershootResolution);

                // Adjust the hitLocation based on the overshoot resolution for the angle
                hitLocation.hitAngle = AdjustHitLocation(hitLocation.hitAngle, 0.0f, 360.0f, angleOvershootResolution);

                hitLocationBuffer[n] = hitLocation;
            }

            return(hitLocationBuffer);
        }
Example #3
0
        /// <summary>
        /// Checks to see if the given body part that was hit has a device that should be triggered. If it does,
        /// it tells that device to play their haptic for that hit location.
        /// </summary>
        /// <param name="bodyLocation">The body part that was hit</param>
        /// <param name="hitLocation">The height/angle of the hit on the body part</param>
        public void BodyPartHit(HumanBodyBones bodyLocation, BodyCoordinateHit hitLocation, ScriptableHapticPattern hapticPattern = null)
        {
            // Check to make sure this body part isn't ignored
            if (ignoreBoneSet.Contains(bodyLocation))
            {
                return;
            }

            if (bodyAffectedByDevice.ContainsKey(bodyLocation))
            {
                // Tell every device that has this body part to trigger the haptics at the given location
                for (int n = 0; n < bodyAffectedByDevice[bodyLocation].Count; n++)
                {
                    // Check to make sure this haptic device isn't ignored
                    if (ignoreHapticDevices.Contains(bodyAffectedByDevice[bodyLocation][n]))
                    {
                        return;
                    }

                    if (hapticPattern == null)
                    {
                        bodyAffectedByDevice[bodyLocation][n].TriggerDevice(bodyLocation, hitLocation, 0.5f);
                    }
                    else
                    {
                        bodyAffectedByDevice[bodyLocation][n].TriggerDevice(bodyLocation, hitLocation, hapticPattern);
                    }
                }
            }
        }
 /// <summary>
 /// A single haptic pulse that is triggered by an object hitting a body part that has been
 /// set up to recieve haptic events.
 /// </summary>
 /// <param name="bodyPart">The body part of the hit</param>
 /// <param name="hitLocation">The body coordinate system hit</param>
 /// <param name="intensity">The intensity to play the haptic vibration</param>
 public void TriggerDevice(HumanBodyBones bodyPart, BodyCoordinateHit hitLocation, float intensity)
 {
     if (affectedBodyPart.HitInsideAffectedArea(bodyPart, hitLocation))
     {
         StartHaptics(bodyPart, hitLocation, intensity);
     }
 }
 public void OnBodyPartHit(BodyCoordinate bodyCoordinate, BodyCoordinateHit hitInfo, Vector3 hitLocation)
 {
     if (BodyPartHit != null)
     {
         BodyPartHit(this, new HapticInformation(bodyCoordinate, hitInfo, hitLocation));
     }
 }
        protected override void StartHaptics(HumanBodyBones bodyPart, BodyCoordinateHit hitLocation, float intensity)
        {
#if VRTK_DEFINE_STEAMVR_PLUGIN_2_0_0_OR_NEWER && VRTK_DEFINE_STEAMVR_INPUT_COMPILED
            vibration.Execute(0.0f, hapticDuration / Constants.MS_TO_SECONDS, frequency, intensity, trackedObject.inputSource);
#elif VRTK_DEFINE_STEAMVR_PLUGIN_LEGACY
            SteamVR_Controller.Input((int)trackedObject.index).TriggerHapticPulse((ushort)(intensity * VIVE_VIBRATION_VALUE));
#endif
        }
        /// <summary>
        /// Plays a pattern that is triggered by an object hitting a body part that has been
        /// set up to recieve haptic events.
        /// </summary>
        /// <param name="bodyPart">The body part of the hit</param>
        /// <param name="hitLocation">The body coordinate system hit</param>
        /// <param name="hapticPattern">The haptic pattern</param>
        public void TriggerDevice(HumanBodyBones bodyPart, BodyCoordinateHit hitLocation, ScriptableHapticPattern hapticPattern)
        {
            if (bodyPart == affectedBodyPart.affectableBodyParts)
            {
                hapticPattern.hitOffset = hitLocation;

                PlayPattern(bodyPart, hapticPattern);
            }
        }
Example #8
0
        protected override void StartHaptics(HumanBodyBones bodyPart, BodyCoordinateHit hitLocation, float intensity)
        {
#if VRTK_DEFINE_SDK_MANUS_VR
            Manus.ManusSetVibration(handData.Session,
                                    isRightGlove ? device_type_t.GLOVE_RIGHT : device_type_t.GLOVE_LEFT,
                                    intensity,
                                    (ushort)hapticDuration);
#endif
        }
Example #9
0
        private void OnCollisionEnter(Collision collision)
        {
            BodyCoordinateHit            bodyHit    = CalculateBodyCoordinateHitFromPosition(collision.contacts[0].point);
            HapticPatternCollisionHolder hitPattern = collision.gameObject.GetComponent <HapticPatternCollisionHolder>();

            if (hitPattern != null)
            {
                manager.BodyPartHit(attachedBody, bodyHit, hitPattern.GetHapticPattern());
            }
            else
            {
                manager.BodyPartHit(attachedBody, bodyHit);
            }
        }
 public bool HitInsideSpace(BodyCoordinateHit hitLocation)
 {
     if (hitLocation.hitHeight >= startHeight &&
         hitLocation.hitHeight <= endHeight &&
         hitLocation.hitAngle >= startAngle &&
         hitLocation.hitAngle <= endAngle)
     {
         return(true);
     }
     else
     {
         return(false);
     }
 }
Example #11
0
        protected override void StartHaptics(HumanBodyBones bodyPart, BodyCoordinateHit hitLocation, float intensity)
        {
#if VRTK_DEFINE_SDK_SENSE_GLOVE
            int fingerIndex = FindHitFingerIndex(bodyPart);

            if (fingerIndex != -1)
            {
                fingers[fingerIndex]     = true;
                intensities[fingerIndex] = (int)(intensity * 100);
                duration[fingerIndex]    = hapticDuration;
            }

            glove.SendBuzzCmd(fingers, intensities, duration);
#endif
        }
Example #12
0
        public int BodyCoordinateHitIndex(HumanBodyBones hitBone, BodyCoordinateHit hitLocation)
        {
            // Check if it's on the same bone
            if (hitBone == affectableBodyParts)
            {
                for (int n = 0; n < affectedAreaList.Count; n++)
                {
                    // Check if it's an affect area on the same bone
                    if (affectedAreaList[n].HitInsideSpace(hitLocation))
                    {
                        return(n);
                    }
                }
            }

            return(-1);
        }
Example #13
0
        protected override void StartHaptics(HumanBodyBones bodyPart, BodyCoordinateHit hitLocation, float intensity)
        {
#if VRTK_DEFINE_SDK_OCULUS
            if (isLeftController)
            {
                hapticsClipLeft.Reset();
                hapticsClipLeft.WriteSample((byte)(intensity * byte.MaxValue));
                OVRHaptics.LeftChannel.Preempt(hapticsClipLeft);
            }
            else
            {
                hapticsClipRight.Reset();
                hapticsClipRight.WriteSample((byte)(intensity * byte.MaxValue));
                OVRHaptics.RightChannel.Preempt(hapticsClipRight);
            }
#endif
        }
Example #14
0
 protected override void StartHaptics(HumanBodyBones bodyPart, BodyCoordinateHit hitLocation, float intensity)
 {
     if (IsHapticDeviceValid())
     {
         HapticCapabilities hapticCapabilities;
         if (hapticDevice.TryGetHapticCapabilities(out hapticCapabilities) && hapticCapabilities.supportsImpulse)
         {
             bool successful = hapticDevice.SendHapticImpulse(hapticChannel, intensity);
             if (!successful)
             {
                 Debug.LogWarningFormat("Unity XR Haptic Device {0} failed to play haptics");
             }
         }
     }
     else
     {
         Debug.LogWarningFormat("Unity XR Haptic Device for the {0} failed to play haptics: device is invalid", handNodeType.ToString());
     }
 }
Example #15
0
        /// <summary>
        /// Calculates the world position of a BodyCoordinateHit.
        /// </summary>
        /// <param name="bodyHit">The height and angle of the collider to find the position</param>
        /// <param name="accountForCapsule">If true, the position should account for the circle ends on the capsule</param>
        /// <returns>The world position based on the collider and provided body hit</returns>
        public Vector3 CalculatePositionFromBodyCoordinateHit(BodyCoordinateHit bodyHit, bool accountForCapsule = false)
        {
            float   heightPosition = CalculatePositionFromNormalizedHeight(bodyHit.hitHeight);
            Vector3 radius         = CalculatePositionFromAngle(bodyHit, heightPosition, accountForCapsule);

            switch (capCollider.direction)
            {
            // X Axis
            case 0:
                return(new Vector3(heightPosition, radius.y, radius.z));

            // Y Axis
            case 1:
                return(new Vector3(radius.x, heightPosition, radius.z));

            // Z Axis
            case 2:
                return(new Vector3(radius.x, radius.y, heightPosition));

            default:
                return(Vector3.zero);
            }
        }
Example #16
0
        protected override void StartHaptics(HumanBodyBones bodyPart, BodyCoordinateHit hitLocation, float intensity)
        {
#if VRTK_DEFINE_SDK_OCULUS
            if (hapticsClipLeft == null || hapticsClipRight == null)
            {
                OVRHaptics.Config.Load();
                hapticsClipLeft  = new OVRHapticsClip();
                hapticsClipRight = new OVRHapticsClip();
            }

            int clipLengthBytes =
                Mathf.Min(
                    Mathf.Max(OVRHaptics.Config.SampleRateHz * hapticDuration, OVRHaptics.Config.MinimumBufferSamplesCount),
                    OVRHaptics.Config.MaximumBufferSamplesCount
                    );

            if (isLeftController)
            {
                hapticsClipLeft.Reset();
                for (int i = 0; i < clipLengthBytes; i++)
                {
                    hapticsClipLeft.WriteSample((byte)(intensity * byte.MaxValue));
                }
                OVRHaptics.LeftChannel.Preempt(hapticsClipLeft);
            }
            else
            {
                hapticsClipRight.Reset();
                for (int i = 0; i < clipLengthBytes; i++)
                {
                    hapticsClipRight.WriteSample((byte)(intensity * byte.MaxValue));
                }
                OVRHaptics.RightChannel.Preempt(hapticsClipRight);
            }
#endif
        }
 /// <summary>
 /// How the device plays a single haptic pulse
 /// </summary>
 /// <param name="hitLocation">The hit location in the BodyCoordinate space</param>
 /// <param name="intensity">The normalized (0-1) intensity value</param>
 protected abstract void StartHaptics(HumanBodyBones bodyPart, BodyCoordinateHit hitLocation, float intensity);
Example #18
0
 protected override void StartHaptics(HumanBodyBones bodyPart, BodyCoordinateHit hitLocation, float intensity)
 {
     // no op
 }
        public void GetMouseClicks(SceneView sceneView)
        {
            // Only care about mouse down events
            if (Event.current.type != EventType.MouseDown)
            {
                return;
            }

            // convert GUI coordinates to screen coordinates
            Vector3 screenPosition       = Event.current.mousePosition;
            Vector3 cameraScreenPosition = screenPosition;

            cameraScreenPosition.y = Camera.current.pixelHeight - cameraScreenPosition.y;

            Ray        ray = Camera.current.ScreenPointToRay(cameraScreenPosition);
            RaycastHit hit;

            // Wait for double clicks on left mouse
            if (Event.current.clickCount == 2 && Event.current.button == 0)
            {
                // Cast ray into the scene
                if (Physics.Raycast(ray, out hit))
                {
                    Event.current.Use();

                    BodyCoordinate bodyPart = hit.collider.GetComponent <BodyCoordinate>();

                    if (bodyPart != null)
                    {
                        BodyCoordinateHit hitLocation = bodyPart.CalculateBodyCoordinateHitFromPosition(hit.point);

                        OnBodyPartHit(bodyPart, hitLocation, hit.point);

                        return;
                    }

                    BodyHitUI uiHit = hit.collider.GetComponent <BodyHitUI>();

                    if (uiHit != null)
                    {
                        // Make sure that another UI is not already displaying
                        lastUIHit?.HideUI(screenPosition, true);

                        lastUIHit = uiHit;

                        lastUIHit.DisplayUI(screenPosition);
                        return;
                    }
                }
            }
            else if (Event.current.clickCount == 1)
            {
                // Close the hitUI if they click outside of it
                if (lastUIHit != null)
                {
                    // Right/middle clicks will force close the UI
                    bool wasHidden = (Event.current.button != 0) ? lastUIHit.HideUI(screenPosition, true) : lastUIHit.HideUI(screenPosition);

                    if (wasHidden)
                    {
                        lastUIHit = null;
                    }
                }
            }
        }
 public BodyCoordinateHit(BodyCoordinateHit otherHit)
 {
     hitHeight = otherHit.hitHeight;
     hitAngle  = otherHit.hitAngle;
 }
 /// <summary>
 /// Adds a keyframe to the Haptic Pattern at the specified time.
 /// </summary>
 /// <param name="time">The time for the keyframe</param>
 /// <param name="location">The hit angle and height</param>
 /// <param name="intensity">The intensity between 0 and 1</param>
 public void AddKey(float time, BodyCoordinateHit location, float intensity)
 {
     heightCurve.AddKey(time, location.hitHeight);
     angleCurve.AddKey(time, location.hitAngle);
     intensityCurve.AddKey(time, intensity);
 }
Example #22
0
        private Vector3 CalculatePositionFromAngle(BodyCoordinateHit bodyHit, float heightPosition = 0.0f, bool positionOnCapsule = false)
        {
            // Short circuit, if the height is at the extremes, then it will be at the poles
            if (positionOnCapsule)
            {
                if (bodyHit.hitHeight == 0.0f)
                {
                    return(transform.TransformPoint(ProximalPosition));
                }
                else if (bodyHit.hitHeight == 1.0f)
                {
                    return(transform.TransformPoint(DistalPosition));
                }
            }

            // Calculate the directional vector towards the hit point
            Vector3 rotationDirection = Vector3.zero;

            if (invertAngleDirection)
            {
                bodyHit.hitAngle = 360 - bodyHit.hitAngle;
            }

            switch (capCollider.direction)
            {
            // X Axis
            case 0:
                rotationDirection = Quaternion.AngleAxis(bodyHit.hitAngle, transform.right) * polarAxis;
                break;

            // Y Axis
            case 1:
                rotationDirection = Quaternion.AngleAxis(bodyHit.hitAngle, transform.up) * polarAxis;
                break;

            // Z Axis
            case 2:
                rotationDirection = Quaternion.AngleAxis(bodyHit.hitAngle, transform.forward) * polarAxis;
                break;
            }

            // Account for the angle of the collider
            Vector3 positionByAngle = rotationDirection * capCollider.radius;

            // Since the capsule has two circles at the ends, make sure the position is along the curve on the circle if required
            if (positionOnCapsule)
            {
                // Don't bother doing this if new height is not at one of the circles extremes
                float radiusNormalizedPerHeight = capCollider.radius / capCollider.height;

                if (bodyHit.hitHeight >= radiusNormalizedPerHeight && bodyHit.hitHeight <= (1 - radiusNormalizedPerHeight))
                {
                    return(transform.TransformPoint(positionByAngle));
                }

                // Get the transform that is aligned with this point along the axis
                Vector3 leveledTransform = transform.TransformPoint(capCollider.center);

                switch (capCollider.direction)
                {
                case 0:     // X Axis
                    leveledTransform = new Vector3(heightPosition, leveledTransform.y, leveledTransform.z);
                    positionByAngle  = new Vector3(heightPosition, positionByAngle.y, positionByAngle.z);
                    break;

                case 1:     // Y Axis
                    leveledTransform = new Vector3(leveledTransform.x, heightPosition, leveledTransform.z);
                    positionByAngle  = new Vector3(positionByAngle.x, heightPosition, positionByAngle.z);
                    break;

                case 2:     // Z Axis
                    leveledTransform = new Vector3(leveledTransform.x, leveledTransform.y, heightPosition);
                    positionByAngle  = new Vector3(positionByAngle.x, positionByAngle.y, heightPosition);
                    break;
                }

                // Get the direction from the point towards the transform
                Vector3 directionTowardsCapsule = leveledTransform - positionByAngle;

                RaycastHit[] hitInfo;

                // Shoot a ray to find the edge of the capsule collider in the calculated direction
                hitInfo = Physics.RaycastAll(positionByAngle, directionTowardsCapsule.normalized, .5f);

                for (int n = 0; n < hitInfo.Length; n++)
                {
                    if (hitInfo[n].collider.gameObject.name == "Capsule")
                    {
                        // Move the positionByAngle in the direction towards the transform at the proper distance
                        positionByAngle += (directionTowardsCapsule.normalized * hitInfo[n].distance);
                    }
                }
            }

            return(transform.TransformPoint(positionByAngle));
        }
 private void OnDisable()
 {
     // Don't keep a saved offset value since it's only set by a collision
     hitOffset = new BodyCoordinateHit();
 }
 /// <summary>
 /// Adds a keyframe to the pattern for a given curve
 /// </summary>
 /// <param name="curveIndex">The curve index to add the keyframe to</param>
 /// <param name="time">The timing for the new keyframe</param>
 /// <param name="location">The height/angle of the keyframe</param>
 /// <param name="intensity">The intensity value of the keyframe</param>
 public void AddKey(int curveIndex, float time, BodyCoordinateHit location, float intensity)
 {
     curveList[curveIndex].AddKey(time, location, intensity);
 }
 public HapticFeedbackEventArgs(HumanBodyBones body, BodyCoordinateHit hit, float intense)
 {
     bodyPart          = body;
     hitLocation       = hit;
     feedbackIntensity = intense;
 }
 public HapticInformation(BodyCoordinate bodyCoordinate, BodyCoordinateHit hitInfo, Vector3 hitLocation)
 {
     bodyPart         = bodyCoordinate;
     bodyHitInfo      = hitInfo;
     worldHitLocation = hitLocation;
 }