예제 #1
0
        public override void OverrideRayEndPoint(Ray ray, ref Vector3 rayEndPoint)
        {
            bool triggerJustClicked  = false;
            bool triggerJustReleased = false;

            VRInput.GetInstantButtonEvent(VRInput.primaryController, CommonUsages.triggerButton, ref triggerJustClicked, ref triggerJustReleased);

            // Project ray on the widget plane.
            Plane widgetPlane = new Plane(-transform.forward, transform.position);

            widgetPlane.Raycast(ray, out float enter);
            Vector3 worldCollisionOnWidgetPlane = ray.GetPoint(enter);

            Vector3 localWidgetPosition          = transform.InverseTransformPoint(worldCollisionOnWidgetPlane);
            Vector3 localProjectedWidgetPosition = new Vector3(localWidgetPosition.x, localWidgetPosition.y, 0.0f);

            if (IgnoreRayInteraction())
            {
                rayEndPoint = transform.TransformPoint(localProjectedWidgetPosition);
                return;
            }


            //Vector2 localCenter = new Vector2(width / 2.0f, -height / 2.0f);
            Vector2 project = new Vector3(localWidgetPosition.x, localWidgetPosition.y);

            if (triggerJustClicked)
            {
                grippedPos = project;
            }

            if (Vector2.Distance(project, grippedPos) < 3.0f * height)
            {
                grippedUnderThreshold          = true;
                localProjectedWidgetPosition.x = grippedPos.x;
                localProjectedWidgetPosition.y = grippedPos.y;
            }
            else
            {
                grippedUnderThreshold = false;
            }

            Vector3 worldProjectedWidgetPosition = transform.TransformPoint(localProjectedWidgetPosition);

            rayEndPoint = worldProjectedWidgetPosition;
        }
예제 #2
0
파일: UITimeBar.cs 프로젝트: ubisoft/vrtist
        public override void OverrideRayEndPoint(Ray ray, ref Vector3 rayEndPoint)
        {
            bool triggerJustClicked  = false;
            bool triggerJustReleased = false;

            VRInput.GetInstantButtonEvent(VRInput.primaryController, CommonUsages.triggerButton, ref triggerJustClicked, ref triggerJustReleased);

            // Project ray on the widget plane.
            Plane widgetPlane = new Plane(-transform.forward, transform.position);
            float enter;

            widgetPlane.Raycast(ray, out enter);
            Vector3 worldCollisionOnWidgetPlane = ray.GetPoint(enter);

            Vector3 localWidgetPosition          = transform.InverseTransformPoint(worldCollisionOnWidgetPlane);
            Vector3 localProjectedWidgetPosition = new Vector3(localWidgetPosition.x, localWidgetPosition.y, 0.0f);

            if (IgnoreRayInteraction())
            {
                // return endPoint at the surface of the widget.
                rayEndPoint = transform.TransformPoint(localProjectedWidgetPosition);
                return;
            }

            float startX = 0;
            float endX   = width;

            float currentValuePct      = (float)(Value - minValue) / (float)(maxValue - minValue);
            float currentKnobPositionX = startX + currentValuePct * (endX - startX);

            // TODO: apply drag directly on the Value and previous Value.

            // DRAG

            if (!triggerJustClicked && lerp)
            {
                localProjectedWidgetPosition.x = Mathf.Lerp(currentKnobPositionX, localProjectedWidgetPosition.x, GlobalState.Settings.RaySliderDrag);
            }

            // CLAMP

            if (localProjectedWidgetPosition.x < startX)
            {
                localProjectedWidgetPosition.x = startX;
            }

            if (localProjectedWidgetPosition.x > endX)
            {
                localProjectedWidgetPosition.x = endX;
            }

            // Compute closest int for snapping.
            float pct          = (localProjectedWidgetPosition.x - startX) / (endX - startX);
            float fValue       = (float)minValue + pct * (float)(maxValue - minValue);
            int   roundedValue = Mathf.RoundToInt(fValue);

            // SNAP X to closest int
            localProjectedWidgetPosition.x = startX + ((float)roundedValue - minValue) * (endX - startX) / (float)(maxValue - minValue);
            // SNAP Y to middle of knob object. TODO: use actual knob dimensions
            localProjectedWidgetPosition.y = -height + 0.02f;
            // SNAP Z to the thickness of the knob
            localProjectedWidgetPosition.z = -0.005f;

            // SET
            if (roundedValue != GlobalState.Animation.CurrentFrame)
            {
                onSlideEvent.Invoke(roundedValue);
                if (triggerJustClicked)
                {
                    lerp = false;
                }
            }

            // Haptic intensity as we go deeper into the widget.
            //float intensity = Mathf.Clamp01(0.001f + 0.999f * localWidgetPosition.z / UIElement.collider_min_depth_deep);
            //intensity *= intensity; // ease-in

            //VRInput.SendHaptic(VRInput.rightController, 0.005f, intensity);

            Vector3 worldProjectedWidgetPosition = transform.TransformPoint(localProjectedWidgetPosition);

            rayEndPoint = worldProjectedWidgetPosition;
        }
예제 #3
0
        public override void OverrideRayEndPoint(Ray ray, ref Vector3 rayEndPoint)
        {
            bool triggerJustClicked  = false;
            bool triggerJustReleased = false;

            VRInput.GetInstantButtonEvent(VRInput.primaryController, CommonUsages.triggerButton, ref triggerJustClicked, ref triggerJustReleased);

            // Project ray on the widget plane.
            Plane widgetPlane = new Plane(-transform.forward, transform.position);
            float enter;

            widgetPlane.Raycast(ray, out enter);
            Vector3 worldCollisionOnWidgetPlane = ray.GetPoint(enter);

            Vector3 localWidgetPosition          = transform.InverseTransformPoint(worldCollisionOnWidgetPlane);
            Vector3 localProjectedWidgetPosition = new Vector3(localWidgetPosition.x, localWidgetPosition.y, 0.0f);

            if (IgnoreRayInteraction())
            {
                // return endPoint at the surface of the widget.
                rayEndPoint = transform.TransformPoint(localProjectedWidgetPosition);
                return;
            }

            float widthWithoutMargins = width - 2.0f * margin;
            float startX = margin + widthWithoutMargins * sliderPositionBegin + railMargin;
            float endX   = margin + widthWithoutMargins * sliderPositionEnd - railMargin;

            // SPAWN KEYBOARD

            if (triggerJustClicked && localProjectedWidgetPosition.x > endX)
            {
                ToolsUIManager.Instance.OpenNumericKeyboard(OnValidateKeyboard, transform, (float)Value);
                rayEndPoint = transform.TransformPoint(localProjectedWidgetPosition);
                return;
            }

            // DRAG

            if (!triggerJustClicked) // if trigger just clicked, use the actual projection, no interpolation.
            {
                float drag = GlobalState.Settings.RaySliderDrag;
                localProjectedWidgetPosition.x = Mathf.Lerp(lastProjected, localProjectedWidgetPosition.x, drag);
            }
            lastProjected = localProjectedWidgetPosition.x;


            // CLAMP

            if (localProjectedWidgetPosition.x < startX)
            {
                localProjectedWidgetPosition.x = startX;
            }

            if (localProjectedWidgetPosition.x > endX)
            {
                localProjectedWidgetPosition.x = endX;
            }

            localProjectedWidgetPosition.y = -height / 2.0f;

            // SET

            float pct = (localProjectedWidgetPosition.x - startX) / (endX - startX);

            if (HasCurveData())
            {
                Value = dataCurve.Evaluate(pct);
            }
            else // linear
            {
                float v = minValue + pct * (maxValue - minValue);
                Value = v; // will replace the slider cursor.
            }
            onSlideEvent.Invoke(currentValue);
            int intValue = Mathf.RoundToInt(currentValue);

            onSlideEventInt.Invoke(intValue);

            // OUT ray end point

            Vector3 worldProjectedWidgetPosition = transform.TransformPoint(localProjectedWidgetPosition);

            rayEndPoint = worldProjectedWidgetPosition;
        }
예제 #4
0
        private void HandleRaycast()
        {
            // TODO:
            // - audioClick.Play(); ????
            // - VRInput.SendHaptic(VRInput.rightController, 0.005f, intensity); ???

            //
            // Find out if the trigger button was pressed, in order to send the info the the widget hit.
            //

            bool triggerJustClicked  = false;
            bool triggerJustReleased = false;

            VRInput.GetInstantButtonEvent(VRInput.primaryController, CommonUsages.triggerButton, ref triggerJustClicked, ref triggerJustReleased);

            //
            // Raycast, find out the closest volume, handle and widget.
            //

            Vector3 worldStart        = transform.TransformPoint(0.0104f, 0, 0.065f);
            Vector3 worldEnd          = transform.TransformPoint(0.0104f, 0, 1f);
            Vector3 newWorldDirection = worldEnd - worldStart;
            Vector3 worldDirection    = prevWorldDirection != Vector3.zero ? Vector3.Lerp(prevWorldDirection, newWorldDirection, rayStiffness) : newWorldDirection;

            worldDirection.Normalize();
            prevWorldDirection = worldDirection;
            Vector3 rayEndPoint = worldEnd;

            Ray r = new Ray(worldStart, worldDirection);

            if (UIElement.UIEnabled.Value)
            {
                // If a widget is locked (trigger has been pressed on it), give it a chance to handle the ray endpoint.
                if (WidgetIsClicked && widgetClicked.OverridesRayEndPoint())
                {
                    widgetClicked.OverrideRayEndPoint(r, ref rayEndPoint);
                }
            }

            // Lambda to avoid copy-paste.
            System.Action handleHitNothing = () =>
            {
                if (WidgetIsClicked && widgetClicked.OverridesRayEndPoint())
                {
                    ActivateRay(true);
                    ray.SetParameters(worldStart, rayEndPoint, newWorldDirection);
                }
                else
                {
                    ActivateRay(false);
                    ReleaseUIEnabledGuard(); // release the guard if there was one.
                }
                HandleRayOutOfWidget(triggerJustReleased);
            };

            //
            // First, try to hit anything, in order to findout if we hit a Non-UI object first.
            //

            RaycastHit hitInfo;
            int        allLayersMask = -1; // ~0

            float scale = 1f / GlobalState.WorldScale;

            if (!Physics.Raycast(r, out hitInfo, 3.0f * scale, allLayersMask, QueryTriggerInteraction.Collide))
            {
                // Nothing hit
                HandleHoverPhysicObject(null);
                handleHitNothing();
                return;
            }

            bool UIHit = (null != hitInfo.transform.gameObject.GetComponent <UIElement>()) ||
                         (null != hitInfo.transform.gameObject.GetComponent <UIHandle>()) ||
                         (null != hitInfo.transform.gameObject.GetComponent <UIVolumeTag>());

            if (!UIHit)
            {
                // hit a non-UI object.
                HandleHoverPhysicObject(null);
                handleHitNothing();
                return;
            }

            // detect if the first ray was shoot from inside an object
            Ray   backRay   = new Ray(hitInfo.point - 0.01f * worldDirection, -worldDirection);
            float d         = hitInfo.distance - 0.01f;
            bool  raycastOK = Physics.Raycast(backRay, out hitInfo, hitInfo.distance, allLayersMask, QueryTriggerInteraction.Collide);

            if (raycastOK && hitInfo.distance < d)
            {
                HandleHoverPhysicObject(null);
                handleHitNothing();
                return;
            }

            //
            // Raycast ALL UI elements
            //

            RaycastHit[] hits;
            //int layersMask = LayerMask.GetMask(new string[] { "CameraHidden", "SelectionCameraHidden", "HoverCameraHidden", "Default" });
            int layersMask = LayerMask.GetMask(new string[] { "CameraHidden", "SelectionCameraHidden", "HoverCameraHidden" });

            hits = Physics.RaycastAll(r, 3.0f * scale, layersMask, QueryTriggerInteraction.Collide);
            if (hits.Length > 0)
            {
                if (!UIElement.UIEnabled.Value)
                {
                    return;
                }

                // Ray hits anything UI, but a tool action is happening.
                // Create a guard to disable any action if not already created.
                if (CommandManager.IsUndoGroupOpened())
                {
                    if (null == uiEnabledGuard)
                    {
                        uiEnabledGuard = UIElement.UIEnabled.SetValue(false);
                    }
                    ActivateRay(false);
                    return;
                }

                bool volumeIsHit = false;
                bool widgetIsHit = false;
                bool physicIsHit = false;

                float closestVolumeDistance = Mathf.Infinity;
                float closestWidgetDistance = Mathf.Infinity;
                float closestHandleDistance = Mathf.Infinity;
                float closestPhysicDistance = Mathf.Infinity;

                Vector3 volumeCollisionPoint = Vector3.zero;
                Vector3 widgetCollisionPoint = Vector3.zero;
                Vector3 handleCollisionPoint = Vector3.zero;
                Vector3 physicCollisionPoint = Vector3.zero;

                UIElement   widget = null;
                UIHandle    handle = null;
                UIVolumeTag volume = null;
                GameObject  physic = null;

                //
                // Find if a volume/handle/widget has been hit, and compute the closest hit distance/point.
                //

                for (int i = 0; i < hits.Length; ++i)
                {
                    Transform hit = hits[i].transform;

                    UIVolumeTag volumeHit = hit.GetComponent <UIVolumeTag>();
                    if (volumeHit != null)
                    {
                        volumeIsHit = true;
                        if (hits[i].distance < closestVolumeDistance)
                        {
                            volume = volumeHit;
                            volumeCollisionPoint  = hits[i].point; // world space
                            closestVolumeDistance = hits[i].distance;
                        }
                    }

                    UIHandle handleHit = hit.GetComponent <UIHandle>();
                    if (handleHit != null)
                    {
                        if (hits[i].distance < closestHandleDistance)
                        {
                            handle = handleHit;
                            handleCollisionPoint  = hits[i].point; // world space
                            closestHandleDistance = hits[i].distance;
                        }
                    }

                    UIElement widgetHit = hit.GetComponent <UIElement>();
                    if (widgetHit != null)
                    {
                        widgetIsHit = true;
                        if (hits[i].distance < closestWidgetDistance)
                        {
                            widget = widgetHit;
                            widgetCollisionPoint  = hits[i].point; // world space
                            closestWidgetDistance = hits[i].distance;
                        }
                    }

                    GameObject objectHit = hit.gameObject;
                    if (objectHit.CompareTag("PhysicObject"))
                    {
                        physicIsHit = true;
                        if (hits[i].distance < closestPhysicDistance)
                        {
                            physic = objectHit;
                            physicCollisionPoint  = hits[i].point; // world space
                            closestPhysicDistance = hits[i].distance;
                        }
                    }
                }



                //
                // Send messages and states to the widget hit, with priorities.
                //


                //else if (handleIsHit)
                //{
                //    HandleHoverPhysicObject(null);

                //    if (WidgetIsClicked && widgetClicked.OverridesRayEndPoint())
                //    {
                //        ActivateRay(true);
                //        ray.SetParameters(worldStart, rayEndPoint, newWorldDirection);
                //    }
                //    else
                //    {
                //        ActivateRay(false);
                //    }
                //    HandleRayOutOfWidget(triggerJustReleased);
                //}
                if (widgetIsHit)
                {
                    HandleHoverPhysicObject(null);

                    if (prevWidget != widget)            // change widget
                    {
                        if (WidgetIsClicked)             // trigger is held pushed.
                        {
                            if (widgetClicked == widget) // on same widget
                            {
                                if (!widgetClicked.IgnoreRayInteraction())
                                {
                                    widgetClicked.OnRayEnterClicked(); // act as if we re-click on widget.
                                }
                            }
                            else // click has been pushed on another widget
                            {
                                if (prevWidget == widgetClicked)
                                {
                                    if (!widgetClicked.IgnoreRayInteraction())
                                    {
                                        widgetClicked.OnRayExitClicked();
                                    }
                                }
                                // dont do anything for the new widget, not even hover.
                            }
                        }
                        else // no click, simple hover
                        {
                            if (prevWidget != null)
                            {
                                if (!prevWidget.IgnoreRayInteraction())
                                {
                                    prevWidget.OnRayExit();
                                }
                            }

                            if (!widget.IgnoreRayInteraction())
                            {
                                widget.OnRayEnter();
                            }
                        }
                    }
                    else // still on same widget
                    {
                        if (WidgetIsClicked) // trigger is held pushed.
                        {
                            if (widgetClicked == widget) // on same widget
                            {
                                if (!widgetClicked.IgnoreRayInteraction())
                                {
                                    widgetClicked.OnRayHoverClicked();
                                }
                            }
                            else // still hovering a widget which is not the one clicked.
                            {
                                // TODO: should we add another state here? this is a FAKE hover.
                                //       we want to show that this was the clicked widget but the ray is elsewhere.
                                //if (!widgetClicked.IgnoreRayInteraction())
                                //widgetClicked.OnRayHover(r); // simple hover without the click effect.

                                // do nothing for the new widget.
                            }
                        }
                        else
                        {
                            if (!widget.IgnoreRayInteraction())
                            {
                                widget.OnRayHover(r);
                            }
                        }
                    }

                    // "Just click" is independant of whether we stay or change hit widget.
                    if (triggerJustClicked)
                    {
                        if (!widget.IgnoreRayInteraction())
                        {
                            widget.OnRayClick();
                            SoundManager.Instance.Play3DSound(audioSource, SoundManager.Sounds.ClickIn);
                            UIElement.ClickHapticFeedback(); // TODO: voir si on le met individuellement dans chaque widget avec des exceptions.
                        }

                        widgetClicked = widget;
                        if (widgetClicked.OverridesRayEndPoint())
                        {
                            // call this here when the "triggerJustClicked" state of VRInput is still set.
                            widgetClicked.OverrideRayEndPoint(r, ref rayEndPoint);
                        }
                    }

                    // I prefer treating "Just released" outside of the rest.
                    // BUT this leads to maybe 2 events sent for the same widget.
                    if (triggerJustReleased)
                    {
                        // do not send Release to another widget than the one which received the click.
                        if (WidgetIsClicked)
                        {
                            if (widgetClicked == widget)
                            {
                                if (!widget.IgnoreRayInteraction())
                                {
                                    widget.OnRayReleaseInside();
                                    SoundManager.Instance.Play3DSound(audioSource, SoundManager.Sounds.ClickOut);
                                    UIElement.ClickHapticFeedback();
                                }
                            }
                            else
                            {
                                // clear state of previously clicked widget
                                if (!widgetClicked.IgnoreRayInteraction())
                                {
                                    if (widgetClicked.OnRayReleaseOutside())
                                    {
                                        SoundManager.Instance.Play3DSound(audioSource, SoundManager.Sounds.ClickOut);
                                        UIElement.ClickHapticFeedback();
                                    }
                                }

                                // give the new widget a chance to play some OnHover animation.
                                if (!widget.IgnoreRayInteraction())
                                {
                                    widget.OnRayEnter();
                                }
                            }
                        }
                        else
                        {
                            Debug.LogWarning("Just Released received without having clicked before on any widget!!");
                        }

                        widgetClicked = null;
                    }

                    prevWidget = widget; // even if the same.

                    ActivateRay(true);

                    if (widget.GetComponent <UIPanel>())
                    {
                        ray.SetPanelColor();
                    }
                    else
                    {
                        ray.SetWidgetColor();
                    }

                    if (WidgetIsClicked && widgetClicked.OverridesRayEndPoint())
                    {
                        ray.SetParameters(worldStart, rayEndPoint, newWorldDirection);
                    }
                    else
                    {
                        ray.SetParameters(worldStart, widgetCollisionPoint, newWorldDirection);
                    }
                }
                else if (physicIsHit)
                {
                    if (WidgetIsClicked && widgetClicked.OverridesRayEndPoint())
                    {
                        ActivateRay(true);
                        ray.SetParameters(worldStart, rayEndPoint, newWorldDirection);
                        HandleHoverPhysicObject(null);
                    }
                    else
                    {
                        ActivateRay(true);
                        ray.SetParameters(worldStart, physicCollisionPoint, newWorldDirection);
                        HandleHoverPhysicObject(physic);
                    }
                    HandleRayOutOfWidget(triggerJustReleased);
                }
                else if (volumeIsHit)
                {
                    //HandleHoverPhysicObject(null);

                    ray.gameObject.SetActive(true);
                    if (WidgetIsClicked && widgetClicked.OverridesRayEndPoint())
                    {
                        ray.SetParameters(worldStart, rayEndPoint, newWorldDirection);
                    }
                    else
                    {
                        ray.SetVolumeColor();
                        ray.SetParameters(worldStart, worldStart + worldDirection * 0.3f, newWorldDirection); // volumeCollisionPoint
                    }

                    HandleRayOutOfWidget(triggerJustReleased);
                }
                else // Layer UI but neither UIVolumeTag nor UIElement ==> Grid or Tool Mouthpiece.
                {
                    HandleHoverPhysicObject(null);

                    if (WidgetIsClicked && widgetClicked.OverridesRayEndPoint())
                    {
                        ActivateRay(true);
                        ray.SetParameters(worldStart, rayEndPoint, newWorldDirection);
                    }
                    else
                    {
                        ActivateRay(false);
                    }
                    HandleRayOutOfWidget(triggerJustReleased);
                }
            }
            else // No collision, most common case.
            {
                HandleHoverPhysicObject(null);
                handleHitNothing();
            }
        }
예제 #5
0
        public override void OverrideRayEndPoint(Ray ray, ref Vector3 rayEndPoint)
        {
            bool triggerJustClicked  = false;
            bool triggerJustReleased = false;

            VRInput.GetInstantButtonEvent(VRInput.primaryController, CommonUsages.triggerButton, ref triggerJustClicked, ref triggerJustReleased);

            // Project ray on the widget plane.
            Plane widgetPlane = new Plane(-transform.forward, transform.position);
            float enter;

            widgetPlane.Raycast(ray, out enter);
            Vector3 worldCollisionOnWidgetPlane = ray.GetPoint(enter);

            Vector3 localWidgetPosition          = transform.InverseTransformPoint(worldCollisionOnWidgetPlane);
            Vector3 localProjectedWidgetPosition = new Vector3(localWidgetPosition.x, localWidgetPosition.y, 0.0f);

            if (IgnoreRayInteraction())
            {
                // return endPoint at the surface of the widget.
                rayEndPoint = transform.TransformPoint(localProjectedWidgetPosition);
                return;
            }

            float startX = 0;
            float endX   = width;

            float currentKnobPositionX = cursorPosition * width;

            // DRAG

            if (!triggerJustClicked) // if trigger just clicked, use the actual projection, no interpolation.
            {
                localProjectedWidgetPosition.x = Mathf.Lerp(currentKnobPositionX, localProjectedWidgetPosition.x, GlobalState.Settings.RaySliderDrag);
            }

            // CLAMP

            if (localProjectedWidgetPosition.x < startX)
            {
                localProjectedWidgetPosition.x = startX;
            }

            if (localProjectedWidgetPosition.x > endX)
            {
                localProjectedWidgetPosition.x = endX;
            }

            localProjectedWidgetPosition.y = -height / 2.0f;

            // SET

            float pct = localProjectedWidgetPosition.x / width;

            SetAlpha(Mathf.Clamp(pct, 0, 1));
            colorPicker.OnColorChanged();

            Vector3 worldProjectedWidgetPosition = transform.TransformPoint(localProjectedWidgetPosition);

            //cursorShapeTransform.position = worldProjectedWidgetPosition;
            rayEndPoint = worldProjectedWidgetPosition;
        }
예제 #6
0
        public override void OverrideRayEndPoint(Ray ray, ref Vector3 rayEndPoint)
        {
            bool triggerJustClicked  = false;
            bool triggerJustReleased = false;

            VRInput.GetInstantButtonEvent(VRInput.primaryController, CommonUsages.triggerButton, ref triggerJustClicked, ref triggerJustReleased);

            // Project ray on the widget plane.
            Plane widgetPlane = new Plane(-transform.forward, transform.position);
            float enter;

            widgetPlane.Raycast(ray, out enter);
            Vector3 worldCollisionOnWidgetPlane = ray.GetPoint(enter);

            Vector3 localWidgetPosition          = transform.InverseTransformPoint(worldCollisionOnWidgetPlane);
            Vector3 localProjectedWidgetPosition = new Vector3(localWidgetPosition.x, localWidgetPosition.y, 0.0f);

            if (IgnoreRayInteraction())
            {
                // return endPoint at the surface of the widget.
                rayEndPoint = transform.TransformPoint(localProjectedWidgetPosition);
                return;
            }

            // CLAMP

            float startX = 0.0f;
            float endX   = width;

            if (localProjectedWidgetPosition.x < startX)
            {
                localProjectedWidgetPosition.x = startX;
            }

            if (localProjectedWidgetPosition.x > endX)
            {
                localProjectedWidgetPosition.x = endX;
            }

            localProjectedWidgetPosition.y = -height / 2.0f;

            // GRIP CLOSEST Keyframe

            if (triggerJustClicked)
            {
                deltaFrame = 0;
                float distThreshold = 0.31f / 20.0f;
                closestIndex = -1;
                float closestDistance = Mathf.Infinity;
                int   i = 0;
                foreach (Transform child in transform)
                {
                    float dist = Mathf.Abs(localProjectedWidgetPosition.x - child.localPosition.x);
                    if (dist < closestDistance && dist < distThreshold)
                    {
                        closestDistance = dist;
                        closestIndex    = i;
                    }
                    i++;
                }

                if (closestIndex != -1)
                {
                    localProjectedWidgetPosition.x = transform.GetChild(closestIndex).localPosition.x;
                }
            }
            else if (triggerJustReleased)
            {
                dopesheet.OnUpdateKeyframe(closestIndex, deltaFrame);
                deltaFrame   = 0;
                closestIndex = -1;
            }
            else
            {
                // JOYSTICK Left/Right
                bool joyRightJustClicked  = false;
                bool joyRightJustReleased = false;
                bool joyRightLongPush     = false;
                VRInput.GetInstantJoyEvent(VRInput.primaryController, VRInput.JoyDirection.RIGHT, ref joyRightJustClicked, ref joyRightJustReleased, ref joyRightLongPush);

                bool joyLeftJustClicked  = false;
                bool joyLeftJustReleased = false;
                bool joyLeftLongPush     = false;
                VRInput.GetInstantJoyEvent(VRInput.primaryController, VRInput.JoyDirection.LEFT, ref joyLeftJustClicked, ref joyLeftJustReleased, ref joyLeftLongPush);

                if (joyRightJustClicked || joyLeftJustClicked || joyRightLongPush || joyLeftLongPush)
                {
                    float localDeltaOneFrame = dopesheet != null ? 0.31f / (dopesheet.LocalLastFrame - dopesheet.LocalFirstFrame) : 0.0f;
                    if (joyRightJustClicked || joyRightLongPush)
                    {
                        if (closestIndex != -1)
                        {
                            deltaFrame++;
                            Transform child            = transform.GetChild(closestIndex);
                            Vector3   newChildPosition = child.localPosition + new Vector3(+localDeltaOneFrame, 0, 0);
                            localProjectedWidgetPosition.x = newChildPosition.x;
                            child.localPosition            = newChildPosition;
                        }
                    }
                    else if (joyLeftJustClicked || joyLeftLongPush)
                    {
                        if (closestIndex != -1)
                        {
                            deltaFrame--;
                            Transform child            = transform.GetChild(closestIndex);
                            Vector3   newChildPosition = child.localPosition + new Vector3(-localDeltaOneFrame, 0, 0);
                            localProjectedWidgetPosition.x = newChildPosition.x;
                            child.localPosition            = newChildPosition;
                        }
                    }
                }
                else
                {
                    if (closestIndex != -1)
                    {
                        localProjectedWidgetPosition.x = transform.GetChild(closestIndex).localPosition.x;
                    }
                }
            }

            // OUT ray end point

            Vector3 worldProjectedWidgetPosition = transform.TransformPoint(localProjectedWidgetPosition);

            rayEndPoint = worldProjectedWidgetPosition;
        }
예제 #7
0
        public override void OverrideRayEndPoint(Ray ray, ref Vector3 rayEndPoint)
        {
            bool triggerJustClicked  = false;
            bool triggerJustReleased = false;

            VRInput.GetInstantButtonEvent(VRInput.primaryController, CommonUsages.triggerButton, ref triggerJustClicked, ref triggerJustReleased);

            // Project ray on the widget plane.
            Plane widgetPlane = new Plane(-transform.forward, transform.position);
            float enter;

            widgetPlane.Raycast(ray, out enter);
            Vector3 worldCollisionOnWidgetPlane = ray.GetPoint(enter);

            Vector3 localWidgetPosition          = transform.InverseTransformPoint(worldCollisionOnWidgetPlane);
            Vector3 localProjectedWidgetPosition = new Vector3(localWidgetPosition.x, localWidgetPosition.y, 0.0f);

            if (IgnoreRayInteraction())
            {
                // return endPoint at the surface of the widget.
                rayEndPoint = transform.TransformPoint(localProjectedWidgetPosition);
                return;
            }

            float startX = 0;
            float endX   = width;
            float startY = 0;
            float endY   = -height;

            Vector2 currentKnobPosition = new Vector2(cursorPosition.x * width, (-1.0f + cursorPosition.y) * height);

            // DRAG

            if (!triggerJustClicked) // if trigger just clicked, use the actual projection, no interpolation.
            {
                localProjectedWidgetPosition.x = Mathf.Lerp(currentKnobPosition.x, localProjectedWidgetPosition.x, GlobalState.Settings.RaySliderDrag);
                localProjectedWidgetPosition.y = Mathf.Lerp(currentKnobPosition.y, localProjectedWidgetPosition.y, GlobalState.Settings.RaySliderDrag);
            }

            // CLAMP

            if (localProjectedWidgetPosition.x < startX)
            {
                localProjectedWidgetPosition.x = startX;
            }

            if (localProjectedWidgetPosition.x > endX)
            {
                localProjectedWidgetPosition.x = endX;
            }

            if (localProjectedWidgetPosition.y > startY)
            {
                localProjectedWidgetPosition.y = startY;
            }

            if (localProjectedWidgetPosition.y < endY)
            {
                localProjectedWidgetPosition.y = endY;
            }

            // SET

            float x = localProjectedWidgetPosition.x / width;
            float y = 1.0f - (-localProjectedWidgetPosition.y / height);

            x = Mathf.Clamp(x, 0, 1);
            y = Mathf.Clamp(y, 0, 1);
            SetSaturation(new Vector2(x, y));
            colorPicker.OnColorChanged();

            // Haptic intensity as we go deeper into the widget.
            //float intensity = Mathf.Clamp01(0.001f + 0.999f * localWidgetPosition.z / UIElement.collider_min_depth_deep);
            //intensity *= intensity; // ease-in

            //VRInput.SendHaptic(VRInput.rightController, 0.005f, intensity);

            Vector3 worldProjectedWidgetPosition = transform.TransformPoint(localProjectedWidgetPosition);

            //cursorShapeTransform.position = worldProjectedWidgetPosition;
            rayEndPoint = worldProjectedWidgetPosition;
        }
예제 #8
0
        public override void OverrideRayEndPoint(Ray ray, ref Vector3 rayEndPoint)
        {
            bool triggerJustClicked  = false;
            bool triggerJustReleased = false;

            VRInput.GetInstantButtonEvent(VRInput.primaryController, CommonUsages.triggerButton, ref triggerJustClicked, ref triggerJustReleased);

            // Project ray on the widget plane.
            Plane widgetPlane = new Plane(-transform.forward, transform.position);
            float enter;

            widgetPlane.Raycast(ray, out enter);
            Vector3 worldCollisionOnWidgetPlane = ray.GetPoint(enter);

            Vector3 localWidgetPosition          = transform.InverseTransformPoint(worldCollisionOnWidgetPlane);
            Vector3 localProjectedWidgetPosition = new Vector3(localWidgetPosition.x, localWidgetPosition.y, 0.0f);

            if (IgnoreRayInteraction())
            {
                // return endPoint at the surface of the widget.
                rayEndPoint = transform.TransformPoint(localProjectedWidgetPosition);
                return;
            }

            float heightWithoutMargins = height - 2.0f * margin;
            float startY = -height + margin + heightWithoutMargins * sliderPositionBegin + railMargin;
            float endY   = -height + margin + heightWithoutMargins * sliderPositionEnd - railMargin;

            float currentValuePct = (Value - minValue) / (maxValue - minValue);

            if (HasCurveData())
            {
                currentValuePct = invDataCurve.Evaluate(Value);
            }
            float currentKnobPositionY = startY + currentValuePct * (endY - startY);

            // DRAG

            if (!triggerJustClicked)
            {
                localProjectedWidgetPosition.y = Mathf.Lerp(currentKnobPositionY, localProjectedWidgetPosition.y, GlobalState.Settings.RaySliderDrag);
            }

            // CLAMP
            // SNAP Y top
            if (localProjectedWidgetPosition.y < startY)
            {
                localProjectedWidgetPosition.y = startY;
            }

            // SNAP Y bottom
            if (localProjectedWidgetPosition.y > endY)
            {
                localProjectedWidgetPosition.y = endY;
            }

            // SNAP X to middle
            localProjectedWidgetPosition.x = width / 2.0f;

            // SET

            float pct = (localProjectedWidgetPosition.y - startY) / (endY - startY);

            if (HasCurveData())
            {
                Value = dataCurve.Evaluate(pct);
            }
            else // linear
            {
                Value = minValue + pct * (maxValue - minValue); // will replace the slider cursor.
            }
            Value = minValue + pct * (maxValue - minValue); // will replace the slider cursor.
            onSlideEvent.Invoke(currentValue);
            int intValue = Mathf.RoundToInt(currentValue);

            onSlideEventInt.Invoke(intValue);

            // Haptic intensity as we go deeper into the widget.
            //float intensity = Mathf.Clamp01(0.001f + 0.999f * localWidgetPosition.z / UIElement.collider_min_depth_deep);
            //intensity *= intensity; // ease-in

            //VRInput.SendHaptic(VRInput.rightController, 0.005f, intensity);

            Vector3 worldProjectedWidgetPosition = transform.TransformPoint(localProjectedWidgetPosition);

            //cursorShapeTransform.position = worldProjectedWidgetPosition;
            rayEndPoint = worldProjectedWidgetPosition;
        }
예제 #9
0
        public override void OverrideRayEndPoint(Ray ray, ref Vector3 rayEndPoint)
        {
            bool triggerJustClicked  = false;
            bool triggerJustReleased = false;

            VRInput.GetInstantButtonEvent(VRInput.primaryController, CommonUsages.triggerButton, ref triggerJustClicked, ref triggerJustReleased);

            // Project ray on the widget plane.
            Plane widgetPlane = new Plane(-transform.forward, transform.position);
            float enter;

            widgetPlane.Raycast(ray, out enter);
            Vector3 worldCollisionOnWidgetPlane = ray.GetPoint(enter);

            Vector3 localWidgetPosition          = transform.InverseTransformPoint(worldCollisionOnWidgetPlane);
            Vector3 localProjectedWidgetPosition = new Vector3(localWidgetPosition.x, localWidgetPosition.y, -thickness);

            if (IgnoreRayInteraction())
            {
                // return endPoint at the surface of the widget.
                rayEndPoint = transform.TransformPoint(localProjectedWidgetPosition);
                return;
            }

            float w2 = width / 2.0f;
            float h2 = height / 2.0f;
            float ir = innerCirclePct * w2; // circle inner radius
            float or = outerCirclePct * w2; // circle outer radius
            float mr = (ir + or) / 2.0f;    // circle middle radius
            float cw = (or - ir);           // circle width
            float tr = trianglePct * w2;

            Vector2 circleCenter_L = new Vector2(w2, -h2);
            Vector2 cursor_L       = new Vector2(localProjectedWidgetPosition.x, localProjectedWidgetPosition.y);

            // Just clicked, find out which subpart to lock on
            if (triggerJustClicked)
            {
                float cursorDistanceFromCenter = Vector2.Distance(cursor_L, circleCenter_L);
                if (cursorDistanceFromCenter >= ir && cursorDistanceFromCenter <= or)
                {
                    lockedOnCircle = true;
                }
                else
                {
                    // TODO: really check for triangle bounds, not only bounding circle.
                    if (cursorDistanceFromCenter <= tr)
                    {
                        lockedOnTriangle = true;
                    }
                }
            }

            if (lockedOnCircle)
            {
                Vector2 cursor_C = cursor_L - circleCenter_L;
                float   angle    = Mathf.Rad2Deg * (Mathf.PI - Mathf.Atan2(cursor_C.y, cursor_C.x));
                float   newHue   = angle / 360.0f;

                // DRAG
                if (!triggerJustClicked)
                {
                    float oldHue = hsv.x;
                    if (newHue - oldHue < -0.5f) // ex: 0.9 -> 0.1 ==> 0.9 -> 1.1
                    {
                        newHue = Mathf.Lerp(oldHue, newHue + 1.0f, GlobalState.Settings.RayHueDrag);
                        if (newHue >= 1.0f)
                        {
                            newHue -= 1.0f;
                        }
                    }
                    else if (newHue - oldHue > 0.5f) // ex: 0.1 -> 0.9 ==> 1.1 -> 0.9
                    {
                        newHue = Mathf.Lerp(oldHue + 1.0f, newHue, GlobalState.Settings.RayHueDrag);
                        if (newHue >= 1.0f)
                        {
                            newHue -= 1.0f;
                        }
                    }
                    else // ex: 0.1 -> 0.2
                    {
                        newHue = Mathf.Lerp(oldHue, newHue, GlobalState.Settings.RayHueDrag);
                    }
                }

                HSV = new Vector3(newHue, hsv.y, hsv.z); // NOTE: also re-position the cursors.

                colorPicker.OnColorChanged();

                localProjectedWidgetPosition = new Vector3(
                    w2 + mr * -Mathf.Cos(hsv.x * 2.0f * Mathf.PI),
                    -h2 + mr * Mathf.Sin(hsv.x * 2.0f * Mathf.PI),
                    -thickness);
            }
            else if (lockedOnTriangle)
            {
                Vector3 closest;
                Vector3 baryOfClosest;
                ClosestPointToTriangle2D(localProjectedWidgetPosition, pt_A_HUE, pt_B_WHITE, pt_C_BLACK, out closest, out baryOfClosest);
                localProjectedWidgetPosition = new Vector3(closest.x, closest.y, -thickness);
                barycentric = baryOfClosest;

                // DRAG
                //if (!triggerJustClicked)
                //{
                //    localProjectedWidgetPosition = Vector3.Lerp(lastProjected, localProjectedWidgetPosition, GlobalState.Settings.RaySliderDrag);
                //    barycentric = GetBarycentricCoordinates2D(localProjectedWidgetPosition, pt_A_HUE, pt_B_WHITE, pt_C_BLACK);
                //}
                //lastProjected = localProjectedWidgetPosition;

                //float H, S, V;
                //Color.RGBToHSV(BarycentricToRGB(), out H, out S, out V);
                //// TODO: make a function PointInTriangleToRGB(closest, a, b, c), using the resterizer algo to find color instead of barycentric.
                //hsv = new Vector3(hsv.x, S, V);

                Vector3 _sv = PointInTriangleToHSV(closest);
                hsv = new Vector3(hsv.x, _sv.y, _sv.z);

                UpdateCursorPositions();

                colorPicker.OnColorChanged();
            }

            Vector3 worldProjectedWidgetPosition = transform.TransformPoint(localProjectedWidgetPosition);

            rayEndPoint = worldProjectedWidgetPosition;
        }