[DX11] Drawing points with geometry shader

Started by
4 comments, last by Erik Rufelt 12 years, 6 months ago
I found out that for drawing points an lines with different sizes geometry shaders are the way to go...

My first draft lookes like this:

...
cbuffer Size : register( b3 )
{
float size;
}

...

[maxvertexcount(4)]
void GS_POINT( point GS_INPUT input[1], inout TriangleStream<PS_INPUT> OutStream )
{
PS_INPUT Out[4];
Out[0].pos = input[0].pos;
Out[0].pos.x = Out[0].pos.x - size;
Out[0].pos.y = Out[0].pos.y - size;

Out[1].pos = input[0].pos;
Out[1].pos.x = Out[1].pos.x - size;
Out[1].pos.y = Out[1].pos.y + size;

Out[2].pos = input[0].pos;
Out[2].pos.x = Out[2].pos.x + size;
Out[2].pos.y = Out[2].pos.y - size;

Out[3].pos = input[0].pos;
Out[3].pos.x = Out[3].pos.x + size;
Out[3].pos.y = Out[3].pos.y + size;


for( uint i=0; i<4; ++i )
{
Out.pos = mul( Out.pos, World );
Out.pos = mul( Out.pos, View );
Out.pos = mul( Out.pos, Projection );
OutStream.Append( Out );
}

OutStream.RestartStrip();
}



The point is, that i wanted to manipulate the point size not in object space but in pixels, hoever i counldn't find anything like that.
I would be so happy if one of you could tell me how to do that
Advertisement
Do the World/View/Projection multiplications first, and then add 'size' to the result. Note that your XY coordinates will be between -1.0 and +1.0 when on screen, so to add one pixel to the size, you need to add 1.0 / width on X and 1.0 / height on Y, where width and height are the dimensions of your viewport.
Thank you, but 1.0/width and 1.0/height seem to be too small...

The first visual results ( 1 Pixel ) I get when I multiply those values with 4, otherwise no triangle is drawn. Everything is set to screen resolution ( viewport, buffer width, projection matrix ). Is there any other thing i have to take care of?
My mistake, should be 2.0 / width, as the coordinates are between -1 and +1 which has a width of 2.

Try something like this, which should get you a single pixel drawn. Multiply sizes by 2 to get 2 pixels etc.

const float4 sizes[4] = {
float4(0, 0, 0, 0),
float4(0, 2/h, 0, 0),
float4(2/w, 0, 0, 0),
float4(2/w, 2/h, 0, 0)
};
for( uint i=0; i<4; ++i )
{
Out.pos = mul( Out.pos, World );
Out.pos = mul( Out.pos, View );
Out.pos = mul( Out.pos, Projection );

Out.pos = Out.pos / Out.pos.w;
Out.pos += sizes;

OutStream.Append( Out );
}
Thank you verry much!
The code works perfectly well.

One more question i have:
What does this line do?
Out.pos = Out.pos / Out.pos.w;

Isn't the w-component 1 in most cases? I just like to understand the code im using.
For normal perspective projection it will be what Z was before the multiplication with the projection matrix, and the division is what actually brings the coordinates into [-1, 1] (if they're on screen).
The division will always be performed by D3D after your shader is run, but if you do it in the shader W/W = 1 and you output the coordinates exactly as their final values. Also this is what makes it possible to specify the size in pixels even if Z is not constant. If you draw in 2D and always use Z=1 for example you could skip the division.

See for example D3DXMatrixPerspectiveFovLH for how the projection matrix looks. W will be the vector multiplied by the rightmost column.
The Direct3D Transformation Pipeline explains more about how it works.

This topic is closed to new replies.

Advertisement