一维高斯(Gaussian / 正态分布)
密度函数的两处 σ
一维高斯的概率密度函数(PDF):
f ( x ) = 1 2 π σ exp ( − x 2 2 σ 2 ) f(x) = \frac{1}{\sqrt{2\pi}\,\sigma} \exp\!\left(-\frac{x^2}{2\sigma^2}\right) f ( x ) = 2 π σ 1 exp ( − 2 σ 2 x 2 )
σ \sigma σ (标准差)在式子里出现两次,作用不同:
指数里的 2 σ 2 2\sigma^2 2 σ 2 :管宽度。x = ± σ x = \pm\sigma x = ± σ 处函数值降到峰值的 e − 1 / 2 ≈ 0.607 e^{-1/2} \approx 0.607 e − 1/2 ≈ 0.607 ,σ \sigma σ 越大衰减越慢,曲线越胖。
前面的系数 1 / ( 2 π σ ) 1/(\sqrt{2\pi}\sigma) 1/ ( 2 π σ ) :管高度。峰值就在 x = 0 x=0 x = 0 ,大小正好是 1 / ( 2 π σ ) 1/(\sqrt{2\pi}\sigma) 1/ ( 2 π σ ) 。
两处 σ \sigma σ 互相绑定不是巧合:这条曲线下的总面积被归一化为 1。宽度翻倍(σ × 2 \sigma \times 2 σ × 2 ),高度必须减半,否则面积守恒不成立。所以”σ 大,曲线又矮又胖”是归一化的直接推论。
容易混淆:σ 还是 σ²
方差(variance)是 σ 2 \sigma^2 σ 2 ,标准差是 σ \sigma σ 。指数里写的是 2 σ 2 2\sigma^2 2 σ 2 ,即方差。这个区别到三维会变成:协方差矩阵的特征值 λ \lambda λ 对应 σ 2 \sigma^2 σ 2 ,半轴长 a a a 对应 σ \sigma σ ,两者是平方关系 (λ = a 2 \lambda = a^2 λ = a 2 )——这是后面所有形状计算的符号约定,记错就开错根号。
3DGS 用的高斯不归一化
注意一个本系列的关键事实:3DGS 里的三维高斯不带前面的归一化系数 ,直接写
G ( x ) = exp ( − 1 2 ( x − μ ) T Σ − 1 ( x − μ ) ) G(x) = \exp\!\left(-\tfrac{1}{2}(x-\mu)^T\,\Sigma^{-1}\,(x-\mu)\right) G ( x ) = exp ( − 2 1 ( x − μ ) T Σ − 1 ( x − μ ) )
中心处值恒为 1,胖瘦全由 Σ \Sigma Σ 决定。它不再表示概率密度,而是一个”空间影响力场”:每个高斯对周围像素的贡献还要乘上不透明度 o o o 。归一化系数被扔掉,是因为渲染时根本不需要面积守恒——浓淡由 o o o 单独控制,解耦更干净。
参考
从曲线到椭球:等值面为何是椭球
多维高斯的一般形式
d d d 维高斯(unnormalized,3DGS 用的形式):
G ( x ) = exp ( − 1 2 ( x − μ ) T Σ − 1 ( x − μ ) ) G(\mathbf{x}) = \exp\!\left(-\tfrac{1}{2}(\mathbf{x}-\mu)^T\,\Sigma^{-1}\,(\mathbf{x}-\mu)\right) G ( x ) = exp ( − 2 1 ( x − μ ) T Σ − 1 ( x − μ ) )
μ ∈ R d \mu \in \mathbb{R}^d μ ∈ R d :中心位置
Σ ∈ R d × d \Sigma \in \mathbb{R}^{d\times d} Σ ∈ R d × d :协方差矩阵(covariance matrix),对称正定
指数里的二次型 ( x − μ ) T Σ − 1 ( x − μ ) (\mathbf{x}-\mu)^T\Sigma^{-1}(\mathbf{x}-\mu) ( x − μ ) T Σ − 1 ( x − μ ) 叫马氏距离(Mahalanobis distance)的平方 ,它把”离中心多远”按各方向的散开程度做了归一
横切一刀:等值线的形状
在高度 h h h 处横切,即解 G ( x ) = h G(\mathbf{x}) = h G ( x ) = h 。两边取对数:
( x − μ ) T Σ − 1 ( x − μ ) = − 2 ln h (\mathbf{x}-\mu)^T\,\Sigma^{-1}\,(\mathbf{x}-\mu) = -2\ln h ( x − μ ) T Σ − 1 ( x − μ ) = − 2 ln h
左边是 x \mathbf{x} x 的二次型,右边是常数——这正是中心在 μ \mu μ 的椭球(二维时是椭圆)的标准方程 。
二维:同心椭圆,所有等高线形状相同,只是整体缩放
三维:同心椭球(等值面,isosurface)
切得越低(h h h 越小),右边常数越大,椭球越大
“切出一圈圈同心椭圆”不是动画的艺术处理,是二次型等值面的必然结果:高斯的等值面永远是椭球 ,区别只在大小。
三根主轴从哪来
椭球的形状(朝向 + 三根半轴长)完全由 Σ − 1 \Sigma^{-1} Σ − 1 决定,而 Σ − 1 \Sigma^{-1} Σ − 1 与 Σ \Sigma Σ 共享特征向量、特征值互为倒数。所以读懂一个高斯的形状,归结为读懂 Σ \Sigma Σ 的特征分解——特征向量给方向,特征值给轴长(的平方)。这是下一块的内容。
易错点
等值面方程里是 Σ − 1 \Sigma^{-1} Σ − 1 ,不是 Σ \Sigma Σ 。直接看 Σ \Sigma Σ 的元素猜形状容易反掉:方差大的方向,等值面反而拉得长——λ \lambda λ 大 → Σ − 1 \Sigma^{-1} Σ − 1 该方向分量小 → 要跑更远才凑够常数 → 轴更长。结论一致,但推导要过一遍倒数。
椭球是”等值面”,不是高斯的”边界” 。高斯在全空间都非零,没有硬边界;渲染时看到的椭球轮廓来自截断(如 2.83 σ 2.83\sigma 2.83 σ 或 3 σ 3\sigma 3 σ 处砍掉),属于实现策略,不是数学定义。
特征分解(Eigendecomposition)= 主轴说明书
谱定理
任何实对称矩阵都能正交对角化。协方差矩阵 Σ \Sigma Σ 是 3 × 3 3\times3 3 × 3 实对称(半正定)矩阵,所以:
Σ = R d i a g ( λ 1 , λ 2 , λ 3 ) R T \Sigma = R\,\mathrm{diag}(\lambda_1, \lambda_2, \lambda_3)\,R^T Σ = R diag ( λ 1 , λ 2 , λ 3 ) R T
R R R :正交矩阵(R T R = I R^TR = I R T R = I ),三个特征向量 按列排进去,就是椭球三根主轴的方向
λ i \lambda_i λ i :特征值 ,实数且非负
习惯上按 λ 1 ≥ λ 2 ≥ λ 3 \lambda_1 \ge \lambda_2 \ge \lambda_3 λ 1 ≥ λ 2 ≥ λ 3 排序,长轴对应 λ 1 \lambda_1 λ 1
几何读法:先把标准球沿坐标轴按 λ i \sqrt{\lambda_i} λ i 拉伸(d i a g \mathrm{diag} diag ),再用 R R R 整体旋转——R R R 管朝向,λ \lambda λ 管胖瘦。
为什么特征值是半轴长的”平方”
等值面方程(见上一块)是 ( x − μ ) T Σ − 1 ( x − μ ) = k 2 (\mathbf{x}-\mu)^T\Sigma^{-1}(\mathbf{x}-\mu) = k^2 ( x − μ ) T Σ − 1 ( x − μ ) = k 2 。沿第 i i i 个特征向量方向 v i \mathbf{v}_i v i 走距离 t t t ,代入 Σ − 1 v i = λ i − 1 v i \Sigma^{-1}\mathbf{v}_i = \lambda_i^{-1}\mathbf{v}_i Σ − 1 v i = λ i − 1 v i :
t 2 ⋅ 1 λ i = k 2 ⇒ t = k λ i t^2 \cdot \frac{1}{\lambda_i} = k^2 \quad\Rightarrow\quad t = k\sqrt{\lambda_i} t 2 ⋅ λ i 1 = k 2 ⇒ t = k λ i
即第 i i i 根半轴的长度 a i = k λ i a_i = k\sqrt{\lambda_i} a i = k λ i (k k k 是等值面高度参数)。固定 k k k ,半轴长 a i = λ i a_i = \sqrt{\lambda_i} a i = λ i ,也就是 λ i = a i 2 \lambda_i = a_i^2 λ i = a i 2 。
本系列的符号约定正是据此定的:λ \lambda λ 对一维高斯里的 σ 2 \sigma^2 σ 2 (方差),a a a 对 σ \sigma σ (标准差)。写 Σ = R d i a g ( a 2 ) R T \Sigma = R\,\mathrm{diag}(a^2)\,R^T Σ = R diag ( a 2 ) R T 时,d i a g \mathrm{diag} diag 里放的是轴长的平方,不是轴长。
“Σ 不描述点在哪”
Σ \Sigma Σ 只编码”往哪个方向、散开多远”——形状与朝向。位置信息全在 μ \mu μ 里。把椭球整体平移,Σ \Sigma Σ 一个数都不变。这也解释了为什么 3DGS 把位置 μ \mu μ 和形状参数(q q q 、s s s )分成两组独立存储、独立优化。
易错点
特征值非负 ≠ 特征值是轴长 。λ = a 2 \lambda = a^2 λ = a 2 ,开根号才是轴长。看到 λ 1 = 0.09 \lambda_1 = 0.09 λ 1 = 0.09 就说”半轴 0.09”是常见口误,实际是 0.3 0.3 0.3 。
R R R 的列才是特征向量 。有些教材按行写、有些按列写,本系列统一:R R R 的第 i i i 列 = 第 i i i 根主轴方向的单位向量。
反过来用:给一个椭球,量出三根主轴方向排成 R R R 、半轴长平方排成 d i a g ( a 2 ) \mathrm{diag}(a^2) diag ( a 2 ) ,就合成了 Σ \Sigma Σ ——这正是 3DGS 的存储方式(B08 展开)。
参考
手算:绕 z 轴转 45°
题目设定
二维椭球,两根半轴沿 x x x 、y y y ,轴长 a 1 = 0.3 a_1 = 0.3 a 1 = 0.3 m、a 2 = 0.1 a_2 = 0.1 a 2 = 0.1 m。初始协方差是对角阵(特征值 = 轴长平方):
Σ = d i a g ( 0.3 2 , 0.1 2 ) = ( 0.09 0 0 0.01 ) \Sigma = \mathrm{diag}(0.3^2,\ 0.1^2) = \begin{pmatrix} 0.09 & 0 \\ 0 & 0.01 \end{pmatrix} Σ = diag ( 0. 3 2 , 0. 1 2 ) = ( 0.09 0 0 0.01 )
绕 z z z 轴转 θ = 45 ° \theta = 45° θ = 45° ,旋转矩阵 c = cos θ c = \cos\theta c = cos θ 、s = sin θ s = \sin\theta s = sin θ ,此处 c = s = 2 2 ≈ 0.707 c = s = \frac{\sqrt2}{2} \approx 0.707 c = s = 2 2 ≈ 0.707 :
R = ( c − s s c ) R = \begin{pmatrix} c & -s \\ s & c \end{pmatrix} R = ( c s − s c )
搬运律:Σ′ = R Σ Rᵀ
旋转一个分布,协方差按 Σ ′ = R Σ R T \Sigma' = R\,\Sigma\,R^T Σ ′ = R Σ R T 变换(这就是 B08 参数化里同一条式子的逆用)。逐项展开,对角元素:
Σ 11 ′ = c 2 λ 1 + s 2 λ 2 = 0.5 ( 0.09 + 0.01 ) = 0.05 \Sigma'_{11} = c^2\lambda_1 + s^2\lambda_2 = 0.5\,(0.09 + 0.01) = 0.05 Σ 11 ′ = c 2 λ 1 + s 2 λ 2 = 0.5 ( 0.09 + 0.01 ) = 0.05
非对角元素:
Σ 12 ′ = c s ( λ 1 − λ 2 ) = 0.5 ( 0.09 − 0.01 ) = 0.04 \Sigma'_{12} = cs\,(\lambda_1 - \lambda_2) = 0.5\,(0.09 - 0.01) = 0.04 Σ 12 ′ = cs ( λ 1 − λ 2 ) = 0.5 ( 0.09 − 0.01 ) = 0.04
于是:
Σ ′ = ( 0.05 0.04 0.04 0.05 ) \Sigma' = \begin{pmatrix} 0.05 & 0.04 \\ 0.04 & 0.05 \end{pmatrix} Σ ′ = ( 0.05 0.04 0.04 0.05 )
旋转把对角阵转出了非零的非对角项——非对角元素的出现只说明主轴不再对齐坐标轴 ,不代表形状变了。
验算:特征值原封不动
对 ( p q q p ) \begin{pmatrix} p & q \\ q & p \end{pmatrix} ( p q q p ) 这种对称阵,特征值就是 p ± q p \pm q p ± q (特征向量沿 45 ° 45° 45° 与 − 45 ° -45° − 45° ):
λ 1 ′ = 0.05 + 0.04 = 0.09 , λ 2 ′ = 0.05 − 0.04 = 0.01 \lambda'_1 = 0.05 + 0.04 = 0.09, \qquad \lambda'_2 = 0.05 - 0.04 = 0.01 λ 1 ′ = 0.05 + 0.04 = 0.09 , λ 2 ′ = 0.05 − 0.04 = 0.01
与最初的 0.09 0.09 0.09 、0.01 0.01 0.01 完全一致。旋转只换了特征向量(方向),特征值(轴长平方)不动。
更快的核验:两个旋转不变量
不用解特征方程,两步心算就能确认没算错:
迹不变 :t r Σ ′ = 0.05 + 0.05 = 0.10 = 0.09 + 0.01 \mathrm{tr}\,\Sigma' = 0.05 + 0.05 = 0.10 = 0.09 + 0.01 tr Σ ′ = 0.05 + 0.05 = 0.10 = 0.09 + 0.01 (特征值之和守恒)
行列式不变 :det Σ ′ = 0.05 2 − 0.04 2 = 0.0009 = 0.09 × 0.01 \det\Sigma' = 0.05^2 - 0.04^2 = 0.0009 = 0.09 \times 0.01 det Σ ′ = 0.0 5 2 − 0.0 4 2 = 0.0009 = 0.09 × 0.01 (特征值之积守恒)
相似变换 R Σ R T R\Sigma R^T R Σ R T 保持全部特征值,迹和行列式只是其中最好算的两个。手推协方差变换后先查这两条,能抓住绝大多数抄错/算错。
易错点
搬运方向 :把坐标系旋转和把物体旋转用反,会得到 Σ ′ = R T Σ R \Sigma' = R^T\Sigma R Σ ′ = R T Σ R ,数值巧合时(如此例的 45 ° 45° 45° )看不出来,换 30 ° 30° 30° 就翻车。本系列统一:物体转 R R R ,协方差左乘 R R R 右乘 R T R^T R T 。
c s = 0.5 cs = 0.5 cs = 0.5 只在 45 ° 45° 45° 成立 。一般角度 Σ 12 ′ = c s ( λ 1 − λ 2 ) = 1 2 sin 2 θ ( λ 1 − λ 2 ) \Sigma'_{12} = cs(\lambda_1-\lambda_2) = \tfrac12\sin 2\theta\,(\lambda_1-\lambda_2) Σ 12 ′ = cs ( λ 1 − λ 2 ) = 2 1 sin 2 θ ( λ 1 − λ 2 ) ,别背成定值。
一个高斯,十四个数
参数清单
组 记号 个数 存储形式 使用前 位置 μ \mu μ 3 世界坐标,米 直接用 旋转 q q q 4 四元数(quaternion) 归一化后转 R ( q ) R(q) R ( q ) 尺度 s s s 3 对数尺度 (log-scale)a = e s a = e^s a = e s 还原线性轴长不透明度 o o o 1 logit 过 sigmoid 得 α ∈ ( 0 , 1 ) \alpha \in (0,1) α ∈ ( 0 , 1 ) 颜色 SH-DC 3 球谐直流分量 c = 0.5 + C 0 ⋅ f d c c = 0.5 + C_0 \cdot f_{dc} c = 0.5 + C 0 ⋅ f d c
合计 3 + 4 + 3 + 1 + 3 = 14 3+4+3+1+3 = 14 3 + 4 + 3 + 1 + 3 = 14 。这是本系列一个高斯的”最小完备描述”(完整版还有 45 个高阶球谐系数,颜色展开到 3 阶时一个高斯共 59 个参数,EP07 展开)。
为什么一半参数都”存的不是用的”
三个参数组在硬盘里都是编码形式 ,使用前各过一次解码:
尺度存对数 :s = ln a s = \ln a s = ln a ,还原 a = e s a = e^s a = e s 。对数映射把 ( 0 , + ∞ ) (0, +\infty) ( 0 , + ∞ ) 摊平到整个实数轴,优化器怎么改 s s s ,a a a 恒为正。实测 PLY 文件里 scale_0..2 字段存的就是 s s s (对数值可正可负,如 s = − 1 ⇒ a = e − 1 ≈ 0.37 s=-1 \Rightarrow a = e^{-1} \approx 0.37 s = − 1 ⇒ a = e − 1 ≈ 0.37 ),加载端必须 exp 还原——认错了轴长差出数量级。
不透明度存 logit :o = l o g i t ( α ) = ln α 1 − α o = \mathrm{logit}(\alpha) = \ln\frac{\alpha}{1-\alpha} o = logit ( α ) = ln 1 − α α ,还原 α = σ ( o ) = 1 1 + e − o \alpha = \sigma(o) = \frac{1}{1+e^{-o}} α = σ ( o ) = 1 + e − o 1 。同理把 ( 0 , 1 ) (0,1) ( 0 , 1 ) 区间摊平到实数轴,保证不透明度永远落在合法范围。实测 PLY 里 o p a c i t y = − 2.197 \mathrm{opacity} = -2.197 opacity = − 2.197 对应 α = 0.1 \alpha = 0.1 α = 0.1 。
颜色存原始 SH 系数 :f d c f_{dc} f d c 是加 0.5 0.5 0.5 偏移之前 的系数,显示时才算 c = 0.5 + C 0 ⋅ f d c c = 0.5 + C_0 \cdot f_{dc} c = 0.5 + C 0 ⋅ f d c (B10 展开)。
共同动机:把有约束的量(正数、( 0 , 1 ) (0,1) ( 0 , 1 ) 区间)编码成无约束的实数 ,梯度下降随便走都不会越界。这是整条参数化设计的同一个套路。
七个数管形状,多出的一个是伏笔
形状 = 3 个轴长 + 3 个旋转自由度 = 6 个自由度,却存了 4 + 3 = 7 4+3=7 4 + 3 = 7 个数。多出的那个是四元数的冗余:∥ q ∥ = 1 \|q\| = 1 ∥ q ∥ = 1 的约束吃掉一个自由度,4 个数实际只表达 3 个旋转自由度。为什么甘愿多存一个?——这是 B08 的主题(Q1)。
易错点
s s s 和 a a a 是两个记号、两种数 :s s s 是对数(硬盘里的),a = e s a = e^s a = e s 是线性轴长(合成 Σ \Sigma Σ 用的)。全系列一词一义,读代码读文件时先确认手里是哪个。
o o o 不是 α \alpha α :o o o 是 logit,直接当透明度乘进渲染就错了,必须先过 sigmoid。
七数 vs 六数:为什么不直接优化协方差
六数方案的诱惑与陷阱
3 × 3 3\times3 3 × 3 对称矩阵只有 6 个独立元素(3 对角 + 3 非对角),比七数方案省一个数、还不用管任何约束。问题出在:协方差矩阵必须(半)正定 ,而”对称 + 6 个自由实数”保证不了这一点。
梯度下降每一步都对 6 个数做无约束扰动,没有任何机制拦住它走出正定区域。一旦走出:
某个特征值 λ i < 0 \lambda_i < 0 λ i < 0
半轴长 a i = λ i a_i = \sqrt{\lambda_i} a i = λ i 变成虚数
前向渲染里 Σ \Sigma Σ 要投影、要求逆,负特征值直接让画面崩溃或产生 NaN
要靠约束补救(每步投影回正定锥、加惩罚项),实现和调参都更麻烦。
七数方案:正定性免费
Σ = R ( q ) d i a g ( a 1 2 , a 2 2 , a 3 2 ) R ( q ) T \Sigma = R(q)\,\mathrm{diag}(a_1^2, a_2^2, a_3^2)\,R(q)^T Σ = R ( q ) diag ( a 1 2 , a 2 2 , a 3 2 ) R ( q ) T
用 7 个参数合成 Σ \Sigma Σ 而不是直接存它:
R ( q ) R(q) R ( q ) 是旋转矩阵(4 个数,∥ q ∥ = 1 \|q\|=1 ∥ q ∥ = 1 ),管主轴朝向
a i = e s i a_i = e^{s_i} a i = e s i (3 个数),管轴长,e e e 的任意实数次幂恒正 ⇒ λ i = a i 2 > 0 \Rightarrow \lambda_i = a_i^2 > 0 ⇒ λ i = a i 2 > 0 严格成立
无论优化器把 q q q 、s s s 改成什么样,合成出来的 Σ \Sigma Σ 天生对称正定 ——正定约束不是外加的,是参数化方式自带的。这就是”正定性免费保证”的准确含义。
附带收益一:参数解耦
想旋转只改 q q q ,想伸缩只改 s s s ,互不干扰。直接改 6 个协方差元素时,动一个数同时改变方向和轴长,二者纠缠,优化轨迹更差。解耦也让学习率、阈值可以按参数组分别设置(位置、旋转、尺度在原版实现里学习率各不相同)。
附带收益二:对数尺度的梯度行为
a = e s a = e^s a = e s 下,d a d s = a \dfrac{da}{ds} = a d s d a = a ,即 d a a = d s \dfrac{da}{a} = ds a d a = d s :s s s 的固定步长对应 a a a 的固定比例变化 。大椭球迈大步、小椭球迈小步,不同尺度的参数在梯度意义上被拉平了。若直接优化 a a a ,同样的步长对小椭球是巨变、对大椭球是挠痒,训练稳定性差。
易错点
“六个自由度存七个数”不是浪费是代价 :四元数的 ∥ q ∥ = 1 \|q\|=1 ∥ q ∥ = 1 约束吃掉一个自由度,换来正定免费 + 解耦 + 稳定,这笔账是赚的。
d i a g \mathrm{diag} diag 里是 a 2 a^2 a 2 不是 a a a :合成 Σ \Sigma Σ 时先平方(λ = a 2 \lambda = a^2 λ = a 2 ),而 a = e s a = e^s a = e s ,所以 d i a g \mathrm{diag} diag 里实际是 e 2 s e^{2s} e 2 s 。三层记号 s → a → λ s \to a \to \lambda s → a → λ 别跳步。
严格说 R d i a g ( a 2 ) R T R\,\mathrm{diag}(a^2)\,R^T R diag ( a 2 ) R T 对任意实数 a a a 只保证半正定;a = e s > 0 a = e^s > 0 a = e s > 0 严格正,才是”正定”而非”半正定”。
参考
四元数(Quaternion):旋转的压缩编码
构造式:从 q 到 R
本系列约定 q = ( x , y , z , w ) q = (x, y, z, w) q = ( x , y , z , w ) ,w w w 是标量部分,使用前提 ∥ q ∥ = x 2 + y 2 + z 2 + w 2 = 1 \|q\| = \sqrt{x^2+y^2+z^2+w^2} = 1 ∥ q ∥ = x 2 + y 2 + z 2 + w 2 = 1 。对应的 3 × 3 3\times3 3 × 3 旋转矩阵:
1-2(y^2+z^2) & 2(xy-wz) & 2(xz+wy) \\
2(xy+wz) & 1-2(x^2+z^2) & 2(yz-wx) \\
2(xz-wy) & 2(yz+wx) & 1-2(x^2+y^2)
\end{pmatrix}$$
只有乘法和加法,抄下来就能算,GPU 上极便宜。这就是它压过欧拉角(有万向锁、要算三角函数)和直接存 $R$(9 个数、6 个正交约束)的原因:4 个数、1 个约束,换 3 个旋转自由度。
## 怎么自查它是个旋转
旋转矩阵的充要条件:$R^TR = I$ 且 $\det R = 1$。不用全推,快查两条:
- **每行每列都是单位向量**:以第一行为例,$(1-2y^2-2z^2)^2 + 4(xy-wz)^2 + 4(xz+wy)^2$,在 $\|q\|=1$ 下展开化简恰为 1
- 对角项对称地写成 $1 - 2(\text{另外两个分量的平方和})$,是这套公式最好记的指纹
## 模长不为一,会发生什么
公式里每一项都隐含用了 $x^2+y^2+z^2+w^2 = 1$(对角项 $1-2(y^2+z^2)$ 就是拿这个等式化出来的)。若 $\|q\| = k \neq 1$,矩阵各元素以 $k^2$ 的比例失真,结果**既不是缩放旋转也不是旋转**——行列不再归一、不再正交,合成的 $\Sigma$ 形状直接坏掉。
这不是理论吓唬人:实际工程里遇到过导出工具(nerfstudio)写出的四元数未归一化,实测模长最大到 4.3,加载后必须重新归一化 $q \leftarrow q/\|q\|$ 才能用。读取任何来源的 $q$,先查模长,是成本最低的防御。
## 一个数学事实:q 和 −q 是同一个旋转
四元数对旋转是"双重覆盖":$q$ 与 $-q$ 代入构造式得到完全相同的 $R$(每一项都是分量两两相乘,同号翻转全部抵消)。训练时同一个椭球的 $q$ 在正负之间跳来跳去不是 bug;但如果对两个四元数做插值/平均,要先对齐符号(点积为负则翻一个),否则插值会绕远路。
## 参考
- [四元数与三维旋转(维基百科)](https://zh.wikipedia.org/wiki/四元数与三维旋转)
- [Quaternions and rotation sequences(Kuipers, 经典教材章节)](https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation) 颜色:平均色与那个 0.5
为什么 RGB 三个数不够
固定 RGB 意味着颜色与观察方向无关(view-independent),哑光墙面够用;金属、车漆、高光的颜色随视角变化,三个数表达不了。3DGS 的方案:把每个高斯的颜色写成观察方向 d d d 的函数 ,用球谐(Spherical Harmonics, SH)基展开。
球谐展开的结构
c ( d ) = 0.5 + ∑ l , m S l m Y l m ( d ) c(d) = 0.5 + \sum_{l,m} S_{lm}\, Y_{lm}(d) c ( d ) = 0.5 + ∑ l , m S l m Y l m ( d )
Y l m ( d ) Y_{lm}(d) Y l m ( d ) :定义在单位球面上的一组标准基函数,阶数 l l l 越高,能表达的方向变化越剧烈
S l m S_{lm} S l m :每个高斯自己的展开系数(可训练参数)
l = 0 l=0 l = 0 那一项(直流项 DC )是常数基 Y 00 Y_{00} Y 00 ,贡献与方向无关——它就是平均色 ;l ≥ 1 l \ge 1 l ≥ 1 的高阶项负责”换个角度颜色怎么变”
本集只存 DC(3 个数,RGB 各一个系数)。完整版展开到 3 阶:每通道 1 + 3 + 5 + 7 = 16 1+3+5+7 = 16 1 + 3 + 5 + 7 = 16 个系数,去掉 DC 后每通道 15 个高阶系数、三通道共 45 个(PLY 里的 f_rest 字段),那时一个高斯是 14 + 45 = 59 14 + 45 = 59 14 + 45 = 59 个参数。
式子里的 0.5 是什么
原版实现里 0 阶只有一项常数基 Y 00 = C 0 Y_{00} = C_0 Y 00 = C 0 ,其中
C 0 = 1 2 π ≈ 0.2821 C_0 = \frac{1}{2\sqrt\pi} \approx 0.2821 C 0 = 2 π 1 ≈ 0.2821
所以只含 DC 时颜色公式具体化为:
c = 0.5 + C 0 ⋅ f d c c = 0.5 + C_0 \cdot f_{dc} c = 0.5 + C 0 ⋅ f d c
关键点:f d c f_{dc} f d c 存的是偏移之前的原始系数 (PLY 里 f_dc 字段就是它)。加 0.5 的作用是把零点挪到中灰:f d c = 0 f_{dc} = 0 f d c = 0 对应颜色 0.5 0.5 0.5 ,系数正负对称地往亮/暗两边走,优化器从中性点出发,初始化、梯度都更规整。
漏掉 0.5 的真实代价
这不是理论细节。自研训练器的前向着色器曾写成 col = C0·dc(漏了 +0.5),结果:训练 loss 照样降——优化器把全体 dc 系数抬高约 + 1.77 +1.77 + 1.77 (恰好补偿 0.5 / C 0 ≈ 1.77 0.5/C_0 \approx 1.77 0.5/ C 0 ≈ 1.77 )来自我欺骗,训练内部自洽、自评 48 dB 毫无破绽;但模型一放进正确的 查看器,整幅画面泛白雾。教训:渲染公式里的常数偏移也是契约的一部分,训练端和显示端必须逐字一致。
易错点
f d c f_{dc} f d c ≠ 颜色 :要经 0.5 + C 0 ⋅ f d c 0.5 + C_0 \cdot f_{dc} 0.5 + C 0 ⋅ f d c 才是 [0,1] 颜色;把 PLY 的 f_dc 直接当 RGB 显示会整体偏暗/溢出。
DC 是平均色,不是主色/基色 :它是所有方向上的方向平均,高阶项在此基础上按视角修正。
C 0 ≈ 0.2821 C_0 \approx 0.2821 C 0 ≈ 0.2821 是球谐基归一化的结果,不是调出来的经验常数。
参考