แสดงสถานที่ใกล้เคียงด้วย AR บน Android (Kotlin)

1. ก่อนเริ่มต้น

บทคัดย่อ

Codelab นี้จะสอนวิธีใช้ข้อมูลจาก Google Maps Platform เพื่อแสดงสถานที่ใกล้เคียงในเทคโนโลยีความจริงเสริม (AR) บน Android

2344909dd9a52c60.png

ข้อกำหนดเบื้องต้น

  • มีความเข้าใจพื้นฐานเกี่ยวกับการพัฒนา Android โดยใช้ Android Studio
  • คุ้นเคยกับ Kotlin

สิ่งที่คุณจะได้เรียนรู้

  • ขอสิทธิ์จากผู้ใช้เพื่อเข้าถึงกล้องและตำแหน่งของอุปกรณ์
  • ผสานรวมกับ Places API เพื่อดึงข้อมูลสถานที่ใกล้เคียงรอบตำแหน่งของอุปกรณ์
  • ผสานรวมกับ ARCore เพื่อค้นหาพื้นผิวระนาบแนวนอนเพื่อให้สามารถยึดและวางวัตถุเสมือนในพื้นที่ 3 มิติโดยใช้ Sceneform
  • รวบรวมข้อมูลเกี่ยวกับตำแหน่งของอุปกรณ์ในพื้นที่โดยใช้ SensorManager และใช้ Maps SDK สำหรับ Android Utility Library เพื่อวางตำแหน่งออบเจ็กต์เสมือนในส่วนหัวที่ถูกต้อง

สิ่งที่ต้องมี

2. ตั้งค่า

Android Studio

Codelab นี้ใช้ Android 10.0 (API ระดับ 29) และกำหนดให้คุณต้องติดตั้งบริการ Google Play ใน Android Studio หากต้องการติดตั้งทั้ง 2 รายการนี้ ให้ทำตามขั้นตอนต่อไปนี้

  1. ไปที่ SDK Manager ซึ่งคุณเข้าถึงได้โดยคลิกเครื่องมือ > SDK Manager

6c44a9cb9cf6c236.png

  1. ตรวจสอบว่าติดตั้ง Android 10.0 แล้ว หากยังไม่ได้ติดตั้ง ให้เลือกช่องทําเครื่องหมายข้าง Android 10.0 (Q) แล้วคลิกตกลง จากนั้นคลิกตกลงอีกครั้งในกล่องโต้ตอบที่ปรากฏขึ้น

368f17a974c75c73.png

  1. สุดท้าย ให้ติดตั้งบริการ Google Play โดยไปที่แท็บ SDK Tools เลือกช่องทําเครื่องหมายข้าง Google Play services คลิก OK แล้วเลือก OK อีกครั้งในกล่องโต้ตอบที่ปรากฏขึ้น**

497a954b82242f4b.png

API ที่จำเป็น

ในขั้นตอนที่ 3 ของส่วนต่อไปนี้ ให้เปิดใช้ Maps SDK สำหรับ Android และ Places API สำหรับ Codelab นี้

เริ่มต้นใช้งาน Google Maps Platform

หากคุณยังไม่เคยใช้ Google Maps Platform มาก่อน ให้ทำตามคู่มือการเริ่มต้นใช้งาน Google Maps Platform หรือดูเพลย์ลิสต์การเริ่มต้นใช้งาน Google Maps Platform เพื่อทำตามขั้นตอนต่อไปนี้

  1. สร้างบัญชีสำหรับการเรียกเก็บเงิน
  2. สร้างโปรเจ็กต์
  3. เปิดใช้ Google Maps Platform API และ SDK (แสดงอยู่ในส่วนก่อนหน้า)
  4. สร้างคีย์ API

ไม่บังคับ: โปรแกรมจำลอง Android

หากไม่มีอุปกรณ์ที่รองรับ ARCore คุณสามารถใช้โปรแกรมจำลอง Android เพื่อจำลองฉาก AR รวมถึงจำลองตำแหน่งของอุปกรณ์แทนได้ เนื่องจากคุณจะใช้ Sceneform ในแบบฝึกหัดนี้ด้วย คุณจึงต้องทำตามขั้นตอนในส่วน "กำหนดค่าโปรแกรมจำลองเพื่อรองรับ Sceneform" ด้วย

3. การเริ่มใช้งานอย่างง่าย

เรามีโค้ดเริ่มต้นที่จะช่วยให้คุณเริ่มต้นใช้งานได้อย่างรวดเร็วที่สุด และช่วยให้คุณทำตาม Codelab นี้ได้ คุณสามารถข้ามไปยังวิธีแก้ปัญหาได้ แต่หากต้องการดูขั้นตอนทั้งหมด โปรดอ่านต่อ

คุณสามารถโคลนที่เก็บได้หากติดตั้ง git ไว้

git clone https://github.com/googlecodelabs/display-nearby-places-ar-android.git

หรือจะคลิกปุ่มด้านล่างเพื่อดาวน์โหลดซอร์สโค้ดก็ได้

เมื่อได้รับรหัสแล้ว ให้เปิดโปรเจ็กต์ที่อยู่ในไดเรกทอรี starter

4. ภาพรวมโครงการ

สำรวจโค้ดที่คุณดาวน์โหลดจากขั้นตอนก่อนหน้า ภายในที่เก็บนี้ คุณควรจะเห็นโมดูลเดียวชื่อ app ซึ่งมีแพ็กเกจ com.google.codelabs.findnearbyplacesar

AndroidManifest.xml

แอตทริบิวต์ต่อไปนี้จะประกาศในไฟล์ AndroidManifest.xml เพื่อให้คุณใช้ฟีเจอร์ที่จำเป็นในโค้ดแล็บนี้ได้

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

<!-- Sceneform requires OpenGL ES 3.0 or later. -->
<uses-feature
   android:glEsVersion="0x00030000"
   android:required="true" />

<!-- Indicates that app requires ARCore ("AR Required"). Ensures the app is visible only in the Google Play Store on devices that support ARCore. For "AR Optional" apps remove this line. -->
<uses-feature android:name="android.hardware.camera.ar" />

สำหรับ uses-permission ซึ่งระบุสิทธิ์ที่ผู้ใช้ต้องให้ก่อนจึงจะใช้ความสามารถเหล่านั้นได้ เราได้ประกาศสิ่งต่อไปนี้

  • android.permission.INTERNET - เพื่อให้แอปของคุณดำเนินการเครือข่ายและดึงข้อมูลผ่านอินเทอร์เน็ตได้ เช่น ข้อมูลสถานที่ผ่าน Places API
  • android.permission.CAMERA - ต้องมีสิทธิ์เข้าถึงกล้องเพื่อให้คุณใช้กล้องของอุปกรณ์เพื่อแสดงวัตถุใน Augmented Reality ได้
  • android.permission.ACCESS_FINE_LOCATION—ต้องมีสิทธิ์เข้าถึงตำแหน่งเพื่อให้คุณดึงข้อมูลสถานที่ใกล้เคียงที่สัมพันธ์กับตำแหน่งของอุปกรณ์ได้

สำหรับ uses-feature ซึ่งระบุว่าแอปนี้ต้องใช้ฟีเจอร์ฮาร์ดแวร์ใดบ้าง จะมีการประกาศดังนี้

  • ต้องใช้ OpenGL ES เวอร์ชัน 3.0
  • ต้องใช้อุปกรณ์ที่รองรับ ARCore

นอกจากนี้ ระบบจะเพิ่มแท็กข้อมูลเมตาต่อไปนี้ภายใต้วัตถุแอปพลิเคชัน

<application
  android:allowBackup="true"
  android:icon="@mipmap/ic_launcher"
  android:label="@string/app_name"
  android:roundIcon="@mipmap/ic_launcher_round"
  android:supportsRtl="true"
  android:theme="@style/AppTheme">
  
  <!-- 
     Indicates that this app requires Google Play Services for AR ("AR Required") and causes
     the Google Play Store to download and install Google Play Services for AR along with
     the app. For an "AR Optional" app, specify "optional" instead of "required". 
  -->

  <meta-data
     android:name="com.google.ar.core"
     android:value="required" />

  <meta-data
     android:name="com.google.android.geo.API_KEY"
     android:value="@string/google_maps_key" />

  <!-- Additional elements here --> 

</application>

รายการข้อมูลเมตาแรกคือการระบุว่า ARCore เป็นข้อกำหนดสำหรับแอปนี้ในการเรียกใช้ และรายการที่ 2 คือวิธีที่คุณระบุคีย์ API ของ Google Maps Platform ให้กับ Maps SDK สำหรับ Android

build.gradle

ใน build.gradle จะมีการระบุทรัพยากร Dependency เพิ่มเติมต่อไปนี้

dependencies {
    // Maps & Location
    implementation 'com.google.android.gms:play-services-location:17.0.0'
    implementation 'com.google.android.gms:play-services-maps:17.0.0'
    implementation 'com.google.maps.android:maps-utils-ktx:1.7.0'

    // ARCore
    implementation "com.google.ar.sceneform.ux:sceneform-ux:1.15.0"

    // Retrofit
    implementation "com.squareup.retrofit2:retrofit:2.7.1"
    implementation "com.squareup.retrofit2:converter-gson:2.7.1"
}

ต่อไปนี้คือคำอธิบายโดยย่อของการขึ้นต่อกันแต่ละรายการ

  • ไลบรารีที่มีรหัสกลุ่ม com.google.android.gms ได้แก่ play-services-location และ play-services-maps ใช้เพื่อเข้าถึงข้อมูลตำแหน่งของอุปกรณ์และเข้าถึงฟังก์ชันการทำงานที่เกี่ยวข้องกับ Google Maps
  • com.google.maps.android:maps-utils-ktx คือไลบรารีส่วนขยาย Kotlin (KTX) สำหรับไลบรารียูทิลิตีของ Maps SDK สำหรับ Android ระบบจะใช้ฟังก์ชันการทำงานในไลบรารีนี้เพื่อจัดตำแหน่งออบเจ็กต์เสมือนในพื้นที่จริงในภายหลัง
  • com.google.ar.sceneform.ux:sceneform-ux คือไลบรารี Sceneform ซึ่งจะช่วยให้คุณแสดงฉาก 3 มิติที่สมจริงได้โดยไม่ต้องเรียนรู้ OpenGL
  • การอ้างอิงภายในรหัสกลุ่ม com.squareup.retrofit2 คือการอ้างอิง Retrofit ซึ่งช่วยให้คุณเขียนไคลเอ็นต์ HTTP เพื่อโต้ตอบกับ Places API ได้อย่างรวดเร็ว

โครงสร้างโปรเจ็กต์

คุณจะเห็นแพ็กเกจและไฟล์ต่อไปนี้

  • **api -**แพ็กเกจนี้มีคลาสที่ใช้ในการโต้ตอบกับ Places API โดยใช้ Retrofit
  • **ar -**แพ็กเกจนี้มีไฟล์ทั้งหมดที่เกี่ยวข้องกับ ARCore
  • **model -**แพ็กเกจนี้มีคลาสข้อมูลเดียว Place ซึ่งใช้ในการแคปซูลสถานที่เดียวตามที่ Places API แสดงผล
  • MainActivity.kt - นี่คือ Activity รายการเดียวที่อยู่ในแอปของคุณ ซึ่งจะแสดงแผนที่และมุมมองกล้อง

5. การตั้งค่าฉาก

เจาะลึกคอมโพเนนต์หลักของแอปโดยเริ่มจากชิ้นส่วนของเทคโนโลยีความจริงเสริม

MainActivity มี SupportMapFragment ซึ่งจะจัดการการแสดงออบเจ็กต์แผนที่ และคลาสย่อยของ ArFragmentPlacesArFragment—ซึ่งจะจัดการการแสดงฉากความเป็นจริงเสริม

การตั้งค่า Augmented Reality

นอกเหนือจากการแสดงฉาก Augmented Reality แล้ว PlacesArFragment ยังจัดการการขอสิทธิ์เข้าถึงกล้องจากผู้ใช้ด้วย หากยังไม่ได้รับสิทธิ์ นอกจากนี้ยังขอสิทธิ์เพิ่มเติมได้โดยการลบล้างเมธอด getAdditionalPermissions เนื่องจากคุณต้องได้รับสิทธิ์เข้าถึงตำแหน่งด้วย ให้ระบุสิทธิ์ดังกล่าวและลบล้างเมธอด getAdditionalPermissions ดังนี้

class PlacesArFragment : ArFragment() {

   override fun getAdditionalPermissions(): Array<String> =
       listOf(Manifest.permission.ACCESS_FINE_LOCATION)
           .toTypedArray()
}

เรียกใช้

เปิดโค้ดโครงร่างในไดเรกทอรี starter ใน Android Studio หากคลิกเรียกใช้ > เรียกใช้ "แอป" จากแถบเครื่องมือและติดตั้งใช้งานแอปในอุปกรณ์หรือโปรแกรมจำลอง คุณควรได้รับแจ้งให้เปิดใช้สิทธิ์เข้าถึงตำแหน่งและกล้องก่อน คลิกอนุญาต แล้วคุณจะเห็นมุมมองกล้องและมุมมองแผนที่อยู่ข้างกันดังนี้

e3e3073d5c86f427.png

การตรวจจับเครื่องบิน

เมื่อมองไปรอบๆ สภาพแวดล้อมที่คุณอยู่ด้วยกล้อง คุณอาจเห็นจุดสีขาว 2 จุดซ้อนทับบนพื้นผิวแนวนอน คล้ายกับจุดสีขาวบนพรมในรูปภาพนี้

2a9b6ea7dcb2e249.png

จุดสีขาวเหล่านี้คือแนวทางที่ ARCore ระบุเพื่อแสดงว่าตรวจพบระนาบแนวนอนแล้ว ระนาบที่ตรวจพบเหล่านี้ช่วยให้คุณสร้างสิ่งที่เรียกว่า "Anchor" เพื่อวางตำแหน่งออบเจ็กต์เสมือนในพื้นที่จริงได้

อ่านข้อมูลเพิ่มเติมเกี่ยวกับ ARCore และวิธีที่ ARCore เข้าใจสภาพแวดล้อมรอบตัวคุณได้ที่แนวคิดพื้นฐานของ ARCore

6. รับข้อมูลสถานที่ใกล้เคียง

จากนั้นคุณจะต้องเข้าถึงและแสดงตำแหน่งปัจจุบันของอุปกรณ์ แล้วดึงข้อมูลสถานที่ใกล้เคียงโดยใช้ Places API

การตั้งค่า Maps

คีย์ API ของ Google Maps Platform

ก่อนหน้านี้ คุณได้สร้างคีย์ API ของ Google Maps Platform เพื่อเปิดใช้การค้นหา Places API และเพื่อให้ใช้ Maps SDK สำหรับ Android ได้ เปิดไฟล์ gradle.properties แล้วแทนที่สตริง "YOUR API KEY HERE" ด้วยคีย์ API ที่คุณสร้างขึ้น

แสดงตำแหน่งอุปกรณ์บนแผนที่

เมื่อเพิ่มคีย์ API แล้ว ให้เพิ่มตัวช่วยในแผนที่เพื่อช่วยให้ผู้ใช้ทราบตำแหน่งของตนเองเมื่อเทียบกับแผนที่ โดยไปที่setUpMaps method แล้วตั้งค่า googleMap.isMyLocationEnabled เป็น true. ภายใน mapFragment.getMapAsync call การดำเนินการนี้จะแสดงจุดสีน้ำเงินบนแผนที่

private fun setUpMaps() {
   mapFragment.getMapAsync { googleMap ->
       googleMap.isMyLocationEnabled = true
       // ...
   }
}

รับตำแหน่งปัจจุบัน

หากต้องการทราบตำแหน่งของอุปกรณ์ คุณจะต้องใช้คลาส FusedLocationProviderClient เราได้ดำเนินการขออินสแตนซ์นี้แล้วในเมธอด onCreate ของ MainActivity หากต้องการใช้ออบเจ็กต์นี้ ให้กรอกข้อมูลในเมธอด getCurrentLocation ซึ่งรับอาร์กิวเมนต์ Lambda เพื่อให้ส่งตำแหน่งไปยังผู้เรียกเมธอดนี้ได้

หากต้องการใช้วิธีนี้ให้เสร็จสมบูรณ์ คุณสามารถเข้าถึงพร็อพเพอร์ตี้ lastLocation ของออบเจ็กต์ FusedLocationProviderClient แล้วเพิ่ม addOnSuccessListener ดังนี้

fusedLocationClient.lastLocation.addOnSuccessListener { location ->
    currentLocation = location
    onSuccess(location)
}.addOnFailureListener {
    Log.e(TAG, "Could not get location")
}

เมธอด getCurrentLocation จะเรียกใช้จากภายใน Lambda ที่ระบุใน getMapAsync ในเมธอด setUpMaps ซึ่งจะดึงข้อมูลสถานที่ใกล้เคียง

เริ่มการเรียกเครือข่าย Places

ในgetNearbyPlacesการเรียกเมธอด โปรดทราบว่าระบบจะส่งพารามิเตอร์ต่อไปนี้ไปยังเมธอด placesServices.nearbyPlaces ซึ่งได้แก่ คีย์ API, ตำแหน่งของอุปกรณ์, รัศมีเป็นเมตร (ซึ่งตั้งค่าเป็น 2 กม.) และประเภทสถานที่ (ปัจจุบันตั้งค่าเป็น park)

val apiKey = "YOUR API KEY"
placesService.nearbyPlaces(
   apiKey = apiKey,
   location = "${location.latitude},${location.longitude}",
   radiusInMeters = 2000,
   placeType = "park"
)

หากต้องการทำการเรียกเครือข่ายให้เสร็จสมบูรณ์ ให้ส่งคีย์ API ที่คุณกำหนดไว้ในไฟล์ gradle.properties ข้อมูลโค้ดต่อไปนี้กำหนดไว้ในไฟล์ build.gradle ภายใต้การกำหนดค่า android > defaultConfig

android {
   defaultConfig {
       resValue "string", "google_maps_key", (project.findProperty("GOOGLE_MAPS_API_KEY") ?: "")
   }
}

ซึ่งจะทำให้ค่าทรัพยากรสตริง google_maps_key พร้อมใช้งานในเวลาบิลด์

หากต้องการทำการเรียกเครือข่ายให้เสร็จสมบูรณ์ คุณเพียงแค่อ่านทรัพยากรสตริงนี้ผ่าน getString ในออบเจ็กต์ Context

val apiKey = this.getString(R.string.google_maps_key)

7. สถานที่ใน AR

จนถึงตอนนี้ คุณได้ทำสิ่งต่อไปนี้แล้ว

  1. ขอสิทธิ์เข้าถึงกล้องและตำแหน่งจากผู้ใช้เมื่อเรียกใช้แอปเป็นครั้งแรก
  2. ตั้งค่า ARCore เพื่อเริ่มติดตามระนาบแนวนอน
  3. ตั้งค่า Maps SDK ด้วยคีย์ API
  4. รับตำแหน่งปัจจุบันของอุปกรณ์
  5. ดึงข้อมูลสถานที่ใกล้เคียง (โดยเฉพาะสวนสาธารณะ) โดยใช้ Places API

ขั้นตอนที่เหลือในการทำแบบฝึกหัดนี้ให้เสร็จสมบูรณ์คือการวางตำแหน่งสถานที่ที่คุณดึงข้อมูลในเทคโนโลยีความจริงเสริม

การทำความเข้าใจฉาก

ARCore สามารถทำความเข้าใจฉากในโลกจริงผ่านกล้องของอุปกรณ์ได้โดยการตรวจจับจุดที่น่าสนใจและโดดเด่นซึ่งเรียกว่าจุดฟีเจอร์ในแต่ละเฟรมของรูปภาพ เมื่อจัดกลุ่มจุดฟีเจอร์เหล่านี้และปรากฏว่าอยู่บนระนาบแนวนอนร่วมกัน เช่น โต๊ะและพื้น ARCore จะทำให้ฟีเจอร์นี้พร้อมใช้งานในแอปเป็นระนาบแนวนอน

ดังที่เห็นก่อนหน้านี้ ARCore จะช่วยแนะนำผู้ใช้เมื่อตรวจพบระนาบโดยการแสดงจุดสีขาว

2a9b6ea7dcb2e249.png

การเพิ่มแองเคอร์

เมื่อตรวจพบระนาบแล้ว คุณจะแนบออบเจ็กต์ที่เรียกว่าจุดยึดได้ คุณสามารถวางออบเจ็กต์เสมือนและรับประกันว่าออบเจ็กต์เหล่านั้นจะปรากฏในตำแหน่งเดิมในพื้นที่ได้ผ่าน Anchor แก้ไขโค้ดเพื่อแนบโมเดลเมื่อตรวจพบเครื่องบิน

ใน setUpAr จะมี OnTapArPlaneListener แนบมากับ PlacesArFragment ระบบจะเรียกใช้ Listener นี้ทุกครั้งที่มีการแตะระนาบในฉาก AR ในการเรียกนี้ คุณสามารถสร้าง Anchor และ AnchorNode จาก HitResult ที่ระบุไว้ใน Listener ได้ดังนี้

arFragment.setOnTapArPlaneListener { hitResult, _, _ ->
   val anchor = hitResult.createAnchor()
   anchorNode = AnchorNode(anchor)
   anchorNode?.setParent(arFragment.arSceneView.scene)
   addPlaces(anchorNode!!)
}

AnchorNode คือตำแหน่งที่คุณจะแนบออบเจ็กต์โหนดลูก PlaceNode อินสแตนซ์ ในฉากซึ่งจัดการในการเรียกเมธอด addPlaces

เรียกใช้

หากคุณเรียกใช้แอปที่มีการแก้ไขข้างต้น ให้มองไปรอบๆ จนกว่าจะตรวจพบเครื่องบิน แตะจุดสีขาวที่ระบุเครื่องบินได้เลย เมื่อทำตามขั้นตอนดังกล่าวแล้ว คุณควรจะเห็นเครื่องหมายบนแผนที่สำหรับสวนสาธารณะที่ใกล้ที่สุดทั้งหมดรอบตัวคุณ อย่างไรก็ตาม หากสังเกตดีๆ คุณจะเห็นว่าออบเจ็กต์เสมือนจะติดอยู่กับสมอที่สร้างขึ้นและไม่ได้วางไว้เทียบกับตำแหน่งที่สวนสาธารณะเหล่านั้นอยู่ในอวกาศ

f93eb87c98a0098d.png

ในขั้นตอนสุดท้าย คุณจะแก้ไขปัญหานี้ได้โดยใช้ไลบรารียูทิลิตี Maps SDK สำหรับ Android และ SensorManager ในอุปกรณ์

8. การกำหนดตำแหน่งสถานที่

หากต้องการวางไอคอนสถานที่เสมือนจริงในเทคโนโลยีความจริงเสริมให้ตรงกับส่วนหัวที่ถูกต้อง คุณจะต้องมีข้อมูล 2 อย่าง ได้แก่

  • ตำแหน่งทิศเหนือจริง
  • มุมระหว่างทิศเหนือกับแต่ละสถานที่

การระบุทิศเหนือ

คุณสามารถระบุทิศเหนือได้โดยใช้เซ็นเซอร์ตำแหน่ง (สนามแม่เหล็กโลกและตัวตรวจวัดความเร่ง) ที่มีในอุปกรณ์ เมื่อใช้เซ็นเซอร์ทั้ง 2 ตัวนี้ คุณจะรวบรวมข้อมูลแบบเรียลไทม์เกี่ยวกับตำแหน่งของอุปกรณ์ในพื้นที่ได้ ดูข้อมูลเพิ่มเติมเกี่ยวกับเซ็นเซอร์ตำแหน่งได้ที่คำนวณการวางแนวของอุปกรณ์

หากต้องการเข้าถึงเซ็นเซอร์เหล่านี้ คุณจะต้องขอรับ SensorManager จากนั้นลงทะเบียน SensorEventListener ในเซ็นเซอร์เหล่านั้น ระบบจะดำเนินการตามขั้นตอนเหล่านี้ให้คุณแล้วในเมธอดวงจรของ MainActivity

override fun onCreate(savedInstanceState: Bundle?) {
   super.onCreate(savedInstanceState)
   // ...
   sensorManager = getSystemService()!!
   // ...
}

override fun onResume() {
   super.onResume()
   sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD)?.also {
       sensorManager.registerListener(
           this,
           it,
           SensorManager.SENSOR_DELAY_NORMAL
       )
   }
   sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)?.also {
       sensorManager.registerListener(
           this,
           it,
           SensorManager.SENSOR_DELAY_NORMAL
       )
   }
}

override fun onPause() {
   super.onPause()
   sensorManager.unregisterListener(this)
}

ในonSensorChangedเมธอด จะมีออบเจ็กต์ SensorEvent ซึ่งมีรายละเอียดเกี่ยวกับข้อมูลของเซ็นเซอร์ที่กำหนดเมื่อมีการเปลี่ยนแปลงตามช่วงเวลา โปรดเพิ่มโค้ดต่อไปนี้ลงในเมธอดนั้น

override fun onSensorChanged(event: SensorEvent?) {
   if (event == null) {
       return
   }
   if (event.sensor.type == Sensor.TYPE_ACCELEROMETER) {
       System.arraycopy(event.values, 0, accelerometerReading, 0, accelerometerReading.size)
   } else if (event.sensor.type == Sensor.TYPE_MAGNETIC_FIELD) {
       System.arraycopy(event.values, 0, magnetometerReading, 0, magnetometerReading.size)
   }

   // Update rotation matrix, which is needed to update orientation angles.
   SensorManager.getRotationMatrix(
       rotationMatrix,
       null,
       accelerometerReading,
       magnetometerReading
   )
   SensorManager.getOrientation(rotationMatrix, orientationAngles)
}

โค้ดด้านบนจะตรวจสอบประเภทเซ็นเซอร์ และจะอัปเดตค่าเซ็นเซอร์ที่เหมาะสม (ค่าจากตัวตรวจวัดความเร่งหรือแมกนีโตมิเตอร์) โดยขึ้นอยู่กับประเภท การใช้ค่าที่อ่านได้จากเซ็นเซอร์เหล่านี้จะช่วยให้ทราบค่าขององศาจากทิศเหนือที่สัมพันธ์กับอุปกรณ์ (เช่น ค่าของ orientationAngles[0])

ส่วนหัวทรงกลม

เมื่อกำหนดทิศเหนือแล้ว ขั้นตอนถัดไปคือการกำหนดมุมระหว่างทิศเหนือกับแต่ละสถานที่ จากนั้นใช้ข้อมูลดังกล่าวเพื่อจัดตำแหน่งสถานที่ในส่วนหัวที่ถูกต้องในเทคโนโลยีความจริงเสริม

หากต้องการคำนวณส่วนหัว คุณจะต้องใช้ไลบรารียูทิลิตีของ Maps SDK สำหรับ Android ซึ่งมีฟังก์ชันช่วย 2-3 ฟังก์ชันสำหรับการคำนวณระยะทางและส่วนหัวผ่านรูปทรงเรขาคณิตทรงกลม ดูข้อมูลเพิ่มเติมได้ที่ภาพรวมของไลบรารีนี้

จากนั้นคุณจะใช้เมธอด sphericalHeading ในไลบรารียูทิลิตี ซึ่งจะคำนวณส่วนหัว/แบริ่งระหว่างออบเจ็กต์ LatLng 2 รายการ ต้องมีข้อมูลนี้ภายในเมธอด getPositionVector ที่กำหนดไว้ใน Place.kt ในท้ายที่สุด เมธอดนี้จะแสดงออบเจ็กต์ Vector3 ซึ่ง PlaceNode แต่ละรายการจะใช้เป็นตำแหน่งในพื้นที่ AR

จากนั้นแทนที่คำจำกัดความของส่วนหัวในเมธอดนั้นด้วยคำจำกัดความต่อไปนี้

val heading = latLng.sphericalHeading(placeLatLng)

การดำเนินการดังกล่าวจะทำให้เกิดการกำหนดเมธอดต่อไปนี้

fun Place.getPositionVector(azimuth: Float, latLng: LatLng): Vector3 {
   val placeLatLng = this.geometry.location.latLng
   val heading = latLng.sphericalHeading(placeLatLng)
   val r = -2f
   val x = r * sin(azimuth + heading).toFloat()
   val y = 1f
   val z = r * cos(azimuth + heading).toFloat()
   return Vector3(x, y, z)
}

ตำแหน่งในเครื่อง

ขั้นตอนสุดท้ายในการวางแนวสถานที่อย่างถูกต้องใน AR คือการใช้ผลลัพธ์ของ getPositionVector เมื่อมีการเพิ่มออบเจ็กต์ PlaceNode ลงในฉาก ไปที่ addPlaces ใน MainActivity ตรงใต้บรรทัดที่ตั้งค่าองค์กรระดับบนในแต่ละ placeNode (ใต้ placeNode.setParent(anchorNode)) ตั้งค่า localPosition ของ placeNode เป็นผลลัพธ์ของการเรียกใช้ getPositionVector ดังนี้

val placeNode = PlaceNode(this, place)
placeNode.setParent(anchorNode)
placeNode.localPosition = place.getPositionVector(orientationAngles[0], currentLocation.latLng)

โดยค่าเริ่มต้น เมธอด getPositionVector จะตั้งค่าระยะทาง y ของโหนดเป็น 1 เมตรตามที่ระบุโดยค่า y ในเมธอด getPositionVector หากต้องการปรับระยะนี้ เช่น เป็น 2 เมตร ให้แก้ไขค่าดังกล่าวตามต้องการ

การเปลี่ยนแปลงนี้จะทำให้PlaceNodeออบเจ็กต์ที่เพิ่มเข้ามาอยู่ในส่วนหัวที่ถูกต้อง ตอนนี้ให้เรียกใช้แอปเพื่อดูผลลัพธ์

9. ขอแสดงความยินดี

ขอแสดงความยินดีที่มาไกลถึงจุดนี้

ดูข้อมูลเพิ่มเติม