Jetpack XR SDK מאפשר לכם להשתמש ב-Jetpack SceneCore כדי ליצור, לשלוט ולנהל מופעים של Entity כמו מודלים תלת-ממדיים, סרטונים סטריאוסקופיים ו-PanelEntity באמצעות Jetpack SceneCore.
Jetpack SceneCore משתמש בשתי תבניות ארכיטקטוניות נפוצות כדי לתמוך בפיתוח תלת-ממד: גרף סצנה ומערכת רכיבי ישויות (ECS).
שימוש בתרשים הסצנה ליצירה ולשליטה בישויות
כדי ליצור אובייקטים במרחב תלת-ממדי ולשלוט בהם, אפשר להשתמש ב-Session API של Jetpack SceneCore כדי לקבל גישה לגרף הסצנה. גרף הסצנה מותאם לעולם האמיתי של המשתמש ומאפשר לארגן ישויות תלת-ממדיות כמו לוחות ומודלים תלת-ממדיים במבנה היררכי, ולשמור את המצב של הישויות האלה.
אחרי שמקבלים גישה לגרף הסצנה, אפשר להשתמש בממשקי ה-API ב-Jetpack Compose for XR כדי ליצור ממשק משתמש מרחבי (לדוגמה, מופעים של SpatialPanel ושל Orbiter) בתוך גרף הסצנה. לגבי תוכן תלת-ממדי כמו מודלים תלת-ממדיים, אפשר לגשת ישירות להפעלה. מידע נוסף זמין בקטע מידע על ActivitySpace בדף הזה.
מערכת רכיבים של ישות
מערכת רכיבי ישויות פועלת לפי העיקרון של הרכבה על פני ירושה. אפשר להרחיב את ההתנהגות של ישויות על ידי צירוף רכיבים שמגדירים את ההתנהגות, וכך להחיל את אותה התנהגות על סוגים שונים של ישויות. מידע נוסף זמין במאמר הוספת התנהגות משותפת לישויות בדף הזה.
מידע על ActivitySpace
לכל Session יש ActivitySpace שנוצר באופן אוטומטי עם Session. ה-ActivitySpace הוא Entity ברמה העליונה בתרשים של הסצנה.
ה-ActivitySpace מייצג מרחב תלת-ממדי עם מערכת קואורדינטות ימנית (ציר ה-x מצביע ימינה, ציר ה-y מצביע למעלה וציר ה-z מצביע אחורה ביחס לנקודת האפס) ועם יחידות של מטרים שתואמות לעולם האמיתי. המיקום של ActivitySpace הוא שרירותי במידה מסוימת (כי המשתמשים יכולים לאפס את המיקום של ActivitySpace בעולם האמיתי), ולכן מומלץ למקם את התוכן ביחס אחד לשני ולא ביחס למיקום של ActivitySpace.
עבודה עם ישויות
הישויות הן מרכזיות ב-SceneCore. רוב הדברים שהמשתמש רואה ומקיים איתם אינטראקציה הם ישויות שמייצגות חלוניות, מודלים תלת-ממדיים ועוד.
מכיוון שהרכיב ActivitySpace הוא הצומת ברמה העליונה בתרשים הסצנה, כברירת מחדל, כל הישויות החדשות ממוקמות ישירות בתוך ActivitySpace. אפשר להעביר מיקומים של ישויות לאורך גרף הסצנה על ידי הגדרת parent או באמצעות addChild().
לישויות יש כמה התנהגויות שמוגדרות כברירת מחדל, שמשותפות לכל הישויות, כמו שינוי המיקום, הסיבוב או הנראות. לEntity
תת-מחלקות ספציפיות, כמו GltfModelEntity, יש התנהגויות נוספות שתומכות בתת-המחלקות.
שינוי ישויות
כשמבצעים שינוי בנכס Entity ששייך למחלקת הבסיס Entity
השינוי יועבר לכל הצאצאים שלו. לדוגמה, שינוי של Pose של Entity אב גורם לכך שכל הצאצאים שלו יקבלו את אותו שינוי. שינוי ביחידה ארגונית ברמת הצאצא Entity לא משפיע על היחידה הארגונית ברמה העליונה שלה.
המאפיין Pose מייצג את המיקום והסיבוב של הישות במרחב התלת-ממדי. המיקום הוא Vector3 שמורכב ממיקומים מספריים x, y ו-z. הסיבוב מיוצג על ידי Quaternion. המיקום של Entity תמיד יחסי לישות האם שלו. במילים אחרות, מיקום של Entity שמוגדר כ- (0, 0, 0) יהיה בנקודת האפס של ישות האם שלו.
// Place the entity forward 2 meters val newPosition = Vector3(0f, 0f, -2f) // Rotate the entity by 180 degrees on the up axis (upside-down) val newOrientation = Quaternion.fromEulerAngles(0f, 0f, 180f) // Update the position and rotation on the entity entity.setPose(Pose(newPosition, newOrientation))
כדי להשבית Entity, משתמשים ב-setEnabled(). הפעולה הזו הופכת אותו לבלתי נראה ומפסיקה את כל העיבוד שמתבצע בו.
// Disable the entity. entity.setEnabled(false)
כדי לשנות את הגודל של Entity בלי לשנות את הצורה הכללית שלו, משתמשים בsetScale().
// Double the size of the entity entity.setScale(2f)
הוספת התנהגות נפוצה לישויות
אפשר להשתמש ברכיבים הבאים כדי להוסיף התנהגות נפוצה לישויות:
-
MovableComponent: מאפשר למשתמש להעביר ישויות ResizableComponent: מאפשר למשתמש לשנות את הגודל של ישויות באמצעות דפוסי ממשק משתמש עקביים-
InteractableComponent: מאפשרת לכם לתעד אירועי קלט לאינטראקציות מותאמות אישית
צריך ליצור מופעים של רכיבים באמצעות שיטת היצירה המתאימה במחלקה Session. לדוגמה, כדי ליצור ResizableComponent, מתקשרים אל ResizableComponent.create().
כדי להוסיף את ההתנהגות הספציפית של הרכיב ל-Entity, משתמשים בשיטה addComponent().
איך משתמשים ב-MovableComponent כדי לאפשר למשתמשים להעביר ישות
ההרשאה MovableComponent מאפשרת למשתמש להזיז את Entity.
אירועי תנועה נשלחים לרכיב כשמתבצעת אינטראקציה עם הרכיבים. ההתנהגות של המערכת כברירת מחדל, שנוצרה באמצעות MovableComponent.createSystemMovable(), גורמת להזזת Entity כשגוררים את הקישוטים:
val movableComponent = MovableComponent.createSystemMovable(session) entity.addComponent(movableComponent)
הפרמטר האופציונלי scaleInZ (שמוגדר כברירת מחדל ל-true) גורם לישות להתאים את הגודל שלה באופן אוטומטי כשהיא מתרחקת מהמשתמש, בדומה לאופן שבו המערכת משנה את הגודל של חלוניות במרחב הביתי.
בגלל האופי ההיררכי של מערכת רכיבי הישות, קנה המידה של ההורה ישפיע על כל הצאצאים שלו.
אפשר גם לציין אם הישות יכולה להיות מעוגנת לסוג משטח כמו משטחים אופקיים או אנכיים, או למשטחים סמנטיים ספציפיים כמו שולחן, קיר או תקרה. כדי לציין אפשרויות של עוגן, מציינים קבוצה של AnchorPlacement כשיוצרים את MovableComponent. בדוגמה הזו, הישות שאפשר להזיז ולעגן לכל משטח אופקי של רצפה או שולחן:
val anchorPlacement = AnchorPlacement.createForPlanes( anchorablePlaneOrientations = setOf(PlaneOrientation.VERTICAL), anchorablePlaneSemanticTypes = setOf(PlaneSemanticType.FLOOR, PlaneSemanticType.TABLE) ) val movableComponent = MovableComponent.createAnchorable( session = session, anchorPlacement = setOf(anchorPlacement) ) entity.addComponent(movableComponent)
שימוש ב-ResizableComponent כדי לשנות את הגודל של רכיב Entity
התכונה ResizableComponent מאפשרת למשתמשים לשנות את הגודל של Entity. האזור ResizableComponent כולל רמזים חזותיים לאינטראקציה שמזמינים את המשתמש לשנות את הגודל של Entity. כשיוצרים את ResizableComponent, אפשר לציין גודל מינימלי או מקסימלי (במטרים). יש לכם גם אפשרות לציין יחס גובה-רוחב קבוע כשמשנים את הגודל, כך שהרוחב והגובה ישתנו באופן יחסי זה לזה.
כשיוצרים ResizableComponent, מציינים resizeEventListener שמטפל באירועי העדכון. אתם יכולים להגיב לאירועים שונים של ResizeState, כמו RESIZE_STATE_ONGOING או RESIZE_STATE_END.
דוגמה לשימוש ב-ResizableComponent עם יחס רוחב-גובה קבוע ב-SurfaceEntity:
val resizableComponent = ResizableComponent.create(session) { event -> if (event.resizeState == ResizeEvent.ResizeState.END) { // update the Entity to reflect the new size surfaceEntity.shape = SurfaceEntity.Shape.Quad(FloatSize2d(event.newSize.width, event.newSize.height)) } } resizableComponent.minimumEntitySize = FloatSize3d(177f, 100f, 1f) resizableComponent.isFixedAspectRatioEnabled = true // Maintain a fixed aspect ratio when resizing surfaceEntity.addComponent(resizableComponent)
שימוש ב-InteractableComponent כדי לתעד אירועי קלט של משתמשים
התג InteractableComponent מאפשר לכם לתעד אירועי קלט מהמשתמש, למשל כשמשתמש יוצר אינטראקציה עם Entity או מעביר מעליו את העכבר. כשיוצרים InteractableComponent, מציינים listener שמקבל את אירועי הקלט.
כשמשתמש מבצע פעולת קלט כלשהי, הפונקציה של מאזין האירועים מופעלת עם פרטי הקלט שמופיעים בפרמטר InputEvent.
-
InputEvent.actionמציין את סוג הקלט, כמו העברת העכבר או הקשה על ישות -
InputEvent.sourceמציין מאיפה הגיע הקלט, למשל קלט של יד או של בקר -
InputEvent.pointerTypeמציין אם הקלט הגיע מיד ימין או מיד שמאל
רשימה מלאה של כל הקבועים של InputEvent זמינה במאמרי העזרה.
בקטע הקוד הבא מוצגת דוגמה לשימוש ב-InteractableComponent כדי להגדיל את הגודל של ישות באמצעות יד ימין ולהקטין אותו באמצעות יד שמאל.
val executor = Executors.newSingleThreadExecutor() val interactableComponent = InteractableComponent.create(session, executor) { // when the user disengages with the entity with their hands if (it.source == InputEvent.Source.HANDS && it.action == InputEvent.Action.UP) { // increase size with right hand and decrease with left if (it.pointerType == InputEvent.Pointer.RIGHT) { entity.setScale(1.5f) } else if (it.pointerType == InputEvent.Pointer.LEFT) { entity.setScale(0.5f) } } } entity.addComponent(interactableComponent)
יצירת מודלים תלת-ממדיים בהתאמה אישית בזמן ריצה
Custom Mesh API מאפשר ליצור צורות תלת-ממדיות באופן פרוגרמטי ישירות בקוד, במקום לטעון נכסים סטטיים כמו קובצי glTF. בעזרת בנייה של גיאומטריה בהתאמה אישית תוך כדי תנועה, אפשר לרנדר נתונים פרוצדורליים, צורות דינמיות בהתאמה אישית וסביבות תלת-ממדיות שנראות אינסופיות, כמו פני שטח שממשיכים להיווצר בזמן שהמשתמשים חוקרים אותם. בנוסף, יצירת רשתות בזמן ריצה תורמת לצמצום הגודל של קובצי הבינארי, כי אין צורך לארוז אינספור וריאציות של נכס תלת-ממדי יחיד.