इकाइयां बनाना, उन्हें कंट्रोल करना, और मैनेज करना

एक्सआर की सुविधा वाले डिवाइस
इस गाइड की मदद से, इन तरह के एक्सआर डिवाइसों के लिए अनुभव बनाए जा सकते हैं.
एक्सआर हेडसेट
वायर्ड एक्सआर ग्लास

Jetpack XR SDK की मदद से, Jetpack SceneCore का इस्तेमाल करके Entity इंस्टेंस बनाए, कंट्रोल किए, और मैनेज किए जा सकते हैं. जैसे, 3D मॉडल, स्टीरियोस्कोपिक वीडियो, और Jetpack SceneCore का इस्तेमाल करके PanelEntity.

Jetpack SceneCore, 3D डेवलपमेंट के लिए दो सामान्य आर्किटेक्चर पैटर्न का इस्तेमाल करता है: सीन ग्राफ़ और इकाई-कॉम्पोनेंट सिस्टम (ईसीएस).

सीन ग्राफ़ का इस्तेमाल करके, इकाइयां बनाएं और उन्हें कंट्रोल करें

3D स्पेस में ऑब्जेक्ट बनाने और उन्हें कंट्रोल करने के लिए, Jetpack SceneCore के Session API का इस्तेमाल किया जा सकता है. इससे सीन ग्राफ़ का ऐक्सेस मिलता है. सीन ग्राफ़, उपयोगकर्ता की असली दुनिया के साथ अलाइन होता है. इससे पैनल और 3D मॉडल जैसी 3D इकाइयों को क्रमबद्ध तरीके से व्यवस्थित किया जा सकता है. साथ ही, इन इकाइयों की स्थिति को बनाए रखा जा सकता है.

सीन ग्राफ़ का ऐक्सेस मिलने के बाद, Jetpack Compose for XR में मौजूद एपीआई का इस्तेमाल करके, सीन ग्राफ़ में स्पेशल यूज़र इंटरफ़ेस (जैसे, SpatialPanel और Orbiter इंस्टेंस) बनाए जा सकते हैं. 3D मॉडल जैसे 3D कॉन्टेंट के लिए, सीधे सेशन को ऐक्सेस किया जा सकता है. ज़्यादा जानने के लिए, इस पेज पर ActivitySpace के बारे में जानकारी देखें.

इकाई कॉम्पोनेंट सिस्टम

इकाई कॉम्पोनेंट सिस्टम, इनहेरिटेंस के बजाय कंपोज़िशन के सिद्धांत का पालन करता है. व्यवहार तय करने वाले कॉम्पोनेंट अटैच करके, इकाइयों के व्यवहार को बढ़ाया जा सकता है. इससे अलग-अलग तरह की इकाइयों पर एक जैसा व्यवहार लागू किया जा सकता है. ज़्यादा जानकारी के लिए, इस पेज पर इकाइयों में सामान्य व्यवहार जोड़ना लेख पढ़ें.

ActivitySpace के बारे में जानकारी

हर Session में एक ActivitySpace होता है, जो Session के साथ अपने-आप जनरेट होता है. ActivitySpace, सीन ग्राफ़ में टॉप-लेवल Entity होता है.

ActivitySpace, तीन डाइमेंशन वाला स्पेस होता है. इसमें राइट-हैंडेड कोऑर्डिनेट सिस्टम होता है. इसमें x-ऐक्सिस दाईं ओर, y-ऐक्सिस ऊपर की ओर, और z-ऐक्सिस ऑरिजिन के पीछे की ओर होता है. साथ ही, इसमें यूनिट के तौर पर मीटर का इस्तेमाल किया जाता है, जो असल दुनिया से मेल खाता है. ActivitySpace की जगह कुछ हद तक मनमुताबिक होती है, क्योंकि उपयोगकर्ता ActivitySpace की जगह को असल दुनिया में रीसेट कर सकते हैं. इसलिए, हमारा सुझाव है कि कॉन्टेंट को ऑरिजिन के हिसाब से रखने के बजाय, एक-दूसरे के हिसाब से रखें.

इकाइयों के साथ काम करना

SceneCore के लिए इकाइयां बहुत ज़रूरी होती हैं. उपयोगकर्ता को जो भी चीज़ें दिखती हैं और जिनसे वह इंटरैक्ट करता है वे पैनल, 3D मॉडल वगैरह को दिखाने वाली इकाइयां होती हैं.

ActivitySpace सीन ग्राफ़ का टॉप-लेवल नोड है. इसलिए, डिफ़ॉल्ट रूप से सभी नई इकाइयों को सीधे ActivitySpace में रखा जाता है. सीन ग्राफ़ में मौजूद इकाइयों की जगह बदलने के लिए, parent सेट करें या addChild() का इस्तेमाल करें.

सभी इकाइयों के लिए, कुछ डिफ़ॉल्ट व्यवहार होते हैं. जैसे, पोज़िशन, रोटेशन या दिखने की स्थिति बदलना. Entity की कुछ खास सबक्लास, जैसे कि GltfModelEntity, में कुछ अतिरिक्त व्यवहार होते हैं. ये व्यवहार सबक्लास के साथ काम करते हैं.

इकाइयों में बदलाव करना

जब बेस Entity क्लास से जुड़ी किसी Entity प्रॉपर्टी में बदलाव किया जाता है, तो यह बदलाव उससे जुड़ी सभी चाइल्ड प्रॉपर्टी में भी लागू हो जाता है. उदाहरण के लिए, पैरंट Entity के Pose में बदलाव करने से, उसकी सभी चाइल्ड यूनिट में एक जैसा बदलाव होता है. चाइल्ड Entity में बदलाव करने से, पैरंट पर कोई असर नहीं पड़ता.

Pose, 3D स्पेस में मौजूद इकाई की जगह और रोटेशन को दिखाता है. जगह की जानकारी, x, y, z की संख्यात्मक स्थितियों वाली Vector3 होती है. रोटेशन को 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 पर सेट होता है) की मदद से, 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 का इस्तेमाल करके, किसी इकाई को उपयोगकर्ता के हिसाब से साइज़ बदलने की सुविधा देना

ResizableComponent की मदद से, उपयोगकर्ता किसी Entity का साइज़ बदल सकते हैं. ResizableComponent में विज़ुअल इंटरैक्शन के ऐसे संकेत शामिल होते हैं जो उपयोगकर्ता को Entity का साइज़ बदलने का न्योता देते हैं. ResizableComponent बनाते समय, कम से कम या ज़्यादा से ज़्यादा साइज़ (मीटर में) तय किया जा सकता है. आपके पास साइज़ बदलते समय, आसपेक्ट रेशियो (लंबाई-चौड़ाई का अनुपात) तय करने का विकल्प भी होता है. इससे चौड़ाई और लंबाई, एक-दूसरे के हिसाब से बदलती हैं.

ResizableComponent बनाते समय, ऐसा ResizableComponent तय करें जो अपडेट इवेंट को हैंडल करता हो.resizeEventListener आपके पास अलग-अलग ResizeState इवेंट के लिए जवाब देने का विकल्प होता है. जैसे, RESIZE_STATE_ONGOING या RESIZE_STATE_END.

यहां SurfaceEntity पर, तय किए गए आसपेक्ट रेशियो (लंबाई-चौड़ाई का अनुपात) के साथ ResizableComponent का इस्तेमाल करने का एक उदाहरण दिया गया है:

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 बनाते समय, एक ऐसा लिसनर तय करें जो इनपुट इवेंट को स्वीकार करे. जब उपयोगकर्ता कोई इनपुट कार्रवाई करता है, तो लिसनर को 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.RIGHT) {
            entity.setScale(1.5f)
        } else if (it.pointerType == InputEvent.Pointer.LEFT) {
            entity.setScale(0.5f)
        }
    }
}
entity.addComponent(interactableComponent)