使用 MetaKit 插件
本文介绍如何在你的项目中集成 MetaKit 插件,体验虚拟人、Animoji、Sticker、灯光特效和背景特效功能模块。
前提条件
在集成 MetaKit 插件前,请确保开发环境满足以下要求:
- 已集成 4.3.x 版本的实时互动 SDK,并确保你已在 App 中实现了基本的实时音视频功能,请参考实现音视频互动。
注意
- 通过 CocoaPods 集成时,打开
Podfile,指定pod 'AgoraRtcEngine_Special_iOS', 'x.y.z',x.y.z替换为具体的 SDK 版本号。 - MetaKit 插件需要用到实时互动 SDK 的面部捕捉插件 (
AgoraFaceCaptureExtension.xcframework) 和虚拟背景插件 (AgoraVideoSegmentationExtension.xcframework),你可以按需删除不需要的插件以减小 App 体积。
- 通过 CocoaPods 集成时,打开
- Xcode 13.0 及以上版本。
- iOS 14.0 及以上版本的真机设备,设备的前置摄像头与麦克风功能正常。
- Apple 开发者账号。
- 已安装 CocoaPods,详见 Getting Started with CocoaPods。
- 可以访问互联网的计算机。如果你的网络环境部署了防火墙,参考应对防火墙限制以正常使用声网服务。
集成 MetaKit 插件
在体验 MetaKit 插件前,请参考以下步骤配置你的项目。
添加 MetaKit 插件依赖
请参考以下步骤获取并集成 MetaKit 插件:
-
进入下载页面,下载并解压 MetaKit iOS 插件。
-
打开文件夹,解压
Libraries.zip,将解压后的文件复制到对应的项目路径中。库 集成路径 AgoraMetaKitExtension.xcframework/SDKExtension/AgoraMetaKit.xcframework/SDKExtension/注意声网提供 XCFramework 格式的插件支持
arm64架构,但不支持armv7架构。 -
用 Xcode 打开项目,添加对应动态库的依赖,确保添加的动态库 Embed 属性设置为 Embed & Sign。
配置 MetaKit 资源
-
打开 MetaKit iOS 插件的文件夹,
/assets/路径下包含不同场景及功能所需的 Bundle 文件资源。功能模块、用途说明和资源大小见下表:功能模块 用途说明 资源大小 虚拟人 虚拟人模型分包资源 ( material_avatar_xxx),包含虚拟人形像girl、boy和huamulan。可使用面捕驱动、捏脸、换装等能力。material_avatar_girl: 17.7 MBmaterial_avatar_boy: 5.4 MB(不支持换装)material_avatar_huamulan: 5.3 MB(不支持捏脸换装)
Animoji Animoji 模型分包资源 ( material_animoji_xxx),包含 Animoji 形象dog、girlhead和arkit。可使用面捕驱动能力。material_animoji_dog: 3.3 MBmaterial_animoji_girlhead: 4.2 MBmaterial_animoji_arkit: 2 MB
Sticker Sticker 模型分包资源 ( material_sticker_xxx),包含 Sticker 挂件glass、facemask、dragonhat和veil。可使用面捕驱动能力。material_sticker_glass: 2.5 MBmaterial_sticker_facemask: 1.9 MBmaterial_sticker_dragonhat: 2.4 MBmaterial_sticker_veil: 2.6 MB
背景特效 背景特效分包资源 ( material_bgeffect_xxx),包含360(360 全景背景)和3d(3D 背景)。material_bgeffect_360: 3.1 MBmaterial_bgeffect_3d: 5.6 MB
灯光特效 灯光特效分包资源 ( material_effect_xxx),包含 3D 打光、广告灯、氛围灯、极光特效、人像边缘火焰、人像边缘光线和屏幕波纹。material_effect_3dlight: 1.9 MBmaterial_effect_advertiselight: 8.2 MBmaterial_effect_envlight: 1.9 MBmaterial_effect_aura: 2 MBmaterial_effect_purpleflame: 2 MBmaterial_effect_ray: 1.9 MBmaterial_effect_wave: 1.9 MB
-
每个单包资源 (
material_xxx) 代表一种场景效果。将多个你想体验的单包资源资源 (material_xxx) 平行放置在一个根目录下,加载场景资源时,将资源目录的绝对路径设置给 MetaKit。例如,体验女孩虚拟形象和人像边缘火焰特效,步骤如下:- 将
material_avatar_girl和material_effect_purpleflame合成一个资源目录(如下图所示)。准备好资源目录后,将其放置在移动设备 SD 卡的目录下,如/sdcard/metaAssets/。 loadMaterial时,将路径设置为/sdcard/metaAssets/material_avatar_girl,体验女孩虚拟人场景。- 再次
loadMaterial,将路径指定为/sdcard/metaAssets/material_effect_purpleflame,切换为人像边缘火焰。
注意业务层需自行确保下载解压后资源的完备性。如果目录不正确或有 Bundle 文件丢失的情况,加载时会出现异常。
- 将
添加 iOS 设备权限
打开项目的 Info.plist 文件,编辑属性列表,添加体验 MetaKit 插件所需的麦克风和摄像头权限。
| 权限 | 说明 |
|---|---|
Privacy - Microphone Usage Description | 使用音频功能。 |
Privacy - Camera Usage Description | 表情驱动、背景分割等功能需要访问摄像头以做 AI 推理。 |
体验 MetaKit 插件
项目配置完成后,请参照以下步骤体验 MetaKit 插件的各个功能模块。
监听插件事件回调
-
调用
sharedEngineWithConfig初始化AgoraRtcEngineKit时,你需要在AgoraRtcEngineConfig中创建插件的事件回调接口类AgoraMediaFilterEventDelegate,并注册onEvent等插件事件回调。Swiftlet config = AgoraRtcEngineConfig()
config.appId = appID
config.eventDelegate = self
// 创建并初始化 AgoraRtcEngineKit
agoraEngine = AgoraRtcEngineKit.sharedEngine(with: config, delegate: self)
// 创建插件的事件回调接口类,注册 onEvent 等插件事件回调
extension ViewController: AgoraMediaFilterEventDelegate {
func onEvent(_ provider: String?, extension: String?, key: String?, value: String?) {
}
func onExtensionStarted(_ provider: String?, extension: String?) {
}
func onExtensionStopped(_ provider: String?, extension: String?) {
}
func onExtensionError(_ provider: String?, extension: String?, error: Int32, message: String?) {
}
} -
在回调中指定
provider为agora_video_filters_metakit,extension为metakit,即筛选来自 MetaKit 插件的事件。onEvent会透传引擎状态,如unityLoadFinish(Unity 环境加载完成)和materialLoaded(场景视图加载完成)等。注意- 下列代码注释中介绍了每个引擎状态的含义及时序,请确保在收到确切的引擎状态后,执行对应的操作,以免出现不必要的时序问题。
- 引擎状态的回调不在主线程执行。如果需要在收到回调后执行其他重要操作,请使用
dispatch_async将这些任务切换到主线程,以避免线程问题。
Swiftfunc onEvent(_ provider: String?, extension: String?, key: String?, value: String?) {
guard let provider = provider, let extension = extension, provider == "agora_video_filters_metakit", extension == "metakit" else {
return
}
guard let status = key else {
return
}
switch status {
case "initializeFinish":
// 引擎初始化完成
// 如有 initialize 操作,请在最后调用 destroy 销毁引擎,确保引擎的正常生命周期,减少对性能和内存的影响
break;
case "unityLoadFinish":
// Unity 环境加载完成
// 收到此状态后,可以调用 loadMaterial 加载场景资源
break;
case "materialLoaded":
// 加载场景资源成功
// 收到此状态后,可以根据场景进一步执行捏脸换装、特效参数设置等操作
// 如不再需要体验场景,调用 unloadMaterial 卸载场景资源
DispatchQueue.main.async {
// 回调不是主线程抛过来的,请在 dispatch 后执行操作
}
break;
case "materialUnLoaded":
// 卸载场景资源完成
// 收到此状态后,不可再次加载场景资源,仅可调用 destroy 执行引擎销毁操作
break;
default:
break
}
}
func onExtensionError(_ provider: String?, extension: String?, error: Int32, message: String?) {
if provider == "agora_video_filters_metakit" && extension == "metakit" {
print("[MetaKit] onExtensionError, Code: \(error), Message: \(message ?? "")")
}
}
启用插件
启用面部捕捉插件、虚拟背景插件和 MetaKit 插件。
在启用 MetaKit 插件前,你需要先启用面部捕捉插件和虚拟背景插件。
-
启用面部捕捉插件。
- 调用
registerExtensionWithVendor和enableExtensionWithVendor注册并启用面部捕捉插件,传入对应的插件服务商名称 (agora_video_filters_face_capture) 和插件名称 (face_capture)。 - 调用
setExtensionPropertyWithVendor认证和授权面部捕捉插件的 AI 模块,其中key为authentication_information,value包含公司名称 (company_id) 和面捕证书 (license)。
注意公司名称和面捕证书需要联系 sales@shengwang.cn 获取。
Swift// 注册面部捕捉插件
agoraEngine?.registerExtension(withVendor: "agora_video_filters_face_capture", extension: "face_capture", sourceType: AgoraMediaSourceType.primaryCamera)
// 启用面部捕捉插件
agoraEngine?.enableExtension(withVendor: "agora_video_filters_face_capture", extension: "face_capture", enabled: true)
// 授权面部捕捉插件
agoraEngine?.setExtensionPropertyWithVendor("agora_video_filters_face_capture",
extension: "face_capture",
key: "authentication_information",
value: "{\"company_id\":\"agoraDemo\", \"license\":\"xxxxxxxxxx"}",
sourceType: AgoraMediaSourceType.primaryCamera) - 调用
-
启用虚拟背景插件。
- 调用
setParameters设置"rtc.video.seg_before_exts"为true,确保虚拟背景插件优先于 MetaKit 插件执行。 - 调用
enableVirtualBackground开启虚拟背景,其中:- 指定背景填充 (
backgroundSourceType) 为AgoraVirtualBackgroundNone,将背景处理为 alpha 信息,即分割人像和背景。 - 指定分割模式 (
modelType) 为SegModelAgoraAi,即选择适用于全部场景的背景处理。
- 指定背景填充 (
Swift// 确保虚拟背景插件优先于 MetaKit 插件执行
agoraKit.setParameters("{\"rtc.video.seg_before_exts\":true}")
let bg_src = AgoraVirtualBackgroundSource()
// 将背景处理为 alpha 信息,分割人像和背景
bg_src.backgroundSourceType = .none
let seg_prop = AgoraSegmentationProperty()
seg_prop.greenCapacity = 0
// 选择适用于全部场景的背景处理
seg_prop.modelType = .agoraAi
// 启用虚拟背景插件
agoraEngine?.enableVirtualBackground(true, backData: bg_src, segData: seg_prop) - 调用
-
启用 MetaKit 插件。
调用registerExtensionWithVendor和enableExtensionWithVendor注册并启用 MetaKit 插件,传入对应的插件服务商名称 (agora_video_filters_metakit) 和插件名称 (metakit)。Swift// 注册 MetaKit 插件
agoraEngine?.registerExtension(withVendor: "agora_video_filters_metakit", extension: "metakit", sourceType: AgoraMediaSourceType.primaryCamera)
// 启用 MetaKit 插件
agoraEngine?.enableExtension(withVendor: "agora_video_filters_metakit", extension: "metakit", enabled: true)
初始化插件
调用 setExtensionPropertyWithVendor 初始化 MetaKit 插件,其中 key 为 initialize,value 为空。
agoraEngine?.setExtensionPropertyWithVendor("agora_video_filters_metakit", extension: "metakit", key:"initialize", value:"{}")
创建渲染视图
当 onEvent 回调捕获到 unityLoadFinish 事件时,代表 Unity 环境已加载完成。此时,调用 createSceneView 创建一个 SceneView 用于显示 MetaKit 插件的渲染画面。
let metakit: MetaKitEngine = MetaKitEngine.sharedInstance()
var frame = CGRect(x: 0, y: 0, width: 360, height: 640);
// 1. sceneView 为原生 iOS UIView,如果需要展示在 UI 上,可自行添加到父 view 上
// 2. 如果想要铺满渲染画面,sceneView 的 frame 尽量确保和素材的比例是对等的(默认 9:16)
// 否则画面会按等比例适应,画面居中,上下左右留白
let sceneView = metakit.createSceneView(frame)
加载场景资源
创建好视图后,加载场景资源并渲染到该视图上。此时,可以调用 setExtensionPropertyWithVendor 加载 MetaKit 场景资源,其中 key 为 loadMaterial,value 包含场景信息。
- 下文中虚拟人、Animoji、Sticker、灯光特效和背景特效的资源加载均类似此步骤 (
key为loadMaterial),区别仅在于加载的资源包不同 (value中指定的资源包路径不同)。 - 资源加载操作 (
loadMaterial) 可以多次执行,无需在每次加载后执行卸载操作 (unloadMaterial) 。例如:在调用loadMaterial(pathA)后,如需切换为其他场景资源,可以再次调用loadMaterial(pathB)、loadMaterial(pathC)等,每次加载会全量覆盖之前的场景,最后再执行unloadMaterial()卸载场景资源即可。
let address = unsafeBitCast(avatarView!, to: Int64.self)
// path 为 Unity 的资源包目录,请提前下载并解压好
// view 为上文创建的 SceneView 的地址句柄
let dict = ["path": path, "view": String(address)]
let data = try? JSONSerialization.data(withJSONObject: dict, options: [])
let dictInfo = String(data: data!, encoding: String.Encoding.utf8)
self.agoraKit?.setExtensionPropertyWithVendor("agora_video_filters_metakit", extension: "metakit",
key:"loadMaterial",
value:dictInfo ?? "")
当 onEvent 回调捕获到 materialLoaded 事件时,代表场景资源已加载完成。接下来,你可以体验虚拟人、Animoji、Sticker、灯光特效和背景特效功能模块。
设置虚拟人
-
调用
setExtensionPropertyWithVendor添加一个虚拟人场景,其中key为loadMaterial,value为素材的配置信息。 你想选用哪个虚拟人形象,请指定对应的资源名 (material_avatar_xxx),例如:女孩虚拟人形象的资源名为material_avatar_girl。信息除
girl、boy和huamulan三个插件中已有的虚拟形象外,声网 MetaKit 插件提供开放的美术生态,支持一键导入按声网的美术标准制作的虚拟人模型,为用户提供更灵活的创作和集成选项。联系声网技术支持使用该功能。Swiftlet address = unsafeBitCast(sceneView!, to: Int64.self) // 获取视图的地址句柄
let dict = ["path": path_to_material_avatar_girl, "view": String(address)]
let data = try? JSONSerialization.data(withJSONObject: dict, options: [])
let dictInfo = String(data: data!, encoding: String.Encoding.utf8)
self.agoraKit?.setExtensionPropertyWithVendor("agora_video_filters_metakit", extension: "metakit",
key:"loadMaterial",
value:dictInfo ?? "")当
onEvent回调捕获到materialLoaded事件时,代表场景视图已添加完成,视图中会展示一个 Blendshape 驱动的虚拟人形象,捕捉你的面部表情并作出对应的神态变化,跟随你的摆头等动作。 -
对虚拟人进行捏脸操作,支持以下两种方式:
- (推荐)方式一:加载虚拟人时,直接应用整套捏脸效果。只需要在
loadMaterial时指定资源为material_package_faceshape,即可加载虚拟人形象及整套捏脸数据。 - 方式二:加载虚拟人后,动态按部位对虚拟人进行捏脸操作。调用
setExtensionPropertyWithVendor,其中key为updateFace,value支持传入多组捏脸部位的资源 ID 及其对应的调节幅度。详见捏脸资源。
Swiftlet parts = [
// key 为捏脸部位的资源 ID
// value 为对应的捏脸幅度,取值范围为 [0,100],默认值为 50
["key": "C_updown_2", "value": 20],
["key": "EB_thickness", "value": 40],
["key": "E_width_1", "value": 60],
["key": "N_width_1", "value": 80]
]
let dict = ["value": parts]
let data = try? JSONSerialization.data(withJSONObject: dict, options: [])
let str = String(data: data!, encoding: String.Encoding.utf8)
// 根据 JSON 配置进行捏脸操作
agoraKit?.setExtensionPropertyWithVendor("agora_video_filters_metakit", extension: "metakit",
key:"updateFace",
value:str!) - (推荐)方式一:加载虚拟人时,直接应用整套捏脸效果。只需要在
-
对虚拟人进行换装操作,支持以下两种方式:
- (推荐)方式一:在加载虚拟人时,直接应用整套换装效果。在
loadMaterial时指定资源为material_package_dress2或material_package_dress3,即可加载虚拟人形象及整套换装效果。 - 方式二:在加载虚拟人后,动态按部位对虚拟人进行换装操作。调用
setExtensionPropertyWithVendor,其中key为updateDress,value支持传入由多个换装部位的资源 ID 组成的 Int 数组。详见换装资源。
Swift// id 设置为多个资源 ID 组成的 Int 数组
let dict = ["id": [10002, 10102, 10402, 12102, 12501, 14102, 15002]]
let data = try? JSONSerialization.data(withJSONObject: dict, options: [])
let str = String(data: data!, encoding: String.Encoding.utf8)
// 根据 JSON 配置进行换装操作
agoraKit?.setExtensionPropertyWithVendor("agora_video_filters_metakit", extension: "metakit",
key:"updateDress",
value:str!)此外,MetaKit 插件还支持切换虚拟人的形象和视角,详见虚拟人 key-value 说明。
- (推荐)方式一:在加载虚拟人时,直接应用整套换装效果。在
设置 Animoji 和 Sticker
- Animoji
- Sticker
调用 setExtensionPropertyWithVendor 添加一个 Animoji 场景,其中 key 为 loadMaterial,value 为素材的配置信息。你想选用哪个 Animoji 效果,请指定对应的资源名 (material_animoji_xxx),例如:狗狗头套 Anomoji 的资源名为 material_animoji_dog。
除 dog、girlhead 和 arkit 三个插件中已有的 Animoji 外,声网 MetaKit 插件提供开放的美术生态,支持一键导入按声网的美术标准制作的 Animoji 形象,为用户提供更灵活的创作和集成选项。联系声网技术支持使用该功能。
let address = unsafeBitCast(sceneView!, to: Int64.self) // 获取视图的地址句柄
let dict = ["path": path_to_material_animoji_dog, "view": String(address)]
let data = try? JSONSerialization.data(withJSONObject: dict, options: [])
let dictInfo = String(data: data!, encoding: String.Encoding.utf8)
self.agoraKit?.setExtensionPropertyWithVendor("agora_video_filters_metakit", extension: "metakit",
key:"loadMaterial",
value:dictInfo ?? "")
当 onEvent 回调捕获到 materialLoaded 事件时,代表场景视图已添加完成。此时,画面中会出现一个遮住人脸的狗狗头套,捕捉你的面部表情并作出对应的神态变化,跟随你的摆头等动作。此外,MetaKit 插件支持你切换 Animoji 形象并调节 Animoji 形象的渲染等级,详见 Animoji key-value 说明。
调用 setExtensionPropertyWithVendor 添加一个 Sticker 场景视图,其中 key 为 loadMaterial,value 为素材的配置信息。你想选用哪个 Sticker 效果,请指定对应的资源名 (material_sticker_xxx),例如:眼镜贴纸的资源名为 material_sticker_glass。
除 veil、glass、facemask 和 dragonhat 四个插件中已有的 Sticker 外,声网 MetaKit 插件提供开放的美术生态,支持一键导入按声网的美术标准制作的 Sticker 形象,为用户提供更灵活的创作和集成选项。联系声网技术支持使用该功能。
let address = unsafeBitCast(sceneView!, to: Int64.self) // 获取视图的地址句柄
let dict = ["path": path_to_material_sticker_glass, "view": String(address)]
let data = try? JSONSerialization.data(withJSONObject: dict, options: [])
let dictInfo = String(data: data!, encoding: String.Encoding.utf8)
self.agoraKit?.setExtensionPropertyWithVendor("agora_video_filters_metakit", extension: "metakit",
key:"loadMaterial",
value:dictInfo ?? "")
当 onEvent 回调捕获到 materialLoaded 事件时,代表场景视图已添加完成。此时,视图中会展示一个遮住人眼的眼镜贴纸,跟随你的摆头等动作。
设置灯光和背景特效
- 灯光特效
- 背景特效
-
调用
setExtensionPropertyWithVendor添加一个灯光特效场景,其中key为loadMaterial,value为素材的配置信息。你想选用哪个灯光特效,请指定对应的资源名 (material_effect_xxx),例如:3D 打光的资源名为material_effect_3dlight。成功设置该特效后,画面中会有一盏 3D 灯光从斜方来回扫过。Swiftlet address = unsafeBitCast(sceneView!, to: Int64.self) // 获取视图的地址句柄
let dict = ["path": path_to_material_effect_3dlight, "view": String(address)]
let data = try? JSONSerialization.data(withJSONObject: dict, options: [])
let dictInfo = String(data: data!, encoding: String.Encoding.utf8)
self.agoraKit?.setExtensionPropertyWithVendor("agora_video_filters_metakit", extension: "metakit",
key:"loadMaterial",
value:dictInfo ?? "") -
调用
setExtensionPropertyWithVendor调节灯光特效的参数,其中key为setEffectVideo,value中包含一系列灯光素材的配置参数。MetaKit 插件提供 3D 打光、屏幕波纹、极光特效、人像边缘火焰等灯光特效,并支持对灯光效果的颜色、强度、范围等参数进行精细化配置,详见灯光特效 key-value 说明。Swiftlet address = unsafeBitCast(sceneView!, to: Int64.self) // 获取视图的地址句柄
let light_dict = ["id": 1001, "param": ["intensity": 2.0, "scale": 0.3] as [String : Any], "enable": true] as [String : Any]
let light_data = try? JSONSerialization.data(withJSONObject: light_dict, options: [])
let light_info = String(data: light_data!, encoding: String.Encoding.utf8)
agoraKit?.setExtensionPropertyWithVendor("agora_video_filters_metakit", extension: "metakit",
key:"setEffectVideo",
value:light_info!)
调用 setExtensionPropertyWithVendor 添加一个背景特效场景,其中 key 为 loadMaterial,value 为素材的配置信息。你想选用哪个背景特效,请指定对应的资源名 (material_bgeffect_xxx),例如:360 全景背景素材的资源名为 material_bgeffect_360。
let address = unsafeBitCast(sceneView!, to: Int64.self) // 获取视图的地址句柄
let dict = ["path": path_to_bgeffect, "view": String(address)]
let data = try? JSONSerialization.data(withJSONObject: dict, options: [])
let dictInfo = String(data: data!, encoding: String.Encoding.utf8)
self.agoraKit?.setExtensionPropertyWithVendor("agora_video_filters_metakit", extension: "metakit",
key:"loadMaterial",
value:dictInfo ?? "")
成功设置该特效后,可以观察到视频画面背景变为 360 全景,转动手机能体验到全景效果。此外,MetaKit 插件还支持 2D 背景和 3D 背景,如需将背景替换为指定资源或开启陀螺仪效果,详见背景特效 key-value 说明。
开启视图输出
调用 setExtensionPropertyWithVendor 开启视图输出,其中 key 为 enableSceneVideo,value 中将 enable 设置为 true 开启场景视图的画面捕获。开启视图输出后,本地视图的渲染效果会传输到远端,加入频道的观众也能看到渲染效果。
let address = unsafeBitCast(sceneView!, to: Int64.self)
let value = enable ? 1 : 0
agoraKit?.setExtensionPropertyWithVendor("agora_video_filters_metakit",
extension: extension_name,
key:"enableSceneVideo",
value:"{\"view\":\"\(address)\",\"enable\":\(value)}")
释放资源
停止使用插件时,可以参照以下示例代码卸载场景资源、移除场景视图并销毁引擎。
// 1. 卸载场景资源
agoraEngine?.setExtensionPropertyWithVendor("agora_video_filters_metakit", extension: "metakit",
key:"unloadMaterial", value:"{}")
// 2. 移除视图
sceneView?.removeFromSuperview()
metakit.removeSceneView(sceneView?)
// 3. 收到 materialUnLoaded 后,执行销毁引擎
agoraEngine?.setExtensionPropertyWithVendor("agora_video_filters_metakit", extension: "metakit",
key:"destroy", value:"{}")