Ale*_*hik 5 c# wpf pixel-shader
我在WPF中遇到了像素着色器的奇怪行为.
这个问题100%可重复,所以我写了一个小的演示程序.您可以在此处下载源代码.
万恶之源是名为MyFrameworkElement的小类:
internal sealed class MyFrameworkElement : FrameworkElement
{
public double EndX
{
get
{
return (double)this.GetValue(MyFrameworkElement.EndXProperty);
}
set
{
this.SetValue(MyFrameworkElement.EndXProperty, value);
}
}
public static readonly DependencyProperty EndXProperty =
DependencyProperty.Register("EndX",
typeof(double),
typeof(MyFrameworkElement),
new FrameworkPropertyMetadata(0d, FrameworkPropertyMetadataOptions.AffectsRender));
protected override void OnRender(DrawingContext dc)
{
dc.DrawLine(new Pen(Brushes.Red, 2), new Point(0, 0), new Point(this.EndX, 100));
dc.DrawLine(new Pen(Brushes.Green, 3), new Point(10, 300), new Point(200, 10));
}
}
Run Code Online (Sandbox Code Playgroud)
如您所见,此框架元素呈现2行:下面的行具有永久坐标,但上面的行依赖于EndX依赖项属性.
所以这个框架元素是像素着色器效果的目标.为简单起见,我使用此处的灰度着色器效果.所以我将GrayscaleEffect应用于MyFrameworkElement.你可以看到结果,看起来不错.
直到我大幅增加EndX属性.

小线模糊,大线很好!
但是如果我删除灰度效果,所有线条都会看起来应该如此.

任何人都可以解释这种模糊的原因是什么?或者甚至更好我如何解决这个问题?
使用自定义像素着色器,它必须创建中间位图,然后像素着色器对该纹理进行采样。
您正在创建大量渲染,因此您在渲染路径中遇到了一些限制。
一个快速解决方法是剪辑您想要渲染的内容,如下所示:
Geometry clip = new RectangleGeometry(new Rect(0,0,this.ActualWidth, this.ActualHeight));
dc.PushClip(clip);
dc.DrawLine(new Pen(Brushes.Red, 2), new Point(0, 0), new Point(this.EndX, 100));
dc.DrawLine(new Pen(Brushes.Green, 3), new Point(200, 10), new Point(10, 300));
dc.Pop();
Run Code Online (Sandbox Code Playgroud)
更新:
一种理论是,当位图超过最大纹理大小(这可能会根据您的显卡架构而变化)时,它会使用过滤器来缩放位图......因此它会以不同的大小通过像素着色器......然后它缩放回原始大小。
因此,缩放过滤器会根据位图的内容产生伪影(即水平线和垂直线比对角线更好地在缩小和放大的情况下生存)。
.NET 4 将用于过滤的默认过滤器更改为较低质量的过滤器...双线性,而不是 Fant...也许这也会影响您获得的质量。
http://10rem.net/blog/2010/05/16/more-on-image-resizing-in-net-4-vs-net-35sp1-bilinear-vs-fant
更新2:
这证实了我上面的想法。
如果您使用 Windows 性能工具包/套件(Windows SDK 的一部分),那么当您增加滑块值时,您可以看到橙色图中的视频内存被吞噬,因为正在创建更大的中间位图纹理。它不断增加,直到达到极限,然后趋于平缓……这就是像素化变得明显的时候。

更新3:
如果将渲染模式设置为“软件渲染器”(第 0 层),那么您可以看到它如何处理渲染如此大的视觉效果 - 伪影开始出现在不同的点......大概是因为纹理大小限制更大/与您的 GPU 不同。但伪影仍然出现,因为它内部使用了双线性滤波器。
尝试使用 RenderOptions.SetBitmapScalingMode 将过滤器升级到 Fant 似乎不会以任何方式改变渲染质量(我猜是因为当它通过自定义像素着色器路径时它不会受到尊重)。
将其放入 Application_Startup 中以查看软件渲染器结果:
RenderOptions.ProcessRenderMode = RenderMode.SoftwareOnly;
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
954 次 |
| 最近记录: |