您的位置:首页 > 其它

Directx11基于GeometryShader的粒子系统

2015-06-09 14:05 465 查看
粒子系统作为在游戏中一个挺常见的技术,用在各种爆炸,下雨,火焰等特效中。我们利用GPU中的GeomtryShader来实现一个粒子系统。以下雨特效为例。

介绍粒子系统具体实现前先介绍下GeomtryShader的StreamOutput这个特性。StreamOutput这个Stage把GeometryShader的计算结果输出到一个buffer中。




下面主要从Shader代码设计的角度讲下如何实现一个下雨特效的粒子系统,其核心算法说白了就一句话:分成主粒子和副粒子。主粒子按时间间隔分裂副粒子,副粒子到了一定的时间就死亡。




绘制时要么用公告板绘制一个粒子,要么用一条直线绘制一个粒子。

只是具体的shader代码的设计要花点心思,在其在shader内部经过了两个technique,一个主要利用Geometry Shader的StreamOuput输出到一段buffer中;另一个利用上面的计算结果来进行绘制,具体的粒子运动情况(受重力)的更新等可以放在第二个technique的geometry shader里面。

第一个technique,也就是负责利用Geometry来计算,并通过StreamOutput输出到一个buffer中的technique,为了整体清晰我先把technique写出来:



view
sourceprint?

001.
technique11
 StreamOutTech


002.


003.


004.


005.
{


006.


007.


008.


009.
pass
 P0


010.


011.


012.


013.
{


014.


015.


016.


017.
SetVertexShader(CompileShader(vs_4_0,StreamOut_VS()));


018.


019.


020.


021.
SetGeometryShader(
 ConstructGSWithSO( CompileShader(gs_4_0,StreamOut_GS()),
"POSITION.xyz;VELOCITY.xyz;SIZE.xy;AGE.x;TYPE.x"
)
 );


022.


023.


024.


025.
SetPixelShader(NULL);


026.


027.


028.


029.
SetDepthStencilState(DisableDepth,0);


030.


031.


032.


033.
}


034.


035.


036.


037.
}


038.


039.


040.


041.
//================================================


042.


043.


044.


045.
//StreamOutTech


046.


047.


048.


049.
//================================================


050.


051.


052.


053.
Particle
 StreamOut_VS(Particle vIn)


054.


055.


056.


057.
{


058.


059.


060.


061.
return
vIn;


062.


063.


064.


065.
}


066.


067.


068.


069.
[maxvertexcount(6)]


070.


071.


072.


073.
void
StreamOut_GS(point
 Particle gIn[1],inout PointStream<Particle> pStream)


074.


075.


076.


077.
{


078.


079.


080.


081.
gIn[0].age+=timeStep;


082.


083.


084.


085.
if
(gIn[0].type==P_EMITTER)


086.


087.


088.


089.
{


090.


091.


092.
//主喷射粒子,时间到了一定阀值,就该生成一定数量的副粒子.


093.


094.


095.
if
(gIn[0].age>0.01f)


096.


097.


098.


099.
{


100.


101.


102.


103.
//生成副粒子


104.


105.


106.


107.
for
(
int
i=0;i<5;i++)


108.


109.


110.


111.
{


112.


113.


114.


115.
Particle
 nPt;


116.


117.


118.


119.
nPt.initPosW=emitPosW.xyz+35.0f*GetRandomVec3((
float
)i/5.0f);


120.


121.


122.


123.
nPt.initPosW.y=40.0f;


124.


125.


126.


127.
nPt.initVelW=float3(0.0f,0.0f,0.0f);


128.


129.


130.


131.
nPt.size=float2(1.0f,1.0f);


132.


133.


134.


135.
nPt.age=0.0f;


136.


137.


138.


139.
nPt.type=P_FLARE;


140.


141.


142.


143.
pStream.Append(nPt);


144.


145.


146.


147.
}


148.


149.


150.


151.
gIn[0].age=0.0f;


152.


153.


154.


155.
}
//if(age)


156.


157.


158.


159.
pStream.Append(gIn[0]);


160.


161.


162.


163.
}
//if(type==)


164.


165.


166.


167.
else


168.


169.


170.
{
//副粒子,看时间到了就销毁,不然输出到steamout
 buffer中继续绘制


171.


172.


173.


174.
if
(gIn[0].age<=3.0f)


175.


176.


177.


178.
{


179.


180.


181.


182.
pStream.Append(gIn[0]);


183.


184.


185.


186.
}


187.


188.


189.


190.
}


191.


192.


193.


194.
}


第二个technique就简单了,就是基本的绘制。在GeomtryShader可以更新粒子的运动情况,和把每个雨点看成一条直线。



view
sourceprint?

001.
technique11
 DrawTech


002.


003.


004.


005.
{


006.


007.


008.


009.
pass
 P0


010.


011.


012.


013.
{


014.


015.


016.


017.
SetVertexShader(CompileShader(vs_4_0,Draw_VS()));


018.


019.


020.


021.
SetGeometryShader(
 CompileShader(gs_4_0,Draw_GS()) );


022.


023.


024.


025.
SetPixelShader(
 CompileShader(ps_4_0,Draw_PS()) );


026.


027.


028.


029.
SetDepthStencilState(NoWriteDepth,0);


030.


031.


032.


033.
}


034.


035.


036.


037.
}


038.


039.


040.


041.
Particle
 Draw_VS(Particle vIn)


042.


043.


044.


045.
{


046.


047.


048.


049.
return
vIn;


050.


051.


052.


053.
}


054.


055.


056.


057.
[maxvertexcount(2)]


058.


059.


060.


061.
void
Draw_GS(point
 Particle gIn[1],inout LineStream<DrawGSOut> pStream)


062.


063.


064.


065.
{


066.


067.


068.


069.
if
(gIn[0].type!=P_EMITTER)


070.


071.


072.
//不绘制主粒子


073.


074.
{


075.


076.
//更新粒子的运动情况,这里我们只用了最简单的牛顿定律


077.


078.
float3
 posW1=gIn[0].initPosW+gIn[0].initVelW*gIn[0].age+0.5f*(gForce*0.7)*gIn[0].age*gIn[0].age;


079.


080.


081.


082.
float3
 posW2=posW1+0.2f*gForce;


083.


084.
//把粒子绘制成一条直线,当然也可以绘制成公告板等


085.


086.


087.


088.


089.
DrawGSOut
 gOut1;


090.


091.


092.


093.
gOut1.posH=mul(float4(posW1,1.0f),viewMtx);


094.


095.


096.


097.
gOut1.posH=mul(gOut1.posH,projectMtx);


098.


099.


100.


101.
gOut1.tex=float2(0.0f,0.0f);


102.


103.


104.


105.
pStream.Append(gOut1);


106.


107.


108.


109.
DrawGSOut
 gOut2;


110.


111.


112.


113.
gOut2.posH=mul(float4(posW2,1.0f),viewMtx);


114.


115.


116.


117.
gOut2.posH=mul(gOut2.posH,projectMtx);


118.


119.


120.


121.
gOut2.tex=float2(1.0f,1.0f);


122.


123.


124.


125.
pStream.Append(gOut2);


126.


127.


128.


129.
}


130.


131.


132.


133.
}


134.


135.


136.


137.
float4
 Draw_PS(DrawGSOut pIn):SV_Target


138.


139.


140.


141.
{


142.


143.


144.


145.
return
gTexArray.Sample(gLinearSam,float3(pIn.tex,0.0f));


146.


147.


148.


149.
}


最后场景截图





延伸阅读:

1、Directx11与PhysX的结合

2、Directx11:基于GeometryShader的Billboard公告板绘制

3、Directx11_使用Effect框架包装ComputeShader

4、Directx11_使用Effect框架包装ComputeShader

5、用DirectX实现粒子系统(一)

6、用DirectX实现粒子系统(二)

7、用DirectX实现粒子系统(三)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: