pygame里live2d的使用方法(live2d-py)

前言:

        首先,我们需要明确:

                对于pygame框架,是由SDL写出来的,而SDLOpenGL一步步写出来的。所以说,在pygame框架里使用live2d就需要pygame的OPENGL模式以及live2d-py库

        所以本篇文章主要介绍:

        (1)live2d-py库的使用方法

        (2)OpenGL与pygame的交互

        (3)部分OpenGL基础知识


目录:

前言:

live2d-py:

        ①、导入模块

        ②、初始化

        ③、实例化模型对象

        ④、加载模型

        ⑤、正常pygame循环

        ⑥、其他常用方法

        (1)、Resize,调整live2d大小

        (2)、SetScale,设置模型缩放比例

        (3)、SetAutoBreathEnable,开启/关闭 自动呼吸

        (4)、SetAutoBlinkEnable,开启/关闭 自动眨眼

        (5)、SetOffset,设置模型偏移量

        (6)、SetExpression,设置live2d表情

        (7)、SetRandomExpression,随机设置一个live2d表情

        (8)、StartMotion,设置live2d动作

        (9)、StartRandomMotion,随机设置一个live2d动作

        (10)、IsMotionFinished,判断当前动作是否完成

        (11)、ResetExpression,重新设置live2d表情为默认表情

        (12)、StopAllMotions,停止所有的动作

        ⑦、其它注意事项

        (1)、禁止/允许日志输出

        (2)、与pygame交互

OpenGL & Pygame交互

        ①、安装OpenGL:

        ②、渲染图片:

        ③、渲染文字:

                ④、注意:

         (1)、多放置

         (2)、v2模型的特殊性

实例:

后记:


live2d-py:

        首先,肯定是需要pip一下:

pip install live2d-py

        之后,我们需要知道:对于live2dv2v3之分,(大致)也就是2d3d的区别。

        区别方式就是:

                v2里面会有.moc文件;而v3里面的是.moc3文件。


        ①、导入模块

        这时候就要根据我们的模型的版本进行导入。

        如果是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:
    #这个函数会激活内部的OpenGL函数
    #其实,v2模型也能用这个函数,但最好区分一下
    live2d.glewInit()

#这时候用到了pygame的OpenGL模式
pygame.display.set_mode((1200, 800), DOUBLEBUF | OPENGL, vsync = 1)

        

        ③、实例化模型对象

        之后就是需要实例化模型对象,以此通过一些方法来控制live2d的行为。

model = live2d.LAppModel()

        之后,就可以调用这个对象里的方法控制live2d。

        

        ④、加载模型

        需要让对象知道控制的哪个live2d:

#对于v2模型,一般导入的是后缀名是(.model.json)的json文件路径
#如:
model_json_path: str = "my_v2_model.model.json"

#对于v3模型,一般导入的是后缀名是(.model3.json)的json文件路径
#如:
model_json_path: str = "my_v3_model.model3.json"

#最后加载live2d
model.LoadModelJson(model_json_path)

        ⑤、正常pygame循环

        之后就可以通过pygame的事件来进行一系列操作了。

        一般,调用的顺序就是:clearBuffer -> Update -> Draw -> flip/update

run: bool = True

while run:
    for event in pygame.event.get():
        match event.type:

            case pygame.QUIT:
                run = not run
                break

            case _:
                pass

    #其他的操作之后就要刷新live2d了
    ...

    #1、清除缓冲区
    live2d.clearBuffer()

    #2、更新live2d到缓冲区
    model.Update()

    #3、渲染live2d到屏幕
    model.Draw()

    #4、需要用的pygame刷新
    pygame.display.flip() #或者是pygame.display.update()

    #之后是其他的操作
    ...

#退出之后:
#1、结束live2d
live2d.dispose()
#2、结束pygame
pygame.quit()
#3、结束程序
exit()

        这样,就能正常显示live2d了。

        但是,可能达不到自己想要的效果,比如:大小位置动作表情之类的还没有设置,那么请看下文所讲述的。

        

        ⑥、其他常用方法

        这个对象还有好多方法来控制live2d的一些属性。

        (1)、Resize,调整live2d大小

window_width: int  = 800
window_height: int = 600

model.Resize(window_width, window_height)

        (2)、SetScale,设置模型缩放比例

live2d_scale: float = 0.8

#缩小了20%,也就是变成了原来大小的80%
model.SetScale(live2d_scale)

        (3)、SetAutoBreathEnable,开启/关闭 自动呼吸

#开启自动呼吸
model.SetAutoBreathEnable(True)

#关闭自动呼吸
model.SetAutoBreathEnable(False)

        (4)、SetAutoBlinkEnable,开启/关闭 自动眨眼

#开启自动眨眼
model.SetAutoBlinkEnable(True)

#关闭自动眨眼
model.SetAutoBlinkEnable(False)

        (5)、SetOffset,设置模型偏移量

offset_x: int = 100
offset_y: int = 100

#现在live2d会偏移原点(100, 100)
model.SetOffset(offset_x, offset_y)

        (6)、SetExpression,设置live2d表情

#这个函数的第一个参数是:字符串类型的表情ID
#这个ID可以去相应的.model.json里去查看
#进入后找到"expressions"键,里面的"name"都是表情ID

#例如:
model.SetExpression("cry")

model.SetExpression("default")

        (7)、SetRandomExpression,随机设置一个live2d表情

#单纯的随机挑选一个live2d表情
model.SetRandomExpression()

        (8)、StartMotion,设置live2d动作

#这个函数有三个主要参数,分别是:
#group: str     -> 和SetExpression类似,都是填入.model.json里面的"name"
#no: int        -> 默认为0就行
#priority: int  -> 代表这个动作的优先级,毕竟动作的发生需要时间,没有特殊需求那就1即可

#例如:
model.StartMotion("happy", 0, 1)

        (9)、StartRandomMotion,随机设置一个live2d动作

#类似于SetRandonExpression
model.StartRandomMotion()

        (10)、IsMotionFinished,判断当前动作是否完成

#若当前动作完成
print(model.IsMotionFinished()) #输出:True

#若当前动作未完成
print(model.IsMotionFinished()) #输出:False

        (11)、ResetExpression,重新设置live2d表情为默认表情

#那什么是默认的表情呢?
#就是.model.json里面Expression里的"default"表情

model.ResetExpression()

        (12)、StopAllMotions,停止所有的动作

model.StopAllMotions()

        ⑦、其它注意事项

        (1)、禁止/允许日志输出

                在正常情况下,live2d-py这个库会不断地输出日志到缓冲区,可能会扰乱我们的正常工作。那么需要调用下列函数来“禁止日志输出”

import live2d.v2 as live2d

#参数是False则禁止日志输出
#反之,允许日志输出
live2d.setLogEnable(False)

        (2)、与pygame交互

                因为使用的是pygameOpenGL模式所以pygame的图片/文字渲染就行不通了,现在需要使用OpenGL来进行操作了。


OpenGL & Pygame交互

        我们需要知道,OpenGL是一个状态机

                就是通过改变全局OpenGL的状态来进行差异化“输出”。

        OpenGL主要由三个包构成,分别是:

        -OpenGL.GL:是核心API,包含了主要函数

        -OpenGL.GLU:包含了许多被包装的实用方法

        -OpenGL.GLUT:包含了关于屏幕的创建以及基本事件

        而我们在这里只需要使用OpenGL.GL包就满足了。


        ①、安装OpenGL:

pip install PyOpenGL PyOpenGL-accelerate

        ②、渲染图片:

                我们知道,在pygame里都是以pygame.SurfaceType进行渲染的,而要在OpenGL的话需要将pygame.SurfaceType转换成字节串(bytes)来转换。

                需要注意的是,OpenGL的坐标系和pygame的坐标系不一样

                -OpenGL以中心为原点的权值/±1坐标系;

                -pygame以TopLeft为原点的数值坐标系。

                如下图:

                具体方法&讲解如下:

#导入OpenGL.GL包
#下面没见过的函数都是来自这里
from OpenGL.GL import *
import pygame

surface = pygame.image.load("image.png").convert_alpha()

#1、将surface对象转成成字节串,并保持RGB通道
texture_data: bytes = pygame.image.tostring(surface, "RGBA", 1)

#2、获得纹理id,可以看成申请一段空间
id = glGenTextures(1)

#3、告诉OpenGL,这段空间的纹理是2D纹理(图片)
glBindTexture(GL_TEXTURE_2D, id)

#4、将图片的字节串绑定到这段空间里,下面细讲
glTexImage2D(
    GL_TEXTURE_2D,
    0,
    GL_RGBA,
    surface.get_width(),
    surface.get_height(),
    0,
    GL_RGBA,
    GL_UNSIGNED_BYTE,
    texture_data
)

#5、设置参数:开启模糊但反锯齿模式(可以这么理解)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)

#6、为了防止中间可能的其他函数的干扰,需要再绑定一次
glBindTexture(GL_TEXTURE_2D, id)

#7、渲染的开始,并且通过“四边形”模式(图片)渲染
glBegin(GL_QUADS)

#8、如上图:
glTexCoord2f(0, 0); glVertex3f(x1, y1, z1) #如图,图片左下角,分别对应xyz的权值,z1=0即可
glTexCoord2f(1, 0); glVertex3f(x2, y2, z2) #如图,图片右下角,分别对应xyz的权值,z2=0即可
glTexCoord2f(1, 1); glVertex3f(x3, y3, z3) #如图,图片右上角,分别对应xyz的权值,z3=0即可
glTexCoord2f(0, 1); glVertex3f(x4, y4, z4) #如图,图片左上角,分别对应xyz的权值,z4=0即可

#9、结束渲染
glEnd()

        而这些函数,需要在pygame基本循环里去使用,就类似于pygame的blit一样。

        当然,最好不要直接用,最好把它们封装成函数或类,毕竟没必要一直生成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函数(C++解释)(来自微软)

void WINAPI glTexImage2D(
         GLenum  target, #模式,GL_TEXTURE_2D
         GLint   level,  #细节级别编号。 级别 0 是基础图像级别。
         GLint   internalformat, #纹理中颜色分量的数量,与tostring的相同,GL_RGBA
         GLsizei width,  #长度
         GLsizei height, #宽度
         GLint   border, #边框的宽度,必须为 0 或 1,为1就行。
         GLint   format, #和level一样,都选GL_RGBA
         GLenum  type,   #字节串类型(bytes)
   const GLvoid  *pixels #纹理数据,就是那个字节串
);

        

        ③、渲染文字:

                和渲染图片类似,需要注意的是:

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不能省略了!如果省略,那么文字不能正常显示了!

       ④、注意:

        一般,以上方法都是可以使用的,但真正实践的时候有复杂需求的话会出现诸多问题,有些我能解决但有些解决不了:

         (1)、多放置

                不允许多放置:放置多个时,放置的不知道为什么全是第一个。(局限在v2模型)

         (2)、v2模型的特殊性

                (仅仅)v2模型的展示时,需要在最后加一句(glUseProgram(0))来恢复设置,才能正常的放置图片/文字并显示:

run: bool = True

while run:

    #其他的操作之后就要刷新live2d了
    ...

    #1、清除缓冲区
    live2d.clearBuffer()

    #2、更新live2d到缓冲区
    model.Update()

    #3、渲染live2d到屏幕
    model.Draw()

    #4、需要用的pygame刷新
    pygame.display.flip() #或者是pygame.display.update()

    #之后是其他的操作
    ...
    
    #⭐、就是这句话
    glUseProgram(0)

#退出之后:
#1、结束live2d
live2d.dispose()
#2、结束pygame
pygame.quit()
#3、结束程序
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()

if live2d.LIVE2D_VERSION == 3:
	live2d.glewInit()

pygame.display.set_mode((1200, 800), DOUBLEBUF | OPENGL, vsync = 1)

model: live2d.LAppModel = live2d.LAppModel()
model.LoadModelJson(r"v2\kasumi2\kasumi2.model.json")
model.Resize(1200, 800)
model.SetAutoBlinkEnable(True)
model.SetAutoBreathEnable(True)
model.StartRandomMotion()

back = Live2D.render(pygame.image.load(r"beach1.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()

 

后记:

        文章有问题还请大家指正

        live2d-py的作者是国人,他在BiliBili上有号,也发过视频。

kirakiradokidoki⭐~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值