0%

这是GDC2020上的一个分享,主题是“更快速地开发工具,加速工具开发的设计决策”

分享嘉宾是Niklas Gray,Our Machinery CTO

源视频地址 https://www.youtube.com/watch?v=yYq_dviv1B0

首先是分享嘉宾的自我介绍

我叫Niklas Gray,我是写游戏引擎的;参与开发的引擎如下:

  • Diesel ,游戏开发商Grin 内部用引擎,代表作有Ghost Recon(幽灵行动)和PayDay(收获日)
  • Bitsquid ,一款商业引擎,代表作有Vermintide (末日鼠疫)和Helldivers(绝地战兵)
  • Stingray ,AutoDesk在2014年收购来Bitsquid,Stingray是Bitsquid的更名版本
  • The Machinery ,Niklas从2017年开始开发的新引擎,特性是Lightweight、Flexible、Modular and extensible

本次主题分享内容

  • 为什么工具开发这么难?
  • 我们能够做些什么

工具开发失败简史

Bitsquid 1.0

  • 引擎只定义文件格式,工具完全由用户自己开发,但用户其实并不想开发工具

Bitsquid 2.0

  • 决定使用WinForms快速的开发工具
  • 但WinFroms的UI非常丑陋
  • 由于没有清晰的规划,随着时间累积项目难以维护(不过对用户来说还是很好用的)

Bitsquid 3.0

  • 决定做出改变,在排序了几个UI库后,最终选择了看起来还不错的WPF
  • 但没想到工具开发时间变长了
  • WPF和WinForms相比门槛变高,因为要了解WPF、XAML等…
  • 设想用WPF完全重写WinFroms工具,最终未能完成

Stingray

  • 希望开发平台无关的编辑器,这意味着不能使用WPF;考虑到可以购买一些Web技术和不少人有Web开发经验;最终决定开发一款Web编辑器
  • 但该技术选型的开发栈很长,涉及到C#, Lua, C++, WPF,WinForms, Chromium,Qt, JavaScript,Angular, WebSockets
  • 没想到开发工具的时间更长了
  • 基于web重写工具的设想又落空来
  • 最终结果是WinForms、WPF、Web各种工具同时存在,情况变得更加复杂

Bitsquid/Stingray 的核心问题

  • 不断更改开发框架
  • 工具开发耗时长以至于无法完成
  • 工具运行时性能差劲

结果就是:非常差的工具!

那么我们是如何做出改变的?请继续往下看。

为什么改变开发框架

  • 某种程度上,是决策错误
  • 某种程度上,是因为技术在不断变迁;继续使用过时的技术会非常痛苦

为什么工具开发会如此耗时

  • 每一个小工具都要有UI,都要经过设计、编码和测试

  • Undo, copy/paste, serialize, drag-and-drop 等特性实现起来比较耗时

  • 技术栈太长,难以理解

    • 当出现bug时,bug发生在Angular, JavaScript, WebSocket, Chromium, C#, Lua 还是C++?
    • 总之一切都很复杂
  • 工具开发只能由某些人来做,当引擎工程师想要加个功能时,因为太复杂而无法独自完成

为什么会遇到性能问题

  • 传统的web开发经验并不适用
    • 常规Web开发一般不太关心性能
    • 游戏场景通常比较复杂,编辑器开发会更复杂
  • 刚开始东西少,常规的web并没有遇到什么问题;但随着东西越来越多,很快性能就是要急需解决的问题。但这个时候已经不是通过profile找到热点、解决热点函数那么简单了。往往是需要对某个系统进行重写。
  • 过长的开发栈使得查问题变得非常困难

我们如何解决这些问题

  • 基于良好设计的数据模型,自动进行undo、redo、copy、paste
  • 简化技术栈
    • 让事情更加明显、容易理解
    • 避免更改开发框架
    • 控制好性能
  • 基于数据自动生成UI并重用UI
    • Properties, Tree, Graph 等
    • 不用再为创建UI做很多工作

新的数据模型

The Truth

  • 用统一的方式描述所有数据

  • 基于数据模型定义Undo这样的操作

  • 每一个对象都有类型和属性

    1587267799367

    注:the truth是Machinery引擎底层数据模型。here可以了解背后故事

多线程无锁访问

  • 改变数据分成两个步骤:write、commit

  • 写时复制

  • 读时不必加锁

    1587268067315

Undo

  • On Commit时,将新旧object保存在undo scope

  • On Undo时,恢复旧object

  • undo scope可以保存不同object的多次更改

    1587275528768

Prefabs/Prototypes

1587275643566

Live Collaboration

支持多人实时协作同一个工程

The Truth: Pros & Cons

优点

  • 提供了很多基础功能,如undo、redo、copy、paste
  • 甚至一些高级功能,如实时协作和原型设计

缺点

  • 有些数据并不适合用key-value format
  • 这套系统很复杂且处于中心位置
    • 没有简单的方式提供给其他系统使用
    • 修改会导致复杂度骤增

简化技术栈

我们的技术栈

  • 所有代码都用C语言编写
  • 外部依赖非常少

1587273271561

Draw 2D: 2DUI库

  • 函数:stroke_rect(), fill_rect()
  • 直接将数据写入到vertex buffer和index buffer
  • 所有UI在一个drawcall内绘制,详细介绍可参考here

Draw 2D: Clipping

  • 裁剪矩形被写入到vertex buffer
  • 实现了gpu裁剪,在PS中基于裁剪矩形做裁剪

Draw 2D: Overlays

1587277585876

UI

  • 立即模式UI,没有UI对象的创建和释放
  • 所有UI和交互处理都在一个drawcall内完成
  • 所有控件都会在每帧绘制一次
  • 控件不会被永久保存,通过ID识别不同控件

IMGUI: Pros & Cons

  • More straightforward code flow (debugging, profiling)
  • No need to synchronize state
  • Redraw every frame – expensive?
    • Viewport typically wants to render every frame anyway
    • Can do it just on mouse/keyboard events
    • Easy to match performance to what is shown on screen
  • New mindset: no objects to talk to
    • Can usually find ways around it

(接下来一部分介绍来IMGUI模式遇到的问题以及他们的解决思路,这里略去细节…)

小结

优点

  • 开发栈完全可控,更易于理解和调试
  • 所有地方都使用相同的API,这样工具程序和其他程序之间就不存在什么障碍壁垒;任何人都可以把事情做好

缺点

  • 你需要从零开始构建(大概6人月的工作量)
    • 前期投入很快就会收回
    • 你也可以直接使用Dear IMGUI
  • 需要考虑很多设计决策
  • IMGUI需要新的思维模式

UI生成

Motivation

  • 减少创建UI的工作

(Niklas给了几个参考图和一些示例代码,就不在这里罗列了,详见视频…)

结论

  • 创建UI更快了,进度不再被UI任务阻塞
  • 引擎开发由两个人在两年内完成
  • 数据模型看起来很酷但也可怕,因为没增加一项就会导致更复杂
  • Aspects 用来自定义数据行为,是一种非常棒的方式
  • 独自一人去实现这些功能是一项非常大的工作
  • 创建工具集需要很多”functional design”
  • 我们也牺牲来一些特性,如文字自右向左排列

All-in-all we’re happy with the direction .

观后感

  1. 从历史中总结经验教训,使用IMGUI提高了Niklas他们的工具开发效率
  2. The Truth数据模型在Machinery引擎处于中心位置,为工具开发提供来很多遍历功能;但同时因增加项而变得更加复杂;进而导致难以维护
  3. 视频中提到的很多历史问题,其实我们也都遇到过
  4. 要向大佬们学习,善于总结和改进
  5. IMGUI和RMGUI的争论在网上就有很多,抛开具体场景谈好坏都是耍流氓
  6. Machinery引擎还在开发中,目前刚发布了beta版本;但仅限于内测。为进一步学习和了解,两天前我发邮件申请加入内测,暂未得到回复

我们为什么能看见这个世界

光照方程是对真实世界的近似模拟,真实世界中光沿直线传播,经过物体反射和折射进入人眼,经由人眼中多种视锥细胞形成视觉信号,这些信号复合后为人呈现了色彩缤纷的世界。

光的可见性度量

术语 作用 单位
Luminous Flux(光通量) measures the total amount of power of visible light emitted from the light source(度量从光源发出的可见光) lumen
luminous intensity(光强) luminous flux per unit solid angle(单位立体角光通量) lumen/sr, or candela
illuminance(亮度) luminous flux per unit area(单位面积接收的光通量) lumen/m^2, or lux
Luminance(照度) measure of how much light can be detected by our eyes looking at a surface at a particular angle. The formal definition of luminance is luminous flux per unit solid angle per unit area.(单位面积单位立体角人眼接收到的光通量) lumen/(m^2·sr), or cd/m^2.

_config.yml图片来源

什么是gamma

vout=vingamma

首先,gamma是系数;是描述输入和输出之间关系的一个系数。可以用于描述物理世界可见光量和人脑接收到的可见光信号量之间的一个系数。在物理世界中,两倍的光量会产生两倍的亮度,也就是说呈线性关系。但人脑接收到的可见光信号量不是线性关系,而是幂次方关系。

linear vs nonlinear gamma - cameras vs human eyes

图片来源

当gamma等于1时称之为linear gamma,当gamma小于1时称之为gamma encoding或gamma compression;当gamma大于1时称之为gamma decoding。

但通常会使用大小等于2.2的gamma。为什么是2.2呢,因为这刚好是人脑接收到的可见光信号量幂次关系的逆。

img

图片来源

计算机上最早的显示器是CRT显示器,由于硬件特性两倍的电压并不能产生两个的亮度。电压与亮度关系呈2.2幂次方关系;经人眼视锥细胞识别最终形成的可见光信号量在传递给大脑后,刚好又变成了线性关系。

为什么gamma难以理解

因为生产图片、图片加载处理、观察图片这几个过程跨越了时间和空间,只有在一种约定好的方式下工作才能获得理想结果。简单来说就是工作流比较长,而这些工作流之间又有约束,这是导致gamma难以理解的原因。

从工作流看gamma

1586821388623

我们从右往左看上图:

5视觉形成

人眼中视锥细胞接收物体表面反射的光线形成信号,最终传给大脑进行解析。由于生理特性的原因视觉信号并不是线性关系。这是由人的生理特性决定的。也是我们希望呈现的结果。

4显示器显示

早期用于电脑的显示器是CRT显示器,该显示器的特性是会产生非线性的电子信号。由于CRT的衰减特性和人眼的增强特性,最终结果刚好线性的。后来的显示器保留来衰减计算,我们可通过修改现实器配置调整gamma数值。

3光照计算

光照计算是对物理世界的近似模式,光照计算也要在线性空间下进行。但因为显示器的衰减特性,要进行gamma 补偿计算。

2图片加载

因为光照计算要在线性空间进行,而图片通常是sRGB空间(非线性),所以在贴图加载完后要转到线性空间。

1图片生产

美工进行计算机绘图并保存在磁盘上,磁盘上的贴图通常是在sRGB空间;但这不是必须的,美工可以在导出图片时选择保存的格式。另一种就是用相机拍照,相机的感光元件是电子器件,对光线的处理是线性的;但为了适应整个工作流,通常是保存为非线性的sRGB。使用sRGB图片的好处是可以保存更多对我们视觉有效的信息。

小结

以前总是站在某一个特定过程去理解gamma,结果就总是似懂非懂。当从整个工作流去理解gamma后就容易多了。

参考链接

http://6degreesoffreedom.co/luminance-vs-illuminance/

https://www.cambridgeincolour.com/tutorials/gamma-correction.htm

https://learnopengl.com/Advanced-Lighting/Gamma-Correction

https://learnopengl-cn.github.io/05%20Advanced%20Lighting/02%20Gamma%20Correction/

https://zh.wikipedia.org/wiki/%E8%A7%86%E9%94%A5%E7%BB%86%E8%83%9E

与其徘徊犹豫,不如奋起直追。先相信再看见,相信“相信”的力量。

“Everything we know is only some kind of approximation.” - Richard Feynman.

Illumination(物理学范畴)

The transport of energy from light sources to surfaces & points

  • Category
    • direct vs indirect
    • empirical vs physically based
    • local vs global
  • Two components
    • light source
      • propertices
        • color
        • position
        • direction
        • shape
        • attenuation
      • light type
        • ambient light sources
        • directional light sources
        • point light sources
        • pot light rsources
        • area light sources
    • surface properties
      • color
      • position
      • orientation
      • micro-structure
Lighting(物理学范畴)

The process of computing the luminous intensity at a particular 3-D point, usually on a surface.
Interaction between materials and light sources.

Category

  • Lambert lighting
  • Phone lighting
    • empiracal ,include there components:ambient、 diffuse、specular
  • Blinn Phone
Shading(图形学范畴)

The process of assigning colors to pixels. Which determines the color of a pixel.

Category

  • Flat shading

    Calculates illumination at a single point for each polygon

  • Gouraud shading
    The normal vector at vertex V is calculated as the average of the surface normals for each polygon sharing that vertex

  • Phone shading
    linearly interpolating the surface normal across the facet, applying the Phong lighting model at every pixel

参考链接

https://web.csl.cornell.edu/courses/cs5620/lectures/05_Illumination_and_Shading.pdf

http://cs.boisestate.edu/~alark/cs464/lectures/Shading.pdf

http://web.cse.ohio-state.edu/~shen.94/581/Site/Slides_files/illumination.pdf

约定

  • 右手坐标系(摄像机看向Z轴负方向)

正交矩阵推导

Key Point

  • 将长方体变换为立方体
  • 先平移、再旋转
  • 摄像机朝向负z,在数值上f小于n

1586138514328

透视矩阵推导

Key Point

  • 先转换到正交体,再进行正交矩阵计算
  • 世界空间中的一个点在齐次坐标下有多种表示方式
  • 利用两个特殊点(x y n 1)和(0 0 f 1)

1586142539978

1586142563317

1586142599480

参考链接

https://www.bilibili.com/video/BV1X7411F744?p=4

有敬畏之心的人在解决问题时不会存有侥幸心理,而是会不断提出猜测并进行有效性验证。

没有敬畏之心的人在解决问题时往往在揭开问题真相之前就止步了,他们往往会说:“可能是这个情况,应该不会再有错”、“我觉着没问题”。

如果你提出“你是否对猜测进行来验证”;他们给出的回答通常是:“不用验证了来,肯定不会有错”、“我们这边难以复现,没有办法做进一步确认”。

有时候运气好,之后确实没有暴露出问题。但好运不会总是相伴,所以大多数结果是问题频出。只不过有时候问题解决的比较快或影响面比较小,而没有被重视。

尽快大多数人都认为做事需要敬畏之心,但这很难进行沟通和传递。对我们个人来说,更多的是要靠观察和复盘总结。

约定

  • 右手坐标系
  • 列向量

如何定位相机

定位摄像机需要3个向量

  • 相机位置 pos
  • 观察位置 target
  • 相机上向量 up

1585404714096

定义FPS相机

Position、Target、Up、Pitch、Yaw

因为不需要翻滚,所以这里没有定义Roll

如何移动相机

1
vec3 Front=Target-Position;	 	//计算相机前进方向

相机前进和后退:

1
2
Position += Front;			 //相机前进
Position -= Front; //相机后退

相机左右移动:

1
2
3
vec Right = cross(Front,v3c(0,1,0));	 //重新计算Right,因为Front会因为旋转而改变
Position += Right; //相机右移
Position -= Right; //相机左移

如何旋转相机

1585456963733

1
2
3
4
5
6
front.y = sin(pitch);
front.x = cos(pitch) * cos(yaw);
front.z = cos(pitch) * sin(yaw);
Front=normalize(front)

mat4 view = lookat(Position,Position+Front,Up);

推导LookAt

首先,明确两个matrix

  • camera transform matrix将camera当做世界中的一个物体来看,用于定位相机位置和朝向;记为 Mtm
  • view matrix,用于将world space转换到view space,记为 Mview

其中:

Mtm=MT * MR

相机作为世界中的一个物体,在确认位置和朝向时;操作的顺序是先旋转再平移;因为我们使用的列向量,所以上述记法MR在右侧。也就是说,从右到左进行计算。

下图(px,py,pz)表示相机位置,r1-r9表示3x3的旋转矩阵。

1585443958345

Mview=Mtm-1=MR-1 * MT-1=MRT * MT-1

因为旋转矩阵是正交矩阵,正交矩阵的逆等于其转置,因此

Mview=MRT * MT-1

1585444860584

1585405367107

下面我们计算right、up、forward三个向量。

1
2
3
4
5
vec3 worldup=(0.f,1.f,0.f);

vec3 forward = normalize(pos-target); //zaxis,注意forward指向z正向
vec3 right = normalize(cross(worldup,forward)); //xaxis
vec3 up = normalize(cross(forward,right)); //yaxis

由上我们求得了3个正交基向量,代入上面的公式,可得到view matrix

1
2
3
4
|	right.x		right.y		right.z		-dot(right,pos)		|
| up.x up.y up.z -dot(up,pos) |
| forward.x forward.y forward.z -dot(forward,pos) |
| 0 0 0 1 |

实现LookAtRH

1
2
3
4
5
6
7
8
9
10
11
12
13
14
mat4 LookAtRH(vec3 position,vec3 target,vec3 wolrdup)
{
vec3 forward = normalize(position-target);
vec3 right = normalize(cross(nomalize(worldup),forward));
vec3 up = normalize(forward,right);

mat4 view(1.0f);
view[0][0] = right.x; view[1][0] = right.y; view[2][0] = right.z; view[3][0] = -dot(right, position);
view[0][1] = up.x; view[1][1] = up.y; view[2][1] = up.z; view[3][1] = -dot(up, position);
view[0][2] = forward.x; view[1][2] = forward.y; view[2][2] = forward.z; view[3][2] = -dot(forward, position);
view[0][3] = 0; view[1][3] = 0; view[2][3] = 0; view[3][3] = 1;

return view;
}

春节本应是举欢庆、阖家团圆的日子;谁都没想到武汉肺炎席卷来整个大地。以下是维基上的记录:

2019-2020年新型冠状病毒肺炎事件中华人民共和国国家卫生健康委员会标准名称为新型冠状病毒感染的肺炎疫情[35],是指由2019新型冠状病毒所导致,且包括发热肺炎等症状[注 1]在内的传染病流行引发的事件。疫情最初被认为在中华人民共和国湖北省武汉市江汉区华南海鲜市场爆发[38],随后发现首宗及初期个案并非全部在此[39][40]。新型冠状病毒的传染来源尚未找到[41][注 2]传播途径及扩散程度尚不明确[43][36]世界卫生组织中国国家卫生健康委员会组织的专家相信,该病毒可以人传人[44][45],分析指潜伏期亦具传染性[46]

最早的已知病例出现于2019年12月1日[40]。首个前往医院就诊病例的症状发生于12月8日[47]。12月下旬开始出现围绕到访华南海鲜市场的大量病例,共占到最初41人中的27例,然而有13人没有接触史[47]。2019年12月30日晚间,多份由武汉市卫健委于12月30日发出、有关“不明原因肺炎”的文件在网上广传,武汉市疾控中心翌日向传媒证实文件属实,并开始向公众通报病例,指正在查证是何种肺炎[48]。2020年1月7日晚上9时,专家检测出病毒为新型冠状病毒[49]。1月13日起,泰国日本等地陆续确认来自中国大陆的输出个案[50][51]。由于邻近春节期间,大量人员已经流动至外省返乡,2020年1月中筛检试剂盒开始发放后,1月20日起,包括广东北京上海等地,中国大陆除武汉外其他地区开始大量通报有确诊病例[52][53]中国工程院院士钟南山呼吁民众戴口罩及避免前往武汉[54],时任武汉市长周先旺及中国国家卫健委亦先后呼吁民众不要进出武汉[55][56]。不过世界卫生组织表示因没有证据证明口罩能有效保护没有生病的人,故没有呼吸道症状的一般人无需戴口罩,不过可依据当地地区的文化习惯佩戴之[57]

update :

两个月过去了,国内的疫情基本上控制住来,但全球范围内在急剧扩张。疫情对各国经济和人民生活带来很大影响。

2020

新的一年,新的征程,砥砺前行,不负韶华。

本文有感于前几天和同事的一次交流。同事Y提醒我二进制资源分支这项任务要特别注意衍生资源这种类型,由于我的敏感反应;原本是善意的提醒结果成了我的辩论和两人之间的争论。

沟通是不同的行为主体,通过各种载体实现信息的双向流动,形成行为主体的感知,以达到特定目标的行为过程。

沟通包括输出者、接受者、信息、渠道等四个主要因素。沟通包含倾听和表达。

同理心是从某个人的角度来体验世界,重新创建个人观点的能力。具体来说包括3个方向:

  • 体会对方的感觉;这需要哦我们终止自己的论断,将自己的意见放在一边,同时试着去了解对方
  • 体会对方的感受
  • 真诚地关心对方的福祉,不光是和对方有一样的想法和感受,而是更进一步,真实地关系他们的福祉

和同理心相似的是3F倾听

  • Fact, 倾听事实是指不用自己的想法和固有观念对对方的话进行评判,客观地接受对方谈话中的信息,努力把握对方话语中的客观事实,不带偏见看问题
  • Feel,倾听感情是指在倾听事实的同时,通过语音、语调乃至肢体语言感知对方的感情
  • Focus,倾听意图是指把握对方真的想要什么,真正的意图是什么

如果当时我能够做到3F倾听和同理心,那结果肯定会大有不同

沟通的原则

  • 沟通可以是有目的或无目的的行为
  • 沟通是不可逆转的
  • 人不可能不沟通
  • 沟通是不可复制的
  • 沟通同时具有内容和关系两个向度

沟通的迷思

  • 沟通得越多不见得沟通得越好
  • 意思不在字眼里
  • 成功的沟通并不表示彼此了解
  • 人的反应并非只针对单一事件或特定的对象
  • 沟通不会解决所有问题