投稿日
2012/12/14 金曜日
作ってみた、というだけですので細かい説明には期待しないように。
左が通常のスキニング(線形ブレンド)、右がデュアルクオータニオンによるスキニングです。
ボーン数は見ての通り2、ポリゴン数は各々114です。
(ちなみにこの動画はiOSシミュレータで動作してるものを録画したものです。)
しかしまぁなんというか、デュアルクオータニオンには期待してたんですが、モデルが悪いからかどっちもどっちって感じがするところが残念です。
もっと生物的なものをモデルにするとマッチするのかもしれません。
ただ、品質は置いといてもボーン毎に必要な頂点シェーダのuniform変数のサイズが半分で済むのはかなりの利点かなと思います。
(ボーン毎に必要な4×4の変換行列が、ボーン毎の4×2のデュアルクオータニオンで済む)
それに、通常のスキニングの処理フローを大きく変える必要がないのも良いですね。
(ホストプログラム側でボーンの変換行列をデュアルクオータニオンに変換し、頂点シェーダでデュアルクオータニオンのままブレンドした後行列に戻して頂点や法線に適用するだけ)
NormalSkinning.vsh
#define BONE_NUM 2
attribute vec4 position;
attribute vec3 normal;
attribute vec2 weights;
varying lowp vec4 colorVarying;
uniform mat4 projectionMatrix;
uniform mat4 modelViewMatrix;
uniform mat4 boneMatrices[BONE_NUM];
void main()
{
// 法線の変換
vec3 n = (mat3(boneMatrices[0]) * normal) * weights.x
+ (mat3(boneMatrices[1]) * normal) * weights.y;
// ライティング
vec3 eyeNormal = normalize(n);
vec3 lightPosition = vec3(1.0, 0.0, 1.0);
vec4 diffuseColor = vec4(0.4, 0.4, 1.0, 1.0);
float nDotVP = max(0.0, dot(eyeNormal, normalize(lightPosition)));
colorVarying = diffuseColor * nDotVP;
// 頂点の変換
vec4 p = (boneMatrices[0] * position) * weights.x
+ (boneMatrices[1] * position) * weights.y;
gl_Position = projectionMatrix * modelViewMatrix * p;
}
DualQuaternionSkinning.vsh
#define BONE_NUM 2
attribute vec4 position;
attribute vec3 normal;
attribute vec2 weights;
varying lowp vec4 colorVarying;
uniform mat4 projectionMatrix;
uniform mat4 modelViewMatrix;
uniform vec4 boneDQs[BONE_NUM * 2];
mat4 dq2matrix(vec4 Qn, vec4 Qd)
{
// デュアルクオータニオンから4x4の行列を得る
mat4 M = mat4(0.0);
float len2 = dot(Qn, Qn);
float w = Qn.w;
float x = Qn.x;
float y = Qn.y;
float z = Qn.z;
float t0 = Qd.w;
float t1 = Qd.x;
float t2 = Qd.y;
float t3 = Qd.z;
M[0][0] = w * w + x * x - y * y - z * z;
M[1][0] = 2.0 * x * y - 2.0 * w * z;
M[2][0] = 2.0 * x * z + 2.0 * w * y;
M[0][1] = 2.0 * x * y + 2.0 * w * z;
M[1][1] = w * w + y * y - x * x - z * z;
M[2][1] = 2.0 * y * z - 2.0 * w * x;
M[0][2] = 2.0 * x * z - 2.0 * w * y;
M[1][2] = 2.0 * y * z + 2.0 * w * x;
M[2][2] = w * w + z * z - x * x - y * y;
M[3][0] = -2.0 * t0 * x + 2.0 * w * t1 - 2.0 * t2 * z + 2.0 * y * t3;
M[3][1] = -2.0 * t0 * y + 2.0 * t1 * z - 2.0 * x * t3 + 2.0 * w * t2;
M[3][2] = -2.0 * t0 * z + 2.0 * x * t2 + 2.0 * w * t3 - 2.0 * t1 * y;
M[3][3] = len2;
return M / len2;
}
void main()
{
// デュアルクオータニオンを合成
vec4 blendedDQ[2];
blendedDQ[0] = boneDQs[0] * weights.x + boneDQs[2] * weights.y;
blendedDQ[1] = boneDQs[1] * weights.x + boneDQs[3] * weights.y;
// スキニング用の変換行列化
mat4 skinTransform = dq2matrix(blendedDQ[0], blendedDQ[1]);
// 法線の変換
vec3 n = mat3(skinTransform) * normal;
// ライティング
vec3 eyeNormal = normalize(n);
vec3 lightPosition = vec3(1.0, 0.0, 1.0);
vec4 diffuseColor = vec4(0.4, 0.4, 1.0, 1.0);
float nDotVP = max(0.0, dot(eyeNormal, normalize(lightPosition)));
colorVarying = diffuseColor * nDotVP;
// 頂点の変換
gl_Position = projectionMatrix * modelViewMatrix * skinTransform * position;
}
最近のコメント
たかたむ
はじめまして。初リアルフォース(R3ですが)で,同…
nokiyameego
ZFS poolのデバイスラベル破損で悩んていたと…
名前
しゅごい
Jane Doe
FYI Avoid Annoying Unexpe…
Jane Doe
ご存じとは思いますが、whileには、”~の間”と…
花粉症対策2019 – 日曜研究室
[…] 花粉症対策についてはこれまで次の記事を書いてきました。https://…
花粉症対策2019 – 日曜研究室
[…] 花粉症対策についてはこれまで次の記事を書いてきました。https://…
花粉症対策2019 – 日曜研究室
[…] 花粉症対策についてはこれまで次の記事を書いてきました。https://…
花粉症対策2019 – 日曜研究室
[…] 花粉症対策についてはこれまで次の記事を書いてきました。https://…
花粉症対策2019 – 日曜研究室
[…] 花粉症対策についてはこれまで次の記事を書いてきました。https://…