[WPF]WPF中材质制作——图片和矢量图之争
如果要做下面這樣的一個(gè)東西作為背景。你會(huì)如何做呢?
圖1. 目標(biāo)背景效果
方案一,用PS畫出來。然后把這個(gè)PNG圖片作為背景色。這個(gè)方案可以,但是如果想讓這個(gè)線的顏色可配置呢?如何線的粗細(xì)不確定呢?無論哪個(gè)問題,用像素圖的方式都不好解決。
方案二,用WPF的矢量圖繪制。這個(gè)方案可以比較容易地解決上面兩個(gè)問題。
?
但是無論我們用哪種方式,都不會(huì)把整個(gè)圖的大小畫出來。而是畫是一個(gè)最小的圖元,然后重復(fù)。
標(biāo)量圖方案
對(duì)于PS畫的標(biāo)量而言,有下面這樣的一個(gè)圖就可以了。然后在要繪制的區(qū)域內(nèi)無限重復(fù)。尤其是做網(wǎng)頁的上的材質(zhì)都是這樣,要知道圖片的大小可不是比文字,全部繪制出來的話圖片可能會(huì)很大。而且Visual Designer改起來也會(huì)比較累。
圖2. PNG材質(zhì)圖片(放大后)
比如這個(gè)圖叫Twill.png,大小是6*6。那么在WPF中使用這個(gè)圖元來建立圖1中材質(zhì)的代碼如下。
??????? <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>
?
默認(rèn)情況下,這個(gè)用方案一實(shí)現(xiàn)的材質(zhì)很完美,和圖1完美一樣。但是如果用ViewBox把這個(gè)圖片放下之后會(huì)出現(xiàn)下面的現(xiàn)象。
圖3. 實(shí)現(xiàn)渲染效果(ViewBox放大)
?
能看出圖片已經(jīng)是一塊塊的了。你可以把這個(gè)看作WPF的Bug。如果我是QA我就會(huì)這么認(rèn)為。雖然我也很理解這是平滑處理+TitleMode渲染的結(jié)果——平滑算法沒有把這個(gè)大圖當(dāng)成整個(gè)的一個(gè)圖處理,而是單獨(dú)地處理每一小塊。但是我也相信這不是什么難以解決的問題。所以它就是一個(gè)Bug,沒有什么好說的。只不過這是個(gè)小Bug,不Fix也就算了(因?yàn)橛衅渌鼑?yán)重的Bug等著MS的Dev們),反正有辦法解決的。
?
一個(gè)不完全解決方案,可以使這個(gè)分塊的視覺效果弱化50.00%。就是把圖元改成這個(gè)樣子。
圖4. 更好的PNG材質(zhì)
?
不一定是一塊倆像素,一塊4個(gè)像素。不過兩者個(gè)數(shù)之差越小越好。所以最好是兩條3像素的線。然后視覺圖會(huì)變成下面這個(gè)樣子。
圖5. 顯示效果(ViewBox放大)
?
比之前要好一些。至于原因讀者自己分析一下吧。(包括那個(gè)50.00%是如何計(jì)算出來的)
?
所以有經(jīng)驗(yàn)的材質(zhì)設(shè)計(jì)者,即使能用簡(jiǎn)單的角銜接,也不會(huì)用,而只使用邊銜接。(當(dāng)然他們主要并不是為了這個(gè)原因)
?
上面討論完了位圖的作法。如果你的圖片不需要支持縮放,而且又不嫌PNG占用空間大的話,用PNG圖片還是很不錯(cuò)的方案的。
?
矢量圖的實(shí)現(xiàn)方案
?
有人會(huì)覺得在WPF做個(gè)矢量圖太簡(jiǎn)單了。不就是用Expression Design畫么?對(duì),沒有錯(cuò),但是問題你要畫成什么個(gè)樣子?因?yàn)槭噶繄D的畫法就多了。矢量的一個(gè)特點(diǎn)就是,圖像不再是以像素為單位的。而是一個(gè)完完整整的圖形。我的第一感覺是這樣的。(也許你的不是)
圖6. 向量材質(zhì)圖(根本不可行)
?
有人可能一眼就看出問題了,這種做法里,線的兩頭不是方的。多個(gè)這樣的小圖接起來,線看上去也不會(huì)是連續(xù)的。解決辦法和標(biāo)量圖的是一樣的。就是使用邊銜接。把圖中的一條線分成兩條。下面是兩條做法。請(qǐng)讀者自行判斷哪種更好,并解釋原因。
??
圖7. 可選向量材質(zhì)圖
上圖的代碼分別是:
<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來畫這個(gè)東西,相信代碼一定不會(huì)這么簡(jiǎn)潔的。Expression Design最讓人不能忍受的就是生成出來的數(shù)據(jù),常常有1.00001這樣的東西。
?
對(duì)應(yīng)的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>
?
但是無論向量圖自身的定義是多么的“平滑”,不幸的是它最終還是要被渲染到以像素為單位的顯示器上。更不幸的是,由于向量圖的定義一般不與顯示器的像素格匹配,所以在渲染的過程中,勢(shì)必要做處理。結(jié)果渲染出來的就是下面這個(gè)熊樣了。
圖8. 向量材質(zhì)渲染效果
?
最上面一條是期望的效果,下面兩條就分別是由那兩個(gè)向量圖元定義出來的渲染效果。如果看不清楚,下面是他們倆的放大圖。(請(qǐng)讀者自行判斷上面的結(jié)果分別是基于哪個(gè)向量圖元繪制的)
圖9. 向量材質(zhì)渲染效果(放大圖)
?
從圖中可以看出,最終的渲染結(jié)果沒有對(duì)齊到像素,嚴(yán)格來講就是渲染結(jié)果不正確。(順便說一下,請(qǐng)不要提SnapsToDevicePixels這個(gè)屬性,如果你覺得這個(gè)屬性可以解決這個(gè)問題,只說明你還沒有搞清楚這個(gè)屬性是在什么時(shí)候發(fā)揮作用的。其實(shí)即使我這樣說了,我感覺還是會(huì)有人回復(fù)說要用這個(gè)屬性,因?yàn)樗麄儧]有認(rèn)真看文章。)
關(guān)于向量圖的性能問題
而且,向量沒有對(duì)齊到像素的另一個(gè)嚴(yán)重問題就是性能。這個(gè)性能差異用肉眼就可以看得出來。如果你拖拽窗口,會(huì)發(fā)布由上面這兩個(gè)向量渲染出來的背景在閃。(此測(cè)試方法理論上只在低配置系統(tǒng)上可行。)為什么會(huì)閃,因?yàn)樗葘?duì)齊到像素的方式至少多計(jì)算1倍的像素點(diǎn),而且每個(gè)像素點(diǎn)的顏色都要重新計(jì)算一遍。這個(gè)計(jì)算量是很大的。
?
所以很多用WPF做過開發(fā)的人,會(huì)發(fā)現(xiàn)如果直接用Design繪制出來的復(fù)雜向量圖做整個(gè)程序的背景,程序就會(huì)變得很卡,如果先轉(zhuǎn)成PNG之類的圖片,再用圖片做背景,性能就會(huì)好得多。原因就在于此。使用向量,每個(gè)像素點(diǎn)的信息都要重新計(jì)算出來。而使用圖片,如果圖片大小和背景大小一樣,則只需要原模原樣地把圖片上的像素信息搬到顯示器上就行了,不需要計(jì)算什么。
?
但是這并不能說向量圖就一定性能低下。如果能把向量圖,做得與像素點(diǎn)能對(duì)應(yīng)起來,向量圖也一樣可以具有很好的性能。比如上面的向量圖閃,如果我們把向量圖定義成下面這個(gè)樣子就不會(huì)閃了。
高性能向量圖方案
圖10. 像素對(duì)齊的向量材質(zhì)圖
這個(gè)向量的定義需要更多的代碼,如下所示:
<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>
?
雖然看上去代碼更多了,但是由于它對(duì)齊到了像素點(diǎn),所以其實(shí)性能更好。根據(jù)肉眼觀測(cè),完全看不到閃爍現(xiàn)象。
?
但是這樣的向量圖已經(jīng)失去了向量圖的意義了,向量圖的一個(gè)重點(diǎn)特點(diǎn)就是無極縮放。放大之后圖像依然平滑。但是這個(gè)向量圖其實(shí)就和一個(gè)標(biāo)量圖的效果是一樣的了——放大之后就會(huì)有鋸齒出現(xiàn)。但是如果一個(gè)向量圖不會(huì)放大,用這樣方式還是很不錯(cuò),既提前了性能,又保證了圖像的清晰、銳利。但是這樣做的成本很高,做個(gè)小圖還可以,做個(gè)大圖就很不現(xiàn)實(shí)了。
圖片模糊
無論是標(biāo)量圖還是矢量圖,實(shí)現(xiàn)項(xiàng)目中常常會(huì)出現(xiàn)模糊。下一篇將會(huì)為大家介紹幾種常見的導(dǎo)致模糊的情況和解決辦法。
總結(jié)
以上是生活随笔為你收集整理的[WPF]WPF中材质制作——图片和矢量图之争的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Web 单点登录系统
- 下一篇: 预告