Closed
Description
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
Labels
No labels