สร้าง ควบคุม และจัดการเอนทิตี

Jetpack XR SDK ช่วยให้คุณใช้ Jetpack SceneCore เพื่อสร้าง ควบคุม และจัดการอินสแตนซ์ Entity เช่น โมเดล 3 มิติ วิดีโอสเตอริโอสโคปิก และ PanelEntity โดยใช้ Jetpack SceneCore

Jetpack SceneCore ใช้รูปแบบสถาปัตยกรรมทั่วไป 2 รูปแบบเพื่อรองรับการพัฒนา 3 มิติ ได้แก่ Scene Graph และระบบเอนทิตี-คอมโพเนนต์ (ECS)

ใช้กราฟฉากเพื่อสร้างและควบคุมเอนทิตี

หากต้องการสร้างและควบคุมออบเจ็กต์ในพื้นที่ 3 มิติ คุณสามารถใช้ API Session ของ Jetpack SceneCore เพื่อรับสิทธิ์เข้าถึงกราฟฉาก กราฟฉากสอดคล้องกับโลกแห่งความจริงของผู้ใช้ และช่วยให้คุณจัดระเบียบเอนทิตี 3 มิติ เช่น แผงและโมเดล 3 มิติ เป็นโครงสร้างแบบลำดับชั้น และเก็บสถานะของเอนทิตีเหล่านั้น

เมื่อได้รับสิทธิ์เข้าถึงกราฟฉากแล้ว คุณจะใช้ API ใน Jetpack Compose สำหรับ XR เพื่อสร้าง UI เชิงพื้นที่ (เช่น อินสแตนซ์ SpatialPanel และ Orbiter) ภายในกราฟฉากได้ สำหรับเนื้อหา 3 มิติ เช่น โมเดล 3 มิติ คุณจะเข้าถึงเซสชันได้โดยตรง ดูข้อมูลเพิ่มเติมได้ที่เกี่ยวกับ ActivitySpace ในหน้านี้

ระบบคอมโพเนนต์เอนทิตี

ระบบเอนทิตี-คอมโพเนนต์เป็นไปตามหลักการของการประกอบมากกว่า การรับช่วง คุณขยายลักษณะการทำงานของเอนทิตีได้โดยการแนบ คอมโพเนนต์ที่กำหนดลักษณะการทำงาน ซึ่งจะช่วยให้คุณใช้ลักษณะการทำงานเดียวกันกับ เอนทิตีประเภทต่างๆ ได้ ดูข้อมูลเพิ่มเติมได้ที่หัวข้อเพิ่มลักษณะการทำงานทั่วไป ให้กับเอนทิตีในหน้านี้

เกี่ยวกับ ActivitySpace

Session แต่ละรายการจะมีActivitySpace ที่สร้างขึ้นโดยอัตโนมัติ พร้อมกับSession ActivitySpace คือ Entity ระดับบนสุดในกราฟฉาก

ActivitySpace แสดงพื้นที่ 3 มิติที่มีระบบพิกัดแบบมือขวา (แกน x ชี้ไปทางขวา แกน y ชี้ขึ้น และแกน z ชี้กลับ เมื่อเทียบกับจุดเริ่มต้น) และมีหน่วยเป็นเมตรซึ่งตรงกับโลกแห่งความจริง จุดเริ่มต้นของ ActivitySpace ค่อนข้างเป็นไปตามอำเภอใจ (เนื่องจากผู้ใช้สามารถรีเซ็ตตำแหน่งของ ActivitySpace ภายในโลกจริงได้) ดังนั้นจึงขอแนะนำให้วางตำแหน่งเนื้อหาโดยอิงตามตำแหน่งของเนื้อหาอื่นๆ แทนที่จะอิงตามจุดเริ่มต้น

ทำงานกับเอนทิตี

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

เนื่องจาก ActivitySpace เป็นโหนดระดับบนสุดของกราฟฉาก โดยค่าเริ่มต้น เอนทิตีใหม่ทั้งหมดจะอยู่ใน ActivitySpace โดยตรง คุณย้าย เอนทิตีไปตามกราฟฉากได้โดยเรียกใช้ setParent() หรือ addChild()

เอนทิตีมีลักษณะการทำงานเริ่มต้นบางอย่างสำหรับสิ่งที่เป็นสากลสำหรับเอนทิตีทั้งหมด เช่น การเปลี่ยนตำแหน่ง การหมุน หรือระดับการมองเห็น Entity คลาสย่อยที่เฉพาะเจาะจง เช่น GltfModelEntity มีลักษณะการทำงานเพิ่มเติมที่ รองรับคลาสย่อย

แก้ไขเอนทิตี

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

Pose แสดงตำแหน่งและการหมุนของเอนทิตีภายในพื้นที่ 3 มิติ 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: อนุญาตให้ผู้ใช้ปรับขนาดเอนทิตีด้วย รูปแบบ UI ที่สอดคล้องกัน
  • InteractableComponent: ให้คุณบันทึกเหตุการณ์อินพุตสำหรับการโต้ตอบที่กำหนดเอง

การสร้างอินสแตนซ์ของคอมโพเนนต์ต้องทำผ่านวิธีการสร้างที่เหมาะสมในคลาส Session เช่น หากต้องการสร้าง ResizableComponent ให้เรียกใช้ ResizableComponent.create()

หากต้องการเพิ่มลักษณะการทำงานของคอมโพเนนต์ที่เฉพาะเจาะจงลงใน Entity ให้ใช้เมธอด addComponent()

ใช้ MovableComponent เพื่อให้ผู้ใช้ย้ายเอนทิตีได้

MovableComponent อนุญาตให้ผู้ใช้ย้าย Entity ได้ นอกจากนี้ คุณยังระบุได้ด้วยว่าต้องการยึดเอนทิตีกับพื้นผิวประเภทใด เช่น พื้นผิวแนวนอนหรือแนวตั้ง หรือพื้นผิวเชิงความหมายที่เฉพาะเจาะจง เช่น โต๊ะ ผนัง หรือเพดาน หากต้องการระบุตัวเลือก Anchor ให้ระบุชุด 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 เพื่อให้ผู้ใช้ปรับขนาดเอนทิตีได้

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)