qbhf2's picture
added NvidiaWarp and GarmentCode repos
66c9c8a
/** Copyright (c) 2022 NVIDIA CORPORATION. All rights reserved.
* NVIDIA CORPORATION and its licensors retain all intellectual property
* and proprietary rights in and to this software, related documentation
* and any modifications thereto. Any use, reproduction, disclosure or
* distribution of this software and related documentation without an express
* license agreement from NVIDIA CORPORATION is strictly prohibited.
*/
#pragma once
namespace wp
{
struct HashGrid
{
float cell_width;
float cell_width_inv;
int* point_cells{nullptr}; // cell id of a point
int* point_ids{nullptr}; // index to original point
int* cell_starts{nullptr}; // start index of a range of indices belonging to a cell, dim_x*dim_y*dim_z in length
int* cell_ends{nullptr}; // end index of a range of indices belonging to a cell, dim_x*dim_y*dim_z in length
int dim_x;
int dim_y;
int dim_z;
int num_points;
int max_points;
void* context;
};
// convert a virtual (world) cell coordinate to a physical one
CUDA_CALLABLE inline int hash_grid_index(const HashGrid& grid, int x, int y, int z)
{
// offset to ensure positive coordinates (means grid dim should be less than 4096^3)
const int origin = 1<<20;
x += origin;
y += origin;
z += origin;
assert(0 < x);
assert(0 < y);
assert(0 < z);
// clamp in case any particles fall outside the guard region (-10^20 cell index)
x = max(0, x);
y = max(0, y);
z = max(0, z);
// compute physical cell (assume pow2 grid dims)
// int cx = x & (grid.dim_x-1);
// int cy = y & (grid.dim_y-1);
// int cz = z & (grid.dim_z-1);
// compute physical cell (arbitrary grid dims)
int cx = x%grid.dim_x;
int cy = y%grid.dim_y;
int cz = z%grid.dim_z;
return cz*(grid.dim_x*grid.dim_y) + cy*grid.dim_x + cx;
}
CUDA_CALLABLE inline int hash_grid_index(const HashGrid& grid, const vec3& p)
{
return hash_grid_index(grid,
int(p[0]*grid.cell_width_inv),
int(p[1]*grid.cell_width_inv),
int(p[2]*grid.cell_width_inv));
}
// stores state required to traverse neighboring cells of a point
struct hash_grid_query_t
{
CUDA_CALLABLE hash_grid_query_t() {}
CUDA_CALLABLE hash_grid_query_t(int) {} // for backward pass
int x_start;
int y_start;
int z_start;
int x_end;
int y_end;
int z_end;
int x;
int y;
int z;
int cell;
int cell_index; // offset in the current cell (index into cell_indices)
int cell_end; // index following the end of this cell
int current; // index of the current iterator value
HashGrid grid;
};
CUDA_CALLABLE inline hash_grid_query_t hash_grid_query(uint64_t id, wp::vec3 pos, float radius)
{
hash_grid_query_t query;
query.grid = *(const HashGrid*)(id);
// convert coordinate to grid
query.x_start = int((pos[0]-radius)*query.grid.cell_width_inv);
query.y_start = int((pos[1]-radius)*query.grid.cell_width_inv);
query.z_start = int((pos[2]-radius)*query.grid.cell_width_inv);
// do not want to visit any cells more than once, so limit large radius offset to one pass over each dimension
query.x_end = min(int((pos[0]+radius)*query.grid.cell_width_inv), query.x_start + query.grid.dim_x-1);
query.y_end = min(int((pos[1]+radius)*query.grid.cell_width_inv), query.y_start + query.grid.dim_y-1);
query.z_end = min(int((pos[2]+radius)*query.grid.cell_width_inv), query.z_start + query.grid.dim_z-1);
query.x = query.x_start;
query.y = query.y_start;
query.z = query.z_start;
const int cell = hash_grid_index(query.grid, query.x, query.y, query.z);
query.cell_index = query.grid.cell_starts[cell];
query.cell_end = query.grid.cell_ends[cell];
return query;
}
CUDA_CALLABLE inline bool hash_grid_query_next(hash_grid_query_t& query, int& index)
{
const HashGrid& grid = query.grid;
if (!grid.point_cells)
return false;
while (1)
{
if (query.cell_index < query.cell_end)
{
// write output index
index = grid.point_ids[query.cell_index++];
return true;
}
else
{
query.x++;
if (query.x > query.x_end)
{
query.x = query.x_start;
query.y++;
}
if (query.y > query.y_end)
{
query.y = query.y_start;
query.z++;
}
if (query.z > query.z_end)
{
// finished lookup grid
return false;
}
// update cell pointers
const int cell = hash_grid_index(grid, query.x, query.y, query.z);
query.cell_index = grid.cell_starts[cell];
query.cell_end = grid.cell_ends[cell];
}
}
}
CUDA_CALLABLE inline int iter_next(hash_grid_query_t& query)
{
return query.current;
}
CUDA_CALLABLE inline bool iter_cmp(hash_grid_query_t& query)
{
bool finished = hash_grid_query_next(query, query.current);
return finished;
}
CUDA_CALLABLE inline hash_grid_query_t iter_reverse(const hash_grid_query_t& query)
{
// can't reverse grid queries, users should not rely on neighbor ordering
return query;
}
CUDA_CALLABLE inline int hash_grid_point_id(uint64_t id, int& index)
{
const HashGrid* grid = (const HashGrid*)(id);
if (grid->point_ids == nullptr)
return -1;
return grid->point_ids[index];
}
CUDA_CALLABLE inline void adj_hash_grid_query(uint64_t id, wp::vec3 pos, float radius, uint64_t& adj_id, wp::vec3& adj_pos, float& adj_radius, hash_grid_query_t& adj_res) {}
CUDA_CALLABLE inline void adj_hash_grid_query_next(hash_grid_query_t& query, int& index, hash_grid_query_t& adj_query, int& adj_index, bool& adj_res) {}
CUDA_CALLABLE inline void adj_hash_grid_point_id(uint64_t id, int& index, uint64_t & adj_id, int& adj_index, int& adj_res) {}
} // namespace wp