יצירה, בקרה וניהול של ישויות

‫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. אפשר להעביר מיקומים של ישויות לאורך גרף הסצנה על ידי קריאה ל-setParent() או ל-addChild().

לישויות יש כמה התנהגויות ברירת מחדל לגבי דברים שמשותפים לכל הישויות, כמו שינוי המיקום, הסיבוב או החשיפה. למחלקות משנה ספציפיות, כמו GltfModelEntity, יש התנהגויות נוספות שתומכות במחלקת המשנה.Entity

שינוי ישויות

כשמבצעים שינוי בנכס 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, משתמשים ב-setHidden().

// Hide the entity
entity.setHidden(true)

כדי לשנות את הגודל של Entity בלי לשנות את הצורה הכללית שלו, משתמשים ב-setScale().

// Double the size of the entity
entity.setScale(2f)

הוספת התנהגות נפוצה לישויות

אפשר להשתמש ברכיבים הבאים כדי להוסיף התנהגות נפוצה לישויות:

  • MovableComponent: מאפשר למשתמש להעביר ישויות
  • ResizableComponent: מאפשר למשתמש לשנות את הגודל של ישויות באמצעות דפוסי ממשק משתמש עקביים
  • InteractableComponent: מאפשרת לכם לתעד אירועי קלט לאינטראקציות מותאמות אישית

צריך ליצור מופעים של רכיבים באמצעות שיטת היצירה המתאימה במחלקה Session. לדוגמה, כדי ליצור ResizableComponent, קוראים ל-ResizableComponent.create().

כדי להוסיף את ההתנהגות הספציפית של הרכיב ל-Entity, משתמשים בשיטה addComponent().

איך משתמשים ב-MovableComponent כדי לאפשר למשתמשים להזיז ישות

ההרשאה MovableComponent מאפשרת למשתמש להזיז את Entity. אפשר גם לציין אם הישות יכולה להיות מוצמדת לסוג משטח כמו משטחים אופקיים או אנכיים, או למשטחים סמנטיים ספציפיים כמו שולחן, קיר או תקרה. כדי לציין אפשרויות של עוגן, מציינים קבוצה של AnchorPlacement כשיוצרים את MovableComponent.

דוגמה לישות שאפשר להזיז ולעגן לכל משטח אנכי, ורק למשטחים אופקיים של רצפה ותקרה.

val anchorPlacement = AnchorPlacement.createForPlanes(
    planeTypeFilter = setOf(PlaneSemantic.FLOOR, PlaneSemantic.TABLE),
    planeSemanticFilter = setOf(PlaneType.VERTICAL)
)

val movableComponent = MovableComponent.create(
    session = session,
    systemMovable = false,
    scaleInZ = false,
    anchorPlacement = setOf(anchorPlacement)
)
entity.addComponent(movableComponent)

כשהמשתמש מזיז את הישות, הפרמטר scaleInZ משנה באופן אוטומטי את קנה המידה של הישות כשהיא מתרחקת מהמשתמש, בדומה לאופן שבו המערכת משנה את קנה המידה של החלוניות במרחב הביתי. בגלל האופי ההיררכי של מערכת רכיבי הישות, קנה המידה של רכיב האב ישפיע על כל רכיבי הצאצא שלו.

שימוש ב-ResizableComponent כדי לשנות את הגודל של רכיב Entity

התכונה ResizableComponent מאפשרת למשתמשים לשנות את הגודל של Entity. האזור ResizableComponent כולל רמזים חזותיים לאינטראקציה שמזמינים את המשתמש לשנות את הגודל של Entity. כשיוצרים את ResizableComponent, אפשר לציין גודל מינימלי או מקסימלי (במטרים). יש לכם גם אפשרות לציין יחס גובה-רוחב קבוע כשמשנים את הגודל, כך שהרוחב והגובה ישתנו באופן יחסי זה לזה.

כשמשתמשים ב-ResizableComponent, צריך לציין ResizeListener כדי להגיב לאירועי שינוי גודל ספציפיים, כמו onResizeUpdate או onResizeEnd.

דוגמה לשימוש בתג ResizableComponent עם יחס רוחב-גובה קבוע בתג SurfaceEntity:

val resizableComponent = ResizableComponent.create(session)
resizableComponent.minimumSize = Dimensions(177f, 100f, 1f)
resizableComponent.fixedAspectRatio = 16f / 9f // Specify a 16:9 aspect ratio

resizableComponent.addResizeListener(
    executor,
    object : ResizeListener {
        override fun onResizeEnd(entity: Entity, finalSize: Dimensions) {

            // update the size in the component
            resizableComponent.size = finalSize

            // update the Entity to reflect the new size
            (entity as SurfaceEntity).canvasShape = SurfaceEntity.CanvasShape.Quad(finalSize.width, finalSize.height)
        }
    },
)

entity.addComponent(resizableComponent)

שימוש ב-InteractableComponent כדי לתעד אירועי קלט של משתמשים

התג InteractableComponent מאפשר לכם לתעד אירועי קלט מהמשתמש, כמו כשמשתמש יוצר אינטראקציה עם Entity או מעביר מעליו את העכבר. כשיוצרים InteractableComponent, צריך לציין InputEventListener כדי לקבל את אירועי הקלט. כשמשתמש מבצע פעולת קלט כלשהי, השיטה onInputEvent נקראת עם פרטי הקלט הספציפיים שסופקו בפרמטר InputEvent.

רשימה מלאה של כל הקבועים של 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_TYPE_RIGHT) {
            entity.setScale(1.5f)
        } else if (it.pointerType == InputEvent.POINTER_TYPE_LEFT) {
            entity.setScale(0.5f)
        }
    }
}
entity.addComponent(interactableComponent)