You need to sign in or sign up before continuing.
Commit d01e7228 authored by Nikhila Ravi's avatar Nikhila Ravi Committed by Facebook GitHub Bot
Browse files

Fix coordinate system conventions in point cloud renderer

Summary:
Applying the changes added for mesh rasterization to ensure that +Y is up and +X is left so that the coordinate system is right handed.

Also updated the diagram in the docs to indicate that (0,0) is in the top left hand corner.

Reviewed By: gkioxari

Differential Revision: D20394849

fbshipit-source-id: cfb7c79090eb1f55ad38b92327a74a70a8dc541e
parent 32ad869d
......@@ -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) {
......
......@@ -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;
}
......
......@@ -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)
......
......@@ -47,9 +47,16 @@ std::tuple<torch::Tensor, torch::Tensor, torch::Tensor> RasterizePointsNaiveCpu(
(point_start_idx + num_points_per_cloud[n].item().to<int32_t>());
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<std::tuple<float, int, float>> 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<int32_t>());
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) {
......
......@@ -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.
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment