自由学习记录(126)
本文探讨了现代软件AI集成模式与游戏引擎渲染技术的两个关键领域。在生产力软件方面,主流产品主要通过三种方式整合AI:Copilot助手模式(如Office)、原生功能嵌入(如Photoshop)和自动化工作流(如Zapier),这种交互方式正从传统UI操作转向意图驱动的自然语言交互。在游戏引擎方面,详细分析了Unity和Blender的渲染管线差异,特别是SceneColor/Depth纹理的生成


“后续 pass 对 depth 的读取方式(SRV)当前深度的存在形态(attachment/DSV)读取方式(SRV)不兼容不兼容conversion pass(Copy/Resolve/Prepass)Copy/Resolve/Prepass)Copy/Resolve/Prepass)Copy/Resolve/Prepass)Copy/Resolve/Prepass)conversion passFrame Debugger / RenderDoc 里验证
https://marketplace.microsoft.com/en-us/product/saas/wa200009404?tab=overview

Claude in Excel 并不是 Excel 本身升级,而是 Office 插件(Office Add-in)。它通过 Excel 的 JavaScript API 读取工作表数据,然后把数据发送给 Claude 模型处理,再把结果写回 Excel。
功能通常包括:
-
自动分析表格数据
-
生成公式
-
总结数据趋势
-
用自然语言操作 Excel
例如:
或者通过侧边栏直接提问。
本质上它相当于:
↓
插件 API
↓
LLM
↓
返回结果
所以技术上并不复杂,但产品价值很大,因为 Excel 是数据入口。
接下来回答你更关键的问题:是不是很多软件都“进化了”?
答案是:几乎所有主流生产力软件都在做同样的事情,而且大体有三种集成模式。
第一种是 Copilot 模式。
也就是软件内置一个 AI 助手,通过侧边栏或命令调用。
例如:
Microsoft 365 Copilot
-
Excel:数据分析、公式生成
-
Word:写文档、总结
-
PowerPoint:自动生成 PPT
-
Outlook:自动写邮件
Google Workspace 也有类似功能。
这种模式的特点是:
↓
自然语言
↓
软件 API
↓
AI 生成操作
用户不再直接操作复杂 UI。
第二种是 AI 原生功能嵌入。
不是聊天助手,而是直接改变软件功能。
例如:
Photoshop
-
Generative Fill
-
自动扩展画布
Figma
-
自动生成 UI
-
自动布局
Notion
-
自动生成文档
-
自动整理知识库
这些 AI 功能已经成为软件的一部分。
第三种是 AI 自动化工作流。
一些软件开始让 AI 控制整套操作流程,例如:
Zapier / Make / Airtable
AI 可以:
-
读取数据
-
写脚本
-
调用 API
-
自动生成报表
本质上是:
再说一个更大的行业变化:
软件的交互模式正在改变。
传统软件交互是:
AI 软件变成:
例如在 Excel 里,你可能直接说:
“找出销售增长最快的地区并画图”
AI 会自动:
-
分析数据
-
写公式
-
生成图表
这种模式有时被叫做 intent-driven interface(意图驱动界面)。
不过也要注意一个现实情况:
AI 集成的效果差异很大。
有些只是简单调用 LLM:
send to model
return text
功能其实比较浅。
而真正深度集成的系统需要:
-
深度 API
-
结构化数据访问
-
权限管理
-
自动执行能力
这也是为什么 Microsoft 和 Google 推 AI 很快,因为他们的软件本身是平台级系统。
如果把趋势再往前看 5 年,很可能会出现一种新的软件形态:
AI-native application。
也就是软件不再围绕 UI 设计,而是围绕 AI 设计。
结构会变成:
↓
AI planner
↓
调用软件模块
↓
完成任务
软件变成 一组可调用能力(capabilities)。
Goo / Eevee(你图里的 Screenspace Info)
-
“Scene Color”:更接近“当前渲染目标/帧缓冲里已经写进去的颜色”(可能是渲染进行到某个阶段时的 color buffer 采样)。
-
“Scene Depth”:更接近“当前渲染目标关联的 depth buffer(Z buffer)采样”。
Unity(URP/HDRP)
-
“Scene Color”通常对应的是一个显式生成的纹理资源,例如 URP 的
_CameraOpaqueTexture(或 HDRP 的类似颜色缓冲/历史缓冲)。
关键点:它不是“随时可读的 framebuffer”,而是管线在某个时刻把颜色拷贝/resolve 到一张“可采样的纹理”。 -
“Scene Depth”通常对应
_CameraDepthTexture(或 HDRP 的 depth pyramid / depth buffer 视图)。
同样:它往往需要 resolve/copy 或者 prepass,才能变成 shader 可采样的纹理。
最直观结论:Unity 的“SceneColor/Depth”更像“由渲染器调度生成的资源”,而 Goo 节点更像“在 Eevee 管线里提供对当前屏幕空间缓存的访问”。
Unity 最关键的差异是:同名的 “Scene Color/Depth”经常不是“全程实时可读”,而是“在一个固定节点抓取的快照”。
URP 典型是:
-
_CameraOpaqueTexture:通常在 Opaque 完成之后拷贝一份(是否包含天空盒、是否包含某些后处理前结果,取决于具体版本与设置;但核心是“某个固定时刻的 opaque 颜色快照”)。 -
_CameraDepthTexture:通常在 Opaque/Depth 生成之后(或 DepthPrepass 之后)可用。
DepthTexture 大多定义为“Opaque 深度”(透明通常不写进这张 depth,除非你额外做透明深度 pass)。以OpaqueTexture 大多定义为“Opaque 颜色”(透明通常在之后再叠加)。

DepthTexture 大多定义为“Opaque 深度”透明通常不写进这张 depth除非你额外做透明深度OpaqueTexture 大多定义为“Opaque 颜色”“屏幕空间边缘/遮挡//深度差”遇到:透明物体不在 depth 里,透明物体不在 depth 里透明物体不在 depth 里透明物体不在 depth 里透明物体不在 depth 里透明物体不在 depth 里透明物体不在 depth 里
透明物体不在depth里,也就是当取depth时,透明的物体不写入深度(判断是否透明?看渲染队列的顺序?记得是builtin的,好像srp不用渲染队列这个概念了?所以,看的是pass里填的Light tag是什么?)
Goo/Eevee:
-
取决于它接的是哪条内部 buffer 路径
很多 NPR 屏幕空间节点默认就是“场景已渲染结果/深度”(但透明合成是否已进来,要看 Eevee 的 blend/resolve 阶段以及 Goo 的节点接入点)透明合成是否已进来,要看 Eevee 的 blend/resolve 阶段以及 Goo 的节点接入点
透明合成是否已进来,要看 Eevee 的 blend/resolve 阶段以及 Goo 的节点接入点
所以物体默认都写入深度,如果一个材质透明的物体单独不想写入,可以通知depth buffer不要把自己写入
查阅goo engine的github,验证真实性
这个东西有深入的必要?goo blender 里的
Depth 编码差异:非线性、反转 Z、MSAA、以及空间定义工程里通常追求可控性 → 倾向线性化工程里通常追求可控性 → 倾向线性化NPR 节点网络里有时反而利用非线性当特性差异主要体现在:生成时机、包含对象集合、编码方式(尤其 depth)、以及颜色空间/动态范围。
Unity 常见情况:
-
深度是“硬件深度”(非线性,投影空间)
很多平台/管线采用 Reversed-Z(近处 1 远处 0)做差分/阈值判断,通常需要“线性化”到 eye-space depth 或 view-space Z,否则参数会随相机 near/far、投影矩阵剧烈变化。MSAA 时,depth resolve/copy 的行为会影响你拿到的是 per-sample 还是 resolved depth(通常是 resolved/单值),边缘会跟几何覆盖有关。
Goo/Eevee:
-
很多实现也是采样 GPU depth buffer(同样是非线性投影深度),但具体是否 reversed、范围、以及是否做过任何转换,要看 Goo 节点内部是否输出“原始 Z”还是“线性 Z”。
-
而且 Blender 的“View Position”输入让它先投影到屏幕 UV 再采样,这一点与你在 Unity 里自己算 screenUV 再 sample depth 的逻辑对应,但矩阵约定(右手/左手、NDC 深度范围、clip space)会不同。
不要看到“Depth”就直接 subtract;先确认编码(非线性/线性、是否 reversed)与空间定义(viewZ/ndcZ)。编码(非线性/线性、是否 reversed)编码(非线性/线性、是否 reversed)空间定义空间定义(viewZ/ndcZ)。可能是线性空间纹理(项目 Color Space = Linear),采样后再按 shader 约定处理。可能是 LDR 或 HDRURP 资产 HDR、相机、平台、后处理路径)。项目 Color Space = Linear采样后再按 shader 约定处理动态分辨率、TAA、上采样颜色纹理可能是“抖动后/缩放后”的结果screenUV 与实际像素对齐要非常谨慎。启用了动态分辨率、TAA、上采样颜色纹理可能是“抖动后/缩放后”的结果
unity urp启用了动态分辨率、TAA、上采样,颜色纹理可能是“抖动后/缩放后”的结果?里面的srp控制了什么?
unity这样的优化都没做吗,可信度存疑
Eevee 的 framebuffer 可能处于某种内部色彩管理/显示变换链路之中(取样点是在“场景线性”还是“显示变换后”要看接入点)。显示变换链路内部色彩管理/“场景线性”“显示变换后”NPR 节点有时更偏向“拿到已经接近最终显示的 scene color”,以便做描边/分色等艺术效果;但这取决于 Goo 的实现位置。Unity 里,如果你做depth(viewPosA) - depth(viewPosB)
常见坑是:你减的是非线性 depth,差值没有物理意义,阈值非常难调;正确做法通常是两者都线性化到 view-space depth 再比较。subtract 只是做一种“屏幕空间边缘响应”近似,并不表示真实距离差。NPR 中这常常是刻意利用非线性的“近处更敏感”的特性。参与的是 Transparent 渲染阶段,而这个阶段的 shader pass 默认(也通常应该)是 ZWrite Off。明物体之所以通常“不在 depth 里”透明物体“不在 depth核心原Transparent 渲染阶段shader pass 默认ZWrite Off渲染队列(Render Queue)仍然存在于 SRP渲染队列(Render Queue)仍然存在于 SRP渲染队列(Render Queue)仍然存SRP
渲染队列(Render Queue)仍然存在于 SRP
SRP 没有抛弃 Render Queue。Unity 里所有材质都有 material.renderQueue,并且 SRP 的排序/过滤仍然大量依赖 queue 范围(Opaque: 0~2499,Transparent: 3000~3999,常见默认)。URP 的 DrawObjectsPass 会用 FilteringSettings(RenderQueueRange.opaque / transparent) 过滤物体。
SRP 不看渲染队列了吗?不是,SRP 更依赖它
但 URP/HDRP 的默认实现仍是:
-
Opaque pass:RenderQueueRange.opaque
-
Transparent pass:RenderQueueRange.transparent
换句话说:Render Queue 在 SRP 不但没消失,反而是最稳定、最通用的过滤维度之一。
Light tag”Light tag”告诉 SRP:这个 pass 属于哪一种渲染阶段/用途绘制某个阶段时只会挑选匹配的 pass某个阶段时挑选匹配的 pass前向渲染颜色 passUniversalForward / UniversalForwardOnly:前向渲染颜色 pass
同一块 GPU memory 可以有不同 view:Depth buffer memory
├── DSV / DepthAttachment (写深度)
└── SRV / Texture (shader读取)
URP/HDRP 的调度模型是:
ShadowMap pass → 只找 LightMode=ShadowCaster
Opaque pass → 只找 UniversalForward / Lit
Transparent pass → 只找 Forward
shader 里写 10 个 pass 没意义
只有 pipeline stage 需要的 pass tag 才会被调度。

很多人把这两个混为一谈,这是第二个概念缺失。
shader pass ≠ pipeline pass两个混为一谈概念缺失

不是所有 attachment 都能直接作为 SRV

向下兼容不是一种道德施舍,而是一种协议封装(Protocol Encapsulation)。通过向下兼容,成功实现了系统的操作闭合(Operational Closure),既参与了社会交换,又防止了内部逻辑被平庸的噪声污染。现实物理空间中会产生巨大的负面反馈(如嫉妒、排挤、行政阻碍)。能效平衡:布尔迪厄(Pierre Bourdieu)**的场域理论看,直接的“拒绝”是一种过于赤裸的权力展示,容易引发阶层抵抗。直接的“拒绝”是一种过于赤裸的权力展示通过这种“兼容”建立了一道软性屏障在维持兼容话术的同时,已经在心理模型中完成了对该主体的逻辑降权。误认为这种兼容是“真实的认同”本身就是一种极度的不合群“反抗”这种平庸的能量都不屑于支付。PC immediate GPU 模型。
移动 GPU(Mali / PowerVR / Apple GPU)是:
流程:
在 tile 内:
如果 shader 想读取 depth texture:
这会导致:
所以 pipeline 宁可:
整个问题统一为一句话:
当某个 pass 需要以 SRV 方式读取 depth,而当前 depth 只存在于 attachment / tile memory / MSAA layout 中时,pipeline 必须插入一个 conversion pass(copy / resolve / prepass)。



但很多平台:
-
mobile
-
tile GPU
-
older Metal
没有直接 depth resolve path
或者 resolve 代价很高。
于是引擎常见策略:
而不是 resolve。
Tile GPU 深度 attachment 不能采样
图里的疑问:
tilegpu 不能?
更准确说法是:
Tile GPU 不允许在 tile memory 中直接被 shader 采样。
典型 tile 架构:
Mali
Apple GPU
PowerVR
渲染流程:
↓
tile memory
↓
resolve -> system memory
如果 depth attachment 还在 tile memory:
shader 无法 SRV 读取。
要采样 depth:
必须:
或者
这一步会触发:
带来巨大带宽。
所以引擎策略:
→ depth texture
→ 后续 pass SRV
而不是:
强制 DepthPrepass 的根本原因其实只有一个:
后续 pass 需要 depth SRV
而当前 depth 是:
产生 resource usage conflict
FrameGraph 需要选择一种转换:
可选路径:
ResolveDepth
DepthPrepass
引擎根据:
MSAA
tile GPU
bandwidth
选择一种。
Unity Manual 的直接说明
Unity 官方文档明确写到:
LightMode tag 的值决定 Render Pipeline 在不同阶段选择哪个 Pass 执行。 Unity Documentation+1
例如 URP 支持的 LightMode:
-
UniversalForward -
UniversalGBuffer -
ShadowCaster -
DepthOnly -
DepthNormalsOnly -
SRPDefaultUnlit -
Meta
每个值都对应 pipeline 的某个阶段。 Unity Documentation
二、DepthOnly / ShadowCaster 官方说明
Unity Manual 还直接给了例子:
要创建 depth prepass,需要添加
LightMode="DepthOnly"的 pass。 Unity Documentation
示例代码:
{
Name "DepthOnlyPass"
Tags { "LightMode"="DepthOnly" }
ZWrite On
ColorMask 0
}
文档说明:
这个 pass 在 camera depth texture 或 depth prepass 阶段被执行。
为什么 shader 写很多 pass 但只执行几个
这是 SRP 的核心设计:
Pipeline 不是执行 shader 的所有 pass,而是只挑符合 LightMode 的 pass。
流程类似:
DrawRenderers(filter = UniversalForward)
RenderDepthPrepass()
DrawRenderers(filter = DepthOnly)
RenderShadowMap()
DrawRenderers(filter = ShadowCaster)
也就是说:
而不是:
这是 SRP 和旧 Built-in Pipeline 的最大区别之一。
为什么 Unity 要这样设计
主要有三个原因。
1 RenderGraph / FrameGraph 风格调度
现代引擎(Unity SRP / UE RDG / Frostbite FG)都遵循:
↓
select shader pass
而不是:
否则 pipeline 无法控制:
-
depth prepass
-
shadow map
-
motion vector
-
SSAO depth normal
-
GBuffer

Shader 可以被多个阶段复用
例如同一个 shader:
ShadowCaster
UniversalForward
DepthNormals
Meta
不同阶段只执行需要的 pass。
典型例子:
-> ShadowCaster
camera depth prepass
-> DepthOnly
opaque shading
-> UniversalForward
图里的总结其实是简化模型:
它写成:
Opaque → UniversalForward
ShadowMap → ShadowCaster
但真实 pipeline 更复杂,例如:
URP 实际是:
filter = DepthOnly
OpaquePass
filter = UniversalForward / UniversalForwardOnly
ShadowPass
filter = ShadowCaster
DepthNormalPass
filter = DepthNormalsOnly
此外还存在:
Meta
GBuffer
所以“只找某个 pass”只是理解模型,不是完整实现。
SRP 的 draw call 是:
而不是:
DrawRenderers 内部逻辑是:
find shader pass with LightMode
所以:
pipeline 只挑1个
这就是你图里那句话:
只有pipeline stage需要的pass会被调度
的真实来源。

GPU 负责写入 buffer attachment
以 URP 为例,CPU 每帧大致做:
遍历摄像机、灯光、物体
做剔除、排序、批处理
决定是否要生成 _CameraDepthTexture
决定是走 Depth Prepass 还是 Copy Depth
生成一串 GPU 命令:先画谁、后画谁、写哪些 RT、用哪个 shader pass
所以你可以理解为:
SRP/URP 是 CPU 侧的调度规则
它规定“深度纹理什么时候产生、怎么产生、后续哪些 shader 能读到它”
GPU 真正生成 depth 的过程发生在光栅化阶段。
每个三角形送进 GPU 后:
顶点着色器把顶点变到裁剪空间
GPU 做三角形光栅化,得到覆盖到的像素
每个像素会有一个深度值
深度值写入 depth buffer
后续像素可以拿这个 depth 做测试或采样
所以:
Depth Buffer 是 GPU 渲染时自然产生的
_CameraDepthTexture 是 Unity/URP 把这个结果“整理成 shader 可读资源”的一种形式
depth 不是“某个 shader 算出来的特效值”,它首先是 GPU 渲染硬件的基础缓冲。---没错,基础缓冲,gpu本来就要的
你在 shader 里做 Depth Rim,本质在做什么
这时关系就是:
CPU / URP 先安排一张可读 depth texture
GPU 在前面的 pass 里把场景深度写进去
当前像素 shader 再去采样这个深度
把“当前像素深度”和“邻域/偏移位置深度”做比较
得到边缘、遮挡、接触线之类效果
所以这类效果本质是:
CPU/SRP 负责准备资源
GPU 负责生产和采样这些资源
shader 只是利用这些已有中间结果做计算
https://catlikecoding.com/unity/custom-srp/2-0-0/?utm_source=chatgpt.com#1
Catlike Coding 的 **Custom SRP 系列(包括 2.0.0 项目版)**是按“从最小可运行 pipeline → 逐步增加真实渲染系统组件”的顺序设计的。作者刻意按 真实渲染管线构建顺序讲解,而不是按功能模块分类。
先搭 pipeline skeleton → 再加入 rendering stages → 最后加入 feature systems。
基础框架阶段(Pipeline Skeleton)
目标:先让 SRP 能渲染任何东西。
顺序是:
-
Custom Render Pipeline
-
Camera Renderer
-
Command Buffer
-
Culling
-
Draw Geometry
最终效果:
→ CameraRenderer
→ Setup
→ Cull
→ DrawRenderers
→ Submit
这一阶段只实现:
-
SRPAsset
-
RenderPipeline
-
CameraRenderer
-
ScriptableRenderContext
-
CommandBuffer
也就是 SRP 的 最小工作版本。
例如只渲染:
-
skybox
-
unlit geometry
这个阶段的核心目的是理解:
CommandBuffer
DrawRenderers
SRP 的最核心三个 API。 CSDN Blog


https://discussions.unity.com/t/how-to-learn-the-srp/1661736


SRP 只是 调度框架,不是渲染算法
SRP 本质只做三件事:
CommandBuffer recording
Pass scheduling
真正复杂的是 renderer implementation。
例如 URP 的 Forward Renderer:
DepthPrepass
MainLightShadow
AdditionalLightShadow
DrawOpaque
Skybox
CopyDepth
DrawTransparent
PostProcess
FinalBlit
SRP 只是:
renderer.Execute()
所以 SRP 很容易理解,但 renderer 很复杂。


源码复杂的地方在:
platform abstraction
render graph integration
debug/editor systems
这些不属于渲染理论,而是 engine engineering。
为什么 Unity SRP 的架构其实和 DX12/Vulkan 的 modern renderer 架构并不完全一致。
很多 AAA 引擎已经变成:
Bindless
Mesh Shader
Indirect rendering
而 SRP 仍然偏:
更多推荐



所有评论(0)