■GLSLでスキニングシェーダー書いてみた
わりとGLSLでスキニングシェーダーをやったという記事を見かけないので
ここで書いてみます。
大変だった点はGLSLでは、Cのようなキャストを受け付けない点。
そのためブレンドインデックスをどうやってint型にするかで悩みました。
実際には、下記のソースコードに示すように int( )で囲ってやる程度で済む話なのですが、
知らないと結構悩みます。
*備考
マトリックスを使わずにfloat4 (すなわちvec4)でやっているのは
単に自分のスタイルなだけです。
先輩のシェーダースタイルに影響された可能性が大です。
matrix型のほうが変換がmulで書ける分だけソースコードはすっきりします。
float4の4つという表現だと、シェーダー定数設定をするコードがすっきりします。
またMatrixをfloat4x3型として使っているような場合で効率よくシェーダー定数を使うことが出来ます。
他にはライティングが適当です。
平行光源と若干のアンビエント成分いれたつもりのコードです。
*ソースコード(VertexProgram)
1頂点あたり4ボーンのスキニングシェーダーです。
1回のマトリックスパレットは36個です。
36個にした理由は、tiny.xがこの個数で描けるからです。
#version 120 attribute vec4 in_position; attribute vec3 in_normal; attribute vec2 in_texcoord0; attribute vec4 in_blendindices; attribute vec4 in_blendweight; varying vec4 outCol; varying vec2 outTexcoord0; uniform vec4 gViewProj[4]; uniform vec4 gMatrixPalette[4 * 36 ]; uniform vec4 gDiffuse; void main() { int index[4]; index[0] = int(in_blendindices.x); index[1] = int(in_blendindices.y); index[2] = int(in_blendindices.z); index[3] = int(in_blendindices.w); float weight[4] ; weight[0] = in_blendweight.x; weight[1] = in_blendweight.y; weight[2] = in_blendweight.z; weight[3] = in_blendweight.w; vec4 pos = vec4(0,0,0,1); vec3 nrm = vec3(0,0,0); for( int i = 0; i < 4; i++ ) { int idx = index[i]; float w = weight[i]; pos.x += dot( gMatrixPalette[ idx*4 + 0 ], in_position ) * w; pos.y += dot( gMatrixPalette[ idx*4 + 1 ], in_position ) * w; pos.z += dot( gMatrixPalette[ idx*4 + 2 ], in_position ) * w; nrm.x += dot( gMatrixPalette[ idx*4 + 0 ].xyz, in_normal.xyz ) * w; nrm.y += dot( gMatrixPalette[ idx*4 + 1 ].xyz, in_normal.xyz ) * w; nrm.z += dot( gMatrixPalette[ idx*4 + 2 ].xyz, in_normal.xyz ) * w; } gl_Position.x = dot( gViewProj[0], pos ); gl_Position.y = dot( gViewProj[1], pos ); gl_Position.z = dot( gViewProj[2], pos ); gl_Position.w = dot( gViewProj[3], pos ); outCol = gDiffuse * max( 0.1, dot( in_normal, vec3( 0.7, 0.7, -0.7) ) ); outTexcoord0 = in_texcoord0; }