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

באמצעות Jetpack XR SDK תוכלו להשתמש ב-Jetpack SceneCore כדי ליצור, לשלוט ולנהל מכונות Entity, כמו מודלים תלת-ממדיים, וידאו סטריאופוליסקופי ו-PanelEntity.

ב-Jetpack SceneCore נעשה שימוש בשני דפוסי ארכיטקטורה נפוצים כדי לתמוך בפיתוח תלת-ממד: תרשים סצנה ומערכת ישות-רכיב (ECS).

שימוש בתרשים הסצינה כדי ליצור ישויות ולשלוט בהן

כדי ליצור אובייקטים במרחב תלת-ממדי ולשלוט בהם, צריך להשתמש ב-API של Session ב-Jetpack SceneCore כדי לקבל גישה לתרשים הסצינה. תרשים הסצינה תואם לעולם האמיתי של המשתמש ומאפשר לארגן ישויות תלת-ממדיות כמו לוחות ומודלים תלת-ממדיים במבנה היררכי, ולשמור את המצב של הישויות האלה.

אחרי שתקבלו גישה לתרשים הסצנה, תוכלו להשתמש בממשקי ה-API ב-Jetpack Compose for XR כדי ליצור ממשק משתמש מרחבי (לדוגמה, SpatialPanel ו-Orbiter) בתרשים הסצנה. לגבי תוכן תלת-ממדי, כמו מודלים תלת-ממדיים, אפשר לגשת ישירות לסשן. מידע נוסף זמין בקטע מידע על ActivitySpace שבדף הזה.

מערכת רכיבים של ישות

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

מידע על ActivitySpace

לכל Session יש ActivitySpace שנוצר באופן אוטומטי עם ה-Session. ה-ActivitySpace הוא ה-Entity ברמת העליונה בתרשים הסצינה.

מרחב הפעילות מייצג מרחב תלת-ממדי עם מערכת קואורדינטות ימנית (ציר ה-X מצביע ימינה, ציר ה-Y מצביע למעלה וציר ה-Z מצביע לאחור ביחס למקור) ועם יחידות של מטרים שתואמות לעולם האמיתי. המקור של ActivitySpace הוא שרירותי במידה מסוימת (כי המשתמשים יכולים לאפס את המיקום של ActivitySpace בעולם האמיתי), לכן מומלץ למקם את התוכן ביחס זה לזה במקום ביחס למקור.

עבודה עם ישויות

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

מכיוון ש-ActivitySpace הוא הצומת ברמה העליונה של תרשים הסצנה, כברירת מחדל כל הישויות החדשות ממוקמות ישירות ב-ActivitySpace. כדי להעביר ישויות לאורך תרשים הסצנה, אפשר להפעיל את הפונקציה setParent או את הפונקציה addChild.

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

מניפולציה של ישויות

כשמשנים נכס Entity ששייך לכיתה הבסיסית Entity, השינוי יועבר אל כל הצאצאים שלו. לדוגמה, שינוי הערך של Pose של הורה Entity גורם לכל הצאצאים שלו לקבל את אותה התאמה. שינוי ב-Entity ברמת הצאצא לא משפיע על ההורה.

Pose מייצג את המיקום והסיבוב של הישות במרחב תלת-ממדי. המיקום הוא Vector3 שמורכב מהמיקומים המספריים x,‏ y ו-z. הסיבוב מיוצג על ידי Quaternion. המיקום של Entity הוא תמיד ביחס לישות ההורה שלו. במילים אחרות, Entity שהמיקום שלו הוא (0,‏ 0, ‏ 0) יוצב במקור של הישות ההורה שלו.

//place the entity forward 2 meters
val modelPosition = 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, צריך להפעיל את הפונקציה session.createResizableComponent().

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

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

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

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

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

val movableComponent = xrSession.createMovableComponent(
    systemMovable = false,
    scaleInZ = false,
    anchorPlacement = setOf(anchorPlacement)
)
entity.addComponent(movableComponent)

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

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

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

val resizableComponent = xrSession.createResizableComponent()
resizableComponent.minimumSize = Dimensions(177f, 100f, 1f )
resizableComponent.fixedAspectRatio = 16f / 9f //Specify a 16:9 aspect ratio
entity.addComponent(resizableComponent)

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

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

רשימה מלאה של כל הקבועים של InputEvent מופיעה בחומר העזר.

קטע הקוד הבא מציג דוגמה לשימוש ב-InteractableComponent כדי להגדיל את הגודל של ישות באמצעות היד הימנית ולהקטין אותו באמצעות היד השמאלית.

private val executor by lazy { Executors.newSingleThreadExecutor() }
val interactableComponent = xrSession.createInteractableComponent(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)