【Win 10 應用開發】UI Composition 劄記(五):燈光

來源:互聯網
上載者:User

標籤:技術   min   one   txt   圖片   orm   圖形   eva   密度   

UI Composition 除了能夠為 UI 元素建立三維空間外,還有相當重要的一個組件——燈光。宇宙萬物的精彩繽紛,皆源於光明,光,使我們看到各種東西,除了黑洞之外的世界都是五彩斑讕的。故而,真要類比現實物體,合理的燈光照射是很關鍵,不然就“不像”了。

Composition API 為各種燈光效果提煉了一個公用基類——CompositionLight,它帶有兩個規範性的屬性:

Targets:可視化元素的集合。用來確定情境中哪些東西應該被照亮。比如,你類比了一面牆,牆壁上掛著各種畫,有山水,有鳥獸,有美女,有蝙蝠,如果你要看畫,黑乎乎的你連根狗毛也看不見的,所以你看到很多美術館或博物館都會安裝各種燈源,只有打燈你才能看到這些畫的。如果你希望看美女,那麼就把美女加入 Targets 集合,這樣美女就會被燈光照亮。

ExclusionsFromTargets:這是一個排除項列表。與上面的剛好反過來,就是指定你不希望被照亮的物體。如果你覺得蝙蝠太猙獰太恐怖,不想看,你可以把它排除掉,就不會被燈光照亮了。

 

環境光線

環境光線類似於咱們家裡的白熾光、節能燈等,這種光源比較均勻,基本可以把整個房間照亮。

我們看一個環境光線的例子。下面樣本,在介面上載入一張圖片,然後我們用環境光線去照亮它。順便放一個 Slider 控制項,目的是可以調節光照的強度。

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">        <Grid.RowDefinitions>            <RowDefinition/>            <RowDefinition Height="auto"/>        </Grid.RowDefinitions>        <Image Source="Assets/5.jpg" Stretch="Uniform" Name="img"/>        <Slider Grid.Row="1" Margin="2,9" StepFrequency="0.1" Value="1" Minimum="0" Maximum="10" ValueChanged="OnSliderValChanged"/>    </Grid>

切換到代碼檔案,在頁面類的建構函式中,咱們添加一下燈光效果。

        AmbientLight light = null;        public MainPage()        {            this.InitializeComponent();            Visual v = ElementCompositionPreview.GetElementVisual(img);            Compositor compos = v.Compositor;            light = compos.CreateAmbientLight();            light.Targets.Add(v);        }

注意,我為什麼要把 AmbientLight 的變數聲明到類層級呢,因為可以在後面調整它的強度。下面是 Slider 控制項的 ValueChanged 事件的處理代碼。

        private void OnSliderValChanged(object sender, RangeBaseValueChangedEventArgs e)        {            if(light != null)            {                light.Intensity = (float)e.NewValue;            }        }

這裡要先判斷一下 light 變數是否為 null,因為這個事件處理是在 XAML 代碼中關聯的,即在頁面類執行個體構造過程中會調用這個方法(主要是設定 Value 屬性的值時發生),那個時候,環境光線對象還沒有建立,如果不判斷,就會出現 null 引用異常。

AmbientLight 類表示環境光線,它有一個 Color 屬性,用以指定光的顏色,預設是白光。當物體被白光照亮時,它呈現的是本色(本來面目)。所以,上面代碼的執行效果如。

 

Intensity 表示光照強度,從上面的例子咱們看到,這個值應該大於 0,小於等於 0 就全黑了,什麼都看不見,那就沒有意義了,值也不要太大,所以我這個例子最大就到 10 ,當然你可以設定 100、1000,可是強度太大了,會亮瞎眼的,什麼也看不見,也是沒有意義的。光照強度預設是 1 ,我們可以根據需要設定合適的值。

我們還可以換一下其他顏色的光,比如,我們改一下代碼,用充滿幽靈意味的綠光去照射一下。

  light.Color = Colors.Green;

然後,效果很驚人。

 

 

定點光

點光,即 PointLight,它就像一盞小燈泡,發出的光並不能像環境光線那樣覆蓋全面,而是點狀的,但它可以照亮四周的物體,而且距離物體近的話,照得更亮,這就很像火把、蠟燭。所以,PointLight 類的屬性會比環境光線多一些,也複雜一些。

Color 和 Intensity 屬性是一樣的,前者表示燈光的顏色,後者表示強度。除此之外,還有以下這幾個:ConstantAttenuation、QuadraticAttenuation、LinearAttenuation,這幾個屬性的性質是一樣的,只是演算法不同,有的是平方值的,有的是線性。這些值是用來設定光的衰減速度,啥意思呢,我們剛剛不是說過嗎,點狀光的照亮程度是跟距離有關,隨著燈光與物體的距離增大,亮度會衰減。當然,如果光線很強的情況下,距離遠可能照亮的範圍更大,近距離情況下,會把局部照得更亮。這幾個值就是用來描述光線衰減的速度。在現實世界中,這可能與空氣能見度或空氣密度有關,因為這些要素會影響光的傳播。但在虛擬圖形中不存在真實的大氣,所以需要通過演算法來類比。

由於點狀光是一個發光點,所以它肯定會有位置的,即座標,下面兩個屬性用來確定點狀光的座標:Offset 屬性確定位置,它是一個三維座標;CoordinateSpace 又是啥呢,它要求指定一個可視化對象,用來計算光照的強度的。你想啊,大晚上,你在一片荒野上點根火把,你會覺得這火把好像不怎麼亮,但是,如果你在一個狹窄的山洞裡面點一根火把,你就會覺得它特別亮。所以,這個屬性就是設定一個容器,好確定這點光到底能照多亮。

下面我們看看定點光的例子。

在介面上我們放置一個文本,然後,下面的 Slider 控制項用來調整點光的衰減速度,即  ConstantAttenuation 屬性,這個值越大,表明同樣距離下燈光會更弱,因為它衰減得更快更明顯,這個值是大於0的任意值。

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">        <Grid.RowDefinitions>            <RowDefinition />            <RowDefinition Height="auto"/>        </Grid.RowDefinitions>        <Border Background="Black" Grid.Row="0" Name="bd">            <TextBlock VerticalAlignment="Center" HorizontalAlignment="Center" Text="歡迎觀臨" FontSize="150" FontFamily="華文行楷" Foreground="Gold" Name="text"/>        </Border>        <Slider Grid.Row="1" Margin="2,7" Maximum="5" Minimum="1" Value="1" StepFrequency="0.1" Name="sld"/>    </Grid>

TextBlock 為什麼要放到一個 Border 中呢,前面說了,定點光需要一個容器來計算照亮程度,所以,Border 是用來作為參考容器的。

 

切換到程式碼檢視,在頁面類的建構函式中,我們來加一下定點光。

        public MainPage()        {            this.InitializeComponent();            // 擷取容器            Visual vsContainer = ElementCompositionPreview.GetElementVisual(bd);            // 擷取 TextBlock 的可視化對象            Visual txtVisual = ElementCompositionPreview.GetElementVisual(text);            Compositor compos = vsContainer.Compositor;            // 建立光源            PointLight light = compos.CreatePointLight();            // 燈光顏色            light.Color = Colors.Silver;            // 強度            light.Intensity = 3.6f;            // 位置            light.Offset = new Vector3(500f, 280f, 45f);            // 照射目標            light.Targets.Add(txtVisual);            // 相對容器            light.CoordinateSpace = vsContainer;            // 處理 ValueChanged 事件            sld.ValueChanged += (k, x) =>            {                light.ConstantAttenuation = (float)sld.Value;            };        }

這一回處理 ValueChanged 事件就不需要判斷 light 是否為null了,因為附加這個事件處理時,light 對象已經初始化。

注意,這裡我們不僅要擷取 TextBlock 的Visual ,儘管我們的照亮目標是它,但是,因為這種光源需要容器,所以我們要同時獲得 Border 的 Visual。

 

來,看看效果吧。

 

 

 

錐光

這種光源類似手電筒的光,其實與上面的 Pointlight 很像,但錐光帶有內圈和外圈。所以,錐光也有顏色、強度、衰減程度等參數,當然也會有位置。

InnerConeAngle 是內圈的角度,OuterConeAngle 是外圈的角度,用弧度角表示。如果想用角度,可以用 InnerConeAngleInDegrees 和 OuterConeAngleInDegrees 屬性。

InnerConeIntensity 表示內圈的光線強度,OuterConeIntensity 表示外圈的光線強度。

Offset 表示光的位置,和上面的定點光類似,但錐光多了個 Direction 屬性。用過手電你都知道的,它有個照射方向。如果光源位於物體前方,要想讓它照亮物體,Z軸上的方向必須是負值,只有負值才會照進螢幕裡面;如果光源在物體後面,Z軸上的方向當然要正值,這樣照射方向才會指向螢幕外。

 

我們做個例子。在介面上放一張圖,先給大家看看原圖。

 

這書房是不是很高大上呢。然後我們讓它在 Image 元素上載入。

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">        <Border Name="bd" Background="Black">            <Image Name="img" Source="Assets/2.jpg"/>        </Border>    </Grid>

Image 元素外面也需要一個容器,這裡我還是用Border,因為錐光和定點光一樣,需要一個容器來計算光照。

定位到代碼檔案,在頁面類的建構函式中添加光源。

        public MainPage()        {            this.InitializeComponent();            // 擷取目標元素與容器元素            Visual container = ElementCompositionPreview.GetElementVisual(bd);            Visual vimg = ElementCompositionPreview.GetElementVisual(img);            // 建立光源            SpotLight light = vimg.Compositor.CreateSpotLight();            // 設定容器            light.CoordinateSpace = container;            // 添加照亮目標            light.Targets.Add(vimg);            // 外圈和內圈光線的顏色            light.OuterConeColor = Colors.Blue;            light.InnerConeColor = Colors.LightYellow;            // 外圈和內圈光線的強度            light.InnerConeIntensity = 3.2f;            light.OuterConeIntensity = 1f;            // 角度            light.InnerConeAngleInDegrees = 30f;            light.OuterConeAngleInDegrees = 90f;            // 位置            light.Offset = new Vector3(550f, 270f, 150f);            // 方向            light.Direction = new Vector3(-1f, 1.1f, -1f);        }

 

好了,看看效果吧。

 

 OK,本篇就說到這裡了,開飯了。

 

【Win 10 應用開發】UI Composition 劄記(五):燈光

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.