GLSLスキニング実験

行列パレットの大きさが足りなくて、100を越えるボーンをもつpmdモデルを
vertex shaderでskinningするのは難しいようだ。

無理なパターン

attribute vec4 my_Vertex;
attribute vec4 my_Uv;
//attribute mat4 my_BoneMatrix[256]; // 間違い
// 確保できない 20個くらいまで?
uniform mat4 my_BoneMatrix[256];
attribute float my_BoneIndex0;
attribute float my_BoneIndex1;
attribute float my_BoneWeight0;

void main(void)
{
    gl_TexCoord[0]=my_Uv;
    gl_FrontColor=gl_Color;
    if(my_BoneWeight0>0.99){
        gl_Position=gl_ModelViewProjectionMatrix*my_BoneMatrix[my_BoneIndex0]*my_Vertex;
    }
    else if(my_BoneWeight0<0.01){
        gl_Position=gl_ModelViewProjectionMatrix*my_BoneMatrix[my_BoneIndex1]*my_Vertex;
    }
    else{
        gl_Position=gl_ModelViewProjectionMatrix*(
            my_BoneMatrix[my_BoneIndex0]*my_BoneWeight0+
            my_BoneMatrix[my_BoneIndex1]*(1.0-my_BoneWeight0)
            )*my_Vertex;
    }
}

とりあえず動くパターン

仕方ないのでインデックスを展開した配列を渡す方法でとりあえず動かしてみた。
pythonで実験したのでCでやった場合にメリットがあるかは不明。

attribute vec4 my_Vertex;
attribute vec4 my_Uv;
attribute mat4 my_BoneMatrix0;
attribute mat4 my_BoneMatrix1;
attribute float my_BoneWeight0;

void main(void)
{
    gl_TexCoord[0]=my_Uv;
    gl_FrontColor=gl_Color;
    if(my_BoneWeight0>0.99){
        gl_Position=gl_ModelViewProjectionMatrix*my_BoneMatrix0*my_Vertex;
    }
    else if(my_BoneWeight0<0.01){
        gl_Position=gl_ModelViewProjectionMatrix*my_BoneMatrix1*my_Vertex;
    }
    else{
        gl_Position=gl_ModelViewProjectionMatrix*(
            my_BoneMatrix0*my_BoneWeight0+
            my_BoneMatrix1*(1.0-my_BoneWeight0)
            )*my_Vertex;
    }
}

VTF

Vertex Texture Fetch
日本語だと頂点テクスチャ。
テクスチャに行列などのデータを入れておいてVertexShaderで読み込む機能。
uniform変数に入らないような大量のボーン行列を入れるのにも使えるらしい。
うちのGeForce6200なんかじゃつらそうだが・・・
http://blogs.msdn.com/ito/archive/2009/05/07/more-bones-07.aspx
http://developer.nvidia.com/object/using_vertex_textures.html
http://www.4gamer.net/specials/3de/050706_gf7800/001/050706_gf7800_01.shtml
http://www.ozone3d.net/tutorials/vertex_displacement_mapping.php