上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。
続き
それでも1パーティクルずつ描画が重いことには変わりないので
何かいい方法がないものかと調べていると、インスタンシングという手法を見つけた

以下、63パーティクルを1回の呼び出しで描画するサンプル。大事なところは赤字にしました
//============================================================
//.fx
//============================================================

float4x4 ArrayMatWVP[63]; // float4x4はレジスタ4つ消費相当。2.0は255レジスタまで保障されてる
// テクスチャ
texture ParticleTex;
sampler ParticleSamp=sampler_state {
Texture=;
MipFilter=LINEAR;
MinFilter=LINEAR;
MagFilter=LINEAR;
};

struct VS_OUTPUT
{
float4 Position : POSITION;
float4 Color : COLOR0;
float2 UV : TEXCOORD0;
};

VS_OUTPUT VertexShader(
float4 Position : POSITION,
float4 Color : COLOR0,
float2 UV : TEXCOORD0,
float1 Index : TEXCOORD1 //インスタンス番号 )
{
VS_OUTPUT Out = (VS_OUTPUT)0;
Out.Position = mul(Position, ArrayMatWVP[(int)Index]);
Out.Color = Color;
Out.UV = UV;
return Out;
}

float4 PixelShader( VS_OUTPUT In ) : COLOR
{
return tex2D(ParticleSamp, In.UV) * In.Color;
}

technique TShader
{
pass P0
{
VertexShader = compile vs_2_0 VertexShader();
PixelShader = compile ps_2_0 PixelShader();
}
}

//============================================================
//.cpp 色々省略してます
//============================================================
//------------------------------------------------------------
//宣言
//------------------------------------------------------------
#define MAX_PARTICLE 63//パーティクル数


//パーティクル
struct PARTICLE_DATA
{
PARTICLE_DATA()
{
ZeroMemory(this, sizeof(PARTICLE_DATA));
vScale = D3DXVECTOR2(1.0f,1.0f);
}
D3DXVECTOR3 vPos;
D3DXVECTOR3 vRot;
D3DXVECTOR2 vScale;
D3DXVECTOR3 vDir;
};
//パーティクルの頂点フォーマト
struct PARTICLE_VERTEX
{
float x,y,z;
DWORD color;
float u,v;
float index; //インスタンス番号
};

PARTICLE_DATA ArrayParticle[MAX_PARTICLE]; //パーティクル
PARTICLE_VERTEX vertices[MAX_PARTICLE*4]; //頂点
WORD indexes[MAX_PARTICLE*6]; //DrawIndexedPrimitiveで使う

//------------------------------------------------------------
//初期化
//------------------------------------------------------------
//頂点
for(int i=0; i < MAX_PARTICLE; i++)
{
vertices[i*4+0].x = -0.5;
vertices[i*4+0].y = -0.5;
vertices[i*4+0].z = 0;

vertices[i*4+1].x = -0.5;
vertices[i*4+1].y = 0.5;
vertices[i*4+1].z = 0;

vertices[i*4+2].x = 0.5;
vertices[i*4+2].y = -0.5;
vertices[i*4+2].z = 0;

vertices[i*4+3].x = 0.5;
vertices[i*4+3].y = 0.5;
vertices[i*4+3].z = 0;

vertices[i*4+0].u = 0;
vertices[i*4+0].v = 1;
vertices[i*4+1].u = 0;
vertices[i*4+1].v = 0;
vertices[i*4+2].u = 1;
vertices[i*4+2].v = 1;
vertices[i*4+3].u = 1;
vertices[i*4+3].v = 0;

vertices[i*4+0].color = 0xffffffff;
vertices[i*4+1].color = 0xffffffff;
vertices[i*4+2].color = 0xffffffff;
vertices[i*4+3].color = 0xffffffff;

vertices[i*4+0].index = i;
vertices[i*4+1].index = i;
vertices[i*4+2].index = i;
vertices[i*4+3].index = i;


indexes[i*6+0] = i*4+0;
indexes[i*6+1] = i*4+1;
indexes[i*6+2] = i*4+2;
indexes[i*6+3] = i*4+1;
indexes[i*6+4] = i*4+2;
indexes[i*6+5] = i*4+3;
}

//------------------------------------------------------------
//描画
//------------------------------------------------------------
D3DXMATRIX matBillboard = ビューの逆行列;
D3DXMATRIX matView, matProj, matVP, matWVP;
d3dデバイス->GetTransform(D3DTS_VIEW, &matView);
d3dデバイス->GetTransform(D3DTS_PROJECTION, &matProj);
D3DXMatrixMultiply(&matVP, &matView, &matProj);

D3DXMATRIX ArrayMatWVP[MAX_PARTICLE];

for(int i=0; i < MAX_PARTICLE; i++)
{
// メッシュのワールド変換
D3DXMATRIX matPos,matScale, matRotZ;
D3DXMatrixTranslation(&matPos, ArrayParticle[i].vPos.x, ArrayParticle[i].vPos.y, ArrayParticle[i].vPos.z); //位置のマトリックス
D3DXMatrixScaling(&matScale, ArrayParticle[i].vScale.x, ArrayParticle[i].vScale.y, 1.0f); //拡大のマトリックス
D3DXMatrixRotationZ(&matRotZ, 0); //Z回転のマトリックス
//マトリックスの合成(拡大×回転×位置)
ArrayMatWVP[i] = matScale * (matRotZ * matBillboard) * matPos * matVP;
}

d3dデバイス->SetFVF( D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX2 | D3DFVF_TEXCOORDSIZE2(0) | D3DFVF_TEXCOORDSIZE1(1) );


LPD3DXEFFECT->SetTechnique("TShader");
LPD3DXEFFECT->.SetTexture("ParticleTex", tex);
LPD3DXEFFECT->SetMatrixArray("ArrayMatWVP", ArrayMatWVP, MAX_PARTICLE);

LPD3DXEFFECT->Begin(NULL, 0);
LPD3DXEFFECT->BeginPass(0);
d3dデバイス->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST,0,MAX_PARTICLE*4,MAX_PARTICLE*2,indexes,D3DFMT_INDEX16,vertices,sizeof(PARTICLE_VERTEX));
LPD3DXEFFECT->EndPass();
LPD3DXEFFECT->End();



いくつか紹介されているサイトがあるが、FVFの説明が見当たらなかったので書いておく
D3DFVF_TEX0 - D3DFVF_TEX8の数字は頂点に含まれるテクスチャ座標の数をあらわす
D3DFVF_TEXCOORDSIZEn(coordIndex)はcoordIndex番目のテクスチャの次元数をあらわす
なので
d3dデバイス->SetFVF( D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX2 | D3DFVF_TEXCOORDSIZE2(0) | D3DFVF_TEXCOORDSIZE1(1) );

テクスチャ座標を2つ持ち、0番目のテクスチャ座標は2次元、1番目のテクスチャ座標は1次元
となる

この1次元のテクスチャ座標にインスタンス番号を入れて、頂点シェーダーで受け取り、番号に対応する行列を掛けているのである!おわり!

バーン!
20120612particle.png
スポンサーサイト
夏だ!

花火だ!

パーティクルだ!

20120608particle.jpg

全てのポリゴンをまとめて描画したほうが速いってよく見かけるけど
そうなると頂点座標を自前で変換しないといけなくて、それに処理を取られて
結局1枚ずつ描画するほうが速かった

メッシュのような頂点を動かさないものはまとめて描画
パーティクルのように動かすものは個別に描画
って感じでいいのだろうか
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。