• [WPF]WPF中材质制作——图片和矢量图之争


    如果要做下面这样的一个东西作为背景。你会如何做呢?

    1. 目标背景效果

    方案一,用PS画出来。然后把这个PNG图片作为背景色。这个方案可以,但是如果想让这个线的颜色可配置呢?如何线的粗细不确定呢?无论哪个问题,用像素图的方式都不好解决。

    方案二,用WPF的矢量图绘制。这个方案可以比较容易地解决上面两个问题。

    但是无论我们用哪种方式,都不会把整个图的大小画出来。而是画是一个最小的图元,然后重复。

    标量图方案

    对于PS画的标量而言,有下面这样的一个图就可以了。然后在要绘制的区域内无限重复。尤其是做网页的上的材质都是这样,要知道图片的大小可不是比文字,全部绘制出来的话图片可能会很大。而且Visual Designer改起来也会比较累。

    2. PNG材质图片(放大后)

    比如这个图叫Twill.png,大小是6*6。那么在WPF中使用这个图元来建立图1中材质的代码如下。

            <DrawingBrush x:Key="PicTwillBrush"

                          Stretch="Fill" TileMode="Tile"

                          Viewport="0,0,6,6" ViewportUnits="Absolute">

                <DrawingBrush.Drawing>

                    <ImageDrawing ImageSource="Textures\Twill.png" Rect="0,0,6,6"/>

                </DrawingBrush.Drawing>

            </DrawingBrush>

    默认情况下,这个用方案一实现的材质很完美,和图1完美一样。但是如果用ViewBox把这个图片放下之后会出现下面的现象。

    3. 实现渲染效果(ViewBox放大)

    能看出图片已经是一块块的了。你可以把这个看作WPFBug。如果我是QA我就会这么认为。虽然我也很理解这是平滑处理+TitleMode渲染的结果——平滑算法没有把这个大图当成整个的一个图处理,而是单独地处理每一小块。但是我也相信这不是什么难以解决的问题。所以它就是一个Bug,没有什么好说的。只不过这是个小Bug,不Fix也就算了(因为有其它更严重的Bug等着MSDev们),反正有办法解决的。

    一个不完全解决方案,可以使这个分块的视觉效果弱化50.00%。就是把图元改成这个样子。

    4. 更好的PNG材质

    不一定是一块俩像素,一块4个像素。不过两者个数之差越小越好。所以最好是两条3像素的线。然后视觉图会变成下面这个样子。

    5. 显示效果(ViewBox放大)

    比之前要好一些。至于原因读者自己分析一下吧。(包括那个50.00%是如何计算出来的)

    所以有经验的材质设计者,即使能用简单的角衔接,也不会用,而只使用边衔接。(当然他们主要并不是为了这个原因)

    上面讨论完了位图的作法。如果你的图片不需要支持缩放,而且又不嫌PNG占用空间大的话,用PNG图片还是很不错的方案的。

    矢量图的实现方案

    有人会觉得在WPF做个矢量图太简单了。不就是用Expression Design画么?对,没有错,但是问题你要画成什么个样子?因为矢量图的画法就多了。矢量的一个特点就是,图像不再是以像素为单位的。而是一个完完整整的图形。我的第一感觉是这样的。(也许你的不是)

    6. 向量材质图(根本不可行)

    有人可能一眼就看出问题了,这种做法里,线的两头不是方的。多个这样的小图接起来,线看上去也不会是连续的。解决办法和标量图的是一样的。就是使用边衔接。把图中的一条线分成两条。下面是两条做法。请读者自行判断哪种更好,并解释原因。

      

    7. 可选向量材质图

    上图的代码分别是:

    <StreamGeometry x:Key="SimpleTwill">M3,0 L4,0 0,4 0,3 Z M3,6 L4,6 6,4 6,3 Z</StreamGeometry>

    <StreamGeometry x:Key="BestTwill">M2.5,0 L3.5,0 0,3.5 0,2.5Z M2.5,6 L3.5,6 6,3.5 6,2.5 Z</StreamGeometry>

    如果一开始你是用Expression Design来画这个东西,相信代码一定不会这么简洁的。Expression Design最让人不能忍受的就是生成出来的数据,常常有1.00001这样的东西。

    对应的Brush代码是:

             <DrawingBrush x:Key="SimpleTwillBrush">

                      Stretch="Fill" TileMode="Tile"

                      Viewport="0,0,6,6" ViewportUnits="Absolute">

                  <DrawingBrush.Drawing>

                      <GeometryDrawing Brush="Red" Geometry="{StaticResource SimpleTwill}"/>

                  </DrawingBrush.Drawing>

             </DrawingBrush>

    但是无论向量图自身的定义是多么的“平滑”,不幸的是它最终还是要被渲染到以像素为单位的显示器上。更不幸的是,由于向量图的定义一般不与显示器的像素格匹配,所以在渲染的过程中,势必要做处理。结果渲染出来的就是下面这个熊样了。

    8. 向量材质渲染效果

    最上面一条是期望的效果,下面两条就分别是由那两个向量图元定义出来的渲染效果。如果看不清楚,下面是他们俩的放大图。(请读者自行判断上面的结果分别是基于哪个向量图元绘制的)

    9. 向量材质渲染效果(放大图)

    从图中可以看出,最终的渲染结果没有对齐到像素,严格来讲就是渲染结果不正确。(顺便说一下,请不要提SnapsToDevicePixels这个属性,如果你觉得这个属性可以解决这个问题,只说明你还没有搞清楚这个属性是在什么时候发挥作用的。其实即使我这样说了,我感觉还是会有人回复说要用这个属性,因为他们没有认真看文章。)

    关于向量图的性能问题

    而且,向量没有对齐到像素的另一个严重问题就是性能。这个性能差异用肉眼就可以看得出来。如果你拖拽窗口,会发布由上面这两个向量渲染出来的背景在闪。(此测试方法理论上只在低配置系统上可行。)为什么会闪,因为它比对齐到像素的方式至少多计算1倍的像素点,而且每个像素点的颜色都要重新计算一遍。这个计算量是很大的。

    所以很多用WPF做过开发的人,会发现如果直接用Design绘制出来的复杂向量图做整个程序的背景,程序就会变得很卡,如果先转成PNG之类的图片,再用图片做背景,性能就会好得多。原因就在于此。使用向量,每个像素点的信息都要重新计算出来。而使用图片,如果图片大小和背景大小一样,则只需要原模原样地把图片上的像素信息搬到显示器上就行了,不需要计算什么。

    但是这并不能说向量图就一定性能低下。如果能把向量图,做得与像素点能对应起来,向量图也一样可以具有很好的性能。比如上面的向量图闪,如果我们把向量图定义成下面这个样子就不会闪了。

    高性能向量图方案

    10. 像素对齐的向量材质图

    这个向量的定义需要更多的代码,如下所示:

    <StreamGeometry x:Key="PixelTwill">M0,2 L1,2 1,3 0,3 Z M1,1 L2,1 2,2 1,2 z M2,0 L3,0 3,1 2,1 Z M3,5 L4,5 4,6 3,6 Z M4,4 L5,4 5,5 4,5 Z M5,3 L6,3 6,4 5,4 Z</StreamGeometry>

    虽然看上去代码更多了,但是由于它对齐到了像素点,所以其实性能更好。根据肉眼观测,完全看不到闪烁现象。

    但是这样的向量图已经失去了向量图的意义了,向量图的一个重点特点就是无极缩放。放大之后图像依然平滑。但是这个向量图其实就和一个标量图的效果是一样的了——放大之后就会有锯齿出现。但是如果一个向量图不会放大,用这样方式还是很不错,既提前了性能,又保证了图像的清晰、锐利。但是这样做的成本很高,做个小图还可以,做个大图就很不现实了。

    图片模糊

    无论是标量图还是矢量图,实现项目中常常会出现模糊。下一篇将会为大家介绍几种常见的导致模糊的情况和解决办法。

  • 相关阅读:
    二、Java面向对象(11)_final修饰符
    二、Java面向对象(10)_代码块
    二、Java面向对象(9)_面向对象——多态思想
    二、Java面向对象(8)_继承思想——Object类
    二、Java面向对象(8)_继承思想——子类初始化过程
    二、Java面向对象(8)_继承思想——super关键字
    二、Java面向对象(8)_继承思想——方法覆盖
    WP8.1 RT 生命周期详解‏‏‏‏‏‏‏‏‏‏‏‏‏
    将十六进制色值转换成Color
    WindowsPhone8.1RT建立空白应用挂起没反应的解决方案
  • 原文地址:https://www.cnblogs.com/nankezhishi/p/wpftexturesolution.html
Copyright © 2020-2023  润新知