下面是一段3dgs的原文
Specifically, the color is given by volumetric rendering along a ray:
where samples of density , transmittance , and color are taken along the ray with intervals . This can be re-written as
with
这是标准nerf的渲染方程,注意式的形式,这里表示为透射率,是一个与采样间隔、体密度有关的值,是点处的颜色。
根据Volume Rendering Digest这篇文章中的推导
由于将视作表示射线击中粒子的微分可能性(即在行驶无穷小距离时击中粒子的概率)。解出微分方程的形式中就会带有项,排除掉这些数学符号的干扰,其本质是一种alpha-blending或者叫 alpha compositing
那么对于3dgs来说,其alpha-blending的形式,
也就很好理解了。
其中是该splatting在渲染方向上的颜色,是一个学习到的透明度值。
其中是与方向有关的颜色值,本质上是一组球谐函数的基,在3dgs的cuda源码中可以找到
cpp// Forward method for converting the input spherical harmonics
// coefficients of each Gaussian to a simple RGB color.
__device__ glm::vec3 computeColorFromSH(int idx, int deg, int max_coeffs, const glm::vec3* means, glm::vec3 campos, const float* shs, bool* clamped)
{
// The implementation is loosely based on code for
// "Differentiable Point-Based Radiance Fields for
// Efficient View Synthesis" by Zhang et al. (2022)
glm::vec3 pos = means[idx];
glm::vec3 dir = pos - campos;
dir = dir / glm::length(dir);
glm::vec3* sh = ((glm::vec3*)shs) + idx * max_coeffs;
glm::vec3 result = SH_C0 * sh[0];
if (deg > 0)
{
float x = dir.x;
float y = dir.y;
float z = dir.z;
result = result - SH_C1 * y * sh[1] + SH_C1 * z * sh[2] - SH_C1 * x * sh[3];
if (deg > 1)
{
float xx = x * x, yy = y * y, zz = z * z;
float xy = x * y, yz = y * z, xz = x * z;
result = result +
SH_C2[0] * xy * sh[4] +
SH_C2[1] * yz * sh[5] +
SH_C2[2] * (2.0f * zz - xx - yy) * sh[6] +
SH_C2[3] * xz * sh[7] +
SH_C2[4] * (xx - yy) * sh[8];
if (deg > 2)
{
result = result +
SH_C3[0] * y * (3.0f * xx - yy) * sh[9] +
SH_C3[1] * xy * z * sh[10] +
SH_C3[2] * y * (4.0f * zz - xx - yy) * sh[11] +
SH_C3[3] * z * (2.0f * zz - 3.0f * xx - 3.0f * yy) * sh[12] +
SH_C3[4] * x * (4.0f * zz - xx - yy) * sh[13] +
SH_C3[5] * z * (xx - yy) * sh[14] +
SH_C3[6] * x * (xx - 3.0f * yy) * sh[15];
}
}
}
result += 0.5f;
// RGB colors are clamped to positive values. If values are
// clamped, we need to keep track of this for the backward pass.
clamped[3 * idx + 0] = (result.x < 0);
clamped[3 * idx + 1] = (result.y < 0);
clamped[3 * idx + 2] = (result.z < 0);
return glm::max(result, 0.0f);
}
这段代码用gpt解释
txt这段代码是一个CUDA内核函数,用于将球谐系数(spherical harmonics coefficients)转换为简单的RGB颜色。这个函数是图形渲染中的一部分,特别是在计算光源对场景中物体颜色的影响时。球谐函数是拉普拉斯方程在球坐标系中的解,它们在描述光的散射和辐射传输中非常有用。 下面是对这段代码的逐行解释: __device__ 关键字表明这个函数可以在GPU上作为CUDA内核运行。 glm::vec3 computeColorFromSH(...) 定义了一个函数,它接受球谐系数、球面谐波的阶数、最大系数数、高斯分布的均值、相机位置、球谐系数数组和是否被截断的标志数组作为输入,并返回一个glm::vec3类型的RGB颜色。 glm::vec3 pos = means[idx]; 获取当前高斯分布的均值位置。 glm::vec3 dir = pos - campos; 计算从相机位置到当前位置的方向向量。 dir = dir / glm::length(dir); 归一化方向向量。 glm::vec3* sh = ((glm::vec3*)shs) + idx * max_coeffs; 计算指向当前高斯分布球谐系数数组的指针。 glm::vec3 result = SH_C0 * sh[0]; 初始化结果颜色,使用阶数为0的球谐系数。 if (deg > 0) 开始一个条件块,用于计算阶数大于0的球谐系数对颜色的影响。 9-15. 在这个条件块内部,计算更高阶的球谐系数对颜色的贡献。SH_C1, SH_C2, SH_C3 应该是预定义的系数数组,用于计算不同阶数的球谐系数对最终颜色的影响。 result += 0.5f; 将一个小的偏移量加到结果颜色上,以避免颜色太暗。 17-19. clamped 数组用于跟踪RGB颜色分量是否被截断(即是否小于0)。如果某个分量小于0,相应的标志会被设置为true。 return glm::max(result, 0.0f); 确保所有颜色分量都是非负的,返回最终的RGB颜色。 这个函数的目的是将复杂的球谐分析转换为直观的RGB颜色,这在光线追踪和实时渲染算法中很常见。代码中提到的“Differentiable Point-Based Radiance Fields for Efficient View Synthesis”由Zhang等人在2022年提出,这是一种先进的视图合成技术,它允许在保持渲染效率的同时,对场景进行不同的光照和视角变化。
3dgs默认使用了3阶的球谐函数。
于是我们会思考一个问题,我们可以使用3dgs渲染一个语义图么?
理论上也是可以的,只需要把式中的改成,让也是一组球谐函数的基,然后对应也要有另一组学习到的,这样就可以渲染出一张语义图了。但是该如何输入监督信息呢?
我们可以将输入的图像用语义分割网络进行处理,这样每一个view就也带有一张语义图真值了。
思考1:会不会造成语义空间上的不连续?由于仅仅使用2d的监督信息,可能会造成只在有语义真值的渲染方向上表现较好,而在没见过的方向上,语义的表现较差,但是实际上语义随渲染方向的改变应该很小。(同一个物体的语义不随方向改变?)
思考2:如何引入3d信息对语义进行修正?在点云语义分割任务上,有很多可以参考的文章。
本文作者:insomnia
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!