接上篇文章

Live2D(WebSDK 4.X)网页看板娘设置(一)

欢迎大家阅读本篇教程

该篇教程为进阶版的看板娘设置教程,阅读完后可以极大程度的自定义你的看板娘项目。

教程内容:

  • 去掉canvas中的背景图案和切换模型按钮,并将背景设置为透明
  • 新增配置类,对需要自定义的属性进行修改,同时在模型中新建mapper
  • 设置模型放大倍率
  • 修改鼠标交互方式
  • 适配模型的控制属性,自定义模型加载的位置
  • 模块化该项目

1.修改canvas绘制的内容

打开【Sample\TypeScript\Demo\src\lappview.ts】文件,定位至以下位置,将我们不需要的功能注释掉。

定位到initializeSprite()函数

  /*** 执行图像初始化*/public initializeSprite(): void{let width: number = canvas.width;let height: number = canvas.height;let textureManager = LAppDelegate.getInstance().getTextureManager();const resourcesPath = LAppDefine.ResourcesPath;let imageName: string = "";//注释掉所有图片加载方法/** // 背景画像初期化imageName = LAppDefine.BackImageName;// 创建回调函数,因为它是异步的let initBackGroundTexture = (textureInfo: TextureInfo): void =>{let x: number = width * 0.5;let y: number = height * 0.5;let fwidth = textureInfo.width * 2.0;let fheight = height * 0.95;this._back = new LAppSprite(x, y, fwidth, fheight, textureInfo.id);};//将背景图片的注释掉textureManager.createTextureFromPngFile(resourcesPath + imageName, false, initBackGroundTexture);// 歯車画像初期化imageName = LAppDefine.GearImageName;let initGearTexture = (textureInfo: TextureInfo): void =>{let x = width - textureInfo.width * 0.5;let y = height - textureInfo.height * 0.5;let fwidth = textureInfo.width;let fheight = textureInfo.height;this._gear = new LAppSprite(x, y, fwidth, fheight, textureInfo.id);};textureManager.createTextureFromPngFile(resourcesPath + imageName, false, initGearTexture);
*/-------省略其他代码-------}

onTouchesEnded函数

public onTouchesEnded(pointX: number, pointY: number): void{// 触摸结束let live2DManager: LAppLive2DManager = LAppLive2DManager.getInstance();live2DManager.onDrag(0.0, 0.0);{let x: number = this._deviceToScreen.transformX(this._touchManager.getX()); // 論理座標変換した座標を取得。let y: number = this._deviceToScreen.transformY(this._touchManager.getY()); // 論理座標変化した座標を取得。if(LAppDefine.DebugTouchLogEnable){LAppPal.printLog("[APP]touchesEnded x: {0} y: {1}", x, y);}live2DManager.onTap(x, y);/*// 点击了齿轮,调用live2D管理器切换人物模型if(this._gear.isHit(pointX, pointY)){live2DManager.nextScene();}*/}}

完成后我们找到Sample\TypeScript\Demo\src\lappdelegate.tsrun函数

 /*** 実行処理。*/public run(): void{// メインループlet loop = () =>{// インスタンスの有無の確認if(s_instance == null){ return;}// 時間更新LAppPal.updateTime();// 画面の初期化//这里时初始化背景的,四个参数分别是 r g b a//原本的参数是0,0,0,1//我们把它改成0,0,0,0gl.clearColor(0.0, 0.0, 0.0, 0.0);----------------------省略.....----------------------};loop();}

修改完背景后,我们修改模型在页面中的布局。这里我是参考的别人的布局方式:是帐篷啊

完成以上步骤后我们可以运行一下看看效果

2.了解自己准备使用的模型

为了使项目兼容更多的模型,我们需要先了解不同模型直接的差异

  • 首先是版本问题,该项目只支持模型入口文件为 *.moc3.json的模型
  • 其次是模型的控制参数,这个是我们最需要关注的,因为这关系到你能不能控制人物的交互行为

控制参数我们可以使用官方的Cubism Viewer打开文件,之后点击moc文件,来查看。这里我们主要关注和控制身体、面部、眼球相关的参数(官方标准值为:ParamAngleX、Y、Z,ParamBodyAngleX和ParamEyeBallX、Y)

有了以上的了解,我们可以进行下一步,接下来我们要做的就是将当前模型的非标准值与标准值进行映射

首先,我们打开进入到你准备的模型的根目录(moc3.json文件同级),在这里新建mapper.json文件,内容如下:

{"parameter": [//  标准值:模型中所对应的值,如果你的模型用的就是标准值,也需要这样操作{"ParamAngleX": "PARAM_ANGLE_X"},{"ParamAngleY": "PARAM_ANGLE_Y"},{"ParamAngleZ": "PARAM_ANGLE_Z"},{"ParamEyeBallX": "PARAM_EYE_BALL_X"},{"ParamBodyAngleX": "PARAM_BODY_ANGLE_X"},{"ParamEyeBallY": "PARAM_EYE_BALL_Y"}],//这个暂时不用,后续更新的话有可能会使用到"url": [],//如果你想调整模型的位置,修改这个值,分别对应X轴和Y轴"center":[2,1]
}

该文件是根据我自己在源码中修改的加载逻辑而额外加的,方便来回切换模型时使用,你根据你自己的情况来决定要不要进行这一步。

第一步和第二步准备工作做好后,我们开始修改源码中与模型有关的内容

3. 修改资源路径等文件

  1. 新建MocMapper.ts文件
/*** 将Moc文件中的id值和资源文件名称及对应的url映射到程序中*/
import {resourcesConfig } from './lappdefine'export class MocMapper {private parameterIdMAp: Map<string, string> = new Map();private resourcesPathToUrlMap = new Map();private jsonResources = null;public static mapper: MocMapper = null;/*** 根据url地址获取资源路径和url的映射对象* @param url 保存映射关系的json的url地址*/public static  getInstance() {if (this.mapper == null) {this.mapper = new MocMapper();}return this.mapper;}/*** 将当前模型的id值保存到键值对中* @param defaultParameter 官方默认的id值* @param currentModParameter  当前模型中与官方默认值效果相同的id值* @note 一般只需要设置 ParamEyeBall[X,Y]  ParamAngle[X,Y,Z]*/public setParameter(defaultParameter: string, currentModParameter: string) {this.parameterIdMAp.set(defaultParameter,currentModParameter)}/*** * @param defaultParameter 根据默认id值获取当前模型对应的id值* @returns */public getParemeter(defaultParameter: string): string {return this.parameterIdMAp.get(defaultParameter)}
/*** * @param resourcesPath moc3.json中的资源路径* @param url 服务器中该路径对应文件的访问地址*/public setPathToUrl(resourcesPath:string, url:string) {this.resourcesPathToUrlMap.set(resourcesPath, url);}
/***  根据资源路径获取url* @param resourcesPath 资源路径* @returns */public getUrl(resourcesPath: string): string {return this.resourcesPathToUrlMap.get(resourcesPath)}public getJsonConfig() {return this.jsonResources;}
/*** 从指定url读取模型目录中的mapper.json【自定义的变量映射关系文件】文件* @param url mapper文件的url*/public async setMapperJson(url: string) {this.jsonResources = await fetch(url).then(async function (response) {const json = await response.json();return json;})let arrayOfparameters = this.getJsonConfig().parameter;let arrayOfUrl = this.getJsonConfig().url;//将id值存入map中for (let i = 0; i < arrayOfparameters.length; i++) {let item = arrayOfparameters[i]for (let key in item) {this.setParameter(key,item[key])}}//将资源路径和url映射关系存入map中for (let i = 0; i < arrayOfUrl.length;i++) {let item = arrayOfUrl[i]for (let key in item) {this.setParameter(key,item[key])}}//设置模型的中心位置let centerPointScal = this.getJsonConfig().center;resourcesConfig.setXscal(centerPointScal[0]);resourcesConfig.setYscal(centerPointScal[1]);}
}
  1. 打开【Samples\TypeScript\Demo\src\lappdefine.ts】文件

修改源文件内容如下:

import { LogLevel } from '@framework/live2dcubismframework';// Canvas width and height pixel values, or dynamic screen size ('auto').
export const CanvasSize: { width: number; height: number } | 'auto' = 'auto';// 画面,默认放大倍率
export const ViewScale = 2;export const ViewMaxScale = 4.0;
export const ViewMinScale = 0.4;
export const ViewLogicalLeft = -1.0;
export const ViewLogicalRight = 1.0;
export const ViewLogicalBottom = -1.0;
export const ViewLogicalTop = 1.0;
export const ViewLogicalMaxLeft = -2.0;
export const ViewLogicalMaxRight = 2.0;
export const ViewLogicalMaxBottom = -2.0;
export const ViewLogicalMaxTop = 2.0;//新建ResouConfig对象
class ResourceConfig {public resourcesPath: string;public modelNames: string[];public modelSize: number;public canvasId: string = 'live2d';public x_scal: number = 2;public y_scal:number = 1constructor() {this.resourcesPath = '../../Resources/';this.modelNames = ['Haru', 'Hiyori', 'Mark', 'Natori', 'Rice'];this.modelSize = this.modelNames.length;}public setResourcesPath(path:string) {this.resourcesPath = path;}public setCanvasId(canvasId:string) {this.canvasId = canvasId;}public setModelNames(models:string[]) {this.modelNames = models;this.setModelSize();}public setModelSize() {this.modelSize = this.modelNames.length;}public getResourcesPath() {return this.resourcesPath;}public getModelNames() {return this.modelNames;}public getModelSize() { return this.modelSize;}public getCanvasId() {return  this.canvasId}public setXscal(scal:number) {  this.x_scal = scal }public setYscal(scal:number) {  this.y_scal = scal }public getXscal() { return this.x_scal }public getYscal() { return this.y_scal}}
//将该对象导出,方便在其他文件中使用
export const resourcesConfig = new ResourceConfig();// 相対パス
//export const ResourcesPath = '../../Resources/';// モデルの後ろにある背景の画像ファイル
export const BackImageName = '';// 歯車
export const GearImageName = '';// 終了ボタン
export const PowerImageName = '';// モデル定義---------------------------------------------
// モデルを配置したディレクトリ名の配列
// ディレクトリ名とmodel3.jsonの名前を一致させておくこと
//export const ModelDir: string[] = ['Haru', 'Hiyori', 'Mark', 'Natori', 'Rice'];
//export const ModelDirSize: number = ModelDir.length;//下方省略.................
  1. 打开**【Samples\TypeScript\Demo\src\lappdelegate.ts】,导入lappdefine.ts中的resourceConfig对象,定位到initialize()**修改内容如下:
import * as LAppDefine from './lappdefine';
/**
省略其他方法
*/public initialize(): boolean {// 修改成我们自己配置的canvascanvas = <HTMLCanvasElement>document.getElementById(LAppDefine.resourcesConfig.getCanvasId());// glコンテキストを初期化// @ts-ignoregl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');if (!gl) {alert('Cannot initialize WebGL. This browser does not support.');gl = null;document.body.innerHTML ='This browser does not support the <code>&lt;canvas&gt;</code> element.';// gl初期化失敗return false;}// キャンバスを DOM に追加// document.body.appendChild(canvas);if (!frameBuffer) {frameBuffer = gl.getParameter(gl.FRAMEBUFFER_BINDING);}// 透過設定gl.enable(gl.BLEND);gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);// 注释掉原有的点击和触摸事件
/*const supportTouch: boolean = 'ontouchend' in document;if (supportTouch) {// タッチ関連コールバック関数登録document.ontouchstart = onTouchBegan;document.ontouchmove = onTouchMoved;document.ontouchend = onTouchEnded;//document.ontouchend = onTouchEnded;//canvas.ontouchcancel = onTouchCancel;} else {*/// マウス関連コールバック関数登録//只能在canvas的事件上调用on*Ended()方法,不然会影响人物的点击效果//onmousemove方法只能在onmousedown和onmouseup之间调用,不然没有效果//document.onmousemove = onMouseMoved;canvas.onmouseup = onClickEnded;document.addEventListener("mousemove", function (e) {if (!LAppDelegate.getInstance()._view) {LAppPal.printMessage("view notfound");return;}//之前我是使用documents对象来获取canvas,其实已经有全局变量了,这里也可以直接用let rect = canvas.getBoundingClientRect();let posX: number = e.clientX - rect.left;let posY: number = e.clientY - rect.top;LAppDelegate.getInstance()._view.onTouchesMoved(posX, posY);}, false);//在这里加上鼠标离开浏览器后,一切归位document.addEventListener("mouseout", function (e) {//鼠标离开document后,将其位置置为(0,0)  let live2DManager: LAppLive2DManager = LAppLive2DManager.getInstance();live2DManager.onDrag(0.0, 0.0);}, false);// AppViewの初期化this._view.initialize();// Cubism SDKの初期化this.initializeCubism();return true;}
  1. 打开【Samples\TypeScript\Demo\src\lapplive2dmanager.ts】文件,添加或修改以下方法
//开头导入相关文件
import { MocMapper}from './MocMapper'
import * as LAppDefine from './lappdefine';
-----------------------------下边是对象内容----------------------------------------------public nextScene(): void {const no: number = (this._sceneIndex + 1) % LAppDefine.resourcesConfig.getModelSize();this.changeScene(no);}/*** 随机加载模型 */public randomScene(): void {//设置随机的模型选项let randomNum= Math.random()*(LAppDefine.resourcesConfig.getModelSize()+1)//取值范围[0,size+1)包含小数//转为整数后再次取余防止出现数组越界问题let indexOfModel = Math.floor(randomNum)%LAppDefine.resourcesConfig.getModelSize()this.changeScene(indexOfModel);}public  async changeScene(index: number): Promise<void> {this._sceneIndex = index;if (LAppDefine.DebugLogEnable) {LAppPal.printMessage(`[APP]model index: ${this._sceneIndex}`);}// ModelDir[]に保持したディレクトリ名から// model3.jsonのパスを決定する。// ディレクトリ名とmodel3.jsonの名前を一致させておくこと。const model: string = LAppDefine.resourcesConfig.getModelNames()[index];const modelPath: string = LAppDefine.resourcesConfig.getResourcesPath() + model + '/';let modelJsonName: string = LAppDefine.resourcesConfig.getModelNames()[index];modelJsonName += '.model3.json';let mapperJsonOfModel = modelPath + 'mapper.json';let mapper = MocMapper.getInstance();await mapper.setMapperJson(mapperJsonOfModel)this.releaseAllModel();this._models.pushBack(new LAppModel());this._models.at(0).loadAssets(modelPath, modelJsonName);}
  1. 打开【Sample\TypeScript\Demo\src\lappview.ts】文件,initializeSprite()函数
//修改
const resourcesPath = LAppDefine.resourcesConfig.getResourcesPath();
  1. 打开【Framework\src\math\cubismmodelmatrix.ts】,导入resourcesConfig,然后找到构造方法
//在开头加上
import { resourcesConfig } from '../../../Samples/TypeScript/Demo/src/lappdefine';---------------------------------下面是构造方法内容----------------------------------------------
constructor(w?: number, h?: number) {super();this._width = w !== undefined ? w : 0.0;this._height = h !== undefined ? h : 0.0;//这个是官方随便给的一个数,调整后会影响模型的放大倍率this.setHeight(2.0);//设置模型中心位置this.setCenterPosition(w*resourcesConfig.getXscal()/2, h*resourcesConfig.getYscal()/2);}
  1. 修改【Sample\TypeScript\Demo\src\main.ts】
import { LAppDelegate } from './lappdelegate';
import { resourcesConfig} from './lappdefine';
import { LAppLive2DManager} from './lapplive2dmanager'function  start() {// create the application instanceif (LAppDelegate.getInstance().initialize() == false) {return;}LAppDelegate.getInstance().run();
}
function stop() {LAppDelegate.releaseInstance();
}
/*** 根据index来控制切换模型,只能填整数* @param index 模型的次序* 从1开始。 小于0:随机加载* >0加载数组下标为index-1的模型* ==0 加载下一个模型*/
function changeScene(index: number) {let manager = LAppLive2DManager.getInstance();if (index < 0) {manager.randomScene();} else if (index > 0 ) {manager.changeScene(index-1)} else if (index ==0) {manager.nextScene();}
}
module.exports = { start , stop , changeScene , resourcesConfig}
  1. 打开【Samples\TypeScript\Demo\src\lappmodel.ts】,导入MocMapper,定位到构造方法
 public constructor() {super();this._modelSetting = null;this._modelHomeDir = null;this._userTimeSeconds = 0.0;this._eyeBlinkIds = new csmVector<CubismIdHandle>();this._lipSyncIds = new csmVector<CubismIdHandle>();this._motions = new csmMap<string, ACubismMotion>();this._expressions = new csmMap<string, ACubismMotion>();this._hitArea = new csmVector<csmRect>();this._userArea = new csmVector<csmRect>();let mapper = MocMapper.mapper;if (mapper != null) {this._idParamAngleX = CubismFramework.getIdManager().getId(mapper.getParemeter("ParamAngleX"));this._idParamAngleY = CubismFramework.getIdManager().getId(mapper.getParemeter("ParamAngleY"));this._idParamAngleZ = CubismFramework.getIdManager().getId(mapper.getParemeter("ParamAngleZ"));this._idParamEyeBallX = CubismFramework.getIdManager().getId(mapper.getParemeter("ParamEyeBallX"));this._idParamEyeBallY = CubismFramework.getIdManager().getId(mapper.getParemeter("ParamEyeBallY"));this._idParamBodyAngleX = CubismFramework.getIdManager().getId(mapper.getParemeter("ParamBodyAngleX"));} else {this._idParamAngleX = CubismFramework.getIdManager().getId(CubismDefaultParameterId.ParamAngleX);this._idParamAngleY = CubismFramework.getIdManager().getId(CubismDefaultParameterId.ParamAngleY);this._idParamAngleZ = CubismFramework.getIdManager().getId(CubismDefaultParameterId.ParamAngleZ);this._idParamEyeBallX = CubismFramework.getIdManager().getId(CubismDefaultParameterId.ParamEyeBallX);this._idParamEyeBallY = CubismFramework.getIdManager().getId(CubismDefaultParameterId.ParamEyeBallY);this._idParamBodyAngleX = CubismFramework.getIdManager().getId(CubismDefaultParameterId.ParamBodyAngleX);}this._state = LoadStep.LoadAssets;this._expressionCount = 0;this._textureCount = 0;this._motionCount = 0;this._allMotionCount = 0;this._wavFileHandler = new LAppWavFileHandler();}
  1. 打开【Samples\TypeScript\Demo\webpack.config.js】,修改打包输出方式
module.exports = {mode: 'production',target: ['web', 'es5'],entry: './src/main.ts',output: {path: path.resolve(__dirname, 'dist'),filename: 'bundle.js',publicPath: '/dist/',library: 'live2dLoader',libraryTarget:'umd'},resolve: {extensions: ['.ts', '.js'],//省略。。。。。。。。。。。
  1. 打开【index.html】,添加js代码
 <script type="text/javascript">var loader  = live2dLoader //这两个是必须设置的loader.resourcesConfig.setResourcesPath("./live2d/models/")loader.resourcesConfig.setModelNames(['a','b'])loader.start();console.log(loader)</script>

以上修改完成后,打包运行即可。

结尾

修改完成后的项目我上传到GitHub:https://github.com/cqc233/live2dDemo

如果对于某个细节不是很明白可以参考我的旧版文章:

Live2D(Cubism3.x)网页看板娘设置(二)

Live2D(Cubism3.x)网页看板娘设置(三)

live2d(Web SDK 4.x)Web看板娘进阶相关推荐

  1. 用html5看板娘,记在nuxt.js中引入一个萌哒哒的看板娘(Live2d模型)

    在vue中引入看板娘很简单,网上资源也很多 那么在nuxt中如何引入呢?这个问题我试了好多好多方法,像vue一样引入全局组件...都不行,最后找到了一个方法. 其实就是运用nuxt中的app.html ...

  2. live2d PHP,GitHub - hiccphp/live2d-widget: 把萌萌哒的看板娘抱回家 | Live2D widget for web platform...

    Live2D Widget 特性 Feature 在网页中添加Live2D看板娘.与PJAX兼容,支持无刷新加载. Add Live2D widget to web page. Compatible ...

  3. html中看板娘添加,如何在自己开发的web中放入“看板娘”

    什么是看板娘? 那就她了--> 就是她~ 看板娘是一种职业和习惯称呼,也是ACGN次文化中的萌属性之一.简而言之就是小店的女服务生,也有"吸引顾客,招揽生意,提高人气"等作用 ...

  4. L2Dwidget二次元看板娘的web用法

    打工人的猎奇心:     发现某些blog网站左下方或者右下方出现的二次元卡通人物或萌萌阿猫,除了萌,还可以监听鼠标的行为,产生互动的现象.为探究竟,打工人开始了行动- 一.看板娘 hexo live ...

  5. 给网站加个漂亮可爱的看板娘live2d,自建api,简化无错版

    给网站加个漂亮可爱的看板娘live2d,自建api,简化无错版 演示及相关下载 演示地址: 下载地址: 添加看板娘流程 1.解压文件到你的站点目录 如:https://www.ex.com/live2 ...

  6. Hexo添加Live2D看板娘最新教程

    目录 前言 介绍 Live2D 看板娘 添加Live2D看板娘 准备工作 安装依赖 下载model文件 添加live2d看板娘到hexo 查看效果 发布 结束语 参考 前言 上次我们搭建了hexo博客 ...

  7. live2d 看板娘 简单添加看版娘到自己的网站

    简单添加看版娘到自己的网站 关注公众号后台回复  "看板娘"  获取全部文件(接口,源代码). 我们先来看一下我们的网站会变成什么样吧! http://www.djyqxbc.vi ...

  8. Live2D看板娘详细实现

    Live2D看板娘实现 国际惯例先上图: 所需资源: 链接:https://pan.baidu.com/s/1s7IJIqGnn-cNRAfoS-qG5w 提取码:dhf4 其中包含了看板娘所需的CS ...

  9. 网易技术干货 | 云信Web SDK测试实践

    一.项目介绍 网易云信于2015年成立,为网易集团下属的内资公司,总部位于杭州.除资深老杭研外,团队核心90%来自硅谷.百度.腾讯.阿里.华为等大型企业/独角兽公司,平均行业经验10年以上,掌握业内领 ...

最新文章

  1. Python学习十大良好习惯
  2. 华硕无双新品首爆:H45标压处理器+全球首款2.8K 120Hz OLED屏
  3. caffe 使用小技巧
  4. joson返回数据库的时间格式在前台用js转换
  5. 鱼之死,越狱章鱼和雾霾黑客
  6. Spring AOP切面实现:参数传递
  7. 朋友去面试阿里蚂蚁金服测试岗位过程经历
  8. Gradle build daemon disappeared unexpectedly (it may have been killed or may hav
  9. webRTC(八):查看offer/answer 的 SDP
  10. MQ-3酒精模拟量 电压转换公式
  11. 2016MDCC移动开发者大会总结
  12. 鸿蒙对比ios流畅,鸿蒙OS 2.0对比iOS 14:苹果流畅度完败?
  13. 几种车载网络特征对比
  14. 解决IDEA项目一直Updating Index
  15. 近期基金有所上涨,你的基金回本了吗?如果回本了,你还会继续持仓吗?
  16. 磁盘IOPS和带宽(throughput)
  17. 6.oop-类和对象
  18. 无人巴士和无人出租车都能用的L4自动驾驶通用硬件方案
  19. 1、Centos7系统的初化始配置
  20. Linux——匿名管道、命名管道及进程池概念和实现原理

热门文章

  1. express模板引擎 html,Express新手入坑笔记之动态渲染HTML
  2. 中国统计年鉴1981-2021年
  3. 数据库基础理解(1)绪论片
  4. 开机运行到window启动画面马上蓝屏重启
  5. 小游戏画面清晰自适应手机全屏
  6. Invalid Host header 服务器域名访问出现的问题
  7. 绊倒阿里的从来都不会是二选一
  8. 混合云时代下,如何制定多云策略
  9. java标识符可以$开头吗_JAVA标识符
  10. Oracle数仓分区表创建及其数据清理存储过程