12

enter image description here

The dark gray lines are supposed to be black and 1 pixel wide:

pRT->DrawLine(Point2F(100, 120), Point2F(300, 120), blackbrush, 1);

The light gray lines are supposed to be black and 0.5 pixel wide:

pRT->DrawLine(Point2F(120, 130), Point2F(280, 130), blackbrush, 0.5);

Instead, they are both 2 pixels wide. If I ask for 2 pixels wide, the line is black, but naturally 2 pixels wide.

The render target has the same size as the client area of the window. I would like pixel accuracy like in GDI, one coordinate = one pixel and pure colors...

Thanks.

2 Answers 2

21

Direct2D is rendering correctly. When you give it a pixel coordinate such as (100, 120), that refers to the top and left corner of the pixel element that spans from pixel coordinates (100, 120) to (101, 121) (top/left are inclusive, right/bottom are exclusive). Since it's a straight horizontal line you are effectively getting a filled rectangle from (99.5, 119.5) - (300.5, 120.5). Since the edges of this spill into adjacent pixels, that's why you're getting "2 pixel width" lines at the "wrong" brightness. You must think in terms of pixel coordinates (points with no area) and pixel elements (physical points on the screen with an area of 1x1, or just 1 of course).

If you want to draw a straight line from that covers the pixels (100, 120) to (300, 120), you should either use SemMike's suggestion of using aliased rendering (which is great for straight lines!), or you can use half-pixel offsets (because strokeWidth=1; for other strokeWidths, adjust by strokeWidth/2). Drawing from (100.5, 120.5) - (299.5, 120.5) with a stroke width of 1.0 will get you what you're looking for. That stroke extends around the pixel coordinates you specify, so you will get the "filled rectangle" over the pixel elements (100, 120) - (300, 121). And again, that's an exclusive range, so 'y=121' isn't actually filled, neither is x=300.

If you're wondering why this doesn't happen with something like GDI, it's because it doesn't do antialiased rendering, so everything always snaps to pixel elements. If you're wondering why this doesn't happen with WPF while using Shapes, it's because it uses layout rounding (UseLayoutRounding) and pixel snapping. Direct2D does not provide those services because it's a relatively low-level API.

2
  • Thanks for the explanation, makes sense. Did I miss this in the MSDN docs on Direct2D somewhere or is it not there and I was supposed to know? "Drawing from (100.5, 120.5) - (299.5, 120.5) with a stroke width of 1.0 will get you what you're looking for" If I understand you correctly, that would be (100.5, 120.5) - (300.5, 120.5). Otherwise the last pixel of the line is omitted. By the way, "SemMike's suggestion": same guy, I was answering my own question...
    – SemMike
    Commented May 27, 2012 at 22:54
  • 2
    Whether you use 299.5 or 300.5 depends on whether you want a 200px wide line or a 201px line. And this is probably not in the docs because it's fairly standard stuff for modern 2D graphics APIs, but it's also a bit non-obvious and advanced, and often people who're working on advanced stuff forget what they didn't know before they were that advanced. I find it helps to think of it like a sheet of grid paper. Where the horizontal and vertical lines intersect are the integer pixel coordinates, and the squares between them are the "physical" pixel elements. Commented May 28, 2012 at 0:08
5

You can play around with pRenderTarget->DrawLine(Point2F(100-0.5, 120-0.5), Point2F(300-0.5, 120-0.5), blackbrush, 1), but it becomes rapidly tricky. The simplest is:

pRenderTarget->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);

Hope it helps somebody...

2
  • I wouldn't recommend avoiding the correct mental picture. The minute you need to antialias or draw a shape that is not an axis aligned line, your code (written on an incorrect mental assumption) will confuse you. This is standard stuff, the same for GDI+ as well.
    – jnm2
    Commented Jul 1, 2014 at 14:46
  • Except in DX11, texel co-ordinates are midpoint oriented, so it's not as 'standard' as it once was. Commented Mar 6, 2015 at 6:39

Not the answer you're looking for? Browse other questions tagged or ask your own question.