10 # include <openvdb/tools/Dense.h>
11 # include <openvdb/tools/GridTransformer.h>
12 # include <openvdb/tools/Morphology.h>
13 # include <openvdb/tools/Statistics.h>
64 const int quads_indices[6][4] = {
79 const float3 quads_normals[6] = {
94 static int add_vertex(
int3 v,
97 unordered_map<size_t, int> &used_verts)
99 size_t vert_key =
v.x +
v.y * (res.
x + 1) +
v.z * (res.
x + 1) * (res.
y + 1);
100 unordered_map<size_t, int>::iterator it = used_verts.find(vert_key);
102 if (it != used_verts.end()) {
106 int vertex_offset = vertices.size();
107 used_verts[vert_key] = vertex_offset;
108 vertices.push_back(
v);
109 return vertex_offset;
112 static void create_quad(
int3 corners[8],
116 unordered_map<size_t, int> &used_verts,
120 quad.v0 = add_vertex(corners[quads_indices[face_index][0]], vertices, res, used_verts);
121 quad.v1 = add_vertex(corners[quads_indices[face_index][1]], vertices, res, used_verts);
122 quad.v2 = add_vertex(corners[quads_indices[face_index][2]], vertices, res, used_verts);
123 quad.v3 = add_vertex(corners[quads_indices[face_index][3]], vertices, res, used_verts);
124 quad.normal = quads_normals[face_index];
126 quads.push_back(
quad);
145 openvdb::CoordBBox bbox;
152 void add_grid(openvdb::GridBase::ConstPtr grid,
bool do_clipping,
float volume_clipping);
160 const float face_overlap_avoidance);
166 const float face_overlap_avoidance);
175 template<
typename Gr
idType>
176 void merge_grid(openvdb::GridBase::ConstPtr grid,
bool do_clipping,
float volume_clipping)
178 typename GridType::ConstPtr typed_grid = openvdb::gridConstPtrCast<GridType>(grid);
181 using ValueType =
typename GridType::ValueType;
183 typename GridType::ValueOnIter iter =
copy->beginValueOn();
185 for (; iter; ++iter) {
186 if (openvdb::math::Abs(iter.getValue()) < ValueType(volume_clipping)) {
194 topology_grid->topologyUnion(*typed_grid);
205 void VolumeMeshBuilder::add_grid(openvdb::GridBase::ConstPtr grid,
207 float volume_clipping)
212 topology_grid->setTransform(grid->transform().copy());
218 else if (topology_grid->transform() != grid->transform()) {
220 temp_grid->setTransform(grid->transform().copy());
221 openvdb::tools::resampleToMatch<openvdb::tools::BoxSampler>(*topology_grid, *temp_grid);
222 topology_grid = temp_grid;
223 topology_grid->setTransform(grid->transform().copy());
226 if (grid->isType<openvdb::FloatGrid>()) {
227 merge_grid<openvdb::FloatGrid>(grid, do_clipping, volume_clipping);
229 else if (grid->isType<openvdb::Vec3fGrid>()) {
230 merge_grid<openvdb::Vec3fGrid>(grid, do_clipping, volume_clipping);
232 else if (grid->isType<openvdb::Vec4fGrid>()) {
233 merge_grid<openvdb::Vec4fGrid>(grid, do_clipping, volume_clipping);
235 else if (grid->isType<openvdb::BoolGrid>()) {
236 merge_grid<openvdb::BoolGrid>(grid, do_clipping, volume_clipping);
238 else if (grid->isType<openvdb::DoubleGrid>()) {
239 merge_grid<openvdb::DoubleGrid>(grid, do_clipping, volume_clipping);
241 else if (grid->isType<openvdb::Int32Grid>()) {
242 merge_grid<openvdb::Int32Grid>(grid, do_clipping, volume_clipping);
244 else if (grid->isType<openvdb::Int64Grid>()) {
245 merge_grid<openvdb::Int64Grid>(grid, do_clipping, volume_clipping);
247 else if (grid->isType<openvdb::Vec3IGrid>()) {
248 merge_grid<openvdb::Vec3IGrid>(grid, do_clipping, volume_clipping);
250 else if (grid->isType<openvdb::Vec3dGrid>()) {
251 merge_grid<openvdb::Vec3dGrid>(grid, do_clipping, volume_clipping);
253 else if (grid->isType<openvdb::MaskGrid>()) {
254 topology_grid->topologyUnion(*openvdb::gridConstPtrCast<openvdb::MaskGrid>(grid));
262 openvdb::tools::dilateActiveValues(
263 topology_grid->tree(), pad_size, openvdb::tools::NN_FACE, openvdb::tools::IGNORE_TILES);
272 const float face_overlap_avoidance)
282 topology_grid->tree().voxelizeActiveTiles();
293 (
void)face_overlap_avoidance;
298 static bool is_non_empty_leaf(
const openvdb::MaskGrid::TreeType &
tree,
const openvdb::Coord coord)
300 auto *leaf_node =
tree.probeLeaf(coord);
301 return (leaf_node && !leaf_node->isEmpty());
309 const openvdb::MaskGrid::TreeType &
tree = topology_grid->tree();
310 tree.evalLeafBoundingBox(bbox);
312 const int3 resolution =
make_int3(bbox.dim().x(), bbox.dim().y(), bbox.dim().z());
314 unordered_map<size_t, int> used_verts;
316 for (
auto iter =
tree.cbeginLeaf(); iter; ++iter) {
317 if (iter->isEmpty()) {
321 openvdb::CoordBBox leaf_bbox = iter->getNodeBoundingBox();
323 leaf_bbox.max() = leaf_bbox.max().offsetBy(1);
325 int3 min =
make_int3(leaf_bbox.min().x(), leaf_bbox.min().y(), leaf_bbox.min().z());
326 int3 max =
make_int3(leaf_bbox.max().x(), leaf_bbox.max().y(), leaf_bbox.max().z());
345 static const int LEAF_DIM = openvdb::MaskGrid::TreeType::LeafNodeType::DIM;
346 auto center = leaf_bbox.min() + openvdb::Coord(LEAF_DIM / 2);
349 create_quad(corners, vertices_is, quads, resolution, used_verts,
QUAD_X_MIN);
353 create_quad(corners, vertices_is, quads, resolution, used_verts,
QUAD_X_MAX);
357 create_quad(corners, vertices_is, quads, resolution, used_verts,
QUAD_Y_MIN);
361 create_quad(corners, vertices_is, quads, resolution, used_verts,
QUAD_Y_MAX);
365 create_quad(corners, vertices_is, quads, resolution, used_verts,
QUAD_Z_MIN);
369 create_quad(corners, vertices_is, quads, resolution, used_verts,
QUAD_Z_MAX);
380 const float face_overlap_avoidance)
384 bbox = topology_grid->evalActiveVoxelBoundingBox();
385 openvdb::Coord dim = bbox.dim();
388 float3 point_offset = cell_size * face_overlap_avoidance;
390 out_vertices.reserve(vertices.size());
392 for (
size_t i = 0; i < vertices.size(); ++i) {
396 out_vertices.push_back(vertex + point_offset);
401 (
void)face_overlap_avoidance;
409 int index_offset = 0;
410 tris.resize(quads.size() * 6);
411 face_normals.reserve(quads.size() * 2);
413 for (
size_t i = 0; i < quads.size(); ++i) {
414 tris[index_offset++] = quads[i].v0;
415 tris[index_offset++] = quads[i].v2;
416 tris[index_offset++] = quads[i].v1;
418 face_normals.push_back(quads[i].
normal);
420 tris[index_offset++] = quads[i].v0;
421 tris[index_offset++] = quads[i].v3;
422 tris[index_offset++] = quads[i].v2;
424 face_normals.push_back(quads[i].
normal);
431 return !topology_grid ||
432 (!topology_grid->tree().hasActiveTiles() && topology_grid->tree().leafCount() == 0);
439 template<
typename Gr
idType>
440 static openvdb::GridBase::ConstPtr openvdb_grid_from_device_texture(
device_texture *image_memory,
441 float volume_clipping,
444 using ValueType =
typename GridType::ValueType;
446 openvdb::CoordBBox dense_bbox(0,
454 if (dense_bbox.empty()) {
458 openvdb::tools::Dense<ValueType, openvdb::tools::MemoryLayout::LayoutXYZ> dense(
459 dense_bbox,
static_cast<ValueType *
>(image_memory->
host_pointer));
461 openvdb::tools::copyFromDense(dense, *sparse, ValueType(volume_clipping));
467 sparse->tree().voxelizeActiveTiles();
476 openvdb::Mat4R index_to_world_mat((
double)(voxel_size.
x * transform_3d[0][0]),
481 (
double)(voxel_size.
y * transform_3d[1][1]),
486 (
double)(voxel_size.
z * transform_3d[2][2]),
488 (
double)transform_3d[0][3],
489 (
double)transform_3d[1][3],
490 (
double)transform_3d[2][3],
494 openvdb::math::Transform::createLinearTransform(index_to_world_mat);
496 sparse->setTransform(index_to_world_tfm);
501 static int estimate_required_velocity_padding(openvdb::GridBase::ConstPtr grid,
502 float velocity_scale)
505 openvdb::math::Extrema extrema;
509 if (grid->isType<openvdb::Vec3fGrid>()) {
510 openvdb::Vec3fGrid::ConstPtr vel_grid = openvdb::gridConstPtrCast<openvdb::Vec3fGrid>(grid);
511 extrema = openvdb::tools::extrema(vel_grid->cbeginValueOn());
512 voxel_size = vel_grid->voxelSize();
514 else if (grid->isType<openvdb::Vec4fGrid>()) {
515 openvdb::Vec4fGrid::ConstPtr vel_grid = openvdb::gridConstPtrCast<openvdb::Vec4fGrid>(grid);
516 extrema = openvdb::tools::extrema(vel_grid->cbeginValueOn());
517 voxel_size = vel_grid->voxelSize();
525 const double max_voxel_size = openvdb::math::Max(voxel_size.x(), voxel_size.y(), voxel_size.z());
526 if (max_voxel_size == 0.0) {
530 const double estimated_padding = extrema.max() *
static_cast<double>(velocity_scale) /
533 return static_cast<int>(
std::ceil(estimated_padding));
549 openvdb::GridBase::ConstPtr grid = vdb_loader->get_grid();
554 if (!grid->isType<openvdb::FloatGrid>()) {
558 return openvdb::gridConstPtrCast<openvdb::FloatGrid>(grid);
561 class MergeScalarGrids {
562 typedef openvdb::FloatTree ScalarTree;
564 openvdb::tree::ValueAccessor<const ScalarTree> m_acc_x, m_acc_y, m_acc_z;
567 MergeScalarGrids(
const ScalarTree *x_tree,
const ScalarTree *y_tree,
const ScalarTree *z_tree)
568 : m_acc_x(*x_tree), m_acc_y(*y_tree), m_acc_z(*z_tree)
572 MergeScalarGrids(
const MergeScalarGrids &other)
573 : m_acc_x(other.m_acc_x), m_acc_y(other.m_acc_y), m_acc_z(other.m_acc_z)
577 void operator()(
const openvdb::Vec3STree::ValueOnIter &it)
const
579 using namespace openvdb;
581 const math::Coord xyz = it.getCoord();
582 float x = m_acc_x.getValue(xyz);
583 float y = m_acc_y.getValue(xyz);
584 float z = m_acc_z.getValue(xyz);
586 it.setValue(math::Vec3s(
x,
y,
z));
590 static void merge_scalar_grids_for_velocity(
const Scene *
scene,
Volume *volume)
597 openvdb::FloatGrid::ConstPtr vel_x_grid = get_vdb_for_attribute(volume,
599 openvdb::FloatGrid::ConstPtr vel_y_grid = get_vdb_for_attribute(volume,
601 openvdb::FloatGrid::ConstPtr vel_z_grid = get_vdb_for_attribute(volume,
604 if (!(vel_x_grid && vel_y_grid && vel_z_grid)) {
612 vecgrid->tree().topologyUnion(vel_x_grid->tree());
613 vecgrid->tree().topologyUnion(vel_y_grid->tree());
614 vecgrid->tree().topologyUnion(vel_z_grid->tree());
616 MergeScalarGrids op(&vel_x_grid->tree(), &vel_y_grid->tree(), &vel_z_grid->tree());
621 vel_x_grid->transformPtr());
643 for (
Node *
node : volume->get_used_shaders()) {
650 volume_shader = shader;
653 pad_size =
max(1, pad_size);
656 pad_size =
max(2, pad_size);
669 if (!volume_shader) {
677 merge_scalar_grids_for_velocity(
scene, volume);
684 bool do_clipping =
false;
690 openvdb::GridBase::ConstPtr grid;
692 grid = vdb_loader->get_grid();
703 grid = openvdb_grid_from_device_texture<openvdb::FloatGrid>(
707 grid = openvdb_grid_from_device_texture<openvdb::Vec3fGrid>(
711 grid = openvdb_grid_from_device_texture<openvdb::Vec4fGrid>(
719 pad_size =
max(pad_size,
720 estimate_required_velocity_padding(grid, volume->get_velocity_scale()));
723 builder.add_grid(grid, do_clipping, volume->get_clipping());
741 const float face_overlap_avoidance = 0.1f *
751 volume->used_shaders.
clear();
752 volume->used_shaders.push_back_slow(volume_shader);
754 for (
size_t i = 0; i < vertices.size(); ++i) {
758 for (
size_t i = 0; i <
indices.size(); i += 3) {
765 for (
size_t i = 0; i < face_normals.size(); ++i) {
766 fN[i] = face_normals[i];
770 VLOG_WORK <<
"Memory usage volume mesh: "
771 << ((vertices.size() + face_normals.size()) *
sizeof(
float3) +
772 indices.size() *
sizeof(int)) /
NSNotificationCenter * center
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble z
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint y
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
ATTR_WARN_UNUSED_RESULT const BMVert * v
SIMD_FORCE_INLINE btVector3 transform(const btVector3 &point) const
Attribute * add(ustring name, TypeDesc type, AttributeElement element)
list< Attribute > attributes
Attribute * find(ustring name) const
ImageHandle & data_voxel()
void create_volume_mesh(const Scene *scene, Volume *volume, Progress &progress)
VDBImageLoader * vdb_loader(const int tile_index=0) const
device_texture * image_memory(const int tile_index=0) const
ImageHandle add_image(const string &filename, const ImageParams ¶ms)
void set_status(const string &status_, const string &substatus_="")
void convert_quads_to_tris(const vector< QuadData > &quads, vector< int > &tris, vector< float3 > &face_normals)
void add_padding(int pad_size)
void convert_object_space(const vector< int3 > &vertices, vector< float3 > &out_vertices, const float face_overlap_avoidance)
void create_mesh(vector< float3 > &vertices, vector< int > &indices, vector< float3 > &face_normals, const float face_overlap_avoidance)
void generate_vertices_and_quads(vector< int3 > &vertices_is, vector< QuadData > &quads)
#define CCL_NAMESPACE_END
SyclQueue void void size_t num_bytes void
static uint hash_string(const char *str)
ccl_device_inline float hash_uint_to_float(uint kx)
IconTextureDrawCall normal
ccl_gpu_kernel_postfix int ccl_global int * indices
@ ATTR_STD_VOLUME_VELOCITY_Y
@ ATTR_STD_VOLUME_VELOCITY_Z
@ ATTR_STD_VOLUME_VELOCITY
@ ATTR_STD_VOLUME_VELOCITY_X
ccl_device_inline float3 ceil(const float3 &a)
VecMat::Vec3< double > Vec3d
std::unique_ptr< IDProperty, IDPropertyDeleter > create(StringRefNull prop_name, int32_t value)
Allocate a new IDProperty of type IDP_INT, set its name and value.
static void copy(bNodeTree *dest_ntree, bNode *dest_node, const bNode *src_node)
#define SOCKET_FLOAT(name, ui_name, default_value,...)
#define SOCKET_BOOLEAN(name, ui_name, default_value,...)
@ VOLUME_INTERPOLATION_LINEAR
@ VOLUME_INTERPOLATION_CUBIC
CCL_NAMESPACE_BEGIN NODE_DEFINE(Volume)
CCL_NAMESPACE_BEGIN string string_printf(const char *format,...)
void clear(bool preserve_shaders=false) override
void reserve_mesh(int numverts, int numfaces)
void add_vertex(float3 P)
void add_triangle(int v0, int v1, int v2, int shader, bool smooth)
static NodeType * add(const char *name, CreateFunc create, Type type=NONE, const NodeType *base=NULL)
MotionType need_motion() const
ImageManager * image_manager
virtual void clear(bool preserve_shaders=false) override