Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ModelLoader causes lags #594

Open
konrad-thoc opened this issue Feb 7, 2025 · 0 comments
Open

ModelLoader causes lags #594

konrad-thoc opened this issue Feb 7, 2025 · 0 comments

Comments

@konrad-thoc
Copy link

konrad-thoc commented Feb 7, 2025

The code works fine, however, after adding the direction arrow lags appeared, how can I solve this? Here's my code.

class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding
    private lateinit var viewAttachmentManager: ViewAttachmentManager

    private var trackerViewBinding: TrackerViewBinding? = null

    private var destinationNode: AnchorNode? = null
    private var directionArrow: AnchorNode? = null

    private var trackerLat: Double = 0.0 // REPLACE WITH YOUR COORDINATES
    private var trackerLng: Double = 0.0 // // REPLACE WITH YOUR COORDINATES
    private val distanceState = MutableStateFlow<Double>(0.0)
    private var lastDestinationRotation: Rotation? = null

    override fun onResume() {
        super.onResume()
        viewAttachmentManager.onResume()
    }

    override fun onPause() {
        super.onPause()
        viewAttachmentManager.onPause()
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        setupView()
    }

    private fun setupView() {
        binding.apply {
            sceneView.apply {
                lifecycle = [email protected]
                planeRenderer.isEnabled = true
                this.mainLightNode
                // Set rendering distance to 200m
                cameraNode.far = 200f
                configureSession { session, config ->
                    config.focusMode = Config.FocusMode.AUTO
                    config.lightEstimationMode = Config.LightEstimationMode.DISABLED
                    config.depthMode = Config.DepthMode.DISABLED
                    config.planeFindingMode = Config.PlaneFindingMode.DISABLED
                    config.updateMode = Config.UpdateMode.LATEST_CAMERA_IMAGE
                    if (session.isGeospatialModeSupported(Config.GeospatialMode.ENABLED)) {
                        config.geospatialMode = Config.GeospatialMode.ENABLED
                    } else {
                        showErrorMessage("Geospital mode not supported on this device")
                    }
                }
                onSessionUpdated = { session, frame ->
                    updateStatusText(session)

                    drawDestinationTracker(session)
                    drawDirectionArrow(session, frame)
                }
                onTrackingFailureChanged = { reason ->
                    updateInstructions(reason)
                }
                viewAttachmentManager = ViewAttachmentManager(this@MainActivity, this)
            }
        }
    }


    private fun drawDestinationTracker(session: Session) {
        val sceneView = binding.sceneView

        if (destinationNode != null) {
            // Rotate node to camera
            val cameraNode = sceneView.cameraNode
            if (distanceState.value < 1 && lastDestinationRotation != null) {
                destinationNode!!.rotation = lastDestinationRotation!!
            } else {
                destinationNode!!.lookAt(cameraNode)
            }
            lastDestinationRotation = destinationNode!!.rotation
            return
        }

        val anchor = createEarthAnchor(session) ?: return
        val anchorNode = AnchorNode(sceneView.engine, anchor)
        // Set the node identifier
        anchorNode.name = Constants.DESTINATION_NODE_NAME
        ViewRenderable.builder()
            .setView(sceneView.context, R.layout.tracker_view)
            .build(sceneView.engine)
            .thenAccept { renderable ->
                trackerViewBinding = TrackerViewBinding.bind(renderable.view)

                val viewNode = ViewNode(
                    engine = sceneView.engine,
                    modelLoader = sceneView.modelLoader,
                    viewAttachmentManager = viewAttachmentManager
                ).apply {
                    setRenderable(renderable)
                    disable()
                    scale = Scale(-10f, 10f, 1f)
                }

                anchorNode.addChildNode(viewNode)

                // Remove duplicates
                val index = sceneView.childNodes.indexOfFirst { it.name == Constants.DESTINATION_NODE_NAME }
                if (index != -1) sceneView.removeChildNode(sceneView.childNodes[index])

                sceneView.addChildNode(anchorNode)
                destinationNode = anchorNode
            }
    }

    private fun createEarthAnchor(session: Session): Anchor? {
        val earth = session.earth ?: return null
        if (earth.trackingState != TrackingState.TRACKING) return null

        val altitude = earth.cameraGeospatialPose.altitude - 1

        return earth.createAnchor(
            trackerLat,
            trackerLng,
            altitude,
            0f, 0f, 0f, 1f,
        )
    }

    private fun drawDirectionArrow(session: Session, frame: Frame) {
        if (destinationNode == null) return
        if (frame.camera.trackingState == TrackingState.TRACKING) {
            val pose = frame.camera.pose
                .compose(Pose.makeTranslation(0.3f, 0f, -1f))
                .extractTranslation()
            val anchor = session.createAnchor(pose)

            if (directionArrow != null) {
                directionArrow!!.anchor = anchor
                // Rotate node to destination
                directionArrow!!.lookAt(destinationNode!!)
                return
            }

            val sceneView = binding.sceneView
            val anchorNode = AnchorNode(sceneView.engine, anchor)
            // Set the node identifier
            anchorNode.name = Constants.DIRECTION_ARROW_NODE_NAME
            lifecycleScope.launch {
                val modelInstance =
                    sceneView.modelLoader.loadModelInstance(Constants.DIRECTION_ARROW_FILE)
                if (modelInstance != null) {
                    val modelNode = ModelNode(
                        modelInstance = modelInstance,
                        scaleToUnits = 0.3f,
                        centerOrigin = Position(y = -0.5f),
                    )
                    modelNode.disable()
                    anchorNode.addChildNode(modelNode)

                    // Remove duplicates
                    val index = sceneView.childNodes.indexOfFirst { it.name == Constants.DIRECTION_ARROW_NODE_NAME }
                    if (index != -1) sceneView.removeChildNode(sceneView.childNodes[index])

                    sceneView.addChildNode(anchorNode)
                    anchorNode.lookAt(destinationNode!!)
                    directionArrow = anchorNode
                } else {
                    showErrorMessage("Unable to load model")
                }
            }
        }
    }

    private fun updateStatusText(session: Session) {
        val earth = session.earth
        if (earth?.trackingState == TrackingState.TRACKING) {
            val cameraGeospatialPose = earth.cameraGeospatialPose
            val geospitalPose = getString(
                R.string.geospatial_pose,
                cameraGeospatialPose.latitude,
                cameraGeospatialPose.longitude,
                cameraGeospatialPose.horizontalAccuracy,
                cameraGeospatialPose.altitude,
                cameraGeospatialPose.verticalAccuracy,
                cameraGeospatialPose.heading,
                cameraGeospatialPose.headingAccuracy,
            )
            binding.statusText.text = resources.getString(
                R.string.earth_state,
                earth.earthState.toString(),
                earth.trackingState.toString(),
                geospitalPose,
            )

//            val distanceToTracker = DistanceCalculator.calculateDistance(
//                cameraGeospatialPose.latitude,
//                cameraGeospatialPose.longitude,
//                trackerLat,
//                trackerLng,
//            )
//            distanceState.value = distanceToTracker
//
//            binding.accuracyText.text = "Accuracy: ${cameraGeospatialPose.getAccuracy()}"
//            trackerViewBinding?.trackerDistance?.text = "${String.format("%.1f", distanceToTracker)} m"
        }
    }

    private fun updateInstructions(reason: TrackingFailureReason?) {
        binding.instructionText.text = reason?.getDescription(this) ?: ""
    }

    private fun showErrorMessage(error: String) {
        Toast.makeText(this, error, Toast.LENGTH_SHORT).show()
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant