Table of Contents

Occlusion mit dem Mega plugin implementieren

Occlusion ist eine Schlüsseltechnologie, um die immersive Integration von virtual und real content in AR zu verbessern. Dieser Artikel führt Sie durch die Implementierung von occlusion Effekten in der xr-frame environment mit EasyAR cloud localization und annotations.

Bevor Sie beginnen

Wie occlusion implementiert wird

  • Offline modeling: Verwenden Sie den Unity editor, um im Block coordinate system 1:1 passende geometry für reale Entitäten wie Wände, Säulen und große Anlagen zu erstellen; oder erstellen Sie ein optimized model durch cropping und face reduction des Block dense model.

  • Runtime alignment: Zur xr-frame runtime wird das Block coordinate system durch cloud localization mit dem real space ausgerichtet und die entsprechende geometry geladen.

  • Material replacement: Weisen Sie diesen geometries spezielle occlusion materials zu.

  • Visual effect: Wenn die GPU andere virtual objects rendert, werden pixels in verdeckten Bereichen automatisch verworfen, weil sie den depth test nicht bestehen. Dadurch folgen virtual objects der occlusion Logik des realen physical space.

Occlusion mit einfacher geometry anordnen

  1. Platzieren Sie box annotations präzise anhand des dense model und der panorama. Nach der Platzierung sieht die annotation wie eine "wall" oder "column" aus.

    Annotation as occlusion

  2. Ändern Sie den Namen der annotation, z. B. occlusion_wall, notieren Sie die ID und laden Sie die annotation hoch.

  3. Verwenden Sie im xr-frame Mini Program die integrierte geometry, um die als occlusion verwendete annotation zu laden.

    Im EMA-Ladecallback verwenden Sie scene.createElement(xrFrameSystem.XRMesh,{}), um simple geometry zu erstellen und das Material easyar-occlusion zuzuweisen.

    Anmerkung

    Laden, registration, deregistration und unloading des Materials easyar-occlusion werden von AR Session gesteuert.

```ts
handleEmaResult(ema: easyar.ema.v0_5.Ema) {
    let blockHolder: easyar.BlockHolder = session.blockHolder;
    ema.blocks.forEach(emaBlock => {
        const blockInfo: easyar.BlockInfo = {
            id: emaBlock.id
        };
        // 若 Block 节点不存在,创建 Block 节点
        blockHolder.holdBlock(blockInfo, easyarPlugin.toXRFrame(emaBlock.transform));
    });
    ema.annotations.forEach(annotation => {
        if (annotation.type != mega.EmaV05AnnotationType.Node) {
            return;
        }
        const nodeAnnotation = annotation as easyar.ema.v0_5.Node;
        const xrNode: xrfs.XRNode = easyarPlugin.createXRNodeFromNodeAnnotation(nodeAnnotation, blockHolder);
        const emaName: string = nodeAnnotation.name;
        const geometryStr: string = nodeAnnotation.geometry === "cube" ? "cube" : "sphere";
        const assetInfo = AnnotationMetaData[nodeAnnotation.id as keyof typeof AnnotationMetaData];
        let model: xrfs.Element;

        if (assetInfo) {
            // GLTF部分
        } else {
            model = scene.createElement(
                xrFrameSystem.XRMesh,
                {
                    // 使用插件注册好的遮挡材质
                    material: "easyar-occlusion",
                    // 使用 xr-frame 内置几何体,此处也可以直接使用 "cube"
                    geometry: geometryStr,
                    name: emaName,
                    "receive-shadow": "false",
                    "cast-shadow": "false"
                    // 注意不要修改 Scale 
                }
            );
            xrNode.addChild(model);
        }
    })
}
```
<video src="https://doc-asset.easyar.com/develop/wechat/mega/media/occlusion03.mp4" style="width:480px; max-width:100%; height:auto;" muted playsinline controls></video>

> Mit occlusion kann dieser Panda hinter der Wand tanzen.

Occlusion mit complex geometry anordnen

Dies gilt für Szenarien mit hochpräziser Occlusion, etwa unregelmäßige Geräte oder Gebäude. Sie können die Maskendatei aus Mapping-Ergebnissen verwenden oder das dichte Block-Modell über Mega Studio in Unity exportieren und es dann zuschneiden und reduzieren, um ein weißes Occlusion-Modell zu erhalten.

Maskendatei aus Mapping-Ergebnissen verwenden

Laden Sie die glb-Maskendatei aus dem Mapping-Ergebnis über Mask file download in der Cloud-Localization-Datenbank herunter und schneiden Sie sie zu. Das zugeschnittene Modell muss beim Laden in xr-frame nicht um die Y-Achse gedreht werden.

Anmerkung

Dieser Weg gilt nur für Mapping-Ergebnisse ab Version 9.6.

  1. Nachdem der Block zur Cloud-Localization-Datenbank hinzugefügt wurde, notieren Sie die Block ID und klicken Sie in der Spalte Action auf Mask file download.

    Download-Einstieg für Maskendatei

  2. Wählen Sie im Popup Low precision und klicken Sie auf Download, um die glb-Maskendatei herunterzuladen.

    Maskendatei herunterladen

  3. Öffnen Sie das heruntergeladene Modell in einer Digital-Content-Software, z. B. Blender.

    Maskendatei vor dem Zuschnitt

    Schneiden Sie das Modell zu, behalten Sie nur den benötigten Occlusion-Bereich und speichern Sie es als glb. Position, Rotation, Skalierung und Koordinatensystem bleiben unverändert.

    Enthält die Maskendatei eines Block mehrere GLB-Dateien, kannst du sie in einer Software zur Erstellung digitaler Inhalte zusammenführen oder einzeln zuschneiden und exportieren. Hänge sie zur Laufzeit alle an denselben Block-Knoten.

    Maskendatei nach dem Zuschnitt

  4. Bereiten Sie die zugeschnittene glb-Datei vor. Sie können die Datei auf einen HTTPS-hosting server hochladen, der für das Mini Program erreichbar ist, und die URL erhalten, oder die Datei im Verzeichnis miniprogram/assets/ des Mini-Program-Projekts ablegen und direkt einen relativen Pfad verwenden. Wenn Sie einen hosting server verwenden, konfigurieren Sie die entsprechende zulässige Download-Domain im Mini-Program-Backend und fügen Sie die Domain der Mini-Program-Whitelist hinzu.

  5. Trage die Modelladresse in der Ressourcen-Konfiguration der Komponente unter sampleAssets.occlusionMesh.src ein. Verwende für Modelle in assets/ einen relativen Pfad. Für eine einzelne GLB-Datei genügt ein Eintrag; bei mehreren Teilen füge für jeden zu ladenden Teil einen Eintrag mit eigener assetId und passendem src hinzu. Beispiel:

    const occlusionMeshAssets = [
        // Eine GLB-Datei
        {
            assetId: "occlusionMesh00",
            type: "gltf",
            src: "assets/Low_Poly_occlusion.glb",
            options: {}
        },
        // Mehrere GLB-Dateien
        {
            assetId: "occlusionMesh01",
            type: "gltf",
            src: "assets/Low_Poly_occlusion_part1.glb",
            options: {}
        },
        {
            assetId: "occlusionMesh02",
            type: "gltf",
            src: "assets/Low_Poly_occlusion_part2.glb",
            options: {}
        }
    ];
    

    Verwende den tatsächlichen Dateinamen des heruntergeladenen oder zugeschnittenen Modells. src kann auch eine HTTPS-URL des Hosting-Servers sein, etwa https://your-domain.example/occlusion.glb.

    Die Komponente sollte model loading, mounting, Zuweisung des occlusion material und resource release implementieren. Mounten Sie das Modell unter dem erfolgreich lokalisierten Block-Knoten und behalten Sie die ursprünglichen position, rotation und scale des Modells bei.

  6. Lade das GLTF-Modell für die Verdeckung im xr-frame-Mini-Programm.

    Sobald die Modelle geladen sind und die Lokalisierung mindestens einmal erfolgreich war, erstelle einen gemeinsamen XRNode unter dem ersten Block-Knoten. Erstelle für jeden geladenen Teil ein XRGLTF und ersetze dessen Mesh-Material durch easyar-occlusion aus dem Mega-Plugin. Die folgende vollständige Methode verbindet Modell-Anbindung und Materialaustausch und kann showOcclusionMesh() im Beispiel ersetzen:

    showOcclusionMesh() {
        if (!scene) { console.error("Empty scene"); return; }
        const blockHolder = session?.blockHolder;
        if (!blockHolder) { console.warn("Empty block holder. Session not initialized."); return; }
        if (occlusionMeshNode) { return; }
        const root = blockHolder.blocks[0]?.el;
        if (!root) { console.warn("Empty block: localization must succeed at least once before showing the occlusion mesh"); return; }
        const loadedMeshes = occlusionMeshAssets.filter(meshAsset =>
            scene.assets.getAsset('gltf', meshAsset.assetId));
        if (loadedMeshes.length === 0) {
            console.warn("Occlusion mesh asset is not loaded");
            return;
        }
        const occlusionMaterial = scene.assets.getAsset("material", "easyar-occlusion");
        if (!occlusionMaterial) {
            console.warn("Occlusion material is not loaded");
            return;
        }
        const node = scene.createElement(xrFrameSystem.XRNode);
        root.addChild(node);
        for (const meshAsset of loadedMeshes) {
            const occlusionMesh = scene.createElement(xrFrameSystem.XRGLTF, {
                model: meshAsset.assetId
            });
            node.addChild(occlusionMesh);
            // Knoten anhängen und Transform einstellen, bevor das Verdeckungsmaterial ersetzt wird.
            // Die Maskendatei des Kartierungsergebnisses behält ihre ursprünglichen Koordinaten; eine Drehung um die Y-Achse ist nicht nötig.
            occlusionMesh.getComponent(xrFrameSystem.GLTF).meshes.forEach((mesh: any) => {
                mesh.setData({ neverCull: true, material: occlusionMaterial });
            });
        }
        node.getComponent(xrFrameSystem.Transform).visible = this.data.occlusionMeshVisible;
        occlusionMeshNode = node;
    },
    

    Alle Teile nutzen den gemeinsamen übergeordneten Knoten occlusionMeshNode. Mit dessen Transform.visible kannst du sie gemeinsam ein- oder ausblenden, ohne ihre Positionen einzeln festzulegen.

    Anmerkung

    AR Session steuert das Laden, Registrieren, Abmelden und Entladen von easyar-occlusion. Rufe das Material nach dem Start der Session ab und verwende es dann.

  7. Starte das Mini-Programm am realen Standort des entsprechenden Block. Warte, bis die Ressourcen geladen sind und die Lokalisierung erfolgreich war, aktiviere Maskendatei und prüfe, ob die verbliebenen Modellteile virtuelle Objekte korrekt verdecken.

Aus Unity exportiertes dichtes Modell verwenden

  1. Klicken Sie in der Unity scene auf den node Mega Block und notieren Sie die BlockID im Inspector panel.

    Record BlockID

  2. Wählen Sie in Block von Mega Studio export.

    Select export

  3. Ändern Sie die export options und exportieren Sie.

    Export options

    In der Abbildung ist 1 der LOD level. Je niedriger der level, desto einfacher das model und desto geringer die Anzahl der faces. Wenn höchste precision benötigt wird, wählen Sie 2; wenn geringere precision zur Verringerung des face count akzeptabel ist, wählen Sie 1 oder 0.

    In der Abbildung ist 2 die texture export option. Da nur die white model als occlusion benötigt wird, sind textures nicht erforderlich.

  4. Schneiden und reduzieren Sie das exportierte model in digital content creation software, z. B. Blender, und speichern Sie es als Glb.

    Tipp

    Im Beispiel wird Blender Decimate Modifier verwendet.

    Before cropping

    Nach cropping und reduction:

    After cropping

  5. Legen Sie die für occlusion verwendete Glb-Datei im Verzeichnis miniprogram/assets/ des Mini-Program-Projekts ab und verwenden Sie einen relativen Pfad, oder stellen Sie sie auf einem zugänglichen HTTPS-Dateiserver bereit und verwenden Sie dessen URL. Wenn Sie eine Server-URL verwenden, konfigurieren Sie die entsprechende zulässige Download-Domain im Mini-Program-Backend und fügen Sie die Domain der Mini-Program-Whitelist hinzu.

  6. Laden Sie das als occlusion verwendete GLTF im xr-frame Mini Program.

    Zuerst das für occlusion verwendete GLTF model laden, dann mit scene.createElement(xrFrameSystem.XRGLTF,options) das GLTF model erstellen.

    Verwenden Sie assets.getAsset("material", "easyar-occlusion"), um das material object abzurufen.

    Verwenden Sie model.getComponent(xrFrameSystem.GLTF).meshes.forEach((m: any) => {m.setData({ neverCull: true, material: occlusionMaterial });}, um das material des GLTF model zu ändern.

    Anmerkung

    Laden, registration, deregistration und unloading des Materials easyar-occlusion werden von AR Session gesteuert.

```ts
const sampleAssets = {
    occlusion1: {
        assetId: "occlusion1",
        type: "gltf",
        src: "url/occlusion1.glb",
        options: {}
    }
}
async loadAsset() {
    if (!scene) {console.error("Empty scene"); return;}
    try {
        await scene.assets.loadAsset(sampleAssets.occlusion1);
    } catch (err) {
        console.error(`Failed to load assets: ${err.message}`);
    }
},
addOcclusion() {
    model = scene.createElement(
        xrFrameSystem.XRGLTF,
        {
            "model": assetInfo.assetId,
            "anim-autoplay": assetInfo.animation ? assetInfo.animation : "",
            "scale": assetInfo.scale ? assetInfo.scale : "1 1 1",
            name: "tree"
        }
    );
    const blockID = "aaaa1234-bbbb-cccc-dddd-eeeeee123456" //Hier muss die Block ID eingetragen werden
    if (!blockHolder.getBlockById(blockParent.id)) {
        // Wenn kein Block-Knoten vorhanden ist, erstellen Sie einen
        blockHolder.holdBlock({
            id: blockID
        })
    }
    // Block-Knoten in der xr-frame-Szene abrufen
    let blockElement = blockHolder.getBlockById(blockParent.id).el;
    // Das zugeschnittene Occlusion-Modell als untergeordneten Knoten unter dem Block-Knoten einhängen
    blockElement.addChild(model);
    /**
     * Aufgrund des unterschiedlichen Verhaltens von GLTF-Loadern muss das Modell manchmal so ausgerichtet werden, dass seine Orientierung in xr-frame vollständig mit dem Rendering-Ergebnis in Unity übereinstimmt
    * Manchmal muss das geladene Modell lokal um 180 Grad um die Y-Achse gedreht werden
    */
    let modelTransform = model.getComponent(xrFrameSystem.Transform);
    let currentRotation = modelTransform.quaternion.clone();
    let targetRotation = currentRotation.multiply(new xrFrameSystem.Quaternion().setValue(0, 1, 0, 0));
    modelTransform.quaternion.set(targetRotation);
    //Hinweis: Das Material muss nach dem Ändern von Transform geändert werden
    if (assetInfo.assetId == 'occlusion1') {
        //Occlusion-Material abrufen, das vom Mega-Plugin bereitgestellt wird
        let occlusionMaterial = scene.assets.getAsset("material", "easyar-occlusion");
        //Occlusion-Material ändern
        model.getComponent(xrFrameSystem.GLTF).meshes.forEach((m: any) => {
            m.setData({ neverCull: true, material: occlusionMaterial });
        });
    }
}
```
> [!NOTE]
> Die Verwendung des Mega Block dense model nach cropping als occlusion erfordert hier keine annotation synchronization der spatial position. Das liegt daran, dass in digital content creation software wie Blender das model reduziert und zugeschnitten werden kann, ohne die coordinate system definition zu ändern.
>
> Wenn Sie ein selbst erstelltes GLTF model als occlusion präzise platzieren müssen, siehe [So platzieren Sie ein mit dem Raum ausgerichtetes occlusion model](./sample.md#wechat-mega-sample-precise-occulusion-model).

Den finalen Effekt auf einem realen Gerät sehen Sie im Video am Anfang dieses Artikels.

Erwarteter occlusion Effekt

Der occlusion Effekt in einem xr-frame Mini Program wird hauptsächlich von folgenden Faktoren beeinflusst:

  • Genauigkeit des localization tracking itself
  • Genauigkeit der model Platzierung
  • Genauigkeit des model selbst, wenn es keine simple geometry ist

Eine Fehlanpassung von mehreren Zentimetern während localization drift ist normal.

Zu viele faces im occlusion model können leicht performance beeinträchtigen. Es wird empfohlen, es nur in notwendigen Bereichen zu verwenden und möglichst simple geometry als occlusion einzusetzen.

Nächste Schritte

Verwandte Themen