GaussianShader
一、论文介绍
参考GaussianShader: 3D高斯喷溅与遮阳功能的反射-CSDN博客
代码Asparagus15/GaussianShader:GaussianShader 代码:具有反射表面着色函数的 3D 高斯喷射
二、代码运行
下载示例数据并将其放入文件夹。使用以下命令执行优化器:data
python train.py -s data/horse_blender
--eval -m output/horse_blender -w --brdf_dim 0 --sh_degree -1 --lambda_predicted_normal 2e-1 --brdf_env 512
渲染
python render.py -m output/horse_blender --brdf_dim 0 --sh_degree -1 --brdf_mode envmap --brdf_env 512
三、代码解读
1.train.py
1.1 shade
与gs-ir有些不同
def shade(self, gb_pos, gb_normal, kd, ks, kr, view_pos, specular=True):"""基于BRDF的着色计算函数Args:gb_pos: 世界坐标位置 (H, W, N, 3)gb_normal: 表面法线向量 (H, W, N, 3)kd: 漫反射颜色 (H, W, N, 3)ks: 镜面反射颜色 (H, W, N, 3)kr: 粗糙度参数 (H, W, N, 1)view_pos: 观察点位置 (H, W, N, 3)specular: 是否计算镜面反射Returns:rgb: 最终着色颜色 (H, W, N, 3)extras: 包含漫反射和镜面反射分量的字典"""# 计算观察方向向量并归一化wo = util.safe_normalize(view_pos - gb_pos)# 如果启用镜面反射计算if specular:# 保存原始漫反射颜色diffuse_raw = kd# 粗糙度参数roughness = kr# 镜面反射颜色spec_col = ks# 漫反射颜色系数(1-镜面反射颜色)diff_col = 1.0 - kselse:# 如果不启用镜面反射则抛出异常raise NotImplementedError# 计算反射向量并归一化reflvec = util.safe_normalize(util.reflect(wo, gb_normal))# 表面法线向量nrmvec = gb_normal# 如果有变换矩阵,则对反射向量和法线向量进行坐标变换if self.mtx is not None: # Rotate lookupmtx = torch.as_tensor(self.mtx, dtype=torch.float32, device='cuda')reflvec = ru.xfm_vectors(reflvec.view(reflvec.shape[0], reflvec.shape[1] * reflvec.shape[2], reflvec.shape[3]), mtx).view(*reflvec.shape)nrmvec = ru.xfm_vectors(nrmvec.view(nrmvec.shape[0], nrmvec.shape[1] * nrmvec.shape[2], nrmvec.shape[3]), mtx).view(*nrmvec.shape)# 从预计算的漫反射环境贴图中采样环境光照ambient = dr.texture(self.diffuse[None, ...], nrmvec.contiguous(), filter_mode='linear', boundary_mode='cube')# 计算镜面反射光照分量(?)specular_linear = ambient * diff_col# 如果启用镜面反射if specular:# 计算法线与观察方向的点积,用于Fresnel计算NdotV = torch.clamp(util.dot(wo, gb_normal), min=1e-4)# 构造查找纹理坐标(法线点积和粗糙度)fg_uv = torch.cat((NdotV, roughness), dim=-1)# 加载Fresnel-Glossiness查找表纹理if not hasattr(self, '_FG_LUT'):self._FG_LUT = torch.as_tensor(np.fromfile('scene/NVDIFFREC/irrmaps/bsdf_256_256.bin', dtype=np.float32).reshape(1, 256, 256, 2), dtype=torch.float32, device='cuda')fg_lookup = dr.texture(self._FG_LUT, fg_uv, filter_mode='linear', boundary_mode='clamp')# 根据粗糙度获取对应的mipmap层级miplevel = self.get_mip(roughness)# 从预计算的镜面反射环境贴图中采样(Ls)spec = dr.texture(self.specular[0][None, ...], reflvec.contiguous(),mip=list(m[None, ...] for m in self.specular[1:]),mip_level_bias=miplevel[..., 0],filter_mode='linear-mipmap-linear',boundary_mode='cube')# 计算最终的镜面反射光照# reflectance = specular_tint * fg_lookup[...,0:1] + fg_lookup[...,1:2]reflectance = spec_col * fg_lookup[...,0:1] + fg_lookup[...,1:2]specular_linear += spec * reflectance# spec_col是s(?为什么相加漫反射)# 存储镜面反射分量extras = {"specular": specular_linear}# 计算漫反射分量,使用sigmoid函数进行色调映射diffuse_linear = torch.sigmoid(diffuse_raw - np.log(3.0))extras["diffuse"] = diffuse_linear# 最终颜色为漫反射和镜面反射之和rgb = specular_linear + diffuse_linearreturn rgb, extras
1.2 render结果
out = {"render": rendered_image,"viewspace_points": screenspace_points,"visibility_filter" : radii > 0,"radii": radii,
}
out.update(out_extras)
out_extras包括depth,normal,delta_normal_norm(法线偏移量),alpha,normal_ref(深度图渲染成的法线图)
其中,normal:[-1,1],
out_extras["alpha"] = rasterizer_alpha(means3D = means3D,means2D = means2D,shs = None,colors_precomp = alpha, # 使用全1的alpha值opacities = opacity,scales = scales,rotations = rotations,cov3D_precomp = cov3D_precomp)[0]# 从深度图像渲染法线,并与背景进行alpha混合
out_extras["normal_ref"] = render_normal(viewpoint_cam=viewpoint_camera, depth=out_extras['depth'][0], bg_color=bg_color, alpha=out_extras['alpha'][0])
1.3 损失
loss
- losses_extra['predicted_normal']:对每个像素点计算法线一致性:1 - dot(n, n_pred),并用权重加权平均。n为深度图渲染成的法线normal_ref,n_pred是直接渲染出的法线图,权重是提取alpha的第一个通道:(3, H, W) → (H, W)。(三个通道的值有相同)
- losses_extra['zero_one'] :惩罚高斯球的不透明度值 α 接近 0 或 1,方法是

-
losses_extra['delta_reg']:对法线偏移量加权平均
-
image, gt_image的损失
Ll1 = l1_loss(image, gt_image)
loss = (1.0 - opt.lambda_dssim) * Ll1 + opt.lambda_dssim * (1.0 - ssim(image, gt_image)) 这种稀疏性损失有助于高斯球的几何形状收敛到单个薄板,并提高渲染质量。总之,总训练损耗 L 为

其中,λn = 0.01,λs = 0.001,λr = 0.001。
N,H×W的关系


1.4TensorBoard日志记录
这些文件通常以 .tfevents 结尾。

