Live2D WebGL实现
demo预览:http://www.kakinuma.date/l2d.html
官方:http://www.live2d.com/en/
sdk下载:https://link.zhihu.com/?target=http%3A//app2.live2d.com/cubism/sdk/bowiuex/webgl/Live2D_SDK_WebGL_2.0.05_1_en.zip
sdk目录:

framework框架有一个js,lib库有1个,这是最基本的构成
下面有SampleApp1,Simple两个例子,simple是前者的精简版,只有显示没有功能,就不看它了
SampleApp1中
assets包括了背景和模型等资源
src则是模型的初始化,显示,事件绑定等等的功能实现代码
首先为了测试,先导进了所有的.js,然后添加个标签
<!DOCTYPE HTML>
<html>
<head>
<script src='lib/live2d.min.js'></script>
<script src='framework/Live2DFramework.js'></script>
<script src="src/utils/MatrixStack.js"></script>
<script src="src/utils/ModelSettingJson.js"></script>
<script src="src/PlatformManager.js"></script>
<script src="src/LAppDefine.js"></script>
<script src="src/LAppModel.js"></script>
<script src="src/LAppLive2DManager.js"></script>
<script src="src/SampleApp1.js"></script>
</head> <body>
<canvas id="test" width="450px" height="500px" style="position:fixed;right:0px;bottom:-10px;">
</canvas>
<script>
sampleApp1();
</script>
</body>
</html>
.js 文件都按路径放好就好了
然后试着打开页面,看看报错(压根就没觉得可以直接用,因为我压根就没有添加模型文件
init……应该是初始化有错,具体看看
说是null了应该是没传到参数,所以参数canvasId应该是有问题(顺便Canvas在这应该是画布的意思)
顶上面一行,getId出错,那就应该是html里id没写对……随手写了个test确实太随意了……
这个canvasId的来源就在这函数头顶上,就是初始化的Sample1()

改一下,改成glcanvas,改掉以后出现了新的错误,是同样类别的错误,因为官方Sample里有换模型的按钮,所以我没写,Id一样没get到,但是我不想使用换模型的功能,所以我尝试不使用者这功能
所以在初始化函数SampleApp1()中调用的init中,选择不要那个Button
然后所有的change的地方都暂时选择注释掉,地方不少……change的定义,和一些调用,因为Sample中右键模型也是可以change的
然后问题没了,但是理所当然是空白,因为我没加模型
不过审查元素的话,元素是在的(当然在了

现在的SampleApp1.js被修改为
var thisRef = this;
window.onerror = function(msg, url, line, col, error) {
var errmsg = "file:" + url + "<br>line:" + line + " " + msg;
l2dError(errmsg);
}
function SampleApp1()
{
this.platform = window.navigator.platform.toLowerCase();
this.live2DMgr = new LAppLive2DManager();
this.isDrawStart = false;
this.gl = null;
this.canvas = null;
this.dragMgr = null; /*new L2DTargetPoint();*/
this.viewMatrix = null; /*new L2DViewMatrix();*/
this.projMatrix = null; /*new L2DMatrix44()*/
this.deviceToScreen = null; /*new L2DMatrix44();*/
this.drag = false;
this.oldLen = 0;
this.lastMouseX = 0;
this.lastMouseY = 0;
this.isModelShown = false;
initL2dCanvas("glCanvas");
init();
}
function initL2dCanvas(canvasId)
{
this.canvas = document.getElementById(canvasId);
if(this.canvas.addEventListener) {
this.canvas.addEventListener("mousewheel", mouseEvent, false);
this.canvas.addEventListener("click", mouseEvent, false);
this.canvas.addEventListener("mousedown", mouseEvent, false);
this.canvas.addEventListener("mousemove", mouseEvent, false);
this.canvas.addEventListener("mouseup", mouseEvent, false);
this.canvas.addEventListener("mouseout", mouseEvent, false);
this.canvas.addEventListener("contextmenu", mouseEvent, false);
this.canvas.addEventListener("touchstart", touchEvent, false);
this.canvas.addEventListener("touchend", touchEvent, false);
this.canvas.addEventListener("touchmove", touchEvent, false);
}
}
function init()
{
var width = this.canvas.width;
var height = this.canvas.height;
this.dragMgr = new L2DTargetPoint();
var ratio = height / width;
var left = LAppDefine.VIEW_LOGICAL_LEFT;
var right = LAppDefine.VIEW_LOGICAL_RIGHT;
var bottom = -ratio;
var top = ratio;
this.viewMatrix = new L2DViewMatrix();
this.viewMatrix.setScreenRect(left, right, bottom, top);
this.viewMatrix.setMaxScreenRect(LAppDefine.VIEW_LOGICAL_MAX_LEFT,
LAppDefine.VIEW_LOGICAL_MAX_RIGHT,
LAppDefine.VIEW_LOGICAL_MAX_BOTTOM,
LAppDefine.VIEW_LOGICAL_MAX_TOP);
this.viewMatrix.setMaxScale(LAppDefine.VIEW_MAX_SCALE);
this.viewMatrix.setMinScale(LAppDefine.VIEW_MIN_SCALE);
this.projMatrix = new L2DMatrix44();
this.projMatrix.multScale(1, (width / height));
this.deviceToScreen = new L2DMatrix44();
this.deviceToScreen.multTranslate(-width / 2.0, -height / 2.0);
this.deviceToScreen.multScale(2 / width, -2 / width);
this.gl = getWebGLContext();
if (!this.gl) {
l2dError("Failed to create WebGL context.");
return;
}
this.gl.clearColor(0.0, 0.0, 0.0, 0.0);
changeModel();
startDraw();
}
function startDraw() {
if(!this.isDrawStart) {
this.isDrawStart = true;
(function tick() {
draw();
var requestAnimationFrame =
window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.msRequestAnimationFrame;
requestAnimationFrame(tick ,this.canvas);
})();
}
}
function draw()
{
// l2dLog("--> draw()");
MatrixStack.reset();
MatrixStack.loadIdentity();
this.dragMgr.update();
this.live2DMgr.setDrag(this.dragMgr.getX(), this.dragMgr.getY());
this.gl.clear(this.gl.COLOR_BUFFER_BIT);
MatrixStack.multMatrix(projMatrix.getArray());
MatrixStack.multMatrix(viewMatrix.getArray());
MatrixStack.push();
for (var i = 0; i < this.live2DMgr.numModels(); i++)
{
var model = this.live2DMgr.getModel(i);
if(model == null) return;
if (model.initialized && !model.updating)
{
model.update();
model.draw(this.gl);
if (!this.isModelShown && i == this.live2DMgr.numModels()-1) {
this.isModelShown = !this.isModelShown;
}
}
}
MatrixStack.pop();
}
function changeModel()
{
this.isModelShown = false;
this.live2DMgr.reloadFlg = true;
this.live2DMgr.count++;
this.live2DMgr.changeModel(this.gl);
}
function modelScaling(scale)
{
var isMaxScale = thisRef.viewMatrix.isMaxScale();
var isMinScale = thisRef.viewMatrix.isMinScale();
thisRef.viewMatrix.adjustScale(0, 0, scale);
if (!isMaxScale)
{
if (thisRef.viewMatrix.isMaxScale())
{
thisRef.live2DMgr.maxScaleEvent();
}
}
if (!isMinScale)
{
if (thisRef.viewMatrix.isMinScale())
{
thisRef.live2DMgr.minScaleEvent();
}
}
}
function modelTurnHead(event)
{
thisRef.drag = true;
var rect = event.target.getBoundingClientRect();
var sx = transformScreenX(event.clientX - rect.left);
var sy = transformScreenY(event.clientY - rect.top);
var vx = transformViewX(event.clientX - rect.left);
var vy = transformViewY(event.clientY - rect.top);
if (LAppDefine.DEBUG_MOUSE_LOG)
l2dLog("onMouseDown device( x:" + event.clientX + " y:" + event.clientY + " ) view( x:" + vx + " y:" + vy + ")");
thisRef.lastMouseX = sx;
thisRef.lastMouseY = sy;
thisRef.dragMgr.setPoint(vx, vy);
thisRef.live2DMgr.tapEvent(vx, vy);
}
function followPointer(event)
{
var rect = event.target.getBoundingClientRect();
var sx = transformScreenX(event.clientX - rect.left);
var sy = transformScreenY(event.clientY - rect.top);
var vx = transformViewX(event.clientX - rect.left);
var vy = transformViewY(event.clientY - rect.top);
if (LAppDefine.DEBUG_MOUSE_LOG)
l2dLog("onMouseMove device( x:" + event.clientX + " y:" + event.clientY + " ) view( x:" + vx + " y:" + vy + ")");
if (thisRef.drag)
{
thisRef.lastMouseX = sx;
thisRef.lastMouseY = sy;
thisRef.dragMgr.setPoint(vx, vy);
}
}
function lookFront()
{
if (thisRef.drag)
{
thisRef.drag = false;
}
thisRef.dragMgr.setPoint(0, 0);
}
function mouseEvent(e)
{
e.preventDefault();
if (e.type == "mousewheel") {
if (e.clientX < 0 || thisRef.canvas.clientWidth < e.clientX ||
e.clientY < 0 || thisRef.canvas.clientHeight < e.clientY)
{
return;
}
if (e.wheelDelta > 0) modelScaling(1.1);
else modelScaling(0.9);
} else if (e.type == "mousedown") {
if("button" in e && e.button != 0) return;
modelTurnHead(e);
} else if (e.type == "mousemove") {
followPointer(e);
} else if (e.type == "mouseup") {
if("button" in e && e.button != 0) return;
lookFront();
} else if (e.type == "mouseout") {
lookFront();
} else if (e.type == "contextmenu") {
changeModel();
}
}
function touchEvent(e)
{
e.preventDefault();
var touch = e.touches[0];
if (e.type == "touchstart") {
if (e.touches.length == 1) modelTurnHead(touch);
// onClick(touch);
} else if (e.type == "touchmove") {
followPointer(touch);
if (e.touches.length == 2) {
var touch1 = e.touches[0];
var touch2 = e.touches[1];
var len = Math.pow(touch1.pageX - touch2.pageX, 2) + Math.pow(touch1.pageY - touch2.pageY, 2);
if (thisRef.oldLen - len < 0) modelScaling(1.025);
else modelScaling(0.975);
thisRef.oldLen = len;
}
} else if (e.type == "touchend") {
lookFront();
}
}
function transformViewX(deviceX)
{
var screenX = this.deviceToScreen.transformX(deviceX);
return viewMatrix.invertTransformX(screenX);
}
function transformViewY(deviceY)
{
var screenY = this.deviceToScreen.transformY(deviceY);
return viewMatrix.invertTransformY(screenY);
}
function transformScreenX(deviceX)
{
return this.deviceToScreen.transformX(deviceX);
}
function transformScreenY(deviceY)
{
return this.deviceToScreen.transformY(deviceY);
}
function getWebGLContext()
{
var NAMES = [ "webgl" , "experimental-webgl" , "webkit-3d" , "moz-webgl"];
for( var i = 0; i < NAMES.length; i++ ){
try{
var ctx = this.canvas.getContext(NAMES[i], {premultipliedAlpha : true});
if(ctx) return ctx;
}
catch(e){}
}
return null;
};
function l2dLog(msg) {
if(!LAppDefine.DEBUG_LOG) return;
console.log(msg);
}
function l2dError(msg)
{
if(!LAppDefine.DEBUG_LOG) return;
l2dLog( "<span style='color:red'>" + msg + "</span>");
console.error(msg);
};
这时的index.html为
<!DOCTYPE HTML>
<html>
<head>
<script src='lib/live2d.min.js'></script>
<script src='framework/Live2DFramework.js'></script>
<script src="src/utils/MatrixStack.js"></script>
<script src="src/utils/ModelSettingJson.js"></script>
<script src="src/PlatformManager.js"></script>
<script src="src/LAppDefine.js"></script>
<script src="src/LAppModel.js"></script>
<script src="src/LAppLive2DManager.js"></script>
<script src="src/SampleApp1.js"></script>
</head> <body>
<canvas id="glCanvas" width="450px" height="500px" style="position:fixed;right:0px;bottom:-10px;">
</canvas>
<script>
SampleApp1();
</script>
</body>
</html>
这时的控制台已经有了我们想要的错误了
PlatformManager中

failed to load,所以我们就能知道我们的模型到底该导到哪去
这里要的是一个json,我看官方的文档写的json是定义的模型类,这里就直接试着改一下,去下载一个模型文件,看看都有些什么……
下载到KcWiki曾经使用过的丛云模型,文件结构为

model.json中内容为
{
"version":"Sample 1.0.0",
"model":"murakumo.moc",
"textures":[
"murakumo.2048/texture_00.png"
],
"motions":{
"tap_bust":[
{"file":"motions/murakumo_tap_bust_01.mtn"},
{"file":"motions/murakumo_tap_bust_02.mtn"}
],
"idle":[
{"file":"motions/murakumo_idle_01.mtn"},
{"file":"motions/murakumo_idle_02.mtn"},
{"file":"motions/murakumo_idle_03.mtn"}
],
"tap_ear":[
{"file":"motions/murakumo_tap_ear_01.mtn"}
],
"tap":[
{"file":"motions/murakumo_m_01.mtn"},
{"file":"motions/murakumo_m_02.mtn"}
]
},
"physics":"murakumo.physics.json"
}
所以我们能在这里看到……版本,模型地址,资源动作和……物理特性(讲道理我猜是乳摇用的……
试着导入模型……导入到哪??
platform不是直接用到的,仔细看一看发现,
SampleApp1中有 this.live2DMgr = new LAppLive2DManager();
而LppLive2DManager.js中,有function LAppLive2DManager(),其中有一句Live2DFramework.setPlatformManager(new PlatformManager);
那么Platform就是这样被初始化的,这样产生了模型载入错误,但是路径是在哪设置的……
重新扫一眼文件结构就能发现,有个js叫LAppDefine,看之
var LAppDefine = {
DEBUG_LOG : true,
DEBUG_MOUSE_LOG : false,
// DEBUG_DRAW_HIT_AREA : false,
// DEBUG_DRAW_ALPHA_MODEL : false,
VIEW_MAX_SCALE : 2,
VIEW_MIN_SCALE : 0.8,
VIEW_LOGICAL_LEFT : -1,
VIEW_LOGICAL_RIGHT : 1,
VIEW_LOGICAL_MAX_LEFT : -2,
VIEW_LOGICAL_MAX_RIGHT : 2,
VIEW_LOGICAL_MAX_BOTTOM : -2,
VIEW_LOGICAL_MAX_TOP : 2,
PRIORITY_NONE : 0,
PRIORITY_IDLE : 1,
PRIORITY_NORMAL : 2,
PRIORITY_FORCE : 3,
BACK_IMAGE_NAME : "assets/image/back_class_normal.png",
MODEL_HARU : "assets/live2d/haru/haru.model.json",
MODEL_HARU_A : "assets/live2d/haru/haru_01.model.json",
MODEL_HARU_B : "assets/live2d/haru/haru_02.model.json",
MODEL_SHIZUKU : "assets/live2d/shizuku/shizuku.model.json",
MODEL_WANKO : "assets/live2d/wanko/wanko.model.json",
MOTION_GROUP_IDLE : "idle",
MOTION_GROUP_TAP_BODY : "tap_body",
MOTION_GROUP_FLICK_HEAD : "flick_head",
MOTION_GROUP_PINCH_IN : "pinch_in",
MOTION_GROUP_PINCH_OUT : "pinch_out",
MOTION_GROUP_SHAKE : "shake",
HIT_AREA_HEAD : "head",
HIT_AREA_BODY : "body"
};
这地方大概绑了模型,和它的动作,这时候最好对比一下Sample模型的json
这是haru的json
{
"type":"Live2D Model Setting",
"name":"haru",
"model":"haru_01.moc",
"textures":
[
"haru_01.1024/texture_00.png",
"haru_01.1024/texture_01.png",
"haru_01.1024/texture_02.png"
],
"physics":"haru.physics.json",
"pose":"haru.pose.json",
"expressions":
[
{"name":"f01","file":"expressions/f01.exp.json"},
{"name":"f02","file":"expressions/f02.exp.json"},
{"name":"f03","file":"expressions/f03.exp.json"},
{"name":"f04","file":"expressions/f04.exp.json"},
{"name":"f05","file":"expressions/f05.exp.json"},
{"name":"f06","file":"expressions/f06.exp.json"},
{"name":"f07","file":"expressions/f07.exp.json"},
{"name":"f08","file":"expressions/f08.exp.json"}
],
"layout":
{
"center_x":0,
"y":1.2,
"width":2.9
},
"hit_areas":
[
{"name":"head", "id":"D_REF.HEAD"},
{"name":"body", "id":"D_REF.BODY"}
],
"motions":
{
"idle":
[
{"file":"motions/idle_00.mtn" ,"fade_in":2000, "fade_out":2000},
{"file":"motions/idle_01.mtn" ,"fade_in":2000, "fade_out":2000},
{"file":"motions/idle_02.mtn" ,"fade_in":2000, "fade_out":2000}
],
"tap_body":
[
{ "file":"motions/tapBody_00.mtn" , "sound":"sounds/tapBody_00.mp3"},
{ "file":"motions/tapBody_01.mtn" , "sound":"sounds/tapBody_01.mp3"},
{ "file":"motions/tapBody_02.mtn" , "sound":"sounds/tapBody_02.mp3"}
],
"pinch_in":
[
{ "file":"motions/pinchIn_00.mtn", "sound":"sounds/pinchIn_00.mp3" }
],
"pinch_out":
[
{ "file":"motions/pinchOut_00.mtn", "sound":"sounds/pinchOut_00.mp3" }
],
"shake":
[
{ "file":"motions/shake_00.mtn", "sound":"sounds/shake_00.mp3","fade_in":500 }
],
"flick_head":
[
{ "file":"motions/flickHead_00.mtn", "sound":"sounds/flickHead_00.mp3" }
]
}
}
shizuku的json
{
"type":"Live2D Model Setting",
"name":"shizuku",
"model":"shizuku.moc",
"textures":
[
"shizuku.1024/texture_00.png",
"shizuku.1024/texture_01.png",
"shizuku.1024/texture_02.png",
"shizuku.1024/texture_03.png",
"shizuku.1024/texture_04.png",
"shizuku.1024/texture_05.png"
],
"physics":"shizuku.physics.json",
"pose":"shizuku.pose.json",
"expressions":
[
{"name":"f01","file":"expressions/f01.exp.json"},
{"name":"f02","file":"expressions/f02.exp.json"},
{"name":"f03","file":"expressions/f03.exp.json"},
{"name":"f04","file":"expressions/f04.exp.json"}
],
"layout":
{
"center_x":0,
"y":1.2,
"width":2.4
},
"hit_areas":
[
{"name":"head", "id":"D_REF.HEAD"},
{"name":"body", "id":"D_REF.BODY"}
],
"motions":
{
"idle":
[
{"file":"motions/idle_00.mtn" ,"fade_in":2000, "fade_out":2000},
{"file":"motions/idle_01.mtn" ,"fade_in":2000, "fade_out":2000},
{"file":"motions/idle_02.mtn" ,"fade_in":2000, "fade_out":2000}
],
"tap_body":
[
{ "file":"motions/tapBody_00.mtn", "sound":"sounds/tapBody_00.mp3" },
{ "file":"motions/tapBody_01.mtn", "sound":"sounds/tapBody_01.mp3" },
{ "file":"motions/tapBody_02.mtn", "sound":"sounds/tapBody_02.mp3" }
],
"pinch_in":
[
{ "file":"motions/pinchIn_00.mtn", "sound":"sounds/pinchIn_00.mp3" },
{ "file":"motions/pinchIn_01.mtn", "sound":"sounds/pinchIn_01.mp3" },
{ "file":"motions/pinchIn_02.mtn", "sound":"sounds/pinchIn_02.mp3" }
],
"pinch_out":
[
{ "file":"motions/pinchOut_00.mtn", "sound":"sounds/pinchOut_00.mp3" },
{ "file":"motions/pinchOut_01.mtn", "sound":"sounds/pinchOut_01.mp3" },
{ "file":"motions/pinchOut_02.mtn", "sound":"sounds/pinchOut_02.mp3" }
],
"shake":
[
{ "file":"motions/shake_00.mtn", "sound":"sounds/shake_00.mp3","fade_in":500 },
{ "file":"motions/shake_01.mtn", "sound":"sounds/shake_01.mp3","fade_in":500 },
{ "file":"motions/shake_02.mtn", "sound":"sounds/shake_02.mp3","fade_in":500 }
],
"flick_head":
[
{ "file":"motions/flickHead_00.mtn", "sound":"sounds/flickHead_00.mp3" },
{ "file":"motions/flickHead_01.mtn", "sound":"sounds/flickHead_01.mp3" },
{ "file":"motions/flickHead_02.mtn", "sound":"sounds/flickHead_02.mp3" }
]
}
}
motions大概都是对应的,根据上边贴了的丛云(murakumo)的json,试着把Define的js改为
var LAppDefine = {
DEBUG_LOG : true,
DEBUG_MOUSE_LOG : false,
// DEBUG_DRAW_HIT_AREA : false,
// DEBUG_DRAW_ALPHA_MODEL : false,
VIEW_MAX_SCALE : 2,
VIEW_MIN_SCALE : 0.8,
VIEW_LOGICAL_LEFT : -1,
VIEW_LOGICAL_RIGHT : 1,
VIEW_LOGICAL_MAX_LEFT : -2,
VIEW_LOGICAL_MAX_RIGHT : 2,
VIEW_LOGICAL_MAX_BOTTOM : -2,
VIEW_LOGICAL_MAX_TOP : 2,
PRIORITY_NONE : 0,
PRIORITY_IDLE : 1,
PRIORITY_NORMAL : 2,
PRIORITY_FORCE : 3,
/*
BACK_IMAGE_NAME : "assets/image/back_class_normal.png",
MODEL_HARU : "assets/live2d/haru/haru.model.json",
MODEL_HARU_A : "assets/live2d/haru/haru_01.model.json",
MODEL_HARU_B : "assets/live2d/haru/haru_02.model.json",
MODEL_SHIZUKU : "assets/live2d/shizuku/shizuku.model.json",
MODEL_WANKO : "assets/live2d/wanko/wanko.model.json",
MOTION_GROUP_IDLE : "idle",
MOTION_GROUP_TAP_BODY : "tap_body",
MOTION_GROUP_FLICK_HEAD : "flick_head",
MOTION_GROUP_PINCH_IN : "pinch_in",
MOTION_GROUP_PINCH_OUT : "pinch_out",
MOTION_GROUP_SHAKE : "shake",
HIT_AREA_HEAD : "head",
HIT_AREA_BODY : "body"
*/
MODEL_MURAKUMO : "murakumo/murakumo.model.json",
MOTION_GROUP_IDLE : "idle",
MOTION_GROUP_TAP : "tap",
MOTION_GROUP_TAP_EAR : "tap_ear",
MOTION_GROUP_TAP_BUST : "tap_bust",
HIT_AREA_HEAD : "head",
HIT_AREA_BODY : "body",
HIT_AREA_EAR_L : "ear_l",
HIT_AREA_EAR_R : "ear_r",
HIT_AREA_BUST : "bust"
};
接着出现的新的错误:

LAPPModel在Load时出了问题……PATH不对,搜搜看哪里使用了它……
LAppLive2DManager.prototype.changeModel 有使用,是因为Sample里官方包含了好多模型……改之

LAppLive2DManager.prototype.changeModel = function(gl)
{
// console.log("--> LAppLive2DManager.update(gl)"); if (this.reloadFlg)
{ this.reloadFlg = false;
var no = parseInt(this.count % 4); var thisRef = this;
switch (no)
{
case 0:
this.releaseModel(1, gl);
this.releaseModel(0, gl);
this.createModel();
this.models[0].load(gl, LAppDefine.MODEL_MURAKUMO);
break;
/*
case 1:
this.releaseModel(0, gl);
this.createModel();
this.models[0].load(gl, LAppDefine.MODEL_SHIZUKU);
break;
case 2:
this.releaseModel(0, gl);
this.createModel();
this.models[0].load(gl, LAppDefine.MODEL_WANKO);
break;
case 3:
this.releaseModel(0, gl); // 一体目のモデル
this.createModel();
this.models[0].load(gl, LAppDefine.MODEL_HARU_A, function() {
// 二体目のモデル
thisRef.createModel();
thisRef.models[1].load(gl, LAppDefine.MODEL_HARU_B);
}); break;
*/
default:
break;
}
}
};
然后再刷新……看看啥错误
卧槽!

野生的丛云出现了
测试一下motions……无效
点击没有给出反应,并且点击耳朵应该会有特殊动作(json中的说明)
想来也是,不同的模型有不同的motion,只对json进行了绑定,具体运行好像没有写/改过,应该还漏了某些地方……
试着去搜一下最开始json中绑定的motion变量,能搜到同样LAPPLive2DManager中,有
LAppLive2DManager.prototype.tapEvent = function(x, y)
{
if (LAppDefine.DEBUG_LOG)
console.log("tapEvent view x:" + x + " y:" + y); for (var i = 0; i < this.models.length; i++)
{ if (this.models[i].hitTest(LAppDefine.HIT_AREA_HEAD, x, y))
{ if (LAppDefine.DEBUG_LOG)
console.log("Tap face."); this.models[i].setRandomExpression();
}
else if (this.models[i].hitTest(LAppDefine.HIT_AREA_BODY, x, y))
{ if (LAppDefine.DEBUG_LOG)
console.log("Tap body." + " models[" + i + "]"); this.models[i].startRandomMotion(LAppDefine.MOTION_GROUP_TAP_BODY,
LAppDefine.PRIORITY_NORMAL);
}
} return true;
};
所以可以根据murakumo的json来改一下这个函数
for (var i = 0; i < this.models.length; i++)
{ if (this.models[i].hitTest(LAppDefine.HIT_AREA_HEAD, x, y))
{ if (LAppDefine.DEBUG_LOG)
console.log("Tap face."); this.models[i].startRandomMotion(LAppDefine.MOTION_GROUP_TAP,
LAppDefine.PRIORITY_NORMAL);
}
else if (this.models[i].hitTest(LAppDefine.HIT_AREA_EAR_L, x, y))
{ if (LAppDefine.DEBUG_LOG)
console.log("Tap body." + " models[" + i + "]"); this.models[i].startRandomMotion(LAppDefine.MOTION_GROUP_TAP_EAR,
LAppDefine.PRIORITY_NORMAL);
}
else if (this.models[i].hitTest(LAppDefine.HIT_AREA_EAR_R, x, y))
{ if (LAppDefine.DEBUG_LOG)
console.log("Tap body." + " models[" + i + "]"); this.models[i].startRandomMotion(LAppDefine.MOTION_GROUP_TAP_EAR,
LAppDefine.PRIORITY_NORMAL);
}
else if (this.models[i].hitTest(LAppDefine.HIT_AREA_BUST, x, y))
{ if (LAppDefine.DEBUG_LOG)
console.log("Tap body." + " models[" + i + "]"); this.models[i].startRandomMotion(LAppDefine.MOTION_GROUP_TAP_BUST,
LAppDefine.PRIORITY_NORMAL);
}
}
事实上改过以后控制台仍无输出
意思是点击事件还是没成功

tapEvent报告了点击坐标,但是没有触发事件
而murakumo_idle是随机的表情动作,与点击事件是不同的,那么只能再跟踪一下tapEvent
tapEvent上来首先是打印坐标,有坐标打印出来说明函数是运行了
重新理一遍,经过前辈提醒,json数据被有绑定完全,再翻上去看看json
官方的sample里
除了textures,model,motion等等还有一个hit_areas,看来就是这样了
没有获取到hitareas,所以相当于没点上什么的
json中添加
"hit_areas":
[
{"name":"head", "id":"D_REF.HEAD"},
{"name":"body", "id":"D_REF.BODY"},
{"name":"ear_l", "id":"D_REF.EAR_L"},
{"name":"ear_r", "id":"D_REF.EAR_R"},
{"name":"bust", "id":"D_REF.BUST"}
],
至于这里的ID,是根据.moc模型文件获取的,是模型制作者在制作模型时为部位添加的,官方有提供模型编辑软件,或者记事本去开moc也能看到?
最后大功告成~

后
这篇博是边摸索边写的,可能会相当的乱……难以看懂
后边重新梳理思路的时候会贴一篇新文
Live2D WebGL实现的更多相关文章
- live2d web端加载moc3模型
大佬博客链接:https://blog.csdn.net/weixin_44128558/article/details/104792345 照着大佬的博客做一下,可以先学会怎么生成bundle.js ...
- 为你的网站加上live2d的动态小挂件,博君一晒
原文转载自「刘悦的技术博客」https://v3u.cn/a_id_122 喜欢二次元的朋友一定对大名鼎鼎的live2d技术并不陌生,live2D是一种应用于电子游戏的绘图渲染技术,技术由日本Cybe ...
- Webgl的2D开发方案(一)spritebatcher
使用TypeScript 和 webgl 开发 第一步:实现了SpriteBatcher 例子如下 http://oak2x0a9v.bkt.clouddn.com/test/index.html ...
- HTML5 学习总结(四)——canvas绘图、WebGL、SVG
一.Canvas canvas是HTML5中新增一个HTML5标签与操作canvas的javascript API,它可以实现在网页中完成动态的2D与3D图像技术.<canvas> 标记和 ...
- 数百个 HTML5 例子学习 HT 图形组件 – WebGL 3D 篇
<数百个 HTML5 例子学习 HT 图形组件 – 拓扑图篇>一文让读者了解了 HT的 2D 拓扑图组件使用,本文将对 HT 的 3D 功能做个综合性的介绍,以便初学者可快速上手使用 HT ...
- 基于 WebSocket 实现 WebGL 3D 拓扑图实时数据通讯同步(二)
我们上一篇<基于 WebSocket 实现 WebGL 3D 拓扑图实时数据通讯同步(一)>主要讲解了如何搭建一个实时数据通讯服务器,客户端与服务端是如何通讯的,相信通过上一篇的讲解,再配 ...
- 基于 WebSocket 实现 WebGL 3D 拓扑图实时数据通讯同步(一)
今天没有延续上一篇讲的内容,穿插一段小插曲,WebSocket 实时数据通讯同步的问题,今天我们并不是很纯粹地讲 WebSocket 相关知识,我们通过 WebGL 3D 拓扑图来呈现一个有趣的 De ...
- 基于HTML5的WebGL应用内存泄露分析
上篇(http://www.hightopo.com/blog/194.html)我们通过定制了CPU和内存展示界面,体验了HT for Web通过定义矢量实现图形绘制与业务数据的代码解耦及绑定联动, ...
- 基于WebGL 的3D呈现A* Search Algorithm
http://www.hightopo.com/demo/astar/astar.html 最近搞个游戏遇到最短路径的常规游戏问题,一时起兴基于HT for Web写了个A*算法的WebGL 3D呈现 ...
随机推荐
- 010 winform
2016-01-23 1.winform应用程序是一种智能客户端技术,我们可以使用winform应用程序帮助我们获得信息或者传输信息等. 2.属性Name:在后台要获得前台的控件对象,需要使用Name ...
- IOS 使用wxsqlite3为sqlite3数据库加密
1,下载wxsqlite3 地址http://jaist.dl.sourceforge.net/project/wxcode/Components/wxSQLite3/wxsqlite3-3.1.1. ...
- centos设置静态ip地址
1.修改网卡配置 编辑:vi /etc/sysconfig/network-scripts/ifcfg-eth0 DEVICE=eth0 #描述网卡对应的设备别名,例如ifcfg-eth0的文件中它为 ...
- display:inline-block 和float:left 的区别
display:inline-block 和float:left 的区别 display是指显示状态,float是针对块级元素的浮动. 使用inline-block:控制元素的垂直对齐跟横向排列元 ...
- oracle问题
(1) 连通性: 注册中心负责服务地址的注册与查找,相当于目录服务,服务提供者和消费者只在启动时与注册中心交互,注册中心不转发请求,压力较小 监控中心负责统计各服务调用次数,调用时间等,统计先在内存汇 ...
- .net core 学习笔记(1)-分页控件的使用
最近有个小项目,用.net core开发练练手,碰到的第一个问题就是分页控件的问题,自己写太费时间,上网查了下,发现有人已经封装好了的,就拿过来用了,分页控件github:https://github ...
- USBD_STATUS
USBD_STATUS 该USBD_STATUS数据类型为USB请求定义USB状态值. 的typedef LONG USBD_STATUS; USB状态值的最显著4位被如下表中所定义. 值 ...
- [转]XSS现代WAF规则探测及绕过技术
初始测试 1.使用无害的payload,类似<b>,<i>,<u>观察响应,判断应用程序是否被HTML编码,是否标签被过滤,是否过滤<>等等: 2.如果 ...
- js字符拼接
for (var j = 0; j < 9; j++) { eval("if (datas[i].b" + j + " == '1') { b[j-1] = 1; ...
- php 队列
一.php中对共享内存,消息队列的操作 http://blog.csdn.net/haitun312366/article/details/8614797 二.PHP memcache 队列类 htt ...