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 * Plugin to allow use of MikuMikuDance PMD and VMD files in gl.enchant.js. 11 * 12 * @detail 13 * MMD.js' MMD.Model and MMD.Motion are used in file loading and parse. 14 * Shader source is quoted from MMD.VertexShaderSource and MMD.FragmentShaderSource. 15 * 16 * MMD.js: 17 * https://github.com/edvakf/MMD.js 18 * About 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 mesh object. 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 * Sprite3D optimized for PMD files. 159 * By preloading PMD file, it will be set in assets automatically. 160 * @param {String} [path] file path. 161 * @param {Function} [callback] on load callback. 162 * @param {Function} [onerror] on error callback. 163 * @constructs 164 * @extends enchant.gl.Sprite3D 165 */ 166 initialize: function(path, callback, onerror) { 167 enchant.gl.Sprite3D.call(this); 168 this.program = enchant.gl.mmd.MMD_SHADER_PROGRAM; 169 this.animation = []; 170 this.uMVMatrix = mat4.create(); 171 this.uNMatrix = mat4.create(); 172 173 this.addEventListener('enterframe', function() { 174 var first; 175 var skeleton = this.skeleton; 176 var morph = this.morph; 177 if (this.animation.length === 0) { 178 } else { 179 first = this.animation[0]; 180 181 var data = first.animation._tick(first.frame); 182 first.frame++; 183 184 this._skinning(data.poses); 185 186 this._morphing(data.morphs); 187 188 if (first.frame > first.animation.length) { 189 first = this.animation.shift(); 190 if (this.loop) { 191 first.frame = 0; 192 this.animation.push(first); 193 } 194 } 195 } 196 }); 197 if (arguments.length >= 2) { 198 this.loadPmd(path, callback, onerror); 199 } 200 }, 201 /** 202 * Add animation. 203 * Animation will be played in the order that it is added. 204 * @param {enchant.gl.mmd.MAnimation} animation 205 */ 206 pushAnimation: function(animation) { 207 this.animation.push({ frame: 0, animation: animation }); 208 }, 209 /** 210 * Delete added animation. 211 */ 212 clearAnimation: function(animation) { 213 this.animation = []; 214 }, 215 _skinning: function(poses) { 216 var skeleton = this.skeleton; 217 skeleton.setPoses(poses); 218 skeleton.solveFKs(); 219 skeleton.solveIKs(); 220 this._applySkeleton(); 221 222 }, 223 _morphing: function(morphs) { 224 var target = this.mesh.morphs; 225 for (var i = 0, l = target.length; i < l; i++) { 226 target[i] = 0; 227 } 228 this.morph.morphing(morphs, target); 229 this.mesh._morphs._bufferDataFast(); 230 }, 231 _render: function() { 232 var core = enchant.Core.instance; 233 var scene = core.currentScene3D; 234 var light = scene.directionalLight; 235 var lvec = [ light._directionX, light._directionY, light._directionZ ]; 236 var uMVMatrix = mat4.identity(this.uMVMatrix); 237 mat4.multiply(scene._camera.mat, this.tmpMat, uMVMatrix); 238 var uNMatrix = mat4.identity(this.uNMatrix); 239 mat4.transpose(mat4.inverse(uMVMatrix, uNMatrix)); 240 var uLightDirection = vec3.normalize(lvec); 241 mat4.multiplyVec3(uNMatrix, uLightDirection); 242 core.GL.currentProgram.setAttributes({ 243 aVertexPosition: this.mesh._vertices, 244 aVertexNormal: this.mesh._normals, 245 aTextureCoord: this.mesh._texCoords, 246 aVectorFromBone1: this.mesh._vpos1, 247 aVectorFromBone2: this.mesh._vpos2, 248 aBone1Position: this.mesh._bone1pos, 249 aBone2Position: this.mesh._bone2pos, 250 aBone1Rotation: this.mesh._quats1, 251 aBone2Rotation: this.mesh._quats2, 252 aMultiPurposeVector: this.mesh._morphs, 253 aBoneWeight: this.mesh._weights, 254 aVertexEdge: this.mesh._edges 255 }); 256 core.GL.currentProgram.setUniforms({ 257 uLightDirection: uLightDirection, 258 uPMatrix: scene._camera.projMat, 259 uMVMatrix: uMVMatrix, 260 uNMatrix: uNMatrix 261 }); 262 var length; 263 var material; 264 var offset = 0; 265 for (var i = 0, l = this.mesh.materials.length; i < l; i++) { 266 material = this.mesh.materials[i]; 267 var u = { 268 uAmbientColor: material.ambient, 269 uDiffuseColor: material.diffuse, 270 uSpecularColor: material.specular, 271 uShininess: material.shininess, 272 uAlpha: material.alpha 273 }; 274 if (material.toon) { 275 u.uToon = material.toon; 276 } 277 if (material.texture) { 278 if (material.texture._image.src.match(/sph/)) { 279 u.uUseSphereMap = 1; 280 u.uUseTexture = 0; 281 u.uUseSphereMapAdditive = 0; 282 u.uSphereMap = material.texture; 283 } else { 284 u.uUseSphereMap = 0; 285 u.uUseTexture = 1; 286 u.uTexture = material.texture; 287 } 288 } else { 289 u.uUseTexture = 0; 290 u.uTexture = 0; 291 u.uUseSphereMap = 0; 292 } 293 core.GL.currentProgram.setUniforms(u); 294 295 296 length = material.face_vert_count; 297 enchant.Core.instance.GL.renderElements(this.mesh._indices, offset * 2, length); 298 299 if (material.edge_flag) { 300 enchant.gl.mmd.MMD_SHADER_PROGRAM.setUniforms({ uEdge: 1 }); 301 gl.cullFace(gl.FRONT); 302 enchant.Core.instance.GL.renderElements(this.mesh._indices, offset * 2, length); 303 gl.cullFace(gl.BACK); 304 enchant.gl.mmd.MMD_SHADER_PROGRAM.setUniforms({ uEdge: 0 }); 305 } 306 307 offset += material.face_vert_count; 308 } 309 }, 310 /** 311 * Load PMD files. 312 * Will be dispatched LOAD event when data has loaded. 313 * @param {String} path File path 314 * @param {Function} [callback] onload callback. 315 * @param {Function} [onerror] onerror callback. 316 * @example 317 * // model/miku.pmd loading. 318 * var mk = new MSprite3D(); 319 * mk.loadPmd('model/miku.pmd', function() { 320 * scene.addChild(mk); 321 * }); 322 */ 323 loadPmd: function(path, callback, onerror) { 324 var split = splitPath(path); 325 var model = new MMD.Model(split[1], split[2]); 326 var that = this; 327 this._data = model; 328 callback = callback || function() {}; 329 onerror = onerror || function() {}; 330 this.addEventListener('load', callback); 331 this.addEventListener('error', onerror); 332 model.load(function() { 333 var e; 334 try { 335 that._parse(model); 336 that.dispatchEvent(new enchant.Event(enchant.Event.LOAD)); 337 } catch (err) { 338 e = new enchant.Event(enchant.Event.ERROR); 339 e.message = err.message; 340 enchant.Core.instance.dispatchEvent(e); 341 that.dispatchEvent(e); 342 } 343 }); 344 }, 345 set: function(sp) { 346 this._parse(sp._data); 347 this._data = sp._data; 348 }, 349 clone: function() { 350 var sp = new enchant.gl.mmd.MSprite3D(); 351 sp._parse(this._data); 352 sp._data = this._data; 353 return sp; 354 }, 355 _parse: function(model) { 356 var data; 357 var original; 358 var params = [ 'ambient', 'diffuse', 'specular', 'shininess', 'alpha', 'face_vert_count', 'edge_flag' ]; 359 360 var mesh = new enchant.gl.mmd.MMesh(); 361 var length = model.vertices.length; 362 var v; 363 var b1, b2; 364 var ind; 365 var material; 366 var vertices = new Float32Array(length * 3); 367 var normals = new Float32Array(length * 3); 368 var texCoords = new Float32Array(length * 2); 369 var indices = new Uint16Array(model.triangles); 370 var vpos1 = new Float32Array(length * 3); 371 var vpos2 = new Float32Array(length * 3); 372 var bone1pos = new Float32Array(length * 3); 373 var bone2pos = new Float32Array(length * 3); 374 var quats1 = new Float32Array(length * 4); 375 var quats2 = new Float32Array(length * 4); 376 var morphs = new Float32Array(length * 3); 377 var weights = new Float32Array(length); 378 var edges = new Uint16Array(length); 379 var bindex1 = new Float32Array(length); 380 var bindex2 = new Float32Array(length); 381 var tmp = vec3.create(); 382 var tmp2 = vec3.create(); 383 for (var i = 0; i < length; i++) { 384 v = model.vertices[i]; 385 b1 = model.bones[v.bone_num1]; 386 b2 = model.bones[v.bone_num2]; 387 bindex1[i] = v.bone_num1; 388 bindex2[i] = v.bone_num2; 389 tmp.set([ v.x, v.y, v.z ]); 390 vertices.set(tmp, i * 3); 391 vec3.subtract(tmp, b1.head_pos, tmp2); 392 vpos1.set(tmp2, i * 3); 393 vec3.subtract(tmp, b2.head_pos, tmp2); 394 vpos2.set(tmp2, i * 3); 395 normals.set([ v.nx, v.ny, v.nz ], i * 3); 396 texCoords.set([ v.u, v.v ], i * 2); 397 bone1pos.set(b1.head_pos, i * 3); 398 bone2pos.set(b2.head_pos, i * 3); 399 quats1.set([ 0, 0, 0, 1 ], i * 4); 400 quats2.set([ 0, 0, 0, 1 ], i * 4); 401 morphs.set([ 0, 0, 0 ], i * 3); 402 weights[i] = v.bone_weight; 403 edges[i] = 1 - v.edge_flag; 404 } 405 406 407 mesh.vertices = vertices; 408 mesh.normals = normals; 409 mesh.texCoords = texCoords; 410 mesh.indices = indices; 411 mesh.vpos1 = vpos1; 412 mesh.vpos2 = vpos2; 413 mesh.bone1pos = bone1pos; 414 mesh.bone2pos = bone2pos; 415 mesh.quats1 = quats1; 416 mesh.quats2 = quats2; 417 mesh.weights = weights; 418 mesh.edges = edges; 419 mesh.morphs = morphs; 420 mesh.colors = new Float32Array(length * 4); 421 mesh.bindex1 = bindex1; 422 mesh.bindex2 = bindex2; 423 424 this.mesh = mesh; 425 426 this.mesh.materials = []; 427 428 this.skeleton = new enchant.gl.mmd.MSkeleton(model.bones); 429 var l; 430 for (i = 0, l = model.iks.length; i < l; i++) { 431 data = model.iks[i]; 432 this.skeleton._addIK(data); 433 } 434 435 this.morph = new enchant.gl.mmd.MMorph(model.morphs); 436 437 for (i = 0, l = model.materials.length; i < l; i++) { 438 original = model.materials[i]; 439 material = this.mesh.materials[i] = {}; 440 for (var prop in params) { 441 material[params[prop]] = original[params[prop]]; 442 } 443 if (typeof model.toon_file_names[i] !== 'undefined') { 444 material.toon = new enchant.gl.Texture(model.directory + '/' + model.toon_file_names[original.toon_index], {flipY: false}); 445 } 446 if (original.texture_file_name) { 447 material.texture = new enchant.gl.Texture(model.directory + '/' + original.texture_file_name); 448 } 449 } 450 }, 451 _applySkeleton: function() { 452 var sk = this.skeleton; 453 var mesh = this.mesh; 454 var b1pos, b2pos, b1rot, b2rot; 455 var i3 = 0, i4 = 0; 456 var length = this.mesh.vertices.length / 3; 457 for (var i = 0; i < length; i++) { 458 b1pos = sk.table[mesh.bindex1[i]]._globalpos; 459 b2pos = sk.table[mesh.bindex2[i]]._globalpos; 460 b1rot = sk.table[mesh.bindex1[i]]._globalrot; 461 b2rot = sk.table[mesh.bindex2[i]]._globalrot; 462 463 mesh._bone1pos._array[i3 + 0] = b1pos[0]; 464 mesh._bone1pos._array[i3 + 1] = b1pos[1]; 465 mesh._bone1pos._array[i3 + 2] = b1pos[2]; 466 mesh._bone2pos._array[i3 + 0] = b2pos[0]; 467 mesh._bone2pos._array[i3 + 1] = b2pos[1]; 468 mesh._bone2pos._array[i3 + 2] = b2pos[2]; 469 470 mesh._quats1._array[i4 + 0] = b1rot[0]; 471 mesh._quats1._array[i4 + 1] = b1rot[1]; 472 mesh._quats1._array[i4 + 2] = b1rot[2]; 473 mesh._quats1._array[i4 + 3] = b1rot[3]; 474 mesh._quats2._array[i4 + 0] = b2rot[0]; 475 mesh._quats2._array[i4 + 1] = b2rot[1]; 476 mesh._quats2._array[i4 + 2] = b2rot[2]; 477 mesh._quats2._array[i4 + 3] = b2rot[3]; 478 479 i3 += 3; 480 i4 += 4; 481 } 482 mesh._bone1pos._bufferDataFast(); 483 mesh._bone2pos._bufferDataFast(); 484 mesh._quats1._bufferDataFast(); 485 mesh._quats2._bufferDataFast(); 486 } 487 }); 488 489 490 enchant.gl.mmd.MPose = enchant.Class.create(enchant.gl.Pose, { 491 initialize: function(param) { 492 enchant.gl.Pose.call(this, param.location, param.rotation); 493 this._interpolation = param.interpolation; 494 }, 495 _internalInterpole: function(i, x) { 496 var x1 = this._interpolation[0 + i] / 127; 497 var y1 = this._interpolation[4 + i] / 127; 498 var x2 = this._interpolation[8 + i] / 127; 499 var y2 = this._interpolation[12 + i] / 127; 500 return this._bezierp(x1, y1, x2, y2, x); 501 }, 502 getInterpolation: function(another, ratio) { 503 var v = vec3.create(); 504 var q = quat4.create(); 505 var xt = this._internalInterpole(0, ratio); 506 var yt = this._internalInterpole(1, ratio); 507 var zt = this._internalInterpole(2, ratio); 508 var rt = this._internalInterpole(3, ratio); 509 v[0] = this._position[0] + (another._position[0] - this._position[0]) * xt; 510 v[1] = this._position[1] + (another._position[1] - this._position[1]) * yt; 511 v[2] = this._position[2] + (another._position[2] - this._position[2]) * zt; 512 var loc = v; 513 var rot = quat4.slerp(this._rotation, another._rotation, rt, q); 514 return new enchant.gl.Pose(loc, rot); 515 } 516 }); 517 518 enchant.gl.mmd.MMorph = enchant.Class.create({ 519 initialize: function(data) { 520 this._base = {}; 521 this._morphs = {}; 522 if (typeof data !== 'undefined') { 523 this._load(data); 524 } 525 }, 526 _load: function(data) { 527 this._base = data.slice(0, 1)[0]; 528 var m, name, vert, morph; 529 for (var i = 1, l = data.length; i < l; i++) { 530 m = data[i]; 531 name = m.name; 532 vert = m.vert_data; 533 morph = this._morphs[name] = {}; 534 morph.index = new Float32Array(vert.length); 535 morph.vert = new Float32Array(vert.length * 3); 536 for (var j = 0, ll = vert.length; j < ll; j++) { 537 morph.index[j] = this._base.vert_data[vert[j].index].index * 3; 538 morph.vert[j * 3] = vert[j].x; 539 morph.vert[j * 3 + 1] = vert[j].y; 540 morph.vert[j * 3 + 2] = vert[j].z; 541 } 542 } 543 }, 544 morphing: function(data, target) { 545 var weight, index; 546 for (var prop in data) { 547 weight = data[prop]._weight; 548 if (weight && this._morphs[prop]) { 549 this._morphing(prop, target, weight); 550 } 551 } 552 }, 553 _morphing: function(name, target, weight) { 554 var set = this._morphs[name]; 555 var index; 556 for (var i = 0, l = set.index.length; i < l; i++) { 557 index = set.index[i]; 558 target[index] += set.vert[i * 3] * weight; 559 target[index + 1] += set.vert[i * 3 + 1] * weight; 560 target[index + 2] += set.vert[i * 3 + 2] * weight; 561 } 562 } 563 }); 564 565 enchant.gl.mmd.MMorphPoint = enchant.Class.create({ 566 initialize: function(weight) { 567 this._weight = weight; 568 }, 569 getInterpolation: function(another, ratio) { 570 return new enchant.gl.mmd.MMorphPoint(lerp(this._weight, another._weight, ratio)); 571 } 572 }); 573 574 enchant.gl.mmd.MKeyFrameManager = enchant.Class.create(enchant.gl.KeyFrameManager, { 575 initialize: function() { 576 enchant.gl.KeyFrameManager.call(this); 577 } 578 }); 579 580 /** 581 * @scope enchant.gl.mmd.MAnimation.prototype 582 */ 583 enchant.gl.mmd.MAnimation = enchant.Class.create(enchant.EventTarget, { 584 /** 585 * Animation class optimized to VMD file. 586 * Character data and morphing are loaded. 587 * By preloading VMD file, it will be set in assets automatically. 588 * If argument is delivered {@link enchant.gl.mmd.MAnimation#loadVmd} will be called up. 589 * @param {String} [path] File path. 590 * @param {Function} [callback] onload callback. 591 * @param {Function} [onerror] onerror callback. 592 * @constructs 593 * @extends enchant.EventTarget 594 * @see enchant.gl.mmd.MAnimation#loadVmd 595 */ 596 initialize: function(path, callback, onerror) { 597 enchant.EventTarget.call(this); 598 this.length = -1; 599 if (arguments.length >= 2) { 600 this.loadVmd(path, callback, onerror); 601 } 602 }, 603 /** 604 * Load VMD file. 605 * Will be dispatched LOAD event when data has loaded. 606 * @param {String} path File path 607 * @param {Function} callback Callback function 608 * @example 609 * // motion/dance.vmd is loaded. 610 * var dance = new MAnimation(); 611 * dance.loadVmd('motion/dance.vmd', function() { 612 * mk.pushAnimation(dance); 613 * }); 614 */ 615 loadVmd: function(path, callback, onerror) { 616 var motion = new MMD.Motion(path); 617 var frame; 618 var that = this; 619 620 callback = callback || function() {}; 621 onerror = onerror || function() {}; 622 console.log(this); 623 this.addEventListener('load', callback); 624 this.addEventListener('error', onerror); 625 motion.load(function() { 626 var e; 627 try { 628 that.motions = parseMotion(motion.bone); 629 that.morphs = parseMorph(motion.morph); 630 that._calcLength(); 631 that.dispatchEvent(new enchant.Event(enchant.Event.LOAD)); 632 } catch (err) { 633 e = new enchant.Event(enchant.Event.ERROR); 634 e.message = err.message; 635 enchant.Core.instance.dispatchEvent(e); 636 that.dispatchEvent(e); 637 } 638 }); 639 }, 640 bake: function() { 641 var prop, manager; 642 for (prop in this.morphs) { 643 manager = this.morphs[prop]; 644 if (manager instanceof enchant.gl.mmd.MKeyFrameManager) { 645 manager.bake(); 646 } 647 } 648 for (prop in this.motions) { 649 manager = this.motions[prop]; 650 if (manager instanceof enchant.gl.mmd.MKeyFrameManager) { 651 manager.bake(); 652 } 653 } 654 }, 655 _tick: function(frame) { 656 var poses = this._getFrame(this.motions, frame); 657 var morphs = this._getFrame(this.morphs, frame); 658 return { 659 poses: poses, 660 morphs: morphs 661 }; 662 }, 663 _getFrame: function(data, frame) { 664 var ret = {}; 665 for (var prop in data) { 666 ret[prop] = data[prop].getFrame(frame); 667 } 668 return ret; 669 }, 670 _calcLength: function() { 671 var data, deta; 672 for (var prop in this) { 673 data = this[prop]; 674 if (data instanceof Object) { 675 for (var plop in data) { 676 deta = data[plop]; 677 if (deta instanceof enchant.gl.mmd.MKeyFrameManager) { 678 if (this.length < deta.length) { 679 this.length = deta.length; 680 } 681 } 682 } 683 } 684 } 685 } 686 }); 687 688 var parseMorph = function(data) { 689 var morphs = {}; 690 var morph, name, frame, weight; 691 for (var i = 0, l = data.length; i < l; i++) { 692 morph = data[i]; 693 name = morph.name; 694 frame = morph.frame; 695 weight = morph.weight; 696 if (typeof morphs[name] === 'undefined') { 697 morphs[name] = new enchant.gl.mmd.MKeyFrameManager(); 698 } 699 morphs[name].addFrame(new enchant.gl.mmd.MMorphPoint(weight), frame); 700 } 701 for (var prop in morphs) { 702 morphs[prop]._sort(); 703 } 704 return morphs; 705 }; 706 707 var parseMotion = function(data) { 708 var motions = {}; 709 var bone, name, frame; 710 for (var i = 0, l = data.length; i < l; i++) { 711 bone = data[i]; 712 name = bone.name; 713 frame = bone.frame; 714 if (typeof motions[name] === 'undefined') { 715 motions[name] = new enchant.gl.mmd.MKeyFrameManager(); 716 } 717 motions[name].addFrame(new enchant.gl.mmd.MPose(bone), frame); 718 } 719 for (var prop in motions) { 720 motions[prop]._sort(); 721 } 722 return motions; 723 }; 724 725 var bufferProto = Object.getPrototypeOf(enchant.gl.Buffer); 726 bufferProto.MORPHS = bufferProto.NORMALS; 727 bufferProto.QUATS = bufferProto.COLORS; 728 bufferProto.WEIGHTS = { 729 size: 1, 730 type: 5126, 731 norm: false, 732 stride: 0, 733 offset: 0, 734 btype: 34962, 735 usage: 35044, 736 Atype: Float32Array 737 }; 738 bufferProto.EDGES = { 739 size: 1, 740 type: 5123, 741 norm: false, 742 stride: 0, 743 offset: 0, 744 btype: 34962, 745 usage: 35044, 746 Atype: Uint16Array 747 }; 748 749 var _original_start = enchant.gl.Core.prototype.start; 750 enchant.gl.Core.prototype.start = function() { 751 enchant.gl.mmd.MMD_SHADER_PROGRAM = new enchant.gl.Shader(MMD_VERTEX_SHADER_SOURCE, MMD_FRAGMENT_SHADER_SOURCE); 752 this.GL.setProgram(enchant.gl.mmd.MMD_SHADER_PROGRAM); 753 enchant.gl.mmd.MMD_SHADER_PROGRAM.setUniforms({ 754 uLightMatrix: [ 755 1, 0, 0, 0, 756 0, 1, 0, 0, 757 0, 0, 1, 0, 758 0, 0, 0, 1 759 ], 760 uLightColor: [ 0.6, 0.6, 0.6 ], 761 uSelfShadow: 0, 762 uShadowMap: 0, 763 uGenerateShadowMap: 0, 764 uCenterPoint: 0, 765 uAxis: 0, 766 uAxisColor: [ 1, 0, 1 ], 767 uEdge: 0, 768 uEdgeColor: [ 0, 0, 0 ], 769 uEdgeThickness: 0.004 770 }); 771 this.GL.setDefaultProgram(); 772 _original_start.call(this); 773 }; 774 775 var lerp = function(n1, n2, r) { 776 return n1 + r * (n2 - n1); 777 }; 778 779 var MMD_VERTEX_SHADER_SOURCE = '\n\ 780 uniform mat4 uMVMatrix;\n\ 781 uniform mat4 uPMatrix;\n\ 782 uniform mat4 uNMatrix;\n\ 783 \n\ 784 uniform mat4 uLightMatrix;\n\ 785 \n\ 786 attribute vec3 aVertexNormal;\n\ 787 attribute vec2 aTextureCoord;\n\ 788 attribute float aVertexEdge;\n\ 789 \n\ 790 attribute float aBoneWeight;\n\ 791 attribute vec3 aVectorFromBone1;\n\ 792 attribute vec3 aVectorFromBone2;\n\ 793 attribute vec4 aBone1Rotation;\n\ 794 attribute vec4 aBone2Rotation;\n\ 795 attribute vec3 aBone1Position;\n\ 796 attribute vec3 aBone2Position;\n\ 797 \n\ 798 attribute vec3 aMultiPurposeVector;\n\ 799 \n\ 800 varying vec3 vPosition;\n\ 801 varying vec3 vNormal;\n\ 802 varying vec2 vTextureCoord;\n\ 803 varying vec4 vLightCoord;\n\ 804 \n\ 805 uniform float uEdgeThickness;\n\ 806 uniform bool uEdge;\n\ 807 \n\ 808 uniform bool uGenerateShadowMap;\n\ 809 \n\ 810 uniform bool uSelfShadow;\n\ 811 \n\ 812 uniform bool uAxis;\n\ 813 uniform bool uCenterPoint;\n\ 814 \n\ 815 vec3 qtransform(vec4 q, vec3 v) {\n\ 816 return v + 2.0 * cross(cross(v, q.xyz) - q.w*v, q.xyz);\n\ 817 }\n\ 818 \n\ 819 void main() {\n\ 820 vec3 position;\n\ 821 vec3 normal;\n\ 822 \n\ 823 if (uAxis || uCenterPoint) {\n\ 824 \n\ 825 position = aMultiPurposeVector;\n\ 826 \n\ 827 } else {\n\ 828 \n\ 829 float weight = aBoneWeight;\n\ 830 vec3 morph = aMultiPurposeVector;\n\ 831 \n\ 832 position = qtransform(aBone1Rotation, aVectorFromBone1 + morph) + aBone1Position;\n\ 833 normal = qtransform(aBone1Rotation, aVertexNormal);\n\ 834 \n\ 835 if (weight < 0.99) {\n\ 836 vec3 p2 = qtransform(aBone2Rotation, aVectorFromBone2 + morph) + aBone2Position;\n\ 837 vec3 n2 = qtransform(aBone2Rotation, normal);\n\ 838 \n\ 839 position = mix(p2, position, weight);\n\ 840 normal = normalize(mix(n2, normal, weight));\n\ 841 }\n\ 842 }\n\ 843 \n\ 844 \n\ 845 gl_Position = uPMatrix * uMVMatrix * vec4(position, 1.0);\n\ 846 \n\ 847 if (uCenterPoint) {\n\ 848 gl_Position.z = 0.0;\n\ 849 gl_PointSize = 16.0;\n\ 850 }\n\ 851 \n\ 852 if (uGenerateShadowMap || uAxis || uCenterPoint) return;\n\ 853 \n\ 854 \n\ 855 vTextureCoord = aTextureCoord;\n\ 856 vPosition = (uMVMatrix * vec4(position, 1.0)).xyz;\n\ 857 vNormal = (uNMatrix * vec4(normal, 1.0)).xyz;\n\ 858 \n\ 859 if (uSelfShadow) {\n\ 860 vLightCoord = uLightMatrix * vec4(position, 1.0);\n\ 861 }\n\ 862 \n\ 863 if (uEdge) {\n\ 864 vec4 pos = gl_Position;\n\ 865 vec4 pos2 = uPMatrix * uMVMatrix * vec4(position + normal, 1.0);\n\ 866 vec4 norm = normalize(pos2 - pos);\n\ 867 gl_Position = pos + norm * uEdgeThickness * aVertexEdge * pos.w;\n\ 868 return;\n\ 869 }\n\ 870 }\n\ 871 '; 872 873 var MMD_FRAGMENT_SHADER_SOURCE = '\n\ 874 #ifdef GL_ES\n\ 875 precision highp float;\n\ 876 #endif\n\ 877 \n\ 878 varying vec2 vTextureCoord;\n\ 879 varying vec3 vPosition;\n\ 880 varying vec3 vNormal;\n\ 881 varying vec4 vLightCoord;\n\ 882 \n\ 883 uniform vec3 uLightDirection;\n\ 884 uniform vec3 uLightColor;\n\ 885 \n\ 886 uniform vec3 uAmbientColor;\n\ 887 uniform vec3 uSpecularColor;\n\ 888 uniform vec3 uDiffuseColor;\n\ 889 uniform float uAlpha;\n\ 890 uniform float uShininess;\n\ 891 \n\ 892 uniform bool uUseTexture;\n\ 893 uniform bool uUseSphereMap;\n\ 894 uniform bool uIsSphereMapAdditive;\n\ 895 \n\ 896 uniform sampler2D uToon;\n\ 897 uniform sampler2D uTexture;\n\ 898 uniform sampler2D uSphereMap;\n\ 899 \n\ 900 uniform bool uEdge;\n\ 901 uniform float uEdgeThickness;\n\ 902 uniform vec3 uEdgeColor;\n\ 903 \n\ 904 uniform bool uGenerateShadowMap;\n\ 905 uniform bool uSelfShadow;\n\ 906 uniform sampler2D uShadowMap;\n\ 907 \n\ 908 uniform bool uAxis;\n\ 909 uniform vec3 uAxisColor;\n\ 910 uniform bool uCenterPoint;\n\ 911 \n\ 912 // from http://spidergl.org/example.php?id=6\n\ 913 vec4 pack_depth(const in float depth) {\n\ 914 const vec4 bit_shift = vec4(256.0*256.0*256.0, 256.0*256.0, 256.0, 1.0);\n\ 915 const vec4 bit_mask = vec4(0.0, 1.0/256.0, 1.0/256.0, 1.0/256.0);\n\ 916 vec4 res = fract(depth * bit_shift);\n\ 917 res -= res.xxyz * bit_mask;\n\ 918 return res;\n\ 919 }\n\ 920 float unpack_depth(const in vec4 rgba_depth)\n\ 921 {\n\ 922 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\ 923 float depth = dot(rgba_depth, bit_shift);\n\ 924 return depth;\n\ 925 }\n\ 926 \n\ 927 void main() {\n\ 928 if (uGenerateShadowMap) {\n\ 929 \n\ 930 gl_FragColor = pack_depth(gl_FragCoord.z);\n\ 931 return;\n\ 932 }\n\ 933 if (uAxis) {\n\ 934 gl_FragColor = vec4(uAxisColor, 1.0);\n\ 935 return;\n\ 936 }\n\ 937 if (uCenterPoint) {\n\ 938 vec2 uv = gl_PointCoord * 2.0 - 1.0;\n\ 939 float w = dot(uv, uv);\n\ 940 if (w < 0.3 || (w > 0.5 && w < 1.0)) {\n\ 941 gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n\ 942 } else {\n\ 943 discard;\n\ 944 }\n\ 945 return;\n\ 946 }\n\ 947 \n\ 948 \n\ 949 vec3 norm = normalize(vNormal);\n\ 950 vec3 cameraDirection = normalize(-vPosition);\n\ 951 \n\ 952 vec3 color;\n\ 953 float alpha = uAlpha;\n\ 954 \n\ 955 if (uEdge) {\n\ 956 \n\ 957 color = uEdgeColor;\n\ 958 \n\ 959 } else {\n\ 960 \n\ 961 color = vec3(1.0, 1.0, 1.0);\n\ 962 if (uUseTexture) {\n\ 963 vec4 texColor = texture2D(uTexture, vTextureCoord);\n\ 964 color *= texColor.rgb;\n\ 965 alpha *= texColor.a;\n\ 966 }\n\ 967 if (uUseSphereMap) {\n\ 968 vec2 sphereCoord = 0.5 * (1.0 + vec2(1.0, -1.0) * norm.xy);\n\ 969 if (uIsSphereMapAdditive) {\n\ 970 color += texture2D(uSphereMap, sphereCoord).rgb;\n\ 971 } else {\n\ 972 color *= texture2D(uSphereMap, sphereCoord).rgb;\n\ 973 }\n\ 974 }\n\ 975 \n\ 976 \n\ 977 vec3 halfAngle = normalize(uLightDirection + cameraDirection);\n\ 978 float specularWeight = pow( max(0.001, dot(halfAngle, norm)) , uShininess );\n\ 979 \n\ 980 vec3 specular = specularWeight * uSpecularColor;\n\ 981 \n\ 982 vec2 toonCoord = vec2(0.0, 0.5 * (1.0 - dot( uLightDirection, norm )));\n\ 983 \n\ 984 if (uSelfShadow) {\n\ 985 vec3 lightCoord = vLightCoord.xyz / vLightCoord.w;\n\ 986 vec4 rgbaDepth = texture2D(uShadowMap, lightCoord.xy);\n\ 987 float depth = unpack_depth(rgbaDepth);\n\ 988 if (depth < lightCoord.z - 0.01) {\n\ 989 toonCoord = vec2(0.0, 0.55);\n\ 990 }\n\ 991 }\n\ 992 \n\ 993 color *= uAmbientColor + uLightColor * (uDiffuseColor + specular);\n\ 994 \n\ 995 color = clamp(color, 0.0, 1.0);\n\ 996 color *= texture2D(uToon, toonCoord).rgb;\n\ 997 \n\ 998 }\n\ 999 gl_FragColor = vec4(color, alpha);\n\ 1000 \n\ 1001 }\n\ 1002 '; 1003 }()); 1004