)
前言首先我們需要明確對于pygame框架是由SDL寫出來的而SDL是OpenGL一步步寫出來的。所以說在pygame框架里使用live2d就需要pygame的OPENGL模式以及l(fā)ive2d-py庫。所以本篇文章主要介紹1live2d-py庫的使用方法2OpenGL與pygame的交互已更新3部分OpenGL基礎(chǔ)知識目錄前言live2d-py①、導(dǎo)入模塊②、初始化③、實例化模型對象④、加載模型⑤、正常pygame循環(huán)⑥、其他常用方法1、Resize調(diào)整live2d大小2、SetScale設(shè)置模型縮放比例3、SetAutoBreathEnable開啟/關(guān)閉 自動呼吸4、SetAutoBlinkEnable開啟/關(guān)閉 自動眨眼5、SetOffset設(shè)置模型偏移量6、SetExpression設(shè)置live2d表情7、SetRandomExpression隨機(jī)設(shè)置一個live2d表情8、StartMotion設(shè)置live2d動作9、StartRandomMotion隨機(jī)設(shè)置一個live2d動作10、IsMotionFinished判斷當(dāng)前動作是否完成11、ResetExpression重新設(shè)置live2d表情為默認(rèn)表情12、StopAllMotions停止所有的動作⑦、其它注意事項1、禁止/允許日志輸出2、與pygame交互OpenGL Pygame交互①、安裝OpenGL②、渲染圖片新版1、導(dǎo)入圖片類2、使用圖片類3、放置舊版③、渲染文字④、注意1、多放置2、v2模型的特殊性3、V3模型的特殊性實例V2新版舊版實例V3新版舊版后記live2d-py首先肯定是需要pip一下pip install live2d-py之后我們需要知道對于live2d有v2與v3之分大致也就是2d與3d的區(qū)別。區(qū)別方式就是v2里面會有.moc文件而v3里面的是.moc3文件。①、導(dǎo)入模塊這時候就要根據(jù)我們的模型的版本進(jìn)行導(dǎo)入。如果是v2模型import live2d.v2 as live2d import pygame from pygame.locals import * #這個之后講暫時未用到 from OpenGL.GL import *反之是v3模型import live2d.v3 as live2d import pygame from pygame.locals import * #這個之后講暫時未用到 from OpenGL.GL import *不管是什么版本的模型之后的操作類似但不完全相同。②、初始化之后就是初始化#以pygame的交互為例 pygame.init() live2d.init() #但如果是對于v3模型需要加一句 if live2d.LIVE2D_VERSION 3: #這個函數(shù)會激活內(nèi)部的OpenGL函數(shù) #其實v2模型也能用這個函數(shù)但最好區(qū)分一下 live2d.glewInit() #這時候用到了pygame的OpenGL模式 pygame.display.set_mode((1200, 800), DOUBLEBUF | OPENGL, vsync 1)③、實例化模型對象之后就是需要實例化模型對象以此通過一些方法來控制live2d的行為。model live2d.LAppModel()之后就可以調(diào)用這個對象里的方法控制live2d。④、加載模型需要讓對象知道控制的哪個live2d#對于v2模型一般導(dǎo)入的是后綴名是(.model.json)的json文件路徑 #如 model_json_path: str my_v2_model.model.json #對于v3模型一般導(dǎo)入的是后綴名是(.model3.json)的json文件路徑 #如 model_json_path: str my_v3_model.model3.json #最后加載live2d model.LoadModelJson(model_json_path)⑤、正常pygame循環(huán)之后就可以通過pygame的事件來進(jìn)行一系列操作了。一般調(diào)用的順序就是clearBuffer - Update - Draw - flip/updaterun: bool True while run: for event in pygame.event.get(): match event.type: case pygame.QUIT: run not run break case _: pass #其他的操作之后就要刷新live2d了 ... #1、清除緩沖區(qū) live2d.clearBuffer() #2、更新live2d到緩沖區(qū) model.Update() #3、渲染live2d到屏幕 model.Draw() #4、需要用的pygame刷新 pygame.display.flip() #或者是pygame.display.update() #之后是其他的操作 ... #退出之后 #1、結(jié)束live2d live2d.dispose() #2、結(jié)束pygame pygame.quit() #3、結(jié)束程序 exit()這樣就能正常顯示live2d了。但是可能達(dá)不到自己想要的效果比如大小、位置、動作、表情之類的還沒有設(shè)置那么請看下文所講述的。⑥、其他常用方法這個對象還有好多方法來控制live2d的一些屬性。1、Resize調(diào)整live2d大小window_width: int 800 window_height: int 600 model.Resize(window_width, window_height)2、SetScale設(shè)置模型縮放比例live2d_scale: float 0.8 #縮小了20%也就是變成了原來大小的80% model.SetScale(live2d_scale)3、SetAutoBreathEnable開啟/關(guān)閉 自動呼吸#開啟自動呼吸 model.SetAutoBreathEnable(True) #關(guān)閉自動呼吸 model.SetAutoBreathEnable(False)4、SetAutoBlinkEnable開啟/關(guān)閉 自動眨眼#開啟自動眨眼 model.SetAutoBlinkEnable(True) #關(guān)閉自動眨眼 model.SetAutoBlinkEnable(False)5、SetOffset設(shè)置模型偏移量offset_x: int 100 offset_y: int 100 #現(xiàn)在live2d會偏移原點(diǎn)(100, 100) model.SetOffset(offset_x, offset_y)6、SetExpression設(shè)置live2d表情#這個函數(shù)的第一個參數(shù)是字符串類型的表情ID #這個ID可以去相應(yīng)的.model.json里去查看 #進(jìn)入后找到expressions鍵里面的name都是表情ID #例如 model.SetExpression(cry) model.SetExpression(default)7、SetRandomExpression隨機(jī)設(shè)置一個live2d表情#單純的隨機(jī)挑選一個live2d表情 model.SetRandomExpression()8、StartMotion設(shè)置live2d動作#這個函數(shù)有三個主要參數(shù)分別是 #group: str - 和SetExpression類似都是填入.model.json里面的name #no: int - 默認(rèn)為0就行 #priority: int - 代表這個動作的優(yōu)先級畢竟動作的發(fā)生需要時間沒有特殊需求那就1即可 #例如 model.StartMotion(happy, 0, 1)9、StartRandomMotion隨機(jī)設(shè)置一個live2d動作#類似于SetRandonExpression model.StartRandomMotion()10、IsMotionFinished判斷當(dāng)前動作是否完成#若當(dāng)前動作完成 print(model.IsMotionFinished()) #輸出True #若當(dāng)前動作未完成 print(model.IsMotionFinished()) #輸出False11、ResetExpression重新設(shè)置live2d表情為默認(rèn)表情#那什么是默認(rèn)的表情呢 #就是.model.json里面Expression里的default表情 model.ResetExpression()12、StopAllMotions停止所有的動作model.StopAllMotions()⑦、其它注意事項1、禁止/允許日志輸出在正常情況下live2d-py這個庫會不斷地輸出日志到緩沖區(qū)可能會擾亂我們的正常工作。那么需要調(diào)用下列函數(shù)來“禁止日志輸出”import live2d.v2 as live2d #參數(shù)是False則禁止日志輸出 #反之允許日志輸出 live2d.setLogEnable(False)2、與pygame交互因為使用的是pygame的OpenGL模式所以pygame的圖片/文字渲染就行不通了現(xiàn)在需要使用OpenGL來進(jìn)行操作了。更新文章現(xiàn)有內(nèi)置圖片放置方法請直跳新版OpenGL Pygame交互我們需要知道OpenGL是一個狀態(tài)機(jī)就是通過改變?nèi)諳penGL的狀態(tài)來進(jìn)行差異化“輸出”。OpenGL主要由三個包構(gòu)成分別是-OpenGL.GL是核心API包含了主要函數(shù)-OpenGL.GLU包含了許多被包裝的實用方法-OpenGL.GLUT包含了關(guān)于屏幕的創(chuàng)建以及基本事件而我們在這里只需要使用OpenGL.GL包就滿足了。①、安裝OpenGLpip install PyOpenGL PyOpenGL-accelerate②、渲染圖片現(xiàn)在live2d-py的最新版本“0.5.4”內(nèi)置了圖片放置方法比我之前自己琢磨的方法更加靠譜且快速請忽略舊版內(nèi)容直接學(xué)習(xí)新版方法即可。新版1、導(dǎo)入圖片類from live2d.utils.image import Image2、使用圖片類#這個函數(shù)就一個參數(shù)代表路徑 my_img: Image Image(你的圖片的路徑) #例如在相對路徑有個圖片叫“img.png” my_img: Image Image(img.png)3、放置#官方案例節(jié)選 ... running True while True: for event in pygame.event.get(): if event.type pygame.QUIT: running False break if event.type pygame.MOUSEMOTION: model.Drag(*pygame.mouse.get_pos()) if not running: break live2d.clearBuffer() #就在這里放置 my_img.Draw() model.Update() model.Draw() pygame.display.flip() ...舊版我們知道在pygame里都是以pygame.SurfaceType進(jìn)行渲染的而要在OpenGL的話需要將pygame.SurfaceType轉(zhuǎn)換成字節(jié)串bytes來轉(zhuǎn)換。需要注意的是OpenGL的坐標(biāo)系和pygame的坐標(biāo)系不一樣-OpenGL是以中心為原點(diǎn)的權(quán)值/±1坐標(biāo)系-pygame是以TopLeft為原點(diǎn)的數(shù)值坐標(biāo)系。如下圖具體方法講解如下#導(dǎo)入OpenGL.GL包 #下面沒見過的函數(shù)都是來自這里 from OpenGL.GL import * import pygame surface pygame.image.load(image.png).convert_alpha() #1、將surface對象轉(zhuǎn)成成字節(jié)串并保持RGB通道 texture_data: bytes pygame.image.tostring(surface, RGBA, 1) #2、獲得紋理id可以看成申請一段空間 id glGenTextures(1) #3、告訴OpenGL這段空間的紋理是2D紋理圖片 glBindTexture(GL_TEXTURE_2D, id) #4、將圖片的字節(jié)串綁定到這段空間里下面細(xì)講 glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, surface.get_width(), surface.get_height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, texture_data ) #5、設(shè)置參數(shù)開啟模糊但反鋸齒模式可以這么理解 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) #6、為了防止中間可能的其他函數(shù)的干擾需要再綁定一次 glBindTexture(GL_TEXTURE_2D, id) #7、渲染的開始并且通過“四邊形”模式圖片渲染 glBegin(GL_QUADS) #8、如上圖 glTexCoord2f(0, 0); glVertex3f(x1, y1, z1) #如圖圖片左下角分別對應(yīng)xyz的權(quán)值z10即可 glTexCoord2f(1, 0); glVertex3f(x2, y2, z2) #如圖圖片右下角分別對應(yīng)xyz的權(quán)值z20即可 glTexCoord2f(1, 1); glVertex3f(x3, y3, z3) #如圖圖片右上角分別對應(yīng)xyz的權(quán)值z30即可 glTexCoord2f(0, 1); glVertex3f(x4, y4, z4) #如圖圖片左上角分別對應(yīng)xyz的權(quán)值z40即可 #9、結(jié)束渲染 glEnd()而這些函數(shù)需要在pygame基本循環(huán)里去使用就類似于pygame的blit一樣。當(dāng)然最好不要直接用最好把它們封裝成函數(shù)或類畢竟沒必要一直生成id直接一個變量保存下來就行。例如class Live2D(object): staticmethod def render(surface: pygame.SurfaceType) - object: texture_data: bytes pygame.image.tostring(surface, RGBA, 1) id: object glGenTextures(1) glBindTexture(GL_TEXTURE_2D, id) glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, surface.get_width(), surface.get_height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, texture_data ) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) return id staticmethod def blit(id: object, *args: tuple[tuple[3], tuple[3], tuple[3], tuple[3]]) - None: glBindTexture(GL_TEXTURE_2D, id) glBegin(GL_QUADS) glTexCoord2f(0, 0); glVertex3f(*args[3]) glTexCoord2f(1, 0); glVertex3f(*args[1]) glTexCoord2f(1, 1); glVertex3f(*args[2]) glTexCoord2f(0, 1); glVertex3f(*args[0]) glEnd()其中對于glTexImage2D函數(shù)C解釋來自微軟void WINAPI glTexImage2D( GLenum target, #模式GL_TEXTURE_2D GLint level, #細(xì)節(jié)級別編號。 級別 0 是基礎(chǔ)圖像級別。 GLint internalformat, #紋理中顏色分量的數(shù)量與tostring的相同,GL_RGBA GLsizei width, #長度 GLsizei height, #寬度 GLint border, #邊框的寬度必須為 0 或 1為1就行。 GLint format, #和level一樣都選GL_RGBA GLenum type, #字節(jié)串類型bytes const GLvoid *pixels #紋理數(shù)據(jù)就是那個字節(jié)串 );③、渲染文字和渲染圖片類似需要注意的是back_color (255, 255, 255) font_color (0, 0, 0) text_surface pygame.font.SysFont(幼圓, 36).render(Hello, True, font_color, back_color) #注意這里的back_color不能省略了如果省略那么文字不能正常顯示了④、注意新版無需閱讀此處一般以上方法都是可以使用的但真正實踐的時候有復(fù)雜需求的話會出現(xiàn)諸多問題有些我能解決但有些解決不了1、多放置新版已解決不允許多放置放置多個時放置的不知道為什么全是第一個。局限在v2模型2、v2模型的特殊性僅僅在v2模型的展示時需要在最后加一句glUseProgram(0)來恢復(fù)設(shè)置才能正常的放置圖片/文字并顯示run: bool True while run: #其他的操作之后就要刷新live2d了 ... #1、清除緩沖區(qū) live2d.clearBuffer() #2、加載圖片 Live2D.blit(back, *back_pos) #3、更新live2d到緩沖區(qū) model.Update() #4、渲染live2d到屏幕 model.Draw() #5、需要用的pygame刷新 pygame.display.flip() #或者是pygame.display.update() #之后是其他的操作 ... #?、就是這句話 glUseProgram(0) #退出之后 #1、結(jié)束live2d live2d.dispose() #2、結(jié)束pygame pygame.quit() #3、結(jié)束程序 exit()3、V3模型的特殊性僅僅在v3模型的展示時需要在加載圖片前加一句glEnable(GL_TEXTURE_2D)才能正常的放置圖片/文字并顯示run: bool True while run: #其他的操作之后就要刷新live2d了 ... #1、清除緩沖區(qū) live2d.clearBuffer() #?、就是這句話 glEnable(GL_TEXTURE_2D) #2、加載圖片 Live2D.blit(back, *back_pos) #3、更新live2d到緩沖區(qū) model.Update() #4、渲染live2d到屏幕 model.Draw() #5、需要用的pygame刷新 pygame.display.flip() #或者是pygame.display.update() #之后是其他的操作 ... #而這句話不能有了 #glUseProgram(0) #退出之后 #1、結(jié)束live2d live2d.dispose() #2、結(jié)束pygame pygame.quit() #3、結(jié)束程序 exit()?如果大家能解決的話一定要發(fā)出來造福大家啊實例V2最后就舉個完整的實例來結(jié)束文章下面的全部上面都出現(xiàn)過新版# -*- coding: utf-8 -*- # -*- file: live2d_test.py -*- import pygame import live2d.v2 as live2d from pygame.locals import * from live2d.utils.image import Image #導(dǎo)入新版的圖片模塊 live2d.setLogEnable(False) pygame.init() live2d.init() pygame.display.set_mode((1200, 800), DOUBLEBUF | OPENGL, vsync 1) model: live2d.LAppModel live2d.LAppModel() model.LoadModelJson(rv2\kasumi2\kasumi2.model.json) model.Resize(1200, 800) model.SetAutoBlinkEnable(True) model.SetAutoBreathEnable(True) model.StartRandomMotion() #創(chuàng)建圖片對象 back: Image Image(beach1.jpg) run: bool True while run: for event in pygame.event.get(): if event.type pygame.QUIT: run not run break live2d.clearBuffer() #放置圖片 back.Draw() model.Update() model.Draw() pygame.display.flip() live2d.dispose() pygame.quit() exit()舊版# -*- coding: utf-8 -*- # -*- file: live2d_test.py -*- import live2d.v2 as live2d import pygame from pygame.locals import * from OpenGL.GL import * class Live2D(object): staticmethod def render(surface: pygame.SurfaceType) - object: texture_data pygame.image.tostring(surface, RGBA, 1) id: object glGenTextures(1) glBindTexture(GL_TEXTURE_2D, id) glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, surface.get_width(), surface.get_height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, texture_data ) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) return id staticmethod def blit(id: object, *args: tuple[tuple[3], tuple[3], tuple[3], tuple[3]]) - None: glBindTexture(GL_TEXTURE_2D, id) glBegin(GL_QUADS) glTexCoord2f(0, 0); glVertex3f(*args[3]) glTexCoord2f(1, 0); glVertex3f(*args[1]) glTexCoord2f(1, 1); glVertex3f(*args[2]) glTexCoord2f(0, 1); glVertex3f(*args[0]) glEnd() live2d.setLogEnable(False) pygame.init() live2d.init() pygame.display.set_mode((1200, 800), DOUBLEBUF | OPENGL, vsync 1) model: live2d.LAppModel live2d.LAppModel() model.LoadModelJson(rv2\kasumi2\kasumi2.model.json) model.Resize(1200, 800) model.SetAutoBlinkEnable(True) model.SetAutoBreathEnable(True) model.StartRandomMotion() back Live2D.render(pygame.image.load(rbeach1.jpg).convert_alpha()) back_pos ((-1.0, 1.0, 0), (1.0, -1.0, 0), (1.0, 1.0, 0), (-1.0, -1.0, 0)) run: bool True while run: for event in pygame.event.get(): if event.type pygame.QUIT: run not run break live2d.clearBuffer() Live2D.blit(back, *back_pos) model.Update() model.Draw() pygame.display.flip() if live2d.LIVE2D_VERSION 2: glUseProgram(0) live2d.dispose() pygame.quit() exit()實例V3新版# -*- coding: utf-8 -*- # -*- file: live2d_test.py -*- import pygame import live2d.v3 as live2d from pygame.locals import * from live2d.utils.image import Image #導(dǎo)入新版的圖片模塊 live2d.setLogEnable(False) pygame.init() live2d.init() pygame.display.set_mode((1200, 800), DOUBLEBUF | OPENGL, vsync 1) if live2d.LIVE2D_VERSION 3: #注意此處最好使用新版的live2d.glInit()來代替舊版的live2d.glewInit() live2d.glInit() model: live2d.LAppModel live2d.LAppModel() model.LoadModelJson(rv3\Mao\Mao.model3.json) model.Resize(1200, 800) model.SetAutoBlinkEnable(True) model.SetAutoBreathEnable(True) model.StartRandomMotion() #創(chuàng)建圖片對象 back: Image Image(beach1.jpg) run: bool True while run: for event in pygame.event.get(): if event.type pygame.QUIT: run not run break live2d.clearBuffer() #放置圖片 back.Draw() model.Update() model.Draw() pygame.display.flip() live2d.dispose() pygame.quit() exit()舊版# -*- coding: utf-8 -*- # -*- file: live2d_test.py -*- import live2d.v3 as live2d import pygame from pygame.locals import * from OpenGL.GL import * class Live2D(object): staticmethod def render(surface: pygame.SurfaceType) - object: texture_data pygame.image.tostring(surface, RGBA, 1) id: object glGenTextures(1) glBindTexture(GL_TEXTURE_2D, id) glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, surface.get_width(), surface.get_height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, texture_data ) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) return id staticmethod def blit(id: object, *args: tuple[tuple[3], tuple[3], tuple[3], tuple[3]]) - None: glBindTexture(GL_TEXTURE_2D, id) glBegin(GL_QUADS) glTexCoord2f(0, 0); glVertex3f(*args[3]) glTexCoord2f(1, 0); glVertex3f(*args[1]) glTexCoord2f(1, 1); glVertex3f(*args[2]) glTexCoord2f(0, 1); glVertex3f(*args[0]) glEnd() live2d.setLogEnable(False) pygame.init() live2d.init() pygame.display.set_mode((1200, 800), DOUBLEBUF | OPENGL, vsync 1) if live2d.LIVE2D_VERSION 3: live2d.glewInit() model: live2d.LAppModel live2d.LAppModel() model.LoadModelJson(rResources\v3\Mao\Mao.model3.json) model.Resize(1200, 800) model.SetAutoBlinkEnable(True) model.SetAutoBreathEnable(True) model.StartRandomMotion() back Live2D.render(pygame.image.load(rbeach1.jpg).convert_alpha()) back_pos ((-1.0, 1.0, 0), (1.0, -1.0, 0), (1.0, 1.0, 0), (-1.0, -1.0, 0)) run: bool True while run: for event in pygame.event.get(): if event.type pygame.QUIT: run not run break live2d.clearBuffer() glEnable(GL_TEXTURE_2D) Live2D.blit(back, *back_pos) model.Update() model.Draw() pygame.display.flip() live2d.dispose() pygame.quit() exit()后記文章有問題還請大家指正。live2d-py項目是國人發(fā)起的作者在BiliBili上有賬號。文章更新時間2025.10.01kirakiradokidoki?~