Table of Contents

Реализация окклюзии с помощью плагина Mega

Окклюзия (Occlusion) — ключевая технология для повышения погружения в AR при смешивании виртуального и реального. В этой статье объясняется, как реализовать эффект окклюзии в среде xr-frame с использованием облачного позиционирования и аннотаций EasyAR.

Начало работы

Способы реализации окклюзии

  • Офлайн-моделирование: Создание в редакторе Unity геометрических объектов в системе координат Block, точно соответствующих реальным объектам (стены, колонны, оборудование); или оптимизация модели путем обрезки и уменьшения полигонов плотной модели Block.

  • Выравнивание во время выполнения: Во время выполнения в xr-frame система координат Block выравнивается с реальным пространством через облачное позиционирование, и загружаются соответствующие геометрические объекты.

  • Замена материалов: Назначение этим объектам специального материала окклюзии.

  • Визуальный эффект: При рендеринге виртуальных объектов GPU автоматически отбрасывает пиксели, закрытые реальными объектами (из-за непрохождения теста глубины), что заставляет виртуальные объекты подчиняться логике окклюзии реального пространства.

Как разместить простую геометрическую окклюзию

  1. Точное размещение кубических аннотаций по плотной модели и панорамам. После размещения аннотация должна выглядеть как "стена" или "колонна".

    Аннотация как окклюзия

  2. Измените имя аннотации (например, occlusion_wall), запишите ID и загрузите аннотацию.

  3. В мини-программе xr-frame используйте встроенную геометрию для загрузки аннотации в качестве окклюзии.

    В колбэке загрузки EMA используйте scene.createElement(xrFrameSystem.XRMesh,{}) для создания простого геометрического объекта и назначьте ему материал easyar-occulusion.

    Примечание

    Загрузка, регистрация, отмена регистрации и выгрузка материала easyar-occulusion управляется AR Session.

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>

> С окклюзией эта панда может танцевать за стеной.

Как разместить сложную геометрическую окклюзию

Подходит для сцен, требующих высокой точности окклюзии: нестандартное оборудование, сложные здания и т.д.

Используйте обрезанную и упрощенную плотную модель Block для создания белой модели (white model) окклюзии.

  1. В сцене Unity щелкните узел Mega Block, в панели Inspector запишите BlockID.

    Запись BlockID

  2. В Block Mega Studio выберите экспорт.

    Выбор экспорта

  3. Измените параметры экспорта и экспортируйте.

    Параметры экспорта

    Позиция 1: Уровень LOD. Чем ниже уровень, тем проще модель и меньше полигонов. Для максимальной точности выберите 2, для уменьшения полигонов с потерей точности — 1 или 0.

    Позиция 2: Опция экспорта текстур. Так как нам нужна только белая модель для окклюзии, текстуры не требуются.

  4. Обрежьте экспортированную модель в программе для создания контента (например, Blender), уменьшите количество полигонов и сохраните как Glb.

    Совет

    В примере используется Decimate Modifier в Blender.

    До обрезки

    После обрезки и уменьшения полигонов:

    После обрезки

  5. Разместите файл Glb для окклюзии на файловом сервере, получив URL для загрузки.

  6. В мини-программе xr-frame загрузите GLTF-модель для окклюзии.

    Сначала загрузите GLTF-модель для окклюзии, затем создайте модель с помощью scene.createElement(xrFrameSystem.XRGLTF,options).

    Получите объект материала с помощью assets.getAsset("material", "easyar-occlusion").

    Измените материал модели GLTF с помощью model.getComponent(xrFrameSystem.GLTF).meshes.forEach((m: any) => {m.setData({ neverCull: true, material: occlusionMaterial });}.

    Примечание

    Загрузка, регистрация, отмена регистрации и выгрузка материала easyar-occulusion управляется AR Session.

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" //здесь следует указать Block ID
    if (!blockHolder.getBlockById(blockParent.id)) {
        // Если узел Block не существует, создаем его
        blockHolder.holdBlock({
            id: blockID
        })
    }
    // Получаем узел Block в сцене xr-frame
    let blockElement = blockHolder.getBlockById(blockParent.id).el;
    // Добавляем обрезанную модель окклюзии как дочерний элемент узла Block
    blockElement.addChild(model);
    /**
     * Из-за различий в поведении загрузчиков GLTF, для обеспечения полного соответствия ориентации модели в xr-frame 
    * с результатом рендеринга в Unity, иногда требуется повернуть загруженную модель на 180 градусов вокруг оси Y.
    */
    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);
    //ВАЖНО: Материал необходимо изменять ПОСЛЕ изменения Transform
    if (assetInfo.assetId == 'occlusion1') {
        // Получаем материал окклюзии из плагина mega
        let occlusionMaterial = scene.assets.getAsset("material", "easyar-occlusion");
        // Применяем материал окклюзии
        model.getComponent(xrFrameSystem.GLTF).meshes.forEach((m: any) => {
            m.setData({ neverCull: true, material: occlusionMaterial });
        });
    }
}
> [!NOTE]
> При использовании обрезанной плотной модели Mega Block для окклюзии **не требуется** синхронизация позиции через аннотацию, так как в программах (например, Blender) можно уменьшать полигоны и обрезать модель без изменения системы координат.
>
> Для точного размещения собственной GLTF-модели окклюзии см. [Как разместить точно выровненную модель окклюзии](./sample.md#wechat-mega-sample-precise-occulusion-model)

Финальный эффект на устройстве показан в видео в начале статьи.

Ожидаемый эффект окклюзии

На мини-программе xr-frame эффект окклюзии в основном зависит от:

  • Точности самого трекинга позиционирования
  • Точности размещения модели
  • Точности самой модели (если это не простая геометрия)

Небольшие смещения (несколько сантиметров) при дрейфе позиционирования являются нормальными.

Модели окклюзии с большим количеством полигонов могут повлиять на производительность. Рекомендуется использовать их только в необходимых областях и по возможности применять простые геометрические фигуры.

Следующие шаги

Связанные темы