20.7 火焰
下面的effect文件(fire.fx)用于渲染火焰粒子系统。它由两个technique 组成:
1.一个technique用于更新粒子系统。
2.一个technique用于绘制粒子系统。
这两个technique中的代码一般会随着特定的粒子系统而变化,实现不同的销毁、生成和渲染规则。在本例中,火焰粒子在同一个位置上发射,但是会被赋予不同的初始速度,以使火焰逐渐散开,形成一个火球。

//***********************************************
// GLOBALS *
//***********************************************
cbuffer cbPerFrame
{
float3 gEyePosW;
// for when the emit position/direction is varying
float3 gEmitPosW;
float3 gEmitDirW;
float gGameTime;
float gTimeStep;
float4x4 gViewProj;
};
cbuffer cbFixed
{
// 净常量加速度用于使粒子加速.
float3 gAccelW = {0.0f, 7.8f, 0.0f};
// 当将一个点粒子扩展为一个四边形时,
// 需要用到下面的纹理坐标将纹理平铺到四边形上.
float2 gQuadTexC[4] =
{
float2(0.0f, 1.0f),
float2(1.0f, 1.0f),
float2(0.0f, 0.0f),
float2(1.0f, 0.0f)
};
};
// 纹理数组.
Texture2DArray gTexArray;
// 用于生成随机数的随机纹理.
Texture1D gRandomTex;
SamplerState samLinear
{
Filter = MIN_MAG_MIP_LINEAR;
AddressU = WRAP;
AddressV = WRAP;
};
DepthStencilState DisableDepth
{
DepthEnable = FALSE;
DepthWriteMask = ZERO;
};
DepthStencilState NoDepthWrites
{
DepthEnable = TRUE;
DepthWriteMask = ZERO;
};
BlendState AdditiveBlending
{
AlphaToCoverageEnable = FALSE;
BlendEnable[0] = TRUE;
SrcBlend = SRC_ALPHA;
DestBlend = ONE;
BlendOp = ADD;
SrcBlendAlpha = ZERO;
DestBlendAlpha = ZERO;
BlendOpAlpha = ADD;
RenderTargetWriteMask[0] = 0x0F;
};
//***********************************************
// 辅助函数*
//***********************************************
float3 RandUnitVec3(float offset)
{
// 使用游戏时间给随机纹理的采样值添加偏移量.
float u = (gGameTime + offset);
// [-1,1]区间的坐标
float3 v = gRandomTex.SampleLevel(samLinear, u, 0).xyz;
// 投影到一个单位球上
return normalize(v);
}
//***********************************************
// STREAM-OUT TECH *
//***********************************************
#define PT_EMITTER 0
#define PT_FLARE 1
struct Particle
{
float3 InitialPosW : POSITION;
float3 InitialVelW : VELOCITY;
float2 SizeW : SIZE;
float Age : AGE;
uint Type : TYPE;
};
Particle StreamOutVS(Particle vin)
{
return vin;
}
// The stream-out GS is just responsible for emitting
// new particles and destroying old particles. The logic
// programed here will generally vary from particle system
// to particle system, as the destroy/spawn rules will be
// different.
[maxvertexcount(2)]
void StreamOutGS(point Particle gin[1],
inout PointStream<Particle> ptStream)
{
gin[0].Age += gTimeStep;
if( gin[0].Type == PT_EMITTER )
{
// time to emit a new particle?
if( gin[0].Age > 0.005f )
{
float3 vRandom = RandUnitVec3(0.0f);
vRandom.x *= 0.5f;
vRandom.z *= 0.5f;
Particle p;
p.InitialPosW = gEmitPosW.xyz;
p.InitialVelW = 4.0f*vRandom;
p.SizeW = float2(3.0f, 3.0f);
p.Age = 0.0f;
p.Type = PT_FLARE;
ptStream.Append(p);
// reset the time to emit
gin[0].Age = 0.0f;
}
// always keep emitters
ptStream.Append(gin[0]);
}
else
{
// Specify conditions to keep particle; this may vary from system to system.
if( gin[0].Age <= 1.0f )
ptStream.Append(gin[0]);
}
}
GeometryShader gsStreamOut = ConstructGSWithSO(
CompileShader( gs_5_0, StreamOutGS() ),
"POSITION.xyz; VELOCITY.xyz; SIZE.xy; AGE.x; TYPE.x" );
technique11 StreamOutTech
{
pass P0
{
SetVertexShader( CompileShader( vs_5_0, StreamOutVS() ) );
SetGeometryShader( gsStreamOut );
// disable pixel shader for stream-out only
SetPixelShader(NULL);
// we must also disable the depth buffer for stream-out only
SetDepthStencilState( DisableDepth, 0 );
}
}
//***********************************************
// DRAW TECH *
//***********************************************
struct VertexOut
{
float3 PosW : POSITION;
float2 SizeW : SIZE;
float4 Color : COLOR;
uint Type : TYPE;
};
VertexOut DrawVS(Particle vin)
{
VertexOut vout;
float t = vin.Age;
// 常量加速度的运动学方程
vout.PosW = 0.5f*t*t*gAccelW + t*vin.InitialVelW + vin.InitialPosW;
// fade color with time
float opacity = 1.0f - smoothstep(0.0f, 1.0f, t/1.0f);
vout.Color = float4(1.0f, 1.0f, 1.0f, opacity);
vout.SizeW = vin.SizeW;
vout.Type = vin.Type;
return vout;
}
struct GeoOut
{
float4 PosH : SV_Position;
float4 Color : COLOR;
float2 Tex : TEXCOORD;
};
// DrawGS用于将点扩展为一个面向相机的四边形.
[maxvertexcount(4)]
void DrawGS(point VertexOut gin[1],
inout TriangleStream<GeoOut> triStream)
{
// do not draw emitter particles.
if( gin[0].Type != PT_EMITTER )
{
//
// 计算世界矩阵使公告牌面向相机.
//
float3 look = normalize(gEyePosW.xyz - gin[0].PosW);
float3 right = normalize(cross(float3(0,1,0), look));
float3 up = cross(look, right);
//
// 在世界空间中计算三角形条带的顶点.
//
float halfWidth = 0.5f*gin[0].SizeW.x;
float halfHeight = 0.5f*gin[0].SizeW.y;
float4 v[4];
v[0] = float4(gin[0].PosW + halfWidth*right - halfHeight*up, 1.0f);
v[1] = float4(gin[0].PosW + halfWidth*right + halfHeight*up, 1.0f);
v[2] = float4(gin[0].PosW - halfWidth*right - halfHeight*up, 1.0f);
v[3] = float4(gin[0].PosW - halfWidth*right + halfHeight*up, 1.0f);
//
// 将四边形顶点转换到世界空间并输出为三角形条带.
//
GeoOut gout;
[unroll]
for(int i = 0; i < 4; ++i)
{
gout.PosH = mul(v[i], gViewProj);
gout.Tex = gQuadTexC[i];
gout.Color = gin[0].Color;
triStream.Append(gout);
}
}
}
float4 DrawPS(GeoOut pin) : SV_TARGET
{
return gTexArray.Sample(samLinear, float3(pin.Tex, 0))*pin.Color;
}
technique11 DrawTech
{
pass P0
{
SetVertexShader( CompileShader( vs_5_0, DrawVS() ) );
SetGeometryShader( CompileShader( gs_5_0, DrawGS() ) );
SetPixelShader( CompileShader( ps_5_0, DrawPS() ) );
SetBlendState(AdditiveBlending, float4(0.0f, 0.0f, 0.0f, 0.0f), 0xffffffff);
SetDepthStencilState( NoDepthWrites, 0 );
}
}
文件下载(已下载 570 次)
发布时间:2014/9/2 下午8:50:10 阅读次数:4687
