xr-frame WeChat Mini Program에서 transparent video 재생
시작하기 전에
재생할 transparent video를 준비합니다. Transparent video를 file server에 upload하고 xr-frame에서 load하는 데 사용할 URL을 얻습니다.
Transparent video playback은 scene의 texture replacement에 의존하므로, transparent video를 재생할 위치를 사전에 annotation해야 합니다. Unity Editor를 사용해 annotation을 생성하고 upload할 수 있어야 합니다.
Transparent video란
Transparent video는 H.264/AVC, H.265/HEVC처럼 alpha channel을 native로 지원하지 않는 video encoding format에서 transparent background 효과를 구현하기 위한 기술적 방안입니다.
이 방안은 video image의 color information (RGB) 와 transparency information (Alpha) 를 분리하고, 특정 spatial layout에 따라 같은 frame image에 이어 붙여 black-and-white mask가 포함된 일반 video file을 생성합니다. Playback 측에서는 graphics rendering pipeline이 real time으로 sampling하고 두 부분을 합성하여 transparent background를 가진 dynamic image를 복원합니다.
Color area와 Alpha area의 결합 방식에 따라 주로 두 가지 format으로 나뉩니다.
Side-by-Side (SBS)
Side-by-Side는 RGB color frame과 Alpha mask frame을 horizontal direction으로 나란히 결합하는 format입니다. 일반적으로 왼쪽은 color area, 오른쪽은 해당 grayscale Alpha area로 약속합니다.
Top-by-Bottom (TBB)
Top-by-Bottom은 RGB color frame과 Alpha mask frame을 vertical direction으로 쌓아 결합하는 format입니다. 일반적으로 위쪽 절반은 color area, 아래쪽 절반은 해당 grayscale Alpha area로 약속합니다.
xr-frame Mini Program에서 annotation 위치에 transparent video 재생
먼저 video-texture type의 video resource를 load합니다.
async loadAsset() {
const videoTexture = {
assetId: "fireball",
type: "video-texture",
// 비디오 리소스 URL
src: "url/video-resource.mp4",
options: {
autoPlay: true,
loop: true,
}
};
try {
// video-texture 타입 리소스 로드
await scene.assets.loadAsset(videoTexture);
} catch (err) {
console.error(`Failed to load video texture: ${err.message}`);
}
}
EMA가 load된 callback에서 scene.createElement(xrFrameSystem.XRMesh,{})를 사용해 simple geometry를 만들고, easyar-video-tsbs material을 부여한 뒤 uniform을 u_baseColorMap:video-{$assetId}로 수정합니다.
참고
easyar-video-tsbs 및 easyar-video-ttbb material의 loading, registration, deregistration, unloading은 AR Session이 제어합니다.
handleEmaResult(ema: easyar.ema.v0_5.Ema) {
const 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 assetInfo = AnnotationMetaData[nodeAnnotation.id as keyof typeof AnnotationMetaData];
let model: xrfs.Element;
if (assetInfo) {
// GLTF 부분
} else {
// 내장 Mesh를 사용해 렌더링용 지오메트리 생성
model = scene.createElement(xrFrameSystem.XRMesh, {
geometry: "cube",
material: "easyar-video-tsbs",
uniforms: "u_baseColorMap:video-fireball",
});
xrNode.addChild(model);
}
});
}
참고
video-texture 사용 시 console에 wx.createVideoDecoder with type: 'wemedia' is deprecated warning이 나타나면 무시하십시오.
WeChat official team과 확인한 결과, 이 warning은 사용에 영향을 주지 않습니다.