Android XR

การออกแบบสถาปัตยกรรมเนื้อหาเชิงพื้นที่ใน Android XR ด้วย Unity

ลำโพง

  • Levana Chen

    วิศวกรซอฟต์แวร์

  • Jennifer Stanton

    วิศวกรอาวุโสฝ่ายซอฟต์แวร์

เกี่ยวกับ

เกี่ยวกับการเสวนา

ดูวิธีตรึงและคงประสบการณ์ 3 มิติไว้ในโลกแห่งความเป็นจริงโดยใช้ Unity และ Android XR เซสชันนี้ครอบคลุมเฟรมเวิร์กเอนทิตีเชิงพื้นที่, Cloud Anchor และ Geospatial API ซึ่งแสดงวิธีสร้างแอปที่คำนึงถึงบริบทซึ่งจดจำตำแหน่งทางกายภาพและซิงค์ข้อมูลเชิงพื้นที่ของผู้ใช้หลายคนหนึ่งเครื่องในเซสชันต่างๆ

เราจะตรวจสอบสถาปัตยกรรมเบื้องหลังเอนทิตีเชิงพื้นที่ ทำความเข้าใจวิธีเชื่อมโยงเนื้อหาดิจิทัลกับวัตถุ พื้นผิว และสถานที่ตั้งทางภูมิศาสตร์ที่จับต้องได้ คุณจะได้เรียนรู้เวิร์กโฟลว์ Unity ที่นำไปใช้ได้จริงสำหรับการแมปพื้นที่ การคงเนื้อหาไว้ในเซสชันต่างๆ และการสร้างประสบการณ์ AR/XR ที่รับรู้ตำแหน่งและแชร์ร่วมกันได้

สรุป

  • AR Foundation มี API การเขียนสคริปต์แบบรวมในแพลตฟอร์ม XR โดยใช้ส่วนขยาย OpenXR ซึ่งช่วยให้คุณแสดงและค้นหาฟีเจอร์ในชีวิตจริง เช่น ระนาบและเมชได้
  • Anchor แบบถาวรจะช่วยให้เนื้อหาดิจิทัลมีความเสถียรในเซสชันต่างๆ และการรีสตาร์ทอุปกรณ์ คุณสามารถเก็บข้อมูลไว้ด้วย TrySaveAnchorAsync และโหลดซ้ำโดยใช้ GUID ที่เรียงลำดับแล้ว
  • เฟรมเวิร์กเอนทิตีเชิงพื้นที่มาแทนที่ส่วนขยายที่ติดตามได้เพื่อให้การรองรับข้ามแพลตฟอร์มและประสิทธิภาพที่ดีขึ้นสำหรับการติดตามรายการต่างๆ เช่น กรอบล้อมรอบและเครื่องหมาย
  • ควรปิดใช้คอมโพเนนต์ผู้จัดการจนกว่าจะได้รับสิทธิ์ Android XR ซึ่งจะช่วยหลีกเลี่ยงความล้มเหลวในการเริ่มต้นระบบย่อยที่เกิดจากการจำกัดการเข้าถึงข้อมูลสภาพแวดล้อมที่ละเอียดอ่อน
  • Geospatial API ใช้บริการ Google Cloud ARCore และ VPS เพื่อวางตำแหน่งเนื้อหาในสถานที่กลางแจ้งในโลกจริง

แหล่งข้อมูล

Gemini Notebook

หัวข้อ

  • android-xr
  • ความสามัคคี
  • ar-foundation
  • openxr
  • spatial-entities
  • ด้านล่างสุดของหน้าจอ
  • geospatial-api

ข้อความถอดเสียง

ข้อมูลเบื้องต้นและภาพรวมของ AR Foundation

  • โอเค

  • ขอต้อนรับทุกคน

  • นี่คือการสร้างสถาปัตยกรรมเนื้อหาเชิงมิติพื้นที่บน Android XR ด้วย Unity

  • ฉันชื่อ Jennifer Stanton

  • ฉันทำงานที่ Unity ในตำแหน่งวิศวกรซอฟต์แวร์อาวุโส

  • ฉันทำงานในทีมฟีเจอร์ XR โดยเฉพาะใน AR Foundation และแพ็กเกจที่เกี่ยวข้องซึ่งนำเทคโนโลยีความจริงเสริมและเทคโนโลยีความจริงแบบผสมมาสู่ Unity

  • เราชื่อ Levana Chen จากทีม XR เกมเอนจิน ของ Google

  • ทีมของเรามุ่งเน้นที่การนำเสนอปลั๊กอินและแพ็กเกจที่จะช่วยเพิ่มฟังก์ชันการทำงานของ XR และการผสานรวมเกมเอนจินที่ราบรื่น

  • ความท้าทายที่ยิ่งใหญ่ที่สุดอย่างหนึ่งที่เราได้ยินจากคุณคือการรองรับแพลตฟอร์ม XR หลายแพลตฟอร์มด้วยฐานของโค้ดเดียวกันนั้นเป็นงานที่หนักหน่วง

  • AR Foundation เป็นเลเยอร์ API เทคโนโลยีความจริงขยาย (XR) ระดับสูงของ Unity

  • คุณสามารถกำหนดเป้าหมายแพลตฟอร์ม XR หลายแพลตฟอร์มได้โดยไม่ต้องเขียนโค้ดใหม่ทั้งหมดหรือจัดการฐานของโค้ดหลายรายการ และยังมี API การเขียนสคริปต์เดียวสำหรับฟีเจอร์ AR ในทุกแพลตฟอร์มด้วย

  • ซึ่งจะช่วยให้คุณมุ่งเน้นไปที่การสร้างแอป เกม หรือประสบการณ์การใช้งานได้ และ Unity จะดูแลรายละเอียดแพลตฟอร์มให้คุณเอง

  • วิธีหนึ่งที่ AR Foundation ใช้ในการดำเนินการนี้คือผ่านส่วนขยาย OpenXR

  • ซึ่งเป็นชุด API มาตรฐานอุตสาหกรรมแบบเปิดที่กำหนดโดย Khronos Group

  • OpenXR ได้สร้างเอนทิตีเชิงพื้นที่ด้วย

  • ซึ่งเป็นเฟรมเวิร์กสำหรับเนื้อหาดิจิทัลเพื่อนำเสนอและโต้ตอบกับโลกจริง

  • เอนทิตีเชิงพื้นที่เป็นโมเดลแบบรวมสำหรับการแสดงองค์ประกอบในโลกจริงเป็นออบเจ็กต์ดิจิทัล

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

  • ต่อไป เราจะพูดถึงความสามารถของ AR Foundation เพื่อให้เนื้อหาดิจิทัลของคุณโต้ตอบกับโลกแห่งความจริงได้

  • จากนั้นฉันจะอธิบายการตั้งค่าโปรเจ็กต์ ซึ่งรวมถึงแพ็กเกจและทรัพยากร Dependency อื่นๆ เพื่อให้คุณนำไปใช้ในโปรเจ็กต์ได้

  • จากนั้นเราจะสรุปด้วยการพูดถึงฟีเจอร์บางอย่างที่มีเฉพาะใน Android XR

ฟีเจอร์หลักของ AR Foundation

  • ดังนั้น วิธีหนึ่งที่ AR Foundation แสดงโลกจริงในรูปแบบดิจิทัลคือระนาบ

  • ซึ่งก็คือพื้นผิวเรียบในสภาพแวดล้อมจริง เช่น พื้น ผนัง เพดาน รวมถึงโต๊ะและโซฟา

  • Mesh คือโครงสร้าง 3 มิติที่แสดงเรขาคณิตของโลกจริง

  • นอกจากนี้ เรายังมีวิธีโต้ตอบกับโลกจริงด้วย Ray Cast

  • ซึ่งจะกำหนดตำแหน่งที่รังสีตัดกับเนื้อหาดิจิทัล

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

  • นอกจากนี้ เรายังมี Anchor ซึ่งช่วยให้จุดในพื้นที่คงที่และย้ายตำแหน่งได้

  • เราจะเจาะลึกเกี่ยวกับ Anchor ภายหลังในการนำเสนอนี้

  • ดังนั้นทั้ง 4 รายการนี้จึงถือเป็นฟีเจอร์ AR Foundation

  • นอกจากนี้ยังมีฟีเจอร์อื่นๆ อีกจำนวนหนึ่งที่ไม่ได้กล่าวถึงในสไลด์นี้

  • โดยเฉพาะอย่างยิ่ง ระนาบและ Anchor จะถือว่าเป็นสิ่งที่ติดตามได้เนื่องจากขยายคลาส ARTrackable และผู้จัดการจะติดตามการอัปเดตจากรันไทม์

  • มาดูเรื่องเที่ยวบินกันเลย

  • ระนาบ เรามีคอมโพเนนต์ ARPlane ซึ่งช่วยระบุพื้นผิวเรียบแบบเรียลไทม์

  • ระนาบเหล่านี้มีป้ายกำกับเชิงความหมายที่คุณสามารถค้นหาได้ เพื่อให้ทราบว่าระนาบนั้นเป็นพื้น โต๊ะ ผนัง และอื่นๆ

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

  • นอกจากนี้ เรายังแนบ Mesh Collider เข้ากับเครื่องบินเพื่อจัดการฟิสิกส์ได้ด้วย

  • คุณดูตัวอย่างการตรวจจับระนาบได้ที่นี่

  • นี่คือฉาก Raycast ตัวอย่างของ AR Foundation ที่ทำงานบนอุปกรณ์ Android XR

  • โดยจะตรวจจับรูปหลายเหลี่ยม 2 มิติแบบไดนามิกและเรียลไทม์

  • คุณสามารถสร้างแอปที่มีฟังก์ชันการทำงานนี้ได้โดยทำตามคู่มือการตั้งค่าโปรเจ็กต์ หรือใช้ตัวอย่างหรือเทมเพลตของเรา

  • ต่อไปคือ Mesh

  • Mesh เป็นฟีเจอร์ AR ที่แสดง Mesh 3 มิติของสภาพแวดล้อม

  • เราสามารถแนบ Mesh Collider เข้ากับ Mesh ที่สร้างขึ้นเหล่านี้ได้ ซึ่งจะช่วยให้เนื้อหาดิจิทัลโต้ตอบกับวัตถุในโลกจริงได้

  • Mesh ช่วยให้การบดบังวัตถุมีความสมจริง

  • ดังนั้น วัตถุเสมือนจริงจึงปรากฏอยู่ด้านหลังวัตถุจริงได้

  • หากวัตถุดิจิทัลเคลื่อนที่ในพื้นที่ได้ คุณสามารถใช้เรขาคณิตเดียวกันเพื่อค้นหาเส้นทางที่หลีกเลี่ยงวัตถุในโลกจริง

  • ต่อไปคือการแคสต์รังสี

  • การแคสต์รังสีจะฉายรังสีเสมือนจริงลงในฉาก 3 มิติเพื่อค้นหาจุดตัดโดยที่คุณไม่ต้องกังวลเกี่ยวกับคณิตศาสตร์ที่ซับซ้อน

  • รังสีที่ฉายจากโปรเจ็กต์ A อาจตัดกับวัตถุ 3 มิติหลายรายการในสภาพแวดล้อมของคุณ

  • คุณสามารถกำหนดค่าการแคสต์รังสีให้โดนเฉพาะเนื้อหาดิจิทัลบางประเภทได้

  • เช่น คุณสามารถกำหนดค่าไม่ให้ชนกับระนาบและตัดกับ Mesh เท่านั้น

การตั้งค่าแพ็กเกจและทรัพยากร Dependency

  • ตอนนี้เรามาดูแพ็กเกจที่เกี่ยวข้อง

  • แพ็กเกจเหล่านี้ทั้งหมดจะทำงานร่วมกันเพื่อสื่อสารกันและสร้างประสบการณ์ XR ที่สมบูรณ์

  • ดังที่กล่าวไว้ AR Foundation จะจัดการฟีเจอร์ต่างๆ เช่น ระนาบและ Anchor

  • ปลั๊กอิน OpenXR จะจัดการ API แบบเนทีฟในแพลตฟอร์ม XR ต่างๆ ดังนั้นคุณจึงควรใช้แพ็กเกจนี้หากอุปกรณ์ของคุณใช้ OpenXR

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

  • หากคุณทราบว่าจะกำหนดเป้าหมายเป็นอุปกรณ์ Android XR โดยเฉพาะ เช่น ชุดหูฟัง XR และแว่นตา XR แบบใช้สาย คุณจะต้องใช้แพ็กเกจ Unity OpenXR Android XR

  • และเนื่องจากทั้งหมดนี้เป็นไปตามรูปแบบปลั๊กอิน ผลกระทบต่อโค้ดจึงควรมีน้อยที่สุด

  • บางฟีเจอร์อาจไม่พร้อมใช้งานในแพ็กเกจ AR Foundation บางแพ็กเกจ

  • ตัวอย่างเช่น หากดูแผนภูมินี้ คุณจะเห็นว่าการสร้างเมชยังไม่พร้อมใช้งานในแพ็กเกจ Unity OpenXR Spatial Entities

  • การจัดการปลั๊กอิน XR ช่วยให้คุณจัดการฟีเจอร์ OpenXR ที่เลือกในโปรเจ็กต์ได้

  • ดังนั้นหากคุณอยู่ในเครื่องมือแก้ไข Unity ให้ไปที่ "Edit" (แก้ไข) "Project Settings" (การตั้งค่าโปรเจ็กต์) จากนั้น "XR Plug-in Management" (การจัดการปลั๊กอิน XR) จะอยู่ทางแถบด้านซ้าย

  • และคุณจะเห็นฟีเจอร์และกลุ่มฟีเจอร์ OpenXR ที่นี่ เพื่อให้คุณเลือกและยกเลิกการเลือกฟีเจอร์และกลุ่มฟีเจอร์ที่ต้องการรวมไว้ในบิลด์ได้

  • ตัวอย่างเช่น ในภาพหน้าจอนี้ เรากำลังดูส่วนประกอบทั้งหมดที่มาพร้อมกับแพ็กเกจ Android XR OpenXR

  • จากนั้นคุณสามารถผสมผสานและจับคู่สิ่งเหล่านี้กับเอนทิตีเชิงพื้นที่ได้ เช่น หากต้องการ

  • นี่คือหน้าต่าง Package Manager

  • เราได้ไฮไลต์แพ็กเกจบางส่วนที่คุณอาจเห็นในการตั้งค่าโปรเจ็กต์ XR ทั่วไป

  • อย่างที่เห็น เรามี AR Foundation ซึ่งได้กล่าวถึงไปแล้ว

  • นอกจากนี้ เรายังมีปลั๊กอิน OpenXR ด้วย

  • เรามีแพ็กเกจ Android XR

  • นอกจากนี้ ฉันยังได้ไฮไลต์เครื่องมืออื่นๆ จากแพลตฟอร์มอื่นๆ ด้วย เพราะคุณสามารถสร้างโปรเจ็กต์ที่คอมไพล์ไปยังหลายแพลตฟอร์มได้อย่างแน่นอน

  • และเรายังมีแพ็กเกจอื่นๆ ที่ด้านขวาล่างด้วย

  • Composition Layers ซึ่งใช้ได้กับอุปกรณ์ OpenXR, Core Utils ซึ่งมีประโยชน์มากสำหรับทุกอย่างที่เกี่ยวข้องกับ XR, XR Hands และ XR Interaction Toolkit เพื่อรับอินพุต ซึ่งเป็นสิ่งสำคัญมาก

  • ขั้นตอนถัดไปคือการตรวจสอบความถูกต้องของโปรเจ็กต์

  • ดังนั้น ขอย้ำอีกครั้งว่านี่เป็นส่วนหนึ่งของ XR Plug-in Management

  • การตรวจสอบโปรเจ็กต์สามารถตรวจหาฟีเจอร์ที่ซ้ำกัน รวมถึงปัญหาอื่นๆ ในโปรเจ็กต์ที่คุณต้องแก้ไขเพื่อให้โปรเจ็กต์ทำงานได้

  • แต่ในภาพหน้าจอนี้ ฉันได้ไฮไลต์ฟีเจอร์ที่ซ้ำกันไว้

  • โดยพื้นฐานแล้ว ข้อความนี้หมายความว่ามีฟีเจอร์เดียวกัน 2 รายการ เช่น เรามี Anchor, อาจมีระนาบและ Raycast อยู่ที่นี่

  • ผู้ใช้เลือกที่จะรวมฟีเจอร์เหล่านี้ที่ซ้ำกันจากหลายแพ็กเกจ และระบบเพียงแค่แจ้งให้ผู้ใช้เลือกฟีเจอร์ใดฟีเจอร์หนึ่ง

Anchor ในเครื่องและความต่อเนื่อง

  • ซึ่งนำเราไปสู่ Anchor ในเครื่องและความคงอยู่ถาวร

  • Anchor ช่วยให้มั่นใจว่าเนื้อหาดิจิทัลจะยังคงอยู่ในตำแหน่งที่ต้องการในสภาพแวดล้อม ไม่ว่าสถานะการติดตามของเซสชัน AR จะเปลี่ยนแปลงไปอย่างไรก็ตาม

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

  • แล้วจะเกิดอะไรขึ้นเมื่อผู้ใช้ปิดแอปและรีสตาร์ทในภายหลัง แล้วกลับมาที่แอปในเซสชันแยกต่างหาก

  • Anchor แบบถาวรช่วยให้คุณบันทึก Anchor ในเซสชัน AR แล้วโหลดในเซสชันต่อๆ ไปได้

  • โดยจะยังคงอยู่ตลอดวงจรของแอปและการรีสตาร์ทอุปกรณ์

  • ภาพที่แสดงที่นี่คือตัวอย่าง Anchor แบบถาวรในโปรเจ็กต์ตัวอย่าง AR Foundation

  • ฉากตัวอย่างมีเมนูที่มีฟังก์ชันการทำงานทั้งหมดที่รองรับในแพลตฟอร์มนั้น เช่น การบันทึกและการโหลด Anchor

  • และนั่นก็นำเราไปสู่วงจรของ Anchor แบบถาวร

  • ก่อนอื่น คุณจะต้องสร้าง Anchor ในเครื่อง ดังนั้นระบบจึงยังไม่ได้บันทึกไว้ที่ใดเลย ไม่ได้บันทึกไว้ในพื้นที่เก็บข้อมูลถาวร เป็นเพียง Anchor ในเครื่องเท่านั้น

  • จากนั้นคุณจะเก็บข้อมูลไว้ในพื้นที่เก็บข้อมูล

  • หลังจากนั้น คุณจะรีสตาร์ทแอปได้ แล้วจึงโหลดแอปจากพื้นที่เก็บข้อมูล

  • บางแพลตฟอร์ม รวมถึง Android XR ยังรองรับการลบหรือยกเลิกการคงอยู่ของ Anchor ด้วย

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

  • ในการตั้งค่าการจัดการปลั๊กอิน XR คุณสามารถเลือกตัวเลือก "โหลด Anchor ที่บันทึกไว้โดยอัตโนมัติ" ในฟีเจอร์เอนทิตีเชิงพื้นที่: Anchor

  • และการบันทึก Anchor ก็ใช้โค้ดเพียงไม่กี่บรรทัด

  • ก่อนอื่น เราจะเริ่มในเครื่องมือแก้ไข Unity และตรวจสอบว่าฉากพร้อมแล้วโดยเพิ่มคอมโพเนนต์ AR Anchor Manager ลงในเกมออบเจ็กต์ XR Origin

  • ผู้จัดการจะอัปเดตฉากด้วย Anchor ที่ติดตามจากรันไทม์

  • ซึ่งนำเรามาสู่โค้ด

  • หากต้องการเพิ่ม Anchor คุณเพียงแค่เรียกใช้ TryAddAnchorAsync และส่งท่าทางของตำแหน่งที่ต้องการวาง Anchor

    async void CreateAnchorAsync(ARAnchorManager manager, Pose pose) {
        var result = await manager.TryAddAnchorAsync(pose);
        if (result.status.IsError()) {
            // handle error
            return;
        }
        var anchor = result.value;
    }
  • ต่อไปคือการนำ Anchor ออก

    void RemoveAnchor(ARAnchorManager manager, ARAnchor anchor) {
        var result = manager.TryRemoveAnchor(anchor.trackableId);
        if (result.status.IsError()) {
            // handle error
            return;
        }
    }
    
    void DestroyAnchorComponent(ARAnchor anchor) {
        Destroy(anchor);
    }
  • และในทำนองเดียวกัน โค้ดก็มีเพียงบรรทัดเดียว

  • คุณเรียกใช้ TryRemoveAnchor โดยส่งรหัสที่ติดตามได้ของ Anchor

  • เมื่อสร้าง Anchor ระบบจะกำหนดรหัสที่ติดตามได้ให้แล้ว

  • และเราก็มี TrySaveAnchorAsync

    async void SaveAnchorAsync(ARAnchorManager manager, ARAnchor anchor) {
        var result = await manager.TrySaveAnchorAsync(anchor);
        if (result.status.IsError()) {
            // handle error
            return;
        }
    
        // Save this value, then return it as an input parameter
        SerializableGuid guid = result.value;
    }
  • คุณส่ง Anchor ของ AR เป็นอินพุต

  • ฟังก์ชันนี้จะแสดงผล SerializableGuid ที่ระบุ Anchor ในพื้นที่เก็บข้อมูลถาวร

  • จากนั้นคุณจะใช้ GUID ได้เมื่อโหลด Anchor

  • ซึ่งนำเรามาสู่โฆษณา Anchor แบบโหลด

    async void LoadAnchorAsync(ARAnchorManager manager, SerializableGuid guid) {
        var result = await manager.TryLoadAnchorAsync(guid);
        if (result.status.IsError()) {
            // handle error
            return;
        }
    
        ARAnchor anchor = result.value;
    }
  • ฟังก์ชันที่จะเรียกใช้ที่นี่คือ TryLoadAnchorAsync และคุณส่ง GUID ที่เรียงลำดับจากก่อนหน้านี้

  • ซึ่งจะแสดงผลเป็น Anchor ของ AR

  • เพียงเท่านี้ก็เรียบร้อย

  • ฟังก์ชันเหล่านี้ช่วยให้คุณจัดการทั้ง Anchor ในเครื่องและ Anchor แบบถาวรได้อย่างง่ายดาย

  • ดังนั้น การติดตาม Anchor จึงเป็นงานที่ค่อนข้างใช้ทรัพยากรมากในแพลตฟอร์ม AR ส่วนใหญ่

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

  • และตอนนี้ฉันขอส่งต่อให้ Levana

Android XR SDK สำหรับ Unity

  • ขอบคุณ Jennifer

  • ต่อไป เราจะอธิบายถึงสิ่งที่ Google มีส่วนร่วมในเส้นทาง Android XR ใน Unity

  • ดังนั้น นอกจากปลั๊กอิน Unity OpenXR ที่ Jennifer ได้แนะนำไปแล้ว Google ยังมี Android XR SDK สำหรับ Unity พร้อมความสามารถเพิ่มเติมที่พร้อมใช้งานในแพลตฟอร์ม Android XR ด้วย

  • SDK นี้มีฟีเจอร์และแพ็กเกจมากมาย และในการพูดคุยครั้งนี้ เราจะมุ่งเน้นไปที่แพ็กเกจ Android XR Extension สำหรับ Unity

  • ดังนั้นแพ็กเกจ Android XR Extension สำหรับ Unity จึงเป็นผู้ให้บริการ OpenXR เช่นเดียวกับ Android XR และเอนทิตีเชิงพื้นที่ของ OpenXR

  • และสถาปัตยกรรมของแพ็กเกจนี้มีลักษณะดังนี้ โดยสามารถทำงานพร้อมกันหรือแยกกันก็ได้

  • ดังนั้นแพ็กเกจของ Google จึงสร้างขึ้นบนอินเทอร์เฟซ OpenXR OpenXR มาตรฐานโดยตรง เช่นเดียวกับผู้ให้บริการ OpenXR รายอื่นๆ ทั้งหมด

  • เราจึงแสดงฟีเจอร์ต่างๆ เพื่อเปรียบเทียบกับผู้ให้บริการรายอื่นๆ ทั้งหมด

  • คุณจึงสามารถใช้ข้อมูลนี้เพื่อช่วยตัดสินใจว่าจะเลือกใช้ตัวเลือกใดเมื่อใดและเพราะเหตุใด

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

  • หมายเหตุ: สำหรับผู้ที่สร้างแอปและประสบการณ์การใช้งานใน Android XR อยู่แล้ว เราได้นำเสนอฟีเจอร์นี้ผ่านส่วนขยายที่ติดตามได้ ซึ่งใช้ได้เฉพาะใน Android XR เท่านั้น

  • และต่อมาตามที่ Jennifer กล่าวถึง เราได้ทำงานเป็นกลุ่มเปิด OpenXR แล้วเปิดตัวส่วนขยายเอนทิตีเชิงพื้นที่ทางด้านขวา และมอบประสบการณ์การใช้งานที่สอดคล้องกันและข้ามแพลตฟอร์ม

  • และตอนนี้เรากำลังเลิกใช้งานส่วนขยายที่ติดตามได้เพื่อเปลี่ยนไปใช้เฟรมเวิร์กเอนทิตีเชิงพื้นที่

  • ซึ่งไม่เพียงแต่จะมีประสิทธิภาพมากกว่าเท่านั้น แต่ยังรองรับการใช้งานข้ามแพลตฟอร์มด้วย

การสร้างด้วยเอนทิตีเชิงพื้นที่

  • จากนั้นมาดูเอนทิตีเชิงพื้นที่กันอย่างละเอียด

  • นอกจากที่ Jennifer ได้พูดถึงเครื่องบิน, Ray Casting และ Anchor แล้ว คุณยังจะพบว่าฟีเจอร์นี้ได้รับการรองรับจากผู้ให้บริการเอนทิตีเชิงพื้นที่ เช่น มาร์กเกอร์ ซึ่งสามารถตรวจจับ ถอดรหัสบาร์โค้ด 2 มิติมาตรฐาน และติดตามตำแหน่งในพื้นที่ 3 มิติ รวมถึงรูปภาพที่จะจดจำกราฟิก 2 มิติที่รู้จักและติดตามในพื้นที่ 3 มิติ

  • จากนั้นก็กรอบล้อมรอบ ซึ่งจะระบุวัตถุจริง เช่น แป้นพิมพ์ แล็ปท็อป หรือเมาส์ และติดตามกรอบล้อมรอบในท่าทาง 3 มิติ

  • และในตัวอย่างถัดไป เราจะกำหนดค่าฟีเจอร์กรอบล้อมรอบที่แพ็กเกจส่วนขยายของ Google มีให้

  • มุมมองนี้จะเหมือนกันสำหรับฟีเจอร์ OpenXR ทั้งหมด

  • ดังนั้น คุณเพียงแค่ต้องเปลี่ยนไปใช้แพลตฟอร์ม Android XR ก่อน จากนั้นเปิดใช้ผู้ให้บริการ OpenXR และเลือกฟีเจอร์ OpenXR ที่ต้องการใช้สร้าง เช่น ฟีเจอร์กรอบล้อมรอบเอนทิตีเชิงพื้นที่ที่แสดงที่นี่ แล้วแก้ไขปัญหาการตรวจสอบโปรเจ็กต์

  • ซึ่งจะช่วยให้คุณค้นหาทรัพยากร Dependency ทั้งหมดที่ฟีเจอร์หนึ่งๆ ต้องการ จากนั้นจึงแก้ปัญหาความขัดแย้งที่เกิดจากฟีเจอร์หลายรายการที่ส่งผลต่อระบบย่อยเดียวกัน

  • บางครั้งคุณ ส่วนใหญ่แล้วคุณจะต้องเลือกฟีเจอร์เดียวเท่านั้นหากต้องการใช้ เช่น Anchor, ระนาบ หรือกรอบล้อมรอบที่นี่

  • และสุดท้าย คุณสามารถสร้างฉากตัวอย่างหรือฉากทดสอบได้

  • หากต้องการเข้าถึงออบเจ็กต์ที่ติดตามได้ขณะรันไทม์ คุณเพียงแค่เพิ่มคอมโพเนนต์ AR Bounding Box Manager ซึ่งเป็นคอมโพเนนต์ที่คล้ายกับ AR Anchor Manager จากนั้นใช้อินเทอร์เฟซ AR Foundation เพื่อเข้าถึง

  • หรือจะนำเข้าตัวอย่างเอนทิตีเชิงพื้นที่ที่แพ็กเกจส่วนขยายของเรามีให้เป็นเทมเพลตเพื่อเริ่มต้นใช้งานก็ได้

  • ความแตกต่างที่สำคัญเมื่อคุณใช้ฟีเจอร์ AR Foundation ใน Android XR มีดังนี้

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

  • และเพื่อปกป้องผู้ใช้ Android XR จะจำกัดระบบ ซึ่งก็คือการเข้าถึงข้อมูลที่อยู่เบื้องหลังสิทธิ์

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

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

    void Awake() {
        planeManager = GetComponent<ARPlaneManager>();
        planeManager.enabled = false;
        boundingBoxManager = GetComponent<ARBoundingBoxManager>();
        boundingBoxManager.enabled = false;
        permissionUtil = GetComponent<AndroidXRPermissionUtil>();
    }
    
    void OnEnable() {
        StartCoroutine(WaitForPermissions());
    }
  • เมื่อให้สิทธิ์ที่จำเป็นทั้งหมดแล้ว คุณจะเปิดใช้ผู้จัดการจากสคริปต์ได้ เช่นเดียวกับที่ตัวช่วย WaitForPermissions ทำที่นี่

    IEnumerator WaitForPermissions() {
        planeManager.enabled = false;
        boundingBoxManager.enabled = false;
    
        yield return new WaitUntil(() =>
            permissionUtil.AllPermissionGranted());
    
        // Enable after granted permissions and
        // restart subsystems.
        planeManager.enabled = true;
        boundingBoxManager.enabled = true;
    
        // Save permission status.
        permissionGranted = true;
    }
  • การทำเช่นนี้จะช่วยหลีกเลี่ยงความล้มเหลวในการเริ่มต้นระบบย่อยที่เกิดจากสิทธิ์ไม่เพียงพอ

  • และนี่คือฟีเจอร์พิเศษ

  • ตามที่ Jennifer ได้อธิบายเกี่ยวกับ Anchor โดยใช้ AR Foundation เพื่อขยายความสามารถของ Anchor ใน Android XR แพ็กเกจของเรายังมีฟีเจอร์ใหม่ที่เรียกว่า Anchor ที่แชร์ได้ด้วย

  • ฟีเจอร์นี้จำลองสิ่งที่ฟีเจอร์ Anchor ของ AR Foundation รองรับในปัจจุบัน และยังมาพร้อมกับฟังก์ชันเพิ่มเติมบางอย่าง เช่น Anchor เชิงพื้นที่ด้วย

  • และอย่างที่คุณคงนึกภาพออก Anchor คือสะพานเชื่อมที่แท้จริงระหว่างโลกเสมือนจริงกับโลกจริง

  • และแม้ว่า Jennifer จะอธิบายขั้นตอนการสร้าง การบันทึก และการโหลดให้เราฟังแล้ว แต่ทั้งหมดนี้เกิดขึ้นในพื้นที่จริง เช่น Living Room ของผู้ใช้

  • แต่ที่อื่นๆ ในโลกล่ะ

  • และเราจะแชร์ข้อมูลนี้ให้กันและกันได้อย่างไร

Geospatial API

  • และนี่คือจุดที่ Geospatial API เข้ามามีบทบาท

  • ซึ่งช่วยให้คุณสร้าง Anchor เชิงพื้นที่ตามสถานที่ในโลกจริงได้ เช่น ร้านหนังสือโปรดหรือจุดนัดพบในสวนสาธารณะขนาดใหญ่

  • ดังนั้น Geospatial API จึงสามารถให้เครื่องมือติดตามตำแหน่งทางภูมิศาสตร์ที่แม่นยำผ่าน VPS หรือที่เรียกว่าระบบกำหนดตำแหน่งเสมือน เช่น GPS แต่ใช้ข้อมูล Street View กลางแจ้งเพื่อให้ผลการติดตามที่แม่นยำยิ่งขึ้น

  • ดังนั้นบางท่านอาจคุ้นเคยกับมุมมองนี้อยู่แล้วหากเคยมีประสบการณ์ใช้งานฟีเจอร์เชิงพื้นที่ของ ARCore มาก่อน

  • ดังนั้น หากต้องการเข้าถึง Geospatial API ใน Android XR เราต้องเชื่อมต่อกับแบ็กเอนด์ที่โฮสต์บนแพลตฟอร์ม Google Cloud ก่อน

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

  • ทั้งหมดนี้จะช่วยให้คุณใช้ฟีเจอร์ Android XR Google Cloud ที่ให้บริการโดยแพ็กเกจส่วนขยายของเราได้

  • เมื่อเปิดใช้ Geospatial API และรับคีย์ API จากโปรเจ็กต์ Google Cloud แล้ว คุณจะเปิดใช้ฟีเจอร์นี้และกำหนดค่าการตรวจสอบสิทธิ์ผ่านเมนูการตั้งค่า OpenXR ที่แสดงที่นี่ได้ และหรือคุณจะกำหนดค่าด้วยตนเองผ่าน API การเขียนสคริปต์ที่ชื่อว่า TrySetAuthenticationAsync ก็ได้

    async Task TrySetAuthentication() {
        googleCloudFeature =
            OpenXRSettings.Instance
                .GetFeature<XRGoogleCloudFeature>();
        var result = await googleCloudFeature
            .TrySetAuthenticationAsync(
                strategy, credential);
        if (result.IsSuccess()) {
            // Ready to use for geospatial tracker.
        } else if (result.IsUnsupported())  {
            // Google Cloud feature is not supported
        } else if (result.IsKeylessError()) {
            // Confirm if keyless has been set up properly.
        } else {
            // Handling other common OpenXR errors.
        }
    }
  • โปรดทราบว่าปัจจุบันแพลตฟอร์ม Android XR รองรับเฉพาะการตรวจสอบสิทธิ์ด้วยคีย์ API เท่านั้น แต่จะรองรับข้อมูลเข้าสู่ระบบเพิ่มเติมในอนาคต

  • ดังนั้น เมื่อตรวจสอบสิทธิ์แล้ว คุณจะใช้เครื่องมือจัดการข้อมูลเชิงพื้นที่เพื่อเข้าถึงความสามารถด้านข้อมูลเชิงพื้นที่ได้

  • เราขอแนะนำอย่างยิ่งให้ตรวจสอบ Google Maps ก่อนเกี่ยวกับความครอบคลุมของ VPS ก่อนการผสานรวม

  • ดังนั้น คุณจึงต้องมีสิทธิ์เข้าถึงเครือข่ายเมื่อใช้ฟีเจอร์นี้ด้วย

  • ดังนั้น XR Geospatial Manager จึงทำงานคล้ายกับคอมโพเนนต์เซสชัน AR ที่ AR Foundation มีให้

  • ดังนั้นจึงมาพร้อมกับพร็อพเพอร์ตี้สถานะแบบคงที่เพื่อระบุการรองรับระบบและสถานะการติดตามของเครื่องมือติดตามเชิงพื้นที่

  • คุณสามารถลงทะเบียนเหตุการณ์การเปลี่ยนแปลงสถานะได้โดยใช้ Callback ดังนี้

    void OnGeospatialStateChanged(XRGeospatialStateChangedEventArgs eventArgs) {
        bool isInitFailed = eventArgs.CurrState == XRGeospatialState.InitializationFailed;
        if (isInitFailed && XRGeospatialManager.InitializationResult.IsCloudAuthError()) {
            // Handle cloud authentication issues.
        } else if (isInitFailed) {
            // Check XRGeospatialManager.InitializationResult for other common OpenXR errors.
        } else {
            // Iterate runtime state change, and handle accordingly.
        }
    }
    
    private void OnEnable() {
        XRGeospatialManager.OnStateChanged += OnGeospatialStateChanged;
    }
  • และเมื่อสถานะเชิงพื้นที่ทำงานอยู่ คุณจะใช้อินสแตนซ์ผู้จัดการนี้สำหรับฟังก์ชันการทำงานต่อไปนี้ทั้งหมดได้

  • ก่อนอื่น เช่น หากต้องการตรวจสอบความพร้อมใช้งานของ VPS ด้วยตำแหน่ง GPS ที่ระบุ เราจะใช้ API สถานที่ของ Unity เพื่อรับค่า GPS แล้วตรวจสอบความพร้อมใช้งานของ VPS

    async Task CheckVPSAvailability(CancellationToken token) {
        var location = Input.location.lastData;
        try {
            var result = await geospatialManager.TryCheckVPSAvailabilityAsync(
                location.latitude, location.longitude);
            token.ThrowIfCancellationRequested();
            if (result.status.nativeStatusCode == (int)XrResultAndroid.GeospatialCoordinateInvalid) {
                // Invalid coordinates, try with another location.
            } else if (result.status.IsError()) {
                // Handle common OpenXR error: result.status.ToOpenXRStatus()
            }  else if (result.value == XRVPSAvailability.Available)  {
                // You may use this pose to attach geospatial anchors.
                var currentGeospatialPose = new XRGeospatialPose(location);
            }
        }
    }
  • ดังนั้น โดยพื้นฐานแล้วนี่คือการแทนที่หากคุณไม่ต้องการตรวจสอบการรองรับ VPS ผ่านแผนที่ แต่คุณต้องออกไปกลางแจ้งเพื่อตรวจสอบสถานะ GPS จริง

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

    // Geospatial Pose -> Unity Pose
    var geospatialPose =
        new XRGeospatialPose(Input.location.lastData);
    if (geospatialManager.TryLocate(
            geospatialPose, out XRPoseResult result)) {
        if (result.IsPositionValid ||
            result.IsPositionTracked) {
            transform.position = result.Pose.position;
        }
        if (result.IsRotationValid ||
            result.IsRotationTracked) {
            transform.rotation = result.Pose.rotation;
        }
    }
    // Unity Pose -> Geospatial Pose
    Pose pose = new Pose(
        transform.position, transform.rotation);
    if (geospatialManager.TryLocate(
          pose, out XRGeospatialPoseResult result)) {
        if (result.IsPositionValid ||
            result.IsRotationValid) {
            // You may use for anchor attachment.
        }
    }
  • และเมื่อนำผลลัพธ์จากการตรวจสอบ VPS หรือการแปลงท่าทางสัมผัส คุณจะสามารถแนบ Anchor เชิงพื้นที่กับท่าทางสัมผัสเชิงภูมิสารสนเทศที่ระบุหรือบนประเภทพื้นผิวที่ทราบ เช่น ภูมิประเทศหรือหลังคา

    async void PlaceAnchor(XRGeospatialPose pose) {
        try {
            Result<ARShareableAnchor> anchorResult;
            XRGeospatialSurfaceType typeToPlace = /* Choose your target type */;
            if (typeToPlace == XRGeospatialSurfaceType.Default) {
                anchorResult = geospatialManager.TryAttachGeospatialAnchor(pose);
            } else {
                pose.Altitude = 0;
                anchorResult = await geospatialManager.TryAttachSurfaceAnchorAsync(typeToPlace, pose);
            }
            if (anchorResult.status.IsSuccess()) {
                // ARShareableAnchorManager will track the anchor and update it.
            } else {
                // Handle OpenXR failures.
            }
        }
    }
  • และเมื่อนำสิ่งเหล่านี้มารวมกัน คุณจะสร้างประสบการณ์เชิงพื้นที่ที่มหัศจรรย์อย่างแท้จริงได้โดยมีโลกแห่งความเป็นจริงเป็นศูนย์กลาง

  • ดังนั้น เราจึงวางลูกศรไว้ที่นี่เพื่อนำทางกลุ่มเป้าหมายไปยังสถานที่เป้าหมายในโลกจริง

  • ตกลง

  • ดังนั้น Android XR SDK จึงไม่ใช่แพ็กเกจเดียวที่เรามอบให้นักพัฒนาแอป Unity

  • ตอนนี้ Android XR SDK ของ Google สำหรับ Unity ยังรวมแพ็กเกจ Android XR Interaction Framework และ Android XR Audio ด้วย

  • และเราตื่นเต้นมากที่จะได้ขยาย Android XR SDK ด้วยการรองรับฟีเจอร์เพิ่มเติม รวมถึงเอนทิตีเชิงพื้นที่มากขึ้นด้วย

สรุปและแหล่งข้อมูล

  • เอาล่ะ เรามาถึงช่วงท้ายของเซสชันแล้ว

  • คุณสามารถติดตามแผนกลยุทธ์ของ Unity ทางออนไลน์เพื่อดูสิ่งที่จะเกิดขึ้นต่อไป

  • อย่าลืมว่าเรามี Unity 7 ซึ่งเป็น Unity รุ่นถัดไปที่จะเปิดตัวในช่วงต้นปีหน้า

  • ในระหว่างนี้ คุณสามารถลองใช้เครื่องมือเหล่านี้และสร้างโปรเจ็กต์โดยใช้เทมเพลตเทคโนโลยีความจริงแบบผสม (MR) หรือดูโปรเจ็กต์ตัวอย่าง AR Foundation ใน GitHub ของเรา

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

  • และขอขอบคุณทุกคน

  • เราตื่นเต้นที่จะได้เห็นสิ่งที่คุณสร้างด้วย AR Foundation และเอนทิตีเชิงพื้นที่ใน Android XR

รหัส

ข้อมูลโค้ด

ข้อมูลโค้ด C# ที่ 10:34 ใน "Anchor ในเครื่องและความต่อเนื่อง"
async void CreateAnchorAsync(ARAnchorManager manager, Pose pose) {
    var result = await manager.TryAddAnchorAsync(pose);
    if (result.status.IsError()) {
        // handle error
        return;
    }
    var anchor = result.value;
}
ข้อมูลโค้ด C# ที่นาที 10:43 ใน "Local anchors and persistence"
void RemoveAnchor(ARAnchorManager manager, ARAnchor anchor) {
    var result = manager.TryRemoveAnchor(anchor.trackableId);
    if (result.status.IsError()) {
        // handle error
        return;
    }
}

void DestroyAnchorComponent(ARAnchor anchor) {
    Destroy(anchor);
}
ข้อมูลโค้ด C# ที่ 11:00 ใน "Local anchors and persistence"
async void SaveAnchorAsync(ARAnchorManager manager, ARAnchor anchor) {
    var result = await manager.TrySaveAnchorAsync(anchor);
    if (result.status.IsError()) {
        // handle error
        return;
    }

    // Save this value, then return it as an input parameter
    SerializableGuid guid = result.value;
}
ข้อมูลโค้ด C# ที่นาที 11:17 ใน "Local anchors and persistence"
async void LoadAnchorAsync(ARAnchorManager manager, SerializableGuid guid) {
    var result = await manager.TryLoadAnchorAsync(guid);
    if (result.status.IsError()) {
        // handle error
        return;
    }

    ARAnchor anchor = result.value;
}
ข้อมูลโค้ด C# ที่ 16:45 ใน "การสร้างด้วยเอนทิตีเชิงพื้นที่"
void Awake() {
    planeManager = GetComponent<ARPlaneManager>();
    planeManager.enabled = false;
    boundingBoxManager = GetComponent<ARBoundingBoxManager>();
    boundingBoxManager.enabled = false;
    permissionUtil = GetComponent<AndroidXRPermissionUtil>();
}

void OnEnable() {
    StartCoroutine(WaitForPermissions());
}
ข้อมูลโค้ด C# ที่นาที 16:58 ใน "การสร้างด้วยเอนทิตีเชิงพื้นที่"
IEnumerator WaitForPermissions() {
    planeManager.enabled = false;
    boundingBoxManager.enabled = false;

    yield return new WaitUntil(() =>
        permissionUtil.AllPermissionGranted());

    // Enable after granted permissions and
    // restart subsystems.
    planeManager.enabled = true;
    boundingBoxManager.enabled = true;

    // Save permission status.
    permissionGranted = true;
}
ข้อมูลโค้ด C# ที่ 19:12 ใน "Geospatial API"
async Task TrySetAuthentication() {
    googleCloudFeature =
        OpenXRSettings.Instance
            .GetFeature<XRGoogleCloudFeature>();
    var result = await googleCloudFeature
        .TrySetAuthenticationAsync(
            strategy, credential);
    if (result.IsSuccess()) {
        // Ready to use for geospatial tracker.
    } else if (result.IsUnsupported())  {
        // Google Cloud feature is not supported
    } else if (result.IsKeylessError()) {
        // Confirm if keyless has been set up properly.
    } else {
        // Handling other common OpenXR errors.
    }
}
ข้อมูลโค้ด C# ที่ 20:24 ใน "Geospatial API"
void OnGeospatialStateChanged(XRGeospatialStateChangedEventArgs eventArgs) {
    bool isInitFailed = eventArgs.CurrState == XRGeospatialState.InitializationFailed;
    if (isInitFailed && XRGeospatialManager.InitializationResult.IsCloudAuthError()) {
        // Handle cloud authentication issues.
    } else if (isInitFailed) {
        // Check XRGeospatialManager.InitializationResult for other common OpenXR errors.
    } else {
        // Iterate runtime state change, and handle accordingly.
    }
}

private void OnEnable() {
    XRGeospatialManager.OnStateChanged += OnGeospatialStateChanged;
}
ข้อมูลโค้ด C# ที่ 20:38 ใน "Geospatial API"
async Task CheckVPSAvailability(CancellationToken token) {
    var location = Input.location.lastData;
    try {
        var result = await geospatialManager.TryCheckVPSAvailabilityAsync(
            location.latitude, location.longitude);
        token.ThrowIfCancellationRequested();
        if (result.status.nativeStatusCode == (int)XrResultAndroid.GeospatialCoordinateInvalid) {
            // Invalid coordinates, try with another location.
        } else if (result.status.IsError()) {
            // Handle common OpenXR error: result.status.ToOpenXRStatus()
        }  else if (result.value == XRVPSAvailability.Available)  {
            // You may use this pose to attach geospatial anchors.
            var currentGeospatialPose = new XRGeospatialPose(location);
        }
    }
}
ข้อมูลโค้ด C# ที่ 21:03 ใน "Geospatial API"
// Geospatial Pose -> Unity Pose
var geospatialPose =
    new XRGeospatialPose(Input.location.lastData);
if (geospatialManager.TryLocate(
        geospatialPose, out XRPoseResult result)) {
    if (result.IsPositionValid ||
        result.IsPositionTracked) {
        transform.position = result.Pose.position;
    }
    if (result.IsRotationValid ||
        result.IsRotationTracked) {
        transform.rotation = result.Pose.rotation;
    }
}
ข้อมูลโค้ด C# ที่ 21:03 ใน "Geospatial API"
// Unity Pose -> Geospatial Pose
Pose pose = new Pose(
    transform.position, transform.rotation);
if (geospatialManager.TryLocate(
      pose, out XRGeospatialPoseResult result)) {
    if (result.IsPositionValid ||
        result.IsRotationValid) {
        // You may use for anchor attachment.
    }
}
ข้อมูลโค้ด C# ที่ 21:11 ใน "Geospatial API"
async void PlaceAnchor(XRGeospatialPose pose) {
    try {
        Result<ARShareableAnchor> anchorResult;
        XRGeospatialSurfaceType typeToPlace = /* Choose your target type */;
        if (typeToPlace == XRGeospatialSurfaceType.Default) {
            anchorResult = geospatialManager.TryAttachGeospatialAnchor(pose);
        } else {
            pose.Altitude = 0;
            anchorResult = await geospatialManager.TryAttachSurfaceAnchorAsync(typeToPlace, pose);
        }
        if (anchorResult.status.IsSuccess()) {
            // ARShareableAnchorManager will track the anchor and update it.
        } else {
            // Handle OpenXR failures.
        }
    }
}