渲染器入門
架構概觀
渲染器的設計是模組化、可擴展的,並支援所有輸入的批次處理和梯度計算。下圖描述了渲染管線的所有組成部分。
片段
光柵化器會在一個具名元組中返回 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 單位给出每個最靠近像素的點在 x/y 平面上的有號歐幾里得距離。
有關管線中每個組成部分的更多詳細資訊,請參閱渲染器 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 | ✔️ |