【Win 10 应用开发】UI Composition 札记(五):灯光
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 札记(五):灯光的更多相关文章
- 【Win 10 应用开发】UI Composition 札记(一):视图框架的实现
在开始今天的内容之前,老周先说一个问题,这个问题记得以前有人提过的. 设置 Windows.ApplicationModel.Core.CoreApplicationView.TitleBar.Ext ...
- 【Win 10 应用开发】UI Composition 札记(三):与 XAML 集成
除了 DirectX 游戏开发,我们一般很少单独使用 UI Composition ,因此,与 XAML 互动并集成是必然结果.这样能够把两者的优势混合使用,让UI布局能够更灵活. 说到与 XAML ...
- 【Win 10 应用开发】UI Composition 札记(二):基本构件
在上一篇中,老周用一个示例,演示了框架视图的创建过程,在本篇中,老周将给大伙伴们说一下 Composition 构建 UI 的一些“零件”. UI Composition 有一个核心类——对,就是 C ...
- 【Win 10 应用开发】UI Composition 札记(四):绘制图形
使用 Win 2D 组件,就可以很轻松地绘制各种图形,哪怕你没有 D2D 相关基础,也不必写很复杂的 C++ 代码. 先来说说如何获取 Win 2D 组件.很简单,创建 UWP 应用项目后,你打开“解 ...
- 【Win 10 应用开发】UI Composition 札记(六):动画
动画在 XAML 中也有,而且基本上与 WPF 中的用法一样.不过,在 UWP 中,动画还有一种表现方式—— 通过 UI Composition 来创建. 基于 UI Composition 的动画, ...
- 【Win 10 应用开发】启动远程设备上的应用
这个功能必须在“红石-1”(build 14393)以上的系统版中才能使用,运行在一台设备上的应用,可以通过URI来启动另一台设备上的应用.激活远程应用需要以下前提: 系统必须是build 14393 ...
- 【Win 10应用开发】认识一下UAP项目
Windows 10 SDK预览版需要10030以上版本号的Win 10预览版系统才能使用.之前我安装的9926的系统,然后安装VS 2015 CTP 6,再装Win 10 SDK,但是在新建项目后, ...
- 【Win 10 应用开发】在代码中加载文本资源
记得前一次,老周给大伙,不,小伙伴们介绍了如何填写 .resw 文件,并且在 XAML 中使用 x:Uid 标记来加载.也顺便给大伙儿分析了运行时是如何解析 .resw 文件的. 本来说好了,后续老周 ...
- 【Win 10 应用开发】导入.pfx证书
这个功能其实并不常用,一般开发较少涉及到证书,不过,简单了解一下还是有必要的. 先来说说制作测试证书的方法,这里老周讲两种方法,可以生成用于测试的.pfx文件. 产生证书,大家都知道有个makecer ...
随机推荐
- 【POJ】1704 Georgia and Bob(Staircase Nim)
Description Georgia and Bob decide to play a self-invented game. They draw a row of grids on paper, ...
- FastDFS简介和架构图(内容来自于阅读fastdfs官方文档的总结)
一.FastDFS简介 1. FastDFS是一个轻量级的开源分布式文件系统 2. FastDFS主要解决了大容量的文件存储和高并发访问的问题,文件存取时实现了负载均衡 3. FastDFS实现了软件 ...
- Linux+Apache2.4+PHP5.6+MySQL5.6源码安装步骤
一.安装Apache 若要安装apache服务器软件,需要安装以下几个依赖软件 apr-1.4.6.tar.gz 下载地址:http://apr.apache.org/ apr-util-1.4.1. ...
- Angular - 预加载 Angular 模块
Angular - 预加载延迟模块 在使用路由延迟加载中,我们介绍了如何使用模块来拆分应用,在访问到这个模块的时候, Angular 加载这个模块.但这需要一点时间.在用户第一次点击的时候,会有一点延 ...
- DataGridView的使用记录
首先初始化 1 this.CheckView.Columns.Clear(); 2 DataGridViewComboBoxColumn dcomo = new DataGridViewComboBo ...
- (转)TabIndex 属性
html中的tabIndex属性可以设置键盘中的TAB键在控件中的移动顺序,即焦点的顺序. 把控件的tabIndex属性设成1到32767的一个值,就可以把这个控件加入到TAB键的序列中. 这 ...
- BZOJ-4915-简单的数字题
Description 对任意的四个不同的正整数组成的集合A={a_1,a_2,a_3,a_4 },记S_A=a_1+a_2+a_3+a_4,设n_A是满足a_i+a_j (1 ≤i<j≤4)| ...
- chromium源码阅读--Browser进程初始化
最近在研读chromium源码,经过一段懵懂期,查阅了官网和网上的技术文章,是时候自己总结一下了,首先IPC message loop开始吧,这是每个主线程必须有的一个IPC消息轮训主体,类似之前的q ...
- 【完美解决】2017打开MVC 4项目,cshtml页面提示‘当前上下文不存在名称model’
时间:2017/10/19 背景:领导让再之前的MVC 4老项目上新增功能,从GIT上拉取下来,使用VS2017打开之后,cshtml界面所有和Razor相关的代码均被提示‘当前上下文不存在名称XXX ...
- JS对象深度克隆
首先看一个例子: var student = { name:"yxz", age:25 } var newStudent = student; newStudent.sex = & ...