【游戏开发面经汇总】- 图形学基础篇
发布于 2021-11-24 15:29 ,所属分类:2021面试经验技巧分享
这是一篇超过一万五千字的游戏开发面试经验贴,也是这个面经系列的第二弹,图形学基础篇。本篇文章聚焦于游戏开发岗位面试当中经常考察的进阶知识——图形学,并涵盖了绝大部分游戏开发和图形开发面试中的图形学基础问题。我相信,只要掌握了这篇面经当中的知识点,在下次面试官问你图形学问题的时候,你一定可以做到心中有底、面无惧色。如果你还没有发现这篇文章的价值,也可以先收藏一下,我相信你参加过面试之后,会回来点赞的。
前言
图形学知识,对于图形开发、游戏引擎开发和技术美术岗位几乎是必考的知识点,对于客户端开发岗位来说,也是经常考察的进阶知识。不可否认,图形学的确是一个具有一定门槛、难度较高的领域,很多时候,我们面试的评价,往往也是是通过图形学的掌握程度来划分的。因此,掌握图形学基础知识,无论对于游戏开发的哪个岗位都是具有重要意义的。但同样的,图形学的知识博大精深,除了渲染之外还包括很多其他的领域,其主要方向有四个:几何、渲染、动画、物理,而在各个领域还有着进一步细分的方向,因此一篇文章要将所有图形学领域的知识涵盖在内是不太可能的,我也没有那样的能力。但是对于游戏开发来说,最大的一块就是渲染,往后的排序大概是动画约等于物理,几何次之。所以我们在面试准备中主要的也是渲染方面的知识,这篇文章也正是如此进行的,大部分知识点都是渲染相关的问题,还有一部分会涉及到一些三维数学的知识。
不过话又说回来,图形学除了渲染方向的需求,其他方面也有很大的需求量,甚至人才非常稀缺,所以无论你研究的是图形学的什么方向,只要具备一定的能力,是一定会有用武之处的。甚至对于我而言,物理模拟就是一个比渲染还更有意思的方向,我们项目的开发中,也有很多工作涉及到这一方面的,非常有意思,也很具有挑战性。所以不必担心因为不是渲染方向就找不到工作,不会的。只是无论你是哪个方向,最后的工作都是需要渲染出来,因此渲染知识多少要懂一些,否则工作内容会比较局限。
然后和之前的文章一样,我想声明我不鼓励只会背面经八股文,我这篇文章仍然会放出大量有价值的参考文献,希望读者在看我总结出来的答案之前,都先好好看看这些资料,否则面试挂了不要怪我这篇面经,不是它的错。
只是老话说得好:“临阵磨枪,不亮也光”,面经对于找工作而言其实是短时间内最有效的法宝,甚至可以在你满头大汗0offer的时候捞你一手,所以如果你连这个佛脚也不愿意抱的话,那找工作怕是走远了(大佬请无视这句话)。我在去年和今年的秋招中拿到了包括游戏引擎开发、渲染引擎开发和客户端开发在内的多个一线大厂的offer,去年秋招时投递的五家公司一面都没挂(别问我为什么是去年和今年,逃),这些面经对我来说帮助极大,也是我经历了三十多次面试之后的心血之作。所以,你可以选择相信我。
好了,话不多说,点个赞和收藏,马上开始。
一、渲染基础
1. 图形渲染管线(⭐⭐⭐)
图形渲染管线是图形学知识考察最重要的一个问题,绝对是最高频的,必须掌握。问法有很多种,比如屏幕中一个像素是怎么绘制出来的,绘制出一幅图像的具体过程等。此外还有GPU渲染管线的问法,其实就是省去CPU阶段,直接从GPU阶段开始回答就行了,是一个意思。
【Reference】:《Real Time Rendering 4th》Chapter 2;《游戏引擎架构》P404;细说图形学渲染管线.pdf (positiveczp.github.io);猴子也能看懂的渲染管线(Render Pipeline) - 知乎 (zhihu.com);渲染管线中的不可控、可配置与可控 - 知乎 (zhihu.com)
(注:第一本神书就不说了,可以去看英文原版或者等明年的中译版(译者是我们组长),第二本也是经典书籍,非常值得一看;其余这三篇文章也都写得很好,第一篇最详细,第二篇最通俗易懂,第三篇最底层,详细看完这三篇文章应该对图形渲染管线的理解就没问题了,需要注意的是这三篇文章有些地方会有些出入,遇到疑惑的地方还是以RTR4的描述为主)
1.1 什么是图形渲染管线,分为哪些阶段?(⭐⭐⭐)
图形渲染管线实际上指的是一堆原始图形数据途经一个输送管道,期间经过各种变化处理最终出现在屏幕的过程,在概念上可以将图形渲染管线分为四个阶段:应用程序阶段、几何阶段、光栅化阶段和像素处理阶段。
(1)应用程序阶段的主要任务,是识别出潜在可视的网格实例,并把它们及其材质呈交至图形硬件以供渲染。该阶段包含三大任务:可见性判断、控制着色器参数和渲染状态、提交图元至GPU硬件以供渲染。
(注:应用程序阶段在CPU端完成,后面的所有阶段都是在GPU端完成)
(2)几何阶段主要负责大部分多边形操作和顶点操作,将三维空间的数据转换为二维空间的数据,可以分为顶点着色、投影变换、裁剪和屏幕映射阶段。
(3)光栅化阶段是将图元离散化成片段的过程,其任务是找到需要绘制出的所有片段,包括三角形设定(图元装配)和三角形遍历阶段;
(4)像素处理阶段,给每一个像素正确配色,最后绘制出整幅图像,包括像素着色和合并阶段。
1.2 请详细描述图形渲染管线每个阶段的具体任务?(⭐⭐⭐)
(1)应用程序阶段,该阶段主要是在软件层面上执行的一些工作,包括空间加速算法、视锥剔除、碰撞检测、动画物理模拟等。大体逻辑是:执行视锥剔除,查询出可能需要绘制的图元并生成渲染数据,设置渲染状态和绑定各种Shader参数,调用DrawCall,进入到下一个阶段,GPU渲染管线。
(2)几何阶段,包含顶点着色、投影变换、裁剪和屏幕映射阶段。
注意,虽然在RTR4中几何阶段将顶点着色和投影变化分开了,但这两者都是在顶点着色器中完成的,为了方便理解我们可以统一称为顶点处理阶段。
a. 顶点处理阶段:这个阶段会执行顶点变换和顶点着色的工作。通过模型矩阵、观察矩阵和投影矩阵(也就是MVP矩阵)计算出顶点在裁剪空间下的位置(clip space),以便后续阶段转化为标准化设备坐标系(NDC)下的位置。也可能会计算出顶点的法线(需要有法线变换矩阵)和纹理坐标等。同时,在这个阶段也可能会进行顶点的着色计算,如平面着色 (Flat Shading)和高洛德着色 (Gouraud Shading)都是在顶点着色器中进行着色计算。因为这个阶段是完全可控制的,因此执行什么样的操作由程序员来决定。(此外,在顶点处理阶段的末尾,还有一些可选的阶段,包括曲面细分(tessellation)、几何着色(geometry shading)和流输出(stream output),此处不详细描述)
b. 裁剪阶段:对部分不在视体内部的图元进行裁剪。这部分是几乎完全由硬件控制的,因此没必要详细描述,至于为什么有了视锥剔除,到这个阶段还需要进行一次裁剪,可参考这个问题为什么在ndc归一化坐标已经包含了视锥体剔除功能的情况下 还需要视锥体裁剪?- 知乎 (zhihu.com)。简单来说就是两次裁剪的粒度不同,前者是在物体对象层面的,一般对对象的包围盒做剔除,剔除掉不在视锥体内的物体,NDC裁剪是在三角形层面做的,裁剪掉不在屏幕内的像素。
c. 屏幕映射阶段:主要目的是将之前步骤得到的坐标映射到对应的屏幕坐标系上。
(3)光栅化阶段,包含三角形设置和三角形遍历阶段。
a. 三角形设置(图元装配),计算出三角形的一些重要数据(如三条边的方程、深度值等)以供三角形遍历阶段使用,这些数据同样可用于各种着色数据的插值。
b. 三角形遍历,找到哪些像素被三角形所覆盖,并对这些像素的属性值进行插值。通过判断像素的中心采样点是否被三角形覆盖来决定该像素是否要生成片段。通过三角形三个顶点的属性数据,插值得到每个像素的属性值。此外透视校正插值也在这个阶段执行。
这两个阶段是完全硬件控制的,不可进行任何操作。
(4)像素处理阶段,包括像素着色和测试合并。
a. 像素着色,进行光照计算和阴影处理,决定屏幕像素的最终颜色。各种复杂的着色模型、光照计算都是在这个阶段完成。
b. 测试合并,包括各种测试和混合操作,如裁剪测试、透明测试、模板测试、深度测试以及色彩混合等。经过了测试合并阶段,并存到帧缓冲的像素值,才是最终呈现在屏幕上的图像。
(5)各个阶段的可控性
1.3 请描述OpenGL中由顶点数据输入到绘制出一幅图像的具体过程
(注:这个问题将图形渲染管线具体到了某一个图形API,因此涉及到了一些具体概念,但是大体上跟上面描述的图形渲染管线一致)
【Reference】:你好,三角形 - LearnOpenGL CN (learnopengl-cn.github.io)、【OpenGL】OpenGL渲染流程详解_Zok93-CSDN博客_opengl渲染
(1) vbo将数据存储到缓存中,vao绑定顶点属性关系,然后vbo将缓存数据传给vertex_shader;
(2) 在顶点着色器中进行坐标变换,由mvp矩阵将其转换到裁剪坐标系,以及顶点着色;
(3) 然后到了图元装配阶段,将顶点着色器的输出数据装配成指定图元的形状,之后还有一个可选的几何着色器阶段,将输入的点或线扩展成多边形;
(注意,这个地方的表述正是和平常的图形渲染管线不一致的地方,这里应该是将图形渲染管线中的三角形设定或者说图元组装阶段表述为图元装配阶段,然后下面的光栅化阶段就是三角形遍历阶段)
(4) 然后到裁剪和屏幕映射阶段;裁剪掉视体外的图元,将当前坐标映射到屏幕坐标;
(5) 然后进入光栅化阶段,找到哪些像素被三角形覆盖,以及进行插值计算;
(6) 然后进入到了fragment_shader,执行光照计算,进行着色;
(7) 最后进入到测试混合阶段,包括Alpha测试、模板测试、深度测试等,然后进行混合。
1.4 各种测试(缓冲)的含义,相对顺序?
(1)深度测试:我们在观察物体的时候,位于前面的物体会把后面的物体挡住,所以在渲染的时候,图形管线会先对每一个位置的像素存储一个深度值,称为深度缓冲,代表了该像素点在3D世界中离相机最近物体的深度值。于是在计算每一个物体的像素值的时候,都会将它的深度值和缓冲器当中的深度值进行比较,如果这个深度值小于缓冲器中的深度值,就更新深度缓冲和颜色缓冲的值,否则就丢弃;简单来说,就是根据物体的深度决定是否渲染。
(2)Alpha测试:像素值一般是由RGBA四个分量来表示的,其中的A是alpha,表示的是物体的不透明度。1代表完全不透明,0代表完全透明。可选的 alpha 测试可在深度测试执行前在传入片段上运行。片段的 alpha 值与参考值作某些特定的测试(如等于,大于等),如果片段未能通过测试,它将不再进行进一步的处理。alpha 测试经常用于不影响深度缓存的全透明片段的处理。简单来说,就是根据物体的透明度来决定是否渲染。
(3)模板测试:模板缓冲是用于记录所呈现图元位置的离屏缓存,如下图所示,如果使用了模板缓冲,就相当于在屏幕上有一块模板盖在上面,只有位于这个模板中的图元片段,才会被渲染出来。模板测试就是用片段指定的参考值与模板缓冲中的模板值进行比较,如果达到预设的比较结果,模板测试就通过了,然后用这个参考值更新模板缓冲中的模板值;如果没有达到预设的比较结果,就是没有通过测试,就不更新模板缓冲。简单来说,就是根据物体的位置范围决定是否渲染。
(4)裁剪测试:在裁剪测试中,允许程序员开设一个裁剪框,只有在裁剪框内的片元才会被显示出来,在裁剪框外的片元皆被剔除。裁切测试可以避免当视口比屏幕窗口小时造成的渲染浪费问题。通常情况下,我们会让视口的大小和屏幕空间一样大,此时可以不需要使用到裁切测试。但当两者大小不一样大时,我们需要用到裁切测试来避免其产生的一些问题。如下图所示:
图中的绿色方框表示视口范围,大的黑色方框表示屏幕范围,当视口小于屏幕的时候,如果不用裁剪测试,则会将视口范围外的背景白色也绘制出来,导致渲染浪费,结果也不正确。
(5)各种测试的相对顺序:裁剪->Alpha->模板->深度。
1.5 深度测试在哪个阶段,Early-Z呢,又会存在什么问题?
【Reference】:虚幻4渲染编程(Shader篇)【第十四卷:PreZ And EarlyZ In UE4】 - 知乎 (zhihu.com)
深度测试位于像素处理阶段的测试合并阶段,Early-Z是一种提前深度测试的技术,它位于光栅化阶段之后,像素处理阶段之前,目的是减少进入像素着色阶段的片段,优化性能。Early-Z会带来透明测试的冲突,例如某个片元A虽然遮挡了另一个片元B,但A却是透明的,GPU应当渲染的是片元B,这就产生了矛盾,这就是透明度测试会导致性能下降的原因(因为无法用Early-Z),但是有一种叫PreZ的技术可以解决这个问题,参考上面的链接,不再详述。
2. 辐射度量学(⭐⭐)
【Reference】GAMES101-现代计算机图形学入门-闫令琪_哔哩哔哩_bilibili时长1小时处
2.1 基本概念
(1)辐射能(Radiant Energy),符号Q,表示光穿过一个平面的光能。
(2)辐射通量(Radiant Flux(Power)),符号Φ,表示单位时间内光穿过一个截面的光能。
(3)辐射强度(Radiant Intensity),又叫光强度,符号I,表示单位立体角上的辐射通量。
(4)辐射率(Radiance),又叫光亮度,符号L,表示单位立体角、单位投影面积上的辐射通量。
(5)辐照度(Irradiance),符号E,表示单位面积上的辐射通量。
(6)辐射率和辐照度的区别:想象一个微小的平面,往每一个方向方向吸收光能,那么radiance就表示该平面沿着某一个方向上吸收到的光能,这个微小发光面吸收到的所有能量之和就是Irradiance,等于所有radiance的积分。Radiance是带有方向性的光亮度,Irradiance是不带有方向性的,各个方向上Radiance的积分之和:
2.2 BRDF (⭐⭐⭐)
【Reference】基于物理着色:BRDF - 知乎 (zhihu.com)
(1)基本概念
BRDF(Bidirectional Reflectance Distribution Function),译作双向反射分布函数,是一个用来描述物体表面如何反射光线的方程,表示了当给定一条入射光的时候,某一条特定的出射光线的性质是怎么样的。它的精确定义是出射光辐射率(Radiance)的微分和入射光辐照度(Irradiance)的微分之比。
(2)概念理解
入射光l照到物体表面上,反射光线为v,那么反射光的亮度(辐射率)和入射光的能量(辐照度)会成一个比例,而这个比例就是BDRF。可以理解为,在某一个特定的角度观看某个点时,各个方向的入射光对该点的最终光亮度产生的贡献比例,其实它就是一些零点几的小数。
(3)为什么是辐射率和辐射度微分的比值,而不是辐射率和辐射率,或者辐照度和辐照度的微分比值?
见参考资料的两种解释,比较好理解的是从数学角度来说,只有用Irradiance的微分,这个比值才会有意义,否则直接用出射光的dLo比上入射光的L,会趋于0,如果是dE,则是Li * cosθ * dw,也是趋于0,是有意义的。
2.3 渲染方程、反射方程
【Reference】:渲染方程 - 维基百科,自由的百科全书 (wikipedia.org)、渲染方程Rendering equation - 知乎 (zhihu.com)
(1)基本概念:渲染方程是一个描述光能在场景中流转的方程,它基于能量守恒定律,在理论上给出了一个完美的光能求解结果。其含义是:在某个视点看向特定的位置x,看到的出射光亮度(辐射率)Lo等于x点的自发光亮度Le(辐射率)以及该点的反射光亮度之和,可以由以下公式表示:
(2)概念理解:从某个视角看向某个特定点,光亮度等于该点自身的光亮度,加上从四面八方的入射光线照射到这一点,并且反射到该视角的光亮度之和,因为任何一条入射光线射到x点上可能都会产生视线方向的反射光线,所以需要对半球面做一个积分,而这个积分也恰好用到了BRDF的概念,也就是fr这个参数。W·n其实就是cosθ,θ是入射方向与表面法线的夹角,乘上这个系数的原因跟辐射率的概念相关(单位投影面积的辐射通量),具体不再详细解释。
(3)反射方程:其实就是除去了自发光的部分,只保留半球积分部分。
3. 基于物理的渲染(PBR) (⭐⭐⭐)
PBR是实时渲染中一个非常重要的概念,也是高频考点,尤其是BRDF的镜面反射公式,在面试中会被反复提及,应该尽量掌握。
【Reference】:【基于物理的渲染(PBR)白皮书】(一) 开篇:PBR核心知识体系总结与概览_【浅墨的游戏编程Blog】毛星云(浅墨)的专栏-CSDN博客、理论 - LearnOpenGL CN (learnopengl-cn.github.io)、猴子都能看懂的PBR - 知乎 (zhihu.com)、GAMES202-高质量实时渲染_哔哩哔哩_bilibili Lecture10-11
第一篇文章最全面详尽,也附了很多权威的参考文献,第二篇是经典教程,言简意赅,把最重要的部分都提取出来了,而且偏实践向,第三篇最通俗易懂,把难以理解的地方都进行了特别的说明。好好看完这三篇文章,PBR的基本理解应该就没问题了,最后一个闫神的课就不说了,yyds。
1.1 PBR的基本概念
基于物理的渲染(Physically Based Rendering,PBR)是指使用基于物理的原理和微平面理论建模的着色/光照模型,以及使用从现实中测量的表面参数来准确表示真实世界材质的渲染理念。PBR的范畴包括三个方面:基于物理的材质、基于物理的光照、基于物理适配的相机。
1.2 PBR的BRDF
一般使用一种被称为Cook-Torrance BRDF的模型
(1)整体公式:
(2)镜面反射部分
D(n,h)为法线分布函数(不应该译作正态分布函数),描述这么多个微平面中,有多少个微平面的法线是正确朝向的,返回一个比例,代表了镜面高光部分;
F(h,v)菲涅尔方程,表示不同的入射角,反射率不同,返回一个反射光线所占的比例(反射率),代表了菲涅尔效应部分;
G(n,v,l)几何函数,表示微平面自成阴影的属性,返回一个未被遮蔽的表面的百分比,代表了几何遮蔽部分;
分母是校正因子,作为微观几何局部空间和宏观几何局部空间变换的校正。
(注:具体公式不再列出,看参考文献)
1.3 PBR的计算和实现
PBR的光照结果通过反射方程来计算,分为两部分,一个是漫反射部分,一个是镜面反射部分,如下图公式所示:
(1)漫反射部分的系数lambert项是一个常量值,直接积分即可,通过环境立方体贴图来获取每个方向的辐射率(radiance),然后对于每个出射方向Lo的漫反射积分结果,预计算存储到一张辐照度贴图中(通过对radiance的卷积),在实时渲染时直接通过出射方向采样该辐照度贴图即可求得漫反射部分的结果:
(2)镜面反射部分
根据PBR的反射方程,除去去漫反射的部分即为镜面反射部分:
通过分割近似求和法可以将这个积分划分为两个卷积式子:
第一部分称为预滤波环境贴图,将不同粗糙度的卷积结果存在不同的Mipmap中(不同的粗糙度对应着不同的mipmap级别,处于中间程度的粗糙度可以插值),渲染时可以通过mipmap级数直接去采样对应的贴图得到积分结果;
第二部分称为BRDF部分,它可以进一步拆分为菲涅尔项有关的两部分,分别代表菲涅尔响应的比例和偏差,然后对这两项做卷积预计算,并存到一张查找贴图中(look-up texture,LUT)。渲染时可以将n·wi作为横坐标,以粗糙度roughness作为纵坐标,去LUT中采样获得该条件下的BRDF响应结果,以加快计算速度。
(3)总结:PBR计算结果的漫反射部分,通过卷积存到一张辐照度图当中,该辐照度图是一个立方体贴图,表示了每一个出射光线采样得到的漫反射积分计算结果;镜面反射部分通过分割近似求和法,划分为两个卷积式子,第一部分计算结果存到一张预滤波环境贴图中,将不同粗糙度的卷积结果存在一张Mipmap贴图中;第二部分称为BRDF部分:以n·wi作为横坐标,以粗糙度roughness作为纵坐标,就可以从查找贴图中采样获得该条件下的BRDF响应结果;
(注:PBR的原理和计算部分是一个难点,我感觉自己理解得也不是非常透彻,也没有自己从头动手实践过一次,所以希望大家还是以参考文献为主,自己进行深入理解,我后续有空也会进行钻研。)
1.4 一些具体的问题
(1)漫反射部分为什么要除以一个π?
是因为:
如果散射的光线最后都能汇集到一点的话,积分的结果就是会再乘一个π。所以分散的时候就需要除π。
(2)什么是LUT?
look-up texture,是一个查找纹理,称为BRDF积分贴图。在计算PBR的镜面反射部分时,会将它的第二部分积分结果,也就是BRDF项,进一步拆分为跟菲涅尔项有关的两部分,分别代表菲涅尔响应的比例和偏差,然后对这两项做卷积预计算,并存到这张LUT中,LUT的输入是cosθ和粗糙度,输出结果是菲涅尔响应的系数和偏差,在渲染时可以直接通过cosθ和粗糙度来采样获得BRDF的响应结果,加快计算速度。
(3)PBR的间接光照怎么计算?
其实就是IBL(基于图像的光照)技术。直接光照只考虑单一光源,或者有限个光源,直接用公式计算或者各项求和计算即可,间接光照将环境看作是有无限个光源,因此需要进行积分,就引入了IBL技术。按1.3的回答即可。
4. 光照模型
4.1 光照模型都有哪些,各自如何表示?
什么是光照模型 - 知乎 (zhihu.com)
4.2Phong光照模型和Blin-Phong光照模型的区别?(⭐)
高级光照 - LearnOpenGL CN (learnopengl-cn.github.io)
(1)Phong氏光照模型其实是经验模型,参数信息是通过经验得到的。Phong模型将物体光照分为三个部分进行计算,分别是:漫反射分量、镜面高光和环境光。其中,环境光分量是用来模拟全局光照效果的,其实就是在物体光照信息基础上叠加上一个较小的光照常量,用来表示场景中其他物体反射的间接光照。具体实现:环境分量,直接设置一个ambient分量,乘上光照颜色和物体颜色;漫反射分量,用光线到片段的向量与片段平面法线向量的点乘,乘上光的颜色和物体颜色;镜面分量,通过指数函数pow计算,有一个shininess分量,越大表示高光越尖锐,用到了视线方向和反射光线方向的点积。
(2)Blinn-Phong氏光照模型是对Phong氏光照模型的改进,Phong模型在处理高光时会出现光照不连续的情况。当光源和视点位于同一个方向时,反射光线跟观察方向可能大于90度,反射光线的分量就被消除了,所以出现高光不连续的现象。Blinn-Phong模型在处理镜面反射时不使用观察方向和反射光线的夹角来计算,而是引入了一个新的向量:半角向量(Halfway vector)。半角向量其实很简单,就是入射光线向量L和观察方向V的中间位置(角平分线)。Blinn-Phong求高光亮度的时候使用半角向量和法向量的点积来决定高光亮度。Phong是用反射光线和视线向量的点积来求高光亮度。
5. 全局光照技术(⭐)
【Reference】GAMES101-现代计算机图形学入门-闫令琪_哔哩哔哩_bilibiliLecture13-16、GAMES202-高质量实时渲染_哔哩哔哩_bilibiliLecture7-9、【《Real-Time Rendering 3rd》 提炼总结】(八) 第九章 · 全局光照:光线追踪、路径追踪与GI技术进化编年史 - 知乎 (zhihu.com)
概念:既考虑场景中来自光源的直接光照,又考虑经过场景中其他物体反射后的间接光照的一种渲染技术。即可以理解为:全局光照 = 直接光照(Direct Light) + 间接光照(Indirect Light)
5.1 光线追踪(ray tracing)
(1)基本思想:
其实光线追踪还分为传统递归式光追、分布式光追和蒙特卡洛光追等。
(2)核心算法和伪代码:
5.2 路径追踪(path tracing)
(1)提出背景
由于光追没有考虑漫反射物体的随机反射,而是直接计算着色,停止反射了。但实际上漫反射物体也会向各个方向反射光线,所以引出了路径追踪:
(2)基本思想
路径追踪的基本思想是从视点发出一条光线,光线与物体表面相交时根据表面的材质属性继续采样一个方向(选择一个随机方向),发出另一条光线,如此迭代,直到光线打到光源上(或逃逸出场景),然后用蒙特卡洛的方法,计算其贡献,作为像素的颜色值;由于单条光路的蒙特卡洛积分肯定会不准确,产生很多噪点,所以一般是单个像素发射多条光线进行路径追踪,一条路径就是视点和场景中各个物体反射交点的连线。
(3)核心算法和伪代码:
先用俄罗斯轮盘赌算法(RR),决定是否发出一条光线,若发出,则随机采样一个服从pdf分布的光线方向,发出该条光线,如果光线与光源相交,表示直接光照,直接用蒙特卡洛积分计算结果,再除以一个P_RR,如果是物体,递归地计算交点的着色结果(以目前发射的光线的反方向作为出射方向),把着色结果当作一个光源的亮度,进行蒙特卡洛积分计算,同样除以P_RR:
5.3 光子映射(Photon Mapping)
(1)特点
有偏估计,擅长做caustics(聚焦)材质的渲染和很复杂的路径
(2)基本思想
第一步先从光源随机发射很多条光线,打到diffuse物体上,存储这些光为“光子”,存储的信息包括位置、光强、入射方向等(可以使用层级空间结构kd-tree等);第二步从视点发射各条光线,直到打到diffuse物体上,计算光子的局部密度估计,(光子分布越集中,光越亮),对于任何一个着色点,取它周围最近的n个光子,计算它所占的面积,计算光子密度 n / A,用来表示光的强度;
注:这部分在GAMES101中还提到了两个方法,简单介绍一下:
(3)VCM(vertex connection and merge,顶点连接与合并)
如果双向路径追踪,两个路径的端点比较接近,在一个局部的面上。不要浪费了,在上面用光子映射的算法。结合了双向路径追踪和光子映射。
(4)IR(instant radiosity 实时辐射度) - ManyLight方法
一个光源生成很多个虚拟光源(VPL),然后直接用这些虚拟光源去计算一个片段的着色。
5.4 梅特波利斯光照传输(MLT)
(1)提出背景:路径追踪(Path Tracing)中一个核心问题就是怎样去尽可能多的采样一些贡献大的路径,而该方法可以自适应的生成贡献大的路径,简单来说它(MLT方法)会避开贡献小的路径,而在贡献大的路径附近做更多局部的探索,通过特殊的变异方法,生成一些新的路径,这些局部的路径的贡献往往也很高。与双向路径追踪相比, MLT 更加鲁棒,能处理各种复杂的场景。
(2)原理和特点:该方法使用了马尔可夫链算法(MCMC)来采样,MCMC可以根据已知的样本求得下一个样本(位于其周围的样本),它可以生成以任意函数为pdf的样本;给出一条路径,就可以得到它周围的其他路径;它是无偏的方法,比较擅长做复杂、困难的场景;但是缺点是收敛速度难以估计、不能保证每个像素有一致的收敛速度、经常会产生比较‘脏’的结果;不能用于动画。
5.5 预计算辐射率传输(PRT)
球谐光照与PRT学习笔记(一):引入 - 知乎 (zhihu.com)、GAMES202-高质量实时渲染_哔哩哔哩_bilibili Lecture6
5.6 环境遮蔽(AO)
SSAO - LearnOpenGL CN (learnopengl-cn.github.io)
(1)基本原理
环境光遮蔽(Ambient Occlusion)的原理是通过将褶皱、孔洞和非常靠近的墙面变暗的方法近似模拟出间接光照。这些区域很大程度上是被周围的几何体遮蔽的,光线会很难流失,所以这些地方看起来会更暗一些。
(2)SSAO
屏幕空间环境光遮蔽(Screen Space Ambient Occlusion)的原理是:对于屏幕空间(Screen-filled Quad)上的每一个片段,我们都会根据周边深度值计算一个遮蔽因子(Occlusion Factor)。这个遮蔽因子之后会被用来减少或者抵消片段的环境光照分量。遮蔽因子是通过采集片段周围球体/半球体核心(Kernel)的多个深度样本,并和当前片段深度值对比而得到的。高于片段深度值样本的个数就是我们想要的遮蔽因子。
5.7 实时光线追踪(Real Time Ray-Tracing, RTX)
光线追踪与实时渲染的未来 - 知乎 (zhihu.com)、实时光线追踪技术:业界发展近况与未来挑战 - 知乎 (zhihu.com)、GAMES202-高质量实时渲染_哔哩哔哩_bilibili Lecture12-13
6. 抗锯齿处理技术(⭐⭐)
【Reference】:抗锯齿 - LearnOpenGL CN (learnopengl-cn.github.io)、抗锯齿Anti-Aliasing技术综述 - 简书 (jianshu.com)、Anti-Aliasing 技术盘点 - 知乎 (zhihu.com)
6.1 锯齿产生的原因
光栅化的时候,是以像素中心点是否被三角形覆盖来决定是否生成片段,因此有些片段覆盖了采样点就生成,有些没有覆盖就不生成,最终导致了锯齿现象。
6.2 超采样抗锯齿(SSAA)
先映射到高分辨率缓存中放大,然后对每个图像像素进行采样,一般取临近2-4个像素,采样混合后,生成最终的像素再缩小还原为原来图像一样的大小
6.3 多重采样抗锯齿(MSAA)
请问FXAA、FSAA与MSAA有什么区别?效果和性能上哪个好?- 知乎 (zhihu.com)
(1)基本概念
在光栅化阶段,判断三角形是否被像素覆盖时,会计算多个采样点,然后计算一个覆盖率;在片段着色阶段,每个像素仍然只计算一次颜色值,片段以像素中央来进行计算,只是最后的结果会乘上一个覆盖率;MSAA的高效性在于,他没有每个采样点都计算一次着色,而是每个像素只计算一次着色,最后乘上一个覆盖率;
(2)MSAA的缺点,以及为什么?
延迟渲染与MSAA的那些事 - 知乎 (zhihu.com)
MSAA对延迟渲染的支持不是很好;有三个原因,一个是MSAA本质上是一种发生在光栅化阶段的技术,也就是几何阶段后,着色阶段前,这个技术需要用到场景中的几何信息,但是延迟渲染因为需要节省光照计算的原因,事先把所有信息都放在了GBuffer上,着色计算的时候已经丢失了几何信息;而且关键一点是如果强行这么做,MSAA会增加数倍的带宽性能消耗,因此一般都不会这么做。还有一个原因是是以前DX9的时代,MRT(多重渲染目标)技术不支持MSAA。
6.4 快速近似抗锯齿(FXAA)
进阶渲染系列(六)——FXAA快速近似抗锯齿(平滑像素) (qq.com)
FXAA(Fast Approximate Anti-Aliasing),快速近似抗锯齿处理,是MSAA一种高性能近似;它位于后处理阶段实现,不依赖于硬件;总体思想是:a. 找出图像中的所有边缘(通过亮度比较,G分量);b.平滑化边缘(沿着某个方向将一定范围的像素取出来加权平均)。
6.5 时域抗锯齿(TAA)
DX12渲染管线(2) - 时间性抗锯齿(TAA) - 知乎 (zhihu.com)
从时间维度上进行抗锯齿处理,使用同个像素在不同帧上的不同采样点,根据时间先后进行一个加权平均计算;但是TAA也有缺点,就是容易出现鬼影和抖动的现象;
6.6 深度学习超采样(DLSS)
DLSS 2.0 - 基于深度学习的实时渲染图像重建 - 知乎 (zhihu.com)
DLSS 2.0可以在不损失画质的情况下,通过人工智能 /深度学习,直接把游戏实时渲染的结果实现四倍超采样。
7. 阴影技术(⭐⭐)
【Reference】:游戏中的阴影(一):基础 - 知乎 (zhihu.com)、实时渲染中的软阴影技术 - 知乎 (zhihu.com)、GAMES202-高质量实时渲染_哔哩哔哩_bilibili Lecture3-4
对于静态的物体,可以使用Lightmap烘焙的方法来获取物体的影子(静态阴影),而对于动态的物体,一般采用的是Shadowmap的技术。
7.1 光照贴图(Lightmap)
静态阴影-Lightmap - 知乎 (zhihu.com)
(1)原理:从光源的方向去烘培(离线渲染)一个物体,把结果存一张贴图里,因为离线渲染的时候,如果光线和物体之间有东西被遮挡,那么物体上该点处就会存在阴影,那么在Lightmap上就是一个阴影的值(较暗的像素),然后渲染的时候直接对该物体从光照贴图里面采样即可,
(2)缺点:Lightmap只能存diffuse分量,不能存specular分量,没办法做动态阴影。
7.2阴影贴图(Shadowmap)(⭐⭐)
(1)基本原理:该技术其实是一种渲染到纹理的技术,我们得到的这张贴图一般称作阴影贴图。Shadowmap的原理非常简单,首先是从光源的位置渲染一遍场景,将得到的深度信息写入到贴图中,然后再一次正常的渲染场景,利用我们得到的shadowmap来判断哪些片段落在了阴影中。
(2)Shadowmap的常见问题:
a. 阴影抖动问题,可以通过偏移技术来解决,增加一个bias来比较片段深度,还有更好的一种方式是使用一种自适应偏移的方案,基于斜率去计算当前深度要加的偏移;
b. 阴影锯齿问题,可以使用百分比渐进过滤(Percentage Closer Filter,PCF)技术进行解决:从深度贴图中多次采样,每次采样坐标都稍有些不同,比如上下左右各取9个点进行采样(即一个九宫格),最后加权平均处理,就可以得到柔和的阴影。标准PCF算法采样点的位置比较规则,最后呈现的阴影还是会看出一块一块的Pattern(图块),可以采用一些随机的样本位置,比如Poisson Disk来改善PCF的效果
c. 采样Shadowmap的时候,需要将标准设备坐标系的坐标范围由[-1,1]修正到[0,1],否则贴图的坐标范围是[0,1],会采样错误。
7.3 百分比渐进软阴影((Percentage-Closer Soft Shadows,PCSS)
通过控制PCF的Kernel Size,就可以改变阴影的模糊半径,进而模拟出软阴影的效果,这就是PCSS算法的思路。之所以有软阴影,是因为某些区域处于光源的半影区(Penumbra),所以PCSS算法会设法估算出当前位置的半影区大小,这个大小决定了PCF算法的Kernel Size,最终呈现出一个视觉上的软阴影效果。
7.4 级联阴影贴图(Cascade Shadowmap)
Cascaded Shadow Maps(CSM)实时阴影的原理与实现 - 知乎 (zhihu.com)、CSM阴影技术讲解-腾讯游戏学堂 (qq.com)
Shadowmap对于大型场景渲染显得力不从心,很容易出现阴影抖动和锯齿边缘现象。对于室外大场景的实时阴影,可以使用CSM技术。
8. 延迟渲染(⭐⭐)
【Reference】:延迟着色法 - LearnOpenGL CN (learnopengl-cn.github.io)、延迟渲染 - 知乎 (zhihu.com)
8.1 什么是延迟渲染?G-buffer要存几张贴图?
(1)延迟渲染首先将物体的几何信息(位置、法线、颜色、镜面值)存到几何缓冲区中(即Geometric Buffer,G-Buffer)中,然后在光照处理阶段,使用G-Buffer中的纹理数据,对每个片段进行光照计算;这种渲染方法一个很大的好处就是能保证在G-Buffer中的片段和在屏幕上呈现的像素所包含的片段信息是一样的,因为深度测试已经最终将这里的片段信息作为最顶层的片段。这样保证了对于在光照处理阶段中处理的每一个像素都只处理一次。也就是说延迟渲染基本思想是,先执行深度测试,再进行着色计算,将本来在物体空间(三维空间)进行光照计算放到了屏幕空间(二维空间)进行处理。
(2)在每一帧当中G-buffer存储的信息有:位置、法线、颜色值、镜面值(所以其实有三张纹理,分别存位置、法线和颜色+镜面值(RGB+)A);如果是PBR,应该还要再存一个金属度和粗糙度贴图。
8.2 延迟渲染和正向渲染的区别,优缺点?
(1)区别:正向渲染,先执行着色计算,再执行深度测试;渲染n个物体在m个光源下的着色,复杂度为O(n*m),光源数量对计算复杂度影响大;对于正向渲染,我们通常会对一个像素运行多次片段着色器;延迟渲染,先进行深度测试,再执行着色计算;对于延迟渲染,每一个像素只会执行一次片段着色器。
(2)优点:将光源的数目和场景中物体的数目在复杂度层次上完全分开。渲染n个物体在m个光源下的着色,复杂度为O(n+m),只渲染可见的像素,节省计算量;
(3)缺点:a. 内存开销大,读写G-buffers的内存带宽用量是性能瓶颈;b. 对透明的物体的渲染存在问题(不支持混色);c. 对多重采样抗锯齿(MSAA)处理的支持不友好。
9.纹理贴图
【Reference】:纹理 - LearnOpenGL CN (learnopengl-cn.github.io)、【《Real-Time Rendering 3rd》 提炼总结】(五) 第六章 · 纹理贴图及相关技术 - 知乎 (zhihu.com)、计算机图形学七:纹理映射(Texture Mapping)及Mipmap技术 - 知乎 (zhihu.com)、
9.1 纹理技术的基本原理
简单的理解就是将一张二维图像,按照一定的映射关系,将每个像素贴合到物体表面的对应位置。纹理技术可以增加物体表面的细节。
9.2 纹理环绕和纹理过滤(采样)
(1)环绕方式:设置纹理坐标采样超出范围时,采取什么行为(重复/镜像/插值到边缘等)
(2)过滤方式:决定怎样将纹理像素映射到纹理坐标(怎样对纹理像素采样),分为临近过滤和线性过滤(采样):
9.3 mipmap的概念,如何实现
(1)提出背景:在一个场景内有很多物体,有的远有的近。远处的物体只占很少的片段(假设每个物体都有各自的纹理,且分辨率都很高的话),此时如果要从高分辨率的纹理中采样,会比较困难,因为一个很小的物体,一个像素映射到纹理上会占据很大一块,包含了很多个纹理像素,不好采样,因此引出了多级渐远纹理(mipmap)技术。
(2)原理:将纹理划分为不同大小分辨率的纹理图集,每次缩小1/2划分,根据物体的大小,来对不同级别的纹理进行采样。对远处的物体,采用低分辨率的纹理,对于近处的物体,采用高分辨率的纹理:
9.4 法线贴图(及其他各种贴图)的作用
都是为了实现一种凹凸不平的立体感,增加渲染的真实感:
10.空间加速结构&算法
【Reference】:GAMES101-现代计算机图形学入门-闫令琪_哔哩哔哩_bilibiliLecture13-14、【《Real-Time Rendering 3rd》 提炼总结】(十一) 第十四章 : 游戏开发中的渲染加速算法总结 - 知乎 (zhihu.com)
10.1 轴对齐包围盒(AABB)
把物体放在一个三个轴向对其的包围盒内(一个矩形),如果光线无法与包围盒相交,那必然也无法和包围盒里面的物体相交,这样就可以省略大量不必要的求交计算;而且光线与包围盒的求交计算与具体的物体求交相比,速度是快得很多的;使用AABB的好处,计算可以简化,很容易计算出t,只需要用轴分量计算。
10.2 均匀格子法(Uniform Grids)
在AABB里面划分小格子,然后预处理将物体包含的格子做标记;接着遍历光线上的格子,在计算光线与标记过的格子中的物体是否相交。这样可以省略对那些不包含格子的物体进行求交计算,进一步提高求交速度:
10.3 二叉树、四叉树、八叉树、KD树
照空间进行划分,将对象组织称为二叉树/四叉树/八叉树/KD树的数据结构:
10.4 层次包围盒(Bounding Volume Hierarchy, BVH)
基于对象进行划分,目前得到最广泛的应用:
使用BVH可以避免一个对象同时存在不同的包围盒/区域中,以下是根据空间划分和根据对象进行划分的算法区别:
11. 杂项
11.1 蒙特卡洛积分,重要性采样?
GAMES101-现代计算机图形学入门-闫令琪_哔哩哔哩_bilibili、镜面IBL - LearnOpenGL CN (learnopengl-cn.github.io)
(1)蒙特卡洛积分
这其实是一种以高效的离散方式对连续的积分求近似的非常直观的方法:对任何面积/体积进行积分——例如半球 Ω ——在该面积/体积内生成数量 N 的随机采样,权衡每个样本对最终结果的贡献并求和。
(2)重要性采样
a. 原理:重要性采样即通过现有的一些已知条件(分布函数),想办法集中于被积函数分布可能性较高的区域(重要的区域)进行采样,进而可高效地计算准确的估算结果的的一种策略。
b. 理解:因为概率密度函数可能不是均匀分布的概率密度函数,有些地方出现的概率高,有的地方概率低,因此应该尽可能的多采用概率密度高的区域,否则如果用均匀采样,最后的结果不准确,也造成了计算的浪费
c. 举例:在使用路径追踪(或其他计算方法)的时候,我们会随机生成一条反射光线,如果这个光线是均匀分布的话,很有可能可能许多发射出的光线最后都没有与光源相交,这样就造成了很多计算的浪费。重要性采样是说,着重去采样那些更有可能打到光源上的光线,比如更多地采样光源方向的光线:
11.2 片段(元)和像素的区别?
11.2 着色方式的区别,Flat Shading、Gouraud-shading和Phong-Shading?
平滑着色(flat-shading)是对每个三角形计算着色,三个顶点构成的三角形采用同一种颜色;高德洛着色(Gouraud-shading)是对每个顶点计算颜色,在三角形内的每个点,求线性插值后的结果(如果有镜面高光会存在失真现象);冯氏着色(phong-shading)是逐片段计算的,会在根据输入的顶线信息在光栅化阶段插值得到各个片段的信息,然后在片段着色器中利用位置、法线、纹理坐标等信息计算每个片段的光照信息(对每个片段进行光照计算)。
11.3 后处理效果有哪些,景深是什么?
(1)【《RTR3》 提炼总结】(九) 第十章 · 游戏开发中基于图像的渲染技术总结-腾讯游戏学堂 (qq.com)
2)景深:Chapter 23. Depth of Field: A Survey of Techniques | NVIDIA Developer
在光学领域,特别是摄影摄像领域,景深(Depth of field,DOF),也叫焦点范围(focus range)或有效焦距范围(effective focus),是指场景中最近和最远的物体之间出现的可接受的清晰图像的距离。换言之,景深是指相机对焦点前后相对清晰的成像范围。
10.4 伽马校正是什么?如何校正?
Gamma、Linear、sRGB 和Unity Color Space,你真懂了吗?- 知乎 (zhihu.com)(这篇文章写得极好)
(1)通俗理解:人眼对于颜色亮度变化的感受,跟屏幕显示器的发光二极管的功率不是正比的关系,因此需要做一个非线性的反运算,使得计算机中存储的颜色值的变化跟人眼的感受是一致的。
(2)如何校正:
二、三维数学
1.各种变换矩阵的作用和推导(⭐⭐⭐)
(1)基本概念
模型矩阵M(Model):将局部坐标变换到世界坐标;
观察矩阵V(View):将世界坐标转换为观察坐标,或者说,将物体的世界坐标,转换为在相机视角下的坐标;
投影矩阵P(Projection):将顶点坐标从观察空间变换到裁剪空间(clip space) ,后续操作可以将3D坐标映射到2D的标准化设备坐标系中(NDC)。
(2)推导(十分重要)
面试官特别喜欢考察View矩阵和Projection矩阵的推导,所以有空一定要自己推导一下,篇幅有限,三言两语也讲不清楚,我这里就不赘述了(Projection我当时偷懒没有推导,然后面试被问到了两次,哭)
观察矩阵:推导相机变换矩阵_Popy007(Twinsen)的专栏-CSDN博客
投影矩阵:[图形学笔记]推导投影矩阵 - 知乎 (zhihu.com)、虚幻4渲染编程(数学篇)【第三卷:投影矩阵推导】 - 知乎 (zhihu.com)
2.欧拉角、矩阵、四元数表示旋转的区别和优缺点(⭐⭐⭐)
【Reference】:《游戏引擎架构》P164
(1)欧拉角:定义了绕着三个坐标轴的旋转角,来确定刚体的旋转位置的方式,包括俯仰角pitch,偏航角yaw和滚动角roll;它的优点是比较直观,而且单个维度上的角度也比较容易插值;缺点是它不能进行任意方向的插值,而且会导致万向节死锁的问题,旋转的次序对结果也有影响
(2)矩阵:优点是不受万向节死锁的影响,可以独一无二的表达任意旋转,并且可以通过矩阵乘法来对点或矢量进行旋转变换;现在多数CPU以及所有GPU都有内置的硬件加速点积和矩阵乘法;缺点是不太直观,而且需要比较大的存储空间,也不太容易进行插值计算。
(3)四元数:四元数的好处是能够串接旋转;能把旋转直接作用于点或者矢量;而且能够进行旋转插值;另外它所占用的存储空间也比矩阵小;四元数可以解决万向节死锁的问题。
3.如何判断一个点在三角形(矩形、扇形)内(⭐⭐)
学习|判断一个点是否在三角形内 - 知乎 (zhihu.com)
(1)面积法,点划分的三个小三角形面积是否等于大三角形;
(2)叉乘法,沿逆时针方向,三角形两两顶点构成三个向量,比如AB,BC,CA,分别用这三个向量与起点和P的交点构成的向量求叉乘,如ABxAP, BCxBP, CAxCP,由右手定则,如果三个结果都是正的,说明这个点都在向量的左边;可以推导得出这个点在三角形内,否则只要有一个是负数,就说明在右手边,在三角形外了。
4. 如何判断一条光线是否与一个三角形相交
(1)先判断光线是否和三角形所在的面相交,再判断这个交点是否在三角形内,判断点是否在三角形内;
(2)用Moller Trumbore算法,简称MT算法。(光线的方程是:ray = origin + direction * t) 原理是如果一个点在三角形内,就能用重心坐标系去表示这个点;重心坐标公式,阿发别他伽马,α = 1 – β - λ;带入方程,有3个未知数(β,λ,t),由因为都是三维变量,可以得到三个等式;利用克拉默法则,线性代数的知识,就可以求解出这三个未知数;解出来,判定t是否合理,t > 0,然后α、β和λ三个系数都是非负的,就是有解,在三角形内。
5. 如何判断两个三角形是否相交
如果两个三角形相交,必定至少其中一个三角形的一条边穿过了另一个三角形的内部;把边当作光线去跟另一个三角形求交,如果三条边只要有一条边跟三角形有交点,即可判断两三角形相交,当然关键是要判断计算出来的t是否合理,是否位于边长范围之内。
6. 杂项
6.1 什么是齐次坐标,齐次坐标有什么作用?
(1)所谓齐次坐标就是为矢量或者矩阵增加一个维度,2D平面使用3维向量和三维矩阵,3D空间使用4维向量和4维矩阵;额外的坐标值是任意的,可以看作缩放或者权重。
(2)三维矩阵可以表示旋转和缩放,它们相乘的结果是正确的,但是平移变换不能加到三维矩阵中的相乘去表达,只能将矩阵相乘的结果加一个三维向量;引入齐次坐标之后会增加一个维度,变为四维矩阵,多出来的一维向量用来表示平移,那么就可以在一个矩阵中统一所有的操作:平移、旋转、缩放。
6.2 什么是副法线(切线),有什么用?
关于顶点的法线、切线、副切线 - 知乎 (zhihu.com)
副法线是法线与切线的叉乘得来,法线、切线和副法线可以定义切线空间,有了切线空间可以很方便地进行法线贴图的计算(当然也有其他的用途)。
尾记
文末还是得声明,由于个人能力有限,文章中难免有错漏和不准确之处,如有发现,还请大家批评指正。至于有一些知识点,我自己不是特别了解或者掌握得不是很扎实的话,就不乱发表言论了,直接上参考文献。因为图形学涵盖的范围实在太广了,而且可能会问得很深很偏,即便这篇面经汇总里面列了那么多的问题,我也只敢保守估计能涵盖面试中的70%-80%的问题,其它的,就靠平时积累和运气了。
唉~ 码字不易。上次在发表了第一篇面经相关的文章之后,得到了很多朋友的,也有一些同学在积极催更,我当然也比较开心。然而我平时还是得上班工作,周末可能还得学习或者打打游戏,吹吹水之类的(Doge),所以没办法花太多的时间来更新文章。而且其实这类文章还是比较消耗时间和精力的,虽然大部分内容是之前总结好的笔记,但是真正要分门别类地整理出来,并且进一步归纳总结和查证,以做到尽量准确无误,还是不容易的。而且这个过程还是挺枯燥的。因此之后的计划大概是一个月更新一篇吧,下一篇应该是面经系列的最后一篇了,是一个偏向技巧和经验的总结篇,包含简历+算法&代码+项目经验的一个大总结,也敬请大家期待~
顺便发一下第一篇面经的传送门:
【游戏开发面经汇总】- 计算机基础篇
最后还是引用那句话——“一点一滴的磨练,都是通往强者之路的基石”,工作不好找,Offer也没那么好拿,想成功,就踏踏实实的努力吧。
最后的最后送大家一个万能公式 ——收藏=offer++,点赞=offer=>ssp,喜欢=收获一天的好心情,一键三连+=收获一个完美的职业生涯开端(溜)。
小小提醒,未经许可,请勿转载。
(实名Diss【游戏蛮牛】的创始人
@崇慕
,在未经我允许的情况下两次侵权把我的文章转载到他们的gongzhong号中,难听的话就不说了,截图也不放了,怕影响大家心情。大家如果想入门游戏开发,千万别找这家机构,直接咨询我还有效些,而且还免费。)
往期精选
Unity3D游戏开发中100+效果的实现和源码大全 - 收藏起来肯定用得着
Unity3D 经验者转到 UE4 的经验
喵的Unity游戏开发之路 - 从入门到精通的学习线路和全教程
声明:发布此文是出于传递更多知识以供交流学习之目的。若有来源标注错误或侵犯了您的合法权益,请作者持权属证明与我们联系,我们将及时更正、删除,谢谢。
作者:Steven王
原文:https://zhuanlan.zhihu.com/p/430541328
More:【gongzhong号】u3dnotes
相关资源