渲染器入门
架构概述
渲染器旨在模块化、可扩展,并支持所有输入的批处理和梯度。下图描述了渲染管线的所有组件。
片段
光栅化器以命名元组的形式返回 4 个输出张量。
pix_to_face
:形状为(N, image_size, image_size, faces_per_pixel)
的 LongTensor,指定图像中每个像素重叠的面的索引(在打包的面中)。zbuf
:形状为(N, image_size, image_size, faces_per_pixel)
的 FloatTensor,给出世界坐标中每个像素处最近面的 z 坐标,按 z 顺序排序。bary_coords
:形状为(N, image_size, image_size, faces_per_pixel, 3)
的 FloatTensor,给出每个像素处最近面的重心坐标(以 NDC 单位表示),按 z 顺序排序。pix_dists
:形状为(N, image_size, image_size, faces_per_pixel)
的 FloatTensor,给出每个最接近像素的点的符号欧氏距离(以 NDC 单位表示)。
有关管道中每个组件的更多详细信息,请参阅渲染器 API 参考。
注意
可微渲染器 API 处于实验阶段,可能会发生变化!
坐标变换约定
渲染需要在几个不同的坐标系之间进行变换:世界空间、视图/相机空间、NDC 空间和屏幕空间。在每个步骤中,了解相机的位置、+X、+Y、+Z 轴的对齐方式以及可能的取值范围非常重要。下图概述了 PyTorch3D 中使用的约定。
例如,给定一个茶壶网格,下图显示了世界坐标系、相机坐标系和图像。请注意,世界坐标系和相机坐标系的 +z 方向都指向页面内。
注意:PyTorch3D 与 OpenGL
虽然我们尝试模拟 OpenGL 的几个方面,但坐标系约定存在差异。
- PyTorch3D 中的默认世界坐标系具有指向屏幕内的 +Z,而在 OpenGL 中,+Z 指向屏幕外。两者都是右手系。
- PyTorch3D 中的 NDC 坐标系是右手系,而 OpenGL 中的 NDC 坐标系是左手系(投影矩阵切换了手性)。
光栅化非正方形图像
要光栅化 H != W 的图像,您可以在 RasterizationSettings
中将 image_size
指定为 (H, W) 的元组。
纵横比需要特别考虑。需要注意两个纵横比:- 每个像素的纵横比- 输出图像的纵横比在相机(例如 FoVPerspectiveCameras
)中,aspect_ratio
参数可用于设置像素纵横比。在光栅化器中,我们假设像素为正方形,但图像纵横比可变(即矩形图像)。
在大多数情况下,您希望将相机纵横比设置为 1.0(即正方形像素),并且只在 RasterizationSettings
中改变 image_size
(即以像素为单位的输出图像尺寸)。
Pulsar 后端
从 v0.3 开始,可以使用 pulsar 作为点渲染的后端。它专注于效率,这有利有弊:它经过高度优化,所有渲染阶段都集成在 CUDA 内核中。这导致速度显着提高,并且扩展性更好。我们在 Facebook Reality Labs 使用它来渲染和优化分辨率高达 4K 的包含数百万个球体的场景。您可以在下面找到运行时比较图(设置:bin_size=None
、points_per_pixel=5
、image_size=1024
、radius=1e-2
、composite_params.radius=1e-4
;在 RTX 2070 GPU 上进行基准测试)。
Pulsar 的处理步骤紧密集成在 CUDA 内核中,并且不适用于自定义的 rasterizer
和 compositor
组件。我们提供两种使用 Pulsar 的方法:(1) 存在一个统一的接口,以无缝匹配 PyTorch3D 调用约定。例如,点云教程中对此进行了说明。(2) 可以直接访问 Pulsar 后端,它公开了后端的全部功能(包括 PyTorch3D 中尚不可用的不透明度)。显示其用法以及匹配的 PyTorch3D 接口代码的示例位于 此文件夹中。
纹理选项
对于网格纹理,我们提供了一些选项(在 pytorch3d/renderer/mesh/texturing.py
中)
- 顶点纹理:每个顶点的 D 维纹理(例如 RGB 颜色),可以在面上进行插值。这可以用
(N, V, D)
张量表示。这是一个相当简单的表示,如果网格面很大,则无法模拟复杂的纹理。 - UV 纹理:顶点 UV 坐标和整个网格的一个纹理贴图。对于具有给定重心坐标的面上的一个点,可以通过插值顶点 uv 坐标然后从纹理贴图中采样来计算面颜色。此表示需要两个张量(UV:
(N, V, 2), 纹理贴图:
(N, H, W, 3)`),并且仅限于每个网格仅支持一个纹理贴图。 - 面纹理:在 ShapeNet 网格等更复杂的情况下,每个网格有多个纹理贴图,有些面具有纹理,而其他面则没有。对于这些情况,更灵活的表示是纹理图集,其中每个面表示为
(RxR)
纹理贴图,其中 R 是纹理分辨率。对于面上给定的点,可以使用点的重心坐标从每个面的纹理贴图中采样纹理值。此表示需要一个形状为(N, F, R, R, 3)
的张量。这种纹理方法的灵感来自 SoftRasterizer 实现。有关更多详细信息,请参阅make_material_atlas
和sample_textures
函数。注意:TexturesAtlas
纹理采样仅相对于纹理图集可微,而不相对于重心坐标可微。
一个简单的渲染器
PyTorch3D 中的渲染器由光栅化器和着色器组成。只需几个简单的步骤即可创建一个渲染器
# Imports
from pytorch3d.renderer import (
FoVPerspectiveCameras, look_at_view_transform,
RasterizationSettings, BlendParams,
MeshRenderer, MeshRasterizer, HardPhongShader
)
# Initialize an OpenGL perspective camera.
R, T = look_at_view_transform(2.7, 10, 20)
cameras = FoVPerspectiveCameras(device=device, R=R, T=T)
# Define the settings for rasterization and shading. Here we set the output image to be of size
# 512x512. As we are rendering images for visualization purposes only we will set faces_per_pixel=1
# and blur_radius=0.0. Refer to rasterize_meshes.py for explanations of these parameters.
raster_settings = RasterizationSettings(
image_size=512,
blur_radius=0.0,
faces_per_pixel=1,
)
# Create a Phong renderer by composing a rasterizer and a shader. Here we can use a predefined
# PhongShader, passing in the device on which to initialize the default parameters
renderer = MeshRenderer(
rasterizer=MeshRasterizer(cameras=cameras, raster_settings=raster_settings),
shader=HardPhongShader(device=device, cameras=cameras)
)
自定义着色器
着色器是 PyTorch3D 渲染 API 中最灵活的部分。我们在 shaders.py
中创建了一些着色器示例,但这并不是一个完整的集合。
一个着色器可以包含几个步骤
- 纹理化(例如,顶点 RGB 颜色插值或顶点 UV 坐标插值,然后从纹理图中采样(插值使用来自光栅化的重心坐标))
- 光照/着色(例如,环境光、漫反射光、镜面光、Phong、Gouraud、Flat)
- 混合(例如,仅使用每个像素最近面的硬混合,或使用每个像素前 K 个面的加权和的软混合)
我们根据目前支持的纹理化/着色/混合功能,提供了一些这些功能组合的示例。这些在下面的表格中进行了总结。许多其他组合也是可能的,我们计划扩展纹理化、着色和混合的可用选项。
着色器示例 | 顶点纹理 | UV 纹理 | 纹理图集 | 平面着色 | Gouraud 着色 | Phong 着色 | 硬混合 | 软混合 |
---|---|---|---|---|---|---|---|---|
HardPhongShader | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | |||
SoftPhongShader | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | |||
HardGouraudShader | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | |||
SoftGouraudShader | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | |||
HardFlatShader | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | |||
SoftSilhouetteShader | ✔️ |