Skip to content

ModelLoader causes lags #594

Closed
Closed
@konrad-thoc

Description

@konrad-thoc

The code works fine, however, after adding the 3D model (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()
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions