ก้าวข้ามขีดจำกัดของพื้นที่หน้าจอและยึดแอปของคุณไว้ในโลกแห่งความเป็นจริงด้วย Android XR เซสชันนี้จะสอนวิธีสร้างประสบการณ์ Android XR ที่รับรู้ข้อมูลเชิงพื้นที่โดยใช้ Jetpack Compose Glimmer และ Geospatial API ของ ARCore เราจะเริ่มด้วยการอธิบายวิธีรับท่าทางเชิงพื้นที่ของอุปกรณ์ด้วย ARCore จากนั้น คุณจะได้เห็นวิธีที่คอมโพเนนต์ UI ขั้นต่ำของ Glimmer สามารถยึดกับสถานที่ในโลกจริงผ่านระบบการระบุตำแหน่งด้วยภาพ (VPS) เราจะรวมข้อมูลเหล่านี้เพื่อสร้างประสบการณ์เชิงพื้นที่ที่รับรู้ถึงตำแหน่งและใช้งานง่าย
ข้อความถอดเสียง
สวัสดีทุกคน ยินดีต้อนรับสู่เซสชันแรกในเส้นทาง Android XR ที่งาน Android Developer Summit
ใช่เลย
เราตื่นเต้นมากที่ได้เห็นหลายๆ คนเรียนรู้เกี่ยวกับ Android XR
ฉันชื่อ Yasmine Quintana Evjen และมี Paul Hoover กับ Dereck Bridie มาร่วมพูดคุยด้วยในวันนี้
และหัวข้อของเซสชันนี้จะเกี่ยวกับ Android XR ทั้งหมด รวมถึงวิธีสร้างประสบการณ์ในโลกจริงที่ยึดตามพื้นที่ด้วย Jetpack Compose Glimmer และ ARCore สำหรับ Jetpack XR
แต่ก่อนอื่น เรามาทำความรู้จัก Android XR กันแบบคร่าวๆ ก่อน
Android XR เป็นแพลตฟอร์มใหม่ที่กำหนดนิยามใหม่ของวิธีที่ผู้ใช้โต้ตอบกับแอปของคุณ โดยก้าวข้ามหน้าจอและเข้าสู่พื้นที่รอบตัว
เราออกแบบแพลตฟอร์มมาเพื่อนำประสบการณ์ดิจิทัลมาสู่สภาพแวดล้อมจริงโดยตรง
ไม่ว่าจะเป็นการวางซ้อนที่มองเห็นได้ง่ายซึ่งช่วยปรับปรุงการแสดงตนในโลกจริงหรือสภาพแวดล้อมที่สมจริงแบบไม่สิ้นสุด
นี่คือระบบนิเวศของ Android แบบเปิดที่เราสร้างร่วมกันมาหลายปี และตอนนี้ผืนผ้าใบก็มีขนาดใหญ่เท่ากับห้องและกว้างขวางเท่ากับจินตนาการของคุณ
เรามองว่า XR เป็นสเปกตรัมของอุปกรณ์ต่างๆ ตั้งแต่แว่นตาอัจฉริยะ ซึ่งมอบประสบการณ์การใช้งานแบบเสริมประสิทธิภาพน้ำหนักเบาบนแว่นตาที่มีจอแสดงผลและเสียง ไปจนถึงชุดหูฟังที่สมจริงและแว่นตา XR แบบมีสาย ซึ่งช่วยให้คุณมีสมาธิ ทำงานได้อย่างมีประสิทธิภาพ และมอบความสามารถด้านความบันเทิงที่สมจริง
อุปกรณ์ใหม่ล่าสุดในตระกูล Android XR คือ XREAL AURA ซึ่งพร้อมจำหน่ายแล้ววันนี้
อุปกรณ์นี้มีน้ำหนักเบาและมีประสิทธิภาพสูง ช่วยให้คุณได้รับประสบการณ์การใช้งาน XR ที่คุ้นเคยของ Android
วิสัยทัศน์ของเราสำหรับแพลตฟอร์มนี้คือ หากคุณพัฒนาแอปสำหรับ Android อยู่แล้ว คุณก็พร้อมที่จะพัฒนาแอปสำหรับ XR
เราต้องการช่วยให้คุณสร้างแอปบน Android XR ได้ง่ายๆ โดยใช้โมเดลแอป ไลบรารี และเครื่องมือเดียวกับที่คุณคุ้นเคย
แอปที่เข้ากันได้กับ Android แบบ 2 มิติที่มีอยู่จะทำงานบนชุดหูฟัง Android XR และแว่นตา XR แบบมีสายได้โดยไม่ต้องแก้ไขหรือแก้ไขเพียงเล็กน้อย
และเพื่อสร้างประสบการณ์ XR ที่ยอดเยี่ยมซึ่งให้ความรู้สึกเหมือนอยู่ที่บ้าน เราจึงมีชุดไลบรารีที่สร้างขึ้นสำหรับแพลตฟอร์ม XR โดยเฉพาะ
สําหรับนักพัฒนาแอปที่คุ้นเคยกับการสร้างประสบการณ์การใช้งานบนแพลตฟอร์มที่สมจริงอื่นๆ คุณสามารถสร้างด้วย OpenXR และการรองรับเครื่องมือ 3 มิติของเรา เช่น Unity, Godot และ Unreal
มาพูดถึงการสร้างด้วยไลบรารี Android กัน
เรามี Jetpack XR SDK ซึ่งเป็นชุดไลบรารี Kotlin ที่ช่วยคุณขยายแอปไปยัง XR ในประสบการณ์การใช้งานแบบสมจริงและเทคโนโลยีความจริงเสริม (AR)
มาดูคลังภาพที่สมจริงกัน
ไลบรารี Jetpack XR ของเราจะเข้าสู่เวอร์ชันเบต้าและเวอร์ชันเสถียรในปีนี้ ซึ่งจะช่วยให้คุณมั่นใจในการเริ่มสร้างประสบการณ์ XR ที่สมจริง
เลเยอร์การรับรู้คือ ARCore สำหรับ Jetpack XR
ไลบรารีนี้ให้ข้อมูลเกี่ยวกับโลกจริง เช่น ตำแหน่งของพื้นผิวเรียบอย่างโต๊ะ และตำแหน่งมือของผู้ใช้
โดยสามารถติดตามจุดในพื้นที่ 3 มิติ และให้ข้อมูลดังกล่าวแก่แอปเมื่อได้รับสิทธิ์ที่เหมาะสม
จากนั้นก็มี Jetpack XR SceneCore ซึ่งมีกราฟฉากสำหรับการวางเนื้อหาเชิงพื้นที่
ไลบรารีนี้สามารถแสดงเอนทิตีในพื้นที่ 3 มิติ และมีลักษณะเชิงพื้นที่สำหรับการวางกราฟฉากที่แม่นยำ
และ Jetpack Compose สำหรับ XR มี Composable พื้นที่ย่อยใหม่ที่สร้างขึ้นสำหรับ 3 มิติโดยเฉพาะ
นักพัฒนาแอป Android ที่คุ้นเคยกับเลย์เอาต์ Compose อยู่แล้ว เช่น การสร้างด้วยแถวและคอลัมน์ จะพบว่าการจัดเลย์เอาต์ UI เชิงพื้นที่นั้นใช้งานง่าย
การสร้างแถวเชิงพื้นที่ช่วยให้คุณจัดวางแผงเชิงพื้นที่หลายแผงติดกันได้โดยไม่ต้องคำนวณตำแหน่งหรือขนาดด้วยตนเอง
การใช้ Composable พื้นที่ย่อย เช่น แผงเชิงมิติพื้นที่หรือ Orbiter จะช่วยให้คุณขยายคอมโพเนนต์ 2 มิติไปยังพื้นที่ 3 มิติใหม่นี้ได้อย่างง่ายดาย
และแน่นอนว่า Composable ของพื้นที่ย่อยสามารถทำได้มากกว่าแค่แสดงเนื้อหา 2 มิติ
Compose สำหรับ XR รองรับวิดีโอเชิงมิติพื้นที่และโมเดล 3 มิติผ่านพื้นผิวภายนอกเชิงมิติพื้นที่และโมเดล glTF เชิงมิติพื้นที่
ทีนี้เรามาพูดถึงแอป Augmented กันบ้าง
ไลบรารี Jetpack Projected ช่วยให้คุณปรับปรุงแอปบนอุปกรณ์เคลื่อนที่ที่มีอยู่เพื่อใช้ประโยชน์จากฮาร์ดแวร์แว่นตาอัจฉริยะ เช่น เซ็นเซอร์และจอแสดงผล
สุดท้ายคือ Jetpack Compose Glimmer ซึ่งเป็นชุดเครื่องมือ UI สำหรับสร้างประสบการณ์การใช้งาน Android XR ที่เพิ่มประสิทธิภาพสำหรับแว่นตา
Jetpack Compose Glimmer ประกอบด้วยสไตล์และคอมโพเนนต์ที่พร้อมใช้งานสำหรับการสร้างประสบการณ์ XR
เราเปิดตัว Glimmer เมื่อปีที่แล้วและได้ขยายความสามารถอย่างต่อเนื่อง ซึ่งรวมถึงทักษะ Agentic เพื่อช่วยคุณสร้างแอปแว่นตาที่มีจอแสดงผลด้วย Glimmer
android skills add display-glasses-with-jetpack-compose-glimmerเราได้รับฟังความคิดเห็นของคุณตั้งแต่เปิดตัว
เราทราบมาว่าคุณต้องการให้เราขยาย Jetpack Compose Glimmer ให้ครอบคลุมมากกว่าแว่นตาอัจฉริยะ
เรายินดีที่จะประกาศว่าเราได้ทำการเปลี่ยนแปลงเพื่อรองรับประสบการณ์การใช้งานที่ยึดตามตำแหน่งเชิงพื้นที่ได้ดียิ่งขึ้นด้วย Glimmer ซึ่งเราจะเจาะลึกในภายหลังในการพูดคุยนี้
งานของเราในการเพิ่มประสิทธิภาพ Glimmer เริ่มต้นด้วยการสร้างแพลตฟอร์มใหม่สำหรับการแสดงผลในรูปแบบ XR ที่หลากหลาย ตั้งแต่จอแสดงผลไปจนถึงแว่นตา XR แบบมีสาย
การเพิ่มแพลตฟอร์มใหม่นี้ช่วยให้คุณปรับแต่ง UI ได้อย่างยืดหยุ่นมากขึ้น
และเพื่อเพิ่มความโดดเด่นให้กับแบรนด์แอปของคุณ เราได้เพิ่มสีแบบกำหนดเองลงในคอมโพเนนต์ Glimmer
ใช้สิ่งเหล่านี้เพื่อแสดงสไตล์ของแบรนด์ในแอป XR
ไลบรารี Glimmer ของ Jetpack Compose มีฟังก์ชันตัวช่วยที่แปลงสีเป้าหมายและสีของแบรนด์เป็นสีที่ปลอดภัยสำหรับแว่นตา
ทั้งนี้เพื่อให้มั่นใจว่าการแสดงผลบนจอแสดงผลแบบมองทะลุผ่านเลนส์จะมีความชัดเจนที่สุด
มาดูการทำงานจริงกัน
เราต้องการเปลี่ยนสีปุ่มที่โฟกัสสำหรับแอปแว่นตานี้ ซึ่งฉันจะเลือกสีโปรดที่สวยงามสีหนึ่ง
val brandColor = Color(0xFFFFAABB)
val focusedColor = ButtonDefaults.focusedColor(brandColor)
Column(…) {
LeadingImageCard(
focusable = false,
…
) {
…
}
ButtonGroup(...) {
Button(
onClick = {},
leadingIcon = { … },
focusedColor = focusedColor,
) { Text("Add to cart") }
/* Rest of the buttons */
}
}โปรดทราบว่าเมื่อเพิ่มสีลงในโค้ด ฟังก์ชันตัวช่วยของ Glimmer จะปรับสีให้เป็นสีที่ปลอดภัยสำหรับแว่นตาเพื่อการมองเห็นที่ดีที่สุด
ทั้งหมดนี้สร้างขึ้นภายในไลบรารี Jetpack Compose Glimmer เพื่อให้มั่นใจว่าคุณกำลังสร้างประสบการณ์ที่ดูดีในสภาพแวดล้อมต่างๆ
ใน Android Studio คุณสามารถใช้โปรแกรมจำลองเพื่อดูภาพว่า UI ของแว่นตาจะมีลักษณะอย่างไรในพื้นหลังต่างๆ เช่น สภาพแวดล้อมที่มีแสงสว่าง มืด หรือมีสิ่งรบกวน
การอัปเดตเหล่านี้เป็นเพียงจุดเริ่มต้นเท่านั้น
โอเค ไม่ใช่นะ
ทีมของฉันบอกว่าคุณจะไม่ขำกับเรื่องนี้ แต่ฉันก็ยังคงยึดมั่นในเรื่องนี้
แต่ตอนนี้ฉันจะส่งต่อให้ Paul เพื่อบอกคุณเพิ่มเติมเกี่ยวกับ Jetpack Compose Glimmer
ทดสอบๆ โอเค
ฉันต้องกดปุ่มถัดไป
ขอบคุณนะ Yasmine
โอเค
ดังที่ Yasmine กล่าวไว้ Jetpack Compose Glimmer มีองค์ประกอบพื้นฐานสำหรับการพัฒนาแอปพลิเคชันที่ปรับแต่งมาสำหรับแว่นตาที่มีจอแสดงผล
คอมโพเนนต์ของเราผสานรวมแนวทางปฏิบัติแนะนำที่สร้างขึ้นสำหรับจอแสดงผลแบบ Optical See-Through และเราได้สร้างคอมโพเนนต์เหล่านี้ลงใน API โดยตรงสำหรับคุณ เพื่อช่วยให้นักพัฒนาซอฟต์แวร์ทุกคนสร้างประสบการณ์การใช้งาน Optical See-Through ที่สวยงามและใช้งานได้จริง
เมื่อออกแบบและสร้างแอปสำหรับอุปกรณ์แบบมองทะลุผ่านเลนส์เช่นนี้ คุณต้องคำนึงถึงสิ่งต่างๆ ต่อไปนี้
ประการแรกคือเป็นจอแสดงผลแบบมองทะลุได้ ซึ่งหมายความว่าไม่มีสีดำ
เมื่อมองเห็นโลกได้ สีดำจะโปร่งใส
ดังนั้นคุณจึงไม่สามารถใช้พื้นหลังสีเข้มเพื่อรักษาคอนทราสต์สำหรับ UI, ข้อความ และเนื้อหาได้
แม้ว่าสีดำจะมองไม่เห็น แต่คุณสามารถใช้สีดำเพื่อบดบังเนื้อหาดิจิทัลอื่นๆ ได้
ในเฟรมเวิร์ก UI ของ Glimmer เรามี Depth API ที่ช่วยให้คุณแยกองค์ประกอบ UI ออกจากกันได้อย่างง่ายดายและให้ความรู้สึกถึงลำดับชั้น
คุณจะเห็นว่าความลึกของการ์ดในกองนี้ช่วยให้การ์ดแต่ละใบแยกออกจากกันได้อย่างไร
นักวิทยาศาสตร์ด้านการมองเห็นของเราได้ระบุอัตราส่วนคอนทราสต์เป้าหมายสำหรับข้อความและไอคอนที่มองเห็นได้ในสภาพแสงส่วนใหญ่
อย่างที่ Yasmine แสดงให้เห็น เราสามารถสร้างสิ่งนี้หรือเราได้สร้างสิ่งนี้ไว้ในเฟรมเวิร์ก เพื่อให้คุณมั่นใจได้ว่าเมื่อปรับแต่งสีของแพลตฟอร์ม อินเทอร์เฟซจะอ่านง่ายสำหรับผู้ใช้
เราได้สร้างแนวทางปฏิบัติแนะนำเหล่านี้และแนวทางปฏิบัติแนะนำอื่นๆ ไว้ในคลังคอมโพเนนต์ที่กำลังขยายตัว
เราเพิ่งเปิดตัวคอมโพเนนต์ใหม่ๆ มากมาย
หนึ่งในคอมโพเนนต์ใหม่ล่าสุดของเราคือคอมโพเนนต์เพจเจอร์ที่มีการเปลี่ยนภาพเคลื่อนไหวและท่าทางสัมผัสที่ราบรื่นในตัว
val pagerState =
rememberGlimmerPagerState(pageCount = { 10 })
GlimmerHorizontalPager(pagerState) { page ->
/* Card Content */
}หากคุณคุ้นเคยกับเพจเจอร์แนวนอนของ Compose คอมโพเนนต์นี้จะดูคุ้นเคยมาก
นอกจากนี้ เรายังได้เปิดตัวการ์ดรูปแบบใหม่ 4 แบบที่ออกแบบมาเพื่อการผสานรวมกับเพจเจอร์ สแต็ก และอื่นๆ ได้อย่างราบรื่น ควบคู่ไปกับ UI ของ Glimmer อื่นๆ
การ์ดรูปภาพนำและการ์ดรูปภาพตามจะแสดงข้อความและรูปภาพติดกัน
ดังนั้น ให้ใช้การ์ดรูปแบบต่างๆ เหล่านี้เมื่อคุณมีข้อความและข้อมูลภาพในปริมาณที่เท่ากัน
เราได้แยกการ์ดรูปภาพออกเป็นตัวแปรการ์ดของตัวเอง
เลย์เอาต์นี้เหมาะที่สุดเมื่อคุณมีรูปภาพขนาดใหญ่ที่มีข้อความหรือคำบรรยายเพียงบรรทัดเดียว เช่น เครื่องมือเลือกวิดีโอนี้
ตัวแปรการ์ดการดำเนินการจะฝังปุ่มเดียวลงในการ์ด
ใช้ตัวเลือกนี้เมื่อต้องการให้ผู้ใช้ทราบอย่างแน่ชัดว่าจะเกิดอะไรขึ้นเมื่อเปิดใช้งานการ์ด เช่น ในเครื่องมือเลือกปลายทางนี้
กลุ่มปุ่มช่วยให้คุณใส่ปุ่มจำนวนมากไว้ในพื้นที่ขนาดเล็กได้
ButtonGroup {
Button(onClick = {}) { Text("Button 1") }
Button(onClick = {}) { Text("Button 2") }
Button(onClick = {}) { Text("Button 3") }
Button(onClick = {}) { Text("Button 4") }
Button(onClick = {}) { Text("Button 5") }
}เพียงใช้โค้ดง่ายๆ นี้ คุณก็จะได้การเปลี่ยนภาพที่สวยงาม ลักษณะการเลื่อน สคริมที่ซ่อนขอบและแสดงเมื่อจำเป็นเท่านั้น และอินพุตที่กำหนดเส้นทางจากแว่นตาไปยังตัวควบคุมโดยอัตโนมัติ
กลุ่มปุ่มยังสามารถมีปุ่มไอคอนและปุ่มเปิด/ปิดใหม่ได้ด้วย
var buttonChecked by remember { mutableStateOf(false) }
ToggleButton(
checked = buttonChecked,
leadingIcon = { Icon(FavoriteIcon) },
onCheckedChange = { buttonChecked = it }
) {
Text(if (buttonChecked) "On" else "Off")
}คุณจะเห็นปุ่มทุกประเภทของเราที่ใช้สร้างตัวควบคุมสื่อนี้ได้ที่นี่
และตอนนี้คุณสามารถทดสอบ UI บนพื้นหลังต่างๆ ได้อย่างง่ายดาย
โปรแกรมจำลองแว่นตาช่วยให้คุณใส่ภาพมุมมอง 360 และเลื่อนไปรอบๆ เพื่อทดสอบกับพื้นหลังต่างๆ พื้นหลังที่วุ่นวาย และแสงสว่างหรือความมืดได้
กลุ่มปุ่มเหมาะสำหรับใช้ในมุมมองรายละเอียดเช่นนี้เพื่อแสดงการดำเนินการตามบริบท
เมื่อแตะ คุณสามารถใช้การเปลี่ยนองค์ประกอบที่แชร์เพื่อไปยังสถานะมุมมองแบบละเอียด จากนั้นใช้ท่าทางสัมผัสย้อนกลับของระบบเพื่อกลับไปยังมุมมองก่อนหน้า
ดีมากเลย
นอกจากนี้ เรายังได้เพิ่มตัวบ่งชี้การป้อนข้อมูลด้วยเสียงและกล่องโต้ตอบการแจ้งเตือนด้วย
สรุปก็คือมีสิ่งใหม่ๆ มากมาย
แต่ตอนนี้เราได้เห็นสิ่งใหม่ๆ บางอย่างแล้ว มาสร้างอะไรบางอย่างกันดีกว่า
นอกเหนือจากการใช้ Glimmer เพื่อสร้างแว่นตาอัจฉริยะแล้ว เรายังใช้ Glimmer เพื่อสร้างประสบการณ์การใช้งานแว่นตา XR แบบมีสายได้ด้วย
และเราต้องการให้คุณสร้างประสบการณ์ที่ช่วยเสริมโลกรอบตัวคุณ โดยเริ่มจาก Anchor ตามตำแหน่งในโลกจริง
สมมติว่าคุณอยู่ในเมืองใหม่ อาจจะเดินทางไปร่วมงานประชุมนักพัฒนาซอฟต์แวร์ และต้องการหาร้านอาหารในเมืองรอบๆ ตัวคุณ
คุณสามารถขอให้แอปการนำทางที่ชื่นชอบค้นหาร้านอาหารใกล้เคียงและคะแนนของร้านอาหารเหล่านั้นได้
ข้อมูลสามารถวางซ้อนบนสถานที่ได้โดยตรง ซึ่งจะให้บริบท ข้อมูลเชิงลึก และคำแนะนำ
คุณจะเห็นคอมโพเนนต์ Glimmer ล่าสุดของเราที่ชื่อว่าเครื่องหมายไอคอนได้ที่นี่
ซึ่งช่วยให้คุณไฮไลต์องค์ประกอบสำคัญในโลกจริงและจับคู่กับคอมโพเนนต์อื่นๆ ของ Glimmer เช่น การ์ดนี้ได้
ในตัวอย่างนี้ ระบบจะใส่คำอธิบายประกอบจุดที่น่าสนใจโดยใช้ Google Maps, Places และ Geospatial API
คุณ Dereck มาแสดงวิธีตั้งค่าให้ทุกคนดูกัน
มาเริ่มกันเลย
โอเค
โอเค
ดังนั้นตามที่ Paul ได้กล่าวไว้ก่อนหน้านี้ เรามาเริ่มสร้างกันเลย
เราจะใช้เอกสารประกอบสำหรับนักพัฒนาซอฟต์แวร์ใน developer.android.com/xr และจะดูไลบรารีคอมโพเนนต์ Glimmer ของ Jetpack Compose
คุณจึงจะเห็นภาพรวมของคอมโพเนนต์ทั้งหมดที่มีใน Glimmer
มาเริ่มกันที่ UI ส่วนนี้ที่ Paul แสดงให้เห็นก่อนหน้านี้
เราจึงจะใช้ Glimmer UI เพื่อสร้างตัวบอกสถานะเชิงพื้นที่และกล่องข้อมูล
มาเริ่มกันด้วยการระบุคอมโพเนนต์ที่เราจะใช้
ทางด้านซ้าย คุณจะเห็นเครื่องหมายไอคอน และทางด้านขวา เราจะใช้การ์ดที่อธิบายสถานที่
ดังนั้น หากคุณไปที่ Android Studio คุณจะดูตัวอย่างแผงนี้ได้เหมือนกับคอมโพเนนต์ Compose อื่นๆ และดูการเปลี่ยนแปลงแบบเรียลไทม์ได้
ดังที่กล่าวไว้ก่อนหน้านี้ คุณสามารถดูตัวอย่าง UI ในสภาพแวดล้อมพื้นหลังประเภทต่างๆ ทั้งหมด และตรวจสอบว่าคอนทราสต์ของ UI เพียงพอในสถานการณ์หลายประเภท เช่น สภาพแวดล้อมที่มืดและสว่าง
เมื่อตั้งค่า Canvas แล้ว เราจะสร้างแถว ใส่เครื่องหมายไอคอนลงในแถวโดยเว้นระยะห่าง และใส่การ์ดที่มีข้อความตัวอย่าง
และนี่คือทั้งหมดที่เราอยากบอกคุณ
หากคุณพอใจกับตัวอย่าง 2 มิติ เราจะเริ่มทำเครื่องหมายบางอย่างในโลกจริง และเราจะทำเช่นนั้นโดยการปรับ UI ให้เข้ากับพื้นที่ทำงาน
ซึ่งหมายความว่าเราจะจัดวางในรูปแบบ 3 มิติแทน 2 มิติ
ดังนั้น UI เชิงมิติพื้นที่จะอยู่ในพื้นที่ย่อย ซึ่งเป็นพื้นที่ 3 มิติที่อยู่ด้านหน้าผู้ใช้
Subspace {
SpatialPanel {
VideoPlayer()
}
}และโดยค่าเริ่มต้น พื้นที่ย่อยจะจัดวางเนื้อหาในระยะที่ผู้ใช้มองเห็นได้สบายตา
ก่อนที่เราจะแสดงวิธีใช้ Geospatial API ให้คุณดู ลองวางบางอย่างไว้ใกล้ๆ ก่อน
ดังนั้น Subspace Composable ที่ฉันพูดถึงก่อนหน้านี้จึงมีพารามิเตอร์ที่ไม่บังคับซึ่งช่วยให้คุณระบุเป้าหมายการติดตามได้
val state by
qrCode.state.collectAsState()
Subspace(FollowTarget.anchor(anchor)) {
SpatialPanel {
Row {
IndicatorDot()
Spacer()
QrCodeCard(state)
}
}
}ดังนั้น หากต้องการแนบวัตถุกับโลกจริง ก่อนอื่นคุณจะต้องสร้าง Anchor ที่ได้จาก ARCore สำหรับ Jetpack XR
และในตัวอย่างนี้ ฉันใช้ฟีเจอร์การจดจำคิวอาร์โค้ด
ซึ่งจะช่วยให้คุณอ่านและติดตามคิวอาร์โค้ดได้ เพื่อให้เนื้อหาติดตามคิวอาร์โค้ดนั้นไปรอบๆ พื้นที่ และเราจะแนบ UI ที่เห็นก่อนหน้านี้
ตกลง
ฉันได้แสดงวิธีวางเนื้อหาดิจิทัลในโลกจริงที่อยู่ใกล้เคียงให้คุณดูแล้ว
ลองกลับไปดูตัวอย่างของ Paul กัน
ส่วนตัวแล้วฉันมาจากเนเธอร์แลนด์
ฉันไม่ค่อยคุ้นเคยกับ Mountain View
ดังนั้น หลังจากกิจกรรมนี้ ฉันอยากช่วยคุณสร้างแอปที่จะช่วยคุณค้นหาร้านกาแฟสนุกๆ
มาดูกันว่าเราจะช่วยผู้ใช้ค้นหาจุดชาร์จได้อย่างไรด้วย Geospatial API ซึ่งตอนนี้อยู่ใน ARCore สำหรับ Jetpack XR
ดังนั้น Geospatial API ที่เปิดตัวครั้งแรกบนสมาร์ทโฟนจึงพร้อมใช้งานบน Android XR ด้วยเช่นกัน
โดยจะใช้ข้อมูลจาก Google Street View และรวมเข้ากับการวัด GPS เพื่อระบุตำแหน่งของอุปกรณ์ในพื้นที่ที่รองรับ
ดังนั้น Geospatial API จึงสามารถใช้เพื่อระบุตำแหน่งและทิศทางของผู้ใช้ได้อย่างแม่นยำบนแว่นตาอัจฉริยะ และช่วยให้สามารถใช้กรณีการใช้งานการนำทางแบบเลี้ยวต่อเลี้ยวที่มีความแม่นยำสูงได้
และในอุปกรณ์ที่สมจริง เช่น แว่นตา XR แบบมีสาย Geospatial API ช่วยให้คุณสร้างประสบการณ์ที่วางตำแหน่งได้อย่างถูกต้องในโลกจริง
ตัวอย่างเช่น คุณสามารถยึดเนื้อหาเชิงพื้นที่ไว้กับอาคารหรือสร้างทัวร์ชมเมืองแบบเฉพาะทางได้
มาเริ่มต้นใช้งาน Geospatial API ด้วย 3 ขั้นตอนนี้กันเลย
วิธีแรกคือคุณจะสร้างโปรเจ็กต์ Google Cloud Platform และกำหนดค่าการตรวจสอบสิทธิ์ในแอป
จากนั้นเมื่อกำหนดค่าและเปิดใช้ Geospatial API ในแอปแล้ว คุณจะขอสิทธิ์จากผู้ใช้เพื่อดึงข้อมูลตำแหน่งโดยใช้ความละเอียดสูง
จากนั้นหลังจากกำหนดค่าเซสชันให้ใช้ Geospatial API แล้ว คุณก็พร้อมใช้งาน
คุณดูรายละเอียดทั้งหมดเกี่ยวกับเอกสารประกอบสำหรับนักพัฒนาซอฟต์แวร์เกี่ยวกับ Geospatial API ได้ในหน้านักพัฒนาซอฟต์แวร์ Android XR ที่ปรับปรุงใหม่
เรามาเริ่มด้วยการใช้ตำแหน่งของผู้ใช้เพื่อขอ Places API จาก Google Maps Platform เพื่อค้นหาร้านกาแฟดีๆ ใกล้ผู้ใช้กัน
ก่อนอื่น ผู้ใช้อยู่ที่ไหน
เราจะขอให้ Geospatial API รับข้อมูลอัปเดตอย่างต่อเนื่องเกี่ยวกับตำแหน่งของผู้ใช้
produceState<AppStatus>(Initializing) {
val geospatial = Geospatial.getInstance(session)
val wait = geospatial.state.onEach {
value = WaitingForGeospatial(it.geospatialTrackingState)
}.first {
it.geospatialTrackingState == Geospatial.GeospatialTrackingState.RUNNING
}
val accuracyWait = geospatial.state.onEach {
value = WaitingForGeospatialAccuracy(it)
}.first { it.horizontalAccuracy < horizontalAccuracyRequirement }
value = WaitingForPlacesResults
val result = client.findNearby(context, accWait.geospatialPose)
value = Done(result)
}ดังนั้น เราจะเข้าถึงออบเจ็กต์เชิงพื้นที่ทางภูมิศาสตร์ผ่านเซสชัน XR
หลังจากนั้น เราจะรอให้ Geospatial เริ่มทำงานขณะที่เริ่มต้นเซ็นเซอร์ที่จำเป็นและเชื่อมต่อกับ Cloud API
จากนั้นเราจะรอให้ความแม่นยำถึงระดับหนึ่ง
ดังนั้น ระดับความแม่นยำจึงอาจดีขึ้นเมื่อมีการวัดค่า GPS หรือเมื่อระบบกำหนดตำแหน่งด้วยภาพพบข้อมูลที่ตรงกันในตำแหน่งของผู้ใช้
และการรอให้ได้ระดับความแม่นยำสูงเป็นสิ่งสำคัญเพื่อให้แน่ใจว่าประสบการณ์การใช้งานตามตำแหน่งจะยึดตามสถานที่ที่ถูกต้อง และผลการค้นหามาจากพื้นที่ใกล้เคียงของผู้ใช้
จากนั้นเราก็พร้อมที่จะทำการค้นหาด้วย Places API โดยใช้ค่าตำแหน่งจาก Geospatial API
val bounds = CircularBounds.newInstance(
LatLng(pose.latitude, pose.longitude),
100.0, // radius, in meters
)
val placeFields = listOf(
Place.Field.ID, Place.Field.DISPLAY_NAME,
Place.Field.RATING, Place.Field.LOCATION,
)
return placesClient.searchNearby(
SearchNearbyRequest.builder(bounds, placeFields)
.setIncludedTypes(listOf(PlaceTypes.CAFE))
.setMaxResultCount(10)
.build()
).await()ดังนั้น เราจะใช้ SearchNearbyRequest กับ Places API เพื่อค้นหาสถานที่รอบๆ ตำแหน่งของผู้ใช้ที่เราได้รับมาก่อนหน้านี้ และเราจะค้นหาผลลัพธ์ภายในระยะ 100 เมตร
เราจะดึงรหัสของสถานที่ ชื่อที่แสดง คะแนน และตำแหน่งของสถานที่นั้น
และสุดท้าย เราจะทำการค้นหาด้วยพารามิเตอร์ที่ระบุ รวมถึงตัวกรองประเภทสถานที่
ข้อมูลก็มีเพียงเท่านี้ ต่อไปเราจะกลับไปที่ UI
ดังนั้นเราจะต้องหาวิธีวางเครื่องหมายและกล่องข้อมูลจากก่อนหน้านี้ และเราจะใช้ Anchor เชิงพื้นที่สำหรับสิ่งนั้น
กลับมาที่โค้ดอีกครั้ง เราจะเข้าถึง Geospatial API โดยใช้เซสชัน XR จากนั้นเราจะสร้าง Anchor เชิงพื้นที่โดยใช้ละติจูดและลองจิจูดที่เฉพาะเจาะจงซึ่งได้จากผลการค้นหาก่อนหน้านี้
val anchorResult by produceState<AnchorResult?>(null) {
val geospatial = Geospatial.getInstance(session)
value = geospatial.createAnchorOnSurface(
place.location.latitude, place.location.longitude,
surface = GeospatialSurface.TERRAIN,
altitudeAboveSurface = 3.0,
eastUpSouthQuaternion = Quaternion()
)
}ดังนั้นในตัวอย่างนี้ เราได้ระบุระดับความสูงไว้ที่ 3 เมตรเหนือภูมิประเทศที่พิกัดเหล่านั้น แต่คุณยังสามารถแนบกับหลังคาที่รองรับได้ด้วย ซึ่งหมายความว่าระบบจะกำหนดค่าระดับความสูงโดยสัมพันธ์กับหลังคาของอาคารที่ตำแหน่งนั้น
ดังนั้น คุณยังสามารถหมุน Anchor โดยใช้ควอเทอร์เนียน ซึ่งระบุค่าการหมุนของ Anchor ได้ด้วย
แต่เราจะใช้ค่าเริ่มต้นในตัวอย่างนี้เนื่องจากเราจะทำให้ UI หมุนไปหาผู้ใช้
จากนั้นเราจะแนบ UI ของ Glimmer จากก่อนหน้านี้เข้ากับ Anchor นี้ ซึ่งจะช่วยให้คุณมีองค์ประกอบพื้นฐานสำหรับประสบการณ์ที่ยึดตามพื้นที่
when (anchorResult) {
is AnchorCreateSuccess ->
Subspace(FollowTarget.anchor(anchorResult.anchor)) {
SpatialPanel(SubspaceModifier.rotateToLookAtUser()) {
PlaceIndicator(place)
}
}
else ->
Log.e("Demo", "Failed to create anchor $anchorResult")
}ดังนั้นเราจึงเชื่อว่า Geospatial API จะช่วยมอบประสบการณ์การค้นหาเส้นทางที่ยอดเยี่ยม และการออกแบบด้วย Glimmer จะช่วยสร้างประสบการณ์ของผู้ใช้ที่เข้าใจง่ายซึ่งสร้างขึ้นมาเพื่อจอแสดงผลแบบโปร่งใสโดยเฉพาะ
ดูข้อมูลเพิ่มเติมเกี่ยวกับ Geospatial API ได้ที่ developer.android.com/xr ซึ่งอัปเดตล่าสุด
และฉันจะส่งต่อให้ Yasmine เพื่อสรุปช่วงสุดท้าย
ในเซสชันนี้ เราได้พูดถึงความสามารถบางอย่างของ Android XR ได้แก่ ARCore สำหรับ Jetpack XR และ Jetpack Compose Glimmer
เราตื่นเต้นกับฟีเจอร์ใหม่ๆ ที่ Android XR จะนำมาสู่แว่นตา XR แบบใช้สาย
นักพัฒนาแอปกำลังสร้างแอปสำหรับ Android XR อยู่แล้ว และเราหวังว่าจะได้เห็นผลงานสร้างสรรค์ของคุณใน Google Play Store
หากต้องการเริ่มต้นใช้งาน โปรดดูเอกสารประกอบสำหรับนักพัฒนาซอฟต์แวร์ของเรา รับแรงบันดาลใจจากการทดสอบ XR และเริ่มใช้งานด้วย Codelab
เราได้วางแผนเซสชัน XR, การสาธิต และเวิร์กช็อปที่ยอดเยี่ยมไว้มากมายสำหรับคุณทุกคน
โปรดติดตามและดูข้อมูลเกี่ยวกับการสร้างแอปสำหรับ Android XR ในประสบการณ์การใช้งานแบบสมจริงและเทคโนโลยีความจริงเสริม (AR)
ในนามของทีม Android XR ขอขอบคุณทุกท่านที่มาร่วมงานในวันนี้ และหวังว่าคุณจะเพลิดเพลินกับช่วงเวลาที่เหลือในงาน Android Developer Summit
ขอบคุณมาก
android skills add display-glasses-with-jetpack-compose-glimmerval brandColor = Color(0xFFFFAABB)
val focusedColor = ButtonDefaults.focusedColor(brandColor)
Column(…) {
LeadingImageCard(
focusable = false,
…
) {
…
}
ButtonGroup(...) {
Button(
onClick = {},
leadingIcon = { … },
focusedColor = focusedColor,
) { Text("Add to cart") }
/* Rest of the buttons */
}
}val pagerState =
rememberGlimmerPagerState(pageCount = { 10 })
GlimmerHorizontalPager(pagerState) { page ->
/* Card Content */
}ButtonGroup {
Button(onClick = {}) { Text("Button 1") }
Button(onClick = {}) { Text("Button 2") }
Button(onClick = {}) { Text("Button 3") }
Button(onClick = {}) { Text("Button 4") }
Button(onClick = {}) { Text("Button 5") }
}var buttonChecked by remember { mutableStateOf(false) }
ToggleButton(
checked = buttonChecked,
leadingIcon = { Icon(FavoriteIcon) },
onCheckedChange = { buttonChecked = it }
) {
Text(if (buttonChecked) "On" else "Off")
}Subspace {
SpatialPanel {
VideoPlayer()
}
}val state by
qrCode.state.collectAsState()
Subspace(FollowTarget.anchor(anchor)) {
SpatialPanel {
Row {
IndicatorDot()
Spacer()
QrCodeCard(state)
}
}
}produceState<AppStatus>(Initializing) {
val geospatial = Geospatial.getInstance(session)
val wait = geospatial.state.onEach {
value = WaitingForGeospatial(it.geospatialTrackingState)
}.first {
it.geospatialTrackingState == Geospatial.GeospatialTrackingState.RUNNING
}
val accuracyWait = geospatial.state.onEach {
value = WaitingForGeospatialAccuracy(it)
}.first { it.horizontalAccuracy < horizontalAccuracyRequirement }
value = WaitingForPlacesResults
val result = client.findNearby(context, accWait.geospatialPose)
value = Done(result)
}val bounds = CircularBounds.newInstance(
LatLng(pose.latitude, pose.longitude),
100.0, // radius, in meters
)
val placeFields = listOf(
Place.Field.ID, Place.Field.DISPLAY_NAME,
Place.Field.RATING, Place.Field.LOCATION,
)
return placesClient.searchNearby(
SearchNearbyRequest.builder(bounds, placeFields)
.setIncludedTypes(listOf(PlaceTypes.CAFE))
.setMaxResultCount(10)
.build()
).await()val anchorResult by produceState<AnchorResult?>(null) {
val geospatial = Geospatial.getInstance(session)
value = geospatial.createAnchorOnSurface(
place.location.latitude, place.location.longitude,
surface = GeospatialSurface.TERRAIN,
altitudeAboveSurface = 3.0,
eastUpSouthQuaternion = Quaternion()
)
}when (anchorResult) {
is AnchorCreateSuccess ->
Subspace(FollowTarget.anchor(anchorResult.anchor)) {
SpatialPanel(SubspaceModifier.rotateToLookAtUser()) {
PlaceIndicator(place)
}
}
else ->
Log.e("Demo", "Failed to create anchor $anchorResult")
}