Forum Discussion

ShadowyLynx1866's avatar
19 days ago
Solved

Is there a simple way to increase the pointer distance ?

It seems the pointer max distance is limited. Is there a way to increase this value, in order to be able to select ui items from a panel that is very large or far away for example ? Thx

  • Ok, I digged into the meta scene sample and found a solution from what has been done in 'PremiumMediaSample'.

    Create a new System that will look for collisions of your panel from controllers and dispatch back the hitInfo to the scene.

    Here what I've done. Feel free to use it if it can help you.

    package com.canal.android.quest.system
    
    import androidx.core.net.toUri
    import com.canal.ui.common.util.ALPHA_TRANSPARENT
    import com.meta.spatial.core.Color4
    import com.meta.spatial.core.Entity
    import com.meta.spatial.core.Query
    import com.meta.spatial.core.SystemBase
    import com.meta.spatial.core.Vector3
    import com.meta.spatial.runtime.PanelSceneObject
    import com.meta.spatial.toolkit.Controller
    import com.meta.spatial.toolkit.Transform
    import com.meta.spatial.core.Pose
    import com.meta.spatial.core.Quaternion
    import com.meta.spatial.runtime.AlphaMode
    import com.meta.spatial.runtime.ButtonBits
    import com.meta.spatial.toolkit.Material
    import com.meta.spatial.toolkit.Mesh
    import com.meta.spatial.toolkit.MeshCollision
    import com.meta.spatial.toolkit.Scale
    import com.meta.spatial.toolkit.Visible
    import com.meta.spatial.vr.KPOINTER_DISTANCE
    
    class PointerInfoSystem(
        private val panel: PanelSceneObject,
    ) : SystemBase() {
        private var lastTime = System.currentTimeMillis()
    
        // Create a mesh that will be displayed as a cursor
        private val pointer3dEntity = Entity.create(
            listOf(
                Mesh("apk:///scenes/sphere.glb".toUri(), hittable = MeshCollision.NoCollision),
                Transform(Pose()),
                Scale(0.1f)
            ),
        )
    
        override fun execute() {
            val currentTime = System.currentTimeMillis()
            lastTime = currentTime
    
            val controllerEntities = Query.where { has(Controller.id) }.eval().filter { it.isLocal() }
    
            for (controllerEntity in controllerEntities) {
                val controller = controllerEntity.getComponent<Controller>()
                if (!controller.isActive) continue
    
                val controllerPose = controllerEntity.getComponent<Transform>().transform
    
                val worldOrigin = controllerPose.t
                // Set your new max distance you want to interact with
                val worldTarget = controllerPose * Vector3(0.0f, 0.0f, MAX_POINTER_DISTANCE)
    
                // check for a collision with the scene
                getScene().lineSegmentIntersect(worldOrigin, worldTarget)?.let { hitInfo ->
    
                    // Use 3D pointer only if further than max default pointer distance
                    if (hitInfo.distance > KPOINTER_DISTANCE) {
    
                        // Check if collisions with Panel happens
                        val i**bleep**tingPanel = hitInfo.entity != null && hitInfo.entity == panel.entity
                        // Do some visual feeback when you are clicking
                        val scale = if (controller.isClicking()) 0.08f else 0.1f
    
                        // Add pointer to Panel
                        val pointer3dPose = Pose(hitInfo.point, Quaternion.lookRotation(hitInfo.normal.normalize()))
                        pointer3dEntity.setComponents(
                            listOf(
                                Transform(pointer3dPose),
                                Scale(scale),
                                Visible(i**bleep**tingPanel),
                            ),
                        )
    
                        // Dispatch hitInfo to scene to be able to interact with Panel
                        if (i**bleep**tingPanel) {
                            getScene().onInput(hitInfo, controllerEntity, controller.changedButtons, controller.buttonState)
                        }
                    }
                }
            }
        }
    
        private fun Controller.isClicking(): Boolean {
            // true if the controller is currently pressing the A button
            return (buttonState and ButtonBits.ButtonA) != 0 ||
                // true if the controller is currently holding down either of the triggers
                (buttonState and (ButtonBits.ButtonTriggerL or ButtonBits.ButtonTriggerR)) != 0
        }
    
        private companion object {
            // max distance to ray cast into the scene for a contact
            private const val MAX_POINTER_DISTANCE = 100f
        }
    }

1 Reply

  • Ok, I digged into the meta scene sample and found a solution from what has been done in 'PremiumMediaSample'.

    Create a new System that will look for collisions of your panel from controllers and dispatch back the hitInfo to the scene.

    Here what I've done. Feel free to use it if it can help you.

    package com.canal.android.quest.system
    
    import androidx.core.net.toUri
    import com.canal.ui.common.util.ALPHA_TRANSPARENT
    import com.meta.spatial.core.Color4
    import com.meta.spatial.core.Entity
    import com.meta.spatial.core.Query
    import com.meta.spatial.core.SystemBase
    import com.meta.spatial.core.Vector3
    import com.meta.spatial.runtime.PanelSceneObject
    import com.meta.spatial.toolkit.Controller
    import com.meta.spatial.toolkit.Transform
    import com.meta.spatial.core.Pose
    import com.meta.spatial.core.Quaternion
    import com.meta.spatial.runtime.AlphaMode
    import com.meta.spatial.runtime.ButtonBits
    import com.meta.spatial.toolkit.Material
    import com.meta.spatial.toolkit.Mesh
    import com.meta.spatial.toolkit.MeshCollision
    import com.meta.spatial.toolkit.Scale
    import com.meta.spatial.toolkit.Visible
    import com.meta.spatial.vr.KPOINTER_DISTANCE
    
    class PointerInfoSystem(
        private val panel: PanelSceneObject,
    ) : SystemBase() {
        private var lastTime = System.currentTimeMillis()
    
        // Create a mesh that will be displayed as a cursor
        private val pointer3dEntity = Entity.create(
            listOf(
                Mesh("apk:///scenes/sphere.glb".toUri(), hittable = MeshCollision.NoCollision),
                Transform(Pose()),
                Scale(0.1f)
            ),
        )
    
        override fun execute() {
            val currentTime = System.currentTimeMillis()
            lastTime = currentTime
    
            val controllerEntities = Query.where { has(Controller.id) }.eval().filter { it.isLocal() }
    
            for (controllerEntity in controllerEntities) {
                val controller = controllerEntity.getComponent<Controller>()
                if (!controller.isActive) continue
    
                val controllerPose = controllerEntity.getComponent<Transform>().transform
    
                val worldOrigin = controllerPose.t
                // Set your new max distance you want to interact with
                val worldTarget = controllerPose * Vector3(0.0f, 0.0f, MAX_POINTER_DISTANCE)
    
                // check for a collision with the scene
                getScene().lineSegmentIntersect(worldOrigin, worldTarget)?.let { hitInfo ->
    
                    // Use 3D pointer only if further than max default pointer distance
                    if (hitInfo.distance > KPOINTER_DISTANCE) {
    
                        // Check if collisions with Panel happens
                        val i**bleep**tingPanel = hitInfo.entity != null && hitInfo.entity == panel.entity
                        // Do some visual feeback when you are clicking
                        val scale = if (controller.isClicking()) 0.08f else 0.1f
    
                        // Add pointer to Panel
                        val pointer3dPose = Pose(hitInfo.point, Quaternion.lookRotation(hitInfo.normal.normalize()))
                        pointer3dEntity.setComponents(
                            listOf(
                                Transform(pointer3dPose),
                                Scale(scale),
                                Visible(i**bleep**tingPanel),
                            ),
                        )
    
                        // Dispatch hitInfo to scene to be able to interact with Panel
                        if (i**bleep**tingPanel) {
                            getScene().onInput(hitInfo, controllerEntity, controller.changedButtons, controller.buttonState)
                        }
                    }
                }
            }
        }
    
        private fun Controller.isClicking(): Boolean {
            // true if the controller is currently pressing the A button
            return (buttonState and ButtonBits.ButtonA) != 0 ||
                // true if the controller is currently holding down either of the triggers
                (buttonState and (ButtonBits.ButtonTriggerL or ButtonBits.ButtonTriggerR)) != 0
        }
    
        private companion object {
            // max distance to ray cast into the scene for a contact
            private const val MAX_POINTER_DISTANCE = 100f
        }
    }