Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Kotlin DSL Magic for Augmented Reality

Kotlin DSL Magic for Augmentedย Reality

GDG Dev Fest London 2018

A59baf8d7898908b4979bb9d5f33bb9b?s=128

Giovanni Laquidara

December 07, 2018
Tweet

Transcript

  1. Kotlin DSL magic for Augmented Reality Giovanni Laquidara @joaolaq

  2. AR can bring anything to you. AR can *bring* anything

    to you. It adds computer-generated information and objects to your everyday world. @joaolaq
  3. https://developers.google.com/ar/

  4. MOTION TRACKING ENVIRONMENTAL UNDERSTANDING LIGHT ESTIMATION

  5. ARCore provides SDKs for many of the most popular development

    environments. These SDKs provide native APIs for all of the essential AR features like motion tracking, environmental understanding, and light estimation. With these capabilities you can build entirely new AR experiences or enhance existing apps with AR features. Use your favourite environment @joaolaq
  6. None
  7. None
  8. None
  9. Sceneform Sceneform is a 3D framework that makes it easy

    for Java developers to build augmented reality apps. โ€ข A high-level scene graph API โ€ข A realistic physically based renderer provided by Filament โ€ข An Android Studio plugin for importing, viewing, and building 3D assets https://developers.google.com/ar/develop/java/sceneform/
  10. Development integration

  11. Android sample integration

  12. Android sample integration

  13. Can we make it more readable?

  14. Inspiration <html> <head> <title> A Simple HTML Document </title> </head>

    <body> <p>This is a very simple HTML document</p> <p>It only has two paragraphs</p> </body> </html>
  15. Domain Specific Languages by Martin Fowler (with Rebecca Parsons) Domain

    Specific Languages (DSLs) have been around since I've been in computing, but it's hard to find much information about how to work with them. DSLs are small languages, focused on a particular aspect of a software system. You can't build a whole program with a DSL, but you often use multiple DSLs in a system mainly written in a general purpose language.
  16. Internal DSL โ€ข Internal DSLs are particular ways of using

    a host language to give the host language the feel of a particular language. โ€ข External DSLs have their own custom syntax and you write a full parser to process them.
  17. Kotlin can help us with โ€ข Use of lambdas outside

    of method parentheses โ€ข Lambdas with receivers โ€ข Builders โ€ข Infix โ€ข DSL Marker
  18. Data class Scene data class Scene(var nodes: List<Node>? = null)

  19. lambdas outside of method parentheses. fun scene(block: (Scene) -> Unit)

    : Scene { val s = Scene() block(s) return s }
  20. A scene now val scene = scene { it.nodes =

    listOf(Node(), Node(), Node()) }
  21. Lambda with receiver fun scene(block: Scene.() -> Unit): Scene {

    val s = Scene() s.block() return s } // Or better fun scene(block: Scene.() -> Unit): Scene = Scene().apply { block }
  22. A scene now val scene = scene { nodes =

    listOf(Node(), Node(), Node()) }
  23. I Want immutability data class Scene(val nodes: List<Node>)

  24. None
  25. Builders class SceneBuilder { private val nodes = mutableListOf<Node>() fun

    build(): Scene { return Scene(nodes) } }
  26. Lambda with receiver ( Builder version) fun scene(block: SceneBuilder.() ->

    Unit): Scene = SceneBuilder().apply { block }
  27. Add an Anchor Node // SceneBuilder fun anchorNode(anchor: Anchor, setup:

    AnchorNodeBuilder.() -> Unit = {}) { val nodeBuilder = AnchorNodeBuilder(anchor) nodeBuilder.setup() nodes += nodeBuilder.build() }
  28. AnchorNodeBuilder // SceneBuilder class AnchorNodeBuilder(var anchor: Anchor?) { private val

    nodes = mutableListOf<Node>() fun build(): AnchorNode { anchor?.let { return AnchorNode(anchor).apply { nodes.forEach { it.setParent(this)} } } ?: throw IllegalArgumentException("Anchor cannot be null") }
  29. Our Scene now val scene = scene { anchorNode(anchora) {

    node { transformationSystem = fragment.transformationSystem model = renderable } } }
  30. Add a Transformable Node

  31. Add a Transformable Node // AnchorNodeBuilder fun node(transformationSystem: TransformationSystem? =

    null, model: Renderable? = null, setup: NodeBuilder.() -> Unit = {}) { val nodeBuilder = NodeBuilder(transformationSystem, model) nodeBuilder.setup() nodes += nodeBuilder.build() }
  32. How to build a Node class NodeBuilder(var transformationSystem: TransformationSystem?, var

    model: Renderable?) { fun build(): Node { transformationSystem?.let { return TransformableNode(transformationSystem).apply { renderable = model } } ?: throw IllegalArgumentException("TransformationSystem cannot be null") } }
  33. Generalize open class NodeBuilder(var position: Vector3?, var scale: Vector3?, var

    model: Renderable?) { protected open val nodes = mutableListOf<Node>() open fun build(): Node { return Node().apply { if (position != null) localPosition = position if (scale != null) localScale = scale if (model != null) renderable = model nodes.forEach { it.setParent(this) } } }
  34. Generalize โ€ฆโ€ฆ.. fun node(position: Vector3? = null, scale: Vector3? =

    null, model: Renderable? = null, setup: NodeBuilder.() -> Unit = {}) { val nodeBuilder = NodeBuilder(position, scale, model) nodeBuilder.setup() nodes += nodeBuilder.build() } }
  35. Generalize class AnchorNodeBuilder(var anchor: Anchor?) : NodeBuilder(null, null, null) {

    override fun build(): AnchorNode { anchor?.let { return AnchorNode(anchor).apply { nodes.forEach { it.setParent(this) } } } ?: throw IllegalArgumentException("Anchor cannot be null") } }
  36. DSL Marker @DslMarker annotation class ArDsl @ArDsl class NodeBuilder(var transformationSystem:

    TransformationSystem?, var model: Renderable?) {
  37. DSL Marker ( Context control ) @DslMarker annotation class ArDsl

    @ArDsl class NodeBuilder(var transformationSystem: TransformationSystem?, var model: Renderable?) {
  38. Infix arSceneView!!.scene setTo scene

  39. Infix and Extension function private infix fun com.google.ar.sceneform.Scene.setTo(scene: Scene) {

    this.addChild(scene.nodes.first()) }
  40. Future to couroutines import kotlinx.coroutines.future.await private suspend fun placeObject(fragment: ArFragment,

    anchor: Anchor, model: Uri) { val renderableFuture = ModelRenderable.builder() .setSource(fragment.context, model) .build() try { addNodeToScene(fragment, anchor, renderableFuture.await())
  41. Complex sample val scene = scene { anchorNode { anchor

    = anchora node { node { position = Vector3(0.0f, 0.5f, 0.0f) scale = Vector3(0.5f, 0.5f, 0.5f) model = sunRenderable node { position = Vector3(1.0f * AU_TO_METERS, 0.0f, 0.0f) scale = Vector3(0.05f, 0.05f, 0.05f) model = earthRenderable } }
  42. How to create a DSL with Kotlin and your IDE

  43. With Kotlin super powers โ€ข Use of lambdas outside of

    method parentheses โ€ข Lambdas with receivers โ€ข Builders โ€ข Infix โ€ข DSL Marker โ€ข Operator Overloading โ€ข Extension functions
  44. Next stop, commands https://youtu.be/JzTeAM8N1-o

  45. Give me the source! https://github.com/joaobiriba/sceneform_ar_dsl https://github.com/joaobiriba/ARSample https://github.com/google-ar/sceneform-android-sdk https://github.com/google-ar/arcore-android-sdk/tree/master/samples/hello_ar_java

  46. ? https://bit.ly/2PbaKt9 @joaolaq glaquidara@gmail.com