Table of Contents

Usar o Mega plugin para implementar occlusion

Occlusion é uma tecnologia chave para melhorar a integração imersiva de virtual e real content em AR. Este artigo orienta como implementar efeitos de occlusion no environment xr-frame por meio de EasyAR cloud localization e annotations.

Antes de começar

Como occlusion é implementada

  • Offline modeling: use o Unity editor para criar geometry com correspondência 1:1 no Block coordinate system para entidades do mundo real, como walls, columns e large equipment; ou obtenha um optimized model por cropping e face reduction do Block dense model.

  • Runtime alignment: no runtime xr-frame, alinhe o Block coordinate system com o real space por cloud localization e carregue a geometry correspondente.

  • Material replacement: atribua occlusion materials especiais a essas geometries.

  • Visual effect: quando a GPU renderiza outros virtual objects, os pixels nas partes ocluídas são automaticamente descartados por falharem no depth test, fazendo com que virtual objects sigam a lógica de occlusion do physical space real.

Como posicionar occlusion com simple geometry

  1. Posicione box annotations com precisão comparando com o dense model e o panorama. Após o posicionamento, a annotation parece uma "wall" ou "column".

    Annotation as occlusion

  2. Modifique o nome da annotation, como occlusion_wall, registre o ID e faça upload da annotation.

  3. No xr-frame Mini Program, use sua built-in geometry para carregar a annotation usada como occlusion.

    No callback de carregamento da EMA, use scene.createElement(xrFrameSystem.XRMesh,{}) para criar simple geometry e atribuir o material easyar-occlusion.

    Nota

    O loading, registration, deregistration e unloading do material easyar-occlusion são controlados por AR Session.

```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>

> Com occlusion, este panda pode dançar atrás da wall.

Como posicionar occlusion com complex geometry

Aplica-se a cenários que exigem oclusão de alta precisão, como equipamentos de formato irregular e edifícios irregulares. Você pode usar o arquivo de máscara dos resultados de mapeamento, ou exportar o modelo denso do Block pelo Mega Studio no Unity, depois recortá-lo e reduzi-lo para obter um modelo branco de oclusão.

Usar o arquivo de máscara dos resultados de mapeamento

Baixe o arquivo de máscara glb do resultado de mapeamento pela entrada Mask file download no banco de dados de localização em nuvem e recorte-o. O modelo recortado não precisa ser rotacionado em torno do eixo Y ao ser carregado no xr-frame.

Nota

Este método se aplica apenas a resultados de mapping da versão 9.6 ou posterior.

  1. Depois de adicionar o Block ao banco de dados de localização em nuvem, registre o Block ID correspondente e clique em Mask file download na coluna Action.

    Entrada de download do arquivo de máscara

  2. Na janela pop-up, selecione Low precision e clique em Download para baixar o arquivo de máscara glb.

    Baixar arquivo de máscara

  3. Abra o modelo baixado em um software de criação de conteúdo digital, como Blender.

    Arquivo de máscara antes do recorte

    Recorte o modelo, mantendo apenas a parte necessária para oclusão, e salve como glb. Mantenha posição, rotação, escala e sistema de coordenadas originais.

    Arquivo de máscara depois do recorte

  4. Prepare o arquivo glb recortado. Você pode enviar o arquivo para um hosting server HTTPS acessível pelo Mini Program e obter a URL, ou colocar o arquivo no diretório miniprogram/assets/ do projeto Mini Program e usar diretamente um caminho relativo. Ao usar um hosting server, configure o domínio legal de download correspondente no backend do Mini Program e adicione o domínio à whitelist do Mini Program.

  5. Preencha o endereço do modelo na configuração de recurso do componente sampleAssets.occlusionMesh.src. Se o modelo for colocado no diretório assets/, use um caminho relativo, por exemplo:

    src: "assets/occlusion_mesh_sd.glb",
    

    Também é possível preencher uma URL HTTPS do hosting server, como https://your-domain.example/occlusion.glb.

    O componente deve implementar o carregamento do modelo, mounting, atribuição do material de occlusion e liberação de recursos. Monte o modelo sob o nó Block localizado com sucesso e mantenha position, rotation e scale originais do modelo.

    Depois que o modelo for carregado e a localization tiver sucesso, crie um XRNode sob o primeiro nó Block e então monte o modelo XRGLTF:

    showOcclusionMesh() {
        if (!scene) { console.error("Empty scene"); return; }
        const blockHolder = session?.blockHolder;
        if (!blockHolder) { console.warn("Session not initialized"); return; }
        if (occlusionMeshNode) { return; }
        const root = blockHolder.blocks[0]?.el;
        if (!root) { console.warn("Localization must succeed before showing the occlusion mesh"); return; }
        if (!scene.assets.getAsset("gltf", sampleAssets.occlusionMesh.assetId)) {
            console.warn("Occlusion mesh asset is not loaded");
            return;
        }
        const node = scene.createElement(xrFrameSystem.XRNode);
        root.addChild(node);
        const model = scene.createElement(xrFrameSystem.XRGLTF, {
            model: sampleAssets.occlusionMesh.assetId
        });
        node.addChild(model);
        node.getComponent(xrFrameSystem.Transform).visible = this.data.occlusionMeshVisible;
        occlusionMeshNode = node;
    },
    

    Após o sucesso da localization, monte o modelo sob o nó Block. Não é necessário configurar manualmente a spatial position.

    Esse método exibe diretamente o white model original baixado e mantém a default position, rotation, scale e visible material do modelo. Para resource loading e node mounting, consulte Como carregar conteúdo 3D em uma AR scene no xr-frame runtime.

  6. Execute o Mini Program na cena real correspondente ao Block, exiba o arquivo de máscara após a localization e verifique o alinhamento e a oclusão dos objetos virtuais.

Usar o modelo denso exportado do Unity

  1. Na Unity scene, clique no node Mega Block e registre o BlockID no panel Inspector.

    Record BlockID

  2. Em Block do Mega Studio, selecione export.

    Select export

  3. Modifique as export options e exporte.

    Export options

    Na figura, 1 é o LOD level. Quanto menor o level, mais simples o model e menor o número de faces. Se precisar da precision mais alta, selecione 2; se puder aceitar menor precision para reduzir o face count, selecione 1 ou 0.

    Na figura, 2 é a texture export option. Como precisamos apenas do white model como occlusion, textures não são necessárias.

  4. Faça crop e reduce do model exportado em digital content creation software, como Blender, e salve como Glb.

    Dica

    O exemplo usa o Decimate Modifier do Blender.

    Before cropping

    Após cropping e reduction:

    After cropping

  5. Coloque o arquivo Glb usado para occlusion no diretório miniprogram/assets/ do projeto Mini Program e use um caminho relativo, ou monte-o em um servidor de arquivos HTTPS acessível e use sua URL. Ao usar uma URL de servidor, configure o domínio legal de download correspondente no backend do Mini Program e adicione o domínio à whitelist do Mini Program.

  6. Carregue o GLTF usado como occlusion no xr-frame Mini Program.

    Primeiro carregue o GLTF model usado para occlusion e depois use scene.createElement(xrFrameSystem.XRGLTF,options) para criar o GLTF model.

    Use assets.getAsset("material", "easyar-occlusion") para obter o material object.

    Use model.getComponent(xrFrameSystem.GLTF).meshes.forEach((m: any) => {m.setData({ neverCull: true, material: occlusionMaterial });} para modificar o material do GLTF model.

    Nota

    O loading, registration, deregistration e unloading do material easyar-occlusion são controlados por AR Session.

```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" //Preencha o Block ID aqui
    if (!blockHolder.getBlockById(blockParent.id)) {
        // Se não houver um nó Block existente, crie um
        blockHolder.holdBlock({
            id: blockID
        })
    }
    // Obter o nó Block na cena xr-frame
    let blockElement = blockHolder.getBlockById(blockParent.id).el;
    // Anexar o modelo de oclusão recortado sob o nó Block como seu nó filho
    blockElement.addChild(model);
    /**
     * Como os loaders GLTF se comportam de formas diferentes, para manter a orientação do modelo no xr-frame exatamente igual ao resultado renderizado no Unity
    * Às vezes é preciso girar o modelo carregado 180 graus em torno do eixo Y no próprio local
    */
    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);
    //Observação: o material deve ser alterado depois de modificar Transform
    if (assetInfo.assetId == 'occlusion1') {
        //Obter o material de oclusão fornecido pelo plugin Mega
        let occlusionMaterial = scene.assets.getAsset("material", "easyar-occlusion");
        //Modificar o material de oclusão
        model.getComponent(xrFrameSystem.GLTF).meshes.forEach((m: any) => {
            m.setData({ neverCull: true, material: occlusionMaterial });
        });
    }
}
```
> [!NOTE]
> Aqui, usar o Mega Block dense model após cropping como occlusion não exige annotation synchronization para spatial position. Isso ocorre porque, em digital content creation software como Blender, é possível reduzir e recortar o model sem alterar a coordinate system definition.
>
> Se precisar posicionar com precisão seu próprio GLTF model como occlusion, consulte [Como posicionar um occlusion model alinhado com o espaço](./sample.md#wechat-mega-sample-precise-occulusion-model).

O efeito final em dispositivo real é mostrado no vídeo no início deste artigo.

Efeito esperado de occlusion

O efeito de occlusion em um xr-frame Mini Program é afetado principalmente pelos seguintes pontos:

  • A accuracy do localization tracking em si
  • A accuracy do posicionamento do model
  • A accuracy do próprio model, se não for simple geometry

É normal ocorrer desalinhamento de vários centímetros durante localization drift.

Muitas faces no occlusion model podem facilmente afetar performance. Recomenda-se usá-lo apenas em áreas necessárias e usar simple geometry como occlusion sempre que possível.

Próximas etapas

Tópicos relacionados