open-ar/src/chapter3.md

4.6 KiB

Progetti di esempio

Quando si vuole sviluppare un applicazione con ARCore e Sceneform è necessaria una configurazione iniziale.

Per funzionare ARCore necessita di Android 7.0(API level 24) o superiore. Inoltre se si sta lavorando con un progetto con API level minore di 26 è necessario esplicitare il supporto a Java 8 aggiungendo al file app/build.gradle le seguenti linee.

compileOptions {
   sourceCompatibility JavaVersion.VERSION_1_8
   targetCompatibility JavaVersion.VERSION_1_8
}

Un'altra modifica da fare al file è aggiunta della dipendenza di Sceneform.

implementation "com.google.ar.sceneform.ux:sceneform-ux:1.6.0"

Inoltre nell'AndroidManifest è necessario dichiarare l'utilizzo del permesso della fotocamera1 e l'utilizzo di ARCore2.

Augmented images

Il primo progetto è un classico esempio di AR marker based e ha lo scopo di riconosce un immagine data e sovrapporre ad essa un oggetto virtuale.

Aggiunta del modello

//TODO

Creazione del database

La prima cosa da fare è creare un database con tutte le immagini che si desidera far riconosce all'applicazione. Questa operazione può essere svolta sia quando si sta sviluppando l'applicazione, sia runtime. Per questo progetto si è scelta la seconda opzione.

L'aggiunta dell'immagine al database avviene mediante la funzione setupAugmentedImageDb.

private fun setupAugmentedImageDb (config: Config): Boolean {
        val image = loadImage(IMAGE_FILE_NAME) ?: return false

        val augmentedImageDb = AugmentedImageDatabase(session)
        augmentedImageDb.addImage(IMAGE_NAME, image)
        config.augmentedImageDatabase = augmentedImageDb
        return true
}

Riconoscimento dell'immagine

Sfortunatamente ARCore non permette di gestire il riconoscimento dell'immagine mediante un listener, per cui sarà compito dello sviluppatore controllare quando si è verificato un match. Per fare ciò si usa il metodo addOnUpdateListener() dell'oggetto Scene, che permette di eseguire del codice ogni qual volta che la scena viene aggiornata.

override fun onCreate(savedInstanceState: Bundle?) {
  //...
  
  arSceneView.scene.addOnUpdateListener(this::detectAndPlaceAugmentedImage)
  
  //...
}

Dove la funzione detectAndPlaceAugmentedImage() si occupa di verificare la presenza di un match e nel caso aggiungere l'oggetto virtuale alla scena.

private fun detectAndPlaceAugmentedImage(frameTime: FrameTime) {
  if (isModelAdded)
    return

  val augmentedImage = arSceneView.arFrame
    .getUpdatedTrackables(AugmentedImage::class.java)
    .filter { isTrackig(it) }
    .find { it.name.contains(IMAGE_NAME) }
    ?: return

  val augmentedImageAnchor = augmentedImage.createAnchor(augmentedImage.centerPose)

  buildRenderable(this, Uri.parse(MODEL_NAME)) {
    addTransformableNodeToScene(
      arFragment,
      augmentedImageAnchor,
      it
    )
  }

  isModelAdded = true
}

Rendering del modello

Il rendering del modello avviene attraverso la funzione buildRenderable(). Poiché quest'ultima è un operazione dispendiosa viene restituito un Future3 che racchiude il Renderable vero e proprio. L'interazione con quest'oggetto avviene attraverso una callback che è possibile specificare attraverso il metodo thenAccept().

fun buildRenderable(
  context: Context,
  model: Uri,
  onSuccess: (renderable: Renderable) -> Unit
) {
  ModelRenderable.builder()
    .setSource(context, model)
    .build()
    .thenAccept(onSuccess)
    .exceptionally {
        Log.e("SCENEFORM", "unable to load model", it)
        return@exceptionally null
    }
}

Aggiunta dell'oggetto virtuale nella scena

L'ultima cosa da compiere è l'aggiunta del modello renderizzato alla scena. Questa operazione avviene attraverso la funzione addTrasformableNodeToScene().

fun addTransformableNodeToScene(
  arFragment: ArFragment,
  anchor: Anchor,
  renderable: Renderable
) {
  val anchorNode = AnchorNode(anchor)
  val transformableNode = TransformableNode(arFragment.transformationSystem)
  transformableNode.renderable = renderable
  transformableNode.setParent(anchorNode)
  arFragment.arSceneView.scene.addChild(anchorNode)
  transformableNode.select()
}

  1. Lo sviluppatore deve solo dichiarare l'utilizzo del permesso, la richiesta di concessione è gestita in automatico da Sceneform. ↩︎

  2. L'utilizzo di ARCore deve essere dichiarata in quanto non tutti i dispositivi supportano ARCore. ↩︎

  3. In informatica con il termine future, o promise, delay e deferred, si indica un tecnica che permette di sincronizzare l'esecuzione di un programma concorrente. ↩︎