Graphics Reference
In-Depth Information
The
Snowfall
compute shader applies the force that has been passed into the
ParticleConstants
constant buffer with a call to
ApplyForces
. This simply computes
the current force vector and applies it to the particle's position, based on the current
FrameTime
value. Then, the
Snowfall
shader clamps the
Particle.Position.y
value
to
DomainBoundsMin.y
; if the old and new Y positions are the same (that is, the particle
is sitting on the ground), the
Particle.Energy
property is set to
1.0f
. To ensure that
we do not try to create too many particles, we decreased their
Energy
property by the
current
FrameTime
value. Once the amount of energy reaches zero, the particle is
removed; otherwise, it is added into the
NewState
buffer.
The
DeviceContext.DrawInstancedIndirect
method allows us to generate our
sprites or billboards by passing in a GPU-generated parameter list; the first two being the
instance vertex count (always four for our quads) and number of instances. The instance
count comes directly from the current consume buffer with a call to the
DeviceContext.
CopyStructureCount
method. This allows our compute shaders to control the number
of particles to be rendered.
By utilizing the vertex shader system value input semantics
SV_InstanceID
and
SV_VertexID
, we are able to index into the particle buffer directly and generate our
camera-aligned quads without passing any additional information into the vertex shader.
We compute the vertex UV coordinates and their positions based on the incoming
SV_VertexID
value. Another approach is to use a lookup table, saving approximately
two instructions. The resulting camera-aligned quads (also known as sprites or billboards)
will always face the camera.
Once the quad is rasterized and the fragments are sent to the pixel shader, we sample the
texture and return the value. The texture used in the recipe is a white dot or snowflake shape
with transparency. Multiplying this with any other color allows us to control the particle's final
color. We also fade out the alpha as the particle approaches the near-clip plane, and during
its final second of life.
To allow the particles to perform alpha-blending correctly, we have created an additive
BlendState
instance within our particle renderer. By setting the
blendDesc.
RenderTarget[0].SourceBlend
to
BlendOption.SourceAlpha
, and
blendDesc.
RenderTarget[0].DestinationBlend
to
BlendOption.InverseSourceAlpha
, we
are telling the output merger stage to use the alpha component returned by the pixel shader,
and merge with the render target accordingly. Given a source color of
(1, 1, 1, 0.5)
and
destination color of
(0.6, 0.0, 0.6, 0.9)
, the blending calculation is as follows:
Final Color = (Source Color * BlendOption.SourceAlpha)
BlendOperation.Add (Dest Color * BlendOption.InverseSourceAlpha)
Final Color = ((1, 1, 1) * 0.7) + ((0.6, 0.0, 0.6) * (1 - 0.7))
= (0.7, 0.7, 0.7) + (0.18, 0.0, 0.18)
= (0.88, 0.7, 0.88)