Usar el Mega plugin para implementar occlusion
Occlusion es una tecnología clave para mejorar la integración inmersiva de virtual y real content en AR. Este artículo le guía para implementar efectos de occlusion en el environment xr-frame mediante EasyAR cloud localization y annotations.
Antes de empezar
- Poder usar Mega Studio en Unity.
- Poder crear y subir annotations con el Unity editor.
- Poder crear content alineado con el real world.
Cómo se implementa occlusion
Offline modeling: use el Unity editor para crear geometry con correspondencia 1:1 en el Block coordinate system para entidades del mundo real como walls, columns y large equipment; o bien obtenga un optimized model mediante cropping y face reduction del Block dense model.
Runtime alignment: en runtime de xr-frame, alinee el Block coordinate system con el real space mediante cloud localization y cargue la geometry correspondiente.
Material replacement: asigne occlusion materials especiales a estas geometries.
Visual effect: cuando la GPU renderiza otros virtual objects, los pixels de las partes ocluidas se descartan automáticamente al fallar el depth test, haciendo que los virtual objects sigan la lógica de occlusion del physical space real.
Cómo disponer occlusion con simple geometry
Coloque box annotations con precisión comparándolas con el dense model y el panorama. Tras la colocación, la annotation parece una "wall" o un "column".

Modifique el nombre de la annotation, por ejemplo
occlusion_wall, registre el ID y suba la annotation.En el xr-frame Mini Program, use su built-in geometry para cargar la annotation usada como occlusion.
En el callback de carga de EMA, use
scene.createElement(xrFrameSystem.XRMesh,{})para crear simple geometry y asignar el materialeasyar-occlusion.Nota
La carga, registration, deregistration y unloading del material
easyar-occlusionestán 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>
> Con occlusion, este panda puede bailar detrás de la wall.
Cómo disponer occlusion con complex geometry
Esto se aplica a escenarios que requieren oclusión de alta precisión, como equipos de forma irregular o edificios irregulares. Puede usar el archivo de máscara de los resultados de mapeo, o exportar el modelo denso del Block mediante Mega Studio en Unity, recortarlo y reducirlo para obtener un modelo blanco de oclusión.
Usar el archivo de máscara de los resultados de mapeo
Descargue el archivo de máscara glb del resultado de mapeo mediante Mask file download en la base de datos de localización en la nube y recórtelo. El modelo recortado no necesita rotarse alrededor del eje Y al cargarse en xr-frame.
Nota
Este método solo se aplica a resultados de mapeo de la versión 9.6 o posterior.
Después de agregar el Block a la base de datos, registre el Block ID correspondiente y haga clic en Mask file download en la columna Action.

En la ventana emergente, seleccione Low precision y haga clic en Download para descargar el archivo
glb.
Abra el modelo descargado en software de creación digital, como Blender.

Recorte el modelo, conserve solo la parte necesaria para oclusión y guárdelo como
glb. Mantenga posición, rotación, escala y sistema de coordenadas originales.Si la máscara de un Block contiene varios archivos GLB, puedes combinarlos en un programa de creación de contenido digital o recortarlos y exportarlos por separado. En tiempo de ejecución, agrégalos todos al mismo nodo Block.

Prepare el archivo
glbrecortado. Puede subir el archivo a un servidor de hosting HTTPS accesible por el Mini Program y obtener la URL, o poner el archivo en el directoriominiprogram/assets/del proyecto Mini Program y usar directamente una ruta relativa. Al usar un servidor de hosting, configure el dominio de descarga legal correspondiente en el backend del Mini Program y añada el dominio a la whitelist del Mini Program.Indica la dirección del modelo en
sampleAssets.occlusionMesh.src, dentro de la configuración de recursos del componente. Usa una ruta relativa para los modelos enassets/. Basta una entrada para un solo GLB; si hay varias partes, agrega una entrada por cada una, con unassetIdúnico y susrc. Por ejemplo:const occlusionMeshAssets = [ // Un archivo GLB { assetId: "occlusionMesh00", type: "gltf", src: "assets/Low_Poly_occlusion.glb", options: {} }, // Varios archivos GLB { assetId: "occlusionMesh01", type: "gltf", src: "assets/Low_Poly_occlusion_part1.glb", options: {} }, { assetId: "occlusionMesh02", type: "gltf", src: "assets/Low_Poly_occlusion_part2.glb", options: {} } ];Usa el nombre real del archivo descargado o recortado.
srctambién puede contener una URL HTTPS del servidor, comohttps://your-domain.example/occlusion.glb.El componente debe implementar la carga del modelo, el mounting, la asignación del material de occlusion y la liberación de recursos. Monte el modelo bajo el nodo Block localizado correctamente y mantenga la position, rotation y scale originales del modelo.
Carga el GLTF de oclusión en el Mini Program xr-frame.
Cuando los modelos estén cargados y la localización haya tenido éxito al menos una vez, crea un
XRNodecompartido bajo el primer nodo Block. Crea unXRGLTFpor cada parte cargada y sustituye el material de su malla poreasyar-occlusiondel complemento Mega. El método completo siguiente combina la asociación del modelo y la sustitución del material; puede sustituirshowOcclusionMesh()en el ejemplo: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); // Asocia el nodo y configura Transform antes de sustituir el material de oclusión. // La máscara del resultado del mapeo conserva sus coordenadas originales; no requiere rotación sobre el eje Y. occlusionMesh.getComponent(xrFrameSystem.GLTF).meshes.forEach((mesh: any) => { mesh.setData({ neverCull: true, material: occlusionMaterial }); }); } node.getComponent(xrFrameSystem.Transform).visible = this.data.occlusionMeshVisible; occlusionMeshNode = node; },Todas las partes comparten el nodo principal
occlusionMeshNode. Usa suTransform.visiblepara mostrarlas u ocultarlas juntas sin establecer posiciones espaciales independientes.Nota
AR Session controla la carga, el registro, la cancelación del registro y la descarga de
easyar-occlusion. Obtén y usa el material después de iniciar Session.Ejecuta el Mini Program en el entorno real del Block correspondiente. Espera a que se carguen los recursos y se complete la localización, activa Archivo de máscara y comprueba que las partes conservadas del modelo oculten correctamente los objetos virtuales.
Usar el modelo denso exportado desde Unity
En la Unity scene, haga clic en el nodo Mega Block y registre el BlockID en el panel Inspector.

En Block de Mega Studio, seleccione export.

Modifique las export options y exporte.

En la figura, 1 es el LOD level. Cuanto menor sea el level, más simple será el model y menor el número de faces. Si necesita la precision más alta, seleccione 2; si puede aceptar menor precision para reducir el face count, seleccione 1 o 0.
En la figura, 2 es la texture export option. Como solo necesitamos el white model como occlusion, no se necesitan textures.
Recorte y reduzca el model exportado en digital content creation software, como Blender, y guárdelo como
Glb.Consejo
El ejemplo usa el Decimate Modifier de Blender.

Después de cropping y reduction:

Coloque el archivo
Glbusado para occlusion en el directoriominiprogram/assets/del proyecto Mini Program y use una ruta relativa, o móntelo en un servidor de archivos HTTPS accesible y use su URL. Al usar una URL de servidor, configure el dominio de descarga legal correspondiente en el backend del Mini Program y añada el dominio a la whitelist del Mini Program.Cargue el GLTF usado como occlusion en el xr-frame Mini Program.
Primero cargue el GLTF model usado para occlusion y luego use
scene.createElement(xrFrameSystem.XRGLTF,options)para crear el GLTF model.Use
assets.getAsset("material", "easyar-occlusion")para obtener el material object.Use
model.getComponent(xrFrameSystem.GLTF).meshes.forEach((m: any) => {m.setData({ neverCull: true, material: occlusionMaterial });}para modificar el material del GLTF model.Nota
La carga, registration, deregistration y unloading del material
easyar-occlusionestán 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" //Aquí debe rellenarse el Block ID
if (!blockHolder.getBlockById(blockParent.id)) {
// Si no existe un nodo Block, cree uno
blockHolder.holdBlock({
id: blockID
})
}
// Obtener el nodo Block en la escena xr-frame
let blockElement = blockHolder.getBlockById(blockParent.id).el;
// Montar el modelo de oclusión recortado bajo el nodo Block como nodo hijo
blockElement.addChild(model);
/**
* Debido a diferencias en el comportamiento de los cargadores GLTF, para que la orientación del modelo en xr-frame coincida exactamente con el resultado renderizado en Unity
* A veces hay que rotar el modelo cargado 180 grados alrededor del eje Y en el lugar
*/
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);
//Nota: el material debe modificarse después de modificar Transform
if (assetInfo.assetId == 'occlusion1') {
//Obtener el material de oclusión proporcionado por el plugin Mega
let occlusionMaterial = scene.assets.getAsset("material", "easyar-occlusion");
//Modificar el material de oclusión
model.getComponent(xrFrameSystem.GLTF).meshes.forEach((m: any) => {
m.setData({ neverCull: true, material: occlusionMaterial });
});
}
}
```
> [!NOTE]
> Aquí, usar el Mega Block dense model tras cropping como occlusion no requiere annotation synchronization para spatial position. Esto se debe a que en digital content creation software, como Blender, el model puede reducirse y recortarse sin cambiar la coordinate system definition.
>
> Si necesita colocar con precisión su propio GLTF model como occlusion, consulte [Cómo colocar un occlusion model alineado con el espacio](./sample.md#wechat-mega-sample-precise-occulusion-model).
El efecto final en dispositivo real se muestra en el vídeo al principio del artículo.
Efecto esperado de occlusion
El efecto de occlusion en un xr-frame Mini Program se ve afectado principalmente por lo siguiente:
- La precisión de localization tracking itself
- La precisión de la colocación del model
- La precisión del propio model, si no es simple geometry
Es normal que aparezcan varios centímetros de desalineación durante localization drift.
Demasiadas faces en el occlusion model pueden afectar fácilmente al performance. Se recomienda usarlo solo en áreas necesarias y usar simple geometry como occlusion siempre que sea posible.