1 /** 2 * @fileOverview 3 * mmd.gl.enchant.js 4 * @version 0.2.2 5 * @require enchant.js v0.6.3+ 6 * @require gl.enchant.js v0.3.7+ 7 * @author UEI Corporation 8 * 9 * @description 10 * MikuMikuDanceのPMDファイルとVMDファイルをgl.enchant.js上で使用できるようにするプラグイン. 11 * 12 * @detail 13 * ファイルの読み込み・パースにMMD.jsのMMD.Model.jsとMMD.Motion.jsを使用します. 14 * シェーダのソースをMMD.VertexShaderSource.jsとMMD.FragmentShaderSource.jsから引用しています. 15 * 16 * MMD.js: 17 * https://github.com/edvakf/MMD.js 18 * MMD.jsについて: 19 * http://edv.sakura.ne.jp/mmd/ 20 */ 21 22 // for MMD.js 23 var MMD = {}; 24 25 (function() { 26 27 var splitPath = function(path) { 28 var split = path.match(/(.{0,})\/([^\/\s]{1,}\.pmd)/); 29 if (split == null) { 30 split = [ '.' + path, '.', path ]; 31 } 32 return split; 33 }; 34 35 /** 36 * @type {Object} 37 */ 38 enchant.gl.mmd = {}; 39 40 enchant.Core._loadFuncs['pmd'] = function(src, ext, callback, onerror) { 41 return new enchant.gl.mmd.MSprite3D(src, callback, onerror); 42 }; 43 44 enchant.Core._loadFuncs['vmd'] = function(src, ext, callback, onerror) { 45 return new enchant.gl.mmd.MAnimation(src, callback, onerror); 46 }; 47 48 /** 49 * @scope enchant.gl.mmd.MMesh.prototype 50 */ 51 enchant.gl.mmd.MMesh = enchant.Class.create(enchant.gl.Mesh, { 52 /** 53 * MSprite3D用のメッシュオブジェクト. 54 * @constructs 55 * @extends enchant.gl.Mesh 56 */ 57 initialize: function() { 58 enchant.gl.Mesh.call(this); 59 var vpos1Buffer = new enchant.gl.Buffer(enchant.gl.Buffer.VERTICES); 60 var vpos2Buffer = new enchant.gl.Buffer(enchant.gl.Buffer.VERTICES); 61 var bone1posBuffer = new enchant.gl.Buffer(enchant.gl.Buffer.VERTICES); 62 var bone2posBuffer = new enchant.gl.Buffer(enchant.gl.Buffer.VERTICES); 63 var quats1Buffer = new enchant.gl.Buffer(enchant.gl.Buffer.QUATS); 64 var quats2Buffer = new enchant.gl.Buffer(enchant.gl.Buffer.QUATS); 65 var morphsBuffer = new enchant.gl.Buffer(enchant.gl.Buffer.MORPHS); 66 var weightsBuffer = new enchant.gl.Buffer(enchant.gl.Buffer.WEIGHTS); 67 var edgesBuffer = new enchant.gl.Buffer(enchant.gl.Buffer.EDGES); 68 this._addAttribute(vpos1Buffer, 'vpos1'); 69 this._addAttribute(vpos2Buffer, 'vpos2'); 70 this._addAttribute(bone1posBuffer, 'bone1pos'); 71 this._addAttribute(bone2posBuffer, 'bone2pos'); 72 this._addAttribute(quats1Buffer, 'quats1'); 73 this._addAttribute(quats2Buffer, 'quats2'); 74 this._addAttribute(morphsBuffer, 'morphs'); 75 this._addAttribute(weightsBuffer, 'weights'); 76 this._addAttribute(edgesBuffer, 'edges'); 77 }, 78 _addAttribute: function(buffer, prop) { 79 this['_' + prop] = buffer; 80 Object.defineProperty(this, prop, { 81 get: function() { 82 return this['_' + prop]._array; 83 }, 84 set: function(array) { 85 this['_' + prop]._array = array; 86 if (this._appear) { 87 this['_' + prop]._bufferData(); 88 } 89 } 90 }); 91 } 92 }); 93 94 enchant.gl.mmd.MBone = enchant.Class.create(enchant.gl.Bone, { 95 initialize: function(param) { 96 var pos = vec3.create(); 97 var rot = quat4.identity(); 98 enchant.gl.Bone.call(this, param.name, param.head_pos, pos, rot); 99 }, 100 _applyPose: function() { 101 var parent = this.parentNode; 102 var local = vec3.create(); 103 vec3.subtract(this._origin, parent._origin, local); 104 vec3.add(local, this._position); 105 quat4.multiply(parent._globalrot, this._rotation, this._globalrot); 106 quat4.multiplyVec3(parent._globalrot, local, this._globalpos); 107 vec3.add(this._globalpos, parent._globalpos); 108 } 109 }); 110 111 enchant.gl.mmd.MSkeleton = enchant.Class.create(enchant.gl.Skeleton, { 112 initialize: function(bones) { 113 enchant.gl.Skeleton.call(this); 114 this.table = []; 115 if (bones) { 116 this.load(bones); 117 } 118 }, 119 load: function(bones) { 120 var bone; 121 for (var i = 0, l = bones.length; i < l; i++) { 122 bone = bones[i]; 123 this._add(bone); 124 } 125 }, 126 _add: function(param) { 127 var bone = new enchant.gl.mmd.MBone(param); 128 this.table.push(bone); 129 if (param.parent_bone_index === 0xFFFF) { 130 this.addChild(bone); 131 } else { 132 this.table[param.parent_bone_index].addChild(bone); 133 } 134 if (param.name.match(/ひざ/)) { 135 bone.constraint = function(q) { 136 return quat4.set([ Math.sqrt(1 - q[3] * q[3]), 0, 0, q[3] ], q); 137 }; 138 } 139 }, 140 _addIK: function(data) { 141 var bones = []; 142 var effector = this.table[data.bone_index]; 143 var target = this.table[data.target_bone_index]; 144 for (var i = 0, l = data.child_bones.length; i < l; i++) { 145 bones[i] = this.table[data.child_bones[i]]; 146 } 147 var maxangle = data.control_weight * 4; 148 var iteration = data.iterations; 149 this.addIKControl(effector, target, bones, maxangle, iteration); 150 } 151 }); 152 153 /** 154 * @scope enchant.gl.mmd.MSprite3D.prototype 155 */ 156 enchant.gl.mmd.MSprite3D = enchant.Class.create(enchant.gl.Sprite3D, { 157 /** 158 * PMDファイルに対応したSprite3D. 159 * 引数を渡すと{@link enchant.gl.mmd.MAnimation#loadVmd}が呼び出される. 160 * PMDファイルをプリロードすることでassets内に自動的に生成される. 161 * @param {String} [path] ファイルパス. 162 * @param {Function} [callback] ロード完了時のコールバック関数. 163 * @param {Function} [onerror] ロード失敗時のコールバック関数. 164 * @constructs 165 * @extends enchant.gl.Sprite3D 166 */ 167 initialize: function(path, callback, onerror) { 168 enchant.gl.Sprite3D.call(this); 169 this.program = enchant.gl.mmd.MMD_SHADER_PROGRAM; 170 this.animation = []; 171 this.uMVMatrix = mat4.create(); 172 this.uNMatrix = mat4.create(); 173 174 this.addEventListener('enterframe', function() { 175 var first; 176 var skeleton = this.skeleton; 177 var morph = this.morph; 178 if (this.animation.length === 0) { 179 } else { 180 first = this.animation[0]; 181 182 var data = first.animation._tick(first.frame); 183 first.frame++; 184 185 this._skinning(data.poses); 186 187 this._morphing(data.morphs); 188 189 if (first.frame > first.animation.length) { 190 first = this.animation.shift(); 191 if (this.loop) { 192 first.frame = 0; 193 this.animation.push(first); 194 } 195 } 196 } 197 }); 198 if (arguments.length >= 2) { 199 this.loadPmd(path, callback, onerror); 200 } 201 }, 202 /** 203 * アニメーションを追加する. 204 * アニメーションは追加された順に再生されていく. 205 * @param {enchant.gl.mmd.MAnimation} animation 206 */ 207 pushAnimation: function(animation) { 208 this.animation.push({ frame: 0, animation: animation }); 209 }, 210 /** 211 * 追加されたアニメーションを削除する. 212 */ 213 clearAnimation: function(animation) { 214 this.animation = []; 215 }, 216 _skinning: function(poses) { 217 var skeleton = this.skeleton; 218 skeleton.setPoses(poses); 219 skeleton.solveFKs(); 220 skeleton.solveIKs(); 221 this._applySkeleton(); 222 223 }, 224 _morphing: function(morphs) { 225 var target = this.mesh.morphs; 226 for (var i = 0, l = target.length; i < l; i++) { 227 target[i] = 0; 228 } 229 this.morph.morphing(morphs, target); 230 this.mesh._morphs._bufferDataFast(); 231 }, 232 _render: function() { 233 var core = enchant.Core.instance; 234 var scene = core.currentScene3D; 235 var light = scene.directionalLight; 236 var lvec = [ light._directionX, light._directionY, light._directionZ ]; 237 var uMVMatrix = mat4.identity(this.uMVMatrix); 238 mat4.multiply(scene._camera.mat, this.tmpMat, uMVMatrix); 239 var uNMatrix = mat4.identity(this.uNMatrix); 240 mat4.transpose(mat4.inverse(uMVMatrix, uNMatrix)); 241 var uLightDirection = vec3.normalize(lvec); 242 mat4.multiplyVec3(uNMatrix, uLightDirection); 243 core.GL.currentProgram.setAttributes({ 244 aVertexPosition: this.mesh._vertices, 245 aVertexNormal: this.mesh._normals, 246 aTextureCoord: this.mesh._texCoords, 247 aVectorFromBone1: this.mesh._vpos1, 248 aVectorFromBone2: this.mesh._vpos2, 249 aBone1Position: this.mesh._bone1pos, 250 aBone2Position: this.mesh._bone2pos, 251 aBone1Rotation: this.mesh._quats1, 252 aBone2Rotation: this.mesh._quats2, 253 aMultiPurposeVector: this.mesh._morphs, 254 aBoneWeight: this.mesh._weights, 255 aVertexEdge: this.mesh._edges 256 }); 257 core.GL.currentProgram.setUniforms({ 258 uLightDirection: uLightDirection, 259 uPMatrix: scene._camera.projMat, 260 uMVMatrix: uMVMatrix, 261 uNMatrix: uNMatrix 262 }); 263 var length; 264 var material; 265 var offset = 0; 266 for (var i = 0, l = this.mesh.materials.length; i < l; i++) { 267 material = this.mesh.materials[i]; 268 var u = { 269 uAmbientColor: material.ambient, 270 uDiffuseColor: material.diffuse, 271 uSpecularColor: material.specular, 272 uShininess: material.shininess, 273 uAlpha: material.alpha 274 }; 275 if (material.toon) { 276 u.uToon = material.toon; 277 } 278 if (material.texture) { 279 if (material.texture._image.src.match(/sph/)) { 280 u.uUseSphereMap = 1; 281 u.uUseTexture = 0; 282 u.uUseSphereMapAdditive = 0; 283 u.uSphereMap = material.texture; 284 } else { 285 u.uUseSphereMap = 0; 286 u.uUseTexture = 1; 287 u.uTexture = material.texture; 288 } 289 } else { 290 u.uUseTexture = 0; 291 u.uTexture = 0; 292 u.uUseSphereMap = 0; 293 } 294 core.GL.currentProgram.setUniforms(u); 295 296 297 length = material.face_vert_count; 298 enchant.Core.instance.GL.renderElements(this.mesh._indices, offset * 2, length); 299 300 if (material.edge_flag) { 301 enchant.gl.mmd.MMD_SHADER_PROGRAM.setUniforms({ uEdge: 1 }); 302 gl.cullFace(gl.FRONT); 303 enchant.Core.instance.GL.renderElements(this.mesh._indices, offset * 2, length); 304 gl.cullFace(gl.BACK); 305 enchant.gl.mmd.MMD_SHADER_PROGRAM.setUniforms({ uEdge: 0 }); 306 } 307 308 offset += material.face_vert_count; 309 } 310 }, 311 /** 312 * PMDファイルをロードする. 313 * ロード完了時にLOADイベントが発行される. 314 * @param {String} path ファイルパス 315 * @param {Function} [callback] ロード完了時のコールバック. 316 * @param {Function} [onerror] ロード失敗時のコールバック. 317 * @example 318 * // model/miku.pmd を読み込む. 319 * var mk = new MSprite3D(); 320 * mk.loadPmd('model/miku.pmd', function() { 321 * scene.addChild(mk); 322 * }); 323 */ 324 loadPmd: function(path, callback, onerror) { 325 var split = splitPath(path); 326 var model = new MMD.Model(split[1], split[2]); 327 var that = this; 328 this._data = model; 329 callback = callback || function() {}; 330 onerror = onerror || function() {}; 331 this.addEventListener('load', callback); 332 this.addEventListener('error', onerror); 333 model.load(function() { 334 var e; 335 try { 336 that._parse(model); 337 that.dispatchEvent(new enchant.Event(enchant.Event.LOAD)); 338 } catch (err) { 339 e = new enchant.Event(enchant.Event.ERROR); 340 e.message = err.message; 341 enchant.Core.instance.dispatchEvent(e); 342 that.dispatchEvent(e); 343 } 344 }); 345 }, 346 set: function(sp) { 347 this._parse(sp._data); 348 this._data = sp._data; 349 }, 350 clone: function() { 351 var sp = new enchant.gl.mmd.MSprite3D(); 352 sp._parse(this._data); 353 sp._data = this._data; 354 return sp; 355 }, 356 _parse: function(model) { 357 var data; 358 var original; 359 var params = [ 'ambient', 'diffuse', 'specular', 'shininess', 'alpha', 'face_vert_count', 'edge_flag' ]; 360 361 var mesh = new enchant.gl.mmd.MMesh(); 362 var length = model.vertices.length; 363 var v; 364 var b1, b2; 365 var ind; 366 var material; 367 var vertices = new Float32Array(length * 3); 368 var normals = new Float32Array(length * 3); 369 var texCoords = new Float32Array(length * 2); 370 var indices = new Uint16Array(model.triangles); 371 var vpos1 = new Float32Array(length * 3); 372 var vpos2 = new Float32Array(length * 3); 373 var bone1pos = new Float32Array(length * 3); 374 var bone2pos = new Float32Array(length * 3); 375 var quats1 = new Float32Array(length * 4); 376 var quats2 = new Float32Array(length * 4); 377 var morphs = new Float32Array(length * 3); 378 var weights = new Float32Array(length); 379 var edges = new Uint16Array(length); 380 var bindex1 = new Float32Array(length); 381 var bindex2 = new Float32Array(length); 382 var tmp = vec3.create(); 383 var tmp2 = vec3.create(); 384 for (var i = 0; i < length; i++) { 385 v = model.vertices[i]; 386 b1 = model.bones[v.bone_num1]; 387 b2 = model.bones[v.bone_num2]; 388 bindex1[i] = v.bone_num1; 389 bindex2[i] = v.bone_num2; 390 tmp.set([ v.x, v.y, v.z ]); 391 vertices.set(tmp, i * 3); 392 vec3.subtract(tmp, b1.head_pos, tmp2); 393 vpos1.set(tmp2, i * 3); 394 vec3.subtract(tmp, b2.head_pos, tmp2); 395 vpos2.set(tmp2, i * 3); 396 normals.set([ v.nx, v.ny, v.nz ], i * 3); 397 texCoords.set([ v.u, v.v ], i * 2); 398 bone1pos.set(b1.head_pos, i * 3); 399 bone2pos.set(b2.head_pos, i * 3); 400 quats1.set([ 0, 0, 0, 1 ], i * 4); 401 quats2.set([ 0, 0, 0, 1 ], i * 4); 402 morphs.set([ 0, 0, 0 ], i * 3); 403 weights[i] = v.bone_weight; 404 edges[i] = 1 - v.edge_flag; 405 } 406 407 408 mesh.vertices = vertices; 409 mesh.normals = normals; 410 mesh.texCoords = texCoords; 411 mesh.indices = indices; 412 mesh.vpos1 = vpos1; 413 mesh.vpos2 = vpos2; 414 mesh.bone1pos = bone1pos; 415 mesh.bone2pos = bone2pos; 416 mesh.quats1 = quats1; 417 mesh.quats2 = quats2; 418 mesh.weights = weights; 419 mesh.edges = edges; 420 mesh.morphs = morphs; 421 mesh.colors = new Float32Array(length * 4); 422 mesh.bindex1 = bindex1; 423 mesh.bindex2 = bindex2; 424 425 this.mesh = mesh; 426 427 this.mesh.materials = []; 428 429 this.skeleton = new enchant.gl.mmd.MSkeleton(model.bones); 430 var l; 431 for (i = 0, l = model.iks.length; i < l; i++) { 432 data = model.iks[i]; 433 this.skeleton._addIK(data); 434 } 435 436 this.morph = new enchant.gl.mmd.MMorph(model.morphs); 437 438 for (i = 0, l = model.materials.length; i < l; i++) { 439 original = model.materials[i]; 440 material = this.mesh.materials[i] = {}; 441 for (var prop in params) { 442 material[params[prop]] = original[params[prop]]; 443 } 444 if (typeof model.toon_file_names[i] !== 'undefined') { 445 material.toon = new enchant.gl.Texture(model.directory + '/' + model.toon_file_names[original.toon_index], {flipY: false}); 446 } 447 if (original.texture_file_name) { 448 material.texture = new enchant.gl.Texture(model.directory + '/' + original.texture_file_name); 449 } 450 } 451 }, 452 _applySkeleton: function() { 453 var sk = this.skeleton; 454 var mesh = this.mesh; 455 var b1pos, b2pos, b1rot, b2rot; 456 var i3 = 0, i4 = 0; 457 var length = this.mesh.vertices.length / 3; 458 for (var i = 0; i < length; i++) { 459 b1pos = sk.table[mesh.bindex1[i]]._globalpos; 460 b2pos = sk.table[mesh.bindex2[i]]._globalpos; 461 b1rot = sk.table[mesh.bindex1[i]]._globalrot; 462 b2rot = sk.table[mesh.bindex2[i]]._globalrot; 463 464 mesh._bone1pos._array[i3 + 0] = b1pos[0]; 465 mesh._bone1pos._array[i3 + 1] = b1pos[1]; 466 mesh._bone1pos._array[i3 + 2] = b1pos[2]; 467 mesh._bone2pos._array[i3 + 0] = b2pos[0]; 468 mesh._bone2pos._array[i3 + 1] = b2pos[1]; 469 mesh._bone2pos._array[i3 + 2] = b2pos[2]; 470 471 mesh._quats1._array[i4 + 0] = b1rot[0]; 472 mesh._quats1._array[i4 + 1] = b1rot[1]; 473 mesh._quats1._array[i4 + 2] = b1rot[2]; 474 mesh._quats1._array[i4 + 3] = b1rot[3]; 475 mesh._quats2._array[i4 + 0] = b2rot[0]; 476 mesh._quats2._array[i4 + 1] = b2rot[1]; 477 mesh._quats2._array[i4 + 2] = b2rot[2]; 478 mesh._quats2._array[i4 + 3] = b2rot[3]; 479 480 i3 += 3; 481 i4 += 4; 482 } 483 mesh._bone1pos._bufferDataFast(); 484 mesh._bone2pos._bufferDataFast(); 485 mesh._quats1._bufferDataFast(); 486 mesh._quats2._bufferDataFast(); 487 } 488 }); 489 490 491 enchant.gl.mmd.MPose = enchant.Class.create(enchant.gl.Pose, { 492 initialize: function(param) { 493 enchant.gl.Pose.call(this, param.location, param.rotation); 494 this._interpolation = param.interpolation; 495 }, 496 _internalInterpole: function(i, x) { 497 var x1 = this._interpolation[0 + i] / 127; 498 var y1 = this._interpolation[4 + i] / 127; 499 var x2 = this._interpolation[8 + i] / 127; 500 var y2 = this._interpolation[12 + i] / 127; 501 return this._bezierp(x1, y1, x2, y2, x); 502 }, 503 getInterpolation: function(another, ratio) { 504 var v = vec3.create(); 505 var q = quat4.create(); 506 var xt = this._internalInterpole(0, ratio); 507 var yt = this._internalInterpole(1, ratio); 508 var zt = this._internalInterpole(2, ratio); 509 var rt = this._internalInterpole(3, ratio); 510 v[0] = this._position[0] + (another._position[0] - this._position[0]) * xt; 511 v[1] = this._position[1] + (another._position[1] - this._position[1]) * yt; 512 v[2] = this._position[2] + (another._position[2] - this._position[2]) * zt; 513 var loc = v; 514 var rot = quat4.slerp(this._rotation, another._rotation, rt, q); 515 return new enchant.gl.Pose(loc, rot); 516 } 517 }); 518 519 enchant.gl.mmd.MMorph = enchant.Class.create({ 520 initialize: function(data) { 521 this._base = {}; 522 this._morphs = {}; 523 if (typeof data !== 'undefined') { 524 this._load(data); 525 } 526 }, 527 _load: function(data) { 528 this._base = data.slice(0, 1)[0]; 529 var m, name, vert, morph; 530 for (var i = 1, l = data.length; i < l; i++) { 531 m = data[i]; 532 name = m.name; 533 vert = m.vert_data; 534 morph = this._morphs[name] = {}; 535 morph.index = new Float32Array(vert.length); 536 morph.vert = new Float32Array(vert.length * 3); 537 for (var j = 0, ll = vert.length; j < ll; j++) { 538 morph.index[j] = this._base.vert_data[vert[j].index].index * 3; 539 morph.vert[j * 3] = vert[j].x; 540 morph.vert[j * 3 + 1] = vert[j].y; 541 morph.vert[j * 3 + 2] = vert[j].z; 542 } 543 } 544 }, 545 morphing: function(data, target) { 546 var weight, index; 547 for (var prop in data) { 548 weight = data[prop]._weight; 549 if (weight && this._morphs[prop]) { 550 this._morphing(prop, target, weight); 551 } 552 } 553 }, 554 _morphing: function(name, target, weight) { 555 var set = this._morphs[name]; 556 var index; 557 for (var i = 0, l = set.index.length; i < l; i++) { 558 index = set.index[i]; 559 target[index] += set.vert[i * 3] * weight; 560 target[index + 1] += set.vert[i * 3 + 1] * weight; 561 target[index + 2] += set.vert[i * 3 + 2] * weight; 562 } 563 } 564 }); 565 566 enchant.gl.mmd.MMorphPoint = enchant.Class.create({ 567 initialize: function(weight) { 568 this._weight = weight; 569 }, 570 getInterpolation: function(another, ratio) { 571 return new enchant.gl.mmd.MMorphPoint(lerp(this._weight, another._weight, ratio)); 572 } 573 }); 574 575 enchant.gl.mmd.MKeyFrameManager = enchant.Class.create(enchant.gl.KeyFrameManager, { 576 initialize: function() { 577 enchant.gl.KeyFrameManager.call(this); 578 } 579 }); 580 581 /** 582 * @scope enchant.gl.mmd.MAnimation.prototype 583 */ 584 enchant.gl.mmd.MAnimation = enchant.Class.create(enchant.EventTarget, { 585 /** 586 * VMDファイルに対応したアニメーションクラス. 587 * キャラクターの姿勢とモーフィングのデータが読み込まれる. 588 * 引数を渡すと{@link enchant.gl.mmd.MAnimation#loadVmd}が呼び出される. 589 * VMDファイルをプリロードすることでassets内に自動的に生成される. 590 * @param {String} [path] ファイルパス. 591 * @param {Function} [callback] ロード成功時のコールバック関数. 592 * @param {Function} [onerror] ロード失敗時のコールバック関数. 593 * @constructs 594 * @extends enchant.EventTarget 595 * @see enchant.gl.mmd.MAnimation#loadVmd 596 */ 597 initialize: function(path, callback, onerror) { 598 enchant.EventTarget.call(this); 599 this.length = -1; 600 if (arguments.length >= 2) { 601 this.loadVmd(path, callback, onerror); 602 } 603 }, 604 /** 605 * VMDファイルをロードする. 606 * ロード完了時にLOADイベントが発行される. 607 * @param {String} path ファイルパス 608 * @param {Function} callback コールバック関数 609 * @example 610 * // motion/dance.vmd を読み込む. 611 * var dance = new MAnimation(); 612 * dance.loadVmd('motion/dance.vmd', function() { 613 * mk.pushAnimation(dance); 614 * }); 615 */ 616 loadVmd: function(path, callback, onerror) { 617 var motion = new MMD.Motion(path); 618 var frame; 619 var that = this; 620 621 callback = callback || function() {}; 622 onerror = onerror || function() {}; 623 console.log(this); 624 this.addEventListener('load', callback); 625 this.addEventListener('error', onerror); 626 motion.load(function() { 627 var e; 628 try { 629 that.motions = parseMotion(motion.bone); 630 that.morphs = parseMorph(motion.morph); 631 that._calcLength(); 632 that.dispatchEvent(new enchant.Event(enchant.Event.LOAD)); 633 } catch (err) { 634 e = new enchant.Event(enchant.Event.ERROR); 635 e.message = err.message; 636 enchant.Core.instance.dispatchEvent(e); 637 that.dispatchEvent(e); 638 } 639 }); 640 }, 641 bake: function() { 642 var prop, manager; 643 for (prop in this.morphs) { 644 manager = this.morphs[prop]; 645 if (manager instanceof enchant.gl.mmd.MKeyFrameManager) { 646 manager.bake(); 647 } 648 } 649 for (prop in this.motions) { 650 manager = this.motions[prop]; 651 if (manager instanceof enchant.gl.mmd.MKeyFrameManager) { 652 manager.bake(); 653 } 654 } 655 }, 656 _tick: function(frame) { 657 var poses = this._getFrame(this.motions, frame); 658 var morphs = this._getFrame(this.morphs, frame); 659 return { 660 poses: poses, 661 morphs: morphs 662 }; 663 }, 664 _getFrame: function(data, frame) { 665 var ret = {}; 666 for (var prop in data) { 667 ret[prop] = data[prop].getFrame(frame); 668 } 669 return ret; 670 }, 671 _calcLength: function() { 672 var data, deta; 673 for (var prop in this) { 674 data = this[prop]; 675 if (data instanceof Object) { 676 for (var plop in data) { 677 deta = data[plop]; 678 if (deta instanceof enchant.gl.mmd.MKeyFrameManager) { 679 if (this.length < deta.length) { 680 this.length = deta.length; 681 } 682 } 683 } 684 } 685 } 686 } 687 }); 688 689 var parseMorph = function(data) { 690 var morphs = {}; 691 var morph, name, frame, weight; 692 for (var i = 0, l = data.length; i < l; i++) { 693 morph = data[i]; 694 name = morph.name; 695 frame = morph.frame; 696 weight = morph.weight; 697 if (typeof morphs[name] === 'undefined') { 698 morphs[name] = new enchant.gl.mmd.MKeyFrameManager(); 699 } 700 morphs[name].addFrame(new enchant.gl.mmd.MMorphPoint(weight), frame); 701 } 702 for (var prop in morphs) { 703 morphs[prop]._sort(); 704 } 705 return morphs; 706 }; 707 708 var parseMotion = function(data) { 709 var motions = {}; 710 var bone, name, frame; 711 for (var i = 0, l = data.length; i < l; i++) { 712 bone = data[i]; 713 name = bone.name; 714 frame = bone.frame; 715 if (typeof motions[name] === 'undefined') { 716 motions[name] = new enchant.gl.mmd.MKeyFrameManager(); 717 } 718 motions[name].addFrame(new enchant.gl.mmd.MPose(bone), frame); 719 } 720 for (var prop in motions) { 721 motions[prop]._sort(); 722 } 723 return motions; 724 }; 725 726 var bufferProto = Object.getPrototypeOf(enchant.gl.Buffer); 727 bufferProto.MORPHS = bufferProto.NORMALS; 728 bufferProto.QUATS = bufferProto.COLORS; 729 bufferProto.WEIGHTS = { 730 size: 1, 731 type: 5126, 732 norm: false, 733 stride: 0, 734 offset: 0, 735 btype: 34962, 736 usage: 35044, 737 Atype: Float32Array 738 }; 739 bufferProto.EDGES = { 740 size: 1, 741 type: 5123, 742 norm: false, 743 stride: 0, 744 offset: 0, 745 btype: 34962, 746 usage: 35044, 747 Atype: Uint16Array 748 }; 749 750 var _original_start = enchant.gl.Core.prototype.start; 751 enchant.gl.Core.prototype.start = function() { 752 enchant.gl.mmd.MMD_SHADER_PROGRAM = new enchant.gl.Shader(MMD_VERTEX_SHADER_SOURCE, MMD_FRAGMENT_SHADER_SOURCE); 753 this.GL.setProgram(enchant.gl.mmd.MMD_SHADER_PROGRAM); 754 enchant.gl.mmd.MMD_SHADER_PROGRAM.setUniforms({ 755 uLightMatrix: [ 756 1, 0, 0, 0, 757 0, 1, 0, 0, 758 0, 0, 1, 0, 759 0, 0, 0, 1 760 ], 761 uLightColor: [ 0.6, 0.6, 0.6 ], 762 uSelfShadow: 0, 763 uShadowMap: 0, 764 uGenerateShadowMap: 0, 765 uCenterPoint: 0, 766 uAxis: 0, 767 uAxisColor: [ 1, 0, 1 ], 768 uEdge: 0, 769 uEdgeColor: [ 0, 0, 0 ], 770 uEdgeThickness: 0.004 771 }); 772 this.GL.setDefaultProgram(); 773 _original_start.call(this); 774 }; 775 776 var lerp = function(n1, n2, r) { 777 return n1 + r * (n2 - n1); 778 }; 779 780 var MMD_VERTEX_SHADER_SOURCE = '\n\ 781 uniform mat4 uMVMatrix;\n\ 782 uniform mat4 uPMatrix;\n\ 783 uniform mat4 uNMatrix;\n\ 784 \n\ 785 uniform mat4 uLightMatrix;\n\ 786 \n\ 787 attribute vec3 aVertexNormal;\n\ 788 attribute vec2 aTextureCoord;\n\ 789 attribute float aVertexEdge;\n\ 790 \n\ 791 attribute float aBoneWeight;\n\ 792 attribute vec3 aVectorFromBone1;\n\ 793 attribute vec3 aVectorFromBone2;\n\ 794 attribute vec4 aBone1Rotation;\n\ 795 attribute vec4 aBone2Rotation;\n\ 796 attribute vec3 aBone1Position;\n\ 797 attribute vec3 aBone2Position;\n\ 798 \n\ 799 attribute vec3 aMultiPurposeVector;\n\ 800 \n\ 801 varying vec3 vPosition;\n\ 802 varying vec3 vNormal;\n\ 803 varying vec2 vTextureCoord;\n\ 804 varying vec4 vLightCoord;\n\ 805 \n\ 806 uniform float uEdgeThickness;\n\ 807 uniform bool uEdge;\n\ 808 \n\ 809 uniform bool uGenerateShadowMap;\n\ 810 \n\ 811 uniform bool uSelfShadow;\n\ 812 \n\ 813 uniform bool uAxis;\n\ 814 uniform bool uCenterPoint;\n\ 815 \n\ 816 vec3 qtransform(vec4 q, vec3 v) {\n\ 817 return v + 2.0 * cross(cross(v, q.xyz) - q.w*v, q.xyz);\n\ 818 }\n\ 819 \n\ 820 void main() {\n\ 821 vec3 position;\n\ 822 vec3 normal;\n\ 823 \n\ 824 if (uAxis || uCenterPoint) {\n\ 825 \n\ 826 position = aMultiPurposeVector;\n\ 827 \n\ 828 } else {\n\ 829 \n\ 830 float weight = aBoneWeight;\n\ 831 vec3 morph = aMultiPurposeVector;\n\ 832 \n\ 833 position = qtransform(aBone1Rotation, aVectorFromBone1 + morph) + aBone1Position;\n\ 834 normal = qtransform(aBone1Rotation, aVertexNormal);\n\ 835 \n\ 836 if (weight < 0.99) {\n\ 837 vec3 p2 = qtransform(aBone2Rotation, aVectorFromBone2 + morph) + aBone2Position;\n\ 838 vec3 n2 = qtransform(aBone2Rotation, normal);\n\ 839 \n\ 840 position = mix(p2, position, weight);\n\ 841 normal = normalize(mix(n2, normal, weight));\n\ 842 }\n\ 843 }\n\ 844 \n\ 845 \n\ 846 gl_Position = uPMatrix * uMVMatrix * vec4(position, 1.0);\n\ 847 \n\ 848 if (uCenterPoint) {\n\ 849 gl_Position.z = 0.0;\n\ 850 gl_PointSize = 16.0;\n\ 851 }\n\ 852 \n\ 853 if (uGenerateShadowMap || uAxis || uCenterPoint) return;\n\ 854 \n\ 855 \n\ 856 vTextureCoord = aTextureCoord;\n\ 857 vPosition = (uMVMatrix * vec4(position, 1.0)).xyz;\n\ 858 vNormal = (uNMatrix * vec4(normal, 1.0)).xyz;\n\ 859 \n\ 860 if (uSelfShadow) {\n\ 861 vLightCoord = uLightMatrix * vec4(position, 1.0);\n\ 862 }\n\ 863 \n\ 864 if (uEdge) {\n\ 865 vec4 pos = gl_Position;\n\ 866 vec4 pos2 = uPMatrix * uMVMatrix * vec4(position + normal, 1.0);\n\ 867 vec4 norm = normalize(pos2 - pos);\n\ 868 gl_Position = pos + norm * uEdgeThickness * aVertexEdge * pos.w;\n\ 869 return;\n\ 870 }\n\ 871 }\n\ 872 '; 873 874 var MMD_FRAGMENT_SHADER_SOURCE = '\n\ 875 #ifdef GL_ES\n\ 876 precision highp float;\n\ 877 #endif\n\ 878 \n\ 879 varying vec2 vTextureCoord;\n\ 880 varying vec3 vPosition;\n\ 881 varying vec3 vNormal;\n\ 882 varying vec4 vLightCoord;\n\ 883 \n\ 884 uniform vec3 uLightDirection;\n\ 885 uniform vec3 uLightColor;\n\ 886 \n\ 887 uniform vec3 uAmbientColor;\n\ 888 uniform vec3 uSpecularColor;\n\ 889 uniform vec3 uDiffuseColor;\n\ 890 uniform float uAlpha;\n\ 891 uniform float uShininess;\n\ 892 \n\ 893 uniform bool uUseTexture;\n\ 894 uniform bool uUseSphereMap;\n\ 895 uniform bool uIsSphereMapAdditive;\n\ 896 \n\ 897 uniform sampler2D uToon;\n\ 898 uniform sampler2D uTexture;\n\ 899 uniform sampler2D uSphereMap;\n\ 900 \n\ 901 uniform bool uEdge;\n\ 902 uniform float uEdgeThickness;\n\ 903 uniform vec3 uEdgeColor;\n\ 904 \n\ 905 uniform bool uGenerateShadowMap;\n\ 906 uniform bool uSelfShadow;\n\ 907 uniform sampler2D uShadowMap;\n\ 908 \n\ 909 uniform bool uAxis;\n\ 910 uniform vec3 uAxisColor;\n\ 911 uniform bool uCenterPoint;\n\ 912 \n\ 913 // from http://spidergl.org/example.php?id=6\n\ 914 vec4 pack_depth(const in float depth) {\n\ 915 const vec4 bit_shift = vec4(256.0*256.0*256.0, 256.0*256.0, 256.0, 1.0);\n\ 916 const vec4 bit_mask = vec4(0.0, 1.0/256.0, 1.0/256.0, 1.0/256.0);\n\ 917 vec4 res = fract(depth * bit_shift);\n\ 918 res -= res.xxyz * bit_mask;\n\ 919 return res;\n\ 920 }\n\ 921 float unpack_depth(const in vec4 rgba_depth)\n\ 922 {\n\ 923 const vec4 bit_shift = vec4(1.0/(256.0*256.0*256.0), 1.0/(256.0*256.0), 1.0/256.0, 1.0);\n\ 924 float depth = dot(rgba_depth, bit_shift);\n\ 925 return depth;\n\ 926 }\n\ 927 \n\ 928 void main() {\n\ 929 if (uGenerateShadowMap) {\n\ 930 \n\ 931 gl_FragColor = pack_depth(gl_FragCoord.z);\n\ 932 return;\n\ 933 }\n\ 934 if (uAxis) {\n\ 935 gl_FragColor = vec4(uAxisColor, 1.0);\n\ 936 return;\n\ 937 }\n\ 938 if (uCenterPoint) {\n\ 939 vec2 uv = gl_PointCoord * 2.0 - 1.0;\n\ 940 float w = dot(uv, uv);\n\ 941 if (w < 0.3 || (w > 0.5 && w < 1.0)) {\n\ 942 gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n\ 943 } else {\n\ 944 discard;\n\ 945 }\n\ 946 return;\n\ 947 }\n\ 948 \n\ 949 \n\ 950 vec3 norm = normalize(vNormal);\n\ 951 vec3 cameraDirection = normalize(-vPosition);\n\ 952 \n\ 953 vec3 color;\n\ 954 float alpha = uAlpha;\n\ 955 \n\ 956 if (uEdge) {\n\ 957 \n\ 958 color = uEdgeColor;\n\ 959 \n\ 960 } else {\n\ 961 \n\ 962 color = vec3(1.0, 1.0, 1.0);\n\ 963 if (uUseTexture) {\n\ 964 vec4 texColor = texture2D(uTexture, vTextureCoord);\n\ 965 color *= texColor.rgb;\n\ 966 alpha *= texColor.a;\n\ 967 }\n\ 968 if (uUseSphereMap) {\n\ 969 vec2 sphereCoord = 0.5 * (1.0 + vec2(1.0, -1.0) * norm.xy);\n\ 970 if (uIsSphereMapAdditive) {\n\ 971 color += texture2D(uSphereMap, sphereCoord).rgb;\n\ 972 } else {\n\ 973 color *= texture2D(uSphereMap, sphereCoord).rgb;\n\ 974 }\n\ 975 }\n\ 976 \n\ 977 \n\ 978 vec3 halfAngle = normalize(uLightDirection + cameraDirection);\n\ 979 float specularWeight = pow( max(0.001, dot(halfAngle, norm)) , uShininess );\n\ 980 \n\ 981 vec3 specular = specularWeight * uSpecularColor;\n\ 982 \n\ 983 vec2 toonCoord = vec2(0.0, 0.5 * (1.0 - dot( uLightDirection, norm )));\n\ 984 \n\ 985 if (uSelfShadow) {\n\ 986 vec3 lightCoord = vLightCoord.xyz / vLightCoord.w;\n\ 987 vec4 rgbaDepth = texture2D(uShadowMap, lightCoord.xy);\n\ 988 float depth = unpack_depth(rgbaDepth);\n\ 989 if (depth < lightCoord.z - 0.01) {\n\ 990 toonCoord = vec2(0.0, 0.55);\n\ 991 }\n\ 992 }\n\ 993 \n\ 994 color *= uAmbientColor + uLightColor * (uDiffuseColor + specular);\n\ 995 \n\ 996 color = clamp(color, 0.0, 1.0);\n\ 997 color *= texture2D(uToon, toonCoord).rgb;\n\ 998 \n\ 999 }\n\ 1000 gl_FragColor = vec4(color, alpha);\n\ 1001 \n\ 1002 }\n\ 1003 '; 1004 }()); 1005