Game Development Reference
In-Depth Information
To write a pixel shader, we created “building blocks” of common operations
for different shaders. This design makes it easy to write shaders, as we will show
now. The most important building blocks are the following two, implemented as
macros:
#define LIGHT_LOOP_BEGIN
int tileIndex = GetTileIndex(screenPos);
uint startIndex, endIndex;
GetTileOffsets( tileIndex, startIndex, endIndex );
for ( uint lightListIdx = startIdx;
lightListIdx < endIdx;
lightListIdx++ )
{
int lightIdx = LightIndexBuffer[lightListIdx];
LightParams directLight;
LightParams indirectLight;
if ( isIndirectLight( lightIdx ) )
{
FetchIndirectLight(lightIdx , indirectLight);
}
else
{
FetchDirectLight( lightIndex, directLight );
}
#define LIGHT_LOOP_END
}
LIGHT_LOOP_BEGIN first calculates the tile index of the pixel using its screen-space
position. Then it opens a loop to iterate all the lights overlapping the tile and
fills light parameters for direct and indirect light. LIGHT_LOOP_END is a macro to
close the loop.
By using these building blocks, an implementation of a pixel shader is simple
and looks almost the same as a pixel shader used in forward rendering.
For
example, a shader for a microfacet surface is implemented as follows:
float4 PS ( PSInput i ) : SV_TARGET
{
float3 colorOut = 0;
# LIGHT_LOOP_BEGIN
colorOut += EvaluateMicrofacet ( directLight , indirectLight );
# LIGHT_LOOP_END
return float4(colorOut, 1.f );
}
Other shaders can be implemented by just changing the lines between the two
macros. This building block also allows us to change the implementation easily
 
Search Nedrilad ::




Custom Search