Unity_新手必懂知識(shí)點(diǎn)|顯示原生態(tài)Image

深入U(xiǎn)GUI源碼去認(rèn)識(shí)Image辜梳。

作為Graphic家族最重要的成員之一,我相信你的UI里面Image是必不可少的元素仅醇。我也相信大部分使用者都能夠熟練的應(yīng)用Image冗美。這一篇文章并不是Image的使用教程魔种,只是從源碼角度的對(duì)Image的剖析析二,以及總結(jié)(源碼請(qǐng)自行下載)。

屬性

首先簡(jiǎn)單介紹一下image面板上各屬性:


pro.png

Source Image:圖片資源,支持精靈貼圖叶摄;
Color:圖片顏色属韧,默認(rèn)為白色;
Material:材質(zhì)蛤吓;
Raycast Target:是否是射線投射目標(biāo)宵喂;是——此Image可以接受射線投射,并且會(huì)遮擋被覆蓋UI的事件調(diào)用会傲;否——射線忽視Image锅棕,可以穿透Image。
建議:普通Image選擇否淌山,需要添加事件調(diào)用的Image選擇是裸燎。
Image Type:圖片顯示方式,總共有4種:Simple泼疑,Sliced德绿,Tiled,F(xiàn)illed(本文的介紹重點(diǎn)退渗,此處不在解釋)移稳。
Preserve Aspect:圖片是否以原比例顯示;
Set Native Size:設(shè)置圖片以原尺寸顯示会油。

源碼剖析

接下來主要通過Image幾個(gè)重要的函數(shù)來解讀Image:

1.  private Vector4 GetDrawingDimensions(bool shouldPreserveAspect);

返回的向量就是圖片去掉padding之后中間部分的x,y,z,w坐標(biāo)个粱。源碼如下:

        /// Image's dimensions used for drawing. X = left, Y = bottom, Z = right, W = top.
        ///shouldPreserveAspect為是否按精靈的原比例顯示
        ///rect (x,y是左下角相對(duì)于中心點(diǎn)的坐標(biāo),weight和height分別為寬翻翩,高
        private Vector4 GetDrawingDimensions(bool shouldPreserveAspect)
        {
            //當(dāng)前精靈的填充內(nèi)邊框(left,bottom,right,top)几蜻,一般情況下都是(0,0体斩,0梭稚,0)
            var padding = activeSprite == null ? Vector4.zero : Sprites.DataUtility.GetPadding(activeSprite);
            //當(dāng)前精靈的大小(包含了邊框的大行醭场)
            var size = activeSprite == null ? Vector2.zero : new Vector2(activeSprite.rect.width, activeSprite.rect.height);
            //目標(biāo)繪制區(qū)域的坐標(biāo)及大谢】尽(x,y為該UI相對(duì)于軸心的坐標(biāo),width蹬敲,height為UI寬高)
            Rect r = GetPixelAdjustedRect();

            int spriteW = Mathf.RoundToInt(size.x);
            int spriteH = Mathf.RoundToInt(size.y);
            //計(jì)算出一種比率暇昂,為顯示出來的圖片剔除內(nèi)邊框做準(zhǔn)備
            var v = new Vector4(
                    padding.x / spriteW,
                    padding.y / spriteH,
                    (spriteW - padding.z) / spriteW,
                    (spriteH - padding.w) / spriteH);

            if (shouldPreserveAspect && size.sqrMagnitude > 0.0f)
            {
                //原圖寬高比,目標(biāo)繪制區(qū)域?qū)捀弑?                var spriteRatio = size.x / size.y;
                var rectRatio = r.width / r.height;
                //原圖更寬則按寬調(diào)整高度大小伴嗡,以及重新計(jì)算坐標(biāo)位置急波,反之則按高度調(diào)整
                if (spriteRatio > rectRatio)
                {
                    var oldHeight = r.height;
                    r.height = r.width * (1.0f / spriteRatio);
                    r.y += (oldHeight - r.height) * rectTransform.pivot.y;
                }
                else
                {
                    var oldWidth = r.width;
                    r.width = r.height * spriteRatio;
                    r.x += (oldWidth - r.width) * rectTransform.pivot.x;
                }
            }
            //重新計(jì)算x,y,z,w的大小
            v = new Vector4(
                    r.x + r.width * v.x,
                    r.y + r.height * v.y,
                    r.x + r.width * v.z,
                    r.y + r.height * v.w
                    );

            return v;
        }

計(jì)算最后的向量如圖所示:


v.png
2.  private void GenerateSimpleSprite(VertexHelper vh, bool lPreserveAspect);

簡(jiǎn)單模式下的頂點(diǎn)信息瘪校。源碼如下:

        void GenerateSimpleSprite(VertexHelper vh, bool lPreserveAspect)
        {
            //獲得圖片的位置信息
            Vector4 v = GetDrawingDimensions(lPreserveAspect);
            //獲得精靈的uv坐標(biāo)
            var uv = (activeSprite != null) ? Sprites.DataUtility.GetOuterUV(activeSprite) : Vector4.zero;

            var color32 = color;
            vh.Clear();
            //添加頂點(diǎn)
            vh.AddVert(new Vector3(v.x, v.y), color32, new Vector2(uv.x, uv.y));
            vh.AddVert(new Vector3(v.x, v.w), color32, new Vector2(uv.x, uv.w));
            vh.AddVert(new Vector3(v.z, v.w), color32, new Vector2(uv.z, uv.w));
            vh.AddVert(new Vector3(v.z, v.y), color32, new Vector2(uv.z, uv.y));
            //添加三角形
            vh.AddTriangle(0, 1, 2);
            vh.AddTriangle(2, 3, 0);
        }

可以看得出來澄暮,網(wǎng)格是由4個(gè)頂點(diǎn)名段,兩個(gè)三角形構(gòu)成。在Unity中如圖所示:


simple.png

simple.gif

在這個(gè)模式下泣懊,無論圖片怎么變化伸辟,網(wǎng)格永遠(yuǎn)是由4個(gè)頂?shù)祝瑑蓚€(gè)三角形構(gòu)成馍刮。這種模式也是最少消耗性能的模式信夫。但是帶來的問題是,如果圖形需要非等比例縮放卡啰,那么就會(huì)引起圖片顯示比例失調(diào)而失真静稻。

3.       private void GenerateSlicedSprite(VertexHelper toFill)

裁剪模式下的頂點(diǎn)信息。源碼如下:

        static readonly Vector2[] s_VertScratch = new Vector2[4];
        static readonly Vector2[] s_UVScratch = new Vector2[4];

        /// <summary>
        /// 得到9個(gè)區(qū)域(用邊框裁剪開的9個(gè)區(qū)域)
        /// </summary>
        /// <param name="toFill"></param>
        private void GenerateSlicedSprite(VertexHelper toFill)
        {
            //如果沒有邊框則跟普通精靈頂點(diǎn)三角形是一樣的
            if (!hasBorder)
            {
                GenerateSimpleSprite(toFill, false);
                return;
            }
            Vector4 outer, inner, padding, border;
            if (activeSprite != null)
            {
                outer = Sprites.DataUtility.GetOuterUV(activeSprite);
                inner = Sprites.DataUtility.GetInnerUV(activeSprite);
                padding = Sprites.DataUtility.GetPadding(activeSprite);
                border = activeSprite.border;
            }
            else
            {
                outer = Vector4.zero;
                inner = Vector4.zero;
                padding = Vector4.zero;
                border = Vector4.zero;
            }
            Rect rect = GetPixelAdjustedRect();
            //調(diào)整后的邊框大小
            Vector4 adjustedBorders = GetAdjustedBorders(border / pixelsPerUnit, rect);
            padding = padding / pixelsPerUnit;
            //圖片的真實(shí)坐標(biāo)和大小
            s_VertScratch[0] = new Vector2(padding.x, padding.y);
            s_VertScratch[3] = new Vector2(rect.width - padding.z, rect.height - padding.w);

            s_VertScratch[1].x = adjustedBorders.x;
            s_VertScratch[1].y = adjustedBorders.y;

            s_VertScratch[2].x = rect.width - adjustedBorders.z;
            s_VertScratch[2].y = rect.height - adjustedBorders.w;

            for (int i = 0; i < 4; ++i)
            {
                s_VertScratch[i].x += rect.x;
                s_VertScratch[i].y += rect.y;
            }

            s_UVScratch[0] = new Vector2(outer.x, outer.y);
            s_UVScratch[1] = new Vector2(inner.x, inner.y);
            s_UVScratch[2] = new Vector2(inner.z, inner.w);
            s_UVScratch[3] = new Vector2(outer.z, outer.w);
            toFill.Clear();
            //生成9個(gè)矩形區(qū)域
            for (int x = 0; x < 3; ++x)
            {
                int x2 = x + 1;
                for (int y = 0; y < 3; ++y)
                {
                    if (!m_FillCenter && x == 1 && y == 1)
                        continue;
                    int y2 = y + 1;
                    AddQuad(toFill,
                        new Vector2(s_VertScratch[x].x, s_VertScratch[y].y),
                        new Vector2(s_VertScratch[x2].x, s_VertScratch[y2].y),
                        color,
                        new Vector2(s_UVScratch[x].x, s_UVScratch[y].y),
                        new Vector2(s_UVScratch[x2].x, s_UVScratch[y2].y));
                }
            }
        }

假設(shè)上下左右都存在外邊框的話(即九宮格的圖片格式)匈辱,那么頂點(diǎn)的個(gè)數(shù)是固定的16個(gè)姊扔,如果去除中心的話,三角形是16個(gè)梅誓,帶有中心的話恰梢,三角形是18個(gè)。從源碼可以看出梗掰,網(wǎng)格的邊框4個(gè)角部是永遠(yuǎn)不會(huì)被拉伸嵌言,一直是邊框大小原比例顯示(除非是顯示的尺寸小于邊框的大小)及穗,邊框的中部摧茴,以及圖片去除邊框的中心是會(huì)隨著圖形的拉伸而變化。如圖所示:


sliced.gif

接下來埂陆,把目光放在這張圖片的圓角上:


simple1.gif

上圖為簡(jiǎn)單模式下的圖片拉伸


sliced1.gif

上圖為裁剪模式下的圖片拉伸苛白,你覺得那個(gè)更具原生態(tài)。而且我們也可以使用三宮格焚虱,以及更特殊的裁剪邊框的模式來處理特殊的圖片购裙。
4.         void GenerateTiledSprite(VertexHelper toFill); 

平鋪模式下的頂點(diǎn)信息鹃栽。源碼過長(zhǎng)就不放了躏率,其構(gòu)造方式與裁剪模式相似,不過對(duì)于平鋪模式下民鼓,除了網(wǎng)格邊框的4個(gè)與裁剪模式一樣薇芝,他的邊框中部以及圖像中間會(huì)按尺寸比例像瓦片一樣平鋪產(chǎn)生,因此會(huì)構(gòu)造大量的頂點(diǎn)和三角形丰嘉,因此這種情況除非是特殊需求夯到,盡量不要使用。如圖所示:


tiled.gif
5.        void GenerateFilledSprite(VertexHelper toFill, bool preserveAspect)

覆蓋模式的頂點(diǎn)信息饮亏。其內(nèi)部通過FillAmount的值來控制需要構(gòu)建的頂點(diǎn)的數(shù)量耍贾。這種模式對(duì)于處理進(jìn)度類似的效果非常有效阅爽。除此之外他與簡(jiǎn)單模式具有一樣的特點(diǎn)。如圖所示:


filled.gif

小結(jié)

作為UGUI最重要的控件之一:Image逼争,我們不僅僅要會(huì)使用优床,還要懂得他背后的原理劝赔。Image這幾種模式誓焦,各有各的特點(diǎn),比如icon我們更偏向使用簡(jiǎn)單模式,并按比例顯示着帽,對(duì)于需要拉伸的圖片杂伟,我們往往會(huì)使用裁剪模式。很多時(shí)間仍翰,我們的項(xiàng)目中需要顯示的是一張?jiān)鷳B(tài)的圖片赫粥,那么如果使我們的圖片顯得更加自然,相信在文中予借,你能找到答案越平。關(guān)于頂點(diǎn)這一塊有什么不懂的地方,請(qǐng)參考之前文章:Unity_UGUI|通向UGUI源碼的入口VertexHelper 鏈接:http://www.reibang.com/p/2245969a9173

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末灵迫,一起剝皮案震驚了整個(gè)濱河市秦叛,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌瀑粥,老刑警劉巖挣跋,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異狞换,居然都是意外死亡避咆,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門修噪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來查库,“玉大人,你說我怎么就攤上這事黄琼∨虮ǎ” “怎么了?”我有些...
    開封第一講書人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵适荣,是天一觀的道長(zhǎng)现柠。 經(jīng)常有香客問我,道長(zhǎng)弛矛,這世上最難降的妖魔是什么够吩? 我笑而不...
    開封第一講書人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮丈氓,結(jié)果婚禮上周循,老公的妹妹穿的比我還像新娘强法。我一直安慰自己,他們只是感情好湾笛,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開白布饮怯。 她就那樣靜靜地躺著,像睡著了一般嚎研。 火紅的嫁衣襯著肌膚如雪蓖墅。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,631評(píng)論 1 305
  • 那天临扮,我揣著相機(jī)與錄音论矾,去河邊找鬼。 笑死杆勇,一個(gè)胖子當(dāng)著我的面吹牛贪壳,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蚜退,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼闰靴,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了钻注?” 一聲冷哼從身側(cè)響起蚂且,我...
    開封第一講書人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎队寇,沒想到半個(gè)月后膘掰,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡佳遣,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年识埋,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片零渐。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡窒舟,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出诵盼,到底是詐尸還是另有隱情惠豺,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布风宁,位于F島的核電站洁墙,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏戒财。R本人自食惡果不足惜热监,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望饮寞。 院中可真熱鬧孝扛,春花似錦列吼、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至陌选,卻和暖如春理郑,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背柠贤。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工香浩, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留类缤,地道東北人臼勉。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像餐弱,于是被迫代替她去往敵國(guó)和親宴霸。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 1 CALayer IOS SDK詳解之CALayer(一) http://doc.okbase.net/Hell...
    Kevin_Junbaozi閱讀 5,152評(píng)論 3 23
  • 開發(fā)過程中對(duì)UGUI的一個(gè)小總結(jié)膏蚓。 首先從原畫師拿到效果圖瓢谢,美術(shù)切圖,拿到碎圖后打成大圖驮瞧。 我們先來說一下...
    程序小妖精閱讀 3,770評(píng)論 0 6
  • Unity編輯器基礎(chǔ) 1.請(qǐng)描述游戲動(dòng)畫有幾種氓扛,以及其原理。 主要有關(guān)節(jié)動(dòng)畫论笔、單一網(wǎng)格模型動(dòng)畫(關(guān)鍵幀動(dòng)畫)采郎、骨骼...
    豆錚閱讀 4,531評(píng)論 0 6
  • 轉(zhuǎn)載自VR設(shè)計(jì)云課堂[http://www.reibang.com/u/c7ffdc4b379e]Unity S...
    水月凡閱讀 1,016評(píng)論 0 0
  • 一、界面制作 Q1:UGUI里的這個(gè)選項(xiàng) 狂魔,應(yīng)該是ETC2拆分Alpha通道的意思蒜埋,但是在使用中并沒起作用?請(qǐng)問有...
    hcq666閱讀 2,938評(píng)論 0 57