Android Studioではじめる実践ARCore入門

7e6a79d3fd57e49905f6f4fe53550021?s=47 zukkey
March 06, 2019

Android Studioではじめる実践ARCore入門

UnityによるARの実装方法は、多く掲載されておりますがAndroid Studioでの実装例について情報が少ない現状です。 AndroidでARを実装していく際に、既存のアプリにAR機能を追加していくことが今後可能性としてあるかと思われます。 そういう背景から今回は、私がARCoreの概要および主要な機能について、初心者になるべくわかりやすく説明いたします。

7e6a79d3fd57e49905f6f4fe53550021?s=128

zukkey

March 06, 2019
Tweet

Transcript

  1. 1.

    Copyright © 2019 eureka, Inc. All rights reserved. 1 ɹ"3$PSFΛ"OESPJEΞϓϦʹಋೖ͍ͨ͠ਓɺڵຯ͕͋Δਓʹɺ

    ɹ"OESPJE4UVEJPͰ"3$PSFΛར༻͢Δͷʹඞཁͳ஌ࣝɺ ɹ"3$PSFͰͰ͖Δ͜ͱΛগ͠Ͱ΋ཧղͯ͠΋Β͏ ࠓ೔ͷΰʔϧ
  2. 2.

    Copyright © 2019 eureka, Inc. All rights reserved. Android StudioͰ͸͡ΊΔ

    ࣮ફARCoreೖ໳ @zukkey59 Yappli Android Rejected Conf. MeetUp
  3. 3.

    Copyright © 2019 eureka, Inc. All rights reserved. 3 ɾླ໦༟ଠ࿕

    ͖ͣ͢Ώ͏ͨΖ͏  ɾגࣜձࣾΤ΢ϨΧ ɾ"OESPJE&OHJOFFS ࣗݾ঺հ @zukkey59 yutaro6547
  4. 4.

    Copyright © 2019 eureka, Inc. All rights reserved. 4 ɾ೔ຊ࠷େͷϚονϯάαʔϏε

    ɾ୆࿷ɺؖࠃͰ΋αʔϏεల։ ɾձһ਺ສਓ ɾϚονϯά਺ສ૊ ɾΧοϓϧ਺ສ૊ Pairs Japan / Global
  5. 5.

    Copyright © 2019 eureka, Inc. All rights reserved. 5 ɾ࠷ۙͰ͕͢ɺٕज़ॻయͰॻ͍ͨಉਓࢽ͕

    ɹ঎ۀࢽԽ͞Ε·ͨ͠ʂ ɹΞϚκϯͳͲɺΦϯϥΠϯॻళͰͷΈൢചத ɾࠓճ͸ɺ͜Εʹ·ͭΘΔ͓࿩ ՝֎׆ಈ
  6. 6.

    Copyright © 2019 eureka, Inc. All rights reserved. 6 ɾ͸͡Ίʹ

    ɾ"3$PSFͱ͸"3$PSFͷ৘ใɺ6OJUZͰͷ঺հ͕ଟ͍໰୊"3$PSFͰͰ͖Δ͜ͱ ɾجຊͱͳΔ֓೦ ɹɾϞʔγϣϯτϥοΩϯά؀ڥޫͷՃݮ ɾجຊͱͳΔΫϥε ɹɾ4FTTJPO"ODIPS$POpH1MBOF/PEF ɾ"3$PSFͰͰ͖Δ͜ͱ ɹɾ4DFOFGPSN"VHVNFOUFE*NBHFT$MPVE"ODIPST ɾ͓ΘΓʹ ໨࣍
  7. 8.

    Copyright © 2019 eureka, Inc. All rights reserved. 8 ɾ(PPHMF͕ఏڙ͍ͯ͠Δ4%,

    ɾ"3ػೳʹඞਢͷϞʔγϣϯτϥοΩϯάɺ ɹ؀ڥɺޫͷՃݮͳͲΛશͯαϙʔτͯ͘͠ΕΔ ɾ4DFOFGPSNϥΠϒϥϦΛར༻͢Δ͜ͱͰɺ ɹ0QFO(-ͳͲͷઐ໳஌͕ࣝͳͯ͘΋खܰʹࢼ͢͜ͱ͕Ͱ͖Δ ARCoreͱ͸
  8. 9.

    Copyright © 2019 eureka, Inc. All rights reserved. 9 ɾ"3$PSFͷ৘ใΛ͍͟ௐ΂ͯΈΔͱɺ6OJUZͰͷ঺հࣄྫ͕ଟ͍

    ɾࠓޙɺطଘͷ"OESPJEΞϓϦʹ૊ΈࠐΈ͍ͨͱ͔ɺ ɹ"3ػೳΛ࣠ʹͨ͠ΞϓϦΛ࡞Γ͍ͨͱ͔ग़ͯ͘Δ͔΋ ARCoreͷ৘ใɺUnityͰͷ঺հ͕ଟ͍໰୊
  9. 11.

    Copyright © 2019 eureka, Inc. All rights reserved. 11 ɾ(PPHMF͕ఏڙ͍ͯ͠Δ4%,

    ɾ"3ػೳʹඞਢͷϞʔγϣϯτϥοΩϯάɺ ɹ؀ڥɺޫͷՃݮͳͲΛશͯαϙʔτͯ͘͠ΕΔ ɾ4DFOFGPSNϥΠϒϥϦΛར༻͢Δ͜ͱͰɺ ɹ0QFO(-ͳͲͷઐ໳஌͕ࣝͳͯ͘΋खܰʹࢼ͢͜ͱ͕Ͱ͖Δ ARCoreͱ͸
  10. 12.

    Copyright © 2019 eureka, Inc. All rights reserved. 12 ɾ(PPHMF͕ఏڙ͍ͯ͠Δ4%,

    ɾ"3ػೳʹඞਢͷϞʔγϣϯτϥοΩϯάɺ ɹ؀ڥɺޫͷՃݮͳͲΛશͯαϙʔτͯ͘͠ΕΔ ɾ4DFOFGPSNϥΠϒϥϦΛར༻͢Δ͜ͱͰɺ ɹ0QFO(-ͳͲͷઐ໳஌͕ࣝͳͯ͘΋खܰʹࢼ͢͜ͱ͕Ͱ͖Δ ARCoreͱ͸
  11. 13.

    Copyright © 2019 eureka, Inc. All rights reserved. 13 ɾΩϟϓνϟ͞ΕͨΧϝϥը૾͔Βɺ

    ɹࢹ֮తʹҟͳΔಛ௃఺Λݕग़͠ɺ ɹ఺͔ΒҐஔΛܭࢉ͢Δ ϞʔγϣϯτϥοΩϯά ࢀর: https://developers.google.com/ar/images/MotionTracking.jpg
  12. 14.

    Copyright © 2019 eureka, Inc. All rights reserved. 14 ɾ(PPHMF͕ఏڙ͍ͯ͠Δ4%,

    ɾ"3ػೳʹඞਢͷϞʔγϣϯτϥοΩϯάɺ ɹ؀ڥɺޫͷՃݮͳͲΛશͯαϙʔτͯ͘͠ΕΔ ɾ4DFOFGPSNϥΠϒϥϦΛར༻͢Δ͜ͱͰɺ ɹ0QFO(-ͳͲͷઐ໳஌͕ࣝͳͯ͘΋खܰʹࢼ͢͜ͱ͕Ͱ͖Δ ARCoreͱ͸
  13. 15.

    Copyright © 2019 eureka, Inc. All rights reserved. 15 ɾςʔϒϧͳͲͷҰൠతͳਫฏ໘ɺ

    ɹਨ௚໘ͷಛ௃఺ͷΫϥελ͔Β ɹฏ໘Λݕग़ ؀ڥ ࢀর: https://developers.google.com/ar/images/EnvUnderstanding.jpg
  14. 16.

    Copyright © 2019 eureka, Inc. All rights reserved. 16 ɾ(PPHMF͕ఏڙ͍ͯ͠Δ4%,

    ɾ"3ػೳʹඞਢͷϞʔγϣϯτϥοΩϯάɺ ɹ؀ڥɺޫͷՃݮͳͲΛશͯαϙʔτͯ͘͠ΕΔ ɾ4DFOFGPSNϥΠϒϥϦΛར༻͢Δ͜ͱͰɺ ɹ0QFO(-ͳͲͷઐ໳஌͕ࣝͳͯ͘΋खܰʹࢼ͢͜ͱ͕Ͱ͖Δ ARCoreͱ͸
  15. 17.

    Copyright © 2019 eureka, Inc. All rights reserved. 17 ɾ؀ڥͷর໌ʹ͍ͭͯͷ৘ใΛ

    ɹݕग़͠ɺਪఆͯ͘͠ΕΔ ޫͷՃݮ ࢀর: https://developers.google.com/ar/images/LightEstimation.jpg
  16. 20.

    Copyright © 2019 eureka, Inc. All rights reserved. 20 ɾ4FTTJPO

    ɾ"ODIPS ɾ$POpH ɾ1MBOF ɾ/PEF جຊͱͳΔΫϥε
  17. 21.

    Copyright © 2019 eureka, Inc. All rights reserved. 21 ɾ4FTTJPO

    ɾ"ODIPS ɾ$POpH ɾ1MBOF ɾ/PEF جຊͱͳΔΫϥε
  18. 22.

    Copyright © 2019 eureka, Inc. All rights reserved. 22 ɾ"3ͷγεςϜͷঢ়ଶΛ؅ཧ͢Δ

    ɾηογϣϯͷ։࢝΍ఀࢭͳͲϥΠϑαΠΫϧΛॲཧ͢Δ ɾηογϣϯ࡞੒લʹ͸ɺ"3$PSF͕Πϯετʔϧ͞Ε͍ͯΔ͜ͱΛ ɹ֬ೝ͠ͳͯ͘͸ͳΒͳ͍ Session
  19. 23.

    Copyright © 2019 eureka, Inc. All rights reserved. 23 ɾ4FTTJPO

    ɾ"ODIPS ɾ$POpH ɾ1MBOF ɾ/PEF جຊͱͳΔΫϥε
  20. 25.

    Copyright © 2019 eureka, Inc. All rights reserved. 25 ɾ4FTTJPO

    ɾ"ODIPS ɾ$POpH ɾ1MBOF ɾ/PEF جຊͱͳΔΫϥε
  21. 26.

    Copyright © 2019 eureka, Inc. All rights reserved. 26 ɾ4FTTJPOΫϥεͷઃఆΛอ࣋͢ΔΫϥε

    ɹ$MPVE"ODIPSͷར༻࣌ͳͲɺಛఆͷ৔߹ʹ࢖༻͢Δ Config
  22. 27.

    Copyright © 2019 eureka, Inc. All rights reserved. 27 ɾ4FTTJPO

    ɾ"ODIPS ɾ$POpH ɾ1MBOF ɾ/PEF جຊͱͳΔΫϥε
  23. 29.

    Copyright © 2019 eureka, Inc. All rights reserved. 29 ɾ4FTTJPO

    ɾ"ODIPS ɾ$POpH ɾ1MBOF ɾ/PEF جຊͱͳΔΫϥε
  24. 33.

    Copyright © 2019 eureka, Inc. All rights reserved. 33 ɾ%ΦϒδΣΫτͷදࣔɺૢ࡞

    ɾը૾ΛϚʔΧʔʹͯ͠ɺ%ΦϒδΣΫτΛදࣔ ɾ̎ͭͷ୺຤Ͱɺ%ΦϒδΣΫτΛڞ༗ ARCoreͰͰ͖Δ͜ͱ
  25. 34.

    Copyright © 2019 eureka, Inc. All rights reserved. 34 ɾ%ΦϒδΣΫτͷදࣔɺૢ࡞4DFOFGPSN

    ɾը૾ΛϚʔΧʔʹͯ͠ɺ%ΦϒδΣΫτΛදࣔ ɾ̎ͭͷ୺຤Ͱɺ%ΦϒδΣΫτΛڞ༗ ARCoreͰͰ͖Δ͜ͱ
  26. 35.

    Copyright © 2019 eureka, Inc. All rights reserved. 35 ɾ0QFO(-ͷઐ໳తͳ஌ࣝͳ͠Ͱɺ

    ɹ؆୯ʹ%ΦϒδΣΫτͷදࣔͳͲ͕Ͱ͖ΔϥΠϒϥϦ ɾ"3$PSFͱ૊Έ߹ΘͤΔ͜ͱͰ΋ར༻Ͱ͖Δ͠ɺ ɹ"3$PSFΛซ༻͠ͳͯ͘΋ར༻Մೳ Sceneform
  27. 38.

    Copyright © 2019 eureka, Inc. All rights reserved. class ModelActivity:

    AppCompatActivity() { private var modelRenderable: ModelRenderable? = null … override fun onCreate(savedInstanceState: Bundle?) { … ModelRenderable.builder() .setSource(this, R.raw.rin) .build() .thenAccept { renderable -> modelRenderable = renderable } .exceptionally { val toast = Toast.makeText(this, "ϨϯμϦϯάͰ͖·ͤΜ", Toast.LENGTH_LONG) toast.setGravity(Gravity.CENTER, 0, 0) toast.show() null } } … }
  28. 39.

    Copyright © 2019 eureka, Inc. All rights reserved. class ModelActivity:

    AppCompatActivity() { private var modelRenderable: ModelRenderable? = null … override fun onCreate(savedInstanceState: Bundle?) { … ModelRenderable.builder() .setSource(this, R.raw.rin) .build() .thenAccept { renderable -> modelRenderable = renderable } .exceptionally { val toast = Toast.makeText(this, "ϨϯμϦϯάͰ͖·ͤΜ", Toast.LENGTH_LONG) toast.setGravity(Gravity.CENTER, 0, 0) toast.show() null } } … } %ΦϒδΣΫτΛϨϯμϦϯά͢ΔͨΊͷΫϥεɺॳظԽ
  29. 40.

    Copyright © 2019 eureka, Inc. All rights reserved. class ModelActivity:

    AppCompatActivity() { private var modelRenderable: ModelRenderable? = null … override fun onCreate(savedInstanceState: Bundle?) { … ModelRenderable.builder() .setSource(this, R.raw.rin) .build() .thenAccept { renderable -> modelRenderable = renderable } .exceptionally { val toast = Toast.makeText(this, "ϨϯμϦϯάͰ͖·ͤΜ", Toast.LENGTH_LONG) toast.setGravity(Gravity.CENTER, 0, 0) toast.show() null } } … } %ΦϒδΣΫτͷϨϯμϦϯάΛߏங
  30. 41.

    Copyright © 2019 eureka, Inc. All rights reserved. class ModelActivity:

    AppCompatActivity() { private var modelRenderable: ModelRenderable? = null … override fun onCreate(savedInstanceState: Bundle?) { … ModelRenderable.builder() .setSource(this, R.raw.rin) .build() .thenAccept { renderable -> modelRenderable = renderable } .exceptionally { val toast = Toast.makeText(this, "ϨϯμϦϯάͰ͖·ͤΜ", Toast.LENGTH_LONG) toast.setGravity(Gravity.CENTER, 0, 0) toast.show() null } } … } %ΞηοτΛઃఆ
  31. 42.

    Copyright © 2019 eureka, Inc. All rights reserved. class ModelActivity:

    AppCompatActivity() { private var modelRenderable: ModelRenderable? = null … override fun onCreate(savedInstanceState: Bundle?) { … ModelRenderable.builder() .setSource(this, R.raw.rin) .build() .thenAccept { renderable -> modelRenderable = renderable } .exceptionally { val toast = Toast.makeText(this, "ϨϯμϦϯάͰ͖·ͤΜ", Toast.LENGTH_LONG) toast.setGravity(Gravity.CENTER, 0, 0) toast.show() null } } … } ϨϯμϦϯά͕੒ޭͨ࣌͠ʹɺϨϯμϦϯά݁ՌΛ֨ೲ͢Δ
  32. 43.

    Copyright © 2019 eureka, Inc. All rights reserved. class ModelActivity:

    AppCompatActivity() { private var modelRenderable: ModelRenderable? = null … override fun onCreate(savedInstanceState: Bundle?) { … ModelRenderable.builder() .setSource(this, R.raw.rin) .build() .thenAccept { renderable -> modelRenderable = renderable } .exceptionally { val toast = Toast.makeText(this, "ϨϯμϦϯάͰ͖·ͤΜ", Toast.LENGTH_LONG) toast.setGravity(Gravity.CENTER, 0, 0) toast.show() null } } … } ϨϯμϦϯάʹࣦഊͨ͠ࡍͷྫ֎࣌ͷॲཧ
  33. 44.

    Copyright © 2019 eureka, Inc. All rights reserved. class ModelActivity:

    AppCompatActivity() { … override fun onCreate(savedInstanceState: Bundle?) { … val arFragment = supportFragmentManager.findFragmentById(R.id.ar_fragment) as? ArFragment arFragment?.setOnTapArPlaneListener { hitResult: HitResult, _: Plane, _: MotionEvent -> if (modelRenderable == null) { return@setOnTapArPlaneListener } Node().apply { setParent(arFragment.arSceneView.scene) renderable = modelRenderable } } } … }
  34. 45.

    Copyright © 2019 eureka, Inc. All rights reserved. class ModelActivity:

    AppCompatActivity() { … override fun onCreate(savedInstanceState: Bundle?) { … val arFragment = supportFragmentManager.findFragmentById(R.id.ar_fragment) as? ArFragment arFragment?.setOnTapArPlaneListener { hitResult: HitResult, _: Plane, _: MotionEvent -> if (modelRenderable == null) { return@setOnTapArPlaneListener } Node().apply { setParent(arFragment.arSceneView.scene) renderable = modelRenderable } } } … } "3$PSFͷσϑΥϧτͷઃఆΛ΋ͭ"3'SBHNFOU
  35. 46.

    Copyright © 2019 eureka, Inc. All rights reserved. class ModelActivity:

    AppCompatActivity() { … override fun onCreate(savedInstanceState: Bundle?) { … val arFragment = supportFragmentManager.findFragmentById(R.id.ar_fragment) as? ArFragment arFragment?.setOnTapArPlaneListener { hitResult: HitResult, _: Plane, _: MotionEvent -> if (modelRenderable == null) { return@setOnTapArPlaneListener } Node().apply { setParent(arFragment.arSceneView.scene) renderable = modelRenderable } } } … } ฏ໘Λλοϓͨ͠ࡍͷ-JTUFOFS
  36. 47.

    Copyright © 2019 eureka, Inc. All rights reserved. class ModelActivity:

    AppCompatActivity() { … override fun onCreate(savedInstanceState: Bundle?) { … val arFragment = supportFragmentManager.findFragmentById(R.id.ar_fragment) as? ArFragment arFragment?.setOnTapArPlaneListener { hitResult: HitResult, _: Plane, _: MotionEvent -> if (modelRenderable == null) { return@setOnTapArPlaneListener } Node().apply { setParent(arFragment.arSceneView.scene) renderable = modelRenderable } } } … } "S'SBHNFOUͷγʔϯʹηοτ ϨϯμϦϯάͨ͠%ΦϒδΣΫτΛઃఆ
  37. 49.

    Copyright © 2019 eureka, Inc. All rights reserved. 49 ɾࢦఆͨ͠Ξηοτͷ%ΦϒδΣΫτΛදࣔͰ͖Δ

    ɹಋೖ΍ΞηοτΛೖΕ͍ͨ৔߹ͷৄࡉ͸ɺ ɹॻ੶ʹॻ͍͍ͯΔͷͰͦͪΒΛࢀߟʹ͍ͯͩ͘͠͞ ɹαϯϓϧ͸*NBHJOF73*ODΑΓ͓आΓ͍ͯ͠·͢ ɹࢀরIUUQJNBHJOFHJSMTDPNJNBHJOFHJSMT@VTFS@MJDFOTF@KQ 3DΦϒδΣΫτΛදࣔͰ͖Δ
  38. 51.

    Copyright © 2019 eureka, Inc. All rights reserved. 51 ɾඪ४ͷ8JEHFUͱಉ༷ʹ

    ɹ%ΦϒδΣΫτΛΫϦοΫͨ͠ͱ͖ʹɺ ɹॲཧΛ࣋ͨͤΔ͜ͱ͕Ͱ͖Δ ଞʹ΋SceneformͰͰ͖Δ͜ͱ
  39. 52.

    Copyright © 2019 eureka, Inc. All rights reserved. 52 ɾ%ΦϒδΣΫτͷදࣔɺૢ࡞

    ɾը૾ΛϚʔΧʔʹͯ͠ɺ%ΦϒδΣΫτΛදࣔ"VHVNFOUFE*NBHFT ɾ̎ͭͷ୺຤Ͱɺ%ΦϒδΣΫτΛڞ༗ ARCoreͰͰ͖Δ͜ͱ
  40. 53.

    Copyright © 2019 eureka, Inc. All rights reserved. 53 ɾಛఆͷը૾ΛϚʔΧʔʹͯ͠ɺ%ΦϒδΣΫτͷද͕ࣔՄೳ

    ɾ5IFBSDPSFJNHUPPMΛ࢖ͬͯը૾ϚʔΧʔʹͰ͖Δ͔ௐ΂Δ͜ͱ͕Ͱ͖Δ Augumented Images
  41. 54.

    Copyright © 2019 eureka, Inc. All rights reserved. 54 Augumented

    Images ɾٕज़ॻయͰग़ͨ͠ಉਓࢽɺ ɹձࣾ༗ࢤͰग़൛ͨ͠ɺ ɹΤ΢ϨɾςΫϊϩΪΞͷαϯϓϧ
  42. 55.

    Copyright © 2019 eureka, Inc. All rights reserved. 55 5IFBSDPSFJNHUPPMͰը૾ΛϚʔΧʔʹͰ͖Δ͔ௐ΂Δ

    5IFBSDPSFJNHUPPMͰը૾ͷ%#Λ࡞੒͢Δ %#ʹొ࿥ͨ͠ը૾ͱ̍ϑϨʔϜ͝ͱʹΧϝϥ͔ΒऔಘͰ͖Δը૾ͱ ɹҰக͍ͯ͠Δ͔൑அͯ͠ɺ"3Λදࣔ͢Δ ಋೖͷखॱ
  43. 56.

    Copyright © 2019 eureka, Inc. All rights reserved. 56 5IFBSDPSFJNHUPPMͰը૾ΛϚʔΧʔʹͰ͖Δ͔ௐ΂Δ

    5IFBSDPSFJNHUPPMͰը૾ͷ%#Λ࡞੒͢Δ %#ʹొ࿥ͨ͠ը૾ͱ̍ϑϨʔϜ͝ͱʹΧϝϥ͔ΒऔಘͰ͖Δը૾ͱ ɹҰக͍ͯ͠Δ͔൑அͯ͠ɺ"3Λදࣔ͢Δ ಋೖͷखॱ
  44. 57.
  45. 58.

    Copyright © 2019 eureka, Inc. All rights reserved. 58 ղౚޙɺ֤04͝ͱͷϑΝΠϧ͕ଘࡏ͢ΔͷͰɺر๬ͷ04ʹҠಈ͠

    .BDͳΒλʔϛφϧͰ࣍ͷͱ͓Γʹೖྗ͢Δ͚ͩ BSDPSFJNHFWBMJNHŠJOQVU@JNBHF@QBUIIPHFIPHFGVHBGVHBKQH 8JOEPXTͳΒίϚϯυϓϩϯϓτͰ࣍ͷͱ͓Γʹೖྗ͢Δ͚ͩ BSDPSFJNHFYFFWBMJNHJOQVU@JNBHF@QBUIIPHFIPHFGVHBGVHBKQH The arcoreimg toolͰը૾ΛϚʔΧʔʹͰ͖Δ͔ௐ΂Δ
  46. 60.

    Copyright © 2019 eureka, Inc. All rights reserved. 60 5IFBSDPSFJNHUPPMͰը૾ΛϚʔΧʔʹͰ͖Δ͔ௐ΂Δ

    5IFBSDPSFJNHUPPMͰը૾ͷ%#Λ࡞੒͢Δ %#ʹొ࿥ͨ͠ը૾ͱ̍ϑϨʔϜ͝ͱʹΧϝϥ͔ΒऔಘͰ͖Δը૾ͱ ɹҰக͍ͯ͠Δ͔൑அͯ͠ɺ"3Λදࣔ͢Δ ಋೖͷखॱ
  47. 61.

    Copyright © 2019 eureka, Inc. All rights reserved. 61 ɾ5IFBSDPSFJNHUPPMΛར༻ͯ͠04͝ͱʹ࣍ͷͱ͓Γʹೖྗ͢Δ

    .BD BSDPSFJNHCVJMEECJOQVU@JNBHFT@EJSFDUPSZQBUIUPJNBHFT PVUQVU@EC@QBUIQBUIUPTBNQMF@EBUBCBTFJNHEC 8JOEPXT BSDPSFJNHFYFCVJMEECJOQVU@JNBHFT@EJSFDUPSZQBUIUPJNBHFT PVUQVU@EC@QBUIQBUIUPTBNQMF@EBUBCBTFJNHEC The arcoreimg toolͰը૾ͷDBΛ࡞੒͢Δ
  48. 63.

    Copyright © 2019 eureka, Inc. All rights reserved. 63 5IFBSDPSFJNHUPPMͰը૾ΛϚʔΧʔʹͰ͖Δ͔ௐ΂Δ

    5IFBSDPSFJNHUPPMͰը૾ͷ%#Λ࡞੒͢Δ %#ʹొ࿥ͨ͠ը૾ͱ̍ϑϨʔϜ͝ͱʹΧϝϥ͔ΒऔಘͰ͖Δը૾ͱ ɹҰக͍ͯ͠Δ͔൑அͯ͠ɺ"3Λදࣔ͢Δ ಋೖͷखॱ
  49. 64.

    Copyright © 2019 eureka, Inc. All rights reserved. 64 ̍ϑϨʔϜ͝ͱʹΧϝϥը૾ͱɺࣄલʹ࡞੒ͨ͠%#ͷJNBHFʹ߹க͍ͯ͠

    Δ͔ɺ൑அͯ͠"3Λදࣔ͢ΔॲཧΛॻ͘ ࣄલʹొ࿥ͨ͠%#͔ΒಡΈग़ͯ͠ɺ4FTTJPOΫϥεͱ$POpHΫϥεͰઃఆ Λߦ͏ Augumented ImagesΛ࣮૷͢Δखॱ
  50. 65.

    Copyright © 2019 eureka, Inc. All rights reserved. 65 ̍ϑϨʔϜ͝ͱʹΧϝϥը૾ͱɺࣄલʹ࡞੒ͨ͠%#ͷJNBHFʹ߹க͍ͯ͠

    Δ͔ɺ൑அͯ͠"3Λදࣔ͢ΔॲཧΛॻ͘ ࣄલʹొ࿥ͨ͠%#͔ΒಡΈग़ͯ͠ɺ4FTTJPOΫϥεͱ$POpHΫϥεͰઃఆ Λߦ͏ Augumented ImagesΛ࣮૷͢Δखॱ
  51. 66.

    Copyright © 2019 eureka, Inc. All rights reserved. class AugmentedImageActivity:

    AppCompatActivity() { private var arSceneView: ArSceneView? = null override fun onCreate(savedInstanceState: Bundle?) { … val arFragment = supportFragmentManager.findFragmentById(R.id.ar_fragment) as ArFragment? if (arFragment != null) { arFragment.planeDiscoveryController?.hide() arFragment.planeDiscoveryController?.setInstructionView(null) arSceneView = arFragment.arSceneView arFragment.arSceneView?.scene?.addOnUpdateListener { val frame = arFragment.arSceneView?.arFrame val updatedAugmentedImages = frame?.getUpdatedTrackables(AugmentedImage::class.java) ?: return@addOnUpdateListener for (img in updatedAugmentedImages) { if (img.trackingState == TrackingState.TRACKING) { if (img.name.contains("eure") && !isAttachedModel) { // ͜͜ʹARΛදࣔ͢ΔॲཧΛॻ͘ } } } } } … } }
  52. 67.

    Copyright © 2019 eureka, Inc. All rights reserved. class AugmentedImageActivity:

    AppCompatActivity() { private var arSceneView: ArSceneView? = null override fun onCreate(savedInstanceState: Bundle?) { … val arFragment = supportFragmentManager.findFragmentById(R.id.ar_fragment) as ArFragment? if (arFragment != null) { arFragment.planeDiscoveryController?.hide() arFragment.planeDiscoveryController?.setInstructionView(null) arSceneView = arFragment.arSceneView arFragment.arSceneView?.scene?.addOnUpdateListener { val frame = arFragment.arSceneView?.arFrame val updatedAugmentedImages = frame?.getUpdatedTrackables(AugmentedImage::class.java) ?: return@addOnUpdateListener for (img in updatedAugmentedImages) { if (img.trackingState == TrackingState.TRACKING) { if (img.name.contains("eure") && !isAttachedModel) { // ͜͜ʹARΛදࣔ͢ΔॲཧΛॻ͘ } } } } } … } } 1MBOFͷݕग़Λ0⒎ ॳճදࣔ͞ΕΔखͷίʔνϯάΛͳ͘͢
  53. 68.

    Copyright © 2019 eureka, Inc. All rights reserved. class AugmentedImageActivity:

    AppCompatActivity() { private var arSceneView: ArSceneView? = null override fun onCreate(savedInstanceState: Bundle?) { … val arFragment = supportFragmentManager.findFragmentById(R.id.ar_fragment) as ArFragment? if (arFragment != null) { arFragment.planeDiscoveryController?.hide() arFragment.planeDiscoveryController?.setInstructionView(null) arSceneView = arFragment.arSceneView arFragment.arSceneView?.scene?.addOnUpdateListener { val frame = arFragment.arSceneView?.arFrame val updatedAugmentedImages = frame?.getUpdatedTrackables(AugmentedImage::class.java) ?: return@addOnUpdateListener for (img in updatedAugmentedImages) { if (img.trackingState == TrackingState.TRACKING) { if (img.name.contains("eure") && !isAttachedModel) { // ͜͜ʹARΛදࣔ͢ΔॲཧΛॻ͘ } } } } } … } } ϑϨʔϜ͝ͱʹݺ͹ΕΔ
  54. 69.

    Copyright © 2019 eureka, Inc. All rights reserved. class AugmentedImageActivity:

    AppCompatActivity() { private var arSceneView: ArSceneView? = null override fun onCreate(savedInstanceState: Bundle?) { … val arFragment = supportFragmentManager.findFragmentById(R.id.ar_fragment) as ArFragment? if (arFragment != null) { arFragment.planeDiscoveryController?.hide() arFragment.planeDiscoveryController?.setInstructionView(null) arSceneView = arFragment.arSceneView arFragment.arSceneView?.scene?.addOnUpdateListener { val frame = arFragment.arSceneView?.arFrame val updatedAugmentedImages = frame?.getUpdatedTrackables(AugmentedImage::class.java) ?: return@addOnUpdateListener for (img in updatedAugmentedImages) { if (img.trackingState == TrackingState.TRACKING) { if (img.name.contains("eure") && !isAttachedModel) { // ͜͜ʹARΛදࣔ͢ΔॲཧΛॻ͘ } } } } } … } } ϑϨʔϜ͝ͱʹ"VHVNFOUFE*NBHFͱ͍͏ΫϥεͰࢦఆͯ͠ɺ Χϝϥͷը૾Λऔಘ͢Δ
  55. 70.

    Copyright © 2019 eureka, Inc. All rights reserved. class AugmentedImageActivity:

    AppCompatActivity() { private var arSceneView: ArSceneView? = null override fun onCreate(savedInstanceState: Bundle?) { … val arFragment = supportFragmentManager.findFragmentById(R.id.ar_fragment) as ArFragment? if (arFragment != null) { arFragment.planeDiscoveryController?.hide() arFragment.planeDiscoveryController?.setInstructionView(null) arSceneView = arFragment.arSceneView arFragment.arSceneView?.scene?.addOnUpdateListener { val frame = arFragment.arSceneView?.arFrame val updatedAugmentedImages = frame?.getUpdatedTrackables(AugmentedImage::class.java) ?: return@addOnUpdateListener for (img in updatedAugmentedImages) { if (img.trackingState == TrackingState.TRACKING) { if (img.name.contains("eure")) { // ͜͜ʹARΛදࣔ͢ΔॲཧΛॻ͘ } } } } } … } } ը૾ͷτϥοΩϯάঢ়ଶΛΈͯɺࣄલʹొ࿥ͯ͋ͬͨ͠ը૾ͷ%#ʹ Χϝϥͷը૾͔Βऔಘ͖ͯͨ͠ը૾ʹ֘౰ͨ͠ࡍʹ"3Λදࣔ͢Δ
  56. 71.

    Copyright © 2019 eureka, Inc. All rights reserved. 71 ̍ϑϨʔϜ͝ͱʹΧϝϥը૾ͱɺࣄલʹ࡞੒ͨ͠%#ͷJNBHFʹ߹க͍ͯ͠

    Δ͔ɺ൑அͯ͠"3Λදࣔ͢ΔॲཧΛॻ͘ ࣄલʹొ࿥ͨ͠%#͔ΒಡΈग़ͯ͠ɺ4FTTJPOΫϥεͱ$POpHΫϥεͰઃఆ Λߦ͏ Augumented ImagesΛ࣮૷͢Δखॱ
  57. 72.

    Copyright © 2019 eureka, Inc. All rights reserved. class AugmentedImageActivity:

    AppCompatActivity() { private var session: Session? = null private var arSceneView: ArSceneView? = null override fun onCreate(savedInstanceState: Bundle?) { … if (session == null) { try { session = Session(this) } catch (e: UnavailableArcoreNotInstalledException) { Log.e("Session Error", e.message) } catch (e: UnavailableApkTooOldException) { Log.e("Session Error", e.message) } catch (e: UnavailableSdkTooOldException) { Log.e("Session Error", e.message) } val config = Config(session) val inputStream: InputStream try { inputStream = assets.open("sample_database.imgdb") val imageDatabase = AugmentedImageDatabase.deserialize(session, inputStream) with(config) { augmentedImageDatabase = imageDatabase updateMode = Config.UpdateMode.LATEST_CAMERA_IMAGE session?.configure(this) } } catch (e: IOException) { Toast.makeText(this, "SessionΛઃఆ͢Δ͜ͱ͕Ͱ͖·ͤΜ", Toast.LENGTH_SHORT).show() Timber.e(e) } arSceneView?.setupSession(session) } … } }
  58. 73.

    Copyright © 2019 eureka, Inc. All rights reserved. class AugmentedImageActivity:

    AppCompatActivity() { private var session: Session? = null private var arSceneView: ArSceneView? = null override fun onCreate(savedInstanceState: Bundle?) { … if (session == null) { try { session = Session(this) } catch (e: UnavailableArcoreNotInstalledException) { Log.e("Session Error", e.message) } catch (e: UnavailableApkTooOldException) { Log.e("Session Error", e.message) } catch (e: UnavailableSdkTooOldException) { Log.e("Session Error", e.message) } val config = Config(session) val inputStream: InputStream try { inputStream = assets.open("sample_database.imgdb") val imageDatabase = AugmentedImageDatabase.deserialize(session, inputStream) with(config) { augmentedImageDatabase = imageDatabase updateMode = Config.UpdateMode.LATEST_CAMERA_IMAGE session?.configure(this) } } catch (e: IOException) { Toast.makeText(this, "SessionΛઃఆ͢Δ͜ͱ͕Ͱ͖·ͤΜ", Toast.LENGTH_SHORT).show() Timber.e(e) } arSceneView?.setupSession(session) } … } } 4FTTJPOΛΠϯελϯεԽ
  59. 74.

    Copyright © 2019 eureka, Inc. All rights reserved. class AugmentedImageActivity:

    AppCompatActivity() { private var session: Session? = null private var arSceneView: ArSceneView? = null override fun onCreate(savedInstanceState: Bundle?) { … if (session == null) { try { session = Session(this) } catch (e: UnavailableArcoreNotInstalledException) { Log.e("Session Error", e.message) } catch (e: UnavailableApkTooOldException) { Log.e("Session Error", e.message) } catch (e: UnavailableSdkTooOldException) { Log.e("Session Error", e.message) } val config = Config(session) val inputStream: InputStream try { inputStream = assets.open("sample_database.imgdb") val imageDatabase = AugmentedImageDatabase.deserialize(session, inputStream) with(config) { augmentedImageDatabase = imageDatabase updateMode = Config.UpdateMode.LATEST_CAMERA_IMAGE session?.configure(this) } } catch (e: IOException) { Toast.makeText(this, "SessionΛઃఆ͢Δ͜ͱ͕Ͱ͖·ͤΜ", Toast.LENGTH_SHORT).show() Timber.e(e) } arSceneView?.setupSession(session) } … } } $POpHΛΠϯελϯεԽ
  60. 75.

    Copyright © 2019 eureka, Inc. All rights reserved. class AugmentedImageActivity:

    AppCompatActivity() { private var session: Session? = null private var arSceneView: ArSceneView? = null override fun onCreate(savedInstanceState: Bundle?) { … if (session == null) { try { session = Session(this) } catch (e: UnavailableArcoreNotInstalledException) { Log.e("Session Error", e.message) } catch (e: UnavailableApkTooOldException) { Log.e("Session Error", e.message) } catch (e: UnavailableSdkTooOldException) { Log.e("Session Error", e.message) } val config = Config(session) val inputStream: InputStream try { inputStream = assets.open("sample_database.imgdb") val imageDatabase = AugmentedImageDatabase.deserialize(session, inputStream) with(config) { augmentedImageDatabase = imageDatabase updateMode = Config.UpdateMode.LATEST_CAMERA_IMAGE session?.configure(this) } } catch (e: IOException) { Toast.makeText(this, "SessionΛઃఆ͢Δ͜ͱ͕Ͱ͖·ͤΜ", Toast.LENGTH_SHORT).show() Timber.e(e) } arSceneView?.setupSession(session) } … } } ࢲͷ৔߹͸ɺBTTFU഑ԼʹECΛ࡞੒ͨͨ͠Ίɺ ։͍ͯ%#Λϩʔυ͢Δ
  61. 76.

    Copyright © 2019 eureka, Inc. All rights reserved. class AugmentedImageActivity:

    AppCompatActivity() { private var session: Session? = null private var arSceneView: ArSceneView? = null override fun onCreate(savedInstanceState: Bundle?) { … if (session == null) { try { session = Session(this) } catch (e: UnavailableArcoreNotInstalledException) { Log.e("Session Error", e.message) } catch (e: UnavailableApkTooOldException) { Log.e("Session Error", e.message) } catch (e: UnavailableSdkTooOldException) { Log.e("Session Error", e.message) } val config = Config(session) val inputStream: InputStream try { inputStream = assets.open("sample_database.imgdb") val imageDatabase = AugmentedImageDatabase.deserialize(session, inputStream) with(config) { augmentedImageDatabase = imageDatabase updateMode = Config.UpdateMode.LATEST_CAMERA_IMAGE session?.configure(this) } } catch (e: IOException) { Toast.makeText(this, "SessionΛઃఆ͢Δ͜ͱ͕Ͱ͖·ͤΜ", Toast.LENGTH_SHORT).show() Timber.e(e) } arSceneView?.setupSession(session) } … } } ϩʔυͨ͠σʔλϕʔεΛઃఆ
  62. 77.

    Copyright © 2019 eureka, Inc. All rights reserved. class AugmentedImageActivity:

    AppCompatActivity() { private var session: Session? = null private var arSceneView: ArSceneView? = null override fun onCreate(savedInstanceState: Bundle?) { … if (session == null) { try { session = Session(this) } catch (e: UnavailableArcoreNotInstalledException) { Log.e("Session Error", e.message) } catch (e: UnavailableApkTooOldException) { Log.e("Session Error", e.message) } catch (e: UnavailableSdkTooOldException) { Log.e("Session Error", e.message) } val config = Config(session) val inputStream: InputStream try { inputStream = assets.open("sample_database.imgdb") val imageDatabase = AugmentedImageDatabase.deserialize(session, inputStream) with(config) { augmentedImageDatabase = imageDatabase updateMode = Config.UpdateMode.LATEST_CAMERA_IMAGE session?.configure(this) } } catch (e: IOException) { Toast.makeText(this, "SessionΛઃఆ͢Δ͜ͱ͕Ͱ͖·ͤΜ", Toast.LENGTH_SHORT).show() Timber.e(e) } arSceneView?.setupSession(session) } … } } "3$PSFγεςϜͷঢ়ଶ͕ߋ৽͞ΕΔ࣌ͷ.PEFΛઃఆ
  63. 78.

    Copyright © 2019 eureka, Inc. All rights reserved. class AugmentedImageActivity:

    AppCompatActivity() { private var session: Session? = null private var arSceneView: ArSceneView? = null override fun onCreate(savedInstanceState: Bundle?) { … if (session == null) { try { session = Session(this) } catch (e: UnavailableArcoreNotInstalledException) { Log.e("Session Error", e.message) } catch (e: UnavailableApkTooOldException) { Log.e("Session Error", e.message) } catch (e: UnavailableSdkTooOldException) { Log.e("Session Error", e.message) } val config = Config(session) val inputStream: InputStream try { inputStream = assets.open("sample_database.imgdb") val imageDatabase = AugmentedImageDatabase.deserialize(session, inputStream) with(config) { augmentedImageDatabase = imageDatabase updateMode = Config.UpdateMode.LATEST_CAMERA_IMAGE session?.configure(this) } } catch (e: IOException) { Toast.makeText(this, "SessionΛઃఆ͢Δ͜ͱ͕Ͱ͖·ͤΜ", Toast.LENGTH_SHORT).show() Timber.e(e) } arSceneView?.setupSession(session) } … } } 4FTTJPOʹઃఆΛ൓ө
  64. 80.

    Copyright © 2019 eureka, Inc. All rights reserved. 80 ɾ%ΦϒδΣΫτͷදࣔɺૢ࡞

    ɾը૾ΛϚʔΧʔʹͯ͠ɺ%ΦϒδΣΫτΛදࣔ ɾ̎ͭͷ୺຤Ͱɺ%ΦϒδΣΫτΛڞ༗$MPVE"ODIPST ARCoreͰͰ͖Δ͜ͱ
  65. 81.

    Copyright © 2019 eureka, Inc. All rights reserved. 81 ɾ($1Λར༻ͯ͠ɺ̎ͭͷ୺຤Ͱ"3Λڞ༗͢Δ͜ͱ͕Մೳ

    Cloud Anchors ࢀরݩ: https://developers.google.com/ar/images/cloud-anchors/Cloud_anchors_demo_video.mp4
  66. 82.

    Copyright © 2019 eureka, Inc. All rights reserved. 82 "3'SBHNFOUΛܧঝͨ͠ΫϥεͰɺ$MPVE"ODIPS.PEFΛ&OBCMFʹͨ͠ΧελϜ"3'SBHNFOUΛ࡞੒

    ͢Δ $MPVE"ODIPSTͷঢ়ଶ؅ཧΛ࣋ͭΫϥεΛ༻ҙ͢Δ $MPVE"ODIPSTͷ৘ใΛอଘͨ͠Γɺࢀর͢ΔͨΊͷ'JSFCBTF.BOBHFSΫϥεΛ༻ҙ͢Δ ɹ'JSFCBTFʹ"ODIPS*%Λอଘ͢ΔͨΊͷػߏΛ༻ҙ͢Δ Cloud AnchorsΛ࣮૷͢Δखॱ
  67. 83.

    Copyright © 2019 eureka, Inc. All rights reserved. 83 ɾઐ໳஌͕ࣝͳͯ͘΋ɺ"3$PSFͱ4DFOFGPSNΛར༻͢Δ͜ͱͰɺ

    ɹ"3ػೳΛ؆୯ʹ࣮ݱͰ͖Δ ɾ"S'SBHNFOU͕ศར ɾ"3$PSFͷجຊΫϥεΛԡ͑͞ͱ͚͹େମͰ͖Δ ͓ΘΓʹ