Create ray_marcher.py
Browse files- ray_marcher.py +73 -0
ray_marcher.py
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
| 2 |
+
# All rights reserved.
|
| 3 |
+
#
|
| 4 |
+
# This source code is licensed under the license found in the
|
| 5 |
+
# LICENSE file in the root directory of this source tree.
|
| 6 |
+
# SPDX-FileCopyrightText: Copyright (c) 2021-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
| 7 |
+
# SPDX-License-Identifier: LicenseRef-NvidiaProprietary
|
| 8 |
+
#
|
| 9 |
+
# NVIDIA CORPORATION, its affiliates and licensors retain all intellectual
|
| 10 |
+
# property and proprietary rights in and to this material, related
|
| 11 |
+
# documentation and any modifications thereto. Any use, reproduction,
|
| 12 |
+
# disclosure or distribution of this material and related documentation
|
| 13 |
+
# without an express license agreement from NVIDIA CORPORATION or
|
| 14 |
+
# its affiliates is strictly prohibited.
|
| 15 |
+
#
|
| 16 |
+
# Modified by Zexin He
|
| 17 |
+
# The modifications are subject to the same license as the original.
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
"""
|
| 21 |
+
The ray marcher takes the raw output of the implicit representation and uses the volume rendering equation to produce composited colors and depths.
|
| 22 |
+
Based off of the implementation in MipNeRF (this one doesn't do any cone tracing though!)
|
| 23 |
+
"""
|
| 24 |
+
|
| 25 |
+
import torch
|
| 26 |
+
import torch.nn as nn
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
class MipRayMarcher2(nn.Module):
|
| 30 |
+
def __init__(self, activation_factory):
|
| 31 |
+
super().__init__()
|
| 32 |
+
self.activation_factory = activation_factory
|
| 33 |
+
|
| 34 |
+
def run_forward(self, colors, densities, depths, rendering_options):
|
| 35 |
+
|
| 36 |
+
deltas = depths[:, :, 1:] - depths[:, :, :-1]
|
| 37 |
+
colors_mid = (colors[:, :, :-1] + colors[:, :, 1:]) / 2
|
| 38 |
+
densities_mid = (densities[:, :, :-1] + densities[:, :, 1:]) / 2
|
| 39 |
+
depths_mid = (depths[:, :, :-1] + depths[:, :, 1:]) / 2
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
|
| 43 |
+
# using factory mode for better usability
|
| 44 |
+
densities_mid = self.activation_factory(rendering_options)(densities_mid)
|
| 45 |
+
|
| 46 |
+
density_delta = densities_mid * deltas
|
| 47 |
+
|
| 48 |
+
alpha = 1 - torch.exp(-density_delta)
|
| 49 |
+
|
| 50 |
+
alpha_shifted = torch.cat([torch.ones_like(alpha[:, :, :1]), 1-alpha + 1e-10], -2)
|
| 51 |
+
weights = alpha * torch.cumprod(alpha_shifted, -2)[:, :, :-1]
|
| 52 |
+
|
| 53 |
+
composite_rgb = torch.sum(weights * colors_mid, -2)
|
| 54 |
+
weight_total = weights.sum(2)
|
| 55 |
+
composite_depth = torch.sum(weights * depths_mid, -2) / weight_total
|
| 56 |
+
|
| 57 |
+
# clip the composite to min/max range of depths
|
| 58 |
+
composite_depth = torch.nan_to_num(composite_depth, float('inf'))
|
| 59 |
+
composite_depth = torch.clamp(composite_depth, torch.min(depths), torch.max(depths))
|
| 60 |
+
|
| 61 |
+
if rendering_options.get('white_back', False):
|
| 62 |
+
composite_rgb = composite_rgb + 1 - weight_total
|
| 63 |
+
|
| 64 |
+
# rendered value scale is 0-1, comment out original mipnerf scaling
|
| 65 |
+
# composite_rgb = composite_rgb * 2 - 1 # Scale to (-1, 1)
|
| 66 |
+
|
| 67 |
+
return composite_rgb, composite_depth, weights
|
| 68 |
+
|
| 69 |
+
|
| 70 |
+
def forward(self, colors, densities, depths, rendering_options):
|
| 71 |
+
composite_rgb, composite_depth, weights = self.run_forward(colors, densities, depths, rendering_options)
|
| 72 |
+
|
| 73 |
+
return composite_rgb, composite_depth, weights
|