大多数浏览器和
Developer App 均支持流媒体播放。
-
Swift Playgrounds 中的 SceneKit
探索 Swift Playgrounds 内容团队为在有丰富视觉效果的 app 中高效使用 SceneKit 而总结的技巧与窍门。了解如何整合动画、优化渲染性能、进行辅助功能设计和增加视觉质感,理解利用 3D 素材资源创建高效工作流程的策略。
资源
-
下载
(Swift Playground中 SceneKit的使用)
谢谢
大家早上好 欢迎来到“Swift Playground中 SceneKit的使用”演讲 我是Michael DeWitt 今天我很激动地向大家介绍 如何利用SceneKit 制作Learn to Code内容 但愿你们都已熟悉 Swift Playground 但让我来给大家展示一个 Learn to Code
这是一个Learn to Code 内容的示例课程 存在于Swift Playground内 左侧是课程和用户的代码 但对于本场演讲 我们实际上要重点关注右侧 请注意即时取景 我们可以把它放大为全屏显示 这样看得更清楚
这个角色 百特 现正快速绕着地图跑并收集宝石 不停地上下台阶 当百特收集到全部宝石之后
我们得到了一个祝贺场景 让学习者了解他们实现了很棒的功能 并且百特甚至还会跳舞 让人们了解这真的很棒
这就是我们今天的案例研究 我们要通过这个场景来展示 如何有效地使用SceneKit 并把丰富的3D内容带到你的应用中去
如果你对3D感兴趣 但还是个新手 那你来得正合适 因为我们要从一些 很不一样的东西开始讲起
我们要从简单的2D场景开始讲 关于SceneKit最好的优点之一 就是允许2D程序员 把这个场景放在现有时间轴上 并通过我们发布到Learn to Code中 丰富的3D内容实现3D效果
那么这就是我们今天要谈的内容 我们一共有40分钟 我们可以把它分成三个部分
首先我要讲一下原型设计 以及如何精化想法确保其真的很棒
关于迭代 我想谈谈 你何时会从你的供应商处 获得一些真正的资产 如何建立有效的管道 然后Lemont将上台讲一下调整 并准备好发布场景
首先是原型设计
这是在我们决定使用 Learn to Code 且我们已准备好 开始创建东西时出现的 那么你之前看到过这个图 但在这里它是在情境中
我们一开始有来自表情集合的宝石 和四处散放的资产 因为我们只需要拾取并尽可能快地跑 以在这个新应用中测试交互模型 我们从这里学到了很多 资产看起来怎么样并不重要 但通过这个原型设计过程 我们开始获得一些早期反馈
其中有些评论是关于图形的 它…请求比如说我们 是否可以修改宝石颜色 我们是否在场景周围添加一个边框 或我们是否可以让相机在尽头处 转动以提供一些视觉趣味
这是很好的反馈 它真的非常有迭代性 当你进行原型设计时 你不应该害怕把它们全部扔掉 那么如果我们返回去看情境中的场景 你可以看到它在这个页面上很单调 视觉效果是我们得到的全部反馈 我们只需要重新评估我们的策略
因为我们在SpriteKit中做的 现在我们要开始使用SceneKit 对于你们中 熟悉SpriteKit的人来说 你了解它有以下概念: 基本上是一个执行更新逻辑的场景 一个把对象放在视图中的节点 还有移动对象的行动 现在Apple开发SceneKit 的好处还包括 它有许多这样的相同概念
这就给了我们足够的信心 一个简单的切换 开始使用SceneKit 并深入了解它 那么跟你们中许多人一样 我们看了2015年的 一场WWDC演讲 那是一场很棒的演讲 是SceneKit团队主讲的 内容是关于如何创建简单的场景 就像你们在这里看到的这个一样
但不只是这样 我们还要使用示例中的一些资产 并重新创建我们的场景
所以我们现在来到了这个舞台 我们马上就会告诉你们 这只是一种更好的方式 我的意思是它更拟真 你可以随意拖动相机 并且它会帮助你解决等级问题
这张幻灯片的重点是 即使我们已经明确地提升了视觉质量 当你设计原型时 你仍希望使视觉保真度 保持一个低水平 那么当我们添加新游戏结构时 比如这些门户 我们采用了SceneKit基元实现 因为我们不想提得太高 以确保场景看起来绝对很棒 我们首先要确保这是一个好主意
所以我把这个丢到 Business Tool 101图表上
你基本可以看到项目的整个时间轴 你想把其中一大块分配给原型设计 因为这是你可以做出最多修改的部分 而做出修改需要付出的努力并不多
尤其当你正在做3D时 当你开始获取真实的资产时 这是我们下一个部分要讲到的内容 要进行修改需要付出的努力不断增加 所以当你设计原型时请留意这一点
那么总的来说 其实你想 当你在设计原型时 测试你的交互模型 这并不是与资产相关 你想阐明你接收的反馈 但并不想做出越来越多的修改 想要确保这个想法是有效的 最后利用从这部分获得的洞察力 去写代码 我觉得我们做的最棒的决策是 开始新建项目 当我们朝着这点努力时 这就将我们带入了迭代
现在我们已经有了想法 我们准备好获得一些真正的艺术了 我们开始与设计师一起工作 我们得到了这个早期的2D样稿
你可以看到 它现在与百特的世界很相似 看起来要好点 我想把这个世界分成四部分 我要讲的第一件事就是它是如何建造的 以及有效建造的一些策略 接下来我们要看看如何在你的应用中 完成复杂的动画 通过查看我们如何实现让百特上下台阶
我们还要了解如何用水 和其它场景元素添加视觉趣味
然后我们就重点讲视觉部分 但是还有整个用户方面 实际上不能从3D场景的图形中 获得什么好处 所以我们要花点儿时间讲讲可达性支持 尤其是VoiceOver
好了 首先是给这个世界建模 那么你可以通过模具看到 我们是通过这些组块创建世界的 我们有单项资产 这样做是有原因的
我们不仅需要在资产设计上迭代 还需要在课程设计上迭代 所以我们把像这样的简单拼图拼在一起 确保学习者能顺利学习大纲
但不是把这些单一的组块 放在场景编辑器中 那会非常乏味 而是写一些代码来实现 很像使用Learn to Code 2的学习者们 当他们创建自己的世界时 我们写了一些代码来生成这个 它看起来是这样的
要创建那个世界 你首先要给它一个尺寸 5乘5 你把元素放进去 比如演员 或你在之前的场景中见到过的百特 然后你可以添加附加元素 比如宝石或你在中心看到过的水
但我展示这段代码的原因不是因为 “哇哦 我们写了一个API 创建了一个世界” 这很酷 而其实是因为这与图形是完全分离的 对吧?这段代码在2D中 和在3D中一样有效
让我实际给你展示一下这是什么意思 这里有一个短视频
这里有百特 正在这个世界中移动 我们要添加一些节点 你在场景中看到的红色和绿色节点 其实代表了我们重建 游戏设置所使用的数据
实际上我们所需要的就是那个数据 我们把场景的图形 和用于重建游戏设置的数据分离了
这样做有几个很大的好处 我想让你在给3D世界建模时考虑一下
将数据与图形分离 首先它允许你简单地置换出资产 请记住 我们仍在这个材料上进行迭代 无论如何我们将获得这个组块的新版本 并且我们不想重建这些地图 所以我们就动态地生成了地图
它还允许你获取那个数据 并将其发送到别处 也许你需要将其通过网络发送出去 或在处理过程中发送一些游戏设置逻辑 比如我们在某些游戏场地中所做的那样
一段时间之后 它还将允许你优化几何体 Lemont将会具体介绍 但有一点很关键 就是你并不依赖于 实际的节点和场景才能实现
我有一个警告
你需要一些调试工具 使这个运行起来更棒 我们在很早之前就发现了 你不再只是查看世界了 而是查看如何重建游戏设置 所以我们创建了一个 非常简单的Mac应用 这个应用可以加载 我们所拥有的全部等级 更重要的是它有专门的场景知识 那么既然这样 这个工具就是 允许我们展示你之前 看到过的那些调试节点的工具 它还可以在我们的游戏中 运行难以达到的情况 比如当你达到祝贺序列时 围绕世界旋转 我们想确保能在每一幅地图上使用 但我们不想一直测试每一幅地图 只是为了看到一个结果
那么这就是我们的第一部分 就是我们如何把世界拼在一起 我们分离了数据和图形 并使用了工具
现在讲动画 如果我们近距离地看一下台阶
你可以看到这其实是一个 相当复杂的几何体 对吧?不仅有独立的台阶 台阶上还有一些花样 所以我们想做到超级精确 关于我们角色的脚 落在每个台阶上的位置
我们考虑了一些不同的策略 对于3D场景来说 最常用的一个东西就是 用斜坡替换台阶 因为斜坡的实现很简单 你有一个角色 你向前移动那个角色 你算出他们需要移动多远 然后你只需要把他们从点A转移到点B 当运行行走动作循环时
对于台阶 并不是那么好做 这是百特尝试上台阶 如果你离近点儿看 百特甚至没有接触到第一个台阶 他已经漂浮在半空中了
所以我们要把这个效果做得更好
我们要考虑的第二件事就是 使用SceneKit中的内嵌类型 它其实是SceneKit 约束系统的一部分 用于执行逆向运动 现在逆向运动允许你得到超级精确度 关于你想让角色的脚落在哪个位置 那么我们要指定我们希望角色 上下的每一个台阶
但它却伴随着牺牲了角色的一些个性 对吧? 我们不能控制眼睛的运动 或上半身的运动 不像我们想象中的那么具体 我们其实还有第三种选择 就是把位移合并到动画中去 因为这是我们所采用的策略 让我们再详细地具体看一下
通常对绝大部分游戏来说都有节点 代表一个位置 还有几何体 就是你在场景中实际能看到的东西
现在这两样东西同时移动也是很常见的 所以你需要转换节点和几何体 同时执行行走循环 它会让角色从点A移动到点B 但对于台阶 我们做了一点不一样的处理
我们不干涉节点 并应用了一个动画 这个动画中其实含有位移 那么这就会把几何体从节点中移出来 然后当动画完成后 我们同步节点的位置并移除动画
我们是通过SceneKit中一个 叫作SCNTransaction的类型实现的
SCNTransaction允许你确保 在一帧中进行更新 让我们具体看一下
你用开始和提交调用设置 在我们的示例中 我们想要的动画时长为零 因为我们需要它在同一帧中发生
我们把角色移动到新位置并移除动画 让百特准备好下一轮的动画 让我们看看实际效果
先舒展一下身体
走上台阶…
你现在可以看到 因为我们允许这个动画师 自由地把位移放到动画中 针对百特的移动 我们变得非常精确了 当它上下台阶时 百特的头也会转动 这是一个较好的解决方案 你需要针对你场景中的复杂动画 考虑一下
第三点
让我们看看如何处理场景元素 因为它并不全与角色相关 你还要确保这个世界感觉鲜活
那么让我们近距离看一下水
现在你见过我们之前曾用过 像这样的地图 是吧? 相当基础 刚好能重建这个游戏 但我们想实现像这样的地图
我们的实现方式是将原始地图保存 为SCN文件 以便添加这些附加元素 对吧?那么我们不写代码 来放置每一个场景元素了 我们现在可以在场景编辑器中实现了 因为那样更有意义 若我们在SceneKit 场景编辑器中看一下
它看起来很棒 但现在我们投入了很多时间和精力 给每一个单独的地图 你可以看到这是通过 左边的节点层级实现的
那么问题是你仍然希望 保持一定数量的灵活性 确保设计师不会在下一周过来说 “我做了个新瀑布 看起来更好” 那你不需要修改81幅地图 实现方式是如果我们近距离看瀑布 它使用了一个叫作引用节点的技术 那么这些是我们场景中的水节点 而箭头表示它们被引用到 一个单一的SCN文件 那么你只需要更新那一个文件 它就会传导到全部地图中
现在这并不是与水相关的全部问题 若我们再仔细看看那个SCN文件
像水这样的元素必须得动起来 看着才会有意思 对吧?设计师在这里做得不错 纹理看起来超棒 但它不真实
那么为了实现水的移动 我们要使用一个技术 一个几何体修改器 其实是写一个着色器 你可以通过 右下方的按钮获取 我把它放大一点 不然很难看到 那会打开一个托盘 是Xcode 9中的新功能 你可以修改或指定 你的几何体修改器 构建由SceneKit提供给你的 这个SCN着色器几何体类型 那么这要实现的是 围绕瀑布移动纹理 但它添加了一个很棒的效果 让我们看一下效果
开始吧 那么现在水实际上是在流动的 你可以看到纹理的移动 且它添加了这个很棒的效果 我们将采用同样的技术 处理场景中摇摆的葡萄藤 以及被微风吹动的小草 那么这给你的场景添加了许多生气 这是一个很棒的技术 你可以尝试一下
这是第三点 我们真的很关注视觉效果 我们采取了若干步骤 来解决如何让效果更棒的问题 但还有另外一整个方面 也是你要考虑到的 这就是对于有视力障碍的用户来说 场景看起来是什么样的
那么当你尝试在VoiceOver中 设计一个很棒的体验时 很明显 你希望更多地关注元素 而不是视觉效果 但我不会描述我们所做的一切 我首先希望你先听一下这个体验
打开VoiceOver 横屏 这个世界是五栏乘五行
栏0 行0 百特的高度为0 面朝北 轻触两次切换角色 栏0 行1 宝石高度为0
那么…我们采取了一系列的操作 以在Learn to Code中 支持VoiceOver 但我希望你注意到的第一件事是 我们其实关注的是一个 很棒的非视觉体验 通过添加音乐 通过添加角色声音 你让这个场景听起来很丰富
我们还向VoiceOver中 添加了其它东西 要深入研究这些技巧 请参看今年的一场很不错的演讲 关于使媒体和游戏可理解
对我们来说非常重要的一点 其实是使用VoiceOver 描述重要的地理位置 我想具体介绍这个的原因是 因为它惊人简单 那么跟你的UIKit应用一样 我们覆盖一个可访问性元素
我们可以提供一个自定义标签 在本例中 我们提供了一个标签 用于更新世界的当前内容
所以这是你已经在UIKit中 熟练运用的同样技巧 就是那么简单 你创建其中一个元素
你指定它的帧 我们使用SceneKit中的projectPoint 从3D到2D 并将那个元素添加到视图中
那么我的观点是 即便3D看起来很难获取 它其实很简单 它就是你已经熟悉的技巧 那么有三个主要原因 第一 这对于你的用户来说很棒 最值得的其中一方面很可能 我认为是做这个项目
抱歉 我认为是最值得的其中一个方面 第二是实现就是那么简单 有来自UIKit开发中的一些 你很熟悉的东西 第三 就像没有理由 不让你的应用 在UIKit中可获取一样 也应该没有理由不在3D中这样做
那么如果你想看完整代码 你可以参看 Learn to Code资源 通过在Playground书中 深入研究辅助资源 并且这个文件其实也存在于 Accessibilityextensions.swift中
那么这就是迭代 我们谈了你应该如何将数据 与你场景的图形分离开来 对吧?我们将其用于给世界建模 还有如何实现台阶动画
你甚至应该在这个阶段就重视灵活性 那么当你把全部时间和精力 都花在这上面 确保你正在做像使用引用节点这样的事 以便你仍然有一些灵活性
那么最后 确保你提早审核可达性支持 它不是那种最后可以扩充的东西 如果你有计划它会惊人简单
现在让我们谈谈 如何获取这些设计时间资产 以及如何调整它们 使其拥有超级良好的性能 我要邀请Lemont上台
谢谢Michael 很棒
大家好 我是Lemont 我是Swift Playground 内容团队的工程师 今天我要跟大家谈谈 如何改进SceneKit应用的性能 关于帧频率和用户体验 (调整) 当我们首次开始开发 Learn to Code时 对我们来说最要紧的是 拥有一个非常丰富和细致的世界 正如你在这里所看到的 这就是我们所拥有的 瀑布看起来很逼真 台阶后的阴影看起来很棒 颜色也很丰富和生动 在瀑布中甚至还隐藏有漂亮的雕像
但正如你所了解的 一个看起来漂亮的应用 并不是拥有了不起用户体验的唯一方面 还有性能
那实际是什么意思呢?
要获得一个不错的体验 我们实际上得有 一个响应性很好的帧频率 你的用户正在与你的应用进行交互 他们正在缩放 他们正在做手势 他们正在向场景中添加对象 移除对象 你希望这个过程要很快 并且很流畅
那么我要给你展示我们是如何 在Learn to Code中 提升我们应用的性能
让我们看一个 拥有更复杂的几何学的场景 我提到复杂的几何学 我的意思是这个场景由成千上万个 独立的几何体零件组成
现在每一个零件 都分别要由GPU进行渲染
那么让我们来看看 我们应用的性能怎么样 SceneKit有一个很有用的工具 叫作调试统计视图
我想把它放大看一下
现在你可以在你的应用中启用这个功能 只需要把 你视图中的showStatistics属性 设为真即可
如果我们看一下这些更有意思的数字 …调试视图 你会注意到我们有一个很低的帧频率 每秒29帧 这可不好 我们实际上想要达到每秒至少60帧 这可以允许我们获得流畅的交互 当用户缩放或做手势的时候
到底是什么导致了这么低的帧频率呢? 让我们具体来看一下 每一帧都在做什么?
这里的这个数字是跟渲染有关的 是我们用来渲染 一个完整帧所需的时间
看起来我们需要20.4毫秒
太慢了 如果你算一下 如果你想达到每秒60帧 你必须得在16毫秒以下完成
我们花了20毫秒 都在干什么呢?
要帮助了解这个问题 我们可以看一下 绘制调用的数字 正如你所看到的 用这个方框突出显示了
现在 什么是绘制调用?
快速回顾一下 当你想在场景中绘制对象时 CPU必须得告诉GPU说 “嘿 绘制这个网格” CPU绘制这个网格或几何体对象 那么这就是绘制调用 看起来我们一共有877个绘制调用 有相当多的绘制调用 那么我们可以做什么 以实际提升我们应用的性能呢?
我要跟你分享一个小技巧
那么在我们接下来的演讲中有一个主题 就是如何减少绘制调用的数量
我要跟大家谈三个明显的时期:
组成场景的网格几何体
给我们的场景 提供了一个漂亮外观的材料
以及让我们场景鲜活的光照
让我们看一个之前展示过的例子
现在这个场景有许多单一的零件 我想只看其中一种 小草
现在 如果你近距离地看
你们数学很好吧 你可以数一下 这个屏幕中大概有30个单一的方格 每个方格都有自己的网格 那么CPU必须告诉GPU 逐个渲染这些东西 我们就有了30个绘制调用 现在这是一个小场景 想象一下 如果你想拥有一个很大 很广阔的世界 有成千上万个这样的方格 我们就会有成千上万个绘制调用 想象一下我们的帧频率会怎么样
你可能会注意到一点 这些小草方格可能不需要移动
那么如果它们不移动 我们为什么要绘制这么多呢? 我们是否也许可以绘制一个大的网格?
这是可以的
有一条规则我想要你记住 就是当你与GPU通讯时 每个网格有一个绘制调用 如果你有一千个网格 那么就有一千个绘制调用
那么如果我们看看我们的小草方格 实际上我们想无论如何把它们结合起来 听起来像是个很合理的技巧 我要给你们展示如何实现
假如我们在场景中有两个几何体对象 左边有一个小草方格 右边有另一个小草方格
它们都引用了同一种材料 它们的样子也一样 它们只是移动了位置 并且它们在3D空间中 有不同的地理位置 当你把这个发送给GPU时 你将会得到两个绘制调用
如果我们通过一个叫作扁平的过程 把这两个合并在一起 我们所做的其实就像是在说 让我们把网格A的全部点取出来 并把它们结合到网格B的点中 形成一个超级哥斯拉网格
它的漂亮之处在于 全部这些点都引用了那一种材料 当CPU与GPU通讯时 它要做的就只是说 “嘿 绘制这一个东西”
完成了 现在这听来微不足道 非常简单易用
你可以在你的应用中使用它 通过SCNNode上的一个 叫作flattenedClone的方法 你想做的就是确保有父节点 包含你想要扁平化的节点
并且返回的是一个新的扁平化网格 你可以在你的场景中 合成和替换其它节点
现在这个简单的技巧 在整个Learn to Code中都能使用
所以如果我们以我之前 展示给你们的示例为例 我可以具体到每一个部分 关于哪些能运行这个扁平化逻辑 我要用红色突出显示 扁平化到一起的区域 你在这里可以看到 我们的水现在…小草方格… …较少的…绘制调用 每一个红色部分相当于一个绘制调用 而不是单一的绘制调用
那么我们可以很大程度上减少 场景中绘制调用的次数
我们从550次绘制调用降到了 不到16次 降了很多
谢谢
现在你得在这里用一点儿灵活性 因为你不想全部这些乱七八糟的 你知道的 扁平化全部这些东西 原因正如Michael之前给你们展示的
他让水看起来非常逼真 通过添加那个简单的着色器修改器 为我们提供了这种非常棒的效果
那么如果我们要扁平化所有一切 整个世界大概会一点一点地消失 这并不是我们想要的
那么我们可以有选择性地 选择要扁平化的东西 那么我们把整个瀑布扁平化 在你的世界中或你创建的游戏中 你可能选择让一个对象消失或移动 或缩放或旋转或无论怎样修改它 那么我认为要选择的东西
应该基于你想如何使用你的几何体 如果它有一些动态行为 你可能想与 其它拥有同一种移动方式的东西 一起执行扁平化
那么我要给你一些关于扁平化的小技巧 其中一个是你想存储你的节点 以在同一个组中进行扁平化 父组 父节点 并不一定是同一种几何体类型 我们在这里用的是小草方格 但是… 比如你正在给客厅建模 有一张沙发 一把椅子和一张桌子 它们相对静止 它们都可以 放到一个节点组中 并由这个组自己执行扁平化 在这里你想积极一点 任何东西相对于别的东西都不会移动
扁平化它 你将显著减少你的绘制调用数量
现在这里有一个警告
Learn to Code 的世界是静止的 它是一个很小的世界 只能在屏幕上可见 但对于你的世界 可能会非常广阔 你可以进入某一栋大楼或你…
…在一个大规模的地形上 或你有好几个层级 那么你想要做的是…你不想做的是 把全部东西都乱七八糟地堆在一起 因为即将发生的是 如果你有整个世界的地图集 而场景中只能看到其中一部分 在任何时候 你都要付出一些性能方面的代价 即渲染全部这些点和全部网格 这并不是你想要的
这里有一个小技巧 就是简单地把你的世界 细分为不连续的组块
然后在每一个组块上运行这个过程 当你从一个组块移动到另一个组块时 当相机从一个组块移动到另一个组块时 你实际上获得了扁平化的优点 而不需要付出 马上在场景中渲染一切的代价
接下来我要谈谈材料 现在材料对你的绘制调用数量 甚至影响更大
我会告诉你原因的
这个帧也是来自我之前展示的那个电影 就是我们展示扁平化的场景 这个世界的顶部几乎是在一个网格中
所以这是一个绘制调用 但机警的你们可能会注意到 这里有多种材料 比如显然这些巨石阵 和台阶所用的材料不同 当然不是石头自身 那么这是怎么回事?
让我们谈谈减少材料 因为我们要降低到一个绘制调用
那么我们在屏幕上有两个几何体对象
一个在左边 一个在右边 一个用的是沙子纹理 一个用的是这种看起来 有沙子/小草的纹理
如果我们运行 我之前展示给你的逻辑 扁平化 我们实际上会把那个结合起来 哥斯拉网格 但我们仍然引用的是两种材料 那么当CPU与GPU通讯时 它会说 “嘿 获取这个网格 在上边绘制一些沙子材料” 很棒 好的 现在再次获取这个网格 在上边绘制一部分 小草材料 你仍然有两个绘制调用
你是有机会减少绘制调用的次数的
你可能听说过纹理拼合 但也许你并不理解这到底是什么 这是一个非常简单的过程
你的设计师以及3D工具
把你的材料合并到一个纹理贴图集中
它们会在底层更新你的几何体 以便它指向纹理内正确的位元 但最终结果是你有一个绘制调用
现在能实现…
…即便你有…几个对象或上千个对象
在Learn to Code中 我将给你展示其中一个贴图集 是我刚展示给你的那个世界的贴图集 贴图集就是这个样子的
我们有70多种材料 我们可以浓缩成一个
这是一种很大的节约
这里有另一个优点你可能没有注意到
当你向场景中添加一种材料时 当你的场景加载时 在场景底层生成了一个着色器 你不能启动你的场景 除非着色器已完成编译 如果你有70种材料 你就有70个着色器 你有上百个对象 上百种材料 现在冷不防想到你的加载时间… 你被卡住了 等着场景加载
通过将它合并为 一种材料或较少的材料 你减少了需要编译的着色器的数量 推进了你的启动时间
更不要提较少的I/O了 在读写硬盘方面
那么接下来我想谈谈光照
现在光照很有意思 因为…
光照允许你给你的世界增加丰富 逼真的细节 你想象一个这样的场景 看起来是静态的 有点了无生趣 你添加光照 现在看起来有点意思了 那么让我们的设计师在场景中 添加一些光照 然后给我们提供了这个视觉效果
我们添加了聚光灯 因此当角色在世界中走来走去时 当他们沿着瀑布或草地 移动时会投射影子 这是个不错的效果
我们添加了全方位光照 分散在整个场景中 增加了一点视觉效果 那么你可以看到前景中的台阶 比后景中的台阶要更高亮
最后 我们添加了环境光 以确保场景中的一切东西都是可见的 否则你将拥有非常暗的区域 是光照不能照亮的区域
你可以看到这种很棒的效果 如果你看一下水的阴影的话 非常整洁
现在这里有一点性能消耗 光照可不是免费的
记得我告诉过你的绘制调用吧 绘制调用的个数越多 你得到的性能就越少 你的应用呢? 无论何时当光照点亮网格时
都会生成一个额外绘制调用 你的场景中有五个光照 你就增加了五个绘制调用
有一种方式可以避免这种情况
叫作光照图
现在的情况是你的设计师 和他们的3D工具 将运行一个过程 计算广告所在位置 他们可以很大方地把光照 放在他们想要放的地方 点亮所有东西 那实际上会预计算 你场景中的广告强度 并把它存储在一种材料中 而不像我们之前展示给你们的纹理一样
这里的漂亮之处在于 这个过程不是CPU或GPU加强的 事实上它是免费的 让我们再花点时间谈谈它 而不是讲实际会占用多少CPU 来应用这个
那么只要我们想 我们可以把光照数量降低到零 现在我们不这样做 我们留了一个聚光灯 因为我们区分开了 不是每帧都会改变的光照 我们为什么还要再次渲染这些光照呢 我们在上一帧中就进行了渲染 但什么也没变
但聚光灯会改变 随着你旋转这个世界 聚光灯也会以不同的方式照亮对象 当你让自己的角色 在这个世界走来走去时 它的影子会以不同方式 投射在这个世界 所以我们保留了聚光灯 但我们确保指定把它应用在哪里
角色或场景的某个部分
好消息是它可以与我之前 展示给你们的扁平化一起处理 因为很明显 光照就像一个 绘制调用的倍增器 你猜怎么样 我们减少了第一项 我们减少了需要点亮的网格数量
如果我们真的想在那儿放一个光照 效果也不会比我们刚启动时差
那么在进行这些修改后
让我们看一下我们的性能 看看我们现在怎么样
让我们放大 实际上我想花点时间欣赏一下 光照图的效果 太棒了
如果你看一下第一个台阶的后面 你会看到那个小的阴影以及裂缝 还有… …甚至在瀑布后面也稍微有点暗 岩石周围和巨石阵中的弯曲区域 看起来真的很棒 你知道吗 你并没有付出任何代价 这都是通过使用材料离线实现的 我们的设计师 因为光照和3D工具而疯狂
现在我放大性能图
哇哦 我们现在达到每秒60帧了 我们的用户不会关闭我们的应用 而去做其它事了
让我们看看我们的渲染时间
是2.3毫秒 现在非常了不起 原因有很多 第一 记得我们说过 你必须得低于16毫秒… …才能…
…实现每秒渲染60帧吗? 刚发布的那个新iPad 如果你想利用120赫兹技术刷新率 你得把那个数字降到7以下 我们是2以下 所以我们很不错 启动它
那么让我们谈谈净空高度
漂亮之处是这个数字很低 如果你想给你的场景中添加更多的对象 也许你想添加更多的游戏设置逻辑 通过GameplayKit 或你想联网 或者你只想丰富你的场景 告诉你的设计师“嘿 启动它 让我们在场景中添加更多对象 让它变得更精致” 或者你只想节约电量 你可以那样做
最后让我们看看那个绘制调用的数量
哇哦 73 你还记得吧 刚才的数字超过了700 我们现在使用的绘制调用数量 比刚才的十分之一还要少 我们正在小口品尝 而不是像刚才那样狂吃 非常棒 我们的应用很流畅 当我们再提到净空高度时 你就要记得 你要在你的应用中 实现其它事而不只是渲染 在我们的例子中 我们在左侧运行了Swift编译器 用户可以编辑代码并点击菜单项 以及类似的操作
在你的应用中 也许用户正在做比如缩放 缩放或做一些选择 或…
你知道的 任何会占用更多处理时间的事情 按照你应用中的逻辑
很棒
那么回顾一下
我们讲了扁平化几何体 如何简便地实现性能优化 关于减少你的绘制调用数量
我们讲了使用纹理贴图集 就是你让你的设计师做的东西 你只需要利用即可 那将会减少你所使用的材料 从而影响加载时间 让你的应用启动更快 还会影响磁盘I/O 使加载对象减少 最后 它可以和几何体扁平化一起处理 确保尽可能少地绘制调用数量
最后使用光照图 给你的场景添加丰富的可视化细节
而不需要占用太多的GPU 让你的设计师疯狂起来吧
我们还有一些相关的演讲
谢谢 祝你们度过一个美好的WWDC -
-
正在查找特定内容?在上方输入一个主题,就能直接跳转到相应的精彩内容。
提交你查询的内容时出现错误。请检查互联网连接,然后再试一次。