OptiScaler神经渲染色彩管线解析:OkLab色相校正与AP1色域压缩数学全解
【免费下载链接】OptiScaler_DLSSNR
OptiScaler bridges upscaling/frame gen across GPUs. Supports DLSS2+/XeSS/FSR2+ inputs, replaces native upscalers, enables FSR-FG/XeFG on non-FG titles. Supports Nukem mod for DLSSG-to-FSR3 FG. This fork adds support for neural rendering on dx12 games, more to come.
OptiScaler 的神经渲染(DLSS Neural Rendering)分支让 DLSS 5 的神经渲染模型可以跑在 DX12 游戏的超采样输出之上,而它画面"稳、不偏色"的秘密,就藏在一条精心设计的色彩管线里。这篇文章带你完整拆解这条管线的数学基础:白点归一化、软膝编码、双分支亮度比合成,以及 OkLab 色相校正与 AP1 色域压缩是如何联手保住画面色彩的。
一、为什么神经渲染需要一条色彩管线
神经渲染模型(nvngx_dlssnr.dll,NGX 特性 18)是在成品 sRGB 编码帧上训练出来的,它只认识 0..1 范围内、亮度有界的"成片"。但 OptiScaler 超采样器的输出是线性、开口无界的线性光缓冲——高光可以轻松超过 1,暗部数值可以接近千分之一。
直接把这样的帧喂给模型,等于让它看一张不存在的图片。所以整条管线做的事情可以概括为一句话:把线性帧"翻译"成模型认识的代理图像(proxy),模型回答后再"翻译"回原始帧的线性空间,并且翻译全程不能歪色。
所有相关参数都集中在菜单的 "DLSS Neural Rendering" 分组里(DlssNr_Menu.cpp),配置项则对应 Config.h 中标记为removable as one block的[DlssNr]区块。
二、管线全景:Encode → 模型 → Resolve
整条管线实现在一个预编译的 compute shader 里:dlssnr.hlsl,主机侧的常量缓冲定义在 DlssNr_Common.h(WhitePoint、TransferStrength、ColourStrength等)。运行模式枚举(DlssNr_Common.h):
| 模式 | 作用 |
|---|---|
Encode | 帧 → 代理图(归一化 + 编码) |
Resolve | 代理 + 模型答案 + 原始帧 → 合成最终帧 |
Downsample | 模型按更低分辨率工作时的代理降采样 |
Meter/Calibrate | 读取游戏曝光、标定缓冲尺度 |
合成阶段(resolve)的核心链路是:
- 白点归一化:整帧除以一个"白点"数值,把图片拉进 [0,1];
- 双分支亮度比合成:把模型答案按亮度比缩放回原始帧的亮度位置;
- OkLab 色相校正:防止缩放过程改写色相;
- 亮度比护栏 + 色彩强度混合:限制单帧波动、控制模型色彩介入程度;
- AP1 色域压缩:把越界颜色安全地拉回可显示范围。
三、白点归一化:给开口缓冲找一个"分母"
归一化的分母不是拍脑袋的常量。菜单里 "White point from" 提供三个来源(DlssNr_Menu.cpp):
- Paper white only:手动滑杆。不同游戏需要的数值差异巨大——Nioh 3 的线性缓冲峰值在两百左右,需要约 240 的分母,而 GTA V 的曝光算出来只要 2.7;
- The game's own exposure:直接读游戏自己维护的 1×1 曝光纹理(D3D12 下甚至在 shader 里实时读取,消除 3~4 帧的 CPU 读回延迟);
- A buffer the scan found:针对算出曝光却不传出来的游戏,由曝光扫描(DlssNr_ExposureScan.cpp)按形状匹配候选缓冲并锚定比例。
分母选错的后果很直观:偏小则帧永远归一化不掉,亮度比算出几百,OkLab 的立方根变换拿到远超设计范围的值——屏幕上就是一片绿偏。这也是为什么白点是整条管线的地基。
四、Encode 编码:软膝、Neutwo 与 Hybrid 三条曲线
归一化之后还要把帧编码进 [0,1] 的 sRGB 空间。这是"给模型看什么"的关键决策,gReversibleMode对应三个选项(dlssnr.hlsl):
🔹 软膝 SoftKnee(默认,Off)
亮度超过 0.75 后不再硬切,而是按0.75 + 0.25 × (1 − e^-(luma−0.75)/0.25)指数回卷,避免模型看到一片逐帧闪烁的平白;另外用"峰值通道整体缩放"替代逐通道截断,防止蓝色被截成青色(dlssnr.hlsl)。缺点是回卷把高光细节压进极窄的区间,模型根本分辨不了。
🔹 Neutwo 可逆代理
Neutwo(x) = x·rsqrt(x² + 1)把 [0, ∞) 无死区地映射到 [0, 1),高光层次完整保留且可精确反解。技巧同样是一个标量作用于峰值通道,三通道比例不变、色相不弯(dlssnr.hlsl)。代价是中间调也被压缩,柔光场景反而可能更差。
🔹 Hybrid(折中方案,推荐)
HybridCurve:0.75 以下恒等(中间调与 Off 完全一致),以上只对超出部分施加 Neutwo,拐点处一阶连续。一条在处处 ≥ Off 的曲线:既不留中间调损失,又拿回高光细节(dlssnr.hlsl)。
五、双分支亮度比:合成而不是相加
模型返回的不是一帧"差异",而是一张完整的图。早期版本把它当差值加到帧上,结果没有任何东西约束总和的落点——暖色主体可能带绿回来。现在的设计(dlssnr.hlsl)是把它当一张图,用亮度比拉回原始帧的亮度位置:
- 原始亮度 < 代理亮度(帧比代理暗):
ratio = originalLuma / proxyLuma,以帧自己的亮度为目标; - 原始亮度 > 代理亮度(帧有代理装不下的头room):
ratio = (modelLuma + (originalLuma − proxyLuma)) / modelLuma,把这部分真实亮度叠在模型答案之上而不是缩放掉,高光因此不会被压暗。
在此基础上还有两道保险:
- 暗部底限
kRatioFloor = 1/512:暗像素上微小的模型改动会产生巨大比值,底限让比值随亮度趋零平滑收敛到 1,消除"沸腾"噪块; - 最大比值护栏
boundedRatio = clamp(amplified, 1/guard, guard):强度大于 1 时通过对比值取幂来放大(而不是外推混合),保证结果始终被护栏约束,双向限幅避免暗部塌陷。
色彩强度(Colour strength)则做两件不同的事:0..1 时,在"仅亮度结果(游戏自己的色相 + 模型的明度)"与"完整模型色彩"之间插值——两个端点都是合法图片,中间点也是;大于 1 时进入过饱和模式,只在 OkLab 空间放大 a/b 分量(L 与色相保持不变),越界部分交给下一步 AP1 压缩滚出。
上图是色彩处理不当的典型症状(色调偏移、辉光丢失)。神经渲染管线的每一步设计,本质上都是在回答"如何避免这类偏色"。
六、OkLab 色相校正:色相从哪来,就往哪放
问题的根源:对一个 RGB 三元组做整体比例缩放不会改变色相,但把"差异"加上去会。缩放后的颜色再回混合时,色相可能漂移。OkLab 校正(HueOkLab,dlssnr.hlsl)的做法:
- 进 OkLab:线性 RGB → LMS(Bjorn Ottosson 公布的矩阵)→ 逐分量有符号立方根 → Lab(
ToOkLab,dlssnr.hlsl)。L 是亮度,a 轴是绿↔品红,b 轴是蓝↔黄; - 只借方向,不借幅度:从模型自己的颜色(correct)取色度方向
(a,b)/|chroma|,从缩放后的颜色(incorrect)只取色度模长|chroma|; - 回 RGB 并压色域:
ClampAp1(FromOkLab(...))。
一个容易被忽略的细节:方向必须先归一化再乘以模长,而不是用两个模长之比去缩放。后者要除以correctChroma且只能用"精确等于 0"来防护——一个接近灰的像素色度约 1e-7,会轻松绕开防护,把数值噪声放大成四千倍的饱和色。《仁王3》夜景大量近无彩色像素,正是这个 bug 的现场,表现为被误报为"绿色噪点"。
💡 归一化写法下,方向向量构造即单位长度,输出不可能超过
incorrectChroma——数值上天然有界。
七、AP1 色域压缩:把"不可能的颜色"拉回"可能的颜色"
合成可能产生负分量——那不是任何显示器能显示的颜色。早期实现是硬 clamp:转 AP1 → 逐通道max(0)→ 转回来。但对饱和像素做逐通道操作恰恰就是色相扭曲器:最先触墙的那个通道决定了其余通道的颜色。
现在的ClampAp1(dlssnr.hlsl)改用中性轴压缩:
- 用 Hunt-Pointer-Estevez LMS 基(基于 BT.709)表达颜色,并携带固定的 D65 适应状态(18% 灰);
- 计算同亮度的 D65 中性色——所有颜色被拉向的锚点;
- 求最大标量 s,使
neutral + (color − neutral) · s的每个通道都非负(dlssnr.hlsl); - 整个颜色乘这一个 s:色相原样保留,只有饱和度让步。
关键性质:所有分量非负时 s = 1,输出与输入逐位相同——安全到可以对每个像素无条件执行。色彩强度 >1 的过饱和路径同样依赖它:越界颜色在色域边界"滚落"为最大限度鲜艳但仍是真实颜色的结果,而不是拍平一片死白。
八、参数速查:这些数学对应菜单里的什么
| 菜单参数 | 对应管线步骤 | 建议 |
|---|---|---|
| White point from | 白点归一化 | 优先"游戏自己的曝光";没有就用扫描锚定 |
| Detail strength | 双分支合成的混合端点 | 0 = 超采样原样输出,1 = 模型完整图片 |
| Colour strength | OkLab 混合 + 过饱和 | 0 = 只拿模型的明度;>1 过饱和,边界处滚落 |
| Reversible proxy | SoftKnee / Neutwo / Hybrid 编码 | Hybrid + composed 兼顾中间调与高光 |
| Enlargement | 低分辨率模型答案的回放大方式 | 模型低于 100% 时选 Matched residual |
这些旋钮的完整说明(含每个参数的悬停帮助文本)都在 DlssNr_Menu.cpp。
九、小结
OptiScaler 神经渲染色彩管线的精髓可以浓缩成三条设计原则:
- 合成是比例,不是差值——模型答案是一张完整的图,用亮度比拉回正确位置,插值端点都是合法图片;
- 色相只借方向不借幅度——OkLab 空间里,缩放只改饱和度,色相永远来自模型自己的颜色;
- 越界靠中性轴压缩,不靠逐通道截断——AP1 压缩对合规像素逐位无损,只对越界像素让步饱和度。
顺带说明:这套色彩合成(双分支比值、OkLab 校正、中性轴压缩)源自 RenoDX 的 DLSS 5 插件(clshortfuse),OkLab 矩阵为 Bjorn Ottosson 公布常数,AP1/sRGB/PQ 变换为标准色彩科学,归属详见 RenoDX_ATTRIBUTION.txt,模块整体设计说明见 dlssnr/README.md。理解了这些数学,你就能明白为什么"强度 0 时画面逐位不变""色彩强度 0 时色相分毫不移"——它们不是巧合,而是管线的构造保证。
【免费下载链接】OptiScaler_DLSSNR
OptiScaler bridges upscaling/frame gen across GPUs. Supports DLSS2+/XeSS/FSR2+ inputs, replaces native upscalers, enables FSR-FG/XeFG on non-FG titles. Supports Nukem mod for DLSSG-to-FSR3 FG. This fork adds support for neural rendering on dx12 games, more to come.
相关推荐
Natron Color 节点组完全指南:色彩校正、OCIO 色彩管理与色彩空间转换
Natron Color 节点组完全指南:色彩校正、OCIO 色彩管理与色彩空间转换 导读 本文以 Natron 官方文档中的 Color 节点组( Docum
音视频视频图形学图像处理桌面应用LightCraft 色彩管线解剖:4096 级色调 LUT + OkLab,凭什么敢硬刚 Adobe 的闭源调色
LightCraft 色彩管线解剖:4096 级色调 LUT + OkLab,凭什么敢硬刚 Adobe 的闭源调色 LightCraft 是一个用纯 Rust
告别色彩偏差:Hyprland色彩校正全指南
告别色彩偏差:Hyprland色彩校正全指南 你是否曾遇到过显示器色彩失真的问题?同一图片在不同设备上显示效果迥异,专业设计工作中色彩还原度不足,观影时明暗细节
图形学操作系统
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考