ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

PyTorch3D 隐式渲染中的 Raymarching 模块:Emission-Absorption 与 Absorption-Only 算法解析与实战

PyTorch3D 隐式渲染中的 Raymarching 模块:Emission-Absorption 与 Absorption-Only 算法解析与实战 PyTorch3D 隐式渲染中的 Raymarching 模块Emission-Absorption 与 Absorption-Only 算法解析与实战【免费下载链接】pytorch3dPyTorch3D is FAIRs library of reusable components for deep learning with 3D data项目地址: https://gitcode.com/gh_mirrors/py/pytorch3d本篇文章聚焦 PyTorch3D 隐式渲染implicit rendering流水线中的核心组件——pytorch3d.renderer.implicit.raymarching模块。文章以 raymarching 模块源码 为绝对主体完整讲解EmissionAbsorptionRaymarcher发射-吸收EA与AbsorptionOnlyRaymarcher纯吸收AO两种体渲染算法的数学原理、输入输出契约、参数语义与工程实现细节并结合 ImplicitRenderer/VolumeRenderer、raysampling 模块、官方单元测试 与 fit_textured_volume 教程 给出可复制、可运行的实战用法。读者读完将能理解 EA/AO raymarcher 的内部机制、掌握其在体素渲染与隐式神经场渲染中的接入方式并具备自行实现与验证 raymarching 算法的能力。一、模块定位隐式渲染流水线的最后一环pytorch3d.renderer.implicit子包提供了基于射线ray的隐式场景渲染能力其模块入口对外导出三个层次的组件raysampling从相机出发采样光线MultinomialRaysampler、NDCMultinomialRaysampler、MonteCarloRaysampler等raymarching对每条光线上的采样点做体渲染积分本文主题renderer将 raysampler 与 raymarcher 组装为端到端的ImplicitRenderer/VolumeRenderer。整条流水线在 ImplicitRenderer 的forward中被串联为三个步骤源码注释中给出了权威描述raysampler从输入相机采样光线并将光线变换到世界坐标volumetric_function一个可调用对象forward的入参在被采样光线点处评估rays_densities与rays_featuresraymarcher接收密度与特征值用 raymarching 算法将每条光线渲染为像素。因此raymarcher 是把 3D 场景积分成 2D 图像的收尾组件其输入是每条光线上n_points_per_ray个采样点的密度与特征输出是该光线对应像素的渲染结果。它通常与前端的 raysampler 配对使用二者之间由场景密度/特征场可以是神经网络、体素网格Volumes或任意可调用对象衔接。raymarching.rst文档页面docs/modules/renderer/implicit/raymarching.rst通过 Sphinx autodoc 指令automodule:: pytorch3d.renderer.implicit.raymarching将本模块的 docstring 渲染为 API 参考文档其全部实质内容即来源于下述源码类与函数。二、EmissionAbsorptionRaymarcher发射-吸收EA算法2.1 算法思想EmissionAbsorptionRaymarcher源码见 raymarching.py基于经典的发射-吸收Emission-Absorption体渲染模型。它独立渲染每条光线通过分析沿光线通常是均匀采样的 3D 位置上的密度与特征值完成积分rays_densities形状为(..., n_points_per_ray, 1)的密度张量数值应落在[0, 1]表示每个点的不透明度值越大越不透明即越实心rays_features形状为(..., n_points_per_ray, feature_dim)的特征张量表示当某点不透明密度趋近 1.0时该点应当被渲染出来的内容例如 RGB 颜色。EA 算法首先利用密度沿光线计算吸收函数absorptionabsorption cumprod(1 - rays_densities, dim-1)absorption[..., k]表示光线从起点k0行进到第k个采样点时尚未被吸收的光的比例——即光线还剩多少能量。随后每条光线被渲染为形状(..., feature_dim)的特征向量features方式是取逐点特征的加权和weights absorption * rays_densities features (rays_features * weights).sum(dim-2)这里weights是一个在光线穿过的第一个表面点附近形成尖锐峰值的函数absorption单调递减前方越透明则剩余能量越多rays_densities在遇到表面时陡增二者相乘便在首个表面位置产生强响应。这正是体渲染能够呈现遮挡关系的原因。2.2 surface_thickness避免完美有界体的权重塌缩源码注释特别指出一个数值细节对于严格二值密度的完美有界体积密度只取 0 或 1weights cumprod(1 - rays_densities) * rays_densities会处处为 0——因为在遇到表面之前密度为 0权重为 0遇到表面之后累积乘积已变为 0权重仍为 0。为避免这一退化实现将累积乘积的结果沿光线方向偏移surface_thickness个元素。构造函数签名def __init__(self, surface_thickness: int 1) - None: Args: surface_thickness: Denotes the overlap between the absorption function and the density function. s surface_thickness的默认值为1表示吸收函数与密度函数之间的重叠量。实现中偏移通过辅助函数_shifted_cumprodraymarching.py完成先对输入做torch.cumprod(x, dim-1)然后在结果最后一维前插shift个 1、并去掉末尾shift个元素从而让吸收曲线向右平移一个采样点保证权重函数在表面处非零且可导。2.3 forward 输入输出契约与 eps 参数forward的完整签名def forward( self, rays_densities: torch.Tensor, rays_features: torch.Tensor, eps: float 1e-10, **kwargs, ) - torch.Tensor:各参数语义源码 docstring参数形状说明rays_densities(..., n_points_per_ray, 1)逐点密度取值范围[0, 1]rays_features(..., n_points_per_ray, feature_dim)逐点特征如颜色eps标量默认1e-10计算吸收函数cumprod(1 - rays_densities)前加到密度上的下界防止累积乘积恰好为 0 而阻断梯度学习注意 docstring 中密度形状写作(..., n_points_per_ray, 1)——即最后一个维度必须是 1density_1dTrue校验。返回值形状为(..., feature_dim 1)的张量沿最后一维拼接了两部分features每条光线的特征渲染结果形状(..., feature_dim)opacities每条光线的总不透明度形状(..., 1)取值范围[0, 1]表示该光线被吸收的光总量——值为 0 表示光线完全穿过体积无遮挡。opacities 的计算方式与AbsorptionOnlyRaymarcher一致见下文即opacities 1.0 - torch.prod(1.0 - rays_densities, dim-1, keepdimTrue)forward内部实现顺序为对应 raymarching.py调用_check_raymarcher_inputs与_check_density_bounds做输入合法性检查见第四节取出密度向量rays_densities rays_densities[..., 0]计算偏移后的吸收absorption _shifted_cumprod((1.0 eps) - rays_densities, shiftself.surface_thickness)计算权重并加权求和得到features计算opacities并沿最后一维拼接返回。2.4 求导友好性eps的设计动机是可微性cumprod的结果一旦为精确 0反向传播时梯度将无法流通或产生 NaN而体渲染的核心价值就在于端到端可微从而支持用渲染损失反向优化密度场/特征场。这一点在单元测试 test_emission_absorption中有直接验证测试将rays_densities与rays_features设为requires_gradTrue对渲染结果求loss.backward()后断言两个字段的梯度torch.isfinite(...).all()全部为真。三、AbsorptionOnlyRaymarcher纯吸收AO算法AbsorptionOnlyRaymarcherraymarching.py是 EA 的简化变体只度量每条光线吸收的光总量不产生任何特征渲染。3.1 算法与实现算法仅计算total_transmission prod(1 - rays_densities) # 形状 (..., 1)光线穿过体积后剩余的光 opacities 1 - total_transmission # 被吸收的光forward签名def forward( self, rays_densities: torch.Tensor, **kwargs ) - Union[None, torch.Tensor]:输入rays_densities形状为(..., n_points_per_ray)取值范围[0, 1]返回opacities形状为(..., 1)。实现中同样先做输入校验features_can_be_noneTruedensity_1dTrue取rays_densities[..., 0]后计算1.0 - torch.prod(1 - rays_densities, dim-1, keepdimTrue)。AO raymarcher 的典型用途包括二值掩码/前景分割渲染、遮挡估计以及在需要只关心哪里被挡住、不关心被挡住的内容是什么的场景下作为轻量替代。它输出的 opacity 与 EA 输出的 opacity 分量数学等价——EA 的 docstring 中明确指引读者参考 AO 的文档理解opacities的计算算法。四、输入校验_check_raymarcher_inputs 与 _check_density_bounds两个 raymarcher 在计算前都会调用模块内部的校验函数raymarching.py这也是文档页面由 autodoc 渲染出的隐藏辅助函数_check_raymarcher_inputs校验以下规则rays_densities必须是torch.Tensor实例否则抛ValueErrorrays_densities至少要有 1 维当density_1dTrue时最后一维大小必须为 1若z_can_be_noneFalserays_z必须是张量且形状与rays_densities一致若features_can_be_noneFalserays_features必须是张量且其除最后一维外的形状与rays_densities一致。_check_density_bounds在torch.no_grad()下检查密度元素是否落在默认边界(0.0, 1.0)内越界时发出warnings.warn而非报错。这两条校验在 tests/test_raymarching.py 中有成组的负例测试例如rays_densities为标量、rays_features形状不匹配、密度最后一维不为 1 等非法输入均应触发ValueError。这保证了在进入昂贵的光线积分前尽早失败。五、实战将 raymarcher 接入隐式渲染流水线5.1 与 ImplicitRenderer 配合任意可微场景场ImplicitRendererrenderer.py接受raysampler与raymarcher两个Callable。其forward(cameras, volumetric_function, **kwargs)依次调用 raysampler → volumetric_function → raymarcher返回(images, ray_bundle)其中images形状为(minibatch, ..., feature_dim opacity_dim)。一个最小示例用球体隐式场 EA raymarcher 渲染volumetric_function的写法取自 ImplicitRenderer 类文档from pytorch3d.renderer import ( ImplicitRenderer, NDCMultinomialRaysampler, EmissionAbsorptionRaymarcher, ) raysampler NDCMultinomialRaysampler( image_width256, image_height256, n_pts_per_ray64, min_depth0.1, max_depth4.0, ) raymarcher EmissionAbsorptionRaymarcher() renderer ImplicitRenderer(raysamplerraysampler, raymarcherraymarcher) def volumetric_function(ray_bundle, **kwargs): # 将光线起点/方向/长度转换为 3D 采样点世界坐标 rays_points_world ray_bundle_to_ray_points(ray_bundle) # 密度距球心越远越小sigmoid 压缩到 (0,1) rays_densities torch.sigmoid(-100.0 * rays_points_world.norm(dim-1, keepdimTrue)) # 特征球面上的法向编码为 RGB rays_features torch.nn.functional.normalize(rays_points_world, dim-1) * 0.5 0.5 return rays_densities, rays_features images, ray_bundle renderer(camerascameras, volumetric_functionvolumetric_function)5.2 与 VolumeRenderer 配合体素网格渲染VolumeRendererrenderer.py是ImplicitRenderer的便捷封装它把Volumes实例包装成VolumeSamplerrenderer.py在光线采样点上用torch.nn.functional.grid_samplebilinear/nearestpadding_mode支持zeros/border/reflection插值体素密度与特征再交给 raymarcher 积分。这正是官方教程 fit_textured_volume.ipynb 采用的组合方式from pytorch3d.renderer import VolumeRenderer, NDCMultinomialRaysampler, EmissionAbsorptionRaymarcher # 1) 实例化 raysamplerNDC 坐标网格采样n_pts_per_ray 个深度采样点 raysampler NDCMultinomialRaysampler( image_width..., image_height..., n_pts_per_ray..., min_depth..., max_depth..., ) # 2) 实例化 raymarcher标准发射-吸收算法 raymarcher EmissionAbsorptionRaymarcher() # 3) 组装渲染器 renderer VolumeRenderer(raysamplerraysampler, raymarcherraymarcher)随后以images, ray_bundle renderer(camerascameras, volumesvolumes)完成渲染并通过渲染结果与观测图像的损失反向传播来优化volumes的密度与特征体素。该教程的总结明确指出渲染由NDCMultinomialRaysamplerEmissionAbsorptionRaymarcher组成的体积渲染器完成。5.3 raysampler 的选择与关键参数raymarcher 只关心每条光线上有n_points_per_ray个采样点采样点的产生由 raysampling.py 负责。官方提供的选择包括MultinomialRaysampler在矩形图像网格上规则采样min_x/max_x/min_y/max_y定义像素坐标范围image_width/image_height定义分辨率n_pts_per_ray定义每光线采样点数min_depth/max_depth定义深度区间支持n_rays_per_image、n_rays_total、unit_directions、stratified_sampling等进阶选项NDCMultinomialRaysampler遵循 PyTorch3D 的 NDC 屏幕坐标约定像素坐标在[-1,1]×[-u,u]或[-u,u]×[-1,1]与Meshes/Pointclouds渲染器坐标系统一是MultinomialRaysampler的特例也是教程中的首选MonteCarloRaysampler在 xy 边界内均匀随机采样实值像素位置适合大规模随机光线训练GridRaysampler/NDCGridRaysampler已废弃的旧接口保留向后兼容使用时发出PendingDeprecationWarning应改用MultinomialRaysampler/NDCMultinomialRaysampler。其中stratified_samplingTrue时采样深度会通过_jiggle_within_stratas在每个深度 bin 内做均匀抖动raysampling.py减少规则采样带来的混叠是神经辐射场NeRF 类训练中的常用技巧。5.4 进阶重要性采样与 implicitron 中的泛化实现在 NeRF 类流水线中均匀采样往往不足以刻画高细节表面PyTorch3D 提供sample_pdfsample_pdf.py另有纯 Python 版本sample_pdf_python沿光线做基于权重的重要性重采样将采样点向高密度区域集中粗渲染得到的权重恰好可以作为重采样的依据。sample_pdf通过_C.sample_pdf调用 CUDA 实现detTrue时输出确定性逆 CDF 均匀采样结果。此外隐式渲染在 implicitron 子系统中也有泛化版本implicitron.models.renderer.raymarcher中的AccumulativeRaymarcherBaseraymarcher.py在 EA raymarcher 的基础上扩展出surface_thickness、bg_color背景色 alpha 混合、capping_functionexponential1-exp(-x)对应标准 EAcap1min(x,1)与weight_functionproduct/minimum等可配置项并额外返回渲染权重以支撑 NVS 流水线的 refine 阶段重要性采样。它直接复用本模块的_check_raymarcher_inputs校验函数可见raymarching模块是 PyTorch3D 全库体渲染的基础设施。六、验证与基准从单元测试理解数值语义tests/test_raymarching.py 提供了理解算法语义的最佳窗口。其辅助方法_init_random_rays构造了一个可解析的场景每根光线的深度值depths_gt随机给定密度在深度值之前为 0、之后为 1理想二值密度于是期望的 opacity 为(depths_gt n_pts_per_ray)光线在采样区间内碰到表面则为 1否则为 0期望的特征渲染features_gt恰为表面位置处的rays_features。随后测试断言test_emission_absorptionfeatures_render, opacities_render data_render[..., :-1], data_render[..., -1] self.assertClose(opacities_render, opacities_gt) self.assertClose(features_render * opacities_render[..., None], features_gt * opacities_gt[..., None])即 EA 的 opacity 输出与理论值一致特征渲染在不透明处与表面特征一致。test_absorption_only用同样的数据验证 AO 输出的 opacity。此外测试还验证了用rays_z[..., None]作为rays_features渲染可以得到深度图depths_render * opacities_render ≈ depths_gt * opacities_gt——这是用 EA raymarcher 输出深度的一种标准技巧。对于性能关注者仓库还提供了基准脚本 tests/benchmarks/bm_raymarching.py 可供参考。七、总结与选型建议组件输入输出典型用途EmissionAbsorptionRaymarcher密度 特征(..., feature_dim1)的[features, opacities]颜色/特征渲染 遮挡估计体素渲染、NeRF 类隐式场AbsorptionOnlyRaymarcher仅密度(..., 1)的 opacities掩码/前景分割、遮挡估计、轻量场景选型要点需要渲染特征颜色、深度等时使用 EA并可通过将特征替换为rays_z来廉价获得深度图只关心遮挡/透明度时使用 AO计算更轻两者均要求密度在[0,1]越界仅告警EA 的surface_thickness默认1通常无需调整eps保持默认即可保证梯度流通输入密度最后一维必须为 1特征与密度除最后一维外形状必须一致否则会触发ValueError。综上raymarching模块以两个精简、可微、契约清晰的 raymarcher 构成 PyTorch3D 隐式渲染的核心积分器是理解体渲染原理与搭建自定义神经渲染流水线的理想起点。【免费下载链接】pytorch3dPyTorch3D is FAIRs library of reusable components for deep learning with 3D data项目地址: https://gitcode.com/gh_mirrors/py/pytorch3d创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表