├── .gitignore ├── Dockerfile ├── Makefile ├── README.md ├── example ├── cube.py ├── depth.png ├── normals.png ├── nvdiffrast_compare.ipynb ├── smpl_tmp.pkl └── timing.py ├── minimal_pytorch_rasterizer ├── __init__.py ├── assert_utils.py ├── camera.py ├── cuda │ ├── rasterizer.cpp │ └── rasterizer_kernel.cu ├── rasterizer.py └── utils.py ├── requirements.txt ├── setup.py └── setup.sh /.gitignore: -------------------------------------------------------------------------------- 1 | minimal_pytorch_rasterizer.egg-info/* 2 | dist/* 3 | build/* 4 | 5 | .ipynb_checkpoints 6 | */.ipynb_checkpoints/* 7 | 8 | .idea 9 | */.idea/* 10 | 11 | __pycache__ 12 | */__pycache__/* 13 | 14 | .vscode 15 | */.vscode/* 16 | 17 | example/tmp_u.png 18 | example/tmp_v.png 19 | 20 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nvidia/cudagl:10.2-devel-ubuntu18.04 2 | 3 | ENV TZ=Europe/Moscow 4 | RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone 5 | 6 | RUN apt-get update && apt-get install -y \ 7 | build-essential \ 8 | rsync \ 9 | curl \ 10 | wget \ 11 | htop \ 12 | git \ 13 | openssh-server \ 14 | nano \ 15 | cmake \ 16 | unzip \ 17 | zip \ 18 | python-opencv \ 19 | vim \ 20 | ffmpeg \ 21 | tmux \ 22 | freeglut3-dev 23 | 24 | # cudnn 25 | RUN apt-get update && apt-get install -y --no-install-recommends \ 26 | libcudnn7=7.6.5.32-1+cuda10.2 \ 27 | libcudnn7-dev=7.6.5.32-1+cuda10.2 \ 28 | && apt-mark hold libcudnn7 && \ 29 | rm -rf /var/lib/apt/lists/* 30 | 31 | # nvdiffrast setup 32 | RUN apt-get update && apt-get install -y \ 33 | pkg-config \ 34 | libglvnd0 \ 35 | libgl1 \ 36 | libglx0 \ 37 | libegl1 \ 38 | libgles2 \ 39 | libglvnd-dev \ 40 | libgl1-mesa-dev \ 41 | libegl1-mesa-dev \ 42 | libgles2-mesa-dev 43 | ENV NVIDIA_VISIBLE_DEVICES all 44 | ENV NVIDIA_DRIVER_CAPABILITIES compute,utility,graphics 45 | ENV PYOPENGL_PLATFORM egl 46 | ENV LD_LIBRARY_PATH /usr/lib64:$LD_LIBRARY_PATH 47 | # nvdiffrast python package is installed from requirements.txt then 48 | 49 | 50 | RUN echo '{"file_format_version": "1.0.0", "ICD": {"library_path": "libEGL_nvidia.so.0"}}' | \ 51 | tee /usr/share/glvnd/egl_vendor.d/10_nvidia.json 52 | 53 | ## glew installation from source 54 | RUN curl -L https://downloads.sourceforge.net/project/glew/glew/2.1.0/glew-2.1.0.tgz > /tmp/glew-2.1.0.tgz 55 | RUN mkdir -p /tmp && \ 56 | cd /tmp && tar zxf /tmp/glew-2.1.0.tgz && cd glew-2.1.0 && \ 57 | SYSTEM=linux-egl make && \ 58 | SYSTEM=linux-egl make install && \ 59 | rm -rf /tmp/glew-2.1.0.zip /tmp/glew-2.1.0 60 | 61 | 62 | # fixuid 63 | ARG USERNAME=docker 64 | RUN apt-get update && apt-get install -y sudo curl && \ 65 | addgroup --gid 1000 $USERNAME && \ 66 | adduser --uid 1000 --gid 1000 --disabled-password --gecos '' $USERNAME && \ 67 | adduser $USERNAME sudo && \ 68 | echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers && \ 69 | USER=$USERNAME && \ 70 | GROUP=$USERNAME && \ 71 | curl -SsL https://github.com/boxboat/fixuid/releases/download/v0.4/fixuid-0.4-linux-amd64.tar.gz | tar -C /usr/local/bin -xzf - && \ 72 | chown root:root /usr/local/bin/fixuid && \ 73 | chmod 4755 /usr/local/bin/fixuid && \ 74 | mkdir -p /etc/fixuid && \ 75 | printf "user: $USER\ngroup: $GROUP\n" > /etc/fixuid/config.yml 76 | 77 | 78 | # conda 79 | RUN wget --quiet https://repo.continuum.io/miniconda/Miniconda3-py37_4.8.3-Linux-x86_64.sh -O ~/miniconda.sh && \ 80 | /bin/bash ~/miniconda.sh -b -p /opt/conda && \ 81 | rm ~/miniconda.sh && \ 82 | /opt/conda/bin/conda clean -tipsy && \ 83 | ln -s /opt/conda/etc/profile.d/conda.sh /etc/profile.d/conda.sh && \ 84 | echo ". /opt/conda/etc/profile.d/conda.sh" >> ~/.bashrc 85 | # this version of miniconda's /opt/conda/bin provides pip = pip3 = pip3.7, python = python3 = python3.7 86 | ENV PATH /opt/conda/bin:$PATH 87 | ENV PYTHONDONTWRITEBYTECODE=1 88 | ENV PYTHONUNBUFFERED=1 89 | RUN pip install --upgrade pip 90 | 91 | 92 | # python pkgs 93 | RUN conda install pytorch=1.7.1 torchvision=0.8.2 cudatoolkit=10.2 -c pytorch 94 | COPY requirements.txt /opt/requirements.txt 95 | RUN pip --no-cache-dir install -r /opt/requirements.txt 96 | 97 | COPY ./ /opt/minimal_pytorch_rasterizer 98 | RUN cd /opt/minimal_pytorch_rasterizer && ./setup.sh 99 | 100 | USER $USERNAME:$USERNAME 101 | ENTRYPOINT ["fixuid", "-q"] 102 | CMD ["fixuid", "-q", "bash"] 103 | WORKDIR /src 104 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | NAME?=minimal_pytorch_rasterizer 2 | COMMAND?=bash 3 | VOLUMES?=-v /home/renat:/home/renat 4 | 5 | GPUS?=all 6 | ifeq ($(GPUS),none) 7 | GPUS_OPTION= 8 | else 9 | GPUS_OPTION=--gpus=$(GPUS) 10 | endif 11 | 12 | .PHONY: all 13 | all: stop build run 14 | 15 | .PHONY: build 16 | build: 17 | docker build -t $(NAME) . 18 | 19 | .PHONY: stop 20 | stop: 21 | -docker stop $(NAME) 22 | -docker rm $(NAME) 23 | 24 | .PHONY: run 25 | run: 26 | docker run --rm -dit \ 27 | $(GPUS_OPTION) \ 28 | --net=host \ 29 | --ipc=host \ 30 | -u $(shell id -u ${USER}):$(shell id -g ${USER}) \ 31 | -v $(shell pwd)/example:/example \ 32 | --name=$(NAME) \ 33 | -w /example \ 34 | $(VOLUMES) \ 35 | $(NAME) \ 36 | $(COMMAND) 37 | docker attach $(NAME) 38 | 39 | .PHONY: attach 40 | attach: 41 | docker attach $(NAME) 42 | 43 | .PHONY: logs 44 | logs: 45 | docker logs -f $(NAME) 46 | 47 | .PHONY: exec 48 | exec: 49 | docker exec -it $(NAME) $(COMMAND) 50 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## About 2 | **minimal_pytorch_rasterizer** is a CUDA non-differentiable mesh rasterization library for pytorch tensors with python bindings. 3 | 4 | It projects mesh to image using pinhole camera model. Vertices could have any number of features (channels). Library also estimates normals for mesh visualization. 5 | 6 | A mesh with 6890 vertices and 13776 faces is rasterized on 1000x1000 image in less than 1ms on 2080ti GPU. Check timings [here](./example/timing.py). 7 | 8 | The results are consistent with [nvdiffrast](https://github.com/NVlabs/nvdiffrast) output. Check comparison [here](./example/nvdiffrast_compare.ipynb). 9 | 10 | ## Example 11 | 12 | [Visualize z buffer and normals of cube](./example/cube.py): 13 | ```python 14 | import minimal_pytorch_rasterizer as mpr 15 | import torch 16 | import cv2 17 | import numpy as np 18 | 19 | 20 | dtype = torch.float32 21 | device = torch.device('cuda:0') 22 | 23 | vertices = torch.tensor([ 24 | [0, 0, 0], [1, 0, 0], [1, 1, 0], [0, 1, 0], 25 | [0, 1, 1], [1, 1, 1], [1, 0, 1], [0, 0, 1] 26 | ], dtype=dtype, device=device) 27 | 28 | faces = torch.tensor([ 29 | [0, 2, 1], [0, 3, 2], [2, 3, 4], [2, 4, 5], [1, 2, 5], [1, 5, 6], 30 | [0, 7, 4], [0, 4, 3], [5, 4, 7], [5, 7, 6], [0, 6, 7], [0, 1, 6] 31 | ], dtype=torch.int32, device=device) 32 | 33 | R = torch.tensor(cv2.Rodrigues(np.array([0.5, 0.8, 0.2]))[0], dtype=dtype, device=device) 34 | t = torch.tensor([-0.5, -0.5, 1.3], dtype=dtype, device=device) 35 | vertices = vertices @ R.T + t 36 | 37 | pinhole2d = mpr.Pinhole2D( 38 | fx=250, fy=200, 39 | cx=160, cy=120, 40 | w=320, h=240, 41 | ) 42 | 43 | z_buffer = mpr.project_mesh( 44 | vertices=vertices, 45 | faces=faces, 46 | vertice_values=vertices[:, [2]], # take z coordinate as values 47 | pinhole=pinhole2d 48 | ) 49 | vis_z_buffer_cpu = mpr.vis_z_buffer(z_buffer) 50 | cv2.imwrite('./depth.png', vis_z_buffer_cpu) 51 | 52 | 53 | coords, normals = mpr.estimate_normals( 54 | vertices=vertices, 55 | faces=faces, 56 | pinhole=pinhole2d 57 | ) 58 | vis_normals_cpu = mpr.vis_normals(coords, normals) 59 | cv2.imwrite('./normals.png', vis_normals_cpu) 60 | ``` 61 | Will produce: 62 | 63 | ![result](./example/depth.png) 64 | ![result](./example/normals.png) 65 | 66 | ## Installation 67 | - `pip intall .` or `./setup.sh` 68 | - To build for custom cuda arches set env variable: `export TORCH_CUDA_ARCH_LIST="Pascal Turing"`. This env variable is used [here](https://github.com/pytorch/pytorch/blob/5710374e4e335c6761d2b8b937a2b54a5577cb5d/torch/utils/cpp_extension.py#L1298). 69 | - Possible intallation errors: 70 | - `packedpacked_accessor32` in error msgs means you have pytorch version < 1.3 71 | - Errors caused by pytorch internal header files could mean that you have pytorch cuda version (provided by cudatoolkit) and nvcc cuda version mismatch 72 | - Docker environment to run comparison [notebook](./example/nvdiffrast_compare.ipynb) is provided: 73 | - Install [Docker](https://www.docker.com/), [nvidia-docker](https://github.com/NVIDIA/nvidia-docker), set `nvidia` your default runtime for `docker` 74 | - Build docker image: `make build` 75 | - Enter docker container: `make run` 76 | - Run jupyter 77 | - Tested till pytorch 1.8 78 | - `torch.float32` or `torch.float64` dtypes are supported, `torch.float16` is not 79 | -------------------------------------------------------------------------------- /example/cube.py: -------------------------------------------------------------------------------- 1 | import minimal_pytorch_rasterizer as mpr 2 | import torch 3 | import cv2 4 | import numpy as np 5 | 6 | 7 | dtype = torch.float32 8 | device = torch.device('cuda:0') 9 | 10 | vertices = torch.tensor([ 11 | [0, 0, 0], [1, 0, 0], [1, 1, 0], [0, 1, 0], 12 | [0, 1, 1], [1, 1, 1], [1, 0, 1], [0, 0, 1] 13 | ], dtype=dtype, device=device) 14 | 15 | faces = torch.tensor([ 16 | [0, 2, 1], [0, 3, 2], [2, 3, 4], [2, 4, 5], [1, 2, 5], [1, 5, 6], 17 | [0, 7, 4], [0, 4, 3], [5, 4, 7], [5, 7, 6], [0, 6, 7], [0, 1, 6] 18 | ], dtype=torch.int32, device=device) 19 | 20 | R = torch.tensor(cv2.Rodrigues(np.array([0.5, 0.8, 0.2]))[0], dtype=dtype, device=device) 21 | t = torch.tensor([-0.5, -0.5, 1.3], dtype=dtype, device=device) 22 | vertices = vertices @ R.T + t 23 | 24 | pinhole2d = mpr.Pinhole2D( 25 | fx=250, fy=200, 26 | cx=160, cy=120, 27 | w=320, h=240, 28 | ) 29 | 30 | z_buffer = mpr.project_mesh( 31 | vertices=vertices, 32 | faces=faces, 33 | vertice_values=vertices[:, [2]], # take z coordinate as values 34 | pinhole=pinhole2d 35 | ) 36 | vis_z_buffer_cpu = mpr.vis_z_buffer(z_buffer) 37 | cv2.imwrite('./depth.png', vis_z_buffer_cpu) 38 | 39 | 40 | coords, normals = mpr.estimate_normals( 41 | vertices=vertices, 42 | faces=faces, 43 | pinhole=pinhole2d 44 | ) 45 | vis_normals_cpu = mpr.vis_normals(coords, normals) 46 | cv2.imwrite('./normals.png', vis_normals_cpu) 47 | -------------------------------------------------------------------------------- /example/depth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rmbashirov/minimal_pytorch_rasterizer/de2e1eb9d563e5dbb7b40525829c90ac04f74ef6/example/depth.png -------------------------------------------------------------------------------- /example/normals.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rmbashirov/minimal_pytorch_rasterizer/de2e1eb9d563e5dbb7b40525829c90ac04f74ef6/example/normals.png -------------------------------------------------------------------------------- /example/nvdiffrast_compare.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "id": "genetic-disorder", 7 | "metadata": {}, 8 | "outputs": [], 9 | "source": [ 10 | "import minimal_pytorch_rasterizer as mpr\n", 11 | "import numpy as np\n", 12 | "import torch\n", 13 | "from torch import nn\n", 14 | "import pickle, json\n", 15 | "import cv2\n", 16 | "from copy import deepcopy\n", 17 | "import math\n", 18 | "import nvdiffrast.torch as dr\n", 19 | "import matplotlib.pyplot as plt" 20 | ] 21 | }, 22 | { 23 | "cell_type": "code", 24 | "execution_count": 2, 25 | "id": "marine-burden", 26 | "metadata": {}, 27 | "outputs": [], 28 | "source": [ 29 | "dtype = torch.float32\n", 30 | "device = torch.device('cuda:0')" 31 | ] 32 | }, 33 | { 34 | "cell_type": "markdown", 35 | "id": "unnecessary-marker", 36 | "metadata": {}, 37 | "source": [ 38 | "# Set cube object" 39 | ] 40 | }, 41 | { 42 | "cell_type": "code", 43 | "execution_count": 3, 44 | "id": "rotary-active", 45 | "metadata": {}, 46 | "outputs": [], 47 | "source": [ 48 | "def get_object(dtype, device):\n", 49 | " vertices = torch.tensor([\n", 50 | " [0, 0, 0], [1, 0, 0], [1, 1, 0], [0, 1, 0],\n", 51 | " [0, 1, 1], [1, 1, 1], [1, 0, 1], [0, 0, 1]\n", 52 | " ], dtype=dtype, device=device)\n", 53 | "\n", 54 | " faces = torch.tensor([\n", 55 | " [0, 2, 1], [0, 3, 2], [2, 3, 4], [2, 4, 5], [1, 2, 5], [1, 5, 6],\n", 56 | " [0, 7, 4], [0, 4, 3], [5, 4, 7], [5, 7, 6], [0, 6, 7], [0, 1, 6]\n", 57 | " ], dtype=torch.int32, device=device)\n", 58 | "\n", 59 | " R = torch.tensor(cv2.Rodrigues(np.array([0.5, 0.8, 0.2]))[0], dtype=dtype, device=device)\n", 60 | " t = torch.tensor([-0.5, -0.5, 1.3], dtype=dtype, device=device)\n", 61 | " vertices = vertices @ R.T + t\n", 62 | " \n", 63 | " return vertices, faces" 64 | ] 65 | }, 66 | { 67 | "cell_type": "markdown", 68 | "id": "nutritional-missouri", 69 | "metadata": {}, 70 | "source": [ 71 | "# Set pinhole cam params" 72 | ] 73 | }, 74 | { 75 | "cell_type": "code", 76 | "execution_count": 4, 77 | "id": "adaptive-disease", 78 | "metadata": {}, 79 | "outputs": [], 80 | "source": [ 81 | "K = np.array([\n", 82 | " [250, 0, 160],\n", 83 | " [0, 200, 120],\n", 84 | " [0, 0, 1]\n", 85 | "], dtype=np.float32)\n", 86 | "w = 320\n", 87 | "h = 240\n", 88 | "\n", 89 | "near = 0.01\n", 90 | "far = 100\n", 91 | "\n", 92 | "fx, fy = K[0, 0], K[1, 1]\n", 93 | "cx, cy = K[0, 2], K[1, 2]" 94 | ] 95 | }, 96 | { 97 | "cell_type": "markdown", 98 | "id": "competitive-france", 99 | "metadata": {}, 100 | "source": [ 101 | "# Get nvdiffrast result" 102 | ] 103 | }, 104 | { 105 | "cell_type": "code", 106 | "execution_count": 5, 107 | "id": "varied-incentive", 108 | "metadata": {}, 109 | "outputs": [], 110 | "source": [ 111 | "glctx = dr.RasterizeGLContext()" 112 | ] 113 | }, 114 | { 115 | "cell_type": "code", 116 | "execution_count": 6, 117 | "id": "simplified-veteran", 118 | "metadata": {}, 119 | "outputs": [], 120 | "source": [ 121 | "vertices, faces = get_object(dtype, device)\n", 122 | "\n", 123 | "matrix_ndc = torch.tensor([\n", 124 | " [2 * fx / w, 0.0, (w - 2 * cx) / w, 0],\n", 125 | " [0, 2 * fy / h, (h - 2 * cy) / h, 0],\n", 126 | " [0, 0, (far + near) / (near - far), 2 * far * near / (near - far)],\n", 127 | " [0, 0, -1, 0]\n", 128 | "], device=device, dtype=dtype)\n", 129 | "\n", 130 | "verts_3d_homo = torch.cat([vertices, torch.ones(len(vertices), 1, device=device)], dim=-1)\n", 131 | "verts_3d_homo[:, 2] *= -1 # invert z-axis\n", 132 | "\n", 133 | "verts_ndc = torch.matmul(verts_3d_homo, matrix_ndc.transpose(0, 1))\n", 134 | "\n", 135 | "verts_ndc = torch.unsqueeze(verts_ndc, dim=0)\n", 136 | "\n", 137 | "rast, rast_db = dr.rasterize(glctx, verts_ndc, faces, resolution=[h, w])\n", 138 | "\n", 139 | "render, render_da = dr.interpolate(vertices[:, [2]], rast, faces, rast_db=rast_db, diff_attrs='all')\n", 140 | "\n", 141 | "render_cpu = render[0, ..., 0].detach().cpu().numpy()\n", 142 | "render_cpu[np.isinf(render_cpu)] = 0\n", 143 | "\n", 144 | "nvdiffrast_depth = render_cpu\n", 145 | "nvdiffrast_barycentric_weights = rast[0, ..., [0, 1]].detach().cpu().numpy()" 146 | ] 147 | }, 148 | { 149 | "cell_type": "markdown", 150 | "id": "monthly-samba", 151 | "metadata": {}, 152 | "source": [ 153 | "# Get minimal_pytorch_rasterizer result" 154 | ] 155 | }, 156 | { 157 | "cell_type": "code", 158 | "execution_count": 7, 159 | "id": "necessary-bullet", 160 | "metadata": {}, 161 | "outputs": [], 162 | "source": [ 163 | "vertices, faces = get_object(dtype, device)\n", 164 | "\n", 165 | "pinhole2d = mpr.Pinhole2D(\n", 166 | " fx=fx, fy=fy,\n", 167 | " cx=cx, cy=cy,\n", 168 | " w=w, h=h,\n", 169 | ")\n", 170 | "\n", 171 | "z_buffer = mpr.project_mesh(\n", 172 | " vertices=vertices,\n", 173 | " faces=faces,\n", 174 | " vertice_values=vertices[:, [2]], # take z coordinate as values\n", 175 | " pinhole=pinhole2d\n", 176 | ")\n", 177 | "\n", 178 | "minimal_pytorch_rasterizer_depth = z_buffer[..., 0].detach().cpu().numpy()" 179 | ] 180 | }, 181 | { 182 | "cell_type": "markdown", 183 | "id": "impaired-acceptance", 184 | "metadata": {}, 185 | "source": [ 186 | "# Compare depth" 187 | ] 188 | }, 189 | { 190 | "cell_type": "code", 191 | "execution_count": 8, 192 | "id": "bridal-advocacy", 193 | "metadata": {}, 194 | "outputs": [ 195 | { 196 | "data": { 197 | "image/png": "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\n", 198 | "text/plain": [ 199 | "
" 200 | ] 201 | }, 202 | "metadata": { 203 | "needs_background": "light" 204 | }, 205 | "output_type": "display_data" 206 | } 207 | ], 208 | "source": [ 209 | "fig, axs = plt.subplots(1, 3, figsize=(15, 5))\n", 210 | "axs[0].imshow(nvdiffrast_depth, vmin=0, vmax=2)\n", 211 | "axs[0].set_title('nvdiffrast')\n", 212 | "axs[1].imshow(minimal_pytorch_rasterizer_depth, vmin=0, vmax=2)\n", 213 | "axs[1].set_title('minimal_pytorch_rasterizer')\n", 214 | "axs[2].imshow(np.abs(nvdiffrast_depth - minimal_pytorch_rasterizer_depth), vmin=0, vmax=.01)\n", 215 | "axs[2].set_title('diff, vmax=0.01')\n", 216 | "plt.show()" 217 | ] 218 | }, 219 | { 220 | "cell_type": "markdown", 221 | "id": "square-nutrition", 222 | "metadata": {}, 223 | "source": [ 224 | "# Compare barycentric coordinates" 225 | ] 226 | }, 227 | { 228 | "cell_type": "markdown", 229 | "id": "figured-liverpool", 230 | "metadata": {}, 231 | "source": [ 232 | "minimal_pytorch_rasterizer does not prodive an explicit barycentric coordinates output.\n", 233 | "\n", 234 | "Below is an imitation of what happens in rasterizer_kernel.cu" 235 | ] 236 | }, 237 | { 238 | "cell_type": "code", 239 | "execution_count": 9, 240 | "id": "above-token", 241 | "metadata": {}, 242 | "outputs": [], 243 | "source": [ 244 | "def cpu_render(\n", 245 | " vertices, faces,\n", 246 | " fx, fy, cx, cy, h, w\n", 247 | "):\n", 248 | " \n", 249 | " result = np.ones((h, w), dtype=np.float32) * 1e6\n", 250 | " \n", 251 | " weights = np.zeros((h, w, 3), dtype=np.float32)\n", 252 | " \n", 253 | " n = len(vertices)\n", 254 | " m = len(faces)\n", 255 | " \n", 256 | " xs = np.zeros(n, dtype=np.float32)\n", 257 | " ys = np.zeros(n, dtype=np.float32)\n", 258 | " zs = np.zeros(n, dtype=np.float32)\n", 259 | " for i in range(n):\n", 260 | " z = vertices[i][2]\n", 261 | " z_inv = 1. / z;\n", 262 | " xs[i] = vertices[i][0] * z_inv * fx + cx;\n", 263 | " xs[i] = 2 * xs[i] / w - 1;\n", 264 | " ys[i] = vertices[i][1] * z_inv * fy + cy;\n", 265 | " ys[i] = 2 * ys[i] / h - 1;\n", 266 | " zs[i] = z;\n", 267 | " \n", 268 | " face_ndc = np.zeros(9, dtype=np.float32)\n", 269 | " face_ndc_inv = np.zeros(9, dtype=np.float32)\n", 270 | " \n", 271 | " for face_i in range(m):\n", 272 | " ai = faces[face_i][0];\n", 273 | " bi = faces[face_i][1];\n", 274 | " ci = faces[face_i][2];\n", 275 | " \n", 276 | " face_ndc[0] = xs[ai]; face_ndc[1] = ys[ai]; face_ndc[2] = zs[ai];\n", 277 | " face_ndc[3] = xs[bi]; face_ndc[4] = ys[bi]; face_ndc[5] = zs[bi];\n", 278 | " face_ndc[6] = xs[ci]; face_ndc[7] = ys[ci]; face_ndc[8] = zs[ci];\n", 279 | " \n", 280 | " face_ndc_inv[0] = face_ndc[4] - face_ndc[7];\n", 281 | " face_ndc_inv[1] = face_ndc[6] - face_ndc[3];\n", 282 | " face_ndc_inv[2] = face_ndc[3] * face_ndc[7] - face_ndc[6] * face_ndc[4];\n", 283 | " face_ndc_inv[3] = face_ndc[7] - face_ndc[1];\n", 284 | " face_ndc_inv[4] = face_ndc[0] - face_ndc[6];\n", 285 | " face_ndc_inv[5] = face_ndc[6] * face_ndc[1] - face_ndc[0] * face_ndc[7];\n", 286 | " face_ndc_inv[6] = face_ndc[1] - face_ndc[4];\n", 287 | " face_ndc_inv[7] = face_ndc[3] - face_ndc[0];\n", 288 | " face_ndc_inv[8] = face_ndc[0] * face_ndc[4] - face_ndc[3] * face_ndc[1];\n", 289 | "\n", 290 | " denom = (\n", 291 | " face_ndc[6] * (face_ndc[1] - face_ndc[4]) +\n", 292 | " face_ndc[0] * (face_ndc[4] - face_ndc[7]) +\n", 293 | " face_ndc[3] * (face_ndc[7] - face_ndc[1])\n", 294 | " );\n", 295 | " \n", 296 | " face_ndc_inv /= denom;\n", 297 | " \n", 298 | " min_x = min(min(face_ndc[0], face_ndc[3]), face_ndc[6]);\n", 299 | " min_x = (min_x + 1) / 2 * w; # convert from [-1, 1] to [0, W]\n", 300 | " min_xi = int(math.floor(min_x));\n", 301 | " min_xi = min(max(min_xi, 0), w - 1);\n", 302 | " max_x = max(max(face_ndc[0], face_ndc[3]), face_ndc[6]);\n", 303 | " max_x = (max_x + 1) / 2 * w;\n", 304 | " max_xi = int(math.ceil(max_x));\n", 305 | " max_xi = min(max(max_xi, 0), w - 1);\n", 306 | "\n", 307 | " min_y = min(min(face_ndc[1], face_ndc[4]), face_ndc[7]);\n", 308 | " min_y = (min_y + 1) / 2 * h;\n", 309 | " min_yi = int(math.floor(min_y));\n", 310 | " min_yi = min(max(min_yi, 0), h - 1);\n", 311 | " max_y = max(max(face_ndc[1], face_ndc[4]), face_ndc[7]);\n", 312 | " max_y = (max_y + 1) / 2 * h;\n", 313 | " max_yi = int(math.ceil(max_y));\n", 314 | " max_yi = min(max(max_yi, 0), h - 1);\n", 315 | " \n", 316 | " top, bottom = min_yi, max_yi;\n", 317 | " left, right = min_xi, max_xi;\n", 318 | " \n", 319 | " def calc_bary(x, y):\n", 320 | " if (((y - face_ndc[1]) * (face_ndc[3] - face_ndc[0]) > (x - face_ndc[0]) * (face_ndc[4] - face_ndc[1])) or\n", 321 | " ((y - face_ndc[4]) * (face_ndc[6] - face_ndc[3]) > (x - face_ndc[3]) * (face_ndc[7] - face_ndc[4])) or\n", 322 | " ((y - face_ndc[7]) * (face_ndc[0] - face_ndc[6]) > (x - face_ndc[6]) * (face_ndc[1] - face_ndc[7]))):\n", 323 | " return None\n", 324 | " \n", 325 | " wa = face_ndc_inv[0] * x + face_ndc_inv[1] * y + face_ndc_inv[2];\n", 326 | " wb = face_ndc_inv[3] * x + face_ndc_inv[4] * y + face_ndc_inv[5];\n", 327 | " wc = face_ndc_inv[6] * x + face_ndc_inv[7] * y + face_ndc_inv[8];\n", 328 | " \n", 329 | " wsum = wa + wb + wc;\n", 330 | " wa /= wsum; wb /= wsum; wc /= wsum;\n", 331 | " \n", 332 | " wa /= face_ndc[2];\n", 333 | " wb /= face_ndc[5];\n", 334 | " wc /= face_ndc[8];\n", 335 | " \n", 336 | " wsum = wa + wb + wc;\n", 337 | " wa /= wsum; wb /= wsum; wc /= wsum;\n", 338 | " \n", 339 | " return wa, wb, wc \n", 340 | " \n", 341 | " \n", 342 | " for i in range(top, bottom + 1):\n", 343 | " for j in range(left, right + 1):\n", 344 | " x = (j + 0.5) / w * 2 - 1;\n", 345 | " y = (i + 0.5) / h * 2 - 1;\n", 346 | "\n", 347 | " bary = calc_bary(x, y)\n", 348 | " if bary is None:\n", 349 | " continue\n", 350 | " \n", 351 | " wa, wb, wc = bary\n", 352 | " \n", 353 | " face_z = wa * face_ndc[2] + wb * face_ndc[5] + wc * face_ndc[8];\n", 354 | " \n", 355 | " if face_z < result[i][j]:\n", 356 | " result[i][j] = face_z\n", 357 | " weights[i, j, 0] = wa\n", 358 | " weights[i, j, 1] = wb\n", 359 | " weights[i, j, 2] = wc\n", 360 | " \n", 361 | " return result, weights" 362 | ] 363 | }, 364 | { 365 | "cell_type": "code", 366 | "execution_count": 10, 367 | "id": "informative-pasta", 368 | "metadata": {}, 369 | "outputs": [ 370 | { 371 | "data": { 372 | "image/png": "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\n", 373 | "text/plain": [ 374 | "
" 375 | ] 376 | }, 377 | "metadata": { 378 | "needs_background": "light" 379 | }, 380 | "output_type": "display_data" 381 | } 382 | ], 383 | "source": [ 384 | "vertices, faces = get_object(dtype, device)\n", 385 | "\n", 386 | "cpu_depth, cpu_weights = cpu_render(\n", 387 | " vertices.detach().cpu().numpy(), faces.detach().cpu().numpy(), \n", 388 | " fx=fx, fy=fy,\n", 389 | " cx=cx, cy=cy,\n", 390 | " w=w, h=h\n", 391 | ")\n", 392 | "cpu_depth[cpu_depth > 1e3] = 0\n", 393 | "\n", 394 | "plt.imshow(cpu_depth)\n", 395 | "plt.title('depth cpu')\n", 396 | "plt.show()" 397 | ] 398 | }, 399 | { 400 | "cell_type": "code", 401 | "execution_count": 11, 402 | "id": "literary-james", 403 | "metadata": {}, 404 | "outputs": [ 405 | { 406 | "data": { 407 | "image/png": "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\n", 408 | "text/plain": [ 409 | "
" 410 | ] 411 | }, 412 | "metadata": { 413 | "needs_background": "light" 414 | }, 415 | "output_type": "display_data" 416 | }, 417 | { 418 | "name": "stdout", 419 | "output_type": "stream", 420 | "text": [ 421 | "\n", 422 | "\n", 423 | "\n" 424 | ] 425 | }, 426 | { 427 | "data": { 428 | "image/png": "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\n", 429 | "text/plain": [ 430 | "
" 431 | ] 432 | }, 433 | "metadata": { 434 | "needs_background": "light" 435 | }, 436 | "output_type": "display_data" 437 | }, 438 | { 439 | "name": "stdout", 440 | "output_type": "stream", 441 | "text": [ 442 | "\n", 443 | "\n", 444 | "\n" 445 | ] 446 | } 447 | ], 448 | "source": [ 449 | "for i in range(2):\n", 450 | " gt = nvdiffrast_barycentric_weights[..., i]\n", 451 | " pred = cpu_weights[..., i]\n", 452 | " diff = np.abs(pred - gt)\n", 453 | " \n", 454 | " fig, axs = plt.subplots(1, 3, figsize=(15, 5))\n", 455 | " axs[0].imshow(pred, vmin=0, vmax=1)\n", 456 | " axs[0].title.set_text('pred')\n", 457 | " axs[1].imshow(gt, vmin=0, vmax=1)\n", 458 | " axs[1].title.set_text('gt')\n", 459 | " axs[2].imshow(diff, vmin=0, vmax=.2)\n", 460 | " axs[2].title.set_text('diff, vmax=0.2')\n", 461 | " fig.suptitle(f'Barycentric weight {i}', fontsize=16)\n", 462 | " plt.tight_layout()\n", 463 | " plt.show()\n", 464 | " \n", 465 | " print('\\n' * 2)" 466 | ] 467 | } 468 | ], 469 | "metadata": { 470 | "kernelspec": { 471 | "display_name": "Python 3", 472 | "language": "python", 473 | "name": "python3" 474 | }, 475 | "language_info": { 476 | "codemirror_mode": { 477 | "name": "ipython", 478 | "version": 3 479 | }, 480 | "file_extension": ".py", 481 | "mimetype": "text/x-python", 482 | "name": "python", 483 | "nbconvert_exporter": "python", 484 | "pygments_lexer": "ipython3", 485 | "version": "3.7.7" 486 | } 487 | }, 488 | "nbformat": 4, 489 | "nbformat_minor": 5 490 | } 491 | -------------------------------------------------------------------------------- /example/smpl_tmp.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rmbashirov/minimal_pytorch_rasterizer/de2e1eb9d563e5dbb7b40525829c90ac04f74ef6/example/smpl_tmp.pkl -------------------------------------------------------------------------------- /example/timing.py: -------------------------------------------------------------------------------- 1 | import minimal_pytorch_rasterizer as mpr 2 | 3 | import torch 4 | 5 | from skimage import io 6 | import numpy as np 7 | import argparse 8 | import time 9 | import pickle 10 | from collections import defaultdict 11 | 12 | 13 | def save_t(t_hist, t_names, ts): 14 | assert len(ts) - 1 == len(t_names) 15 | ts = np.array(ts) 16 | ts = ts[1:] - ts[:-1] 17 | for i, t_name in enumerate(t_names): 18 | t_hist[t_name].append(ts[i]) 19 | 20 | 21 | def print_t(t_hist, t_names, skip_fraq=0.1): 22 | skip_counts = [] 23 | max_t_names_len = max(map(len, t_names)) + 5 24 | for t_name in t_names: 25 | dts = t_hist[t_name] 26 | skip_count = int(len(dts) * skip_fraq) 27 | skip_counts.append(skip_count) 28 | dts = dts[skip_count:] 29 | mean_str = f'{np.mean(dts) * 1000:.2f}'.rjust(6) 30 | std_str = f'{np.std(dts) * 1000:.2f}'.ljust(6) 31 | print(f'\t{t_name}: '.ljust(max_t_names_len + 1) + f'{mean_str} +- {std_str}ms') 32 | # print(f'skip_counts: {skip_counts}') 33 | 34 | 35 | def parse_args(): 36 | parser = argparse.ArgumentParser() 37 | parser.add_argument('--repeat', type=int, default=1000) 38 | parser.add_argument('--double', action='store_true') 39 | parsed_args = parser.parse_args() 40 | return parsed_args 41 | 42 | 43 | def calculate_timings_0(vertices_cpu, uv_cpu, faces_cpu, pinhole, repeat, dtype=torch.float32): 44 | t_hist = defaultdict(list) 45 | t_names = [ 46 | 'cpu->gpu_transfer', 47 | 'project_mesh', 48 | 'gpu->cpu_transfer', 49 | ] 50 | 51 | for it in range(repeat): 52 | t0 = time.time() 53 | vertices = torch.tensor(vertices_cpu, dtype=dtype, device='cuda:0') 54 | vertice_values = torch.tensor(uv_cpu, dtype=dtype, device='cuda:0') 55 | faces = torch.tensor(faces_cpu, dtype=torch.int32, device='cuda:0') 56 | 57 | t1 = time.time() 58 | projected = mpr.project_mesh(vertices, faces, vertice_values, pinhole) 59 | 60 | t2 = time.time() 61 | if it == 0: 62 | img = (projected * 255).cpu().numpy().round().clip(0, 255).astype(np.uint8) 63 | else: 64 | img = projected[:5, :5, :].cpu().numpy() 65 | 66 | t3 = time.time() 67 | 68 | if it > 0: 69 | save_t(t_hist, t_names, [t0, t1, t2, t3]) 70 | 71 | if it == 0: 72 | io.imsave('./tmp_u.png', img[:, :, 0]) 73 | io.imsave('./tmp_v.png', img[:, :, 1]) 74 | 75 | if repeat > 1: 76 | print('method 1 timings:') 77 | print_t(t_hist, t_names) 78 | 79 | 80 | def calculate_timings_1(vertices_cpu, uv_cpu, faces_cpu, pinhole, repeat, dtype=torch.float32): 81 | for it in range(repeat + 1): 82 | if it == 0: 83 | vertices = torch.tensor(vertices_cpu, dtype=dtype, device='cuda:0') 84 | vertice_values = torch.tensor(uv_cpu, dtype=dtype, device='cuda:0') 85 | faces = torch.tensor(faces_cpu, dtype=torch.int32, device='cuda:0') 86 | elif it == 1: 87 | start = time.time() 88 | 89 | projected = mpr.project_mesh(vertices, faces, vertice_values, pinhole) 90 | torch.cuda.synchronize() 91 | 92 | if it == 0: 93 | img = (projected * 255).cpu().numpy().round().clip(0, 255).astype(np.uint8) 94 | 95 | io.imsave('./tmp_u.png', img[:, :, 0]) 96 | io.imsave('./tmp_v.png', img[:, :, 1]) 97 | 98 | torch.cuda.synchronize() 99 | end = time.time() 100 | timing = (end - start) / (repeat - 1) * 1000 101 | print(f'method 2 timings:\n\t{timing:.3f}ms') 102 | 103 | 104 | def test_project_mesh(repeat, double=False): 105 | with open('smpl_tmp.pkl', 'rb') as f: 106 | mesh_data = pickle.load(f) 107 | vertices_cpu = mesh_data['vertices'] 108 | faces_cpu = mesh_data['faces'] 109 | uv_cpu = mesh_data['uv'] 110 | 111 | pinhole = mpr.Pinhole2D( 112 | fx=500, fy=500, 113 | cx=500, cy=500, 114 | h=1000, w=1000 115 | ) 116 | 117 | R = np.array([ 118 | [1., 0., 0.], 119 | [0., -1., 0.], 120 | [0., 0., -1.] 121 | ]) 122 | t = np.array([[0., -0.3, 1.2]]) 123 | vertices_cpu = vertices_cpu @ R.T + t 124 | 125 | dtype = torch.float64 if double else torch.float32 126 | calculate_timings_0(vertices_cpu, uv_cpu, faces_cpu, pinhole, repeat, dtype=dtype) 127 | if repeat > 1: 128 | calculate_timings_1(vertices_cpu, uv_cpu, faces_cpu, pinhole, repeat, dtype=dtype) 129 | 130 | 131 | def main(): 132 | parsed_args = parse_args() 133 | test_project_mesh(repeat=parsed_args.repeat, double=parsed_args.double) 134 | 135 | 136 | if __name__ == '__main__': 137 | main() 138 | -------------------------------------------------------------------------------- /minimal_pytorch_rasterizer/__init__.py: -------------------------------------------------------------------------------- 1 | from minimal_pytorch_rasterizer.camera import Pinhole2D 2 | from minimal_pytorch_rasterizer.rasterizer import project_mesh, estimate_normals 3 | from minimal_pytorch_rasterizer.utils import vis_normals, vis_z_buffer 4 | 5 | __version__ = '0.5' 6 | name = 'minimal_pytorch_rasterizer' 7 | -------------------------------------------------------------------------------- /minimal_pytorch_rasterizer/assert_utils.py: -------------------------------------------------------------------------------- 1 | import torch 2 | 3 | def is_cuda_tensor(t): 4 | assert torch.is_tensor(t) 5 | assert t.is_cuda 6 | 7 | def check_shape_len(t, n): 8 | assert len(t.shape) == n 9 | -------------------------------------------------------------------------------- /minimal_pytorch_rasterizer/camera.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import numpy as np 3 | 4 | 5 | class Pinhole2D: 6 | def __init__(self, K=None, fx=None, fy=None, cx=None, cy=None, h=0, w=0): 7 | if K is not None: 8 | assert fx is None and fy is None and cx is None and cy is None 9 | self.fx = K[0, 0] 10 | self.fy = K[1, 1] 11 | self.cx = K[0, 2] 12 | self.cy = K[1, 2] 13 | else: 14 | assert \ 15 | fx is not None and fy is not None and \ 16 | cx is not None and cy is not None 17 | self.fx = fx 18 | self.fy = fy 19 | self.cx = cx 20 | self.cy = cy 21 | self.h = h 22 | self.w = w 23 | 24 | def __str__(self): 25 | result = f'fx: {self.fx}, fy: {self.fy}, cx: {self.cx}, cy: {self.cy}' 26 | if self.h > 0 and self.w > 0: 27 | result += f', h: {self.h}, w: {self.w}' 28 | return result 29 | 30 | def get_K(self): 31 | return np.array([ 32 | [self.fx, 0, self.cx], 33 | [0, self.fy, self.cy], 34 | [0, 0, 1] 35 | ]) 36 | 37 | def project_ndc(self, vertices, eps=1e-9): 38 | """ 39 | vertices: torch.Tensor of shape (N, 3), 3 stands for xyz 40 | """ 41 | assert isinstance(vertices, torch.Tensor) 42 | assert len(vertices.shape) == 2 43 | assert vertices.shape[1] == 3 44 | K = torch.tensor(self.get_K(), 45 | device=vertices.device, dtype=vertices.dtype) 46 | 47 | # apply intrinsics 48 | vertices_ndc = vertices @ K.transpose(0, 1) 49 | 50 | # divide xy by z, leave z unchanged 51 | vertices_ndc[:, [0, 1]] /= vertices_ndc[:, [2]] + eps 52 | 53 | # convert x from [0, w) to [-1, 1] range 54 | # convert y from [0, h) to [-1, 1] range 55 | wh = torch.tensor( 56 | [self.w, self.h], 57 | device=vertices.device, dtype=vertices.dtype 58 | ).unsqueeze(0) 59 | vertices_ndc[:, [0, 1]] = 2 * vertices_ndc[:, [0, 1]] / wh - 1 60 | 61 | return vertices_ndc 62 | -------------------------------------------------------------------------------- /minimal_pytorch_rasterizer/cuda/rasterizer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // CUDA forward declarations 5 | 6 | std::vector estimate_normals_cuda( 7 | const torch::Tensor& vertices_ndc, 8 | const torch::Tensor& faces, 9 | const torch::Tensor& vertices, 10 | const torch::Tensor& vertices_filter, 11 | int h, int w 12 | ); 13 | 14 | 15 | torch::Tensor project_mesh_cuda( 16 | const torch::Tensor& vertices_ndc, 17 | const torch::Tensor& faces, 18 | const torch::Tensor& vertice_values, 19 | const torch::Tensor& vertices_filter, 20 | int h, int w 21 | ); 22 | 23 | // C++ interface 24 | 25 | #define CHECK_CUDA(x) TORCH_CHECK(x.type().is_cuda(), #x " must be a CUDA tensor") 26 | #define CHECK_CONTIGUOUS(x) TORCH_CHECK(x.is_contiguous(), #x " must be contiguous") 27 | #define CHECK_INPUT(x) CHECK_CUDA(x); CHECK_CONTIGUOUS(x) 28 | 29 | void check_equal_dtype(const torch::Tensor& a, const torch::Tensor& b) { 30 | TORCH_CHECK( 31 | a.dtype() == b.dtype(), 32 | "expected equal dtype, got ", a.dtype(), " != ", b.dtype() 33 | ); 34 | } 35 | 36 | void check_equal_gpuid(const torch::Tensor& a, const torch::Tensor& b) { 37 | TORCH_CHECK( 38 | a.device().index() == b.device().index(), 39 | "expected equal gpu id, got ", a.device().index(), " != ", b.device().index() 40 | ); 41 | } 42 | 43 | std::vector estimate_normals( 44 | const torch::Tensor& vertices_ndc, 45 | const torch::Tensor& faces, 46 | const torch::Tensor& vertices, 47 | const torch::Tensor& vertices_filter, 48 | int h, int w 49 | ) { 50 | TORCH_CHECK(h > 0, "h expected to be > 0"); 51 | TORCH_CHECK(w > 0, "w expected to be > 0"); 52 | CHECK_INPUT(vertices_ndc); 53 | CHECK_INPUT(faces); 54 | CHECK_INPUT(vertices_filter); 55 | return estimate_normals_cuda( 56 | vertices_ndc, faces, vertices, vertices_filter, 57 | h, w 58 | ); 59 | } 60 | 61 | torch::Tensor project_mesh( 62 | const torch::Tensor& vertices_ndc, 63 | const torch::Tensor& faces, 64 | const torch::Tensor& vertice_values, 65 | const torch::Tensor& vertices_filter, 66 | int h, int w 67 | ) { 68 | TORCH_CHECK(h > 0, "h expected to be > 0"); 69 | TORCH_CHECK(w > 0, "w expected to be > 0"); 70 | CHECK_INPUT(vertices_ndc); 71 | CHECK_INPUT(faces); 72 | CHECK_INPUT(vertice_values); 73 | CHECK_INPUT(vertices_filter); 74 | return project_mesh_cuda( 75 | vertices_ndc, faces, vertice_values, vertices_filter, 76 | h, w 77 | ); 78 | } 79 | 80 | PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) { 81 | m.def("estimate_normals", &estimate_normals, "estimate_normals (CUDA)"); 82 | m.def("project_mesh", &project_mesh, "project_mesh (CUDA)"); 83 | } -------------------------------------------------------------------------------- /minimal_pytorch_rasterizer/cuda/rasterizer_kernel.cu: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | There are 2 ways to rasterize triangles that came to mind: 4 | 1) iterate over all pixels (they define CUDA grid), for selected pixel feed all triangles to 1 CUDA block 5 | 2) iterate over all triangels (they define CUDA grid), for selected triangle feed pixels that are bounded by selected triangle to 1 CUDA block 6 | 7 | 2nd way is implemented here 8 | */ 9 | 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #define BLOCK_SIZE 512 20 | #define BLOCK_SIZE_2D_X 32 21 | #define BLOCK_SIZE_2D_Y 16 22 | #define BLOCK_SIZE_3D_X 32 23 | #define BLOCK_SIZE_3D_Y 8 24 | #define BLOCK_SIZE_3D_Z 4 25 | 26 | // vertices coords: 27 | // vertices[:, 0]: x 28 | // vertices[:, 1]: y 29 | // vertices[:, 2]: z 30 | 31 | // 2d tensor axis: 32 | // 0: yi 33 | // 1: xi 34 | 35 | // 3d tensor axis: 36 | // 0: zi 37 | // 1: yi 38 | // 2: xi 39 | 40 | template 41 | __device__ __forceinline__ scalar_t atomicMinFloat(scalar_t * addr, scalar_t value) { 42 | scalar_t old; 43 | old = (value >= 0) ? __int_as_float(atomicMin((int *)addr, __float_as_int(value))) : 44 | __uint_as_float(atomicMax((unsigned int *)addr, __float_as_uint(value))); 45 | return old; 46 | } 47 | 48 | __device__ double atomicMin_double(double* address, double val) 49 | { 50 | unsigned long long int* address_as_ull = (unsigned long long int*) address; 51 | unsigned long long int old = *address_as_ull, assumed; 52 | do { 53 | assumed = old; 54 | old = atomicCAS(address_as_ull, assumed, 55 | __double_as_longlong(fmin(val, __longlong_as_double(assumed)))); 56 | } while (assumed != old); 57 | return __longlong_as_double(old); 58 | } 59 | 60 | // kernel utils 61 | 62 | template 63 | __device__ int lower_bound(const scalar_t* values, const scalar_t value, const int N) { 64 | int left = 0; 65 | int right = N; 66 | int mid; 67 | while (right - left > 1) { 68 | mid = (left + right) / 2; 69 | if (values[mid] < value) { 70 | left = mid; 71 | } else { 72 | right = mid; 73 | } 74 | } 75 | return right; 76 | } 77 | 78 | // kernels 79 | 80 | template 81 | __global__ void rasterize_cuda_kernel( 82 | const torch::PackedTensorAccessor32 vertices_ndc, 83 | const torch::PackedTensorAccessor32 faces, 84 | const torch::PackedTensorAccessor32 vertices_filter, 85 | torch::PackedTensorAccessor32 depth, 86 | scalar_t* global_face_ndc_inv, 87 | int* global_is_bad_face 88 | ) { 89 | const int face_indx = blockIdx.x; 90 | const int H = depth.size(0); 91 | const int W = depth.size(1); 92 | 93 | scalar_t min_x, max_x, min_y, max_y; 94 | scalar_t denom; 95 | 96 | __shared__ int vertices_per_thread_x, vertices_per_thread_y; 97 | __shared__ int ai, bi, ci; 98 | __shared__ bool is_bad_face; 99 | __shared__ int min_xi, max_xi, min_yi, max_yi; 100 | __shared__ scalar_t face_ndc[9]; 101 | __shared__ scalar_t face_ndc_inv[9]; 102 | const scalar_t eps = 1e-5; 103 | 104 | if (threadIdx.x == 0 && threadIdx.y == 0) { 105 | ai = faces[face_indx][0]; 106 | bi = faces[face_indx][1]; 107 | ci = faces[face_indx][2]; 108 | 109 | if (vertices_filter[ai] == 0 || vertices_filter[bi] == 0 || vertices_filter[ci] == 0) { 110 | is_bad_face = true; 111 | global_is_bad_face[face_indx] = 1; 112 | return; 113 | } 114 | 115 | face_ndc[0] = vertices_ndc[ai][0]; face_ndc[1] = vertices_ndc[ai][1]; face_ndc[2] = vertices_ndc[ai][2]; 116 | face_ndc[3] = vertices_ndc[bi][0]; face_ndc[4] = vertices_ndc[bi][1]; face_ndc[5] = vertices_ndc[bi][2]; 117 | face_ndc[6] = vertices_ndc[ci][0]; face_ndc[7] = vertices_ndc[ci][1]; face_ndc[8] = vertices_ndc[ci][2]; 118 | 119 | // negative vertex 120 | is_bad_face = false; 121 | if (face_ndc[2] < eps or face_ndc[5] < eps or face_ndc[8] < eps) { 122 | is_bad_face = true; 123 | global_is_bad_face[face_indx] = 1; 124 | return; 125 | } 126 | 127 | face_ndc_inv[0] = face_ndc[4] - face_ndc[7]; 128 | face_ndc_inv[1] = face_ndc[6] - face_ndc[3]; 129 | face_ndc_inv[2] = face_ndc[3] * face_ndc[7] - face_ndc[6] * face_ndc[4]; 130 | face_ndc_inv[3] = face_ndc[7] - face_ndc[1]; 131 | face_ndc_inv[4] = face_ndc[0] - face_ndc[6]; 132 | face_ndc_inv[5] = face_ndc[6] * face_ndc[1] - face_ndc[0] * face_ndc[7]; 133 | face_ndc_inv[6] = face_ndc[1] - face_ndc[4]; 134 | face_ndc_inv[7] = face_ndc[3] - face_ndc[0]; 135 | face_ndc_inv[8] = face_ndc[0] * face_ndc[4] - face_ndc[3] * face_ndc[1]; 136 | 137 | denom = ( 138 | face_ndc[6] * (face_ndc[1] - face_ndc[4]) + 139 | face_ndc[0] * (face_ndc[4] - face_ndc[7]) + 140 | face_ndc[3] * (face_ndc[7] - face_ndc[1]) 141 | ); 142 | 143 | // if (abs(denom) < eps) { 144 | // is_bad_face = true; 145 | // global_is_bad_face[face_indx] = 1; 146 | // return; 147 | // } 148 | 149 | for (int i = 0; i < 9; ++i) { 150 | face_ndc_inv[i] /= denom; 151 | } 152 | 153 | for (int i = 0; i < 9; ++i) { 154 | global_face_ndc_inv[9 * face_indx + i] = face_ndc_inv[i]; 155 | } 156 | 157 | global_is_bad_face[face_indx] = 0; 158 | 159 | min_x = min(min(face_ndc[0], face_ndc[3]), face_ndc[6]); 160 | min_x = (min_x + 1) / 2 * W; // convert from ndc to img coordinates 161 | min_xi = static_cast(floorf(static_cast(min_x))); 162 | min_xi = min(max(min_xi, 0), W - 1); 163 | max_x = max(max(face_ndc[0], face_ndc[3]), face_ndc[6]); 164 | max_x = (max_x + 1) / 2 * W; 165 | max_xi = static_cast(ceilf(static_cast(max_x))); 166 | max_xi = min(max(max_xi, 0), W - 1); 167 | 168 | min_y = min(min(face_ndc[1], face_ndc[4]), face_ndc[7]); 169 | min_y = (min_y + 1) / 2 * H; 170 | min_yi = static_cast(floorf(static_cast(min_y))); 171 | min_yi = min(max(min_yi, 0), H - 1); 172 | max_y = max(max(face_ndc[1], face_ndc[4]), face_ndc[7]); 173 | max_y = (max_y + 1) / 2 * H; 174 | max_yi = static_cast(ceilf(static_cast(max_y))); 175 | max_yi = min(max(max_yi, 0), H - 1); 176 | 177 | vertices_per_thread_x = (max_xi - min_xi) / blockDim.x + 1; 178 | vertices_per_thread_y = (max_yi - min_yi) / blockDim.y + 1; 179 | } 180 | __syncthreads(); 181 | if (is_bad_face) { 182 | return; 183 | } 184 | 185 | const int left = min_xi + vertices_per_thread_x * threadIdx.x; 186 | const int right = min(left + vertices_per_thread_x, max_xi); 187 | 188 | const int top = min_yi + vertices_per_thread_y * threadIdx.y; 189 | const int bottom = min(top + vertices_per_thread_y, max_yi); 190 | 191 | scalar_t x, y, face_z, wa, wb, wc, wsum; 192 | for (int i = top; i <= bottom; i++) { 193 | for (int j = left; j <= right; j++) { 194 | x = 2 * ((scalar_t)j + 0.5) / W - 1; 195 | y = 2 * ((scalar_t)i + 0.5) / H - 1; 196 | 197 | // check pixel is inside the face 198 | if (((y - face_ndc[1]) * (face_ndc[3] - face_ndc[0]) > (x - face_ndc[0]) * (face_ndc[4] - face_ndc[1])) || 199 | ((y - face_ndc[4]) * (face_ndc[6] - face_ndc[3]) > (x - face_ndc[3]) * (face_ndc[7] - face_ndc[4])) || 200 | ((y - face_ndc[7]) * (face_ndc[0] - face_ndc[6]) > (x - face_ndc[6]) * (face_ndc[1] - face_ndc[7]))) { 201 | continue; 202 | } 203 | 204 | wa = face_ndc_inv[0] * x + face_ndc_inv[1] * y + face_ndc_inv[2]; 205 | wb = face_ndc_inv[3] * x + face_ndc_inv[4] * y + face_ndc_inv[5]; 206 | wc = face_ndc_inv[6] * x + face_ndc_inv[7] * y + face_ndc_inv[8]; 207 | wsum = wa + wb + wc; 208 | wa /= wsum; wb /= wsum; wc /= wsum; 209 | 210 | wa /= face_ndc[2]; 211 | wb /= face_ndc[5]; 212 | wc /= face_ndc[8]; 213 | wsum = wa + wb + wc; 214 | wa /= wsum; wb /= wsum; wc /= wsum; 215 | 216 | face_z = wa * face_ndc[2] + wb * face_ndc[5] + wc * face_ndc[8]; 217 | 218 | if (sizeof(scalar_t) == sizeof(double)) { 219 | atomicMin_double((double*)&depth[i][j], (double)face_z); 220 | } else { 221 | atomicMinFloat(&depth[i][j], face_z); 222 | } 223 | } 224 | } 225 | } 226 | 227 | 228 | template 229 | __global__ void interpolate_cuda_kernel( 230 | const torch::PackedTensorAccessor32 vertices_ndc, 231 | const torch::PackedTensorAccessor32 faces, 232 | const torch::PackedTensorAccessor32 depth, 233 | const scalar_t* global_face_ndc_inv, 234 | const int* global_is_bad_face, 235 | const torch::PackedTensorAccessor32 vertice_values, 236 | torch::PackedTensorAccessor32 result 237 | ) { 238 | const int face_indx = blockIdx.x; 239 | 240 | if (global_is_bad_face[face_indx]) { 241 | return; 242 | } 243 | 244 | const int H = depth.size(0); 245 | const int W = depth.size(1); 246 | const int C = vertice_values.size(1); 247 | const scalar_t eps = 1e-5; 248 | 249 | scalar_t min_x, max_x, min_y, max_y; 250 | __shared__ int vertices_per_thread_x, vertices_per_thread_y; 251 | __shared__ int ai, bi, ci; 252 | __shared__ scalar_t face_ndc[9]; 253 | __shared__ scalar_t face_ndc_inv[9]; 254 | __shared__ int min_xi, max_xi, min_yi, max_yi; 255 | 256 | if (threadIdx.x == 0 && threadIdx.y == 0) { 257 | ai = faces[face_indx][0]; 258 | bi = faces[face_indx][1]; 259 | ci = faces[face_indx][2]; 260 | 261 | face_ndc[0] = vertices_ndc[ai][0]; face_ndc[1] = vertices_ndc[ai][1]; face_ndc[2] = vertices_ndc[ai][2]; 262 | face_ndc[3] = vertices_ndc[bi][0]; face_ndc[4] = vertices_ndc[bi][1]; face_ndc[5] = vertices_ndc[bi][2]; 263 | face_ndc[6] = vertices_ndc[ci][0]; face_ndc[7] = vertices_ndc[ci][1]; face_ndc[8] = vertices_ndc[ci][2]; 264 | 265 | for (int i = 0; i < 9; ++i) { 266 | face_ndc_inv[i] = global_face_ndc_inv[9 * face_indx + i]; 267 | } 268 | 269 | min_x = min(min(face_ndc[0], face_ndc[3]), face_ndc[6]); 270 | min_x = (min_x + 1) / 2 * W; // convert from ndc to img coordinates 271 | min_xi = static_cast(floorf(static_cast(min_x))); 272 | min_xi = min(max(min_xi, 0), W - 1); 273 | max_x = max(max(face_ndc[0], face_ndc[3]), face_ndc[6]); 274 | max_x = (max_x + 1) / 2 * W; 275 | max_xi = static_cast(ceilf(static_cast(max_x))); 276 | max_xi = min(max(max_xi, 0), W - 1); 277 | 278 | min_y = min(min(face_ndc[1], face_ndc[4]), face_ndc[7]); 279 | min_y = (min_y + 1) / 2 * H; 280 | min_yi = static_cast(floorf(static_cast(min_y))); 281 | min_yi = min(max(min_yi, 0), H - 1); 282 | max_y = max(max(face_ndc[1], face_ndc[4]), face_ndc[7]); 283 | max_y = (max_y + 1) / 2 * H; 284 | max_yi = static_cast(ceilf(static_cast(max_y))); 285 | max_yi = min(max(max_yi, 0), H - 1); 286 | 287 | vertices_per_thread_x = (max_xi - min_xi) / blockDim.x + 1; 288 | vertices_per_thread_y = (max_yi - min_yi) / blockDim.y + 1; 289 | } 290 | __syncthreads(); 291 | 292 | const int left = min_xi + vertices_per_thread_x * threadIdx.x; 293 | const int right = min(left + vertices_per_thread_x, max_xi); 294 | 295 | const int top = min_yi + vertices_per_thread_y * threadIdx.y; 296 | const int bottom = min(top + vertices_per_thread_y, max_yi); 297 | 298 | scalar_t x, y, face_z, wa, wb, wc, wsum; 299 | for (int i = top; i <= bottom; i++) { 300 | for (int j = left; j <= right; j++) { 301 | x = 2 * ((scalar_t)j + 0.5) / W - 1; 302 | y = 2 * ((scalar_t)i + 0.5) / H - 1; 303 | 304 | // check pixel is inside the face 305 | if (((y - face_ndc[1]) * (face_ndc[3] - face_ndc[0]) > (x - face_ndc[0]) * (face_ndc[4] - face_ndc[1])) || 306 | ((y - face_ndc[4]) * (face_ndc[6] - face_ndc[3]) > (x - face_ndc[3]) * (face_ndc[7] - face_ndc[4])) || 307 | ((y - face_ndc[7]) * (face_ndc[0] - face_ndc[6]) > (x - face_ndc[6]) * (face_ndc[1] - face_ndc[7]))) { 308 | continue; 309 | } 310 | 311 | wa = face_ndc_inv[0] * x + face_ndc_inv[1] * y + face_ndc_inv[2]; 312 | wb = face_ndc_inv[3] * x + face_ndc_inv[4] * y + face_ndc_inv[5]; 313 | wc = face_ndc_inv[6] * x + face_ndc_inv[7] * y + face_ndc_inv[8]; 314 | wsum = wa + wb + wc; 315 | wa /= wsum; wb /= wsum; wc /= wsum; 316 | 317 | wa /= face_ndc[2]; 318 | wb /= face_ndc[5]; 319 | wc /= face_ndc[8]; 320 | wsum = wa + wb + wc; 321 | wa /= wsum; wb /= wsum; wc /= wsum; 322 | 323 | face_z = wa * face_ndc[2] + wb * face_ndc[5] + wc * face_ndc[8]; 324 | 325 | if (face_z - eps < depth[i][j]) { 326 | for (int c = 0; c < C; c++) { 327 | result[i][j][c] = wa * vertice_values[ai][c] + wb * vertice_values[bi][c] + wc * vertice_values[ci][c]; 328 | } 329 | } 330 | } 331 | } 332 | } 333 | 334 | 335 | template 336 | __global__ void estimate_normals_cuda_kernel( 337 | const torch::PackedTensorAccessor32 vertices_ndc, 338 | const torch::PackedTensorAccessor32 faces, 339 | const torch::PackedTensorAccessor32 depth, 340 | const scalar_t* global_face_ndc_inv, 341 | const int* global_is_bad_face, 342 | const torch::PackedTensorAccessor32 vertices, 343 | torch::PackedTensorAccessor32 coords, 344 | torch::PackedTensorAccessor32 normals 345 | ) { 346 | const int face_indx = blockIdx.x; 347 | 348 | if (global_is_bad_face[face_indx]) { 349 | return; 350 | } 351 | 352 | const int H = depth.size(0); 353 | const int W = depth.size(1); 354 | const scalar_t eps = 1e-5; 355 | 356 | scalar_t min_x, max_x, min_y, max_y; 357 | scalar_t v1x, v1y, v1z, v2x, v2y, v2z, nlen; 358 | __shared__ int vertices_per_thread_x, vertices_per_thread_y; 359 | __shared__ int ai, bi, ci; 360 | __shared__ scalar_t face[9]; 361 | __shared__ scalar_t face_ndc[9]; 362 | __shared__ scalar_t face_ndc_inv[9]; 363 | __shared__ int min_xi, max_xi, min_yi, max_yi; 364 | __shared__ scalar_t nx, ny, nz; 365 | 366 | if (threadIdx.x == 0 && threadIdx.y == 0) { 367 | ai = faces[face_indx][0]; 368 | bi = faces[face_indx][1]; 369 | ci = faces[face_indx][2]; 370 | 371 | face[0] = vertices[ai][0]; face[1] = vertices[ai][1]; face[2] = vertices[ai][2]; 372 | face[3] = vertices[bi][0]; face[4] = vertices[bi][1]; face[5] = vertices[bi][2]; 373 | face[6] = vertices[ci][0]; face[7] = vertices[ci][1]; face[8] = vertices[ci][2]; 374 | 375 | v1x = face[3] - face[0]; v2x = face[6] - face[0]; 376 | v1y = face[4] - face[1]; v2y = face[7] - face[1]; 377 | v1z = face[5] - face[2]; v2z = face[8] - face[2]; 378 | 379 | nx = v1y * v2z - v1z * v2y; 380 | ny = v1z * v2x - v1x * v2z; 381 | nz = v1x * v2y - v1y * v2x; 382 | nlen = nx * nx + ny * ny + nz * nz; 383 | nlen = (scalar_t)sqrt((float)nlen); 384 | nx /= nlen; 385 | ny /= nlen; 386 | nz /= nlen; 387 | 388 | face_ndc[0] = vertices_ndc[ai][0]; face_ndc[1] = vertices_ndc[ai][1]; face_ndc[2] = vertices_ndc[ai][2]; 389 | face_ndc[3] = vertices_ndc[bi][0]; face_ndc[4] = vertices_ndc[bi][1]; face_ndc[5] = vertices_ndc[bi][2]; 390 | face_ndc[6] = vertices_ndc[ci][0]; face_ndc[7] = vertices_ndc[ci][1]; face_ndc[8] = vertices_ndc[ci][2]; 391 | 392 | for (int i = 0; i < 9; ++i) { 393 | face_ndc_inv[i] = global_face_ndc_inv[9 * face_indx + i]; 394 | } 395 | 396 | min_x = min(min(face_ndc[0], face_ndc[3]), face_ndc[6]); 397 | min_x = (min_x + 1) / 2 * W; // convert from ndc to img coordinates 398 | min_xi = static_cast(floorf(static_cast(min_x))); 399 | min_xi = min(max(min_xi, 0), W - 1); 400 | max_x = max(max(face_ndc[0], face_ndc[3]), face_ndc[6]); 401 | max_x = (max_x + 1) / 2 * W; 402 | max_xi = static_cast(ceilf(static_cast(max_x))); 403 | max_xi = min(max(max_xi, 0), W - 1); 404 | 405 | min_y = min(min(face_ndc[1], face_ndc[4]), face_ndc[7]); 406 | min_y = (min_y + 1) / 2 * H; 407 | min_yi = static_cast(floorf(static_cast(min_y))); 408 | min_yi = min(max(min_yi, 0), H - 1); 409 | max_y = max(max(face_ndc[1], face_ndc[4]), face_ndc[7]); 410 | max_y = (max_y + 1) / 2 * H; 411 | max_yi = static_cast(ceilf(static_cast(max_y))); 412 | max_yi = min(max(max_yi, 0), H - 1); 413 | 414 | vertices_per_thread_x = (max_xi - min_xi) / blockDim.x + 1; 415 | vertices_per_thread_y = (max_yi - min_yi) / blockDim.y + 1; 416 | } 417 | __syncthreads(); 418 | 419 | const int left = min_xi + vertices_per_thread_x * threadIdx.x; 420 | const int right = min(left + vertices_per_thread_x, max_xi); 421 | 422 | const int top = min_yi + vertices_per_thread_y * threadIdx.y; 423 | const int bottom = min(top + vertices_per_thread_y, max_yi); 424 | 425 | scalar_t x, y, face_z, wa, wb, wc, wsum; 426 | for (int i = top; i <= bottom; i++) { 427 | for (int j = left; j <= right; j++) { 428 | x = 2 * ((scalar_t)j + 0.5) / W - 1; 429 | y = 2 * ((scalar_t)i + 0.5) / H - 1; 430 | 431 | // check pixel is inside the face 432 | if (((y - face_ndc[1]) * (face_ndc[3] - face_ndc[0]) > (x - face_ndc[0]) * (face_ndc[4] - face_ndc[1])) || 433 | ((y - face_ndc[4]) * (face_ndc[6] - face_ndc[3]) > (x - face_ndc[3]) * (face_ndc[7] - face_ndc[4])) || 434 | ((y - face_ndc[7]) * (face_ndc[0] - face_ndc[6]) > (x - face_ndc[6]) * (face_ndc[1] - face_ndc[7]))) { 435 | continue; 436 | } 437 | 438 | wa = face_ndc_inv[0] * x + face_ndc_inv[1] * y + face_ndc_inv[2]; 439 | wb = face_ndc_inv[3] * x + face_ndc_inv[4] * y + face_ndc_inv[5]; 440 | wc = face_ndc_inv[6] * x + face_ndc_inv[7] * y + face_ndc_inv[8]; 441 | wsum = wa + wb + wc; 442 | wa /= wsum; wb /= wsum; wc /= wsum; 443 | 444 | wa /= face_ndc[2]; 445 | wb /= face_ndc[5]; 446 | wc /= face_ndc[8]; 447 | wsum = wa + wb + wc; 448 | wa /= wsum; wb /= wsum; wc /= wsum; 449 | 450 | face_z = wa * face_ndc[2] + wb * face_ndc[5] + wc * face_ndc[8]; 451 | 452 | if (face_z - eps < depth[i][j]) { 453 | coords[i][j][0] = wa * face[0] + wb * face[3] + wc * face[6]; 454 | coords[i][j][1] = wa * face[1] + wb * face[4] + wc * face[7]; 455 | coords[i][j][2] = wa * face[2] + wb * face[5] + wc * face[8]; 456 | 457 | normals[i][j][0] = nx; 458 | normals[i][j][1] = ny; 459 | normals[i][j][2] = nz; 460 | } 461 | } 462 | } 463 | } 464 | 465 | // cpp defined functions 466 | 467 | torch::Tensor project_mesh_cuda( 468 | const torch::Tensor& vertices_ndc, 469 | const torch::Tensor& faces, 470 | const torch::Tensor& vertice_values, 471 | const torch::Tensor& vertices_filter, 472 | int H, int W 473 | ) { 474 | const int N = vertices_ndc.size(0); 475 | const int C = vertice_values.size(1); 476 | const int M = faces.size(0); 477 | 478 | const int gpuid = vertices_ndc.device().index(); 479 | AT_CUDA_CHECK(cudaSetDevice(gpuid)); 480 | auto options = torch::dtype(vertices_ndc.scalar_type()).device(torch::kCUDA, gpuid); 481 | 482 | const dim3 dimGrid(M); 483 | const dim3 dimBlock(4, 4); 484 | 485 | auto depth = torch::ones({H, W}, options) * 1e10; 486 | auto result = torch::zeros({H, W, C}, options); 487 | 488 | AT_DISPATCH_FLOATING_TYPES_AND_HALF(vertices_ndc.scalar_type(), "project_mesh_cuda_kernel", [&] { 489 | scalar_t* global_face_ndc_inv; 490 | cudaMalloc(&global_face_ndc_inv, M * 9 * sizeof(scalar_t)); 491 | int* global_is_bad_face; 492 | cudaMalloc(&global_is_bad_face, M * sizeof(int)); 493 | rasterize_cuda_kernel<<>>( 494 | vertices_ndc.packed_accessor32(), 495 | faces.packed_accessor32(), 496 | vertices_filter.packed_accessor32(), 497 | depth.packed_accessor32(), 498 | global_face_ndc_inv, 499 | global_is_bad_face 500 | ); 501 | AT_CUDA_CHECK(cudaGetLastError()); 502 | 503 | interpolate_cuda_kernel<<>>( 504 | vertices_ndc.packed_accessor32(), 505 | faces.packed_accessor32(), 506 | depth.packed_accessor32(), 507 | global_face_ndc_inv, 508 | global_is_bad_face, 509 | vertice_values.packed_accessor32(), 510 | result.packed_accessor32() 511 | ); 512 | AT_CUDA_CHECK(cudaGetLastError()); 513 | 514 | cudaFree(global_face_ndc_inv); 515 | cudaFree(global_is_bad_face); 516 | AT_CUDA_CHECK(cudaGetLastError()); 517 | }); 518 | 519 | return result; 520 | } 521 | 522 | 523 | std::vector estimate_normals_cuda( 524 | const torch::Tensor& vertices_ndc, 525 | const torch::Tensor& faces, 526 | const torch::Tensor& vertices, 527 | const torch::Tensor& vertices_filter, 528 | int H, int W 529 | ) { 530 | const int N = vertices_ndc.size(0); 531 | const int M = faces.size(0); 532 | 533 | const int gpuid = vertices_ndc.device().index(); 534 | AT_CUDA_CHECK(cudaSetDevice(gpuid)); 535 | auto options = torch::dtype(vertices_ndc.scalar_type()).device(torch::kCUDA, gpuid); 536 | 537 | const dim3 dimGrid(M); 538 | const dim3 dimBlock(4, 4); 539 | 540 | auto depth = torch::ones({H, W}, options) * 1e10; 541 | auto coords = torch::zeros({H, W, 3}, options); 542 | auto normals = torch::zeros({H, W, 3}, options); 543 | 544 | AT_DISPATCH_FLOATING_TYPES_AND_HALF(vertices_ndc.scalar_type(), "project_mesh_cuda_kernel", [&] { 545 | scalar_t* global_face_ndc_inv; 546 | cudaMalloc(&global_face_ndc_inv, M * 9 * sizeof(scalar_t)); 547 | int* global_is_bad_face; 548 | cudaMalloc(&global_is_bad_face, M * sizeof(int)); 549 | rasterize_cuda_kernel<<>>( 550 | vertices_ndc.packed_accessor32(), 551 | faces.packed_accessor32(), 552 | vertices_filter.packed_accessor32(), 553 | depth.packed_accessor32(), 554 | global_face_ndc_inv, 555 | global_is_bad_face 556 | ); 557 | AT_CUDA_CHECK(cudaGetLastError()); 558 | 559 | estimate_normals_cuda_kernel<<>>( 560 | vertices_ndc.packed_accessor32(), 561 | faces.packed_accessor32(), 562 | depth.packed_accessor32(), 563 | global_face_ndc_inv, 564 | global_is_bad_face, 565 | vertices.packed_accessor32(), 566 | coords.packed_accessor32(), 567 | normals.packed_accessor32() 568 | ); 569 | AT_CUDA_CHECK(cudaGetLastError()); 570 | 571 | cudaFree(global_face_ndc_inv); 572 | cudaFree(global_is_bad_face); 573 | AT_CUDA_CHECK(cudaGetLastError()); 574 | }); 575 | 576 | return {coords, normals}; 577 | } 578 | -------------------------------------------------------------------------------- /minimal_pytorch_rasterizer/rasterizer.py: -------------------------------------------------------------------------------- 1 | import torch 2 | from minimal_pytorch_rasterizer.cuda.rasterizer import estimate_normals as estimate_normals_cuda 3 | from minimal_pytorch_rasterizer.cuda.rasterizer import project_mesh as project_mesh_cuda 4 | from minimal_pytorch_rasterizer import assert_utils 5 | 6 | 7 | def estimate_normals(vertices, faces, pinhole, vertices_filter=None): 8 | if vertices_filter is None: 9 | assert_utils.is_cuda_tensor(vertices) 10 | assert_utils.check_shape_len(vertices, 2) 11 | n = vertices.shape[0] 12 | vertices_filter = torch.ones((n), dtype=torch.uint8, device=vertices.device) 13 | vertices = vertices.contiguous() 14 | vertices_ndc = pinhole.project_ndc(vertices) 15 | coords, normals = estimate_normals_cuda( 16 | vertices_ndc, faces, vertices, vertices_filter, 17 | pinhole.h, pinhole.w 18 | ) 19 | return coords, normals 20 | 21 | 22 | def project_mesh(vertices, faces, vertice_values, pinhole, vertices_filter=None): 23 | if vertices_filter is None: 24 | assert_utils.is_cuda_tensor(vertices) 25 | assert_utils.check_shape_len(vertices, 2) 26 | n = vertices.shape[0] 27 | vertices_filter = torch.ones((n), dtype=torch.uint8, device=vertices.device) 28 | vertices = vertices.contiguous() 29 | vertices_ndc = pinhole.project_ndc(vertices) 30 | return project_mesh_cuda( 31 | vertices_ndc, faces, vertice_values, vertices_filter, 32 | pinhole.h, pinhole.w 33 | ) 34 | -------------------------------------------------------------------------------- /minimal_pytorch_rasterizer/utils.py: -------------------------------------------------------------------------------- 1 | import torch 2 | 3 | 4 | def vis_z_buffer(z, percentile=1, vis_pad=0.2): 5 | z = z[:, :, 0] 6 | mask = z > 1e-5 7 | if torch.sum(mask) == 0: 8 | z[...] = 0 9 | else: 10 | vmin = torch.quantile(z[mask], percentile / 100) 11 | vmax = torch.quantile(z[mask], 1 - percentile / 100) 12 | pad = (vmax - vmin) * vis_pad 13 | vmin_padded = vmin - pad 14 | vmax_padded = vmax + pad 15 | z[mask] = vmin + vmax - z[mask] 16 | z = (z - vmin_padded) / (vmax_padded - vmin_padded) 17 | z = torch.clip(torch.round(z * 255), 0, 255) 18 | z_cpu = z.to(dtype=torch.uint8).detach().cpu().numpy() 19 | return z_cpu 20 | 21 | 22 | def vis_normals(coords, normals, vis_pad=0.2): 23 | mask = coords[:, :, 2] > 0 24 | coords_masked = -coords[mask] 25 | normals_masked = normals[mask] 26 | 27 | coords_len = torch.sqrt(torch.sum(coords_masked ** 2, dim=1)) 28 | 29 | dot = torch.sum(coords_masked * normals_masked, dim=1) / coords_len 30 | 31 | h, w = normals.shape[:2] 32 | vis = torch.zeros((h, w), dtype=coords.dtype, device=coords.device) 33 | vis[mask] = torch.clamp(dot, 0, 1) * (1 - 2 * vis_pad) + vis_pad 34 | 35 | vis_cpu = (vis * 255).to(dtype=torch.uint8).detach().cpu().numpy() 36 | 37 | return vis_cpu 38 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | ipykernel==5.2.0 2 | jupyter==1.0.0 3 | matplotlib==3.2.1 4 | munch==2.5.0 5 | nbconvert==5.6.1 6 | numpy==1.19.2 7 | opencv-python==4.2.0.32 8 | pandas==1.0.3 9 | Pillow==7.0.0 10 | plotly==4.9.0 11 | scikit-image==0.16.2 12 | scikit-learn==0.22.2.post1 13 | scipy==1.4.1 14 | tqdm==4.46.0 15 | numba==0.51.2 16 | einops==0.3.0 17 | tensorboard==1.8.0 18 | tensorboardX==1.2 19 | pyyaml 20 | 21 | git+https://github.com/karfly/nvdiffrast_compute-capability_6.0 22 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | from torch.utils.cpp_extension import BuildExtension, CUDAExtension 4 | 5 | 6 | ext_modules = [ 7 | CUDAExtension( 8 | 'minimal_pytorch_rasterizer.cuda.rasterizer', [ 9 | 'minimal_pytorch_rasterizer/cuda/rasterizer.cpp', 10 | 'minimal_pytorch_rasterizer/cuda/rasterizer_kernel.cu', 11 | ]) 12 | ] 13 | 14 | setup( 15 | version='0.5', 16 | description='cuda accelerated point cloud utils', 17 | author='Renat Bashirov', 18 | author_email='rmbashirov@gmail.com', 19 | install_requires=["torch>=1.3"], 20 | packages=['minimal_pytorch_rasterizer', 'minimal_pytorch_rasterizer.cuda'], 21 | name='minimal_pytorch_rasterizer', 22 | ext_modules=ext_modules, 23 | cmdclass={'build_ext': BuildExtension} 24 | ) 25 | -------------------------------------------------------------------------------- /setup.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | pip uninstall -y minimal_pytorch_rasterizer 4 | pip --no-cache-dir install . 5 | 6 | 7 | --------------------------------------------------------------------------------