81.总结
81.1 核心要点速览
渲染路径是什么
渲染路径回答的是:引擎在本帧如何调度光源、阴影 Pass、以及延迟/前向各阶段读写哪些 RT。它在 Project Settings 与相机上配置,优先级高于单个材质里的「自我感觉」——材质不能单独换一条管线。
LightMode 是 Pass 上的标签,用来声明「这一段要插在引擎哪条调度链里」。当前工程启用的渲染路径只会执行与之匹配的 Pass;不匹配时,该 Pass 可能完全不参与光照,表现就像 Shader 写错,实际是 Pass 没被调度。
- 全局 / 相机:
Edit → Project Settings → Graphics设默认路径;相机组件可覆盖,便于主场景与 UI、小地图分轨。 - 迁移或合并工程时:先列出目标路径会调用的
LightMode清单,再改自定义 Shader 的 Pass 标签与Fallback,避免合并后大面积「灯不亮」。
前向渲染 Forward
前向的大致数据流是:光栅化阶段把几何属性插值进片元,光照在片元阶段按光源贡献累加。多光源时,引擎通常用 多 Pass 或多次叠加 实现,而不是在单个片元里对「所有灯」写一个巨型循环——那样寄存器与分支压力都难看。成本上记住一句:灯越多、被照亮的像素越多,前向越容易在片元侧堆工作量。
Built-in 常见拆分:
ForwardBase:环境、主定向光、Lightmap、球谐间接等 基底 多在这里一次算清,给后续 Pass 一个合理的起点颜色。ForwardAdd:对 附加逐像素光源 用Blend One One叠加上去;每多一盏附加光,往往就多一次绘制或一轮叠加。
UNITY_LIGHTMODEL_*、LightingXXX 等符号与当前路径下的 uniform、宏绑定;版本升级后名字可能微调,以 Lighting.cginc 为准 比死记字符串可靠。
顶点照明 Vertex Lit
光照在 顶点着色器 算完,结果经插值进入片元,片元一般不再做完整逐像素光照。顶点数量远小于片元时省算力,但高光、明暗边界会沿三角形边缘拉开,马赫带、三角感 比逐片元前向明显。适合作为对照理解「为什么老设备爱用、现在主流程很少选」。
延迟渲染 Deferred
第一阶段:几何 Pass 把表面参数编码进 G-buffer(多张 RT)。第二阶段:屏幕空间光照 读 G-buffer,对每个光源在屏幕分辨率上累加贡献。灯多时,成本主要由 屏幕分辨率 × 光源数量 驱动,往往比前向「每个物体多画几遍」更容易预算。
代价是 G-buffer 通道与带宽有限:透明物体、MSAA、复杂材质需要的额外数据常常放不下,需要前向 Pass 回退、拆材质或砍特性。延迟路径下 内置变量集合、Include、LightMode 与前向不同,不能照搬前向 Shader 直接跑。
三种路径对照
| 维度 | 前向 Forward | 顶点照明 Vertex Lit | 延迟 Deferred |
|---|---|---|---|
| 计算主战场 | 多在片元;多光源常多 Pass / 多趟 | 顶点为主,片元吃插值 | 屏幕空间光照;多点光时常更划算 |
| 画质倾向 | 逐像素光照好做 | 粗、易见三角感 | 受 G-buffer 精度与带宽限制 |
| 常见取舍 | 灯不太多、透明和 MSAA 要好商量时 | 极省、老机或演示 | 灯多、大面积不透明静态 |
抓三张牌即可:前向怕多灯叠片元;顶点照明省算力换画质;延迟怕透明与 G-buffer 装不下。
多种光源与 Forward 分工
Built-in 用 ForwardBase / ForwardAdd 分工 加 #pragma multi_compile_* 变体,在 编译期 展开点光、聚光、平行光等组合,把 AutoLight.cginc 里需要的 attenuation、Cookie、方向向量绑到正确的 uniform 上,避免运行时一条 if 链扫所有灯型。
- 基底与附加:
ForwardBase铺环境、主光等;ForwardAdd用加法混合叠附加光,职责清晰,变体也好查。 - 变体指令:
multi_compile_fwdbase、multi_compile_fwdadd与POINT/SPOT/USING_DIRECTIONAL_LIGHT等分支配套使用。 - 方向:平行光常用
_WorldSpaceLightPos0.xyz;点光、聚光用世界空间光位置 − 表面点。 - 点光衰减:
unity_WorldToLight得到lightCoord,dot(lightCoord, lightCoord).xx作纹理坐标采_LightTexture0,UNITY_ATTEN_CHANNEL取通道;部分配置下距离衰减在_LightTextureB0。 - 聚光:
lightCoord常为float4,用分量判断是否在锥体内;_LightTexture0常管 Cookie / 角度衰减,_LightTextureB0常管距离衰减。
阴影:投射、接收与衰减合一
阴影分两条链路:投射(ShadowCaster) 从光源视角写深度到 shadow map;接收 在算光照时把像素深度与 map 比较得到可见性因子。SHADOW_*、UNITY_LIGHT_ATTENUATION 封装了 PCF、级联等细节,但调试时仍要分清 哪个 Pass 写深度、哪个 Pass 读阴影。
投射与 Fallback
- 没有
LightMode = ShadowCaster时,物体不会向光源阴影图贡献几何深度;可用Fallback指向内置带 ShadowCaster 的 Shader,减少重复实现。 - 手写投射模板:
#pragma multi_compile_shadowcaster、V2F_SHADOW_CASTER、TRANSFER_SHADOW_CASTER_NORMALOFFSET、SHADOW_CASTER_FRAGMENT;该 Pass 只输出深度相关,不要混入完整光照。
接收(前向)
#include "AutoLight.cginc",配合SHADOW_COORDS、TRANSFER_SHADOW、SHADOW_ATTENUATION。- 宏默认约定:appdata 顶点字段名为
vertex,v2f 中裁剪空间为pos。改名后宏展开对不上,编译或软阴影阶段容易出错。
衰减、附加光与特殊材质
UNITY_LIGHT_ATTENUATION把 距离衰减 × 阴影 合成一个因子,再乘到漫反射、高光等项。ForwardAdd若需要附加光也产生阴影,需multi_compile_fwdadd_fullshadows等变体,否则常见现象是 有衰减、无阴影。- Alpha Test:主 Pass
clip的位置须与 ShadowCaster 一致;Fallback 的 Cutout Shader 属性名(如_Cutoff)要对齐。单面网格从光背面不可见时,投射可能断裂,可将Cast Shadows设为 Two Sided。 - Alpha Blend:关闭
ZWrite的半透明与「用深度写阴影图」的假设冲突;实时真透明阴影成本高,用不透明 Fallback 投射阴影属于 工程上可接受的近似。
标准漫反射与标准高光
「标准」在这里指:法线贴图 + 世界空间光照 已经具备的前提下,把 ForwardBase / ForwardAdd、阴影宏、UNITY_LIGHT_ATTENUATION、附加光按 Built-in 约定接全,得到可维护的默认模板(漫反射去掉高光项;高光保留 Blinn-Phong 一类镜面项)。
- Queue / RenderType:不透明物体常用
Queue=Geometry、RenderType=Opaque,便于替换材质、深度预通道、依赖 RenderType 的后处理按预期工作。 - Fallback:
Fallback "Diffuse"、"Specular"让引擎在查找ShadowCaster等子 Pass 时走成熟路径,减少「有主 Pass、无投射阴影」的遗漏。
立方体纹理与环境映射
Cubemap 把六张 2D 贴图贴在立方体六面,采样时用 单位方向向量 选中对应面与 UV,适合天空盒、环境反射和粗粒度折射(精细折射往往还要屏幕空间或光线步进,这里不展开)。
- 接缝:六面
Wrap Mode用Clamp可减轻面与面交界处的重复采样感。 - 动态:
Camera.RenderToCubemap把场景渲染进 Cubemap;分辨率、是否Readable、与 CPU 读回的同步都要按用途权衡。 - 反射:世界空间反射方向
texCUBE,与漫反射lerp混合是常见写法。 - 折射:
refract(入射方向, 法线, ηA/ηB),片元里常只保留 折射率比值 一个常数。 - 菲涅尔:Schlick 形式
R0 + (1-R0) * pow(1 - dot(V,N), 5),掠射时反射增强;再与漫反射或环境项混合。 - 与直接光的关系:Cubemap 是 环境/反射项,仍应叠加
ForwardBase/ForwardAdd与阴影后的直接光,否则暗部会像自发光。
渲染纹理与镜面、玻璃
Render Texture:相机输出写到纹理而非直接上屏,材质再采样,用于镜子、监视器、扭曲等。与 GrabPass(Pass 内抓取当前颜色缓冲)、**OnRenderImage**(整帧后再处理)是不同入口,共同点都是 先有一份颜色/深度再二次采样。
- 镜子:额外相机渲染「镜像视角」到 RT,主材质按镜像 UV 采样;UV 常做水平翻转
1 - uv.x。若镜子本体不投射复杂阴影,有时Fallback "Diffuse"借内置 ShadowCaster,接收仍按项目需求接。 - Grab 与顺序:玻璃要在 身后场景已画入颜色缓冲 之后再 Grab,故
Queue常设为Transparent一类偏后顺序;RenderType仍可保持Opaque便于替换,以项目约定为准。 - 屏幕 UV:
ComputeGrabScreenPos(clipPos)得齐次坐标,片元中xy / w映射到屏幕 UV,再按法线偏移xy模拟折射。 - Custom Render Texture:
Initialization/Update Mode控制何时更新;Double Buffered缓解同一帧读写同一张 RT 的竞争。与「镜面多相机」解决的是不同层面的问题。
程序纹理、程序材质与 Shader 动态
程序纹理:颜色由算法生成,不依赖预烘焙大图,参数化、平铺规则纹理都方便。
- C# 路径:
Texture2D+SetPixel/Apply适合离线或低频更新,再赋给_MainTex。 - Shader 路径:
floor划分格子、奇偶判定、lerp两色,典型如棋盘格。 - 材质工作流:Substance、Houdini 等离线生成多通道贴图,与运行时片元里算纹是 两条生产线;
.sbsar进 Unity 常依赖对应插件。
**Renderer.material 与 sharedMaterial**:前者访问会 实例化 材质,只影响该物体;后者改资源,同引用物体一起变。批量物体改参数前先想清楚要哪一种。
动态效果与时间驱动
动画本质:每帧更新 顶点、UV、颜色或透明度之一。约 24 FPS 以上人眼会感知为连续运动;与游戏逻辑对齐时,除 _Time 外还要考虑 Time.deltaTime、固定步长等。
- **
_Time/_SinTime/_CosTime**:内置时间标量与预计算三角函数,适合滚动、摇摆等。 - **
unity_DeltaTime**:帧间隔与平滑帧间隔,需要与物理或 UI 同步的位移、速度常用它。 - 序列帧:大图集行列分格,时间取模选帧,UV 缩放到单格;透明物体注意
Queue与混合。 - 滚动 UV:
uv + speed * t后frac回卷到[0,1),做无缝平铺。 - 河流类顶点动画:模型空间正弦位移 + 可选 UV 流动;常
DisableBatching=True,否则批处理破坏物体空间语义。
顶点动画:广告牌、批处理与阴影一致
Billboard:在模型空间用 相机方向 重建正交基 right / up / normal,把顶点摆到始终面向屏幕。normal 常取「相机位置 − 物体中心」在模型空间的方向;_VerticalBillboarding 缩放法线 Y 分量:偏 0 时像立在地面上的牌,偏 1 时完全朝向相机。通常 **透明队列、Cull Off、DisableBatching=True**。
批处理与物体空间:动态/静态批处理合并网格或统一矩阵后,每个物体独立的模型空间 失效,object space 里写的正弦波会整错。要么关闭批处理,要么把 未变形前的模型空间坐标 烘焙进第二套 UV 或顶点色,在 Shader 用 appdata_full 读回。
与阴影一致:主 Pass 位移了顶点,Fallback 的 ShadowCaster 仍用原始网格 时,阴影会留在脚下。应在自定义 ShadowCaster Pass 中 复用同一套顶点变换,再调用 TRANSFER_SHADOW_CASTER_NORMALOFFSET 等写入阴影图。
屏幕后期效果
场景先渲染到颜色缓冲,再 全屏三角形 采样该缓冲做二次处理(调色、模糊、描边)。Built-in 典型写法:MonoBehaviour 上 OnRenderImage,内部用 Graphics.Blit 串联多 Pass 材质。
OnRenderImage、材质与 Sobel
- 契约:
OnRenderImage(source, dest)必须向dest写入,否则输出为黑。[ImageEffectOpaque]仅约束调用顺序在 不透明物体之后;source是否含透明内容仍取决于当前管线与相机设置,排障时用 Frame Debugger 核对实际 Pass 顺序。 - Blit:
Graphics.Blit(source, dest, material, pass)将source绑定为材质的_MainTex并执行指定 Pass,是串联多 Pass 后处理的主轴。 - 运行时材质:
new Material常设HideFlags.DontSave,避免运行期生成的材质写进场景资产。 - 亮度 / 饱和度 / 对比度:亮度缩放 RGB;饱和度用 Rec.709 亮度
L = 0.2126R + 0.7152G + 0.0722B与lerp;对比度向0.5拉。全屏 Pass 常用ZTest Always、Cull Off、ZWrite Off。 - Sobel:3×3 邻域灰度与 Sobel 核得
Gx、Gy,|Gx|+|Gy|作边缘强度;步长用_MainTex_TexelSize对齐像素。
纯色底、高斯、Bloom、累积模糊
- 描边 + 底色:
_BackgroundExtent、_BackgroundColor在原图与「纯色底 + 描边」之间插值。 - 可分高斯:二维核拆成水平、垂直各一次一维卷积;5-tap 权重常用
0.0545 / 0.2442 / 0.4026。公共结构体与函数放在CGINCLUDE…ENDCG,供多 Pass 共用。 - 加重模糊:降低临时 RT 分辨率、多轮
Blit、或增大 UV 偏移步长,可组合使用。 - Bloom:阈值提取亮区 → 高斯模糊 → 与原始场景相加;增益过高会导致整屏灰雾。
- 累积运动模糊:一 Pass 混合当前帧与历史 RGB;另一 Pass 将权重写入 Alpha 供下一帧使用,此处 Alpha 作历史权重容器,与透明度语义不同。
深度与法线纹理
深度纹理表示 从相机沿视线到该像素遮挡面的距离(经 Unity 线性化与宏封装后使用),雾效、屏幕空间运动模糊、几何边缘检测、部分水面交互都依赖它。
获取与解码
- 开启:
Camera.depthTextureMode包含Depth或DepthNormals,每多一种模式通常多一份 填充与带宽。 - 仅深度:
_CameraDepthTexture配合SAMPLE_DEPTH_TEXTURE、LinearEyeDepth(视空间 Z)、Linear01Depth(归一化线性深度)。 - 深度 + 法线:
_CameraDepthNormalsTexture经DecodeDepthNormal,或拆成DecodeFloatRG与DecodeViewNormalStereo;编码细节随 Unity 版本与平台宏变化,以当前UnityCG.cginc等为准。
雾与基于深度的屏幕效果
- 自定义雾:由深度还原世界坐标
worldPos = _WorldSpaceCameraPos + depth * rayDir,rayDir由相机视锥四角射线在片元插值;C# 一次传入射线向量矩阵较省事。雾因子可用线性、指数、平方指数等,再lerp场景色与雾色。 - 内置雾:物体 Shader 中
#pragma multi_compile_fog与UNITY_FOG_*在顶点/片元插值雾色。 - 屏幕空间运动模糊:当前帧用裁剪坐标与深度还原世界位置,乘 上一帧视图投影矩阵 得到上一帧屏幕坐标,与当前帧坐标差为 屏幕空间速度,沿该方向多采样颜色缓冲。
material.SetMatrix传入历史矩阵;若启用 TAA、动态分辨率或抖动投影,须保证 矩阵与source纹理分辨率、抖动 一致,否则拖影错位。
几何边缘(深度 + 法线)
仅对 颜色 做 Sobel 时,贴图自身的明暗对比也会被当成边缘。对 深度 与 观察空间法线 做 Roberts 等对角差分,更容易突出 几何不连续(深度突变、法线转折)。阈值需与 深度尺度 一致,常做归一化或按近远平面缩放,否则近处全边、远处无边。
81.2 面试题精选
基础题
1. Shader 里 LightMode 是干什么的?
题目
Pass 里写的 LightMode 和 Project 里选的渲染路径是什么关系?
深入解析
- LightMode 声明该 Pass 参与哪条渲染路径、哪一光照阶段。
- 工程 当前渲染路径 决定引擎会调度哪些 Pass;不匹配时该 Pass 可能根本不跑或不起光照作用。
- 前向里常见 ForwardBase / ForwardAdd;延迟里常见 Deferred 等,具体枚举以当前 Unity 版本文档为准。
答题示例
LightMode 告诉引擎这个 Pass 属于哪条路径的哪一步;和项目渲染路径对不上就不会按你想的参与光照。
参考文章
- 1.渲染路径-渲染路径概述
2. 前向渲染里 ForwardBase 和 ForwardAdd 大致各干什么?
题目
多光源时为什么常常要两个 Pass?
深入解析
- ForwardBase:一般算 环境/主光基底、Lightmap、球谐间接 等,先铺好「底色」。
- ForwardAdd:对 附加逐像素光源 做 加法混合,每多一类附加光可能多一轮开销。
- 这是 Built-in 前向的经典拆分,URP/HDRP 机制不同,面试若限定 Unity 版本要说清。
答题示例
Base 先算主光和环境等底色,Add 再叠附加光,多光就多次叠加。
参考文章
- 2.渲染路径-前向渲染路径
3. ForwardAdd 里为什么常见 Blend One One?
题目
它和基底 Pass 的颜色怎么叠在一起?
深入解析
- 加法混合把本 Pass 算出的 附加光贡献 直接累进已有颜色缓冲。
- 环境光、主光基底已在
ForwardBase算过,**ForwardAdd** 不应再重复环境项。
答题示例
Add Pass 用 One One 把每一盏附加光的结果加到 framebuffer 上,和 Base 里已经铺好的底色相加。
参考文章
- 8.多种光源-光照衰减
- 11.多种光源-综合实现
4. 点光源在附加 Pass 里怎么用纹理算衰减?
题目
unity_WorldToLight、_LightTexture0 大致干什么?
深入解析
- 先把顶点 变到光源空间 得 **
lightCoord**。 - 用
dot(lightCoord, lightCoord).xx把 距离平方 映射到衰减纹理坐标,采 **_LightTexture0**(或配置下配合 **_LightTextureB0**),取 **UNITY_ATTEN_CHANNEL**。
答题示例
顶点乘 WorldToLight 得到光源空间坐标,用距离平方去采光照衰减纹理得到 atten。
参考文章
- 8.多种光源-光照衰减
- 9.多种光源-点光源光照衰减计算
5. 没有 ShadowCaster Pass 时,物体为什么可能既不投影也不易接好阴影?
题目
Fallback 能补哪一块?
深入解析
- 投影依赖把深度写入光源视角的阴影图;无 ShadowCaster 则本 Shader 不参与该 Pass,除非 Fallback 链上有带 ShadowCaster 的内置 Shader。
- 接收还要在光照 Pass 里对阴影图采样并乘到光照上,与是否 Fallback 无投影是两件事。
答题示例
投影必须走 ShadowCaster 写深度图,没有就自己写或靠 Fallback 借内置的;接收阴影是另一套采样和衰减计算。
参考文章
- 15.阴影-不透明物体阴影-让不透明物体投射阴影
6. 镜面材质里对 UV 做 1 - uv.x 一般在解决什么?
题目
和相机渲染到 RT 的关系?
深入解析
- 相机看到的是 真实世界侧 画面,贴到镜子模型上需要 左右对调 才像反射。
- 在 顶点或片元 改 UV 比改 RT 渲染目标更轻。
答题示例
把采样到的镜子图在横向上翻一下,看起来才像镜面左右对调。
参考文章
- 36.高级纹理-渲染纹理-镜面效果-效果实现
7. 程序纹理用 C# 生成和全在 Shader 里算各有什么取舍?
题目
棋盘格例子说明数据在哪更新。
深入解析
- **C#**:CPU 写像素,适合 编辑器工具、低频更新、要与 Inspector 交互;注意 Apply 与 内存。
- Shader:每像素数学算色,无大贴图资产、参数可调;依赖 GPU 并行。
答题示例
C# 适合算好一张图丢给材质;Shader 适合每帧每像素现算图案。
参考文章
- 41.高级纹理-程序纹理-程序纹理是什么
- 42.高级纹理-程序纹理-基础实现-CSharp代码动态生成程序纹理
- 43.高级纹理-程序纹理-基础实现-Shader代码动态生成程序纹理
8. 顶点动画 Shader 里为什么要写 DisableBatching?
题目
批处理合并后丢了什么信息?
深入解析
- 批处理把多物体 合成更少 DrawCall,顶点可能进入 统一空间 或 合并网格,逐物体模型空间坐标 不再独立。
- 依赖 object space 算 sin 波、广告牌基向量时会 乱套。
答题示例
合批后各模型自己的模型空间混了,顶点动画按模型空间算就会错,所以要关批或把原始坐标烘焙到色/UV。
参考文章
- 49.动态效果-顶点动画-滚动的2D河流-具体实现
- 52.动态效果-顶点动画-顶点动画的注意事项-批处理
9. Renderer.material 和 sharedMaterial 改参数时影响范围差在哪?
题目
什么时候会实例化新材质?
深入解析
- **
material**:首次访问常 克隆 一份实例,只影响该 Renderer。 - **
sharedMaterial**:改的是 资源引用,同材质的物体 一起变。
答题示例
material 是拷一份自己改;sharedMaterial 一改全场景共用那份的都变。
参考文章
- 55.屏幕后期处理效果-CSharp代码修改材质参数
10. CGINCLUDE 和写在单个 Pass 里的 CGPROGRAM 有啥分工?
题目
高斯模糊为什么常用它?
深入解析
CGINCLUDE在 SubShader 内、Pass 外,放 多 Pass 共用的函数、宏、结构体。- 可分高斯 水平/垂直两 Pass 片元逻辑几乎相同,只改 UV 偏移方向,适合抽一层避免复制粘贴。
答题示例
CGINCLUDE 给多个 Pass 共享一份 CG 代码;高斯模糊两个方向 Pass 共用同一套卷积函数。
参考文章
- 64.屏幕后期处理效果-效果实现-高斯模糊-基础实现
11. DepthTextureMode.Depth 和 DepthNormals 各多出来什么纹理?
题目
Shader 里变量名一般叫什么?
深入解析
- Depth:**
_CameraDepthTexture**,配合SAMPLE_DEPTH_TEXTURE+ LinearEyeDepth/Linear01Depth。 - DepthNormals:**
_CameraDepthNormalsTexture**,一包里编码深度与法线,用DecodeDepthNormal等解。
答题示例
Depth 只要深度图;DepthNormals 同一张里还有法线,省一次几何 Pass 但更重一点。
参考文章
- 72.深度和法线纹理-查看深度纹理
- 73.深度和法线纹理-查看法线纹理
进阶题
1. 顶点照明路径为什么「省」但画面容易糙?
题目
和典型前向片元光照比,瓶颈和缺陷各在哪?
深入解析
- 光照在 顶点 算完再 插值,片元侧缺少完整逐光源计算,高光、聚光斑、阴影边界 等高频细节容易 糊、跳、分叉。
- 顶点数远少于片元数,计算量小,适合极简或老管线,不适合主画质。
答题示例
光在顶点算再插到像素里,算得少但细节差,高光和阴影边缘容易不行。
参考文章
- 3.渲染路径-顶点照明渲染路径
2. 延迟渲染为什么擅长「多光源」?
题目
用「谁遍历谁」说明与前向的差异。
深入解析
- 前向:光源影响常体现为 对物体的额外绘制或额外计算,光源多 → 物体侧成本涨得快。
- 延迟:几何 Pass 把参数写进 G-buffer,光照 Pass 在屏幕空间按光源算,复杂度更跟 像素与光源数量 绑定,多小型动态光时常更划算。
- 代价是 带宽、G-buffer 布局、透明与 MSAA 等要额外处理。
答题示例
前向是多光就多折腾物体;延迟先把表面信息存 G-buffer 再在屏幕上算光,多光往往更划算但透明和抗锯齿麻烦。
参考文章
- 4.渲染路径-延迟渲染路径
- 5.渲染路径-渲染路径对比
3. 接收阴影的「三剑客」各自干什么?有什么硬约定?
题目
SHADOW_COORDS、TRANSFER_SHADOW、SHADOW_ATTENUATION 怎么用?
深入解析
SHADOW_COORDS(n):在 v2f 里占位阴影插值坐标,n 取下一个空闲 TEXCOORD 索引。- **
TRANSFER_SHADOW**:顶点里写入阴影坐标;宏内部会读 appdata 的vertex和 **v2f 的pos**,改名会破坏展开。 - **
SHADOW_ATTENUATION**:片元里采样比较得阴影因子,常与 (漫反射+高光) 相乘。
答题示例
COORDS 声明插值寄存器,TRANSFER 在顶点填坐标,ATTENUATION 在片元算出阴影明暗;顶点参数和 pos 名字要对上宏。
参考文章
- 16.阴影-不透明物体阴影-让不透明物体接受阴影
4. UNITY_LIGHT_ATTENUATION 和 multi_compile_fwdadd_fullshadows 解决什么问题?
题目
为什么不手写 atten 再乘 SHADOW_ATTENUATION?
深入解析
UNITY_LIGHT_ATTENUATION(atten, i, worldPos)在AutoLight.cginc里把 距离衰减与阴影衰减 合成一个因子。#pragma multi_compile_fwdadd_fullshadows为 ForwardAdd 生成 带阴影 / 不带阴影 等变体,附加光才能正确收到阴影相关关键字与纹理。
答题示例
一个宏统一光衰减和阴影;ForwardAdd 要用 fullshadows 变体,附加光才有完整阴影路径。
参考文章
- 17.阴影-不透明物体阴影-光照衰减和阴影
5. 玻璃 Shader 为什么常把 Queue 设成 Transparent 却保留 RenderType=Opaque?
题目
Grab 的顺序和材质替换各得到什么?
深入解析
- Queue 延后:保证 身后几何先画进 framebuffer,Grab 内容才正确。
- RenderType 仍 Opaque:便于 Shader Replacement 等仍按不透明参与某些遍历;与「视觉上透明」解耦。
答题示例
Transparent 队列为了晚画好抓屏;RenderType 保持 Opaque 是给引擎其它系统一个「材质类别」标签。
参考文章
- 39.高级纹理-渲染纹理-玻璃效果-基础实现
6. ComputeGrabScreenPos 之后为什么在片元里还要除以 w?
题目
和透视投影有什么关系?
深入解析
grabPos是 齐次屏幕空间 插值结果,透视除法后才是 0~1 纹理 UV 可用的坐标。- 偏移折射时应对 xy 与 w 一致处理,避免近大远小下采样错位。
答题示例
齐次坐标要先除 w 才变成真正的屏幕归一化 UV,不然透视下会歪。
参考文章
- 39.高级纹理-渲染纹理-玻璃效果-基础实现
- 40.高级纹理-渲染纹理-玻璃效果-带法线纹理实现
7. 序列帧动画 Shader 里如何用时间选帧又不爆索引?
题目
图集行列与取余。
深入解析
- 用
floor(_Time.y * speed)或类似得到 流动索引,对 总帧数取余 循环。 - 由 帧索引 推出 行、列,把 0~1 UV 映射到 子矩形 内采样。
答题示例
时间乘速度取整再 mod 总帧数得到第几帧,然后把 UV 缩放到那一小格里采样。
参考文章
- 46.动态效果-纹理动画-序列帧动画
8. OnRenderImage 里若不对 destination 写入会发生什么?
题目
Graphics.Blit 最少要怎么写才能不黑屏?
深入解析
- 回调负责把结果写到 destination;空实现 等于 无输出 → 常见 黑屏。
Graphics.Blit(source, destination)至少 拷贝 source 到 destination。
答题示例
不往 destination 里写就黑;至少要 Blit 一下把 source 拷过去。
参考文章
- 56.屏幕后期处理效果-基本实现原理
9. 后处理基类里为什么要查 shader.isSupported 再给 Material?
题目
HideFlags.DontSave 大致防什么?
深入解析
- 平台/硬件 可能不支持该 Shader,直接 Blit 会 报错或花屏。
- 运行时
new Material若不 DontSave,可能被 序列化进场景 或 污染资产。
答题示例
先 isSupported 再创建材质,避免无效 Blit;DontSave 防止运行时材质当资源存盘。
参考文章
- 57.屏幕后期处理效果-屏幕后处理基类
10. 二维高斯模糊为什么通常拆成「先横再竖」两个 Pass?
题目
复杂度从多少降到多少量级?
深入解析
- 5×5 二维卷积 需 25 次 纹理采样量级;两次一维 5 tap 共 10 次。
- 中间需 一张临时 RT 存第一次结果,再 Blit 第二次。
答题示例
横竖各扫一遍一维核,采样数从 n² 量级降到约 2n;中间多一次 Blit 换性能。
参考文章
- 63.屏幕后期处理效果-效果实现-高斯模糊-基本原理
- 64.屏幕后期处理效果-效果实现-高斯模糊-基础实现
11. Bloom 为什么要「先提亮区再模糊再叠回去」?
题目
阈值 Pass 干什么用?
深入解析
- 阈值提取 让 暗部不参与 模糊,避免 整屏发灰。
- 模糊 让高光 晕开;合成 把光晕 加回 原图产生 辉光。
答题示例
先抠出够亮的像素再模糊,暗处不会被糊成一片,最后加回去才有 Bloom。
参考文章
- 67.屏幕后期处理效果-效果实现-Bloom效果-具体实现
深度题
1. 延迟渲染里透明物体为什么常常要「特殊处理」甚至回退前向?
题目
G-buffer 假设与透明混合冲突在哪里?
深入解析
- 延迟 光照阶段读的是一张或多张已固定的 G-buffer,默认按 不透明表面 排序与混合。
- 透明物体需要 深度排序与 Alpha 混合,与「先全屏算完光照」的流程 冲突;常见做法是 单独前向透明 Pass、分层渲染 或 简化光照。
- 具体项目要在 画质、排序稳定性、性能 间取舍。
答题示例
延迟是按屏幕像素读 G-buffer 算光,透明要排序和混合,和那一套打架,所以透明经常单独前向或分层处理。
参考文章
- 4.渲染路径-延迟渲染路径
- 5.渲染路径-渲染路径对比
2. 透明度测试与透明度混合在阴影上为何难度差很多?
题目
内置半透明 Shader 为什么默认不搞真·透明阴影?
深入解析
- Alpha Test:片元 discard/clip 后可在 ShadowCaster 里同样剔除,再配合 Cutout 类 Fallback 与
_Cutoff/_Color命名对齐;单面网格常需 Two Sided Cast。 - Alpha Blend:关 ZWrite、要排序混合,与 阴影深度/遮挡 的经典路径冲突;内置多直接不承接;Fallback 到不透明 可「假投影」但不真实。
答题示例
Cutout 能 clip 掉阴影投射像素所以还能做;半透明关深度写入又排序,和阴影深度逻辑拧巴,所以内置往往不做真透明阴影。
参考文章
- 18.阴影-透明物体阴影-透明度测试物体阴影
- 19.阴影-透明物体阴影-透明度混合物体阴影
3. Schlick 菲涅尔近似在环境反射里怎么用?
题目
式子中 R₀、V·N 各代表什么直觉?
深入解析
- R(θ) = R₀ + (1−R₀)(1−V·N)⁵:掠射 (V·N→0) 时反射变强,正对 (V·N→1) 时接近 R₀。
- 实现上用
lerp在 漫反射 / 反射采样色 间按 R(θ) 混合,再与 多光源+阴影 流程结合。
答题示例
用视角和法线夹角控制反射权重,掠角更亮更像玻璃边缘;R0 是正对时的基础反射率。
参考文章
- 32.高级纹理-立方体纹理-菲涅尔反射-菲涅尔反射基础实现
- 33.高级纹理-立方体纹理-菲涅尔反射-菲涅尔反射结合漫反射及阴影
4. Render Texture 绑相机和 GrabPass 各适合什么场景?
题目
镜子、全屏玻璃各偏向哪种?
深入解析
- Target Texture:离屏相机 只画特定视角(镜面、小地图),分辨率与更新频率可控,可多相机管理。
- GrabPass:当前 Pass 前 抓取已有颜色缓冲,实现 折射、扭曲、简单玻璃 快,但 每 Grab 多一遍拷贝/带宽成本,复杂项目常改用 单 Pass 模糊 RT 等替代。
答题示例
镜子用专用相机渲染到 RT 再采样;GrabPass 适合抓屏做玻璃扰动,但性能要省着用。
参考文章
- 34.高级纹理-渲染纹理-渲染目标纹理是什么
- 35.高级纹理-渲染纹理-镜面效果-原理和准备工作
- 39.高级纹理-渲染纹理-玻璃效果-基础实现
5. frac 在滚动背景里解决了什么数值问题?
题目
和 Repeat Wrap 的异同?
深入解析
frac显式把坐标 折叠到 [0,1),负数 也按小数部分拉回,适合 手写 UV 动画。- 纹理 Wrap=Repeat 由采样器处理;Shader 里 frac 更可控且可与 速度、时间 直接组合。
答题示例
时间让 UV 一直加会超大,frac 折回 0~1 才能无缝滚。
参考文章
- 47.动态效果-纹理动画-滚动的背景
6. 顶点动画又想合批时,课文里提了哪两种「把模型空间信息带进顶点」的办法?
题目
Shader 里怎么取?
深入解析
- 顶点色:脚本里
mesh.colors写入位置或辅助量,Shader **appdata_full.color**。 - UV2/UV3:存两个分量时用
mesh.uv2等,Shadertexcoord1等语义读取。
答题示例
把要的模型空间信息烘焙进顶点色或第二套 UV,合批后还能在顶点阶段读回来算动画。
参考文章
- 52.动态效果-顶点动画-顶点动画的注意事项-批处理
7. 河流做了顶点起伏,为什么默认 Fallback 的阴影会「对不上」?
题目
要怎么改 ShadowCaster?
深入解析
- 内置 ShadowCaster 用 原始网格 算深度,与 主 Pass 位移后 表面不一致。
- 需在 ShadowCaster Pass 的顶点阶段 重复同一套位移,再交给
TRANSFER_SHADOW_CASTER_NORMALOFFSET等宏。
答题示例
Fallback 的阴影还在用没动的顶点;要自己写 ShadowCaster,顶点算法和主 Pass 一致。
参考文章
- 53.动态效果-顶点动画-顶点动画的注意事项-阴影
8. 用深度纹理做「相机运动」运动模糊时,为什么要传上一帧的 worldToClip 矩阵?
题目
和 69 课那种全屏累积模糊各解决什么问题?
深入解析
- 每像素用 深度 还原 世界坐标,再乘 上一帧视图投影矩阵 得 历史屏幕位置,当前 − 历史 即 屏幕空间运动向量。
- 69 的 帧缓冲累积 不依赖 几何重投影,但需 维护 RT 与 Alpha 通道,适合 整体拖影 而非严格 每像素速度。
答题示例
深度版要知道每个像素在上一帧投到哪,必须带旧 VP;累积版是混上一帧整图,思路不一样。
参考文章
- 74.深度和法线纹理-效果实现-深度纹理实现运动模糊-基本原理
- 75.深度和法线纹理-效果实现-深度纹理实现运动模糊-具体实现
- 69.屏幕后期处理效果-效果实现-运动模糊-具体实现
9. 基于 _CameraDepthNormalsTexture 的边缘检测,相对只对 _MainTex 做 Sobel 有什么优势?
题目
Roberts 对角比的是什么?
深入解析
- 深度突变、法线不连续 对应 几何轮廓;颜色 Sobel 易被 贴图明暗、光照 误检。
- 课文用 对角采样 比较 深度差/法线差 与 敏感度阈值,得到 几何边缘。
答题示例
深度+法线抓的是模型形状边界,不容易被花纹骗;颜色边缘会把材质细节也当边。
参考文章
- 79.深度和法线纹理-效果实现-深度法线纹理实现边缘检测-基本原理
- 80.深度和法线纹理-效果实现-深度法线纹理实现边缘检测-具体实现
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com