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 札记(五):灯光的更多相关文章

  1. 【Win 10 应用开发】UI Composition 札记(一):视图框架的实现

    在开始今天的内容之前,老周先说一个问题,这个问题记得以前有人提过的. 设置 Windows.ApplicationModel.Core.CoreApplicationView.TitleBar.Ext ...

  2. 【Win 10 应用开发】UI Composition 札记(三):与 XAML 集成

    除了 DirectX 游戏开发,我们一般很少单独使用 UI Composition ,因此,与 XAML 互动并集成是必然结果.这样能够把两者的优势混合使用,让UI布局能够更灵活. 说到与 XAML ...

  3. 【Win 10 应用开发】UI Composition 札记(二):基本构件

    在上一篇中,老周用一个示例,演示了框架视图的创建过程,在本篇中,老周将给大伙伴们说一下 Composition 构建 UI 的一些“零件”. UI Composition 有一个核心类——对,就是 C ...

  4. 【Win 10 应用开发】UI Composition 札记(四):绘制图形

    使用 Win 2D 组件,就可以很轻松地绘制各种图形,哪怕你没有 D2D 相关基础,也不必写很复杂的 C++ 代码. 先来说说如何获取 Win 2D 组件.很简单,创建 UWP 应用项目后,你打开“解 ...

  5. 【Win 10 应用开发】UI Composition 札记(六):动画

    动画在 XAML 中也有,而且基本上与 WPF 中的用法一样.不过,在 UWP 中,动画还有一种表现方式—— 通过 UI Composition 来创建. 基于 UI Composition 的动画, ...

  6. 【Win 10 应用开发】启动远程设备上的应用

    这个功能必须在“红石-1”(build 14393)以上的系统版中才能使用,运行在一台设备上的应用,可以通过URI来启动另一台设备上的应用.激活远程应用需要以下前提: 系统必须是build 14393 ...

  7. 【Win 10应用开发】认识一下UAP项目

    Windows 10 SDK预览版需要10030以上版本号的Win 10预览版系统才能使用.之前我安装的9926的系统,然后安装VS 2015 CTP 6,再装Win 10 SDK,但是在新建项目后, ...

  8. 【Win 10 应用开发】在代码中加载文本资源

    记得前一次,老周给大伙,不,小伙伴们介绍了如何填写 .resw 文件,并且在 XAML 中使用 x:Uid 标记来加载.也顺便给大伙儿分析了运行时是如何解析 .resw 文件的. 本来说好了,后续老周 ...

  9. 【Win 10 应用开发】导入.pfx证书

    这个功能其实并不常用,一般开发较少涉及到证书,不过,简单了解一下还是有必要的. 先来说说制作测试证书的方法,这里老周讲两种方法,可以生成用于测试的.pfx文件. 产生证书,大家都知道有个makecer ...

随机推荐

  1. hdu3507 Print Article(斜率DP优化)

    Zero has an old printer that doesn't work well sometimes. As it is antique, he still like to use it ...

  2. JavaScript高级(01)

    前端开发工具 1.1. WebStorm介绍和下载 l  介绍 WebStorm是JetBrains 推出的一款强大的HTML5编辑工具,拥有丰富的代码快速编辑,可以智能的补全代码.代码格式化.htm ...

  3. Fitnesse - Slim Tables

    Fitnesse - Slim Tables 2017-09-28 目录1 什么是Wiki Word?2 Query Table   2.1 Query Table的格式  2.2 源代码3 Scri ...

  4. java基本的要点

    我想告诉大家的不是什么java基本要点,只是对初学者的一点忠告,本人是从八维学校亲身经历过的学生,要想学好并且快速了解java,那你首先必须有英语底子,没有英语底子,几个单词都不会的,我觉得还是放弃学 ...

  5. 实现mysql在windows server 2008下自动备份

    环境:MySQL   安装位置:D:\MySQL论坛数据库名称为:Db_Test数据库备份目的地:D:\db_bak\ 1.首先新建一个bat文件 rem ********************** ...

  6. KMP算法的细节问题

    preface: 想必,很多人都知道D.E.Knuth与V.R.Pratt和J.H.Morris同时提出所谓的狂拽酷炫屌炸天的KMP算法,在对字符串的匹配(或是字符串的查找)方面表现出比较好的效率,该 ...

  7. TypeScript中的怪语法

    TypeScript中的怪语法 如何处理undefined 和 null undefined的含义是:一个变量没有初始化. null的含义是:一个变量的值是空. undefined 和 null 的最 ...

  8. 【转载】CSS3 Transitions, Transforms和Animation使用简介与应用展示

    文章转载自 张鑫旭-鑫空间-鑫生活 http://www.zhangxinxu.com/wordpress/ 原文链接:http://www.zhangxinxu.com/wordpress/?p=1 ...

  9. PhoneWindow,ViewRoot,Activity之间的大致关系

    http://www.nowamagic.net/academy/detail/50160216 在android里,我们都知道activity.但是一个activity跟一个Window是一个什么关 ...

  10. android 统计启动时长,标准

    一.启动的类型 冷启 动,application没有被创建,需要先创建进程,然后启动MainActivity.由于这个过程需要fork一个新进程,所以耗时. 热启动,同上面对照,已经启动过applic ...