Pixels in Direct2D

2019-03-19 08:13发布

问题:

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.

回答1:

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:

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...



标签: direct2d