你可以直接这样回答
我会从 ShaderLab 的 Properties、SubShader/Pass 讲起,再说明 vertex 负责空间变换与传递,fragment 负责法线采样、TBN 变换和输出。编译通过只是起点,还要检查资源绑定、坐标空间、深度/混合状态和平台精度。
这道题真正想听什么?
先确认比较对象和回答边界,再决定要不要展开公式、工程实现或性能取舍。
题目看似要背代码,真正要检查的是数据流:Properties 提供纹理/参数,SubShader/Pass 声明一次绘制契约,顶点函数把位置、UV、TBN 或世界法线传给片元函数,片元函数采样并输出颜色。编译通过不等于坐标空间、纹理语义、深度/混合状态都正确。
把答案讲到 2 分钟面试必答 · 约 2 分钟 · 补足因果、输入和取舍
最小法线 shader 的关键是数据契约而不是代码长度:顶点输出 clip position、UV 和所需的切线/法线,片元解码法线并在正确空间里做光照。每个 Pass 对应一次绘制职责;若透明或阴影需要不同状态,就拆分 Pass。排错先看阶段、资源、空间和输出,而不是只看最终黑图。
面试官可能继续追问什么?补充自测 · 约 3 分钟 · 检查自己是不是真的懂了
- 问:为什么要有
SubShader和Pass? 答:它们描述渲染状态和阶段;透明、深度预写、阴影可能各自需要 Pass。 - 问:法线贴图采样后能直接当世界法线吗? 答:不能。Tangent Space 的 RGB 要经过 TBN 变换,且要遵守切线/镜像 UV 约定。
- 因果链: 属性绑定 → vertex 变换/传递 → fragment 解码与光照 → render target。黑屏先分辨编译错误、资源缺失、空间错误和输出状态。
如果概念还是悬空,就去做实验关键证据 · 约 5–15 分钟 · 预测 → 单变量 → 观察
实验不是第二份答案,它只负责证明答案
如果上面的解释已经听懂,可以直接跳过。卡住时,再沿着这三步把抽象词变成画面证据。
- 先猜 这份数据从哪里进入 Shader,经过哪一步,最后改变哪个像素?
- 去取证 固定其他条件,只改一个参数。先写下变化,不用“更真实”“更高级”这种空词代替证据。
- 再追问为什么 是哪一步造成这个结果?如果结果相反,先检查输入、空间、算法,还是显示输出?
我完全没头绪,给我一个起点
先截下默认状态,只动页面当前开放的那个参数。你只需要说清楚“原来怎样 → 改了什么 → 现在怎样”。
1. 先预测
把 shaderWork=22 作为片元工作量基线,再改变其他控件;它是相对成本证据,不是某个 GPU 的实际指令数。
在现有 ShaderLab Pipeline 代码页 先按 Properties → Pass → Vertex → Fragment 顺序读。用 stage、passCount、textureReads、debugMode 控制做预测:增加一个 Pass 会增加提交,增加纹理读取会提高相对工作量;只改法线贴图强度时,silhouette 不应变化。把 shader 看成“给渲染管线填表”,每个字段都要有收件人。
一个最小骨架的口语翻译:
struct Varyings { float4 positionCS : SV_POSITION; float2 uv : TEXCOORD0; };
Varyings vert(Attributes input) { /* object → clip, pass uv */ }
float4 frag(Varyings input) : SV_Target { /* sample normal, light, output */ }
它不是要逐字背诵,而是“顶点阶段寄出位置/UV,片元阶段按每个像素收件并着色”。坐标空间和精度语义缺失时,代码短也不会正确。
老师追问
先别急着查答案: 先追一条数据从输入到像素:它经过哪一步计算,哪一个中间通道会先暴露问题?
为什么: 你刚才的预测依赖哪个前提?如果把“ShaderLab 法线 Shader”里最关键的变量或约束关掉,画面/输出会先坏在哪里?
如果结果相反: 先排除哪一层,再谈结论?这个规则的边界是什么?
2. 再动手
在 ShaderLab Pipeline Lab 里用 stage 依次只看一个阶段;再在 ShaderLab Pipeline 代码页 对照 stage 数据流。故意将 textureReads 设为 0、debugMode=error,记录“编译成功但缺证据”的表现;恢复后确认最终材质、阶段流和工作量三项都能解释。
3. 最后对证据
stage debug 会显示参数如何进入 Pass 和两个着色阶段;passCount 增加时 draw submission/工作量估算上升。故意缺纹理或输出时,应该看到可读的错误提示而不是把黑屏当答案。这个 Lab 的成本是相对教学估算,不等于某个 GPU 的实际指令数。
答案在代码哪里发生?实现定位 · 约 3 分钟 · 变量、函数和关键行
- ShaderLab 组织段:Properties、SubShader、Pass 的契约。
- 阶段与路径对照:把阶段数据和一次绘制的资源路径对照起来。
- 数值/错误 debug:把缺资源和异常输出变成可观察证据。
完整 5 分钟版本面试扩展 · 约 5 分钟 · 项目边界、验证与降级
项目中会固定纹理语义、颜色空间、法线绿通道、精度与质量宏,先用单 Pass 基线再添加特征。验证记录 draw calls、纹理读取、GPU 时间、编译日志和 fallback;移动端可减少采样、降低精度或关闭非关键法线细节,但要保留可定位的 debug。当前代码页是教学模型,不应声称它覆盖 Unity 所有后端变体。
哪些说法最容易答歪?必看陷阱 · 约 1 分钟 · 面试前最后检查
- 把 ShaderLab 声明层和 HLSL 执行逻辑混为一谈。
- 把 Tangent Space 法线直接输出到世界光照。
- 只说“能编译”,没有资源/空间/深度证据。
- 用增加 Pass 或纹理读取解决画质,却没有记录提交与带宽成本。