diff options
author | Brecht Van Lommel <brecht@blender.org> | 2021-12-01 19:30:46 +0300 |
---|---|---|
committer | Brecht Van Lommel <brecht@blender.org> | 2021-12-16 22:54:04 +0300 |
commit | 35b1e9fc3acd6db565e7e54252a4a4152d8343d9 (patch) | |
tree | 8599df3b2be192d1fe19d30a8afb7e8d8729499e /intern/cycles/bvh/build.cpp | |
parent | 2229179faa44e2c685b4eabd0c51d4c7d5c1f193 (diff) |
Cycles: pointcloud rendering
This add support for rendering of the point cloud object in Blender, as a native
geometry type in Cycles that is more memory and time efficient than instancing
sphere meshes. This can be useful for rendering sand, water splashes, particles,
motion graphics, etc.
Points are currently always rendered as spheres, with backface culling. More
shapes are likely to be added later, but this is the most important one and can
be customized with shaders.
For CPU rendering the Embree primitive is used, for GPU there is our own
intersection code. Motion blur is suppored. Volumes inside points are not
currently supported.
Implemented with help from:
* Kévin Dietrich: Alembic procedural integration
* Patrick Mourse: OptiX integration
* Josh Whelchel: update for cycles-x changes
Ref T92573
Differential Revision: https://developer.blender.org/D9887
Diffstat (limited to 'intern/cycles/bvh/build.cpp')
-rw-r--r-- | intern/cycles/bvh/build.cpp | 130 |
1 files changed, 124 insertions, 6 deletions
diff --git a/intern/cycles/bvh/build.cpp b/intern/cycles/bvh/build.cpp index 3ce268dfb25..91198e4e2a2 100644 --- a/intern/cycles/bvh/build.cpp +++ b/intern/cycles/bvh/build.cpp @@ -26,6 +26,7 @@ #include "scene/hair.h" #include "scene/mesh.h" #include "scene/object.h" +#include "scene/pointcloud.h" #include "scene/scene.h" #include "util/algorithm.h" @@ -113,9 +114,9 @@ void BVHBuild::add_reference_triangles(BoundBox &root, else { /* Motion triangles, trace optimized case: we split triangle * primitives into separate nodes for each of the time steps. - * This way we minimize overlap of neighbor curve primitives. + * This way we minimize overlap of neighbor triangle primitives. */ - const int num_bvh_steps = params.num_motion_curve_steps * 2 + 1; + const int num_bvh_steps = params.num_motion_triangle_steps * 2 + 1; const float num_bvh_steps_inv_1 = 1.0f / (num_bvh_steps - 1); const size_t num_verts = mesh->verts.size(); const size_t num_steps = mesh->motion_steps; @@ -269,6 +270,101 @@ void BVHBuild::add_reference_curves(BoundBox &root, BoundBox ¢er, Hair *hair } } +void BVHBuild::add_reference_points(BoundBox &root, + BoundBox ¢er, + PointCloud *pointcloud, + int i) +{ + const Attribute *point_attr_mP = NULL; + if (pointcloud->has_motion_blur()) { + point_attr_mP = pointcloud->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); + } + + const float3 *points_data = &pointcloud->points[0]; + const float *radius_data = &pointcloud->radius[0]; + const size_t num_points = pointcloud->num_points(); + const float3 *motion_data = (point_attr_mP) ? point_attr_mP->data_float3() : NULL; + const size_t num_steps = pointcloud->get_motion_steps(); + + if (point_attr_mP == NULL) { + /* Really simple logic for static points. */ + for (uint j = 0; j < num_points; j++) { + const PointCloud::Point point = pointcloud->get_point(j); + BoundBox bounds = BoundBox::empty; + point.bounds_grow(points_data, radius_data, bounds); + if (bounds.valid()) { + references.push_back(BVHReference(bounds, j, i, PRIMITIVE_POINT)); + root.grow(bounds); + center.grow(bounds.center2()); + } + } + } + else if (params.num_motion_point_steps == 0 || params.use_spatial_split) { + /* Simple case of motion points: single node for the whole + * shutter time. Lowest memory usage but less optimal + * rendering. + */ + /* TODO(sergey): Support motion steps for spatially split BVH. */ + for (uint j = 0; j < num_points; j++) { + const PointCloud::Point point = pointcloud->get_point(j); + BoundBox bounds = BoundBox::empty; + point.bounds_grow(points_data, radius_data, bounds); + for (size_t step = 0; step < num_steps - 1; step++) { + point.bounds_grow(motion_data + step * num_points, radius_data, bounds); + } + if (bounds.valid()) { + references.push_back(BVHReference(bounds, j, i, PRIMITIVE_MOTION_POINT)); + root.grow(bounds); + center.grow(bounds.center2()); + } + } + } + else { + /* Motion points, trace optimized case: we split point + * primitives into separate nodes for each of the time steps. + * This way we minimize overlap of neighbor point primitives. + */ + const int num_bvh_steps = params.num_motion_point_steps * 2 + 1; + const float num_bvh_steps_inv_1 = 1.0f / (num_bvh_steps - 1); + + for (uint j = 0; j < num_points; j++) { + const PointCloud::Point point = pointcloud->get_point(j); + const size_t num_steps = pointcloud->get_motion_steps(); + const float3 *point_steps = point_attr_mP->data_float3(); + + /* Calculate bounding box of the previous time step. + * Will be reused later to avoid duplicated work on + * calculating BVH time step boundbox. + */ + float4 prev_key = point.motion_key( + points_data, radius_data, point_steps, num_points, num_steps, 0.0f, j); + BoundBox prev_bounds = BoundBox::empty; + point.bounds_grow(prev_key, prev_bounds); + /* Create all primitive time steps, */ + for (int bvh_step = 1; bvh_step < num_bvh_steps; ++bvh_step) { + const float curr_time = (float)(bvh_step)*num_bvh_steps_inv_1; + float4 curr_key = point.motion_key( + points_data, radius_data, point_steps, num_points, num_steps, curr_time, j); + BoundBox curr_bounds = BoundBox::empty; + point.bounds_grow(curr_key, curr_bounds); + BoundBox bounds = prev_bounds; + bounds.grow(curr_bounds); + if (bounds.valid()) { + const float prev_time = (float)(bvh_step - 1) * num_bvh_steps_inv_1; + references.push_back( + BVHReference(bounds, j, i, PRIMITIVE_MOTION_POINT, prev_time, curr_time)); + root.grow(bounds); + center.grow(bounds.center2()); + } + /* Current time boundbox becomes previous one for the + * next time step. + */ + prev_bounds = curr_bounds; + } + } + } +} + void BVHBuild::add_reference_geometry(BoundBox &root, BoundBox ¢er, Geometry *geom, @@ -282,6 +378,10 @@ void BVHBuild::add_reference_geometry(BoundBox &root, Hair *hair = static_cast<Hair *>(geom); add_reference_curves(root, center, hair, object_index); } + else if (geom->geometry_type == Geometry::POINTCLOUD) { + PointCloud *pointcloud = static_cast<PointCloud *>(geom); + add_reference_points(root, center, pointcloud, object_index); + } } void BVHBuild::add_reference_object(BoundBox &root, BoundBox ¢er, Object *ob, int i) @@ -311,6 +411,10 @@ static size_t count_primitives(Geometry *geom) Hair *hair = static_cast<Hair *>(geom); return count_curve_segments(hair); } + else if (geom->geometry_type == Geometry::POINTCLOUD) { + PointCloud *pointcloud = static_cast<PointCloud *>(geom); + return pointcloud->num_points(); + } return 0; } @@ -328,8 +432,9 @@ void BVHBuild::add_references(BVHRange &root) if (!ob->get_geometry()->is_instanced()) { num_alloc_references += count_primitives(ob->get_geometry()); } - else + else { num_alloc_references++; + } } else { num_alloc_references += count_primitives(ob->get_geometry()); @@ -394,7 +499,7 @@ BVHNode *BVHBuild::run() spatial_min_overlap = root.bounds().safe_area() * params.spatial_split_alpha; spatial_free_index = 0; - need_prim_time = params.num_motion_curve_steps > 0 || params.num_motion_triangle_steps > 0; + need_prim_time = params.use_motion_steps(); /* init progress updates */ double build_start_time; @@ -535,7 +640,8 @@ bool BVHBuild::range_within_max_leaf_size(const BVHRange &range, const vector<BVHReference> &references) const { size_t size = range.size(); - size_t max_leaf_size = max(params.max_triangle_leaf_size, params.max_curve_leaf_size); + size_t max_leaf_size = max(max(params.max_triangle_leaf_size, params.max_curve_leaf_size), + params.max_point_leaf_size); if (size > max_leaf_size) return false; @@ -544,6 +650,8 @@ bool BVHBuild::range_within_max_leaf_size(const BVHRange &range, size_t num_motion_triangles = 0; size_t num_curves = 0; size_t num_motion_curves = 0; + size_t num_points = 0; + size_t num_motion_points = 0; for (int i = 0; i < size; i++) { const BVHReference &ref = references[range.start() + i]; @@ -564,12 +672,22 @@ bool BVHBuild::range_within_max_leaf_size(const BVHRange &range, num_triangles++; } } + else if (ref.prim_type() & PRIMITIVE_ALL_POINT) { + if (ref.prim_type() & PRIMITIVE_ALL_MOTION) { + num_motion_points++; + } + else { + num_points++; + } + } } return (num_triangles <= params.max_triangle_leaf_size) && (num_motion_triangles <= params.max_motion_triangle_leaf_size) && (num_curves <= params.max_curve_leaf_size) && - (num_motion_curves <= params.max_motion_curve_leaf_size); + (num_motion_curves <= params.max_motion_curve_leaf_size) && + (num_points <= params.max_point_leaf_size) && + (num_motion_points <= params.max_motion_point_leaf_size); } /* multithreaded binning builder */ |