パーティクルへのモーションブラー

実際の環境ではオブジェクトの移動によって像が乱れてノイズが入ることはなく単位時間で一点から反射して目に入ってくる光の量が移動によって広範囲に分散して一点においては減少するだけだ。つまり移動量に応じて像が伸びて伸びた分透過するようになるだけ。透明度alpha = 物自体の移動方向の長さ/(物自体の移動方向の長さ+移動距離)という仮説を実装してみた。ただ3Dオブジェクトだと頂点を毎回ロックして計算しなくてはならないのであきらめ。いつもどの向きへ動いても長さが一定な円いパーティクルだけに実装してみた。移動した方向へ回転させても問題ないし、像を延ばすのも2面を間に加えるだけなので簡単軽量である。

モーションブラーというより光の線型補間のようなものかもしれん。ブラーしてないし。

SQCAGE_VERTEX tex_v_default[] = {
	{D3DXVECTOR3(-0.5f,	-0.5f,	0), 0xffffffff,  0.0f, 0.0f },
	{D3DXVECTOR3(-0.5f,	0.5f,	0), 0xffffffff,  0.0f, 0.0f },
	{D3DXVECTOR3(0.5f,	0.5f,	0), 0xffffffff,  0.0f, 0.0f },
	{D3DXVECTOR3(0.5f,	-0.5f,	0), 0xffffffff,  0.0f, 0.0f },
};
m = mscale * mbillboard;

const D3DXMATRIX currentworldviewproj = COMPTRANS(D3DXMATRIX(IDENTITYMATRIX),arg.pos) * viewproj;
const D3DXVECTOR2 currentprojpos(currentworldviewproj._41,currentworldviewproj._42);

map<int,D3DXMATRIX>::iterator found = m_lastworldviewprojmap.find(arg.id);

const D3DXMATRIX lastworldviewproj = (found == m_lastworldviewprojmap.end()) ? currentworldviewproj : found->second;
const D3DXVECTOR2 lastprojpos(lastworldviewproj._41,lastworldviewproj._42);

D3DXVECTOR2 vmotion(currentprojpos - lastprojpos);
float vmotionlen = D3DXVec2Length(vmotion);

// 透明度を算出
float size = arg.scale;
color.a *= size / (size + vmotionlen);

if(vmotionlen > 0) vmotion /= vmotionlen; // normalize
D3DXMATRIX mboardrot;
// get rotation matrix
D3DXMatrixRotationZ(&mboardrot, (vmotion.y<0?1.0f:-1.0f) * acosf(-vmotion.x /*(-1,0)との内積*/) );

m = mboardrot * m; // 移動方向への回転を適用

D3DXMATRIX mlast = m * lastworldviewproj;
D3DXMATRIX mcurrent = m * currentworldviewproj;

D3DXVec3TransformCoordArray((D3DXVECTOR3*)v,sizeof(SQCAGE_VERTEX),(D3DXVECTOR3*)tex_v_default,sizeof(SQCAGE_VERTEX),&mcurrent,2);
D3DXVec3TransformCoordArray((D3DXVECTOR3*)(v+2),sizeof(SQCAGE_VERTEX),(D3DXVECTOR3*)(tex_v_default+2),sizeof(SQCAGE_VERTEX),&mlast,2);

v[0].color = v[1].color = v[2].color = v[3].color = (DWORD)color;

v[0].tu = v[1].tu = arg.texgeom[0];
v[1].tv = v[2].tv = arg.texgeom[1];
v[2].tu = v[3].tu = arg.texgeom[0] + arg.texgeom[2];
v[0].tv = v[3].tv = arg.texgeom[1] + arg.texgeom[3];

memcpy(&v[4],&v[0],sizeof(SQCAGE_VERTEX));
memcpy(&v[5],&v[2],sizeof(SQCAGE_VERTEX));

m_lastworldviewprojmap[arg.id] = currentworldviewproj;