Skip to content

Instantly share code, notes, and snippets.

@edom18
Last active August 29, 2015 14:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save edom18/f366d2f35c39840b138f to your computer and use it in GitHub Desktop.
Save edom18/f366d2f35c39840b138f to your computer and use it in GitHub Desktop.
[WebGL] スキニングメッシュ(ボーン)の仕組みを自前で実装してみる ref: http://qiita.com/edo_m18/items/31ee6cbc3b3ff22013ae
var newPosition = [];
var newNormal = [];
for (var i = 0; i < 12; i++) {
var idxBase = i * 3;
var idx0 = idxBase + 0;
var idx1 = idxBase + 1;
var idx2 = idxBase + 2;
var comb1 = [
mat4(),
mat4(),
mat4(),
mat4()
];
var comb2 = mat4.zero;
for (var j = 0; j < 3; j++) {
var boneIdx = i * 4 + j;
var weightIdx = i * 3 + j;
mat4.multiplyScalar(combMatArr[plane.boneIndices[boneIdx]], plane.weights[weightIdx], comb1[j]);
}
var weight = 1.0 - (plane.weights[i * 3 + 0] +
plane.weights[i * 3 + 1] +
plane.weights[i * 3 + 2]);
mat4.multiplyScalar(combMatArr[plane.boneIndices[i * 4 + 3]], weight, comb1[3]);
for (var k = 0; k < 4; k++) {
mat4.add(comb2, comb1[k], comb2);
}
var pos = vec3(plane.position[idx0],
plane.position[idx1],
plane.position[idx2]);
vec3.applyMatrix4(pos, comb2, pos);
newPosition[idx0] = pos.x;
newPosition[idx1] = pos.y;
newPosition[idx2] = pos.z;
var nor = vec3(plane.normal[idx0],
plane.normal[idx1],
plane.normal[idx2]);
mat4.inverse(comb2, comb2);
vec3.applyMatrix4FromRight(nor, comb2, nor);
newNormal[idx0] = nor.x;
newNormal[idx1] = nor.y;
newNormal[idx2] = nor.z;
}
/**
* 各種ボーンを親空間の相対位置に変換
*/
Bone.calcRelativeMat = function (bone, parentOffsetMat) {
bone.children.forEach(function (childBone, idx) {
Bone.calcRelativeMat(childBone, bone.matrixOffset);
});
if (parentOffsetMat) {
mat4.multiply(bone.matrixInit, parentOffsteMat, bone.matrixInit);
}
};
// countはフレームごとに増加していく
var s = Math.sin(count) / 5;
for (var i = 0; i < bones.length; i++) {
// `s`角度だけ全ボーンを回転させる
bones[i].rotate(s, axis);
}
// 合成行列を更新
Bone.updateBone(bones[0], global);
// Planeの定義
var plane = {
position: [
2.0, 0.0, 0.0,
2.0, 1.0, 0.0,
3.0, 1.0, 0.0,
3.0, 0.0, 0.0,
2.0, 2.0, 0.0,
3.0, 2.0, 0.0,
2.0, 3.0, 0.0,
3.0, 3.0, 0.0,
2.0, 4.0, 0.0,
3.0, 4.0, 0.0,
2.0, 5.0, 0.0,
3.0, 5.0, 0.0,
],
color: [
1.0, 0.0, 0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
0.0, 0.0, 1.0, 1.0,
0.0, 0.0, 0.0, 1.0,
1.0, 0.0, 0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
0.0, 0.0, 1.0, 1.0,
0.0, 0.0, 0.0, 1.0,
1.0, 0.0, 0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
0.0, 0.0, 1.0, 1.0,
0.0, 0.0, 0.0, 1.0,
],
normal: [
0.0, 0.0, 1.0,
0.0, 0.0, 1.0,
0.0, 0.0, 1.0,
0.0, 0.0, 1.0,
0.0, 0.0, 1.0,
0.0, 0.0, 1.0,
0.0, 0.0, 1.0,
0.0, 0.0, 1.0,
0.0, 0.0, 1.0,
0.0, 0.0, 1.0,
0.0, 0.0, 1.0,
0.0, 0.0, 1.0,
],
index: [
0, 1, 2,
2, 3, 0,
1, 4, 5,
5, 2, 1,
4, 6, 7,
7, 5, 4,
6, 8, 9,
9, 7, 6,
8, 10, 11,
11, 9, 8,
],
boneIndices: [
0, 0, 0, 0,
1, 2, 0, 0,
0, 1, 0, 0,
0, 0, 0, 0,
1, 2, 0, 0,
1, 2, 0, 0,
2, 3, 0, 0,
2, 3, 0, 0,
3, 4, 0, 0,
3, 4, 0, 0,
4, 0, 0, 0,
4, 0, 0, 0,
],
weights: [
1.0, 0.0, 0.0,
0.5, 0.5, 0.0,
0.5, 0.5, 0.0,
1.0, 0.0, 0.0,
0.5, 0.5, 0.0,
0.5, 0.5, 0.0,
0.5, 0.5, 0.0,
0.5, 0.5, 0.0,
0.5, 0.5, 0.0,
0.5, 0.5, 0.0,
1.0, 0.0, 0.0,
1.0, 0.0, 0.0,
],
};
// 中略
init: function (position) {
this.matrix = mat4();
this.matrixBone = mat4();
this.matrixComb = mat4();
this.matrixInit = mat4.translate(mat4(), position);
this.matrixOffset = mat4.inverse(this.matrixInit);
this.children = [];
},
// 中略
var v1 = vec3(0, 1, 0); // 3要素のベクトル
var v2 = vec2(0, 1);
var v3 = vec3(v2, 0); // vec2成分を流用してvec3を作る
var m1 = mat4(); // 引数なしで単位行列を作る
var m2 = mat4(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); // 引数を与えて初期化
var m3 = mat4(m2); // 同じ値で複製
var result = mat4();
// OpenGLのように結果を得る行列を第3引数に指定する
mat4.multiply(m1, m2, result);
// 戻り値としても計算できる
// result = mat4.multiply(m1, m2);
var nor = vec3(plane.normal[idx0],
plane.normal[idx1],
plane.normal[idx2]);
mat4.inverse(comb2, comb2);
vec3.applyMatrix4FromRight(nor, comb2, nor);
newNormal[idx0] = nor.x;
newNormal[idx1] = nor.y;
newNormal[idx2] = nor.z;
var pos = vec3(plane.position[idx0],
plane.position[idx1],
plane.position[idx2]);
vec3.applyMatrix4(pos, comb2, pos);
newPosition[idx0] = pos.x;
newPosition[idx1] = pos.y;
newPosition[idx2] = pos.z;
// 中略
rotate: function (angle, axis) {
mat4.rotate(this.matrix, angle, axis, this.matrix);
this.updateMatrix();
},
// 中略
updateMatrix: function () {
mat4.multiply(this.matrixInit, this.matrix, this.matrixBone);
},
/**
* 各種ボーンの合成行列を生成
*/
Bone.updateBone = function (bone, parentWorldMat) {
// 親の姿勢行列(ボーン行列)を左から自身の姿勢行列に掛ける
mat4.multiply(parentWorldMat, bone.matrixBone, bone.matrixBone);
// 自身のオフセット行列を右から掛けて合成行列を生成
mat4.multiply(bone.matrixBone, bone.matrixOffset, bone.matrixComb);
bone.children.forEach(function (childBone, idx) {
Bone.updateBone(childBone, bone.matrixBone);
});
};
for (var j = 0; j < 3; j++) {
var boneIdx = i * 4 + j;
var weightIdx = i * 3 + j;
mat4.multiplyScalar(combMatArr[plane.boneIndices[boneIdx]], plane.weights[weightIdx], comb1[j]);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment