using Unity.XR.CoreUtils; using UnityEngine.XR.Interaction.Toolkit.Filtering; using UnityEngine.XR.Interaction.Toolkit.Interactables; namespace UnityEngine.XR.Interaction.Toolkit.Samples.VisionOS { /// /// Slider component that can be poked or indirectly interacted with to change its value. /// Designed to work well with direct or indirect touch interaction. /// [RequireComponent(typeof(BoxCollider))] public class SliderComponent : XRBaseInteractable { [Header("Slider Configuration")] [SerializeField] MeshRenderer m_FillRenderer; [SerializeField] float m_SliderIndirectChangeScale = 1f; [SerializeField] float m_InitialSliderPercent = 0.5f; [SerializeField] FloatUnityEvent m_OnSliderValueChanged; float m_BoxColliderSizeX; int m_PercentageId; Material m_MaterialInstance; Vector3 m_StartLocalGrabPos; float m_Percentage; float m_OnGrabStartPercentage; void Start() { m_MaterialInstance = m_FillRenderer.material; m_PercentageId = Shader.PropertyToID("_Percentage"); m_BoxColliderSizeX = GetComponent().size.x; SetFillPercentage(m_InitialSliderPercent); } /// protected override void OnSelectEntered(SelectEnterEventArgs args) { base.OnSelectEntered(args); m_OnGrabStartPercentage = m_Percentage; m_StartLocalGrabPos = transform.InverseTransformPoint(args.interactorObject.transform.position); } void Update() { if (!isSelected) return; var interactorSelecting = interactorsSelecting[0]; var interactorPosition = interactorsSelecting[0].transform.position; if (interactorSelecting is IPokeStateDataProvider) { UpdateSliderAmtDirect(interactorPosition); } else { UpdateSliderAmtDelta(interactorPosition); } } void UpdateSliderAmtDirect(Vector3 interactorPos) { var localPosition = transform.InverseTransformPoint(interactorPos); var percentage = localPosition.x / m_BoxColliderSizeX + 0.5f; SetFillPercentage(percentage); } void UpdateSliderAmtDelta(Vector3 currentInteractorPos) { var currentLocalPos = transform.InverseTransformPoint(currentInteractorPos); var deltaVector = Vector3.ProjectOnPlane(currentLocalPos - m_StartLocalGrabPos, Vector3.up); var dx = deltaVector.x / m_BoxColliderSizeX; float newPercent = m_OnGrabStartPercentage + dx * m_SliderIndirectChangeScale; SetFillPercentage(newPercent); } float MapRange(float value, float inputMin, float inputMax, float outputMin, float outputMax) { return outputMin + ((value - inputMin) / (inputMax - inputMin) * (outputMax - outputMin)); } void SetFillPercentage(float percentage) { m_Percentage = Mathf.Clamp01(percentage); m_MaterialInstance.SetFloat(m_PercentageId, MapRange(percentage, 0f, 1f, -0.01f, 1.01f)); m_OnSliderValueChanged?.Invoke(1f - m_Percentage); } } }