自由学习记录(66)
主要目的是角色模型,先拿到unity里面,可以被渲染,分清楚哪些是光照的影响范围
还是这里,很关键,可以明白要做的事情,定位在哪里
【技术美术入行作品准备经验分享】原神角色渲染还原教程_哔哩哔哩_bilibili
,带着渲染角色的想法去看 庄懂的教程,,还有色彩理论,雷德蒙的课也很全面,
在 Blender 里:
你给角色的皮肤用了 Subsurface Scattering(SSS)BSDF 节点,Eevee 或 Cycles 会真实计算次表面反射、光扩散。
在 Unity 里:
你得自己写一个 SSS Shader,可能用屏幕空间模糊 + Wrap Lighting 模拟皮肤渗光,不然就得用 HDRP 的 SSS 功能。
Unity 里写的 Shader(无论是 ShaderLab、HLSL、Shader Graph),不能直接在 Blender 里使用或查看。
因为两者使用的是完全不同的渲染架构与着色语言系统。
对比维度 | Unity Shader | Blender 材质系统 |
---|---|---|
着色语言 | HLSL(或 ShaderLab 封装) | Open Shading Language(Cycles) + Eevee 内建规则 |
着色管线 | Scriptable Render Pipeline (SRP) / Built-in | Eevee(实时) / Cycles(路径追踪) |
材质结构 | Shader → Material → Renderer → Mesh | Shader Node → Material Slot → Object |
文件格式 | .shader / .shadergraph | 内嵌于 .blend 文件中,不读取外部 shader 文件 |
所以你不能把 Unity 的 Shader 文件直接拿去 Blender 用,原因是:
1. 语言不兼容
Unity 用 HLSL/ShaderLab,而 Blender Cycles 用的是 OSL(Open Shading Language),Eevee 用自己的 GLSL 管线,完全不通。
2. 渲染原理不同
Unity 是实时光栅化,Blender 的 Cycles 是路径追踪,Lambert 在这两者中渲染方式完全不一样。
3. 材质系统封装不同
Unity 的材质是通过材质球(Material)绑定 Shader,而 Blender 的材质是通过节点系统构建,互不识别。
Ray-MMD 是一个高质量的 MMD 渲染插件系统,类似于 Unity 的高清渲染管线(HDRP),具备以下特性:
-
实时全局光照模拟
-
屏幕空间反射(SSR)
-
次表面散射(SSS)
-
自定义 PBR 材质控制
-
多层次阴影、景深、色差、Bloom 等后处理
对比 .x
文件:
文件类型 | .ray | .x |
---|---|---|
类型 | 材质配置脚本 | DirectX 3D 模型格式 |
作用 | 分配 Shader | 存储网格、骨骼、动画数据 |
用于 MMD | Ray-MMD 材质系统 | 舞台/物体模型加载(非动画) |
可编辑性 | 纯文本脚本 | 二进制/文本结构体,复杂难改 |
是否 Shader | ❌ 不是 Shader,只是映射表 | ❌ 也不是 Shader,是几何数据 |
✅ 所以结论是:
-
.ray
是 Ray-MMD 的“材质使用计划表”,告诉它怎么把.fx
Shader 应用到.pmx
模型的各个材质上。 -
它本身不参与渲染,只作为参数桥梁。
ray.fx
—— 主着色器文件
属性 | 内容 |
---|---|
类型 | .fx 文件(HLSL 编写的 MME 着色器) |
用途 | Ray-MMD 的核心全局渲染器 Shader |
功能 | 控制场景整体的光照响应、材质处理、后处理(Bloom、AO、SSR)等 |
应用方式 | 通常绑定在主角模型、镜面对象、地面模型等上面 |
ray.x
—— 环境体积参考模型
属性 | 内容 |
---|---|
类型 | .x 文件(DirectX 模型格式) |
用途 | 一个不可见但必要的参考模型,用来定义场景中全局光照体积/坐标空间范围 |
外观 | 看不到 / 不显示 / 不参与渲染 |
作用 | 给 ray.fx 提供一个坐标框架,让它知道“我在哪片空间中打光” |
✅ 总结:
ray.x
是 Ray-MMD 的空间参考锚点,你必须在场景中加载它,不然模型可能发黑或光照混乱。
ray_controller.pmx
—— 光照控制器模型
属性 | 内容 |
---|---|
类型 | .pmx 模型文件 |
外观 | 一个小控制面板,加载后显示在 MMD 视图中 |
功能 | 拖动控制器上的滑块,动态调节光源方向、强度、环境光颜色、SSAO 开关等全局参数 |
附带 Shader | 通常绑定了 ray_controller.fx 或 ray_MET.fx |
控制器常见控制项:
-
光源颜色与角度
-
环境光/天空光颜色
-
SSAO 强度
-
Bloom 开关
-
色调映射等
✅ 总结:
ray_controller.pmx
是 Ray-MMD 渲染参数的“面板入口”,你通过它实时调光、开关效果,体验完整的场景控制。
import
✅ 模型和贴图文件不在同一个文件夹
PMX 模型引用的贴图路径是相对路径或硬编码路径,你导入时若贴图不在相对位置,Blender 就无法读取。
✅ 修复方法:
-
把贴图文件(如
.png
,.tga
,.bmp
)放到和.pmx
同一目录或其Texture
文件夹中 -
然后重新导入
.pmx
模型 -
或进入 Shader 编辑器手动绑定贴图(如下)
进入右侧的「材质(Material)面板」(红球图标)
格式 | 定义者/软件 | 内容包含 | 可直接使用的软件 |
---|---|---|---|
.pmx | MikuMikuDance (MMD) | 骨骼、权重、动作、材质、物理(刚体/关节)、Morph 等 | MMD, Blender(通过 MMDTools 插件) |
.fbx | Autodesk | 模型、骨骼、动画、材质信息(不总含贴图) | Unity、Blender、Unreal 等 |
.obj | 通用格式 | 仅模型网格(无动画、无骨骼),可配 .mtl 贴图信息 | Unity、Blender、3dsMax、Maya 等 |
如何在其他软件中使用 .pmx
▶ Blender
-
需安装 MMD Tools 插件
-
可以导入
.pmx
、.vmd
(动作)、.vpd
(姿势) -
可修改模型后导出为
.fbx
(用于 Unity)
▶ Unity
-
没有官方支持
.pmx
的插件 -
通常流程是:
-
用 Blender + MMD Tools 打开
.pmx
-
整理模型骨骼/贴图/动画
-
导出为
.fbx
-
再导入 Unity 中使用(并手动绑定 Animator、材质、Shader 等)
-
.pmx 是闭源格式,MMD 的作者没有开放官方 SDK,只能靠民间逆向实现解析插件(如 MMDTools、PMXEditor、PMX2FBX 等)。Unity 中没有直接支持 .pmx
的稳定方案。
不良后果举例
1. 模型被非法用于商业游戏
例如,有人将 MMD 模型(如初音未来、鸣潮角色等)导入 Unity,通过格式插件直接商用到移动游戏、Steam 游戏中,而未获得原作者授权。原作者既无从得知,也难以维权,尤其在国际传播下更失控。🎯 举例参考:2020 年左右,一些日系 MMD 模型被出现在中国手游内,被网友举报后,游戏才紧急下架角色。2. 擦边内容、恶搞用途泛滥
MMD 模型被用于制作不雅视频、色情动画、猎奇恶搞等内容,而开源格式让更多人轻松导出导入、传播。即使模型作者写了“禁止使用于R18内容”的声明,开源格式也让控制难度急剧上升。🧨 举例参考:MMD 模型圈曾多次爆发“模主封模事件”,就是因为模型被用于不当内容,导致作者关闭模型下载、退出创作。3. 作者完全失去控制权
一旦格式开源,就意味着任何人都能“自己写个软件”来处理 .pmx 文件,不必依赖 MMD 本体。模型可能被改动、再分发,连“署名”都可能被篡改,社区秩序混乱。🎯 举例参考:早期一些非日语圈站点转载大量模型资源,却不保留作者名或使用规约,引发大量抵制。4. 出现“灰色资产交易市场”
有了开源格式,商业工具可以完全绕开版权、自由导入使用 .pmx,导致:模型被无授权打包进资产包售卖。国内外出现“资源整合商”变相盈利,建付费交流群、售卖插件等。💸 举例参考:某些 Discord 或QQ群中流通大量盗用模型的Unity包,很多是MMD模型改装的。5. 社区风气恶化,创作者流失
原本温和、非商业化的二创氛围变成“资源掠夺与滥用”的战场。优质模型作者因反复被侵权、辱骂、二次加工,选择停更、删档、封模。🥀 举例参考:日本许多知名模主(如YYB、TDA)都曾因作品遭滥用而暂停公开发布模型。
开源本身是中性的,但对依赖“信任”“约定”“社区文化”的创作圈来说,过早地开源格式,反而是摧毁生态的开始。
MMD 圈尤其依赖“口头约定 + 模型使用规约 + 圈内自律”,如果这些失效,创作圈就会崩塌。
可是pmx既然可以转Blender里了,Blender又可以转成fbx格式的所有软件通用格式,这一下不就毫无意义了吗
你这个反问非常关键,而且非常现实。确实,既然 .pmx 都能被导入 Blender 并转换成 .fbx,那所谓“闭源保护”不是形同虚设吗?你想要滥用的人照样滥用。那闭源还有什么意义?这问题本质上是在质疑:“是否存在一个‘有效的闭源’,能真正阻止滥用?”我的回答是:你说得对,从技术层面来说,确实无法阻止。
🧩 那为什么还要“闭源”?
闭源并不是为了实现**“绝对禁止”,而是为了增加“门槛”和制造“模糊性”**。
它的作用是:
降低批量化滥用的效率(加阻力)
-
.pmx
→.fbx
是可以做,但不能一键批量处理大批.pmx格式 的模型。 -
插件(如 MMDTools)解析
.pmx
结构并不总是稳定、全面,有一定使用门槛。 -
尤其是有复杂物理、morph 的模型,在转换后会出现大量错位或数据丢失,不适合直接商用。
📌 所以闭源 = 增加“做坏事”的技术壁垒,让滥用的变成少数而非常态。
维持“模糊合法性”的社群秩序
-
闭源意味着:
“你想用我的 模型必须使用 MMD软件 或兼容插件,而且必须手动导入”
-
这在人情和道德层面给创作者一张“遮羞布”——他们可以说:“我没有授权大家商用。”
📌 如果作者自己提供 Unity 插件,那就等于他自己公开放弃控制权了。
形成一种“使用约定上的威慑力”
-
社区规则往往不是靠技术手段执行,而是靠“你违反了规则”这一道德声讨的机制。
-
一旦你(作为模型 创作者)公开表示“我不允许转 Unity”,哪怕别人真的做了,也容易被举报、被拉黑。
📌 闭源增强了“约定”的道德效力。
闭源的目的不是让坏人做不到,而是让“好人不敢轻易变坏”。
Unity 在导入 FBX 模型时如何处理材质与贴图的关键策略:
选项 | 当前设置 | 作用说明 | 对你当前问题的影响 |
---|---|---|---|
Material Creation Mode | Import via Material Description | 尝试使用 FBX 文件中嵌入的材质信息 | ✅ Unity 会试图读取 FBX 内的材质引用,但如果 FBX 中没写贴图路径,就只创建空材质 |
Location | Use Embedded Materials | 直接使用 FBX 文件中的嵌入材质(不生成外部材质球) | ⚠️ 贴图不会单独暴露出来,Unity 无法自动匹配资源库中的贴图 |
Materials | Extract Materials... (按钮) | 可点击导出 FBX 中的材质为 .mat 材质球 | ✅ 如果你想修改/查看材质,建议点这个先提取出来再绑定贴图 |
📌 当前 Unity 无法自动绑定贴图的原因是:
-
FBX 文件没有包含贴图路径或贴图本身(如有路径,也可能是绝对路径不匹配)
-
你设置为
Use Embedded Materials
→ 不生成 Unity 可管理的.mat
材质文件 -
所以
Remapped Materials
显示为None
(空材质),也无法自动匹配贴图
① 点击右侧 “Extract Materials…” 按钮
-
将 FBX 内嵌的材质球提取出来为
.mat
文件 -
推荐选择提取到同目录或
Assets/Materials
子目录中
⚠️ FBX 导入设置中的 Extract Materials
和 Extract Textures
按钮是灰色的,无法点击。
这说明 Unity 无法从该 FBX 中提取材质和贴图的根本原因通常是以下几种之一:
① FBX 文件里根本没有嵌入任何材质/贴图信息(最常见)
-
你这个
VergilDmCV.fbx
是从 外部 3D 软件(如 Blender、Maya)导出的模型,但导出时**材质没有勾选“导出”**或材质信息丢失了。 -
所以 FBX 虽然结构没问题,但里面根本就没有
Material
节点,Unity 也就无法提取出来。
表现就是:
FBX 的
Material
区块为空 →Extract Materials
按钮自然不可用所有
Model_0_Mesh_*
也没有自动挂材质球① FBX 文件里根本没有嵌入任何材质/贴图信息(最常见)
你这个
VergilDmCV.fbx
是从 外部 3D 软件(如 Blender、Maya)导出的模型,但导出时**材质没有勾选“导出”**或材质信息丢失了。所以 FBX 虽然结构没问题,但里面根本就没有
Material
节点,Unity 也就无法提取出来。表现就是:
FBX 的
Material
区块为空 →Extract Materials
按钮自然不可用所有
Model_0_Mesh_*
也没有自动挂材质球
FBX 导出时使用了不兼容的材质(如非标准材质系统)
-
如果是从 Blender 导出 FBX,而材质使用了 Node 系统(而不是 “Principled BSDF” 或 Unity 兼容设置),则 Unity 可能无法识别。
-
Maya/3dsMax 导出时使用 Arnold 等特殊渲染器的材质也会丢失。
方法二:使用 [Blender] 导入查看
Blender 是最强的免费 DCC 工具,也能导入 FBX 并检查材质结构。
🧭 操作流程:
-
打开 Blender(推荐用 3.0+ 版本)
-
菜单栏
File → Import → FBX (.fbx)
-
导入你的
VergilDmCV.fbx
-
选中模型,切换右侧
Material Properties
面板-
查看是否有材质球
-
点开材质球 →
Surface
部分是否有贴图连接(如 Base Color、Normal)
-
📌 如果材质球都为空,说明 FBX 里没写材质信息。
📌 Blender 可配合 UV/Image Editor
进一步检查贴图绑定。
✅ 方法三:使用文本编辑器查看(仅限 ASCII 格式 FBX)
如果你导出的是 .fbx
的 ASCII 格式(非 Binary),可以用文本编辑器打开查看内容结构。
-
打开
.fbx
文件(建议用 VS Code 或 Sublime) -
搜索关键词:
-
Material:
-
Texture:
-
RelativeFilename
(贴图路径) -
Properties70
(参数块)
-
📌 但大多数 FBX 是 Binary 格式,看不懂乱码就说明你不是 ASCII,就用前两个方法。
❌ Blender 无法读取贴图文件,显示
"No such file or directory"
,路径如
C:\Users\86134\Downloads\pl0300_coat_ALBM.dds
✅ 原因总结:贴图引用路径是绝对路径,而该贴图文件已经不在那个目录了
Blender 在打开 .blend
文件时,会尝试去加载贴图文件:
-
如果贴图是使用绝对路径引用(如
C:\xxx\yyy.dds
),但你换了电脑或文件夹变了,就会找不到 -
所以你现在在
Shading
面板中看到的 Image Texture 节点,会是 粉红色无预览的
✅ 正确的修复步骤:重新绑定贴图并转为相对路径
你只需要操作一次即可修复整套贴图引用。
❓ 那么,为什么 Blender 不从当前文件夹找贴图?
🎯 根本原因:FBX 文件内部记录的贴图路径是“导出时写死的”路径
Blender 在导入 FBX 时,不会智能搜索贴图文件夹,而是严格按 FBX 内部记录的贴图路径去读取
这就意味着:
-
如果
.fbx
是用 3ds Max/Maya/Blender 导出时,贴图引用路径是绝对路径(如C:\Users\Bob\Textures\xxx.tga
),Blender 就会直接尝试去那个路径找 -
哪怕你现在的贴图就放在
.fbx
同一目录,Blender 不会去猜、不会搜索、不会自动替换 -
所以贴图加载失败,结果显示全粉红
[FBX 文件]└── Mesh 对象└── 材质(Material)├── 名称(例如 m_coat)├── 渲染模型(Lambert, Phong, PBR...)└── 贴图引用(贴图类型 + 路径)
Unity 支持直接导入 .blend
文件(但是通过后台转 FBX)
Unity 实际上并不原生解析 .blend
文件格式,而是:
-
背后调用你电脑上安装的 Blender(命令行模式)
-
把
.blend
文件自动转换为.fbx
临时缓存文件 -
再按照
.fbx
的导入逻辑去处理模型、骨骼、材质
📍 所以一切材质贴图行为,其实 = FBX 导入逻辑
❓这些 Remapping 条目(比如
m_coat
,m_body
,m_eye
)是否会出现在这里,取决于什么?
✅ 决定这些“Remapped Material”是否出现的关键因素:
1. FBX 文件中是否存在材质槽(Material Slots)
-
这是最关键的!
-
如果 FBX 中的 Mesh 对象绑定了一个或多个材质(哪怕材质本体丢了,只要有名字),Unity 就会在 Remap 区显示这些材质槽名。
🟩 有绑定材质名 → 出现 Remap 项(即使没贴图)
🟥 无绑定材质 → 没有 Remap 项
材质在Blender 和unity里面是同一个东西吗,Blender里面是连连看,unity里面是shader做出来的,两个可以等同吗
❓Blender 里的材质(Material)和 Unity 里的材质是“同一个东西”吗?
✅ 表面上都叫“材质(Material)”,但本质完全不同:
比较项 | Blender 材质 | Unity 材质 |
---|---|---|
表现形式 | 节点图(Node Graph) Shader Editor | 材质球(.mat 文件)挂载 Shader 脚本 |
Shader 来源 | 内置 + 自定义节点(Cycles / Eevee Shader) | Shader 文件 (.shader , .shadergraph ) 明确控制光照和渲染行为 |
工作原理 | 基于“材质节点树”连接贴图与属性 | 基于 Shader 脚本定义材质输入输出行为 |
能否一一转换 | ❌ 不能直接转换 | 只能通过导出贴图+材质名来间接映射 |
你从 Blender 导出 FBX 到 Unity,会发生什么?
导出内容 | 会发生什么 |
---|---|
材质名称 | ✅ 会保留(用于 Remap) |
贴图路径 | ⚠️ 有时会保留,但 Unity 不一定能自动识别 |
节点连接 | ❌ 完全丢失(节点系统无法翻译为 Unity Shader) |
着色模型 | 会被强制降级为 Phong / Lambert(Unity 标准 Shader) |
正确的迁移方式(从 Blender → Unity)
如果你想尽可能“等价迁移”:
-
Blender: 材质只保留基础贴图(BaseColor、Normal、Metallic 等)和命名,不搞复杂节点连接
-
导出 FBX 时:
-
贴图用相对路径或嵌入
-
保留材质名
-
-
Unity:
-
用自定义 Shader 或 URP/Standard Shader 建材质球
-
按照 Blender 的贴图绑定关系重新贴图
-
xxxx
文件_相对路径与绝对路径_哔哩哔哩_bilibili
xxxxxx
只要你安装了 URP,就能看到源码,也可以修改,前提是:
🎯 你需要 把它从 Library/PackageCache/
复制出来放到项目的 Packages/
文件夹里
你截图中 Unity 官方文档的流程就是这个意思:
💡 只有把 URP 包变成 Embedded(嵌入式)包,才可以修改它的源码
不能直接改 Library/PackageCache
里的 URP 源码?
因为它是 Unity 自动生成 &引用的临时包:
路径 | 类型 | 是否可改 | 会不会被覆盖 |
---|---|---|---|
Library/PackageCache/ | 外部引用的只读包 | ❌ 不推荐修改 | ✅ 每次刷新或升级都会被重建 |
Packages/com.unity.xxx/ | 你复制进来的嵌入式包 | ✅ 可以自由修改 | ❌ Unity 不再覆盖,归你项目管理 |
如何“嵌入 URP 包”才能修改?
📁 操作步骤(实际执行):
-
找到项目文件夹的这个目录(非 Assets):
Library/PackageCache/com.unity.render-pipelines.universal@版本号/
-
将它复制到你的项目根目录的
Packages/
目录里:YourProject/ ├── Assets/ ├── Packages/ │ └── com.unity.render-pipelines.universal/
-
Unity 会立刻改为使用你复制出来的版本,并在编辑器内可见且可修改。
xxx
能满足urp的定制就很不错了,srp的定制更深一些,hdrp一般也很难用上
URP 默认 Forward 渲染流程 的一个清晰概览
Main Light Shadowmap
→ Additional Light Shadowmap
→ Depth Prepass
→ Render Opaque
→ Render Skybox
→ Copy Color(有需要时才执行)
→ Render Transparent
→ Post Processing(Bloom, Tonemapping 等)
→ Render UI
→ Final Blit(输出到屏幕)
1️⃣ Main Light Shadowmap
-
渲染主光源(Directional Light)产生的 Shadow Map
-
对应源码文件:
-
MainLightShadowCasterPass.cs
-
2️⃣ Additional Light Shadowmap
-
渲染非主光源(点光、聚光等)的 Shadow Map
-
对应源码:
-
AdditionalLightsShadowCasterPass.cs
-
3️⃣ Depth Prepass
-
对场景做一次深度写入,提前填充 Z-Buffer
-
用于:
-
后期特效(如 DOF、SSR)
-
透明物体排序
-
降低 overdraw
-
-
源码:
-
DepthOnlyPass.cs
-
4️⃣ Render Opaque
-
渲染所有不透明物体(使用 Shader 的 Queue < 2500)
-
同时写入 Color 和 Depth
-
源码:
-
DrawObjectsPass.cs
(配置为 Opaque)
-
5️⃣ Render Skybox
-
渲染天空盒(也属于不透明阶段)
-
源码调用:
context.DrawSkybox(camera);
✅ 蓝框结束:前面这段属于 主 Pass(不透明+深度)
🔁 接下来是“第二阶段”(需要额外 RT 处理)
6️⃣ Copy Color(拷贝颜色)
-
作用:
-
如果后期处理要用 SceneColor(比如 Bloom),但你用了 MSAA,则必须在这里复制一份非 MSAA 的颜色纹理
-
-
什么时候出现:
-
MSAA 开启 + 后处理开启时
-
-
源码:
-
CopyColorPass.cs
-
7️⃣ Render Transparent
-
渲染透明物体(使用 Shader Queue ≥ 2500)
-
会受限于先前的 Depth
-
源码:
-
DrawObjectsPass.cs
(配置为 Transparent)
-
8️⃣ Post Processing
-
应用各种后期效果:
-
Bloom、Color Grading、Tonemapping、Vignette、Motion Blur 等
-
-
Unity 后处理栈(Post Processing v3 或内置 URP PP)
-
源码:
-
PostProcessPass.cs
-
PostProcessPass.CompilePasses()
→ 动态决定哪些效果启用
-
9️⃣ Render UI
-
渲染
Canvas
UI(Overlay 类型) -
Unity 会自动将 UI 调整为最上层
-
通常使用专用
RenderPassEvent.AfterRenderingPostProcessing
🔟 Final Blit
-
将最终图像 Blit 到屏幕(即 BackBuffer / FrameBuffer)
-
这一阶段的目标 RenderTarget 是
Built-in Camera Target
(即你看到的成像) -
源码:
-
FinalBlitPass.cs
-
这一套流程乍一看与 Unity 内置渲染管线(Built-in Forward) 的执行阶段很相似,比如也有:
-
Shadow Pass(阴影贴图)
-
Depth Prepass(可选)
-
Opaque 渲染 → Skybox → Transparent 渲染
-
后处理 → UI → Blit
但 URP(Universal Render Pipeline)本质上是自行组织的渲染框架,虽然模仿了传统渲染顺序,但其背后机制、可扩展性与 Built-in 完全不同。下面是两者的 关键区别对照表:
🆚 URP 与 Built-in Forward 管线对比
渲染阶段 | 内置管线(Built-in) | URP(Universal Render Pipeline) |
---|---|---|
ShadowMap 阶段 | Unity 内部流程自动调用 | 明确由 MainLightShadowCasterPass 、AdditionalLightsShadowCasterPass 管理 |
Depth Prepass | 通常是 Shader 设置 ZWrite On ,不需要手动 Pass | 有专用 DepthOnlyPass.cs 控制,主动写入 Z-buffer |
Opaque 渲染 | Unity 自动处理 Queue < 2500 的物体 | DrawObjectsPass 明确控制,并支持 Feature 插入前后 |
Skybox 渲染 | Unity 自动 DrawSkybox() | UniversalRenderer 手动调用 context.DrawSkybox(camera) |
Transparent 渲染 | 统一按 Queue 顺序执行 | 拆出 DrawObjectsPass(Transparent) 单独执行,插点清晰 |
后处理(Post Processing) | 用后处理栈(PPv2),Pipeline 不知情 | 完全内建于 PostProcessPass.cs ,在 URP 管线内处理 |
UI 渲染 | Overlay UI 在 Built-in 后自然叠加 | 需要在 URP 管线尾部手动 RenderUI |
Final Blit | Unity 自动将渲染结果输出到屏幕 | FinalBlitPass.cs 显式控制 Blit |
URP 的核心优势(区别于内置管线)
-
全流程可视化、可插拔(Passes/Feature)
-
你可以随时在任意阶段插入自定义处理逻辑,而内置管线几乎不可控。
-
-
每一个渲染阶段都由 C# 控制类调度
-
UniversalRenderPipeline.cs
和UniversalRenderer.cs
是总控。 -
每个阶段的具体执行由一个
ScriptableRenderPass
管理,执行顺序通过RenderPassEvent
控制。
-
-
Renderer Feature 可扩展性极强
-
用户可以在特定阶段插入自己的 Blit、Draw、Compute 等逻辑。
-
-
跨平台一致性好
-
URP 针对低端设备做了大量优化,Shader 也比 Built-in 精简。
-
为什么流程“看起来像内置”,但本质不同?
这是因为 Forward 渲染的逻辑本就如此 —— 深度 → 不透明 → 天空 → 透明 → 后处理 → UI → Blit,这是大多数实时渲染引擎的顺序,URP 只是显式地把这些打散、拆解并提供控制能力。
所以:
你看到的只是表象一致,而 URP 真正的强大之处是:
🔧 它的每一步都暴露了脚本可控的钩子点。
urp本质上是基于unity built-in 的一层调用的抽象上层吗
否。URP 并不是简单包裹 Unity Built-in 渲染管线的一层抽象,而是一个完全独立、底层直连 GPU 渲染 API 的自定义渲染框架。
❌ 所以 URP 并不是:
-
❌
Built-in Forward/Deferred
的“封装层” -
❌ 调用 Built-in 的渲染代码(URP 完全不会使用内置的
Camera.Render()
、LightMode = ForwardBase
等) -
❌ 自动复用 Built-in 的 Pass 或 ShaderLab 标签(它有自己约定的 Pass 名如
UniversalForward
)
Shader "URP/MyLit"
{Properties { ... }SubShader{Tags { "RenderPipeline" = "UniversalPipeline" }Pass{Name "ForwardLit"Tags { "LightMode" = "UniversalForward" }HLSLPROGRAM// URP 使用的 include(路径基于包结构)#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"// 你的输入输出结构体(结构与顶点片元一致)struct Attributes { ... };struct Varyings { ... };Varyings vert(Attributes v){// 顶点变换}half4 frag(Varyings i) : SV_Target{// 光照计算// half3 lighting = LightingPhysicallyBased(...);return half4(...);}ENDHLSL}}
}
迁移 Built-in 到 URP 的流程建议(Unlit 类)
-
URP 本身就提供一个叫
SRPDefaultUnlit
的渲染通道; -
无需处理任何光照或阴影;
-
不用引入
Lighting.hlsl
等头文件; -
可直接从 Unity 的 URP 官方模板或 Shader Graph 中学习。
📁 常用 URP HLSL Include 文件
文件 | 功能 |
---|---|
Core.hlsl | 提供基本常量、矩阵、宏 |
Lighting.hlsl | 提供主光源和附加光源计算函数 |
ShaderVariablesFunctions.hlsl | 提供 Fog、反射探针、阴影图采样等通用功能 |
Input.hlsl | 材质参数定义,如 baseColor , normalMap 等 |
-
用 ShaderGraph 建一个简单的 Unlit Shader(BaseColor + MainTex);
-
右键 → "Convert to HLSL"(需要插件或自己对照结构);
-
手动写一份像上面那样的 HLSL Shader;
-
在 Unity 中新建 Material,挂上你自己的 URP Unlit Shader;
-
给模型赋值测试。
Shader "URP/CustomUnlit"
{Properties{_BaseColor("Base Color", Color) = (1,1,1,1)_MainTex("Texture", 2D) = "white" {}}SubShader{Tags { "RenderPipeline" = "UniversalRenderPipeline" }LOD 100Pass{Name "Unlit"Tags { "LightMode" = "SRPDefaultUnlit" }HLSLPROGRAM#pragma vertex vert#pragma fragment frag#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"struct Attributes{float4 positionOS : POSITION;float2 uv : TEXCOORD0;};struct Varyings{float4 positionHCS : SV_POSITION;float2 uv : TEXCOORD0;};CBUFFER_START(UnityPerMaterial)float4 _BaseColor;CBUFFER_ENDTEXTURE2D(_MainTex);SAMPLER(sampler_MainTex);Varyings vert(Attributes IN){Varyings OUT;OUT.positionHCS = TransformObjectToHClip(IN.positionOS.xyz);OUT.uv = IN.uv;return OUT;}half4 frag(Varyings IN) : SV_Target{half4 col = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, IN.uv);return col * _BaseColor;}ENDHLSL}}
}
Standard Shader
和 Surface Shader
是的,你理解得非常准确。
✅
Standard Shader
和Surface Shader
都是 Unity 内置管线(Built-in Rendering Pipeline)中的“上层封装”层,它们不是底层的 Shader 本质,而是 Unity 提供的半自动化系统。
下面我们来逐一分解它们的本质和区别:
✅ 什么是 Surface Shader?
-
Surface Shader 是 Unity 的一套“自动生成底层光照计算代码”的语法糖封装。
-
你写一段结构化代码,比如:
#pragma surface surf Lambert void surf (Input IN, inout SurfaceOutput o) {o.Albedo = tex2D(_MainTex, IN.uv_MainTex).rgb; }
-
Unity 会在编译时根据你指定的光照模型(如 Lambert、BlinnPhong、Standard)自动生成多个 Pass,包括 ForwardBase、ShadowCaster、Meta 等。
🧠 本质上:你只写了“高层逻辑”,Unity 帮你生成了完整底层渲染逻辑。
✅ 什么是 Standard Shader?
-
Standard Shader 是 Unity 官方实现的一个完整 Shader 程序,用来支持 基于物理的渲染(PBR)。
-
它本身不是 Surface Shader,而是用 Unity 内部的复杂系统写出的 Shader(你不能用
#pragma surface
写出它)。 -
它集成了:
-
金属/粗糙度贴图
-
法线贴图
-
环境光反射(GI)
-
实时阴影
-
雾效、透明度、折射等等
-
-
你可以在 Graphics Settings 中看到它是“内置 PBR 材质的默认渲染器”
🧠 它其实是 Built-in 管线下的高级全能材质球封装实现,你不能直接修改源码。
在 URP/HDRP 中不能使用的原因
-
Surface Shader 是 Unity 编译器的一个专属预处理器规则,只对 Built-in 渲染器启用;
-
在 URP/HDRP 中,这套规则已被完全弃用(SRP 是显式管理所有 Pass);
-
同样,Standard Shader 也是为 Built-in Pipeline 编写的固定结构,不适用于 SRP。
对于同一个shader文件,unity是怎么识别出来要用哪个不同的渲染管线?还是说这是技术人员需要注意的事情
Unity 不会自动判断 Shader 属于哪个渲染管线,而是靠你在 Shader 文件中手动指定。
Unity 只识别一条线索:
👉 Shader 的 SubShader
区块中的 Tags { "RenderPipeline" = "xxx" }
SubShader
{Tags { "RenderPipeline" = "UniversalRenderPipeline" }...
}
这段 Tag 是唯一告诉 Unity:
"RenderPipeline" 值 | 意义 |
---|---|
无此标签 | 表示这是一个 Built-in 渲染管线专用 Shader(默认) |
"UniversalRenderPipeline" | 表示这是一个 URP Shader |
"HDRenderPipeline" | 表示这是一个 HDRP Shader |
所以这是技术人员需要显式注意和控制的
Unity 不会也不能自动判断你的 Shader 适用于哪个管线,必须由开发者写清楚。
是否自动识别 Shader 类型 | 答案 |
---|---|
Unity 会判断 Shader 是不是 URP 的? | ❌ 不会 |
Unity 会智能转换 Built-in Shader 到 URP 吗? | ❌ 不会,你需要重写或迁移 |
Unity 会报错提示吗? | ✅ 会提示“当前 RenderPipeline 找不到合适的 SubShader”,显示粉红色材质 |
果你想支持多个渲染管线怎么办?
你可以写多个 SubShader
,用不同的 RenderPipeline
标签:
Shader "MultiPipeline/MyShader"
{SubShader // Built-in{Tags { } // 没写就是 Built-in...}SubShader // URP{Tags { "RenderPipeline" = "UniversalRenderPipeline" }...}SubShader // HDRP{Tags { "RenderPipeline" = "HDRenderPipeline" }...}
}
你问的是:
🔍 Unity 会遍历 Shader 里多个 SubShader(比如 Built-in + URP + HDRP)来找匹配项,那这个识别过程对性能影响大吗?
不会对运行时性能造成可感知影响。
Unity 的渲染管线选择 Shader 的 SubShader 是在材质加载阶段完成一次判断,而不是每帧都判断、遍历。
为什么这个判断几乎没有性能影响?
✅ Unity 在运行时加载材质时:
-
Shader 被加载(包括多个
SubShader
) -
Unity 会从上到下顺序检查每个
SubShader
的Tags
-
如果当前的渲染管线(如 URP)与某个 SubShader 匹配,它就选中那个
-
-
一旦选中后,Unity 会将该 SubShader 编译并缓存下来(用于 GPU 使用)
📌 所以,这个匹配过程只在:
-
Shader/材质初次加载时
-
或者场景切换、Shader Variant Warmup 时发生一次
在运行时(Render Loop):
Unity GPU 渲染用的其实是 已经绑定好的 Pass
和 MaterialPropertyBlock
,不会再去判断 Shader 属于哪个 SubShader。换句话说:
多 SubShader 结构对运行帧率、DrawCall、GPU 性能没有影响。
⚠️ 有影响的情况是:Shader 编译和打包阶段
当你写了多个 SubShader,Unity 会:
-
在构建时生成多个 Shader Variant(因为每个 SubShader 可能有多个 Keywords + Pass)
-
如果你启用了多个渲染管线,还都引用了同一个 Shader 文件,就会让 Shader 编译时间和体积变大
✅ Unity 性能的关键指标分类总览:
性能维度 | 指标名称 | 意义 | 与 Shader/SubShader 是否直接相关 |
---|---|---|---|
CPU性能 | SetPass Calls | 材质或 Shader 切换的次数 | ✅ 强相关(多材质/Shader 会增加) |
Draw Calls | 渲染命令数(每个对象一次 draw) | ✅ 与 Shader 是否合批有关 | |
Batches | 合并后的实际渲染批次数 | ✅ 与 Shader 是否相同、是否开启 SRP Batcher 有关 | |
CPU Time (per frame) | 每帧主线程执行时长 | ✅ 若有大量 Shader 变体加载,会卡顿 | |
GPU性能 | GPU Frame Time | 每帧在 GPU 上渲染的时间 | ✅ 与 Shader 复杂度直接相关 |
Shader Complexity(像素填充率) | 每个像素执行多少指令 | ✅ 强相关 | |
Fragment Overdraw | 同一像素被重复绘制几次 | ✅ 和透明 Shader 结构有关 | |
Texture Samplers | Shader 中采样了多少贴图 | ✅ 一般不超过 16 个 Sampler | |
内存性能 | Shader Variant Count | 编译出的变体数量 | ✅ 多 SubShader / 多 Keywords 会爆炸增长 |
VRAM(GPU 内存占用) | 材质+纹理+Shader 占用的 GPU 内存 | ✅ 间接相关 |
✅ 如何监控这些性能指标?
工具 | 可以查看的性能指标 |
---|---|
Unity Profiler | CPU、GPU Frame Time、SetPass Calls、Draw Calls、Shader Compile Time |
Frame Debugger | 哪个材质绑定了哪个 Shader / Pass、Batches |
RenderDoc | 精确到 GPU shader 执行、采样次数、texture unit |
Profiler Analyzer / Memory Profiler | 纹理、材质、Shader 占用情况 |
URP Debug Window | SRP Batcher 状态、当前使用的 Pass、是否动态剔除 |
如果没有特殊处理,Shader 变体卡顿会在
🟡 每次重新进入场景 / 首次加载该材质使用的 Shader 时发生,
❗️而不是只发生一次、缓存后就永远消失。
Unity 默认不保存 Shader 变体的运行时编译缓存(不像某些游戏引擎会生成 .cache
文件),所以:
-
每次打开游戏,Shader Variant 的编译状态都是“干净”的;
-
一旦有材质加载了未编译的变体,就触发“热编译”卡顿。
场景 | 是否容易卡顿 |
---|---|
初次打开游戏,进入主场景 | ✅ 是(最多 Shader 被首次加载) |
主角换装,材质使用了不同关键词 | ✅ 是(URP 动态 Keyword 较多) |
切换时间状态,触发夜晚特效 | ✅ 是(新 Shader 变体) |
同一材质重复使用 | ❌ 不会卡(已被缓存) |
Unity 官方推荐的避免方法
1. 使用 Shader Variant Collection
你可以手动收集或自动生成所有使用到的 Shader 变体:
ShaderVariantCollection svc = ...;
svc.WarmUp(); // 在加载界面执行
📌 缺点:这个 .shadervariants
文件必须自己维护,否则不会涵盖全部。
2. 使用 Preload Shader 设置
在 Graphics Settings
中设置:
Always Included Shaders: [URP/Unlit, URP/Lit, etc.]
Preloaded Shaders: [填入你的重要 Shader]
✔ Unity 会在游戏启动时预热这些 Shader。
3. 减少变体数量(根治)
-
关闭无用 Keywords(通过 Shader Keywords 管理)
-
减少 SubShader + Pass 数量
-
合并材质 / 减少动态切换
原神启动时显示:“正在编译着色器,请稍等……”
这其实涉及到另一个层级的优化技术,和上面提到的那四项指标(Shader Variant Count、Warmup Time、Material Import Time、Editor Load Time)确实有交集,但又属于不同的工程阶段和控制策略。
原神这种“预编译提示”属于哪种阶段?
🔧 属于 运行时 Shader 预热 & 缓存系统(Runtime Shader Cache)
这种提示来自于:
-
游戏首次运行 / 更新版本后
-
检查本地是否已有缓存过的变体
-
如果没有,就提前 全量离线编译 或 后台编译常用变体
-
通常在主界面前的 Loading 页面集中完成
它和你上面提到的四个指标关系如下:
指标 | 是否相关 | 描述 |
---|---|---|
Shader Variant Count | ✅ 高度相关 | 编译着色器需要覆盖大量变体 |
Shader Warmup Time | ✅ 本质就是在统一预热 | 提前避免后面运行中卡顿 |
Material Import Time | ❌ 无直接关系 | 原神不会在 runtime 动态导入材质 |
Editor Load Time | ❌ 编辑器专属 | 与玩家运行无关 |
原神启动时的“正在编译着色器”提示,是为了集中预热 Shader Variant,避免运行中卡顿,和我们之前讲的四个指标中的
Shader Variant Count
和Shader Warmup Time
高度相关,但属于更高级的“游戏工程级解决方案”。
什么是 Shader 变体(Shader Variant)?
Shader Variant 是指:
同一个 Shader 文件,因不同 关键词(Keyword)组合、渲染管线平台、材质设置 组合而生成的 多个编译版本。
简单说:
你写了一个 Shader,但 Unity 在后台悄悄为你生成了几十、几百、几千甚至上万个实际可用的“版本”——这就是变体。