A blog which discusses various GPU applications including visualization, GPGPU and games.

Friday, January 2, 2009

2D Imposters

A 2D imposter is a simple representation of a geometric shape. Why would we care about these? Imagine rendering millions of circles. Not only would the vertex shader be a bottleneck, but the quality would not be very good due to multisampling. Instead, we can use imposters.

In this example, I am rendering each circle as a simple quadrilateral. The real magic happens in the pixel shader.



Let's take a look at the shader code.

cbuffer shapes
{
float2 square[] =
{
float2(-1.0f, -1.0f),
float2(-1.0f, 1.0f),
float2(1.0f, -1.0f),
float2(1.0f, 1.0f)
};
};

PS_INPUT VS(VS_INPUT input)
{
PS_INPUT output;

float3 vpos = float3(0.4f * square[input.vertid], 0.0f) + 2.6f * input.position;

output.position = mul(float4(vpos, 1.0f), mul(World, Projection));
output.color = input.color;
output.qpos = 1.1f * square[input.vertid];

return output;
}

float4 PS(PS_INPUT input) : SV_Target
{
float dist = length(input.qpos);
float fw = 0.8f * fwidth(dist);
float circ = smoothstep(fw, -fw, dist - 1.0f);
return float4(input.color, circ);
}

The utility of imposter shapes shows through when looking at the vertex shader. The vertex shader need only run 4 times per circle. As you can see, I am not only transforming the square's vertices, I am also passing the raw vertices over to the pixel shader. The pixel shader uses this to measure the distance between the center of the square and each fragment in order to determine which fragments should be visible and which should be blended away.

Why use imposters? Consider a visualization application which needs to render thousands of circles very quickly. This method allows for the rendering of efficient, high-quality circles. In a future post, I will show how this method can be adapted to rendering spheres as quadrilaterals.

No comments:

Post a Comment

Followers