Direct2D中的像素

12

在此输入图片描述

这些深灰色的线应该是黑色并且只有1像素宽:

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

浅灰色的线应该是黑色且宽度为0.5像素:

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

相反,它们都是2像素宽。如果我要求2像素宽,则线条为黑色,但自然而然地为2像素宽。

渲染目标的大小与窗口的客户区域相同。我希望像GDI一样具有像素精度,即一个坐标=一个像素和纯色...

谢谢。

2个回答

21

Direct2D能够正确地进行渲染。当您给定像素坐标,例如(100,120)时,它指的是跨越从像素坐标(100,120)到(101,121)的像素元素的顶部和左侧角落(顶部/左侧包括,右侧/底部不包括)。由于这是一条水平直线,因此您实际上会得到一个从(99.5,119.5)到(300.5,120.5)的填充矩形。由于其边缘溢出到相邻的像素中,这就是为什么您会获得“错误”亮度的“2像素宽度”的线条。您必须以像素坐标(没有区域的点)和像素元素(屏幕上具有1x1面积或只有1个点的物理点)来思考。

如果您想要绘制覆盖像素(100,120)到(300,120)的直线,则应使用SemMike的建议使用带锯齿的渲染(对于直线非常好!),或者您可以使用半像素偏移(因为strokeWidth=1; 对于其他strokeWidth,请按strokeWidth/2调整)。使用线宽为1.0从(100.5,120.5)到(299.5,120.5)进行绘制,将得到您想要的结果。该笔触延伸到您指定的像素坐标周围,因此您将在像素元素(100,120)-(300,121)上获得“填充矩形”。同样,那是一个排他范围,因此'y=121'实际上没有被填充,x=300也是一样。

如果您想知道为什么使用GDI之类的东西不会发生这种情况,那是因为它不执行抗锯齿渲染,因此所有内容始终捕捉到像素元素。如果您想知道为什么在使用Shapes时WPF不会发生这种情况,那是因为它使用布局舍入(UseLayoutRounding)和像素捕捉。Direct2D不提供这些服务,因为它是一个相对较低级别的API。


谢谢解释,我明白了。我是在MSDN文档的Direct2D部分错过了这个内容还是它确实没有提到?“使用1.0的描边宽度从(100.5, 120.5)到(299.5, 120.5)进行绘制将得到你想要的效果。”如果我理解正确,那应该是(100.5, 120.5) - (300.5, 120.5)。否则,线的最后一个像素会被省略。顺便说一下,“SemMike的建议”:同一个人,我在回答自己的问题... - SemMike
2
使用299.5或300.5取决于您想要200像素宽的线还是201像素宽的线。这可能没有在文档中提到,因为对于现代2D图形API来说,这是相当标准的内容,但它也有点不明显和高级,经常会让那些从事高级工作的人忘记他们在变得高级之前所不知道的东西。我发现将其视为一张网格纸很有帮助。水平和垂直线相交的地方是整数像素坐标,它们之间的正方形是“物理”像素元素。 - Rick Brewster

5

您可以尝试使用pRenderTarget->DrawLine(Point2F(100-0.5, 120-0.5), Point2F(300-0.5, 120-0.5), blackbrush, 1)进行实验,但这很快会变得棘手。最简单的方法是:

pRenderTarget->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);

希望这能帮助到某些人...

我不建议避免正确的心理画面。一旦你需要进行抗锯齿处理或绘制不是轴对齐线的形状,你的代码(基于错误的心理假设编写)将会让你感到困惑。这是标准的东西,GDI+也是如此。 - jnm2
除了在DX11中,纹素坐标是以中点为导向的,因此它不再像以前那样“标准”了。 - Gavin Williams

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接