概要:雨粒子每刻的动画使用输出流,在每一帧都使用geometry Shader扩成billboard.
最后,雨粒子的渲染使用的纹理库存储在一个纹理阵列。使用DX10和GeForce8 系列GPU。
1.应用风和重力使粒子一直在作动画。
2.把粒子扩成要在每一帧渲染的精灵。
3.渲染精灵
1.(1)C++使用输出流
//设立渲染点列表,每个粒子存一个顶点。
pd3dDevice->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_POINTLIST);
pd3dDevice->IASetInputLayout(g_pVertexLayoutRainVertex);
//决定哪个顶点缓冲我们既将要渲染
假如这是第一帧我们渲染一个预产生的顶点帧g_pParticleStart
static bool firstFrame=true;
ID3D10Buffer* pBuffers[1];
if(firstFrame)
pBuffers[0]=g_pParticleStart;
else
pBuffers[0]=g_pParticleDrawFrom;
pDevice->IASetVertexBuffers(0,1,pBuffers,stride,offset);
//指向正确的输出缓冲
pBuffers[0] = g_pParticleStreamTo;
pd3dDevice->SOSetTargets( 1, pBuffers, offset );
// 画图,使粒子动画
D3D10_TECHNIQUE_DESC techDesc;
g_pTechniqueAdvanceRain->GetDesc( &techDesc );
g_pTechniqueAdvanceRain->GetPassByIndex(0)->Apply(0);
pd3dDevice->Draw(g_numRainVertices , 0 );
// Get back to normal
pBuffers[0] = NULL;
pd3dDevice->SOSetTargets( 1, pBuffers, offset );
// Swap buffers交换缓冲区
ID3D10Buffer* pTemp = g_pParticleDrawFrom;
g_pParticleDrawFrom = g_pParticleStreamTo;
g_pParticleStreamTo = pTemp;
firstFrame = false;
2.(2)HLSL--使用Geometry shader Expanding
GeometryShader gsStreamOut = ConstructGSWithSO( CompileShader( vs_4_0, VSAdvanceRain() ), "POSITION.xyz; SEED.xyz; SPEED.xyz; RAND.x; TYPE.x" );
technique10 AdvanceParticles
{
pass p0
{
SetVertexShader( CompileShader( vs_4_0, VSAdvanceRain() ) );
SetGeometryShader( gsStreamOut );
SetPixelShader( NULL );
SetDepthStencilState( DisableDepth, 0 );
}
}
(3)HLSL--使用Geometry shader Extruding
// GS for rendering rain as point sprites. Takes a point and turns it into 2 tris.
[maxvertexcount(4)]
void GSRenderRain(point VSParticleIn input[1], inout TriangleStream<PSSceneIn> SpriteStream)
{
float totalIntensity = g_PointLightIntensity*g_ResponsePointLight + dirLightIntensity*g_ResponseDirLight;
if(!cullSprite(input[0].pos,2*g_SpriteSize) && totalIntensity > 0)
{
PSSceneIn output = (PSSceneIn)0;
output.type = input[0].Type;
output.random = input[0].random;
float3 pos[4];
GenRainSpriteVertices(input[0].pos.xyz, input[0].speed.xyz/g_FrameRate + g_TotalVel, g_eyePos, pos);
float3 closestPointLight = g_PointLightPos;
float closestDistance = length(g_PointLightPos - pos[0]);
if( length(g_PointLightPos2 - pos[0]) < closestDistance )
closestPointLight = g_PointLightPos2;
output.pos = mul( float4(pos[0],1.0), g_mWorldViewProj );
output.lightDir = g_lightPos - pos[0];
output.pointLightDir = closestPointLight - pos[0];
output.eyeVec = g_eyePos - pos[0];
output.tex = g_texcoords[0];
SpriteStream.Append(output);
output.pos = mul( float4(pos[1],1.0), g_mWorldViewProj );
output.lightDir = g_lightPos - pos[1];
output.pointLightDir = closestPointLight - pos[1];
output.eyeVec = g_eyePos - pos[1];
output.tex = g_texcoords[1];
SpriteStream.Append(output);
output.pos = mul( float4(pos[2],1.0), g_mWorldViewProj );
output.lightDir = g_lightPos - pos[2];
output.pointLightDir = closestPointLight - pos[2];
output.eyeVec = g_eyePos - pos[2];
output.tex = g_texcoords[2];
SpriteStream.Append(output);
output.pos = mul( float4(pos[3],1.0), g_mWorldViewProj );
output.lightDir = g_lightPos - pos[3];
output.pointLightDir = closestPointLight - pos[3];
output.eyeVec = g_eyePos - pos[3];
output.tex = g_texcoords[3];
SpriteStream.Append(output);
SpriteStream.RestartStrip();
}
}
3.
渲染点精灵
使用DX10新特性Texture Array
渲染雾
运行范例:
范例显示两个点光源和一条直射光下的桥。
左键控制直射光。