[ACCEPTED]-Direct3D Line thickness-shader

Accepted answer
Score: 17

You can use a geometry shader that will 49 take as an input a segment of your line 48 and output a quad (a triangle strip made 47 of two triangles) so that the width of the 46 quad is constant in screen space and matches 45 the desire line thickness. It works perfectly 44 well (for having implemented it in a CAD 43 3D engine).

If geometry shader is not an 42 option, a workaround could be to use a vertex 41 shader, but it will require some re-work 40 of your VB. Keep in mind that the VS must 39 then have knowledge of the line segment 38 in its whole so you will end up storing 37 p and p+1 for each of your VB elements, plus 36 the cost of duplication of indices/vertices 35 (depending the topology used and if you 34 render your line as an indexed primitive 33 or not).

If performance is not an issue, doing 32 the expand on the CPU is maybe the way to 31 go.


About dash patterns: you can use a geometry shader 30 too in order to emulate glLineStipple behavior. If you 29 have a GL_LINES topology, that is to say isolated 28 lines, the pattern restarts at each new 27 line segment. So you just have to compute 26 in the geometry shader the screen-space 25 horizontal start (or vertical start, depending 24 the orientation) of your line segment and 23 pass this extra infos to the pixel shader. The 22 pixel shader will then be responsible of 21 discarding fragments according to the factor and 20 pattern values (DirectX 10/11 Integer and Bitwise 19 instructions make it easy).

Again this works 18 well, and you can combine it with emulated 17 width lines (with the first technique above 16 mentioned).

Now if you have GL_LINE_STRIP topology, the 15 pattern restarts at each new primitive (so 14 for each new draw call). The situation becomes 13 a bit more complicated since you need to 12 have the knowledge of the number of pixels 11 that have been rendered before, and this 10 for each line segment.

You can achieve that 9 with rendering your line strip in a temporary 8 VB using DirectX 10 stream-out functionality 7 (each element of this VB corresponds to 6 the screen-space length of each segment). Then 5 you have to do a Parallel Prefix Sum (aka 4 Scan) of this VB (for accumulating each 3 line segment length values).

Lastly, you 2 render your line strip like for GL_LINES but use 1 this extra Scan VB informations in the PS.

Score: 17

Line thickness is not only not supported 29 by Direct3D, but neither is it supported 28 by any currently existing GPU. There is 27 no GPU that I am aware of that can even 26 draw proper lines at all (they all fake 25 lines by using degenerate polygons - that 24 is, the second and third vertices are at 23 the same position, so the triangle essentially 22 collapses to a single line).

While it is 21 possible to set a line width in OpenGL, the 20 OpenGL driver creates extruded quads (which 19 are not supported by and current GPU either, and 18 emulated using two triangles for each quad) to 17 draw the "lines" on the screen.

So there's 16 probably no way around creating extruded 15 quads for that purpose. There are several 14 ways to achieve that, as Stringer Bell explained 13 in his answer.

The easiest way that works 12 for me is to create a vertex buffer that 11 contains each vertex twice, with normals 10 pointing "right" or "left", depending on 9 whether they are the right or left edge 8 of the line. Then a very simple vertex shader 7 can perform the extrusion (by changing the 6 vertex position by a multiple of its normal 5 vector). This way you can quickly change 4 the line width, without having to recalculate 3 your geometry on the CPU. This can be useful 2 if you want to adjust the line width depending 1 on the object's size or distance.

Score: 0

Regarding your dash pattern (stippling) question, your 6 best bet is probably to render the line 5 as a thin quad and apply a texture to it 4 in the pixel shader, where the texture contains 3 your dash pattern. You will need to set 2 the sampler address mode to wrap, something 1 like:

SamplerState wrapTriLinear {
    AddressU = WRAP;
    AddressV = WRAP;

More Related questions