init chapter 3

- add augmented images project
This commit is contained in:
Raffaele Mignone 2019-01-03 22:20:27 +01:00
parent 6b0b7f5624
commit c893958326
Signed by: norangebit
GPG Key ID: 4B9DF72AB9508845

135
src/chapter3.md Normal file
View File

@ -0,0 +1,135 @@
# 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.
```gradle
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
```
Un'altra modifica da fare al file è aggiunta della dipendenza di Sceneform.
```gradle
implementation "com.google.ar.sceneform.ux:sceneform-ux:1.6.0"
```
Inoltre nell'AndroidManifest è necessario dichiarare l'utilizzo del permesso della fotocamera[^camera] e l'utilizzo di ARCore[^arcore].
## 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`.
```kotlin
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.
```kotlin
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.
```kotlin
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 `Future`[^future] che racchiude il `Renderable` vero e proprio.
L'interazione con quest'oggetto avviene attraverso una callback che è possibile specificare attraverso il metodo `thenAccept()`.
```kotlin
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()`.
```kotlin
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()
}
```
[^camera]: Lo sviluppatore deve solo dichiarare l'utilizzo del permesso, la richiesta di concessione è gestita in automatico da Sceneform.
[^arcore]: L'utilizzo di ARCore deve essere dichiarata in quanto non tutti i dispositivi supportano ARCore.
[^future]: 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.