为什么相邻的矩形会产生条纹效果?

时间:2013-08-07 21:35:35

标签: c# wpf canvas rectangles visual-artifacts

我使用以下代码创建了一些矩形:

double width = 6.546;

for (int i = 0; i < 50; i++)
{
    var rect = new Rectangle()
    {
        Width = width,
        Height = i * 10,
        Fill = Brushes.Blue,
    };

    Canvas.SetLeft(rect, i * width);
    Canvas.SetBottom(rect, 0);

    canvas.Children.Add(rect);
}

结果如下:

verticalbanding

有不同亮度的垂直线条。它们为什么会出现?通过使用大width值可以避免它们。还有其他方法可以避免它们吗?

2 个答案:

答案 0 :(得分:2)

这里的关键问题是Width = width将矩形宽度设置为6,但Canvas.SetLeft(rect, i * width)将矩形的位置设置为0,6,13,19,26 ......(作为整数获得的整数)截断约0,6.546,13.092,19.638,26.184,......的产物。如您所见,一些位置相距7个单位,例如6和13或19和26.因此,六单位矩形不会跨越七个单位的距离。

在这种情况下,使用Width = ceil(width)(即7)设置宽度可确保矩形足够宽,以跨越它们之间的距离。

尽管this answer建议您使用int个数字,但目前尚无法明确这一点。如果将计算转换为int,则必须将位置设置为一个整数(6或7)的倍数,或者计算出计算相同位置的方法(0,6,13,19,26,... )通过使用整数运算而不是浮点运算。前者是改变绘图以适应算术的选择,这是不合需要的。后者保留了图纸中的斜率但具有相同的条带问题。

该答案还建议使用绘图对象的浮点版本。这是一种合理的方法。但是请注意,这只会减少舍入误差(从整数单位到更精细的浮点单位,在这个数量级);它并没有消除它们。在大型图纸中,除非您注意避免,否则可能仍会偶尔出现绘图。因此,了解细节很重要。即使使用浮点,您也希望确保宽度设置为至少与位置变化一样大。

如果您的绘图界面支持,则另一个选项是更改画布的比例。如果您可以将比例乘以1000(但保持最终图纸大小相同),那么您的比例从6.546变为6546,您可以将宽度设置为6546而不是6000或7000.如您所见,我们是回到关键问题:您必须将宽度设置为至少与任意两个位置之间的差值一样大。

如前所述,将宽度设置为7会使此图形可以接受。我讨论其他解决方案的原因在于,在一些附图中,将宽度从理想值6.546改变为7会不期望地增加物体的尺寸。其他解决方案通过允许您保持更接近所需大小的宽度来改进。

答案 1 :(得分:0)

首先,请将此行添加到代码中(在添加Rectangle之前),以了解轻松问题如何消失!

 canvas.SnapsToDevicePixels = true;

与包括我的第一个在内的一些答案所提到的相反,此问题与浮点数无关,而是与WPF中使用的渲染系统相关< em>与设备无关的单位测量但这可能会导致设备工作在每英寸96点(dpi)以上。微软公布了这个问题:

  

...由于抗锯齿,此dpi独立性可能会产生不规则的边缘渲染。当边缘的位置落在设备像素的中间而不是设备像素之间时,可能会出现这些通常被视为模糊或“软”边缘的伪影(Reference

但该解决方案也由SnapToDevicePixels属性提供。 (见this