| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| import torch |
| import math |
| from easydict import EasyDict as edict |
| import numpy as np |
| from ..representations.gaussian import Gaussian |
| import torch.nn.functional as F |
| from easydict import EasyDict as edict |
|
|
|
|
| def intrinsics_to_projection( |
| intrinsics: torch.Tensor, |
| near: float, |
| far: float, |
| ) -> torch.Tensor: |
| """ |
| OpenCV intrinsics to OpenGL perspective matrix |
| |
| Args: |
| intrinsics (torch.Tensor): [3, 3] OpenCV intrinsics matrix |
| near (float): near plane to clip |
| far (float): far plane to clip |
| Returns: |
| (torch.Tensor): [4, 4] OpenGL perspective matrix |
| """ |
| fx, fy = intrinsics[0, 0], intrinsics[1, 1] |
| cx, cy = intrinsics[0, 2], intrinsics[1, 2] |
| ret = torch.zeros((4, 4), dtype=intrinsics.dtype, device=intrinsics.device) |
| ret[0, 0] = 2 * fx |
| ret[1, 1] = 2 * fy |
| ret[0, 2] = 2 * cx - 1 |
| ret[1, 2] = - 2 * cy + 1 |
| ret[2, 2] = far / (far - near) |
| ret[2, 3] = near * far / (near - far) |
| ret[3, 2] = 1. |
| return ret |
|
|
|
|
| def render(viewpoint_camera, pc : Gaussian, pipe, bg_color : torch.Tensor, scaling_modifier = 1.0, override_color = None, need_depth = False): |
| """ |
| Render the scene. |
| |
| Background tensor (bg_color) must be on GPU! |
| """ |
| |
| if 'GaussianRasterizer' not in globals(): |
| from diff_gaussian_rasterization import GaussianRasterizer, GaussianRasterizationSettings |
| |
| |
| screenspace_points = torch.zeros_like(pc.get_xyz, dtype=pc.get_xyz.dtype, requires_grad=True, device="cuda") + 0 |
| try: |
| screenspace_points.retain_grad() |
| except: |
| pass |
| |
| tanfovx = math.tan(viewpoint_camera.FoVx * 0.5) |
| tanfovy = math.tan(viewpoint_camera.FoVy * 0.5) |
| |
| kernel_size = pipe.kernel_size |
| subpixel_offset = torch.zeros((int(viewpoint_camera.image_height), int(viewpoint_camera.image_width), 2), dtype=torch.float32, device="cuda") |
|
|
| raster_settings = GaussianRasterizationSettings( |
| image_height=int(viewpoint_camera.image_height), |
| image_width=int(viewpoint_camera.image_width), |
| tanfovx=tanfovx, |
| tanfovy=tanfovy, |
| kernel_size=kernel_size, |
| subpixel_offset=subpixel_offset, |
| bg=bg_color, |
| scale_modifier=scaling_modifier, |
| viewmatrix=viewpoint_camera.world_view_transform, |
| projmatrix=viewpoint_camera.full_proj_transform, |
| sh_degree=pc.active_sh_degree, |
| campos=viewpoint_camera.camera_center, |
| prefiltered=False, |
| debug=pipe.debug |
| ) |
| |
| rasterizer = GaussianRasterizer(raster_settings=raster_settings) |
|
|
| means3D = pc.get_xyz |
| means2D = screenspace_points |
| opacity = pc.get_opacity |
|
|
| |
| |
| scales = None |
| rotations = None |
| cov3D_precomp = None |
| if pipe.compute_cov3D_python: |
| cov3D_precomp = pc.get_covariance(scaling_modifier) |
| else: |
| scales = pc.get_scaling |
| rotations = pc.get_rotation |
|
|
| |
| |
| shs = pc.get_features |
| colors_precomp = None |
|
|
| |
| rendered_image, radii = rasterizer( |
| means3D = means3D, |
| means2D = means2D, |
| shs = shs, |
| colors_precomp = colors_precomp, |
| opacities = opacity, |
| scales = scales, |
| rotations = rotations, |
| cov3D_precomp = cov3D_precomp |
| ) |
| if need_depth: |
| p_hom = torch.cat([pc.get_xyz, torch.ones_like(pc.get_xyz[...,:1])], -1).unsqueeze(-1) |
| p_view = torch.matmul(viewpoint_camera.world_view_transform.transpose(0,1), p_hom) |
| p_view = p_view[...,:3,:] |
| depth = p_view.squeeze()[...,2:3] |
| depth = depth.repeat(1,3) |
| depth_map = rasterizer( |
| means3D = means3D, |
| means2D = means2D, |
| shs = None, |
| colors_precomp = depth, |
| opacities = opacity, |
| scales = scales, |
| rotations = rotations, |
| cov3D_precomp = cov3D_precomp)[0] |
| |
| |
| return edict({"render": rendered_image, |
| "depth": depth_map if need_depth else None, |
| "viewspace_points": screenspace_points, |
| "visibility_filter" : radii > 0, |
| "radii": radii}) |
|
|
|
|
| class GaussianRenderer: |
| """ |
| Renderer for the Voxel representation. |
| |
| Args: |
| rendering_options (dict): Rendering options. |
| """ |
|
|
| def __init__(self, rendering_options={}) -> None: |
| self.pipe = edict({ |
| "kernel_size": 0.1, |
| "convert_SHs_python": False, |
| "compute_cov3D_python": False, |
| "scale_modifier": 1.0, |
| "debug": False |
| }) |
| self.rendering_options = edict({ |
| "resolution": None, |
| "near": None, |
| "far": None, |
| "ssaa": 1, |
| "bg_color": 'random', |
| }) |
| self.rendering_options.update(rendering_options) |
| self.bg_color = None |
| |
| def render( |
| self, |
| gausssian: Gaussian, |
| extrinsics: torch.Tensor, |
| intrinsics: torch.Tensor, |
| colors_overwrite: torch.Tensor = None, |
| need_depth: bool = False, |
| ) -> edict: |
| """ |
| Render the gausssian. |
| |
| Args: |
| gaussian : gaussianmodule |
| extrinsics (torch.Tensor): (4, 4) camera extrinsics |
| intrinsics (torch.Tensor): (3, 3) camera intrinsics |
| colors_overwrite (torch.Tensor): (N, 3) override color |
| |
| Returns: |
| edict containing: |
| color (torch.Tensor): (3, H, W) rendered color image |
| """ |
| resolution = self.rendering_options["resolution"] |
| near = self.rendering_options["near"] |
| far = self.rendering_options["far"] |
| ssaa = self.rendering_options["ssaa"] |
| |
| if self.rendering_options["bg_color"] == 'random': |
| self.bg_color = torch.zeros(3, dtype=torch.float32, device="cuda") |
| if np.random.rand() < 0.5: |
| self.bg_color += 1 |
| else: |
| self.bg_color = torch.tensor(self.rendering_options["bg_color"], dtype=torch.float32, device="cuda") |
|
|
| view = extrinsics |
| perspective = intrinsics_to_projection(intrinsics, near, far) |
| camera = torch.inverse(view)[:3, 3] |
| focalx = intrinsics[0, 0] |
| focaly = intrinsics[1, 1] |
| fovx = 2 * torch.atan(0.5 / focalx) |
| fovy = 2 * torch.atan(0.5 / focaly) |
| |
| camera_dict = edict({ |
| "image_height": resolution * ssaa, |
| "image_width": resolution * ssaa, |
| "FoVx": fovx, |
| "FoVy": fovy, |
| "znear": near, |
| "zfar": far, |
| "world_view_transform": view.T.float().contiguous(), |
| "projection_matrix": perspective.T.float().contiguous(), |
| "full_proj_transform": (perspective @ view).T.float().contiguous(), |
| "camera_center": camera |
| }) |
|
|
| |
| render_ret = render(camera_dict, gausssian, self.pipe, self.bg_color, override_color=colors_overwrite, scaling_modifier=self.pipe.scale_modifier, need_depth=need_depth) |
|
|
| if ssaa > 1: |
| render_ret.render = F.interpolate(render_ret.render[None], size=(resolution, resolution), mode='bilinear', align_corners=False, antialias=True).squeeze() |
| if need_depth: |
| render_ret.depth = F.interpolate(render_ret.depth[None], size=(resolution, resolution), mode='bilinear', align_corners=False, antialias=True).squeeze() |
| |
| if need_depth: |
| return edict({ |
| 'color': render_ret['render'], |
| 'depth': render_ret['depth'], |
| }) |
| else: |
| return edict({ |
| 'color': render_ret['render'], |
| }) |
|
|