
搜狐畅游2019校招笔试的3D引擎开发工程师渲染方向这套题放到今天看依然很有参考价值。虽然年份早了点但图形学基础、渲染管线和引擎优化这些考点底层逻辑没怎么变各家游戏公司在校招里考察的思路也大同小异。准备校招的同学或者刚入行想做渲染方向的开发者都可以拿这套题当一面镜子照一照自己的知识体系哪里还有窟窿。我结合当年参加笔试的同学反馈和这几年带新人的经验把这道题涉及的核心考点完整拆一遍。不光是给答案更重要的是讲清楚每道题背后想考察什么能力以及你该怎么准备才能稳过这类笔试。1. 题型全景渲染方向的笔试题到底在考什么1.1 卷面构成与考察能力模型搜狐畅游的笔试向来以“实”著称渲染方向的卷子一般由三块组成选择题、简答题、手写代码题。选择题大概二十道左右覆盖三维数学、图形学基础、引擎常识简答题五六道考察渲染管线和优化方案的理解深度最后一道或两道手写代码题可能是算法伪代码也可能让你补全一个Shader的关键函数。这套组合拳的逻辑很清晰选择题筛基础简答题筛理解代码题筛工程能力。很多同学栽跟头不是因为题难而是因为知识结构偏科。有的图形学原理背得滚瓜烂熟但数学底子薄弱碰到四元数插值直接懵有的代码能力不差但对GPU架构没概念优化方案写得像空中楼阁。所以准备这类笔试你要构建的是一个立体的知识网络而不是零散的考点清单。三维数学、渲染管线、光照模型、GPU体系结构、性能优化这五块缺一不可。1.2 我看到的命题趋势和应对思路从2019年到现在的校招笔试渲染方向的题目风格有一些明显变化。早年喜欢考固定管线的概念比如问纹理映射的Mipmap有几层、光照计算是在哪个阶段完成的这几年明显向PBR、延迟渲染、GPU Driven这类工程话题倾斜。但搜狐畅游这套2019年的卷子恰好处在一个承上启下的位置既有经典图形学概念的深度考察也开始涉及PBR和现代渲染架构对现在备考的同学来说参考价值反而比近两年的题更大。应对这类笔试我的建议是抓住两个锚点第一所有知识点都要能落到“GPU到底是怎么执行”这个层面上因为引擎开发工程师和纯图形学理论研究者的核心区别就在于此第二所有优化方案都要能说出“为什么有效”和“代价是什么”面试官最烦那种把Draw Call和批处理挂在嘴边却说不清原理的候选人。2. 数学基础题看似送分实际是分水岭2.1 MVP矩阵不只是背下三个矩阵的名字渲染方向的笔试题三维数学是绝对绕不开的板块而MVP矩阵变换几乎是必考。模型矩阵Model、视图矩阵View、投影矩阵Projection这三个矩阵串联起了一个物体从本地坐标到屏幕坐标的完整旅程。笔试中常见的考法是给出一个具体场景问你某个顶点经过MVP变换后的坐标是多少。这种题看似简单但很多同学会在细节上翻车。要特别注意MVP矩阵在代码里的实际应用顺序是Projection * View * Model * vertex因为列向量是从右往左依次应用的。这个顺序一旦搞反结果就完全错了。理解MVP更重要的方式是建立直觉。我习惯把它类比成拍照片的过程模型矩阵是你在安排模特怎么站、摆什么姿势这是物体自身的状态视图矩阵是你在架设相机决定镜头从哪个位置、朝哪个方向拍投影矩阵则是镜头的成像特性是广角还是长焦是透视还是正交。笔试里还有个高频变体——法线变换。很多人直接用MVP矩阵去变换法线结果光照计算全乱套。根本原因在于法线是方向向量不是位置向量它在齐次坐标下w分量为0不应该受平移影响。更关键的是当模型经历了非均匀缩放时变换后的法线必须用原变换矩阵的逆转置矩阵来变换才能保证法线依然垂直于表面。这个考点考察的是你对数学本质的理解而不只是记住一个“用逆转置矩阵”的口诀。2.2 四元数为什么引擎里几乎不用欧拉角三维旋转也是必考内容而且考得越来越细。欧拉角的万向锁问题是经典考点当三个旋转轴中的两个对齐时会丢失一个旋转自由度导致物体抖动。引擎里用四元数来避免这个问题同时还能方便地进行球面插值Slerp。笔试中常考四元数的基本运算比如两个四元数相乘怎么算、四元数怎么转旋转矩阵、Slerp和Lerp的区别是什么。我给一个容易记的类比四元数可以理解成“带旋转轴和旋转角度的复数扩展版”一个单位四元数(w, x, y, z)其实编码了“绕某个轴转多少度”这个信息。实操层面我建议你把四元数转旋转矩阵的公式手推一遍把Slerp的公式也写一遍。这样考试时即使忘了也能现场推出来。另外要记住一个关键判断四元数在插值时如果两个四元数的点积为负需要先取反再插值否则会走远路。这就是Slerp实现里的“最短路径修正”很多笔试题会在这里挖坑。2.3 坐标系和矩阵运算的细节陷阱这类题目还喜欢考察坐标系变换和矩阵乘法的细节。左手坐标系和右手坐标系的区别Direct3D和OpenGL的差异这些属于送分题但送分题拿不到分就太可惜了。我见过不少同学在“绕任意轴旋转”这类题目上卡壳。核心思路是先把任意轴变换到与坐标轴对齐完成旋转后再变换回去。这本质上是矩阵的复合R T * Rx * T^-1。如果对旋转矩阵的推导过程足够熟悉这类题就是套公式。三维数学部分我的备考建议很简单别看资料动手推。把缩放、旋转、平移的矩阵都自己写一遍把视图矩阵的LookAt推导过程写一遍把透视投影矩阵的推导也过一遍。只要你能独立推导一遍笔试题里百分之九十的数学题都难不住你。3. 渲染管线与光照模型笔试的重头戏3.1 渲染管线全流程你必须能徒手画出来渲染管线是渲染方向笔试的核心中的核心几乎每套卷子都会考。搜狐畅游这套题也不例外要求你描述渲染管线的完整流程。这道题考察的不是背诵而是你是否真的理解每个阶段在做什么、为什么需要这个阶段。完整的渲染管线大致是这样的CPU阶段把顶点数据、纹理、Shader等准备好通过Draw Call提交给GPUGPU端依次经过顶点着色器Vertex Shader、曲面细分可选、几何着色器可选、光栅化Rasterization、片元着色器Fragment Shader、逐片元操作Depth Test、Blending等最后写入帧缓冲。笔试作答时最好画出这个流程并且标注每个阶段的输入输出。顶点着色器的输入是顶点属性位置、法线、UV等输出是变换后的裁剪坐标光栅化的输入是图元三角形输出是片元片元着色器输入是插值后的顶点属性输出是颜色值。这里我要特别强调一个细节顶点着色器和片元着色器之间的数据传递是经过插值的。法线、UV、世界坐标这些从顶点着色器输出的attribute在光栅化阶段会按重心坐标插值然后再作为输入传给片元着色器。很多笔试简答题会问“为什么法线在片元着色器里看着不对”答案往往就出在这个插值环节。3.2 Phong与Blinn-Phong一字之差性能差一倍光照模型是渲染方向的必考知识点。Phong和Blinn-Phong这对“双胞胎”几乎是标配考题。首先要清楚Phong模型的计算方式漫反射用N·L高光用V·R其中R是入射光L关于法线N的反射向量。Blinn-Phong的改进在于用半角向量H代替反射向量R。H的计算是规范化(LV)的结果这样避免了一次反射向量的计算。具体优势有两个一个是性能省去了反射向量计算在很多硬件上半个周期就省下来了另一个是视觉表现Blinn-Phong的高光形状和Phong不完全一样更柔和一些也更接近真实效果。笔试中常见的问法是“Phong和Blinn-Phong的区别各有什么优缺点”这种送分题你要答出层次感计算方式区别、性能区别、适合场景区别。我建议在准备时查一下这两种模型的对比表格把关键公式和适用场景都列清楚。3.3 PBR基础从能量守恒到微表面模型2019年的卷子已经开始涉及PBR基于物理的渲染基础概念到近两年这已经是校招必考了。PBR的核心两个原则能量守恒和微表面模型。能量守恒的意思是出射光的总能量不能超过入射光的总能量。用生活类比就是“镜子只能反射你照进去的光不会无缘无故多出光来”。这个原则反映在BRDF中就是漫反射项和镜面反射项的总能量不能超过1。微表面模型则把表面想象成无数微小的镜面。每个微表面都在以特定方向反射光宏观上看到的效果是所有微表面的统计平均。这个模型被用来解释为什么有些材质看起来粗糙有些看起来光滑——粗糙度决定了微表面法线的分布方差。笔试中PBR部分的常见考点包括BRDF由哪几项组成漫反射项加镜面反射项、Cook-Torrance模型的各个项分别是什么D项是法线分布函数F项是菲涅尔项G项是几何遮蔽项、菲涅尔现象是什么掠射角时反射增强。这些概念不需要你推导复杂的数学公式但至少要能说出每个项的物理意义和大致影响。3.4 前向渲染与延迟渲染经典的架构选择题十套渲染笔试题里至少有八套会考前向渲染和延迟渲染的区别。这题考察的是全局视野看你对渲染架构有没有系统性的认知。前向渲染的思路很直观对每个物体遍历所有光源把光照计算在片元着色器里直接做。优点是实现简单、带宽占用低、支持透明物体方便缺点是光源数量一多片元着色器的计算量线性增长性能撑不住。延迟渲染的思路是“先画几何再算光照”。第一轮把位置、法线、颜色等信息写入G-Buffer第二轮只对屏幕上的每个片元做光照计算。这样光源数量和几何复杂度解耦了支持大量动态光源。缺点是G-Buffer占用显存和带宽很大对移动端不友好而且透明物体很难处理需要额外方案。笔试作答时要能把两者的流程图大致画出来并列出优缺点对比表。我常跟新人说一个记忆方法前向渲染是“边画边算”延迟渲染是“先存后算”。这个类比基本能帮你答对百分之八十的题目。4. 图形API与性能优化考察工程素养的地方4.1 Draw Call为什么昂贵从CPU到GPU的旅途搜狐畅游这类游戏公司的笔试对优化类题目特别看重因为引擎开发工程师日常干的最多的事情就是优化。Draw Call、批处理、GPU Instancing这些概念几乎是必考。Draw Call为什么昂贵很多同学只知道“Draw Call多了会卡”但说不出本质原因。核心在于CPU和GPU之间是异步协作的CPU把渲染命令填充到命令缓冲区GPU再从缓冲区取命令执行。每次Draw Call都涉及CPU提交、驱动处理、GPU解析这一整条链路。如果Draw Call太多CPU提交速度跟不上GPU消费速度GPU就会闲置等待帧率自然就掉下来了。理解了这个底层机制你就明白为什么合批Batching有用把多个小Draw Call合并成一个大Draw Call减少CPU提交次数让GPU尽量满负荷工作。笔试如果问“有哪些降低Draw Call的手段”你要能列举出静态合批、动态合批、GPU Instancing、纹理图集Texture Atlas等方案并且说明每种方案的适用条件和限制。4.2 引擎优化三板斧剔除、LOD、GPU Instancing性能优化类的简答题基本上离不开三个关键词剔除Culling、细节层次LOD、GPU Instancing。剔除的核心思想是“看不见的就不画”。视锥剔除Frustum Culling检查物体是否在相机视锥体内不在就跳过遮挡剔除Occlusion Culling检查物体是否被其他物体完全挡住被挡住了就不画。笔试会让你阐述这两个剔除策略的基本原理以及适用场景。遮挡剔除的GPU Occlusion Query是需要GPU回读结果的有延迟所以基本会用上一帧的查询结果做这一帧的剔除决策这个细节能显示你真的懂工程实现。LOD的思路是“离得远就画得简单”。同一个物体准备多套精度的网格距离相机远的时候用低精度模型近了换高精度模型。笔试常见的考点是LOD切换的评判标准距离、屏幕大小投影以及LOD切换时如何避免“跳变感”。我见过不少同学把LOD和Mipmap混为一谈不要搞混Mipmap是针对纹理的LOD两者思路一样但对象不同。GPU Instancing的思路是“同一个模型只提交一次绘制多次”。把多个相同物体的变换矩阵打包成数组一次Draw Call渲染所有实例。笔试如果问“渲染一万个相同的箱子有什么方案”GPU Instancing就是标准答案。作答时最好能说出要配合使用实例化缓冲区Instance Buffer来存储每个实例的变换信息。4.3 纹理压缩与带宽移动端渲染的隐形杀手渲染优化还有一个高频考点是纹理压缩。很多同学不理解为什么移动端不能直接用RGBA8888纹理答案就是带宽和显存。一个1024x1024的RGBA8888纹理大小是4MB如果游戏里有几百张这样的纹理光是纹理数据就把带宽吃满了。移动端常用的纹理压缩格式是ETC2、ASTC桌面平台用BC系列。笔试常见的问法是“移动端纹理压缩格式有哪些各有什么特点”。ASTC是当前移动端主流因为它的压缩率和质量可以灵活调节支持从4x4到12x12的压缩块ETC2则全面兼容OpenGL ES 3.0设备是Android平台的保底选择。优化类题目的作答策略我总结成一句话“先CPU后GPU先定位后优化”。不要一上来就堆GPU Instancing和延迟渲染这些术语先讲清楚你的性能瓶颈在哪用什么工具定位到的然后才谈优化方案。这种答题思路会极大提升面试官对你的评价。5. 手写代码题如何做到又快又稳5.1 射线与三角形求交一道高频经典题手写代码题是区分度的关键。搜狐畅游这套笔试里我记得有一道射线与三角形求交的题目这是图形学里极其经典的算法在拾取Picking、碰撞检测、光线追踪里都会用到。最常用的实现是Möller–Trumbore算法它的思路是把三角形顶点用重心坐标表示射线方程与重心坐标方程联立解出t、u、v三个参数然后判断u、v是否满足重心坐标的约束条件u 0, v 0, uv 1满足则说明射线与三角形相交。参考实现如下bool RayTriangleIntersect(const glm::vec3 origin, const glm::vec3 dir, const glm::vec3 v0, const glm::vec3 v1, const glm::vec3 v2, float t, float u, float v) { const glm::vec3 e1 v1 - v0; const glm::vec3 e2 v2 - v0; const glm::vec3 p glm::cross(dir, e2); const float det glm::dot(e1, p); // det 接近0时射线与三角形平面平行 if (std::fabs(det) 1e-8f) return false; const float inv_det 1.0f / det; const glm::vec3 s origin - v0; u glm::dot(s, p) * inv_det; if (u 0.0f || u 1.0f) return false; const glm::vec3 q glm::cross(s, e1); v glm::dot(dir, q) * inv_det; if (v 0.0f || u v 1.0f) return false; t glm::dot(e2, q) * inv_det; return t 0.0f; }笔试时不一定要求你写出完整的C代码但核心逻辑和算法思路必须清晰。这里有几个容易栽的坑一个是背面剔除Culling开关是只算正面相交还是正反面都算另一个是浮点数精度判断不能直接用det 0来判断平行要用一个很小的epsilon值。5.2 LookAt矩阵构建视图矩阵的手写版另一个高频代码题是构建LookAt矩阵。这个函数在引擎里太常用了所有相机都需要它。它实现的是“给定眼睛位置、观察目标点和向上的方向计算出视图矩阵”这个功能。参考实现如下glm::lookAt的内部原理glm::mat4 LookAtMatrix(const glm::vec3 eye, const glm::vec3 center, const glm::vec3 up) { const glm::vec3 f glm::normalize(center - eye); // 前向向量 const glm::vec3 s glm::normalize(glm::cross(f, up)); // 右向向量 const glm::vec3 u glm::cross(s, f); // 修正后的上向向量 glm::mat4 result(1.0f); result[0][0] s.x; result[1][0] s.y; result[2][0] s.z; result[0][1] u.x; result[1][1] u.y; result[2][1] u.z; result[0][2] -f.x; result[1][2] -f.y; result[2][2] -f.z; result[3][0] -glm::dot(s, eye); result[3][1] -glm::dot(u, eye); result[3][2] glm::dot(f, eye); return result; }这里最关键的细节是向上的方向向量可能和视线方向不垂直所以要先算右向向量s再用f和s叉乘出修正后的上向向量u。很多人在这一步用原始的up向量直接用结果相机是歪的。这个细节笔试时即使不写代码简答题里也可能考察。5.3 手写Shader的注意点如果笔试要求你补全Shader代码考点通常集中在顶点着色器里做坐标变换、片元着色器里做光照计算。这里我提醒几个高频注意点一是语义绑定。顶点着色器和片元着色器之间的数据传递必须绑定正确的语义比如位置用TEXCOORD0还是SV_POSITION要分清楚。二是向量归一化。计算N·L和N·V之前法线、光照方向、视线方向都要确保归一化否则光照效果会出现奇怪的斑块。三是坐标空间一致性。法线、光照方向、视线方向必须在同一个坐标空间计算不能在模型空间算光照、在切线空间取法线。这类题考察的是代码细节规范如果你能在笔试时写出带注释的关键步骤比如“这里法线变换用的是逆转置矩阵”会给阅卷人留下很好的印象。6. 失分点复盘与备考建议6.1 笔试失分Top3我见过最多的坑结合我接触过的不少校招笔试案例渲染方向考生的失分点高度集中。我用实际经验给你列一下Top3第一只摆结论不讲原因。比如回答“为什么用延迟渲染”只说“支持多光源”就结束了没有分析延迟渲染需要额外维护G-Buffer、占用带宽、难以处理透明物体这些代价。笔试阅卷人看重的正是权衡和取舍。第二知识点是散的没有串联起来。比如能背出Mipmap、LOD、遮挡剔除的定义但说不清它们都是“减少GPU工作量”这个目标下的不同手段。这种碎片化的知识在解答综合题时很吃亏。第三数学公式只会背不会推。最典型的是透视投影矩阵很多人记得里面有f和n但不知道为什么矩阵第三行的形式是这样的。只要题目换一个问法比如“近裁剪面为0时矩阵怎么变”就直接懵了。6.2 高效的备考路线三个月足够如果时间充裕我给准备渲染方向校招的同学一条三个月备考路线顺序很重要别跳第一个月死磕三维数学和渲染管线。每天抽半小时手推一个公式MVP、LookAt、透视投影、四元数旋转全部推导一遍。第二个月深入光照模型和GPU架构。把Phong、Blinn-Phong、PBR手写一遍理解延迟渲染和前向渲染的实现差异找GPU架构的资料尤其是移动端GPU的Tile-Based架构读一读。第三个月刷代码题和做小项目。射线求交、LookAt、Shader补全这些高频题反复手写同时自己动手实现一个小的软光栅化渲染器哪怕只能画个三角形对Pipeline的理解都会有质的飞跃。6.3 想拿高分别忽略这些“软实力”笔试虽然看的是分数但阅卷人也是人一些软实力会直接影响印象分。比如回答简答题时用分点作答先结论后展开逻辑清晰比如写代码时变量命名规范关键步骤加注释比如面对“你怎么优化一个场景”这种开放性题目先问清楚场景特点和目标平台再给方案。这些习惯不是临时能装出来的是平时做项目时的积累。如果你现在还在准备阶段建议刻意练习这种思考方式拿到一个需求先分解再定方案最后再动手。这种结构化思维在校招笔试里非常吃香。我个人在带新人的时候最看重的是对方能不能把一个渲染现象解释得通透。比如一个物体在阴影里显得偏蓝你能不能用环境光和散射的理论解释清楚。这种能力不是靠刷题刷出来的而是靠平时多观察、多质疑、多验证积累出来的。建议你在备考的这三个月里养成写图形学笔记的习惯每学一个概念都问自己“这能解释我在游戏里看到的哪个现象”坚持下来你会发现自己对渲染的理解会连点成线。