当前位置: 首页 > news >正文

自由学习记录(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 ShaderBlender 材质系统
着色语言HLSL(或 ShaderLab 封装)Open Shading Language(Cycles) + Eevee 内建规则
着色管线Scriptable Render Pipeline (SRP) / Built-inEevee(实时) / Cycles(路径追踪)
材质结构Shader → Material → Renderer → MeshShader 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存储网格、骨骼、动画数据
用于 MMDRay-MMD 材质系统舞台/物体模型加载(非动画)
可编辑性纯文本脚本二进制/文本结构体,复杂难改
是否 Shader❌ 不是 Shader,只是映射表❌ 也不是 Shader,是几何数据


✅ 所以结论是:

  • .rayRay-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.fxray_MET.fx

控制器常见控制项:

  • 光源颜色与角度

  • 环境光/天空光颜色

  • SSAO 强度

  • Bloom 开关

  • 色调映射等

✅ 总结:

ray_controller.pmx 是 Ray-MMD 渲染参数的“面板入口”,你通过它实时调光、开关效果,体验完整的场景控制。

import 

✅ 模型和贴图文件不在同一个文件夹

PMX 模型引用的贴图路径是相对路径或硬编码路径,你导入时若贴图不在相对位置,Blender 就无法读取。

✅ 修复方法:
  • 把贴图文件(如 .png, .tga, .bmp)放到和 .pmx 同一目录或其 Texture 文件夹中

  • 然后重新导入 .pmx 模型

  • 或进入 Shader 编辑器手动绑定贴图(如下)

进入右侧的「材质(Material)面板」(红球图标)

格式定义者/软件内容包含可直接使用的软件
.pmxMikuMikuDance (MMD)骨骼、权重、动作、材质、物理(刚体/关节)、Morph 等MMD, Blender(通过 MMDTools 插件)
.fbxAutodesk模型、骨骼、动画、材质信息(不总含贴图)Unity、Blender、Unreal 等
.obj通用格式仅模型网格(无动画、无骨骼),可配 .mtl 贴图信息Unity、Blender、3dsMax、Maya 等

如何在其他软件中使用 .pmx

▶ Blender
  • 需安装 MMD Tools 插件

  • 可以导入 .pmx.vmd(动作)、.vpd(姿势)

  • 可修改模型后导出为 .fbx(用于 Unity)

▶ Unity
  • 没有官方支持 .pmx 的插件

  • 通常流程是:

    1. 用 Blender + MMD Tools 打开 .pmx

    2. 整理模型骨骼/贴图/动画

    3. 导出为 .fbx

    4. 再导入 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 ModeImport via Material Description尝试使用 FBX 文件中嵌入的材质信息✅ Unity 会试图读取 FBX 内的材质引用,但如果 FBX 中没写贴图路径,就只创建空材质
LocationUse Embedded Materials直接使用 FBX 文件中的嵌入材质(不生成外部材质球)⚠️ 贴图不会单独暴露出来,Unity 无法自动匹配资源库中的贴图
MaterialsExtract Materials...(按钮)可点击导出 FBX 中的材质为 .mat 材质球✅ 如果你想修改/查看材质,建议点这个先提取出来再绑定贴图


📌 当前 Unity 无法自动绑定贴图的原因是:

  1. FBX 文件没有包含贴图路径或贴图本身(如有路径,也可能是绝对路径不匹配)

  2. 你设置为 Use Embedded Materials → 不生成 Unity 可管理的 .mat 材质文件

  3. 所以 Remapped Materials 显示为 None(空材质),也无法自动匹配贴图

① 点击右侧 “Extract Materials…” 按钮

  • 将 FBX 内嵌的材质球提取出来为 .mat 文件

  • 推荐选择提取到同目录或 Assets/Materials 子目录中

⚠️ FBX 导入设置中的 Extract MaterialsExtract 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 并检查材质结构。

🧭 操作流程:

  1. 打开 Blender(推荐用 3.0+ 版本)

  2. 菜单栏 File → Import → FBX (.fbx)

  3. 导入你的 VergilDmCV.fbx

  4. 选中模型,切换右侧 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 文件格式,而是:

  1. 背后调用你电脑上安装的 Blender(命令行模式)

  2. .blend 文件自动转换为 .fbx 临时缓存文件

  3. 再按照 .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)

如果你想尽可能“等价迁移”:

  1. Blender: 材质只保留基础贴图(BaseColor、Normal、Metallic 等)和命名,不搞复杂节点连接

  2. 导出 FBX 时:

    • 贴图用相对路径或嵌入

    • 保留材质名

  3. 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 包”才能修改?

📁 操作步骤(实际执行):

  1. 找到项目文件夹的这个目录(非 Assets):

    Library/PackageCache/com.unity.render-pipelines.universal@版本号/

  2. 将它复制到你的项目根目录的 Packages/ 目录里:

    YourProject/ ├── Assets/ ├── Packages/ │ └── com.unity.render-pipelines.universal/

  3. 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 内部流程自动调用明确由 MainLightShadowCasterPassAdditionalLightsShadowCasterPass 管理
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 BlitUnity 自动将渲染结果输出到屏幕FinalBlitPass.cs 显式控制 Blit

URP 的核心优势(区别于内置管线)

  1. 全流程可视化、可插拔(Passes/Feature)

    • 你可以随时在任意阶段插入自定义处理逻辑,而内置管线几乎不可控。

  2. 每一个渲染阶段都由 C# 控制类调度

    • UniversalRenderPipeline.csUniversalRenderer.cs 是总控。

    • 每个阶段的具体执行由一个 ScriptableRenderPass 管理,执行顺序通过 RenderPassEvent 控制。

  3. Renderer Feature 可扩展性极强

    • 用户可以在特定阶段插入自己的 Blit、Draw、Compute 等逻辑。

  4. 跨平台一致性好

    • 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
  1. 用 ShaderGraph 建一个简单的 Unlit Shader(BaseColor + MainTex);

  2. 右键 → "Convert to HLSL"(需要插件或自己对照结构);

  3. 手动写一份像上面那样的 HLSL Shader;

  4. 在 Unity 中新建 Material,挂上你自己的 URP Unlit Shader;

  5. 给模型赋值测试。

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 ShaderSurface Shader

是的,你理解得非常准确。

Standard ShaderSurface 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 在运行时加载材质时:

  1. Shader 被加载(包括多个 SubShader

  2. Unity 会从上到下顺序检查每个 SubShaderTags

    • 如果当前的渲染管线(如 URP)与某个 SubShader 匹配,它就选中那个

  3. 一旦选中后,Unity 会将该 SubShader 编译并缓存下来(用于 GPU 使用)

📌 所以,这个匹配过程只在:

  • Shader/材质初次加载时

  • 或者场景切换、Shader Variant Warmup 时发生一次

在运行时(Render Loop):

Unity GPU 渲染用的其实是 已经绑定好的 PassMaterialPropertyBlock,不会再去判断 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 SamplersShader 中采样了多少贴图✅ 一般不超过 16 个 Sampler
内存性能Shader Variant Count编译出的变体数量✅ 多 SubShader / 多 Keywords 会爆炸增长
VRAM(GPU 内存占用)材质+纹理+Shader 占用的 GPU 内存✅ 间接相关

✅ 如何监控这些性能指标?

工具可以查看的性能指标
Unity ProfilerCPU、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 WindowSRP 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 CountShader Warmup Time 高度相关,但属于更高级的“游戏工程级解决方案”。

什么是 Shader 变体(Shader Variant)?

Shader Variant 是指:
同一个 Shader 文件,因不同 关键词(Keyword)组合渲染管线平台材质设置 组合而生成的 多个编译版本

简单说:

你写了一个 Shader,但 Unity 在后台悄悄为你生成了几十、几百、几千甚至上万个实际可用的“版本”——这就是变体。

http://www.dtcms.com/a/263637.html

相关文章:

  • JT808教程:消息的结构
  • react中在Antd3.x版本中 Select框在单选时 选中框的高度调整
  • Qt 实现Opencv功能模块切换界面功能
  • 【算法】动态规划:python实现 1
  • TensorFlow内核剖析:分布式TensorFlow架构解析与实战指南
  • mini-electron使用方法
  • 内部类与Lambda的衍生关系(了解学习内部类,Lambda一篇即可)
  • C# WPF + Helix Toolkit 实战:用两种方式打造“六面异色立方体”
  • QNN SDK学习笔记
  • 二十八、【环境管理篇】灵活应对:多测试环境配置与切换
  • python开发|yaml用法知识介绍
  • STM32F4操作内部FLASH简洁版
  • 【代码审计】安全审核常见漏洞修复策略
  • 位运算经典题解
  • 启用不安全的HTTP方法
  • 图像处理专业书籍以及网络资源总结
  • Java编程之状态模式
  • 《UE5_C++多人TPS完整教程》学习笔记40 ——《P41 装备(武器)姿势(Equipped Pose)》
  • 基于Socketserver+ThreadPoolExecutor+Thread构造的TCP网络实时通信程序
  • mac重复文件清理,摄影师同款清理方案
  • flv.js视频/直播流测试demo
  • 2025 推理技术风向标:DeepSeek-R1 揭示大模型从 “记忆” 到 “思考” 的进化路径
  • 【linux】基础开发工具(1)
  • Flink Savepoints 总结
  • js代码09
  • Spring Boot WebSocket方案终极指南:Netty与官方Starter对比与实践
  • MFC的List Control自适应主界面大小
  • Android Gradle 插件和 Android Studio 兼容性
  • Windows下配置Docker+WSL集成开发环境
  • 【C#】如果有一个数值如 168.0000100,如何去除末尾的无效零,只显示有效的小数位数,让DeepSeek给我们解答