笔记千千万,一到面试乱如麻。临近面试,发现自己图形学忘的差不多了,赶紧掏出来复习复习。
数学基础
向量点乘、叉乘的几何意义及应用场景:
- 点乘:∣a∣∣b∣cosθ 几何意义是衡量两个向量的相似程度
- 叉乘:三维:
。表示与a、b垂直的法向量。
二维:a×b=x1y2−y1x2。表示面积
- 场景:如何判断在三角形内:1、叉乘同号2、
- 引擎用哪个?2d肯定是叉乘同号最好。3d因为算出来的重心坐标不止可以判断是否在三角形内,而且可以用于颜色插值、法线平滑、细分等等。
矩阵乘法规则、mvp矩阵各个部分的含义:
-
Model矩阵:从局部到世界空间。
-
View矩阵:从世界到观察空间(本质是相机位置+基变换的逆)。
-
Projection矩阵:从视锥体变换到裁剪空间,透视除法原理。
-
社招常见追问:为什么透视投影矩阵最后一行是
[0,0,-1,0]?为什么相机要移动场景反向?在投影矩阵乘完后,点是被拉远了还是拉近了?-
目标是把视锥体(Frustum)压缩成一个立方体(NDC,归一化设备坐标)。其中最后一行是深度,要把xy除以深度
-
看似是移动相机,其实是移动场景,因为相机在(0,0)点不动。
-
视锥体压缩成立方体时,只有近平面和远平面上的点是绝对固定的。中间所有的点,都被一股"非线性扭力"推向远方平面(因为远平面占据了 NDC 中 0, 1 的大半范围)。这导致远处的点被极度挤压在一起,而近处的点被舒展开来
-
变换次序:
四元数的优势,如何做球面线性插值(Slerp)
-
避免万向锁,旋转更平滑。
-
Slerp与Lerp+归一化的区别。
-
lerp:不归一化。先速度快,后速度慢
-
nlerp:计算后归一化(速度并不完全均匀,但够用)
-
slerp:直接计算到球面(完全匀速旋转)
-
-
欧拉角不能lerp,因为如果连续旋转可能在180位置突变为-180,所以欧拉角不能lerp。
-
那如何使用:
-
直接赋值版本:欧拉角作为起点和终点,把欧拉角起点终点转换成四元数,然后进行lerp
-
增量版本:rotate*=四元数。作为增量,以欧拉角为单位,转换成四元数是没问题的。
-
使用四元数接口,绕某轴旋转
-
如果是unity,使用Transform原生rotate接口
-
-
详细教程(只看前10分钟):万向锁?四元数?必须早点学会的技能!------虚幻引擎UE免费教程_哔哩哔哩_bilibili
渲染管线
完整描述一遍渲染管线的各个阶段(含GPU硬件流程)
-
完整管线:
-
顶点数据:读取位置、法线、UV、索引。
-
**几何阶段:**处理顶点
-
顶点着色器:计算顶点的位置和属性。
-
曲面细分:可选,增加顶点和几何细节。
-
几何着色器:可选,修改或生成图元。
-
图元装配:把顶点组成点、线、三角形。
-
裁剪与视口变换:移除视野外部分,转换到屏幕坐标。
-
-
光栅化阶段:把三角形转换成片段。
-
**EarlyZ(早期深度测试):**在片元之前丢掉确定被遮挡的片段(透明物体也写入深度缓存)
-
片元(片段)着色器:计算每个片段的颜色。阿尔法测试(手动丢掉阿尔法低于某个值的片元)
-
**裁剪测试:**检测是否在屏幕内,屏幕外的被丢弃
-
**模板测试:**可以理解为mask。mask之外的(模板缓存值为0的)被丢弃
-
**深度测试:**找到当前物体的深度,写入一个深度缓存,并比较,保存最靠前的。对于半透明,允许深度测试但是不写入深度缓存。
-
混合:最终颜色 =片元颜色 × 片元Alpha+ 背景颜色 × (1 - 片元Alpha)
-
帧缓冲区:双缓冲写入后切换
-
-
Draw Call 是什么?为什么数量多了性能差?如何优化?
-
CPU向GPU发送渲染指令的开销,包括状态设置、数据上传。
-
优化:批处理(Static/Dynamic Batching)、GPU Instancing、合批图集、SRP Batcher(URP)、使用间接绘制(Indirect Draw)。
-
什么时候会打断动态批处理:
-
顶点数大于300
-
shader、材质不同
-
shader过于复杂(具体应该是打开某个参数)、多pass
-
烘焙的光照贴图不同
-
被缩放的物体
-
透明的物体
-
带宽与纹理采样优化
- Mipmap的作用:避免摩尔纹、节省带宽(小像素采大纹理)。
- 各向异性过滤(Anisotropic Filtering)解决什么问题?
- 对远处物体,在贴图采样点距离过远,导致失真。
- 取周围6个点,然后做插值
- 纹理压缩格式(ETC2、ASTC、BC系列)的选择依据。
光照、着色、PBR(未完成)
Lambert、Phong、Blinn-Phong模型的区别与局限
- 能量不守恒,缺少菲涅尔效应,无法模拟金属/非金属差异。
PBR的Cook-Torrance微表面模型组成(D/F/G项)及其常用公式
-
D:法线分布函数(如GGX),影响高光形状。
-
G:几何遮蔽函数(Smith),修正微平面自遮挡。
-
F:菲涅尔方程(Schlick近似),体现不同观察角度的反射率。
-
追问:Disney原则的BRDF有哪些特性? 金属工作流的BaseColor/Metallic/Roughness分别控制什么?
IBL(基于图像的光照)的漫反射与镜面反射部分如何实现?
-
漫反射:辐照度图(Irradiance Map),通过对环境贴图卷积预计算。
-
镜面反射:预过滤环境贴图(不同粗糙度的Mip级)+ BRDF LUT(2D查找表,如Epic的split-sum近似)。
伽马校正与线性空间工作流
-
为什么渲染要用线性空间?纹理输入时去伽马,输出前加伽马。
-
HDR、色调映射(Tone mapping,如ACES)的角色,避免亮部过曝。
阴影技术(未完成)
Shadow Map的基本原理与常见问题
-
透视走样、阴影痤疮(Shadow Acne)、彼得潘现象(Peter Panning)。
-
解决:深度偏移(Bias)、法线偏移(Normal Offset)、提高贴图分辨率、级联阴影贴图(CSM)。
CSM(级联阴影贴图)如何划分层级,如何选择分割距离?
-
对数分割 vs 线性分割,优点与缺点。
-
更新策略:每帧哪些级联需要更新?如何平稳过渡?
PCF / PCSS 软阴影的原理
-
PCF:采样周围深度比较,获得半影过渡。
-
PCSS:根据遮挡物距离动态决定搜索范围,模拟近实远软的阴影。
除了Shadow Map,你还了解哪些阴影技术?
- 阴影体、屏幕空间阴影(Contact Shadow、SSAO/Shadow)、光线追踪阴影。
几何与后处理(未完成)
法线贴图的原理,切线空间的含义,法线图为什么偏蓝?
-
切线空间是局部坐标系(法线、切线、副法线),可将法线扰动"贴"到任意表面。
-
必须保证法线变换时使用TBN矩阵。追问:若模型非等比缩放怎么办?
延迟渲染 vs 前向渲染的优缺点,适合什么场景?
-
延迟渲染:处理大量动态光照效率高,但带宽开销大、MSAA困难、不支持半透明(需额外前向Pass)。
-
前向+:集群向前渲染(Clustered Forward),利用计算着色器优化光源裁剪。
SSAO(屏幕空间环境光遮蔽)的基本思路
-
通过深度缓冲和随机采样,估计屏幕空间中各点的遮挡程度。
-
HBAO、GTAO等改进方向:降噪、更真实的半球积分。
Bloom、运动模糊、景深的后处理实现要点
-
Bloom:亮度提取→多级降采样高斯模糊→与原图叠加。
-
运动模糊:利用速度缓冲(Velocity Buffer)做像素方向模糊。
-
景深:基于CoC(弥散圆)做散景模糊,注意前景/背景分离。
性能优化与图形API(未完成)
如何使用RenderDoc或GPU Profiler分析渲染瓶颈?
-
区分CPU Bound / GPU Bound / Bandwidth Bound。
-
常见优化手段:减少Overdraw(如提前渲染天空盒或不透明几何体从前到后排序)、减少SetPass Call、纹理压缩、顶点优化。
有哪些常见的Overdraw场景及优化方式?
-
大量透明物体叠加、UI层叠、粒子特效。
-
减少半透明面积、使用Occlusion Culling、LOD。
对象池与内存管理在图形引擎中的意义
- 避免频繁创建销毁VBO/贴图/Particle System,重用资源,减少内存碎片。
Vulkan / DX12 的设计理念,相比OpenGL/DX11的核心变化
-
显式控制:内存分配、同步(Fence/Semaphore)、命令缓冲提交由应用负责。
-
多线程录制命令、Pipeline State Object、Descriptor Set等概念,提升并行度和降低驱动开销。
