更新记录
1.0.0(2026-05-10)
- 支持 App Android 和 App iOS 原生 Live2D 模型渲染。
- 支持模型加载、动作播放、表情切换、参数控制、触摸命中。
- 支持语音播放、WAV/音频口型驱动、动作自带声音。
- 支持 AI 实时 PCM16 音频流播放和口型同步。
平台兼容性
uni-app x(5.08)
| Chrome | Safari | Android | iOS | 鸿蒙 | 微信小程序 |
|---|---|---|---|---|---|
| × | × | √ | √ | × | × |
em-live2d 插件使用文档
em-live2d 是 uni-app UTS 原生组件插件,用于在 App 端渲染 Live2D Cubism 模型。插件支持 Android 和 iOS,可在 nvue/uvue 页面中加载模型、播放动作、切换表情、控制参数、播放语音、驱动口型,并接入 AI 实时语音输出。
支持范围
| 平台 | 支持 |
|---|---|
| App Android | 支持 |
| App iOS | 支持 |
| Web/H5 | 不支持原生 Live2D 渲染 |
| 小程序 | 不支持原生 Live2D 渲染 |
应用场景
em-live2d 适合需要在 App 内嵌入可交互虚拟角色的场景:
| 场景 | 说明 |
|---|---|
| AI 虚拟助手 | 结合语音识别、实时大模型和 TTS,让 Live2D 角色完成问答、提醒、讲解和陪伴 |
| 实时语音对话 | AI 返回 PCM 音频流时,边播边驱动口型,适合低延迟对话体验 |
| 语义驱动角色 | 根据意图、情绪、语气切换表情、动作、视线和身体参数,让角色不只是“说话动嘴” |
| 数字人客服 | 在咨询、导购、售后等流程中用虚拟角色承载服务入口 |
| 教学和导览 | 用角色讲解课程、流程、产品、景点或业务规则 |
| 陪伴和互动角色 | 做桌面宠物、情绪陪伴、互动头像、角色扮演等 App 功能 |
| 活动和营销页 | 在 App 内使用品牌虚拟形象做互动展示、欢迎语、动作表演 |
| 本地模型演示 | 快速验证 Live2D 模型资源、动作、表情、音频和口型效果 |
资源放置
建议将 Live2D 模型资源放到应用的 static/live2d 目录:
static/live2d/
165 204/
165 204.model3.json
165 204.moc3
165 204.physics3.json
165 204.4096/
texture_00.png
motion/
idle.motion3.json
dance.motion3.json
expressions/
smile.exp3.json
sounds/
song.wav
页面中使用 /static/... 路径:
/static/live2d/165 204/165 204.model3.json
/static/live2d/165 204/sounds/song.wav
如果模型是下载到本地的,也可以传绝对本地文件路径。路径必须指向 .model3.json。
基础用法
<template>
<view class="page">
<em-live2d
ref="avatar"
class="avatar"
model="/static/live2d/165 204/165 204.model3.json"
:autoIdle="true"
:enableMotionSound="true"
:voiceVolume="1"
@modelLoaded="onModelLoaded"
@modelLoadFailed="onModelLoadFailed"
@motionFinished="onMotionFinished"
@voiceEnded="onVoiceEnded"
@nativeError="onNativeError"
/>
</view>
</template>
<script>
export default {
methods: {
onModelLoaded(event) {
console.log('Live2D model loaded', event)
},
onModelLoadFailed(error) {
console.log('Live2D model load failed', error)
},
onMotionFinished(event) {
console.log('Live2D motion finished', event)
},
onVoiceEnded(event) {
console.log('Live2D voice ended', event)
},
onNativeError(error) {
console.log('Live2D native error', error)
}
}
}
</script>
<style>
.page {
flex: 1;
}
.avatar {
width: 750rpx;
height: 980rpx;
}
</style>
Props
| Prop | 类型 | 默认值 | 说明 |
|---|---|---|---|
model |
String |
'' |
.model3.json 路径,推荐 /static/... |
autoIdle |
Boolean |
true |
模型加载后自动播放 Idle 随机动作 |
enableMotionSound |
Boolean |
true |
动作配置里包含 Sound 时自动播放对应声音 |
voiceVolume |
Number |
1.0 |
语音播放音量 |
加载模型
通过 model 属性加载:
<em-live2d ref="avatar" model="/static/live2d/165 204/165 204.model3.json" />
也可以手动加载:
this.$refs.avatar.loadModel('/static/live2d/165 204/165 204.model3.json')
模型加载成功会触发 modelLoaded,失败会触发 modelLoadFailed。
动作
动作必须在 .model3.json 的 FileReferences.Motions 中声明。调用时使用动作组名和索引:
this.$refs.avatar.startMotion('Dance', 0, 3)
this.$refs.avatar.startRandomMotion('Idle', 1)
this.$refs.avatar.stopAllMotions()
优先级建议:
| 优先级 | 用途 |
|---|---|
1 |
待机、倾听、低优先级动作 |
2 |
普通动作 |
3 |
用户主动触发、强制打断当前动作 |
如果动作没有播放,先确认:
.model3.json中存在该 motion group。index没有越界。- motion 文件路径正确并已打包。
- 当前动作优先级没有被更高优先级动作占用。
表情和参数
表情必须在 .model3.json 的 Expressions 中声明:
this.$refs.avatar.setExpression('smile')
this.$refs.avatar.setRandomExpression()
参数控制:
this.$refs.avatar.setParameter('ParamAngleX', 15)
this.$refs.avatar.addParameter('ParamAngleY', 5, 1)
this.$refs.avatar.multiplyParameter('ParamEyeLOpen', 0.8, 1)
this.$refs.avatar.setParametersBatch(['ParamAngleX', 'ParamAngleY'], [10, -5])
const value = this.$refs.avatar.getParameter('ParamAngleX')
只有模型 .moc3 中真实存在的参数才会生效。
语音和口型
手动控制口型
this.$refs.avatar.setLipSyncValue(1)
this.$refs.avatar.setLipSyncValue(0)
this.$refs.avatar.setLipSyncValues([0.2, 0.8, 0.1])
播放音频并驱动口型
this.$refs.avatar.startLipSyncFromWav('/static/live2d/165 204/sounds/song.wav')
this.$refs.avatar.startLipSyncFromAudio('/static/live2d/165 204/sounds/song.wav')
this.$refs.avatar.stopLipSync()
startLipSyncFromWav(path) 会播放 WAV 并根据音频 RMS 驱动嘴部。startLipSyncFromAudio(path) 用当前平台音频能力播放并驱动口型。
只播放语音
this.$refs.avatar.playVoice('/static/live2d/165 204/sounds/song.wav', false)
this.$refs.avatar.stopVoice()
播放语音并驱动口型
this.$refs.avatar.playVoice('/static/live2d/165 204/sounds/song.wav', true)
语音相关事件:
<em-live2d
@voiceStarted="onVoiceStarted"
@voiceEnded="onVoiceEnded"
@voiceError="onVoiceError"
/>
动作自带声音
如果 motion 条目包含 Sound,并且组件 enableMotionSound 为 true,播放该动作时会自动播放声音:
{
"File": "motions/touch_01.motion3.json",
"Sound": "sounds/haru_talk_13.wav"
}
Sound 路径相对于当前模型目录。
AI 实时语音输出
插件只负责 AI 语音输出的播放和口型驱动;用户麦克风采集、WebSocket、AI 协议由业务层或其他插件处理。
AI 服务返回 PCM16 音频流时,按下面流程推给 Live2D:
this.$refs.avatar.startRealtimeVoice(24000, 1, 'pcm16')
this.$refs.avatar.pushAudioChunk(base64Pcm16Chunk)
this.$refs.avatar.stopRealtimeVoice()
实时音频要求:
| 项 | 要求 |
|---|---|
| 编码 | signed 16-bit little-endian PCM |
| 声道 | mono 或 stereo |
| 采样率 | 调用 startRealtimeVoice(sampleRate, channels, 'pcm16') 时传入 |
| chunk | pushAudioChunk() 参数为 base64 PCM 数据 |
如果 AI 服务已经计算好音量或口型权重,可以直接驱动:
this.$refs.avatar.pushAudioLevel(0.65)
this.$refs.avatar.pushViseme('ParamMouthOpenY', 0.65)
触摸、拖拽和命中区域
this.$refs.avatar.setDrag(x, y)
this.$refs.avatar.tap(x, y)
命中区域通过 hitArea 事件返回:
<em-live2d @hitArea="onHitArea" />
onHitArea(event) {
console.log('hit area', event.message)
}
获取模型信息
getModelInfo() 返回 JSON 字符串,可用于查看当前模型的动作组、表情、参数和命中区域:
const raw = this.$refs.avatar.getModelInfo()
const info = JSON.parse(raw)
console.log(info)
停止和释放
常见停止逻辑:
this.$refs.avatar.stopRealtimeVoice()
this.$refs.avatar.stopVoice()
this.$refs.avatar.stopLipSync()
this.$refs.avatar.stopAllMotions()
this.$refs.avatar.startRandomMotion('Idle', 1)
页面销毁时通常组件会跟随页面释放。需要主动释放时:
this.$refs.avatar.releaseLive2D()
方法总表
| 方法 | 说明 |
|---|---|
loadModel(path) |
加载 .model3.json |
startMotion(group, index, priority = 2) |
播放指定动作 |
startRandomMotion(group, priority = 2) |
随机播放动作组 |
stopAllMotions() |
停止全部动作 |
setExpression(name) |
设置表情 |
setRandomExpression() |
随机表情 |
setParameter(id, value) |
设置参数 |
addParameter(id, value, weight = 1) |
叠加参数 |
multiplyParameter(id, value, weight = 1) |
乘法调整参数 |
setParametersBatch(ids, values) |
批量设置参数 |
getParameter(id) |
获取参数值 |
setLipSyncValue(value) |
设置口型值 |
setLipSyncValues(values) |
设置一组口型值,目前取最后一个 |
startLipSyncFromWav(path) |
播放 WAV 并驱动口型 |
startLipSyncFromAudio(path) |
播放音频并驱动口型 |
stopLipSync() |
停止口型驱动 |
playVoice(path, driveLipSync = false) |
播放语音,可选驱动口型 |
stopVoice() |
停止语音 |
startRealtimeVoice(sampleRate = 24000, channels = 1, format = 'pcm16') |
开始实时 PCM16 语音播放 |
pushAudioChunk(base64Chunk) |
推入 base64 PCM16 音频 chunk |
pushAudioLevel(rms) |
直接推入音量值驱动口型 |
pushViseme(id, weight) |
直接推入口型或参数权重 |
stopRealtimeVoice() |
停止实时语音播放 |
setDrag(x, y) |
设置拖拽坐标 |
tap(x, y) |
触发点击检测 |
getModelInfo() |
返回模型信息 JSON 字符串 |
releaseLive2D() |
释放原生资源 |
事件总表
| 事件 | 说明 |
|---|---|
modelLoaded |
模型加载成功 |
modelLoadFailed |
模型加载失败 |
motionStarted |
动作开始 |
motionFinished |
动作结束 |
expressionChanged |
表情变化 |
hitArea |
点击命中区域 |
voiceStarted |
语音开始 |
voiceEnded |
语音结束 |
voiceError |
语音失败 |
lipSyncStarted |
口型驱动开始 |
lipSyncEnded |
口型驱动结束 |
nativeError |
原生错误 |
事件 payload 通常包含:
{
type: 'motionFinished',
code: null,
message: 'Dance'
}
不同事件的 message 可能是模型路径、动作组、音频路径、命中区域或错误描述。
常见问题
模型加载失败
检查:
model是否指向.model3.json。/static/...路径和真实文件名是否完全一致。.model3.json引用的.moc3、贴图、动作、表情文件是否存在。- 模型目录或文件名有空格时,传入路径也必须完全一致。
动作无法播放
常见原因:
.model3.json没有对应 motion group。index越界。- motion 文件路径错误。
- 当前动作优先级更高。
可尝试:
this.$refs.avatar.stopAllMotions()
this.$refs.avatar.startMotion('Dance', 0, 3)
动作开始了但模型不动
动作文件里的参数 ID 必须存在于模型 .moc3。如果 motion 修改的是模型不存在的参数,动作会被播放,但视觉上不会变化。
嘴不动
检查 .model3.json 是否存在 Groups -> LipSync,并且包含当前模型实际嘴部参数,常见参数是 ParamMouthOpenY。
没声音
检查:
- 音频路径是否正确。
voiceVolume是否大于0。- 是否收到
voiceError。 - 当前平台是否支持该音频格式。
- 实时流是否为 PCM16 little-endian。
调试日志
Android 模型、动作、音频加载问题:
adb logcat -c
adb logcat -v time | grep -E "HylLive2D|NativePrint|model|moc|texture|motion|Live2D"
Android 崩溃和原生错误:
adb logcat -c
adb logcat -v time | grep -E "AndroidRuntime|FATAL|SIGSEGV|NativePrint|Live2D|HylLive2D|em_live2d"
iOS 可在 Xcode 的 Devices and Simulators -> Open Console 或 macOS Console 中按进程名、Bundle ID、EmLive2D、NativePrint 过滤日志。

收藏人数:
购买普通授权版(
试用
使用 HBuilderX 导入示例项目
赞赏(0)
下载 400
赞赏 0
下载 11846804
赞赏 1911
赞赏
京公网安备:11010802035340号