天津储鑫盛钢材现货供应商 发表于 2024-8-18 01:31:53

如何在前端网页实现live2d的动态效果

React如何在前端网页实现live2d的动态效果

业务需求:
因为公司必要做机器人相干的业务,主要是谈天形式的内容,所以必要一个假造的卡通形象。而且为了更直观的展示用户和机器人对话的状态,该live2d动画的嘴型必要根据播放的内容来动。
相干技能原理:

1. 网页上使用live2d的相干技能原理

Live2D是一种先辈的技能,它允许艺术家和开发者创建具有高度表现力的二维脚色动画。这些脚色可以根据用户的交互进行动态相应,从而提供一种非常生动和吸引人的用户体验。Live2D广泛应用于游戏、假造偶像、广告和移动应用程序中。
Live2D由日本Cybernoids公司开发,旨在创造出能够进行平滑动作和心情变化的二维脚色,而不必要传统的帧动画。这是通过对二维图像进行切割和变形来实现的,使得脚色能够以看似三维的方式移动和表达情感。

[*]WebGL和Canvas:Live2D在网页上的实现依赖于WebGL(一个JavaScript API,用于在任何兼容的网页浏览器中渲染高性能的交互式3D和2D图形,而不必要使用插件)和Canvas元素(提供了一个用于绘制图形的2D环境)。通过这些技能,开发者可以在用户的浏览器中直接渲染Live2D模子。
[*]Live2D Cubism SDK:为了在网页上使用Live2D,开发者必要利用Live2D Cubism SDK for Web。这个SDK提供了一系列的API,允许开发者加载、渲染和控制Live2D模子。它处置惩罚模子的动画、变形和用户交互。
[*]模子和动画数据:Live2D模子通常存储在特定格式(如.moc或.moc3)的文件中,这些文件包罗了脚色的图形和骨架信息。动画数据(如心情和动作)通常以JSON或其他格式存储,可以通过SDK的API来播放。
[*]交互性:通过JavaScript和SDK的API,开发者可以实现模子对鼠标移动、点击等用户交互的相应。例如,让脚色的眼睛跟随鼠标移动,或者在点击时播放特定的动画。
[*]性能优化:为了确保流畅的用户体验,特殊是在性能有限的设备上,Live2D在网页上的实现必要进行性能优化。这包罗合理控制动画的帧率、减少不必要的资源加载和使用WebGL的高效特性。
2. 笔墨转语音 TTS

本项目使用的是讯飞的TTS在线笔墨转语音功能。使用Websocket实现客户端和讯飞服务器之间的通讯。总体逻辑就是客户端把必要播报的笔墨发送给讯飞的服务端,服务端颠末处置惩罚后,把笔墨转成了二进制的音频流返回给客户端,然后客户端使用适当的方法播放解析后的音频数据,完成从笔墨到语音的整个过程。
不过这项功能不是本次的内容的重点,另外详解。
3. 语音转笔墨 IAT

不是本次的内容的重点,另外详解。
项目实现

1. 引入live2d相干库

Cubism Web是一个基于Web技能的软件开发工具包,用于创建Live2D。Cubism Web提供了一组工具和库,使开发职员可以轻松地将Live2D模子集成到Web应用程序中。它支持多种平台和框架,包罗HTML5、JavaScript和CSS,因此可以在各种设备和浏览器上运行。
官网如下:
https://www.live2d.com/zh-CHS/sdk/download/web/
下载Cubism SDK文件:
https://img-blog.csdnimg.cn/img_convert/692c5e6f3fa65a60b15cccfcc790d993.png
解压后的目录如下,此中Core焦点库和Framework框架库是我们所必要的。
https://img-blog.csdnimg.cn/img_convert/56695aae98d0b29e4fbef1280b1b7dc2.png

[*]Core
将上述展示的Core文件夹复制到项目标public文件下。
https://img-blog.csdnimg.cn/img_convert/11445c0e508ba4c64d5feafb968047ed.png
同时,在public文件夹下面的index.html中加上如下代码:
<script src = "%PUBLIC_URL%/Core/live2dcubismcore.js"></script>
https://img-blog.csdnimg.cn/img_convert/24b39da27be97cadada76062c82a03af.png

[*]framework
同理,将上述展示的Framework移动到项目标src文件夹下。注意不是pubilc文件夹下了。直接放到src文件夹即可,或者其他目录也行,引用的时候知道地点就行。
https://img-blog.csdnimg.cn/img_convert/1dee759687165282102f2b43784e8805.png

[*]Resources
Resources文件夹下放的是live2d的模子,具体模子的内容可以去官网下载简单的Model,也可以根据必要找计划师去计划你必要的Modal。笔者这边只是展示了项目里面一个Modal里面的内容。
https://img-blog.csdnimg.cn/img_convert/8f5ec6549e77e7b967e4b244ad0d095d.png
官方提供的Modal地点:
https://www.live2d.com/zh-CHS/sdk/download/web/

[*]Render
以上文件预备好后,可以做页面渲染相干的工作了。根据官方给的Demo,如下图所示:
https://img-blog.csdnimg.cn/img_convert/1f0a65da861197285296db8c1e066b5d.png
根据Demo中main.ts中的样例可以推断出,这段代码用于实现Live2D模子的初始化、渲染和相应浏览器事件。

[*]导入必要的模块:首先,代码通过import语句导入了LAppDelegate、LAppDefine和LAppGlManager等模块,这些模块包罗了Live2D模子渲染所需的各种功能和配置。
[*]浏览器加载完成后的处置惩罚:通过监听load事件,当浏览器完成加载后,执行初始化WebGL和创建应用实例的操作。这里涉及到两个关键的步骤:


[*]检查LAppGlManager的实例是否存在,以及调用LAppDelegate的initialize方法进行初始化。这些操作确保了WebGL环境的正确设置和应用的初始化。
[*]调用LAppDelegate.getInstance().run()启动Live2D模子的渲染循环。

[*]浏览器关闭前的处置惩罚:监听beforeunload事件,当浏览器预备关闭前,开释LAppDelegate的实例,以确保资源被正确清算。
[*]浏览器窗口尺寸变化的处置惩罚:监听resize事件,当浏览器窗口尺寸发生变化时,根据LAppDefine.CanvasSize的配置决定是否调用LAppDelegate.getInstance().onResize()方法来调解Live2D模子的尺寸。这保证了模子在差别尺寸的屏幕上都能正确表现。
/**
* Copyright(c) Live2D Inc. All rights reserved.
*
* Use of this source code is governed by the Live2D Open Software license
* that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html.
*/

import { LAppDelegate } from './lappdelegate';
import * as LAppDefine from './lappdefine';
import { LAppGlManager } from './lappglmanager';

/**
* ブラウザロード後の処理
*/
window.addEventListener(
'load',
(): void => {
    // Initialize WebGL and create the application instance
    if (
      !LAppGlManager.getInstance() ||
      !LAppDelegate.getInstance().initialize()
    ) {
      return;
    }

    LAppDelegate.getInstance().run();
},
{ passive: true }
);

/**
* 終了時の処理
*/
window.addEventListener(
'beforeunload',
(): void => LAppDelegate.releaseInstance(),
{ passive: true }
);

/**
* Process when changing screen size.
*/
window.addEventListener(
'resize',
() => {
    if (LAppDefine.CanvasSize === 'auto') {
      LAppDelegate.getInstance().onResize();
    }
},
{ passive: true }
);
而我们必要做的,则是把Demo中除了main.ts的其他文件Copy到项目中在自有的项目中,Render的相干目录如图所示:
https://img-blog.csdnimg.cn/img_convert/849570bb3d5920febc5dc019d157cb7c.png
2. 用React转写main.ts

然后main.ts实现的逻辑,用React的方式进行重构,在index.js中。本文只展示核定代码,因为实际情况会根据需求,增长很多其他的业务实现代码,好比笔者最初的需求是增长live2d的收听、播放等动画效果,所以必要额外传入sourceBuffer等数据。

[*]导入依赖:首先,代码导入了React相干的hooks(如useEffect, useRef, useMemo等),以及Live2D相干的配置和管理模块(LAppDelegate, LAppLive2DManager, LAppDefine等)。
[*]组件结构:ReactLive2d组件通过return语句返回一个包罗元素的结构,这个元素被指定了id=“live2d”,以及动态计算的width和height属性。这个就是用来渲染Live2D动画的画布。
[*]初始化和配置:


[*]在组件挂载时(useEffect),根据传入的props(如live2dModelId)动态设置Live2D模子的目录。
[*]如果满足条件(非移动设备或允许在移动设备上表现),则初始化Live2D应用(LAppDelegate.getInstance().initialize())并运行(LAppDelegate.getInstance().run())。

[*]音频处置惩罚:组件还处置惩罚了音频输入(通过audioContext和source),并将音频数据通过rmsRef(一个自定义的音频处置惩罚引用)毗连到Live2D动画,大概用于根据音频数据动态调解Live2D动画的心情或动作。
[*]清算资源:在组件卸载时,清算资源,如烧毁rmsRef引用和开释Live2D应用实例。
import React, { useEffect, useRef, useMemo, useCallback } from 'react';
import AudioRMS from '@/utils/AudioProcess';
import { Button } from 'antd-mobile';

import { LAppDelegate } from './live2dConfig/lappdelegate';
import { LAppLive2DManager } from './live2dConfig/lapplive2dmanager';
import * as LAppDefine from './live2dConfig/lappdefine';
import './index.css';


function ReactLive2d(props, ref) {
const { width, height, audioContext, source, live2dModelId, isTTSPlaying } = props;
const rmsRef = useRef(null);

// setModelDir()用于根据外部传的Model Id动态的引入模型,如果没有这个需求可以就写死Model的逻辑即可
useEffect(() => {
    // 根据外部传入的modelId,动态设置model
    LAppDefine.lappdefineSet.setModelDir();
    if (!navigator.userAgent.match(/mobile/i)) {
      if (LAppDelegate.getInstance().initialize()) {
      LAppDelegate.getInstance().run();
      }
    }
    return () => {
      rmsRef.current && rmsRef.current.destroy && rmsRef.current.destroy();
      LAppDelegate.releaseInstance();
    }
}, []);

const configRmsWithAudio = () => {
    if (source) {
      source.connect(rmsRef.current.input)
    }
}
useEffect(() => {
    configRmsWithAudio();
}, )

const onData = useCallback((data) => {
    LAppLive2DManager.getInstance().setRmsToValue(data)
}, []);

useEffect(() => {
    if (audioContext) {
      if (!rmsRef.current) {
      rmsRef.current = AudioRMS(audioContext, 'sqr')
      }
      if (isTTSPlaying) {
      rmsRef.current.on('data', onData)
      } else {
      rmsRef.current.off('data', onData)
      }
    }
}, )

const canvasWidth = useMemo(() => {
    if (!window.matchMedia("(orientation: landscape)").matches) {
      return document.body.clientWidth;
    }
    return document.body.clientWidth * 0.3;
}, [])

const canvasHeight = useMemo(() => {
    if (!window.matchMedia("(orientation: landscape)").matches) {
      return document.body.clientHeight * 0.3;
    }
    return document.body.clientHeight * 0.6;
}, [])


return (
    <div className='live2d-container' >
      <div className='live2d-canvas'>
      <canvas
          id="live2d"
          width={width ? width : canvasWidth}
          height={height ? height : canvasHeight}
          className="live2d"
          color="#f5f5f9"
      />
      </div>
    </div>
)
}

export default ReactLive2d;
在上述代码通过React组件设置了一个元素,并通过Live2D的JavaScript API初始化和控制Live2D模子的加载、表现和动作,实现了在Web页面上展示Live2D动画形象的功能。
但是此中有些代码是根据实际业务增长的,不属于原本demo的逻辑,这边做一些简述,防止读者混淆。
//
const onData = useCallback((data) => {
    LAppLive2DManager.getInstance().setRmsToValue(data)
}, []);
// AudioRMS()用于处理音频的技术,实现音频信号的实时分析和处理
// 这段代码的目的是在确认音频源 source 存在的情况下,将它连接到通过 rmsRef 引用的目标的 input 上。
// 这样的操作在音频处理、音频可视化等场景中非常常见,比如连接一个音频源到一个用于计算实时音频信号强度的节点上。
useEffect(() => {
    if (audioContext) {
      if (!rmsRef.current) {
      rmsRef.current = AudioRMS(audioContext, 'sqr')
      }
      if (isTTSPlaying) {
      rmsRef.current.on('data', onData)
      } else {
      rmsRef.current.off('data', onData)
      }
    }
}, )

// 。它调用source的connect方法,将音频源连接到rmsRef.current.input。
// 这里,rmsRef是一个引用(通过useRef创建),指向RMS处理器的实例,而rmsRef.current.input是RMS处理器的输入端。
const configRmsWithAudio = () => {
    if (source) {
      source.connect(rmsRef.current.input)
    }
}
// 这段代码的目的是确保每当音频上下文(audioContext)或音频源(source)发生变化时,都会更新音频源与RMS处理器之间的连接。
useEffect(() => {
    configRmsWithAudio();
}, )
3. 引用

上述工作做完后,引用则变得很简单了。
import ReactLive2d from '...'

...

// 以下参数根据实际情况自行填写即可
<ReactLive2d
    source={bufferSource}
    live2dModelId={'LH1'}
    isTTSPlaying={iatStatus === 'ttsPlaying'}
    audioContext={ttsRecorder.audioContext}
/>
}, )
3. 引用

上述工作做完后,引用则变得很简单了。
import ReactLive2d from '...'

...

// 以下参数根据实际情况自行填写即可
<ReactLive2d
    source={bufferSource}
    live2dModelId={'LH1'}
    isTTSPlaying={iatStatus === 'ttsPlaying'}
    audioContext={ttsRecorder.audioContext}
/>
然后运行引用<ReactLive2d/>的界面上,便可以看到live2d的效果。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 如何在前端网页实现live2d的动态效果