Реализация окклюзии с помощью плагина Mega
Окклюзия (Occlusion) — ключевая технология для повышения погружения в AR при смешивании виртуального и реального. В этой статье объясняется, как реализовать эффект окклюзии в среде xr-frame с использованием облачного позиционирования и аннотаций EasyAR.
Начало работы
- Умение использовать Mega Studio в Unity.
- Умение создавать и загружать аннотации в редакторе Unity.
- Умение создавать контент, выровненный с реальным миром.
Способы реализации окклюзии
Офлайн-моделирование: Создание в редакторе Unity геометрических объектов в системе координат Block, точно соответствующих реальным объектам (стены, колонны, оборудование); или оптимизация модели путем обрезки и уменьшения полигонов плотной модели Block.
Выравнивание во время выполнения: Во время выполнения в xr-frame система координат Block выравнивается с реальным пространством через облачное позиционирование, и загружаются соответствующие геометрические объекты.
Замена материалов: Назначение этим объектам специального материала окклюзии.
Визуальный эффект: При рендеринге виртуальных объектов GPU автоматически отбрасывает пиксели, закрытые реальными объектами (из-за непрохождения теста глубины), что заставляет виртуальные объекты подчиняться логике окклюзии реального пространства.
Как разместить простую геометрическую окклюзию
Точное размещение кубических аннотаций по плотной модели и панорамам. После размещения аннотация должна выглядеть как "стена" или "колонна".

Измените имя аннотации (например,
occlusion_wall), запишите ID и загрузите аннотацию.В мини-программе 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) окклюзии.
В сцене Unity щелкните узел Mega Block, в панели Inspector запишите BlockID.

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

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

Позиция 1: Уровень LOD. Чем ниже уровень, тем проще модель и меньше полигонов. Для максимальной точности выберите 2, для уменьшения полигонов с потерей точности — 1 или 0.
Позиция 2: Опция экспорта текстур. Так как нам нужна только белая модель для окклюзии, текстуры не требуются.
Обрежьте экспортированную модель в программе для создания контента (например, Blender), уменьшите количество полигонов и сохраните как
Glb.Совет
В примере используется Decimate Modifier в Blender.

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

Разместите файл
Glbдля окклюзии на файловом сервере, получив URL для загрузки.В мини-программе 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 эффект окклюзии в основном зависит от:
- Точности самого трекинга позиционирования
- Точности размещения модели
- Точности самой модели (если это не простая геометрия)
Небольшие смещения (несколько сантиметров) при дрейфе позиционирования являются нормальными.
Модели окклюзии с большим количеством полигонов могут повлиять на производительность. Рекомендуется использовать их только в необходимых областях и по возможности применять простые геометрические фигуры.