在 Python 中直接加载和操作 Live2D 模型,不通过 Web Engine 等间接手段进行渲染,提供更高的自由度和拓展性。
Python 的 Live2D 拓展库。基于 Python C++ API 对 Live2D Native (C++) 进行了封装。理论上,只要配置好 OpenGL 上下文,可在 Python 中将 live2d 绘制在任何基于 OpenGL 的窗口。
支持 Live2D 模型版本:
- Cubism 2.X 导出的模型:文件名格式常为
XXX.moc
,XXX.model.json
,XXX.mtn
- Cubism 3.0 及以上导出的模型:文件名格式常为
XXX.moc3
,XXX.model3.json
,XXX.motion3.json
支持窗口库:
- PyQt5
- PySide2 / PySide6
- GLFW
- FreeGlut
- ...
功能:
- 加载模型
- 鼠标拖拽视线
- 鼠标点击触发动作
- 动作播放回调函数
live2d-py |
支持的live2d模型 | 支持的Python版本 | 支持平台 |
---|---|---|---|
live2d.v2 |
Cubism 2.0 及以上,不包括 3.0 | 仅 32 位,支持Python 3.0 及以上版本,但除 Python 3.10.11 外需要自行编译 |
Windows |
live2d.v3 |
Cubism 3.0 及以上,包括 4.0 | 支持 32 / 64 位,支持Python 3.0 及以上版本,但除 Python 3.12 外需要自行编译 |
Windows、Linux |
本仓库已发布的版本中:
- v2 版本仅支持:Python 3.10.11 (win32)
- v3 版本仅支持:Python 3.12+ (win64)
若需要 64 位或 linux 平台支持,则需要拉取本仓库源码使用 CMake 编译。
对于适用 Cubism 2.0 模型,目前只支持 32 位,因为当前网络上能找到的现存 live2d opengl 静态库只有 32 位。
live2d-py
|-- CMakeLists.txt # CMake 配置文件,用于生成 live2d-py
|-- Core # Cubism Live2D Core 头文件和库文件,详情见 Cubism 官方
|-- Framework # Cubism 开发框架
|-- LAppModelWrapper.cpp # live2d native 的 python 封装
|-- Main # live2d native 类
|-- README.md
|-- Resources # 资源文件夹,live2d 模型,应用图标
|-- docs
|-- glew # opengl 接口依赖
|-- include # 项目包含目录
`-- package # 生成的 live2d-py 包,可用 setup.py 打包和安装
Cubism 2.0 模型使用接口见 package/live2d/v2/live2d.pyi。
Cubism 3.0(含4.0) 模型使用接口见 package/live2d/v3/live2d.pyi。
具体与图形库结合的用例示例见 package 文件夹。
文件:
live2d.so
和live2d.pyd
:封装了 c++ 类的动态库,供 python 调用。在import live2d.vX as live2d
时,解释器在文件目录中寻找live2d.so
/live2d.pyd
并载入内存。其中live2d.pyd
在 windows 下使用,live2d.so
在 linux 下使用。live2d.pyi
:python 接口提示文件,仅用于在 IDE 编写时产生代码提示和补全信息。
将 package/live2d
文件夹放置在使用者 main.py
同目录下,在 main.py
中使用如 import live2d.v2
。
live2d-desktop\live2d
|-- v2
| |-- __init__.py
| |-- live2d.pyd
| `-- live2d.pyi
`-- v3
|-- __init__.py
|-- live2d.pyd
|-- live2d.pyi
`-- live2d.so
import live2d.v3 as live2d
import live2d.v2 as live2d
live2d.init()
display = (800,600)
pygame.display.set_mode(display, DOUBLEBUF|OPENGL)
# live2d.v3 还需要调用如下函数
live2d.glewInit()
live2d.setGLProperties()
Resources\Haru
|-- Haru.2048
|-- Haru.cdi3.json
|-- Haru.moc3
|-- Haru.model3.json
|-- Haru.model3.json.bak
|-- Haru.physics3.json
|-- Haru.pose3.json
|-- Haru.userdata3.json
|-- expressions
|-- motions
`-- sounds
model = live2d.LAppModel()
model.LoadModelJson("./Resources/Haru/Haru.model3.json")
model.Resize(800, 600)
# 如果鼠标点击位置是可触发动作区域,且对应动作被触发,
# 则会在动作开始播放前调用该函数
def onStartCallback(group: str, no: int):
print(f"touched and motion [{group}_{no}] is started")
# 动作播放结束后会调用该函数
def onFinishCallback():
print("motion finished")
x, y = pygame.mouse.get_pos()
model.Touch(x, y, onStartCallback, onFinishCallback)
live2d.clearBuffer()
model.Update()
live2d.dispose()
live2d.setLogEnable(False)
# 动作开始播放前调用该函数
def onStartCallback(group: str, no: int):
print(f"touched and motion [{group}_{no}] is started")
# 动作播放结束后会调用该函数
def onFinishCallback():
print("motion finished")
# 播放名称为 Idle 的动作组中第一个动作
model.StartMotion("Idle", 0, onStartCallback, onFinishCallback)
from PySide2.QtGui import QMouseEvent
import live2d.v2 as live2d
from PySide2.QtCore import QTimerEvent
from PySide2.QtWidgets import QApplication
from PySide2.QtWidgets import QOpenGLWidget
def callback():
print("motion end")
class Win(QOpenGLWidget):
model: live2d.LAppModel
def __init__(self) -> None:
super().__init__()
# self.setWindowFlags(Qt.WindowType.FramelessWindowHint | Qt.WindowType.Tool)
# self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground, True)
self.a = 0
self.resize(270, 200)
def initializeGL(self) -> None:
# 将当前窗口作为 OpenGL 的上下文
# 图形会被绘制到当前窗口
self.makeCurrent()
if live2d.LIVE2D_VERSION == 3:
live2d.glewInit()
live2d.setGLProperties()
# 创建模型
self.model = live2d.LAppModel()
# 加载模型参数
if live2d.LIVE2D_VERSION == 2:
# 适用于 2 的模型
self.model.LoadModelJson("./Resources/kasumi2/model.json")
elif live2d.LIVE2D_VERSION == 3:
# 适用于 3 的模型
self.model.LoadModelJson("./Resources/Haru/Haru.model3.json")
# 设置口型同步幅度
self.model.SetLipSyncN(5)
# 以 fps = 30 的频率进行绘图
self.startTimer(int(1000 / 30))
def resizeGL(self, w: int, h: int) -> None:
# 使模型的参数按窗口大小进行更新
self.model.Resize(w, h)
def paintGL(self) -> None:
live2d.clearBuffer()
self.model.Update()
def timerEvent(self, a0: QTimerEvent | None) -> None:
if self.a == 0: # 测试一次播放动作和回调函数
self.model.StartMotion("TapBody", 0, live2d.MotionPriority.FORCE.value, onFinishMotionHandler=callback)
self.a += 1
self.update()
def mousePressEvent(self, event: QMouseEvent) -> None:
# 传入鼠标点击位置的窗口坐标
self.model.Touch(event.pos().x(), event.pos().y());
def mouseMoveEvent(self, event: QMouseEvent) -> None:
self.model.Drag(event.pos().x(), event.pos().y())
if __name__ == "__main__":
import sys
live2d.init()
app = QApplication(sys.argv)
win = Win()
win.show()
app.exec_()
live2d.dispose()
- 克隆本仓库到本地文件夹
live2d-py
git clone [email protected]:Arkueid/live2d-py.git live2d-py
-
安装 CMake 、Visual Studio Code 和 Visual Studio 2022 Release -x86
-
用 Visual Studio Code 打开本仓库
code live2d-py
- 修改
LAppModelWrapper.cpp
同目录下的CMakeLists.txt
将下面 D:/pydk
修改为对应版本的 Python 安装目录。
# 寻找Python
set(CMAKE_PREFIX_PATH D:/pydk)
d:/pydk
的结构如下:
d:\pydk
|-- DLLs
|-- LICENSE.txt
|-- Lib
|-- NEWS.txt
|-- Scripts
|-- Tools
|-- include
|-- libs
|-- python.exe
|-- python.pdb
|-- python3.dll
|-- python310.dll
|-- python310.pdb
|-- python310_d.dll
|-- python310_d.pdb
|-- python3_d.dll
|-- python_d.exe
|-- python_d.pdb
|-- pythonw.exe
|-- pythonw.pdb
|-- pythonw_d.exe
|-- pythonw_d.pdb
`-- vcruntime140.dll
- Visual Studio Code 安装插件:
C/C++
、CMake
、CMake Tools
- 在 Visual Studio Code 中按下
Ctrl + Shift + P
打开选项面板,选择CMake: Configure
- 执行构建,输出文件为
package/live2d/live2d.pyd
。
设置 output 输出日志的编码为 utf-8。
选择构建工具 Visual Studio Community 20XX Release - x86
。如果目标平台为 x64
,则选择 Visual Studio Community 20XX Release - amd64
选择配置为 Release
当配置完毕,生成 build
文件夹后,输出如下:
构建目标选择 LAppModelWrapper
,点击 build
编译生成。
- 使用,将
package
目录下的live2d
文件夹作为Python
模块集成即可。
详见 v2 分支。