diff --git a/docs/notes/assets/world_camera_image.png b/docs/notes/assets/world_camera_image.png index 72ea6d3f..ea0d0a4e 100644 Binary files a/docs/notes/assets/world_camera_image.png and b/docs/notes/assets/world_camera_image.png differ diff --git a/pytorch3d/csrc/rasterize_meshes/rasterize_meshes.cu b/pytorch3d/csrc/rasterize_meshes/rasterize_meshes.cu index 315c7130..d5c6d091 100644 --- a/pytorch3d/csrc/rasterize_meshes/rasterize_meshes.cu +++ b/pytorch3d/csrc/rasterize_meshes/rasterize_meshes.cu @@ -208,7 +208,7 @@ __global__ void RasterizeMeshesNaiveCudaKernel( const int n = i / (H * W); // batch index. const int pix_idx = i % (H * W); - // Determine ordering based on axis convention. + // Reverse ordering of X and Y axes const int yi = H - 1 - pix_idx / W; const int xi = W - 1 - pix_idx % W; @@ -353,7 +353,7 @@ __global__ void RasterizeMeshesBackwardCudaKernel( const int n = t_i / (H * W); // batch index. const int pix_idx = t_i % (H * W); - // Determine ordering based on axis convention. + // Reverse ordering of X and Y axes. const int yi = H - 1 - pix_idx / W; const int xi = W - 1 - pix_idx % W; @@ -557,8 +557,8 @@ __global__ void RasterizeMeshesCoarseCudaKernel( // need to add/subtract a half pixel to get the true extent of the bin. // Reverse ordering of Y axis so that +Y is upwards in the image. const int yidx = num_bins - by; - float bin_y_max = PixToNdc(yidx * bin_size - 1, H) + half_pix; - float bin_y_min = PixToNdc((yidx - 1) * bin_size, H) - half_pix; + const float bin_y_max = PixToNdc(yidx * bin_size - 1, H) + half_pix; + const float bin_y_min = PixToNdc((yidx - 1) * bin_size, H) - half_pix; const bool y_overlap = (ymin <= bin_y_max) && (bin_y_min < ymax); @@ -566,8 +566,8 @@ __global__ void RasterizeMeshesCoarseCudaKernel( // X coordinate of the left and right of the bin. // Reverse ordering of x axis so that +X is left. const int xidx = num_bins - bx; - float bin_x_max = PixToNdc(xidx * bin_size - 1, W) + half_pix; - float bin_x_min = PixToNdc((xidx - 1) * bin_size, W) - half_pix; + const float bin_x_max = PixToNdc(xidx * bin_size - 1, W) + half_pix; + const float bin_x_min = PixToNdc((xidx - 1) * bin_size, W) - half_pix; const bool x_overlap = (xmin <= bin_x_max) && (bin_x_min < xmax); if (y_overlap && x_overlap) { diff --git a/pytorch3d/csrc/rasterize_meshes/rasterize_meshes_cpu.cpp b/pytorch3d/csrc/rasterize_meshes/rasterize_meshes_cpu.cpp index 8b118275..392ad3bf 100644 --- a/pytorch3d/csrc/rasterize_meshes/rasterize_meshes_cpu.cpp +++ b/pytorch3d/csrc/rasterize_meshes/rasterize_meshes_cpu.cpp @@ -473,11 +473,11 @@ torch::Tensor RasterizeMeshesCoarseCpu( } } - // Shift the bin down for the next loop iteration. + // Shift the bin to the left for the next loop iteration. bin_x_max = bin_x_min; bin_x_min = bin_x_min - bin_width; } - // Shift the bin left for the next loop iteration. + // Shift the bin down for the next loop iteration. bin_y_max = bin_y_min; bin_y_min = bin_y_min - bin_width; } diff --git a/pytorch3d/csrc/rasterize_points/rasterize_points.cu b/pytorch3d/csrc/rasterize_points/rasterize_points.cu index d04be892..07458062 100644 --- a/pytorch3d/csrc/rasterize_points/rasterize_points.cu +++ b/pytorch3d/csrc/rasterize_points/rasterize_points.cu @@ -94,8 +94,10 @@ __global__ void RasterizePointsNaiveCudaKernel( // Convert linear index to 3D index const int n = i / (S * S); // Batch index const int pix_idx = i % (S * S); - const int yi = pix_idx / S; - const int xi = pix_idx % S; + + // Reverse ordering of X and Y axes. + const int yi = S - 1 - pix_idx / S; + const int xi = S - 1 - pix_idx % S; const float xf = PixToNdc(xi, S); const float yf = PixToNdc(yi, S); @@ -126,7 +128,7 @@ __global__ void RasterizePointsNaiveCudaKernel( points, p_idx, q_size, q_max_z, q_max_idx, q, radius2, xf, yf, K); } BubbleSort(q, q_size); - int idx = n * S * S * K + yi * S * K + xi * K; + int idx = n * S * S * K + pix_idx * K; for (int k = 0; k < q_size; ++k) { point_idxs[idx + k] = q[k].idx; zbuf[idx + k] = q[k].z; @@ -258,18 +260,23 @@ __global__ void RasterizePointsCoarseCudaKernel( // Get y extent for the bin. PixToNdc gives us the location of // the center of each pixel, so we need to add/subtract a half // pixel to get the true extent of the bin. - const float by0 = PixToNdc(by * bin_size, S) - half_pix; - const float by1 = PixToNdc((by + 1) * bin_size - 1, S) + half_pix; - const bool y_overlap = (py0 <= by1) && (by0 <= py1); + // Reverse ordering of Y axis so that +Y is upwards in the image. + const int yidx = num_bins - by; + const float bin_y_max = PixToNdc(yidx * bin_size - 1, S) + half_pix; + const float bin_y_min = PixToNdc((yidx - 1) * bin_size, S) - half_pix; + + const bool y_overlap = (py0 <= bin_y_max) && (bin_y_min <= py1); if (!y_overlap) { continue; } for (int bx = 0; bx < num_bins; ++bx) { // Get x extent for the bin; again we need to adjust the // output of PixToNdc by half a pixel. - const float bx0 = PixToNdc(bx * bin_size, S) - half_pix; - const float bx1 = PixToNdc((bx + 1) * bin_size - 1, S) + half_pix; - const bool x_overlap = (px0 <= bx1) && (bx0 <= px1); + // Reverse ordering of x axis so that +X is left. + const int xidx = num_bins - bx; + const float bin_x_max = PixToNdc(xidx * bin_size - 1, S) + half_pix; + const float bin_x_min = PixToNdc((xidx - 1) * bin_size, S) - half_pix; + const bool x_overlap = (px0 <= bin_x_max) && (bin_x_min <= px1); if (x_overlap) { binmask.set(by, bx, p); } @@ -395,8 +402,14 @@ __global__ void RasterizePointsFineCudaKernel( if (yi >= S || xi >= S) continue; - const float xf = PixToNdc(xi, S); - const float yf = PixToNdc(yi, S); + + // Reverse ordering of the X and Y axis so that + // in the image +Y is pointing up and +X is pointing left. + const int yidx = S - 1 - yi; + const int xidx = S - 1 - xi; + + const float xf = PixToNdc(xidx, S); + const float yf = PixToNdc(yidx, S); // This part looks like the naive rasterization kernel, except we use // bin_points to only look at a subset of points already known to fall @@ -493,8 +506,12 @@ __global__ void RasterizePointsBackwardCudaKernel( const int xk = yxk % (W * K); const int xi = xk / K; // k = xk % K (We don't actually need k, but this would be it.) - const float xf = PixToNdc(xi, W); - const float yf = PixToNdc(yi, H); + // Reverse ordering of X and Y axes. + const int yidx = H - 1 - yi; + const int xidx = W - 1 - xi; + + const float xf = PixToNdc(xidx, W); + const float yf = PixToNdc(yidx, H); const int p = idxs[i]; if (p < 0) diff --git a/pytorch3d/csrc/rasterize_points/rasterize_points_cpu.cpp b/pytorch3d/csrc/rasterize_points/rasterize_points_cpu.cpp index 893c17cc..dc30540c 100644 --- a/pytorch3d/csrc/rasterize_points/rasterize_points_cpu.cpp +++ b/pytorch3d/csrc/rasterize_points/rasterize_points_cpu.cpp @@ -47,9 +47,16 @@ std::tuple RasterizePointsNaiveCpu( (point_start_idx + num_points_per_cloud[n].item().to()); for (int yi = 0; yi < S; ++yi) { - float yf = PixToNdc(yi, S); + // Reverse the order of yi so that +Y is pointing upwards in the image. + const int yidx = S - 1 - yi; + const float yf = PixToNdc(yidx, S); + for (int xi = 0; xi < S; ++xi) { - float xf = PixToNdc(xi, S); + // Reverse the order of xi so that +X is pointing to the left in the + // image. + const int xidx = S - 1 - xi; + const float xf = PixToNdc(xidx, S); + // Use a priority queue to hold (z, idx, r) std::priority_queue> q; for (int p = point_start_idx; p < point_stop_idx; ++p) { @@ -118,11 +125,15 @@ torch::Tensor RasterizePointsCoarseCpu( const int point_stop_idx = (point_start_idx + num_points_per_cloud[n].item().to()); - float bin_y_min = -1.0f; - float bin_y_max = bin_y_min + bin_width; + float bin_y_max = 1.0f; + float bin_y_min = bin_y_max - bin_width; + + // Iterate through the horizontal bins from top to bottom. for (int by = 0; by < B; by++) { - float bin_x_min = -1.0f; - float bin_x_max = bin_x_min + bin_width; + float bin_x_max = 1.0f; + float bin_x_min = bin_x_max - bin_width; + + // Iterate through bins on this horizontal line, left to right. for (int bx = 0; bx < B; bx++) { int32_t points_hit = 0; for (int p = point_start_idx; p < point_stop_idx; ++p) { @@ -136,6 +147,7 @@ torch::Tensor RasterizePointsCoarseCpu( float point_x_max = px + radius; float point_y_min = py - radius; float point_y_max = py + radius; + // Use a half-open interval so that points exactly on the // boundary between bins will fall into exactly one bin. bool x_hit = (point_x_min <= bin_x_max) && (bin_x_min <= point_x_max); @@ -154,13 +166,13 @@ torch::Tensor RasterizePointsCoarseCpu( // Record the number of points found in this bin points_per_bin_a[n][by][bx] = points_hit; - // Shift the bin to the right for the next loop iteration - bin_x_min = bin_x_max; - bin_x_max = bin_x_min + bin_width; + // Shift the bin to the left for the next loop iteration. + bin_x_max = bin_x_min; + bin_x_min = bin_x_min - bin_width; } - // Shift the bin down for the next loop iteration - bin_y_min = bin_y_max; - bin_y_max = bin_y_min + bin_width; + // Shift the bin down for the next loop iteration. + bin_y_max = bin_y_min; + bin_y_min = bin_y_min - bin_width; } } return bin_points; @@ -193,9 +205,18 @@ torch::Tensor RasterizePointsBackwardCpu( for (int n = 0; n < N; ++n) { // Loop over images in the batch for (int y = 0; y < H; ++y) { // Loop over rows in the image - const float yf = PixToNdc(y, H); + // Reverse the order of yi so that +Y is pointing upwards in the image. + const int yidx = H - 1 - y; + // Y coordinate of the top of the pixel. + const float yf = PixToNdc(yidx, H); + + // Iterate through pixels on this horizontal line, left to right. for (int x = 0; x < W; ++x) { // Loop over pixels in the row - const float xf = PixToNdc(x, W); + + // Reverse the order of xi so that +X is pointing to the left in the + // image. + const int xidx = W - 1 - x; + const float xf = PixToNdc(xidx, W); for (int k = 0; k < K; ++k) { // Loop over points for the pixel const int p = idxs_a[n][y][x][k]; if (p < 0) { diff --git a/pytorch3d/renderer/mesh/rasterize_meshes.py b/pytorch3d/renderer/mesh/rasterize_meshes.py index 8be09b3a..ede0cf43 100644 --- a/pytorch3d/renderer/mesh/rasterize_meshes.py +++ b/pytorch3d/renderer/mesh/rasterize_meshes.py @@ -283,7 +283,7 @@ def rasterize_meshes_python( # X coordinate of one end of the image. Reverse the ordering # of xi so that +X is pointing to the left in the image. xfix = W - 1 - xi - xf = pix_to_ndc(xfix, H) + xf = pix_to_ndc(xfix, W) top_k_points = [] # Check whether each face in the mesh affects this pixel.