کیت توسعه نرمافزار Jetpack XR به شما امکان میدهد با استفاده از Jetpack SceneCore، نمونههای Entity مانند مدلهای سهبعدی ، ویدیوی استریوسکوپی و PanelEntity را با استفاده از Jetpack SceneCore ایجاد، کنترل و مدیریت کنید.
Jetpack SceneCore از دو الگوی معماری رایج برای پشتیبانی از توسعه سهبعدی استفاده میکند: یک نمودار صحنه و یک سیستم اجزای موجودیت (ECS).
استفاده از نمودار صحنه برای ایجاد و کنترل موجودیتها
برای ایجاد و کنترل اشیاء در فضای سهبعدی، میتوانید از رابط برنامهنویسی کاربردی (API) جلسه (Session API) جتپک سینکور (Jetpack SceneCore) برای دسترسی به نمودار صحنه (scene graph) استفاده کنید. نمودار صحنه با دنیای واقعی کاربر همسو میشود و به شما امکان میدهد موجودیتهای سهبعدی مانند پنلها و مدلهای سهبعدی را در یک ساختار سلسله مراتبی سازماندهی کنید و وضعیت آن موجودیتها را نگه دارید.
پس از دسترسی به نمودار صحنه، میتوانید از APIهای موجود در Jetpack Compose for XR برای ایجاد رابط کاربری فضایی (به عنوان مثال، نمونههای SpatialPanel و Orbiter ) در نمودار صحنه استفاده کنید. برای محتوای سهبعدی مانند مدلهای سهبعدی، میتوانید مستقیماً به Session دسترسی داشته باشید. برای کسب اطلاعات بیشتر، به بخش «درباره ActivitySpace» در این صفحه مراجعه کنید.
سیستم مؤلفه موجودیت
یک سیستم کامپوننت موجودیت از اصل ترکیب به جای وراثت پیروی میکند. شما میتوانید رفتار موجودیتها را با اتصال کامپوننتهای تعریفکننده رفتار گسترش دهید، که به شما امکان میدهد رفتار یکسانی را برای انواع مختلف موجودیتها اعمال کنید. برای اطلاعات بیشتر، به بخش «افزودن رفتار مشترک به موجودیتها» در این صفحه مراجعه کنید.
درباره ActivitySpace
هر Session (Session) یک ActivitySpace دارد که به طور خودکار با آن Session ایجاد میشود. ActivitySpace بالاترین سطح Entity در نمودار صحنه (scene graph) است.
ActivitySpace یک فضای سهبعدی با سیستم مختصات راستگرد (محور x به سمت راست، محور y به سمت بالا و محور z به سمت عقب نسبت به مبدا) و با واحدهای متر که با دنیای واقعی مطابقت دارند، نشان میدهد. مبدا ActivitySpace تا حدودی دلخواه است (زیرا کاربران میتوانند موقعیت ActivitySpace را در دنیای واقعی تنظیم مجدد کنند)، بنابراین توصیه میشود محتوا را نسبت به یکدیگر به جای نسبت به مبدا قرار دهید.
کار با موجودیتها
موجودیتها (Entities) در SceneCore نقش محوری دارند. تقریباً هر چیزی که کاربر میبیند و با آن تعامل دارد، موجودیتهایی هستند که پنلها، مدلهای سهبعدی و موارد دیگر را نشان میدهند.
از آنجایی که ActivitySpace گره سطح بالای نمودار صحنه است، به طور پیشفرض، تمام موجودیتهای جدید مستقیماً در ActivitySpace قرار میگیرند. میتوانید با تنظیم parent آن یا با استفاده از addChild() ، موجودیتها را در امتداد نمودار صحنه جابجا کنید.
موجودیتها برخی رفتارهای پیشفرض برای چیزهایی دارند که برای همه موجودیتها عمومیت دارند، مانند تغییر موقعیت، چرخش یا قابلیت مشاهده. زیرکلاسهای خاص Entity ، مانند GltfModelEntity ، رفتارهای اضافی دارند که از زیرکلاس پشتیبانی میکنند.
دستکاری موجودیتها
وقتی تغییری در یک ویژگی Entity که متعلق به کلاس پایه Entity است ایجاد میکنید، این تغییر به همه فرزندان آن به صورت آبشاری (cassert down) منتقل میشود. برای مثال، تنظیم Pose یک Entity والد باعث میشود که همه فرزندان آن نیز تغییر یکسانی داشته باشند. ایجاد تغییر در یک Entity فرزند، تاثیری بر والد آن ندارد.
یک Pose نشان دهنده موقعیت و چرخش Entity در فضای سه بعدی است. این موقعیت یک 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 برای قابل جابجایی کردن یک Entity توسط کاربر
MovableComponent به یک Entity اجازه میدهد تا توسط کاربر قابل جابجایی باشد.
رویدادهای حرکت (Motion Events) زمانی که تزئینات (decorations) با کامپوننت تعامل پیدا میکنند، به آن ارسال میشوند. رفتار پیشفرض سیستم که با MovableComponent.createSystemMovable() ایجاد شده است، Entity شما را زمانی که تزئینات کشیده میشوند، حرکت میدهد:
val movableComponent = MovableComponent.createSystemMovable(session) entity.addComponent(movableComponent)
پارامتر اختیاری scaleInZ (که به طور پیشفرض روی true تنظیم شده است)، باعث میشود که Entity به طور خودکار مقیاس خود را با دور شدن از کاربر تنظیم کند، به روشی مشابه نحوه مقیاسبندی پنلها توسط سیستم در فضای خانه . با توجه به ماهیت "آبشاری" سیستم کامپوننت entity، مقیاس والد بر همه فرزندان آن تأثیر خواهد گذاشت.
همچنین میتوانید مشخص کنید که آیا میتوان موجودیت را به یک نوع سطح مانند سطوح افقی یا عمودی، یا سطوح معنایی خاص مانند میز، دیوار یا سقف متصل کرد یا خیر. برای مشخص کردن گزینههای اتصال، هنگام ایجاد MovableComponent مجموعهای از AnchorPlacement را مشخص کنید. در این مثال، موجودیتی که میتواند جابجا شود و به هر سطح افقی کف یا میز متصل شود:
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)