Использование Mega plugin для реализации occlusion
Occlusion - ключевая технология для усиления immersive-интеграции virtual и real content в AR. Эта статья объясняет, как реализовать эффекты occlusion в environment xr-frame с помощью EasyAR cloud localization и annotations.
Перед началом
- Уметь использовать Mega Studio в Unity.
- Уметь создавать и upload annotations с помощью Unity editor.
- Уметь создавать content, выровненный с real world.
Как реализуется occlusion
Offline modeling: используйте Unity editor, чтобы в Block coordinate system создать geometry, соответствующую 1:1 реальным объектам, таким как стены, колонны и крупное оборудование; либо получите optimized model путем cropping и face reduction Block dense model.
Runtime alignment: во время runtime xr-frame выровняйте Block coordinate system с real space через cloud localization и загрузите соответствующую geometry.
Material replacement: назначьте этим geometry специальные occlusion materials.
Visual effect: когда GPU рендерит другие virtual objects, pixels в закрытых частях автоматически отбрасываются из-за неуспешного depth test, и virtual objects следуют логике occlusion реального physical space.
Как разместить occlusion с простой geometry
Точно разместите box annotations, сверяясь с dense model и panorama. После размещения annotation выглядит как "wall" или "column".

Измените имя annotation, например на
occlusion_wall, запишите ID и upload annotation.В xr-frame Mini Program используйте встроенную geometry, чтобы загрузить annotation, используемую как occlusion.
В callback загрузки EMA используйте
scene.createElement(xrFrameSystem.XRMesh,{}), чтобы создать simple geometry и назначить материалeasyar-occlusion.Примечание
Загрузка, registration, deregistration и unloading материала
easyar-occlusionуправляются 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>
> Благодаря occlusion эта панда может танцевать за стеной.
Как разместить occlusion со сложной geometry
Это подходит для сценариев с высокоточной occlusion, например для оборудования сложной формы и нерегулярных зданий. Можно использовать файл маски из результатов mapping или экспортировать dense model Block через Mega Studio в Unity, затем обрезать и упростить его для получения white model occlusion.
Использование файла маски из результатов mapping
Скачайте файл маски glb из результата mapping через Mask file download в cloud localization database и обрежьте его. Обрезанную модель не нужно поворачивать вокруг оси Y при загрузке в xr-frame.
Примечание
Способ применим только к результатам mapping версии 9.6 и выше.
После добавления Block в cloud localization database запишите соответствующий Block ID и нажмите Mask file download в столбце Action.

В popup выберите Low precision и нажмите Download, чтобы скачать файл маски
glb.
Откройте скачанную модель в ПО для цифрового контента, например Blender.

Обрежьте модель, оставив часть для occlusion, и сохраните как
glb. Не меняйте исходные position, rotation, scale и систему координат.
Подготовьте обрезанный файл
glb. Вы можете загрузить файл на HTTPS hosting server, доступный Mini Program, и получить URL, либо поместить файл в каталогminiprogram/assets/проекта Mini Program и напрямую использовать относительный путь. При использовании hosting server настройте соответствующий разрешенный домен загрузки в backend Mini Program и добавьте домен в whitelist Mini Program.Заполните адрес модели в конфигурации ресурса компонента
sampleAssets.occlusionMesh.src. Если модель помещена в каталогassets/, используйте относительный путь, например:src: "assets/occlusion_mesh_sd.glb",Также можно указать HTTPS URL с hosting server, например
https://your-domain.example/occlusion.glb.Компонент должен реализовать загрузку модели, mounting, назначение occlusion material и освобождение ресурсов. Смонтируйте модель под успешно локализованным узлом Block и сохраните исходные position, rotation и scale модели.
После загрузки модели и успешной localization создайте
XRNodeпод первым узлом Block, затем смонтируйте модель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; },После успешной localization смонтируйте модель под узлом Block. Ручная настройка spatial position не требуется.
Этот метод напрямую отображает загруженную исходную white model и сохраняет default position, rotation, scale и visible material модели. О resource loading и node mounting см. Как загрузить 3D content в AR scene во время xr-frame runtime.
Запустите Mini Program в реальной сцене этого Block, после localization покажите файл маски и проверьте совпадение с реальностью и occlusion виртуальных объектов.
Использование dense model, экспортированной из Unity
В Unity scene нажмите node Mega Block и запишите BlockID в панели Inspector.

В Block Mega Studio выберите export.

Измените export options и выполните export.

На рисунке 1 - это LOD level. Чем ниже level, тем проще model и тем меньше faces. Если нужна максимальная precision, выберите 2; если можно снизить precision ради уменьшения face count, выберите 1 или 0.
На рисунке 2 - это texture export option. Так как нам нужна только white model для occlusion, textures не нужны.
Выполните crop и reduce экспортированной model в digital content creation software, например Blender, и сохраните как
Glb.Совет
В примере используется Blender Decimate Modifier.

После cropping и reduction:

Поместите файл
Glb, используемый для occlusion, в каталогminiprogram/assets/проекта Mini Program и используйте относительный путь либо разместите его на доступном HTTPS-файловом сервере и используйте его URL. При использовании URL сервера настройте соответствующий разрешенный домен загрузки в backend Mini Program и добавьте домен в whitelist Mini Program.Загрузите GLTF, используемый как occlusion, в xr-frame Mini Program.
Сначала load GLTF model для occlusion, затем используйте
scene.createElement(xrFrameSystem.XRGLTF,options), чтобы создать GLTF model.Используйте
assets.getAsset("material", "easyar-occlusion"), чтобы получить material object.Используйте
model.getComponent(xrFrameSystem.GLTF).meshes.forEach((m: any) => {m.setData({ neverCull: true, material: occlusionMaterial });}, чтобы изменить material GLTF model.Примечание
Загрузка, registration, deregistration и unloading материала
easyar-occlusionуправляются 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" //Здесь нужно указать 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 dense model после cropping как occlusion не требует annotation synchronization для spatial position. Это связано с тем, что в digital content creation software, например Blender, можно выполнять reduction и cropping модели без изменения coordinate system definition.
>
> Если нужно точно разместить собственную GLTF model occlusion, см. [Как разместить occlusion model, выровненную с пространством](./sample.md#wechat-mega-sample-precise-occulusion-model).
Финальный эффект работы на реальном устройстве показан в видео в начале статьи.
Ожидаемый эффект occlusion
Эффект occlusion в xr-frame Mini Program в основном зависит от следующего:
- Точность localization tracking itself
- Точность размещения model
- Точность самой model, если это не simple geometry
Несовпадение на несколько сантиметров при localization drift является нормальным.
Слишком большое число faces у occlusion model может легко повлиять на performance. Рекомендуется использовать ее только в необходимых областях и по возможности использовать simple geometry как occlusion.