commit 17b3105 Author: Brecht Van Lommel Date: Tue Feb 4 09:14:06 2020 +0100 Cycles: pointcloud geometry type [WIP] diff --git a/intern/cycles/blender/CMakeLists.txt b/intern/cycles/blender/CMakeLists.txt index e0fa45d..5c8407e 100644 --- a/intern/cycles/blender/CMakeLists.txt +++ b/intern/cycles/blender/CMakeLists.txt @@ -17,16 +17,17 @@ set(INC_SYS set(SRC blender_camera.cpp + blender_curves.cpp blender_device.cpp blender_image.cpp blender_geometry.cpp blender_light.cpp + blender_logging.cpp blender_mesh.cpp blender_object.cpp blender_object_cull.cpp blender_particles.cpp - blender_curves.cpp - blender_logging.cpp + blender_pointcloud.cpp blender_python.cpp blender_session.cpp blender_shader.cpp diff --git a/intern/cycles/blender/blender_curves.cpp b/intern/cycles/blender/blender_curves.cpp index 6288c37..5bc285e 100644 --- a/intern/cycles/blender/blender_curves.cpp +++ b/intern/cycles/blender/blender_curves.cpp @@ -417,6 +417,8 @@ static void export_hair_motion_validate_attribute(Hair *hair, else if (motion_step > 0) { VLOG(1) << "Filling in new motion vertex position for motion_step " << motion_step; + /* TODO: use copy to center. */ + /* Motion, fill up previous steps that we might have skipped because * they had no motion, but we need them anyway now. */ for (int step = 0; step < motion_step; step++) { @@ -448,6 +450,7 @@ static void ExportCurveSegmentsMotion(Hair *hair, ParticleCurveData *CData, int /* export motion vectors for curve keys */ size_t numkeys = hair->curve_keys.size(); + /* TODO: is not float4? */ float4 *mP = attr_mP->data_float4() + motion_step * numkeys; bool have_motion = false; int i = 0; @@ -743,6 +746,7 @@ static void export_hair_curves_motion(Hair *hair, BL::Hair b_hair, int motion_st /* Export motion keys. */ const int num_keys = hair->curve_keys.size(); + /* TODO: is not float4? */ float4 *mP = attr_mP->data_float4() + motion_step * num_keys; bool have_motion = false; int num_motion_keys = 0; diff --git a/intern/cycles/blender/blender_geometry.cpp b/intern/cycles/blender/blender_geometry.cpp index 002f5e0..9b8b668 100644 --- a/intern/cycles/blender/blender_geometry.cpp +++ b/intern/cycles/blender/blender_geometry.cpp @@ -19,6 +19,7 @@ #include "render/hair.h" #include "render/mesh.h" #include "render/object.h" +#include "render/pointcloud.h" #include "render/volume.h" #include "blender/blender_sync.h" @@ -38,6 +39,10 @@ static Geometry::Type determine_geom_type(BL::Object &b_ob, bool use_particle_ha return Geometry::VOLUME; } + if (b_ob.type() == BL::Object::type_POINTCLOUD) { + return Geometry::POINTCLOUD; + } + return Geometry::MESH; } @@ -88,6 +93,9 @@ Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph, else if (geom_type == Geometry::VOLUME) { geom = scene->create_node(); } + else if (geom_type == Geometry::POINTCLOUD) { + geom = scene->create_node(); + } else { geom = scene->create_node(); } @@ -144,6 +152,10 @@ Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph, Volume *volume = static_cast(geom); sync_volume(b_ob, volume, used_shaders); } + else if (geom_type == Geometry::POINTCLOUD) { + PointCloud *pointcloud = static_cast(geom); + sync_pointcloud(b_ob, pointcloud); + } else { Mesh *mesh = static_cast(geom); sync_mesh(b_depsgraph, b_ob, mesh, used_shaders); @@ -181,6 +193,10 @@ void BlenderSync::sync_geometry_motion(BL::Depsgraph &b_depsgraph, Hair *hair = static_cast(geom); sync_hair_motion(b_depsgraph, b_ob, hair, motion_step); } + else if (b_ob.type() == BL::Object::type_POINTCLOUD) { + PointCloud *pointcloud = static_cast(geom); + sync_pointcloud_motion(b_ob, pointcloud, motion_step); + } else if (b_ob.type() == BL::Object::type_VOLUME || object_fluid_gas_domain_find(b_ob)) { /* No volume motion blur support yet. */ } diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp index 212b9cb..772c9ce 100644 --- a/intern/cycles/blender/blender_object.cpp +++ b/intern/cycles/blender/blender_object.cpp @@ -69,7 +69,8 @@ bool BlenderSync::object_is_geometry(BL::Object &b_ob) BL::Object::type_enum type = b_ob.type(); - if (type == BL::Object::type_VOLUME || type == BL::Object::type_HAIR) { + if (type == BL::Object::type_VOLUME || type == BL::Object::type_HAIR || + type == BL::Object::type_POINTCLOUD) { /* Will be exported attached to mesh. */ return true; } @@ -142,7 +143,7 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph, return NULL; } - /* only interested in object that we can create meshes from */ + /* only interested in object that we can create geometry from */ if (!object_is_geometry(b_ob)) { return NULL; } diff --git a/intern/cycles/blender/blender_pointcloud.cpp b/intern/cycles/blender/blender_pointcloud.cpp new file mode 100644 index 0000000..a807dba --- /dev/null +++ b/intern/cycles/blender/blender_pointcloud.cpp @@ -0,0 +1,137 @@ +/* + * Copyright 2011-2013 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "render/attribute.h" +#include "render/pointcloud.h" +#include "render/scene.h" + +#include "blender/blender_sync.h" +#include "blender/blender_util.h" + +#include "util/util_hash.h" + +CCL_NAMESPACE_BEGIN + +static void export_pointcloud(Scene *scene, PointCloud *pointcloud, BL::PointCloud b_pointcloud) +{ + /* TODO: optimize so we can straight memcpy arrays from Blender? */ + + /* Add requested attributes. */ + Attribute *attr_random = NULL; + if (pointcloud->need_attribute(scene, ATTR_STD_POINT_RANDOM)) { + attr_random = pointcloud->attributes.add(ATTR_STD_POINT_RANDOM); + } + + /* Reserve memory. */ + const int num_points = b_pointcloud.points.length(); + pointcloud->reserve(num_points); + + /* Export points. */ + BL::PointCloud::points_iterator b_point_iter; + for (b_pointcloud.points.begin(b_point_iter); b_point_iter != b_pointcloud.points.end(); + ++b_point_iter) { + BL::Point b_point = *b_point_iter; + const float3 co = get_float3(b_point.co()); + const float radius = b_point.radius(); + pointcloud->add_point(co, radius); + + /* Random number per point. */ + if (attr_random != NULL) { + attr_random->add(hash_uint2_to_float(b_point.index(), 0)); + } + } +} + +static void export_pointcloud_motion(PointCloud *pointcloud, + BL::PointCloud b_pointcloud, + int motion_step) +{ + /* Find or add attribute. */ + Attribute *attr_mP = pointcloud->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); + bool new_attribute = false; + + if (!attr_mP) { + attr_mP = pointcloud->attributes.add(ATTR_STD_MOTION_VERTEX_POSITION); + new_attribute = true; + } + + /* Export motion points. */ + const int num_points = pointcloud->num_points(); + float3 *mP = attr_mP->data_float3() + motion_step * num_points; + bool have_motion = false; + int num_motion_points = 0; + + BL::PointCloud::points_iterator b_point_iter; + for (b_pointcloud.points.begin(b_point_iter); b_point_iter != b_pointcloud.points.end(); + ++b_point_iter) { + BL::Point b_point = *b_point_iter; + + if (num_motion_points < num_points) { + float3 P = get_float3(b_point.co()); + mP[num_motion_points] = P; + have_motion = have_motion || (P != pointcloud->points[num_motion_points]); + num_motion_points++; + } + } + + /* In case of new attribute, we verify if there really was any motion. */ + if (new_attribute) { + if (num_motion_points != num_points || !have_motion) { + pointcloud->attributes.remove(ATTR_STD_MOTION_VERTEX_POSITION); + } + else if (motion_step > 0) { + /* Motion, fill up previous steps that we might have skipped because + * they had no motion, but we need them anyway now. */ + for (int step = 0; step < motion_step; step++) { + pointcloud->copy_center_to_motion_step(step); + } + } + } +} + +void BlenderSync::sync_pointcloud(BL::Object b_ob, PointCloud *pointcloud) +{ + size_t old_numpoints = pointcloud->num_points(); + + /* TODO: allow disabling in view layer. */ + BL::PointCloud b_pointcloud(b_ob.data()); + export_pointcloud(scene, pointcloud, b_pointcloud); + + /* tag update */ + const bool rebuild = (pointcloud && old_numpoints != pointcloud->num_points()); + pointcloud->tag_update(scene, rebuild); +} + +void BlenderSync::sync_pointcloud_motion(BL::Object b_ob, PointCloud *pointcloud, int motion_step) +{ + /* Skip if nothing exported. */ + if (pointcloud->num_points() == 0) { + return; + } + + /* Export deformed coordinates. */ + if (ccl::BKE_object_is_deform_modified(b_ob, b_scene, preview)) { + /* PointCloud object. */ + BL::PointCloud b_pointcloud(b_ob.data()); + export_pointcloud_motion(pointcloud, b_pointcloud, motion_step); + } + else { + /* No deformation on this frame, copy coordinates if other frames did have it. */ + pointcloud->copy_center_to_motion_step(motion_step); + } +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp index 0126e5c..1220ae9 100644 --- a/intern/cycles/blender/blender_sync.cpp +++ b/intern/cycles/blender/blender_sync.cpp @@ -153,7 +153,7 @@ void BlenderSync::sync_recalc(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d if (is_geometry || is_light) { const bool updated_geometry = b_update->is_updated_geometry(); - /* Geometry (mesh, hair, volume). */ + /* Geometry (mesh, hair, volume, pointcloud). */ if (is_geometry) { if (b_update->is_updated_transform() || b_update->is_updated_shading()) { object_map.set_recalc(b_ob); diff --git a/intern/cycles/blender/blender_sync.h b/intern/cycles/blender/blender_sync.h index 62fd1ac..116a56b 100644 --- a/intern/cycles/blender/blender_sync.h +++ b/intern/cycles/blender/blender_sync.h @@ -168,12 +168,16 @@ class BlenderSync { Hair *hair, BL::Mesh &b_mesh, BL::Object &b_ob, bool motion, int motion_step = 0); bool object_has_particle_hair(BL::Object b_ob); + /* Point Cloud */ + void sync_pointcloud(BL::Object b_ob, PointCloud *pointcloud); + void sync_pointcloud_motion(BL::Object b_ob, PointCloud *pointcloud, int motion_step); + /* Camera */ void sync_camera_motion( BL::RenderSettings &b_render, BL::Object &b_ob, int width, int height, float motion_time); /* Geometry */ - Geometry *sync_geometry(BL::Depsgraph &b_depsgrpah, + Geometry *sync_geometry(BL::Depsgraph &b_depsgraph, BL::Object &b_ob, BL::Object &b_ob_instance, bool object_updated, diff --git a/intern/cycles/bvh/bvh.cpp b/intern/cycles/bvh/bvh.cpp index 2a11142..0209b92 100644 --- a/intern/cycles/bvh/bvh.cpp +++ b/intern/cycles/bvh/bvh.cpp @@ -205,6 +205,7 @@ void BVH::refit_primitives(int start, int end, BoundBox &bbox, uint &visibility) bbox.grow(ob->bounds); } else { + /* TODO: points */ /* Primitives. */ if (pack.prim_type[prim] & PRIMITIVE_ALL_CURVE) { /* Curves. */ @@ -371,7 +372,7 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size) pack.leaf_nodes.resize(leaf_nodes_size); pack.object_node.resize(objects.size()); - if (params.num_motion_curve_steps > 0 || params.num_motion_triangle_steps > 0) { + if (params.use_motion_steps()) { pack.prim_time.resize(prim_index_size); } @@ -433,15 +434,14 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size) float2 *bvh_prim_time = bvh->pack.prim_time.size() ? &bvh->pack.prim_time[0] : NULL; for (size_t i = 0; i < bvh_prim_index_size; i++) { - if (bvh->pack.prim_type[i] & PRIMITIVE_ALL_CURVE) { - pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + geom_prim_offset; - pack_prim_tri_index[pack_prim_index_offset] = -1; - } - else { - pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + geom_prim_offset; + pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + geom_prim_offset; + if (bvh->pack.prim_type[i] & PRIMITIVE_ALL_TRIANGLE) { pack_prim_tri_index[pack_prim_index_offset] = bvh_prim_tri_index[i] + pack_prim_tri_verts_offset; } + else { + pack_prim_tri_index[pack_prim_index_offset] = -1; + } pack_prim_type[pack_prim_index_offset] = bvh_prim_type[i]; pack_prim_visibility[pack_prim_index_offset] = bvh_prim_visibility[i]; diff --git a/intern/cycles/bvh/bvh_build.cpp b/intern/cycles/bvh/bvh_build.cpp index 360cac5..0432373 100644 --- a/intern/cycles/bvh/bvh_build.cpp +++ b/intern/cycles/bvh/bvh_build.cpp @@ -26,6 +26,7 @@ #include "render/hair.h" #include "render/mesh.h" #include "render/object.h" +#include "render/pointcloud.h" #include "render/scene.h" #include "util/util_algorithm.h" @@ -109,9 +110,9 @@ void BVHBuild::add_reference_triangles(BoundBox &root, BoundBox ¢er, Mesh *m 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; @@ -268,6 +269,113 @@ 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.data(); + const float *radius_data = pointcloud->radius.data(); + 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->motion_steps; + + if (point_attr_mP == NULL) { + /* Really simple logic for static hair. */ + 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 while + * 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()); + } + } + } + /* TODO */ +#if 0 + 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->motion_steps; + /* Calculate bounding box of the previous time step. + * Will be reused later to avoid duplicated work on + * calculating BVH time step boundbox. + */ + float4 prev_keys[4]; + point.cardinal_motion_keys( + points, radius, key_steps, num_keys, num_steps, 0.0f, k - 1, k, k + 1, k + 2, prev_keys); + BoundBox prev_bounds = BoundBox::empty; + point.bounds_grow(prev_keys, 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_keys[4]; + point.cardinal_motion_keys(points, + radius, + key_steps, + num_keys, + num_steps, + curr_time, + k - 1, + k, + k + 1, + k + 2, + curr_keys); + BoundBox curr_bounds = BoundBox::empty; + point.bounds_grow(motion_data + step * num_points, radius_data, bounds); + point.bounds_grow(curr_keys, 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; + } + } + } +#endif +} + void BVHBuild::add_reference_geometry(BoundBox &root, BoundBox ¢er, Geometry *geom, int i) { if (geom->type == Geometry::MESH || geom->type == Geometry::VOLUME) { @@ -278,6 +386,10 @@ void BVHBuild::add_reference_geometry(BoundBox &root, BoundBox ¢er, Geometry Hair *hair = static_cast(geom); add_reference_curves(root, center, hair, i); } + else if (geom->type == Geometry::POINTCLOUD) { + PointCloud *pointcloud = static_cast(geom); + add_reference_points(root, center, pointcloud, i); + } } void BVHBuild::add_reference_object(BoundBox &root, BoundBox ¢er, Object *ob, int i) @@ -305,8 +417,14 @@ static size_t count_primitives(Geometry *geom) } else if (geom->type == Geometry::HAIR) { Hair *hair = static_cast(geom); + // TODO: call num_segments? return count_curve_segments(hair); } + else if (geom->type == Geometry::POINTCLOUD) { + // TODO: num_primitives callback? + PointCloud *pointcloud = static_cast(geom); + return pointcloud->num_points(); + } return 0; } @@ -390,7 +508,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; @@ -531,7 +649,8 @@ bool BVHBuild::range_within_max_leaf_size(const BVHRange &range, const vector &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; @@ -540,6 +659,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]; @@ -560,12 +681,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 */ diff --git a/intern/cycles/bvh/bvh_build.h b/intern/cycles/bvh/bvh_build.h index c35af08..9dfcae7 100644 --- a/intern/cycles/bvh/bvh_build.h +++ b/intern/cycles/bvh/bvh_build.h @@ -39,6 +39,7 @@ class Geometry; class Hair; class Mesh; class Object; +class PointCloud; class Progress; /* BVH Builder */ @@ -68,6 +69,7 @@ class BVHBuild { /* Adding references. */ void add_reference_triangles(BoundBox &root, BoundBox ¢er, Mesh *mesh, int i); void add_reference_curves(BoundBox &root, BoundBox ¢er, Hair *hair, int i); + void add_reference_points(BoundBox &root, BoundBox ¢er, PointCloud *pointcloud, int i); void add_reference_geometry(BoundBox &root, BoundBox ¢er, Geometry *geom, int i); void add_reference_object(BoundBox &root, BoundBox ¢er, Object *ob, int i); void add_references(BVHRange &root); diff --git a/intern/cycles/bvh/bvh_embree.cpp b/intern/cycles/bvh/bvh_embree.cpp index 13bad36..1c93e59 100644 --- a/intern/cycles/bvh/bvh_embree.cpp +++ b/intern/cycles/bvh/bvh_embree.cpp @@ -47,6 +47,7 @@ # include "render/hair.h" # include "render/mesh.h" # include "render/object.h" +# include "render/pointcloud.h" # include "util/util_foreach.h" # include "util/util_logging.h" @@ -96,13 +97,18 @@ static void rtc_filter_occluded_func(const RTCFilterFunctionNArguments *args) *isect = current_isect; int prim = kernel_tex_fetch(__prim_index, isect->prim); int shader = 0; - if (kernel_tex_fetch(__prim_type, isect->prim) & PRIMITIVE_ALL_TRIANGLE) { + int prim_type = kernel_tex_fetch(__prim_type, isect->prim); + /* TODO: utility function? */ + if (prim_type & PRIMITIVE_ALL_TRIANGLE) { shader = kernel_tex_fetch(__tri_shader, prim); } - else { + else if (prim_type & PRIMITIVE_ALL_CURVE) { float4 str = kernel_tex_fetch(__curves, prim); shader = __float_as_int(str.z); } + else if (prim_type & PRIMITIVE_ALL_POINT) { + shader = kernel_tex_fetch(__points_shader, prim); + } int flag = kernel_tex_fetch(__shaders, shader & SHADER_MASK).flags; /* If no transparent shadows, all light is blocked. */ if (flag & (SD_HAS_TRANSPARENT_SHADOW)) { @@ -298,6 +304,7 @@ static bool rtc_progress_func(void *user_ptr, const double n) return !progress->get_cancel(); } +/* TODO: generic? */ static size_t count_primitives(Geometry *geom) { if (geom->type == Geometry::MESH || geom->type == Geometry::VOLUME) { @@ -308,6 +315,10 @@ static size_t count_primitives(Geometry *geom) Hair *hair = static_cast(geom); return hair->num_segments(); } + else if (geom->type == Geometry::POINTCLOUD) { + PointCloud *pointcloud = static_cast(geom); + return pointcloud->num_points(); + } return 0; } @@ -494,6 +505,12 @@ void BVHEmbree::add_object(Object *ob, int i) add_curves(ob, hair, i); } } + else if (geom->type == Geometry::POINTCLOUD) { + PointCloud *pointcloud = static_cast(geom); + if (pointcloud->num_points() > 0) { + add_points(ob, pointcloud, i); + } + } } void BVHEmbree::add_instance(Object *ob, int i) @@ -665,6 +682,7 @@ void BVHEmbree::update_curve_vertex_buffer(RTCGeometry geom_id, const Hair *hair } } + /* TODO: faster */ const size_t num_curves = hair->num_curves(); size_t num_keys = 0; for (size_t j = 0; j < num_curves; ++j) { @@ -796,6 +814,95 @@ void BVHEmbree::add_curves(const Object *ob, const Hair *hair, int i) rtcReleaseGeometry(geom_id); } +void BVHEmbree::update_point_vertex_buffer(RTCGeometry geom_id, const PointCloud *pointcloud) +{ + const Attribute *attr_mP = NULL; + size_t num_motion_steps = 1; + if (pointcloud->has_motion_blur()) { + attr_mP = pointcloud->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); + if (attr_mP) { + num_motion_steps = pointcloud->motion_steps; + } + } + + const size_t num_points = pointcloud->num_points(); + + /* Copy the point data to Embree */ + const int t_mid = (num_motion_steps - 1) / 2; + const float *radius = pointcloud->radius.data(); + for (int t = 0; t < num_motion_steps; ++t) { + const float3 *verts; + if (t == t_mid || attr_mP == NULL) { + verts = pointcloud->points.data(); + } + else { + int t_ = (t > t_mid) ? (t - 1) : t; + verts = &attr_mP->data_float3()[t_ * num_points]; + } + + float4 *rtc_verts = (float4 *)rtcSetNewGeometryBuffer( + geom_id, RTC_BUFFER_TYPE_VERTEX, t, RTC_FORMAT_FLOAT4, sizeof(float) * 4, num_points); + assert(rtc_verts); + if (rtc_verts) { + for (size_t j = 0; j < num_points; ++j) { + rtc_verts[j] = float3_to_float4(verts[j]); + rtc_verts[j].w = radius[j]; + } + } + } +} + +void BVHEmbree::add_points(const Object *ob, const PointCloud *pointcloud, int i) +{ + size_t prim_offset = pack.prim_index.size(); + const Attribute *attr_mP = NULL; + size_t num_motion_steps = 1; + if (pointcloud->has_motion_blur()) { + attr_mP = pointcloud->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); + if (attr_mP) { + num_motion_steps = pointcloud->motion_steps; + } + } + + const size_t num_points = pointcloud->num_points(); + + /* Make room for Cycles specific data. */ + size_t prim_object_size = pack.prim_object.size(); + pack.prim_object.resize(prim_object_size + num_points); + size_t prim_type_size = pack.prim_type.size(); + pack.prim_type.resize(prim_type_size + num_points); + size_t prim_index_size = pack.prim_index.size(); + pack.prim_index.resize(prim_index_size + num_points); + /* TODO: avoid? */ + size_t prim_tri_index_size = pack.prim_index.size(); + pack.prim_tri_index.resize(prim_tri_index_size + num_points); + + enum RTCGeometryType type = RTC_GEOMETRY_TYPE_SPHERE_POINT; + + RTCGeometry geom_id = rtcNewGeometry(rtc_device, type); + int prim_type = num_motion_steps > 1 ? PRIMITIVE_MOTION_POINT : PRIMITIVE_POINT; + for (size_t j = 0; j < num_points; ++j) { + /* Cycles specific data. */ + pack.prim_object[prim_object_size + j] = i; + pack.prim_type[prim_type_size + j] = prim_type; + pack.prim_index[prim_index_size + j] = j; + pack.prim_tri_index[prim_tri_index_size + j] = j; + } + + rtcSetGeometryBuildQuality(geom_id, build_quality); + rtcSetGeometryTimeStepCount(geom_id, num_motion_steps); + + update_point_vertex_buffer(geom_id, pointcloud); + + rtcSetGeometryUserData(geom_id, (void *)prim_offset); + rtcSetGeometryOccludedFilterFunction(geom_id, rtc_filter_occluded_func); + rtcSetGeometryMask(geom_id, ob->visibility); + + rtcCommitGeometry(geom_id); + rtcAttachGeometryByID(scene, geom_id, i * 2); + rtcReleaseGeometry(geom_id); +} + void BVHEmbree::pack_nodes(const BVHNode *) { /* Quite a bit of this code is for compatibility with Cycles' native BVH. */ @@ -892,15 +999,14 @@ void BVHEmbree::pack_nodes(const BVHNode *) uint *bvh_prim_tri_index = &bvh->pack.prim_tri_index[0]; for (size_t i = 0; i < bvh_prim_index_size; ++i) { - if (bvh->pack.prim_type[i] & PRIMITIVE_ALL_CURVE) { - pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + geom_prim_offset; - pack_prim_tri_index[pack_prim_index_offset] = -1; - } - else { - pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + geom_prim_offset; + pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + geom_prim_offset; + if (bvh->pack.prim_type[i] & PRIMITIVE_ALL_TRIANGLE) { pack_prim_tri_index[pack_prim_index_offset] = bvh_prim_tri_index[i] + pack_prim_tri_verts_offset; } + else { + pack_prim_tri_index[pack_prim_index_offset] = -1; + } pack_prim_type[pack_prim_index_offset] = bvh_prim_type[i]; pack_prim_object[pack_prim_index_offset] = 0; @@ -944,6 +1050,13 @@ void BVHEmbree::refit_nodes() rtcCommitGeometry(rtcGetGeometry(scene, geom_id + 1)); } } + else if (geom->type == Geometry::POINTCLOUD) { + PointCloud *pointcloud = static_cast(geom); + if (pointcloud->num_points() > 0) { + update_point_vertex_buffer(rtcGetGeometry(scene, geom_id), pointcloud); + rtcCommitGeometry(rtcGetGeometry(scene, geom_id)); + } + } } geom_id += 2; } diff --git a/intern/cycles/bvh/bvh_embree.h b/intern/cycles/bvh/bvh_embree.h index 841f02e..93dd3c7 100644 --- a/intern/cycles/bvh/bvh_embree.h +++ b/intern/cycles/bvh/bvh_embree.h @@ -34,6 +34,7 @@ CCL_NAMESPACE_BEGIN class Geometry; class Hair; class Mesh; +class PointCloud; class BVHEmbree : public BVH { public: @@ -59,6 +60,7 @@ class BVHEmbree : public BVH { void add_object(Object *ob, int i); void add_instance(Object *ob, int i); void add_curves(const Object *ob, const Hair *hair, int i); + void add_points(const Object *ob, const PointCloud *pointcloud, int i); void add_triangles(const Object *ob, const Mesh *mesh, int i); ssize_t mem_used; @@ -73,6 +75,7 @@ class BVHEmbree : public BVH { void delete_rtcScene(); void update_tri_vertex_buffer(RTCGeometry geom_id, const Mesh *mesh); void update_curve_vertex_buffer(RTCGeometry geom_id, const Hair *hair); + void update_point_vertex_buffer(RTCGeometry geom_id, const PointCloud *pointcloud); RTCDevice rtc_device; diff --git a/intern/cycles/bvh/bvh_optix.cpp b/intern/cycles/bvh/bvh_optix.cpp index 0527c0e..c49b7db 100644 --- a/intern/cycles/bvh/bvh_optix.cpp +++ b/intern/cycles/bvh/bvh_optix.cpp @@ -114,6 +114,7 @@ void BVHOptiX::pack_blas() } } } + /* TODO: points */ // Initialize visibility to zero and later update it during top-level build uint prev_visibility = objects[0]->visibility; @@ -184,13 +185,12 @@ void BVHOptiX::pack_tlas() uint *bvh_prim_visibility = &bvh_pack.prim_visibility[0]; for (size_t i = 0; i < bvh_pack.prim_index.size(); i++, pack_offset++) { - if (bvh_pack.prim_type[i] & PRIMITIVE_ALL_CURVE) { - pack_prim_index[pack_offset] = bvh_prim_index[i] + geom_prim_offset; - pack_prim_tri_index[pack_offset] = -1; + pack_prim_index[pack_offset] = bvh_prim_index[i] + geom_prim_offset; + if (bvh_pack.prim_type[i] & PRIMITIVE_ALL_TRIANGLE) { + pack_prim_tri_index[pack_offset] = bvh_prim_tri_index[i] + pack_verts_offset; } else { - pack_prim_index[pack_offset] = bvh_prim_index[i] + geom_prim_offset; - pack_prim_tri_index[pack_offset] = bvh_prim_tri_index[i] + pack_verts_offset; + pack_prim_tri_index[pack_offset] = -1; } pack_prim_type[pack_offset] = bvh_prim_type[i]; diff --git a/intern/cycles/bvh/bvh_params.h b/intern/cycles/bvh/bvh_params.h index 1a50742..d6c0952 100644 --- a/intern/cycles/bvh/bvh_params.h +++ b/intern/cycles/bvh/bvh_params.h @@ -62,6 +62,8 @@ class BVHParams { int max_motion_triangle_leaf_size; int max_curve_leaf_size; int max_motion_curve_leaf_size; + int max_point_leaf_size; + int max_motion_point_leaf_size; /* object or mesh level bvh */ bool top_level; @@ -77,13 +79,11 @@ class BVHParams { /* Split time range to this number of steps and create leaf node for each * of this time steps. * - * Speeds up rendering of motion curve primitives in the cost of higher - * memory usage. + * Speeds up rendering motion primitives in the cost of higher memory usage. */ - int num_motion_curve_steps; - - /* Same as above, but for triangle primitives. */ int num_motion_triangle_steps; + int num_motion_curve_steps; + int num_motion_point_steps; /* Same as in SceneParams. */ int bvh_type; @@ -111,13 +111,17 @@ class BVHParams { max_motion_triangle_leaf_size = 8; max_curve_leaf_size = 1; max_motion_curve_leaf_size = 4; + /* TODO: tweak */ + max_point_leaf_size = 1; + max_motion_point_leaf_size = 8; top_level = false; bvh_layout = BVH_LAYOUT_BVH2; use_unaligned_nodes = false; - num_motion_curve_steps = 0; num_motion_triangle_steps = 0; + num_motion_curve_steps = 0; + num_motion_point_steps = 0; bvh_type = 0; @@ -145,6 +149,12 @@ class BVHParams { return (size <= min_leaf_size || level >= MAX_DEPTH); } + bool use_motion_steps() + { + return num_motion_curve_steps > 0 || num_motion_triangle_steps > 0 || + num_motion_point_steps > 0; + } + /* Gets best matching BVH. * * If the requested layout is supported by the device, it will be used. diff --git a/intern/cycles/bvh/bvh_split.cpp b/intern/cycles/bvh/bvh_split.cpp index 2f1960d..82add4a 100644 --- a/intern/cycles/bvh/bvh_split.cpp +++ b/intern/cycles/bvh/bvh_split.cpp @@ -22,6 +22,7 @@ #include "render/hair.h" #include "render/mesh.h" +#include "render/pointcloud.h" #include "render/object.h" #include "util/util_algorithm.h" @@ -426,6 +427,19 @@ void BVHSpatialSplit::split_curve_primitive(const Hair *hair, } } +void BVHSpatialSplit::split_point_primitive(const PointCloud *pointcloud, + const Transform *tfm, + int prim_index, + int dim, + float pos, + BoundBox &left_bounds, + BoundBox &right_bounds) +{ + float3 point = pointcloud->points[prim_index]; + float radius = pointcloud->radius[prim_index]; + /* TODO */ +} + void BVHSpatialSplit::split_triangle_reference(const BVHReference &ref, const Mesh *mesh, int dim, @@ -453,6 +467,16 @@ void BVHSpatialSplit::split_curve_reference(const BVHReference &ref, right_bounds); } +void BVHSpatialSplit::split_point_reference(const BVHReference &ref, + const PointCloud *pointcloud, + int dim, + float pos, + BoundBox &left_bounds, + BoundBox &right_bounds) +{ + split_point_primitive(pointcloud, NULL, ref.prim_index(), dim, pos, left_bounds, right_bounds); +} + void BVHSpatialSplit::split_object_reference( const Object *object, int dim, float pos, BoundBox &left_bounds, BoundBox &right_bounds) { @@ -474,6 +498,13 @@ void BVHSpatialSplit::split_object_reference( } } } + else if (geom->type == Geometry::POINTCLOUD) { + PointCloud *pointcloud = static_cast(geom); + for (int point_idx = 0; point_idx < pointcloud->num_points(); ++point_idx) { + split_point_primitive( + pointcloud, &object->tfm, point_idx, dim, pos, left_bounds, right_bounds); + } + } } void BVHSpatialSplit::split_reference(const BVHBuild &builder, @@ -498,6 +529,10 @@ void BVHSpatialSplit::split_reference(const BVHBuild &builder, Hair *hair = static_cast(ob->geometry); split_curve_reference(ref, hair, dim, pos, left_bounds, right_bounds); } + else if (ref.prim_type() & PRIMITIVE_ALL_POINT) { + PointCloud *pointcloud = static_cast(ob->geometry); + split_point_reference(ref, pointcloud, dim, pos, left_bounds, right_bounds); + } else { split_object_reference(ob, dim, pos, left_bounds, right_bounds); } diff --git a/intern/cycles/bvh/bvh_split.h b/intern/cycles/bvh/bvh_split.h index 28ff0e0..7648ef3 100644 --- a/intern/cycles/bvh/bvh_split.h +++ b/intern/cycles/bvh/bvh_split.h @@ -26,6 +26,7 @@ CCL_NAMESPACE_BEGIN class BVHBuild; class Hair; class Mesh; +class PointCloud; struct Transform; /* Object Split */ @@ -123,6 +124,13 @@ class BVHSpatialSplit { float pos, BoundBox &left_bounds, BoundBox &right_bounds); + void split_point_primitive(const PointCloud *pointcloud, + const Transform *tfm, + int prim_index, + int dim, + float pos, + BoundBox &left_bounds, + BoundBox &right_bounds); /* Lower-level functions which calculates boundaries of left and right nodes * needed for spatial split. @@ -141,6 +149,13 @@ class BVHSpatialSplit { float pos, BoundBox &left_bounds, BoundBox &right_bounds); + void split_point_reference(const BVHReference &ref, + const PointCloud *pointcloud, + int dim, + float pos, + BoundBox &left_bounds, + BoundBox &right_bounds); + void split_object_reference( const Object *object, int dim, float pos, BoundBox &left_bounds, BoundBox &right_bounds); diff --git a/intern/cycles/device/device.cpp b/intern/cycles/device/device.cpp index 407f73e..b0e496d 100644 --- a/intern/cycles/device/device.cpp +++ b/intern/cycles/device/device.cpp @@ -52,6 +52,7 @@ std::ostream &operator<<(std::ostream &os, const DeviceRequestedFeatures &reques /* TODO(sergey): Decode bitflag into list of names. */ os << "Nodes features: " << requested_features.nodes_features << std::endl; os << "Use Hair: " << string_from_bool(requested_features.use_hair) << std::endl; + os << "Use Pointclouds: " << string_from_bool(requested_features.use_pointcloud) << std::endl; os << "Use Object Motion: " << string_from_bool(requested_features.use_object_motion) << std::endl; os << "Use Camera Motion: " << string_from_bool(requested_features.use_camera_motion) diff --git a/intern/cycles/device/device.h b/intern/cycles/device/device.h index ddf608a..b0e80e6 100644 --- a/intern/cycles/device/device.h +++ b/intern/cycles/device/device.h @@ -138,6 +138,7 @@ class DeviceRequestedFeatures { /* BVH/sampling kernel features. */ bool use_hair; bool use_hair_thick; + bool use_pointcloud; bool use_object_motion; bool use_camera_motion; @@ -184,6 +185,7 @@ class DeviceRequestedFeatures { nodes_features = 0; use_hair = false; use_hair_thick = false; + use_pointcloud = false; use_object_motion = false; use_camera_motion = false; use_baking = false; @@ -206,6 +208,7 @@ class DeviceRequestedFeatures { nodes_features == requested_features.nodes_features && use_hair == requested_features.use_hair && use_hair_thick == requested_features.use_hair_thick && + use_pointcloud == requested_features.use_pointcloud && use_object_motion == requested_features.use_object_motion && use_camera_motion == requested_features.use_camera_motion && use_baking == requested_features.use_baking && @@ -236,6 +239,9 @@ class DeviceRequestedFeatures { if (!use_hair) { build_options += " -D__NO_HAIR__"; } + if (!use_pointcloud) { + build_options += " -D__NO_POINTS_"; + } if (!use_object_motion) { build_options += " -D__NO_OBJECT_MOTION__"; } diff --git a/intern/cycles/device/opencl/device_opencl_impl.cpp b/intern/cycles/device/opencl/device_opencl_impl.cpp index f0683d1..a254d52 100644 --- a/intern/cycles/device/opencl/device_opencl_impl.cpp +++ b/intern/cycles/device/opencl/device_opencl_impl.cpp @@ -100,6 +100,7 @@ void OpenCLDevice::enable_default_features(DeviceRequestedFeatures &features) features.max_nodes_group = NODE_GROUP_LEVEL_MAX; features.nodes_features = NODE_FEATURE_ALL; features.use_hair = true; + features.use_pointcloud = true; features.use_subsurface = true; features.use_camera_motion = false; features.use_object_motion = false; @@ -124,6 +125,7 @@ string OpenCLDevice::get_build_options(const DeviceRequestedFeatures &requested_ features.use_object_motion = false; features.use_camera_motion = false; features.use_hair = true; + features.use_pointcloud = true; features.use_subsurface = true; features.max_nodes_group = NODE_GROUP_LEVEL_MAX; features.nodes_features = NODE_FEATURE_ALL; @@ -188,6 +190,7 @@ string OpenCLDevice::get_build_options(const DeviceRequestedFeatures &requested_ if (preview_kernel) { DeviceRequestedFeatures preview_features; preview_features.use_hair = true; + preview_features.use_pointcloud = true; build_options += "-D__KERNEL_AO_PREVIEW__ "; build_options += preview_features.get_build_options(); } diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt index db14622..a921676 100644 --- a/intern/cycles/kernel/CMakeLists.txt +++ b/intern/cycles/kernel/CMakeLists.txt @@ -238,11 +238,14 @@ set(SRC_GEOM_HEADERS geom/geom_curve.h geom/geom_curve_intersect.h geom/geom_motion_curve.h + geom/geom_motion_point.h geom/geom_motion_triangle.h geom/geom_motion_triangle_intersect.h geom/geom_motion_triangle_shader.h geom/geom_object.h geom/geom_patch.h + geom/geom_point.h + geom/geom_point_intersect.h geom/geom_primitive.h geom/geom_subd_triangle.h geom/geom_triangle.h diff --git a/intern/cycles/kernel/bvh/bvh.h b/intern/cycles/kernel/bvh/bvh.h index 3049f24..4aac66e 100644 --- a/intern/cycles/kernel/bvh/bvh.h +++ b/intern/cycles/kernel/bvh/bvh.h @@ -216,8 +216,9 @@ ccl_device_intersect bool scene_intersect(KernelGlobals *kg, # ifdef __OBJECT_MOTION__ if (kernel_data.bvh.have_motion) { + // TODO: check __POINTCLOUD__ along with __HAIR__ # ifdef __HAIR__ - if (kernel_data.bvh.have_curves) { + if (kernel_data.bvh.have_curves_or_points) { return bvh_intersect_hair_motion(kg, ray, isect, visibility); } # endif /* __HAIR__ */ @@ -227,7 +228,7 @@ ccl_device_intersect bool scene_intersect(KernelGlobals *kg, # endif /* __OBJECT_MOTION__ */ # ifdef __HAIR__ - if (kernel_data.bvh.have_curves) { + if (kernel_data.bvh.have_curves_or_points) { return bvh_intersect_hair(kg, ray, isect, visibility); } # endif /* __HAIR__ */ @@ -417,7 +418,7 @@ ccl_device_intersect bool scene_intersect_shadow_all(KernelGlobals *kg, # ifdef __OBJECT_MOTION__ if (kernel_data.bvh.have_motion) { # ifdef __HAIR__ - if (kernel_data.bvh.have_curves) { + if (kernel_data.bvh.have_curves_or_points) { return bvh_intersect_shadow_all_hair_motion(kg, ray, isect, visibility, max_hits, num_hits); } # endif /* __HAIR__ */ @@ -427,7 +428,7 @@ ccl_device_intersect bool scene_intersect_shadow_all(KernelGlobals *kg, # endif /* __OBJECT_MOTION__ */ # ifdef __HAIR__ - if (kernel_data.bvh.have_curves) { + if (kernel_data.bvh.have_curves_or_points) { return bvh_intersect_shadow_all_hair(kg, ray, isect, visibility, max_hits, num_hits); } # endif /* __HAIR__ */ diff --git a/intern/cycles/kernel/bvh/bvh_embree.h b/intern/cycles/kernel/bvh/bvh_embree.h index ca63728..9dd1608 100644 --- a/intern/cycles/kernel/bvh/bvh_embree.h +++ b/intern/cycles/kernel/bvh/bvh_embree.h @@ -122,6 +122,10 @@ ccl_device_inline void kernel_embree_convert_hit(KernelGlobals *kg, isect->object = OBJECT_NONE; } isect->type = kernel_tex_fetch(__prim_type, isect->prim); + + if (isect->type == 0) { + abort(); + } } ccl_device_inline void kernel_embree_convert_sss_hit(KernelGlobals *kg, diff --git a/intern/cycles/kernel/bvh/bvh_shadow_all.h b/intern/cycles/kernel/bvh/bvh_shadow_all.h index dccd257..b29e752 100644 --- a/intern/cycles/kernel/bvh/bvh_shadow_all.h +++ b/intern/cycles/kernel/bvh/bvh_shadow_all.h @@ -167,6 +167,14 @@ ccl_device_inline kg, isect_array, P, dir, visibility, object, prim_addr, ray->time, curve_type); break; } + /* TODO: record front and back */ + case PRIMITIVE_POINT: + hit = point_intersect(kg, isect_array, P, dir, visibility, object, prim_addr); + break; + case PRIMITIVE_MOTION_POINT: + hit = point_intersect_motion( + kg, isect_array, P, dir, visibility, object, prim_addr, ray->time); + break; #endif default: { hit = false; diff --git a/intern/cycles/kernel/bvh/bvh_traversal.h b/intern/cycles/kernel/bvh/bvh_traversal.h index 8b2699a..064fa71 100644 --- a/intern/cycles/kernel/bvh/bvh_traversal.h +++ b/intern/cycles/kernel/bvh/bvh_traversal.h @@ -28,6 +28,7 @@ * without new features slowing things down. * * BVH_HAIR: hair curve rendering + * BVH_POINTCLOUD: point cloud rendering * BVH_MOTION: motion blur rendering */ @@ -182,6 +183,26 @@ ccl_device_noinline bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, } break; } + case PRIMITIVE_POINT: + case PRIMITIVE_MOTION_POINT: { + for (; prim_addr < prim_addr2; prim_addr++) { + BVH_DEBUG_NEXT_INTERSECTION(); + bool hit; + if (type == PRIMITIVE_POINT) { + hit = point_intersect(kg, isect, P, dir, visibility, object, prim_addr); + } + else { + hit = point_intersect_motion( + kg, isect, P, dir, visibility, object, prim_addr, ray->time); + } + if (hit) { + /* shadow ray early termination */ + if (visibility & PATH_RAY_SHADOW_OPAQUE) + return true; + } + } + break; + } #endif /* BVH_FEATURE(BVH_HAIR) */ } } diff --git a/intern/cycles/kernel/geom/geom.h b/intern/cycles/kernel/geom/geom.h index 5ff4d5f..29268c5 100644 --- a/intern/cycles/kernel/geom/geom.h +++ b/intern/cycles/kernel/geom/geom.h @@ -29,6 +29,9 @@ #include "kernel/geom/geom_motion_curve.h" #include "kernel/geom/geom_curve.h" #include "kernel/geom/geom_curve_intersect.h" +#include "kernel/geom/geom_motion_point.h" +#include "kernel/geom/geom_point.h" +#include "kernel/geom/geom_point_intersect.h" #include "kernel/geom/geom_volume.h" #include "kernel/geom/geom_primitive.h" // clang-format on diff --git a/intern/cycles/kernel/geom/geom_motion_point.h b/intern/cycles/kernel/geom/geom_motion_point.h new file mode 100644 index 0000000..c4ba0b9 --- /dev/null +++ b/intern/cycles/kernel/geom/geom_motion_point.h @@ -0,0 +1,43 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +CCL_NAMESPACE_BEGIN + +/* Motion Point Primitive + * + * These are stored as regular points, plus extra positions and radii at times + * other than the frame center. Computing the point at a given ray time is + * a matter of interpolation of the two steps between which the ray time lies. + * + * The extra points are stored as ATTR_STD_MOTION_VERTEX_POSITION. + */ + +#ifdef __POINTCLOUD__ + +/* TODO: implement */ +ccl_device_forceinline bool point_intersect_motion(KernelGlobals *kg, + Intersection *isect, + float3 P, + float3 dir, + uint visibility, + int object, + int prim_addr, + float time) +{ + return false; +} + +#endif + +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/geom/geom_point.h b/intern/cycles/kernel/geom/geom_point.h new file mode 100644 index 0000000..7d51718 --- /dev/null +++ b/intern/cycles/kernel/geom/geom_point.h @@ -0,0 +1,109 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +CCL_NAMESPACE_BEGIN + +/* Point Primitive + * + * Point primitive for rendering point clouds. + */ + +#ifdef __POINTCLOUD__ + +/* Reading attributes on various point elements */ + +ccl_device float point_attribute_float( + KernelGlobals *kg, const ShaderData *sd, const AttributeDescriptor desc, float *dx, float *dy) +{ +# ifdef __RAY_DIFFERENTIALS__ + if (dx) + *dx = 0.0f; + if (dy) + *dy = 0.0f; +# endif + + /* TODO: merge ATTR_ELEMENT_PRIM for all? */ + if (desc.element == ATTR_ELEMENT_VERTEX) { + return kernel_tex_fetch(__attributes_float, desc.offset + sd->prim); + } + else { + return 0.0f; + } +} + +ccl_device float2 point_attribute_float2(KernelGlobals *kg, + const ShaderData *sd, + const AttributeDescriptor desc, + float2 *dx, + float2 *dy) +{ +# ifdef __RAY_DIFFERENTIALS__ + if (dx) + *dx = make_float2(0.0f, 0.0f); + if (dy) + *dy = make_float2(0.0f, 0.0f); +# endif + + if (desc.element == ATTR_ELEMENT_VERTEX) { + return kernel_tex_fetch(__attributes_float2, desc.offset + sd->prim); + } + else { + return make_float2(0.0f, 0.0f); + } +} + +ccl_device float3 point_attribute_float3(KernelGlobals *kg, + const ShaderData *sd, + const AttributeDescriptor desc, + float3 *dx, + float3 *dy) +{ +# ifdef __RAY_DIFFERENTIALS__ + if (dx) + *dx = make_float3(0.0f, 0.0f, 0.0f); + if (dy) + *dy = make_float3(0.0f, 0.0f, 0.0f); +# endif + + if (desc.element == ATTR_ELEMENT_VERTEX) { + return float4_to_float3(kernel_tex_fetch(__attributes_float3, desc.offset + sd->prim)); + } + else { + return make_float3(0.0f, 0.0f, 0.0f); + } +} + +/* Point radius */ + +ccl_device float point_radius(KernelGlobals *kg, ShaderData *sd) +{ + if (sd->type & PRIMITIVE_ALL_POINT) { + return kernel_tex_fetch(__points, sd->prim).w; + } + + return 0.0f; +} + +/* Point location for motion pass, linear interpolation between keys and + * ignoring radius because we do the same for the motion keys */ + +ccl_device float3 point_motion_center_location(KernelGlobals *kg, ShaderData *sd) +{ + /* TODO */ + return make_float3(0.0f, 0.0f, 0.0f); +} + +#endif /* __POINTCLOUD__ */ + +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/geom/geom_point_intersect.h b/intern/cycles/kernel/geom/geom_point_intersect.h new file mode 100644 index 0000000..d354728 --- /dev/null +++ b/intern/cycles/kernel/geom/geom_point_intersect.h @@ -0,0 +1,184 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Based on Embree code, copyright 2009-2020 Intel Corporation. + */ + +CCL_NAMESPACE_BEGIN + +/* Point primitive intersection functions. */ + +#ifdef __POINTCLOUD__ + +ccl_device_forceinline bool point_intersect_test(const float4 point, + const float3 P, + const float3 dir, + float *t) +{ + const float3 center = float4_to_float3(point); + const float radius = point.w; + + const float rd2 = 1.0f / dot(dir, dir); + + const float3 c0 = center - P; + const float projC0 = dot(c0, dir) * rd2; + const float3 perp = c0 - projC0 * dir; + const float l2 = dot(perp, perp); + const float r2 = radius * radius; + if (!(l2 <= r2)) { + return false; + } + + const float td = sqrt((r2 - l2) * rd2); + const float t_front = projC0 - td; + const float t_back = projC0 + td; + + const bool valid_front = (0.0f <= t_front) & (t_front <= *t); + const bool valid_back = (0.0f <= t_back) & (t_back <= *t); + + /* check if there is a first hit */ + const bool valid_first = valid_front | valid_back; + if (!valid_first) { + return false; + } + + *t = (valid_front) ? t_front : t_back; + return true; +} + +ccl_device_forceinline void point_intersect_refine( + const float4 point, const float3 P, const float3 dir, float *t, float3 *Ng) +{ + const float3 center = float4_to_float3(point); + const float radius = point.w; + + const float rd2 = 1.0f / dot(dir, dir); + + const float3 c0 = center - P; + const float projC0 = dot(c0, dir) * rd2; + const float3 perp = c0 - projC0 * dir; + const float l2 = dot(perp, perp); + const float r2 = radius * radius; + + const float td = sqrt(fmaxf(r2 - l2, 0.0f) * rd2); + const float t_front = projC0 - td; + const float t_back = projC0 + td; + + /* TODO: how to do stable side selection? */ + const bool valid_front = true; + + *t = (valid_front) ? t_front : t_back; + *Ng = ((valid_front) ? -td : td) * dir - perp; +} + +ccl_device_forceinline bool point_intersect(KernelGlobals *kg, + Intersection *isect, + float3 P, + float3 dir, + uint visibility, + int object, + int prim_addr) +{ + const int prim = kernel_tex_fetch(__prim_index, prim_addr); + const float4 point = kernel_tex_fetch(__points, prim); + + float t = isect->t; + if (!point_intersect_test(point, P, dir, &t)) { + return false; + } + +# ifdef __VISIBILITY_FLAG__ + /* Visibility flag test. we do it here under the assumption + * that most points are culled by node flags. + */ + if (!(kernel_tex_fetch(__prim_visibility, prim_addr) & visibility)) { + return false; + } +# endif + + isect->prim = prim_addr; + isect->object = object; + isect->type = PRIMITIVE_POINT; + isect->u = 0.0f; + isect->v = 0.0f; + isect->t = t; + return true; + + // TODO: integrate into BVH +} + +/* TODO: check if assumptions here match triangle or curve */ +ccl_device_inline float3 point_refine(KernelGlobals *kg, + ShaderData *sd, + const Intersection *isect, + const Ray *ray) +{ + /* TODO: dedup object transform with other prims? */ + /* TODO: implement and integrate into BVH */ + float t = isect->t; + float3 P = ray->P; + float3 D = ray->D; + + if (isect->object != OBJECT_NONE) { +# ifdef __OBJECT_MOTION__ + Transform tfm = sd->ob_itfm; +# else + Transform tfm = object_fetch_transform(kg, isect->object, OBJECT_INVERSE_TRANSFORM); +# endif + + P = transform_point(&tfm, P); + D = transform_direction(&tfm, D * t); + D = normalize_len(D, &t); + } + + int prim = kernel_tex_fetch(__prim_index, isect->prim); + float4 point = kernel_tex_fetch(__points, prim); + + P = P + D * t; + + /* TODO: needed? */ + point_intersect_refine(point, P, D, &t, &sd->Ng); + + P = P + D * t; + + // TODO: compute +# ifdef __UV__ + sd->u = 0.0f; + sd->v = 0.0f; +# endif + + sd->N = sd->Ng; + + // TODO: compute +# ifdef __DPDU__ + /* dPdu/dPdv */ + sd->dPdu = make_float3(0.0f, 0.0f, 0.0f); + sd->dPdv = make_float3(0.0f, 0.0f, 0.0f); +# endif + + if (isect->object != OBJECT_NONE) { +# ifdef __OBJECT_MOTION__ + Transform tfm = sd->ob_tfm; +# else + Transform tfm = object_fetch_transform(kg, isect->object, OBJECT_TRANSFORM); +# endif + + P = transform_point(&tfm, P); + } + + return P; +} + +#endif + +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/geom/geom_primitive.h b/intern/cycles/kernel/geom/geom_primitive.h index 997abf4..7c8f62a 100644 --- a/intern/cycles/kernel/geom/geom_primitive.h +++ b/intern/cycles/kernel/geom/geom_primitive.h @@ -36,6 +36,12 @@ ccl_device_inline float primitive_attribute_float( return curve_attribute_float(kg, sd, desc, dx, dy); } #endif +#ifdef __POINTCLOUD__ + else if (sd->type & PRIMITIVE_ALL_POINT) { + /* TODO: unify */ + return point_attribute_float(kg, sd, desc, dx, dy); + } +#endif #ifdef __VOLUME__ else if (sd->object != OBJECT_NONE && desc.element == ATTR_ELEMENT_VOXEL) { if (dx) @@ -54,6 +60,7 @@ ccl_device_inline float primitive_attribute_float( } } +/* TODO: why separate? */ ccl_device_inline float primitive_surface_attribute_float( KernelGlobals *kg, const ShaderData *sd, const AttributeDescriptor desc, float *dx, float *dy) { @@ -67,6 +74,12 @@ ccl_device_inline float primitive_surface_attribute_float( else if (sd->type & PRIMITIVE_ALL_CURVE) { return curve_attribute_float(kg, sd, desc, dx, dy); } +#endif +#ifdef __POINTCLOUD__ + else if (sd->type & PRIMITIVE_ALL_POINT) { + /* TODO: unify */ + return point_attribute_float(kg, sd, desc, dx, dy); + } #endif else { if (dx) @@ -108,6 +121,12 @@ ccl_device_inline float2 primitive_attribute_float2(KernelGlobals *kg, return curve_attribute_float2(kg, sd, desc, dx, dy); } #endif +#ifdef __POINTCLOUD__ + else if (sd->type & PRIMITIVE_ALL_POINT) { + /* TODO: unify */ + return point_attribute_float2(kg, sd, desc, dx, dy); + } +#endif #ifdef __VOLUME__ else if (sd->object != OBJECT_NONE && desc.element == ATTR_ELEMENT_VOXEL) { kernel_assert(0); @@ -144,6 +163,12 @@ ccl_device_inline float3 primitive_attribute_float3(KernelGlobals *kg, return curve_attribute_float3(kg, sd, desc, dx, dy); } #endif +#ifdef __POINTCLOUD__ + else if (sd->type & PRIMITIVE_ALL_POINT) { + /* TODO: unify */ + return point_attribute_float3(kg, sd, desc, dx, dy); + } +#endif #ifdef __VOLUME__ else if (sd->object != OBJECT_NONE && desc.element == ATTR_ELEMENT_VOXEL) { if (dx) @@ -204,6 +229,12 @@ ccl_device_inline float2 primitive_surface_attribute_float2(KernelGlobals *kg, else if (sd->type & PRIMITIVE_ALL_CURVE) { return curve_attribute_float2(kg, sd, desc, dx, dy); } +#endif +#ifdef __POINTCLOUD__ + else if (sd->type & PRIMITIVE_ALL_POINT) { + /* TODO: unify */ + return point_attribute_float2(kg, sd, desc, dx, dy); + } #endif else { if (dx) @@ -230,6 +261,12 @@ ccl_device_inline float3 primitive_surface_attribute_float3(KernelGlobals *kg, else if (sd->type & PRIMITIVE_ALL_CURVE) { return curve_attribute_float3(kg, sd, desc, dx, dy); } +#endif +#ifdef __POINTCLOUD__ + else if (sd->type & PRIMITIVE_ALL_POINT) { + /* TODO: unify */ + return point_attribute_float3(kg, sd, desc, dx, dy); + } #endif else { if (dx) @@ -291,8 +328,8 @@ ccl_device bool primitive_ptex(KernelGlobals *kg, ShaderData *sd, float2 *uv, in ccl_device float3 primitive_tangent(KernelGlobals *kg, ShaderData *sd) { -#ifdef __HAIR__ - if (sd->type & PRIMITIVE_ALL_CURVE) +#if defined(__HAIR__) || defined(__POINTCLOUD__) + if (sd->type & (PRIMITIVE_ALL_CURVE | PRIMITIVE_ALL_POINT)) # ifdef __DPDU__ return normalize(sd->dPdu); # else @@ -326,6 +363,7 @@ ccl_device_inline float4 primitive_motion_vector(KernelGlobals *kg, ShaderData * /* center position */ float3 center; + /* TODO: point */ #ifdef __HAIR__ bool is_curve_primitive = sd->type & PRIMITIVE_ALL_CURVE; if (is_curve_primitive) { diff --git a/intern/cycles/kernel/kernel_shader.h b/intern/cycles/kernel/kernel_shader.h index e461e164..83f07eb 100644 --- a/intern/cycles/kernel/kernel_shader.h +++ b/intern/cycles/kernel/kernel_shader.h @@ -89,6 +89,14 @@ ccl_device_noinline curve_shader_setup(kg, sd, isect, ray); } else +#endif +#ifdef __POINTCLOUD__ + if (sd->type & PRIMITIVE_ALL_POINT) { + /* point */ + sd->shader = kernel_tex_fetch(__points_shader, sd->prim); + sd->P = point_refine(kg, sd, isect, ray); + } + else #endif if (sd->type & PRIMITIVE_TRIANGLE) { /* static triangle */ @@ -1343,17 +1351,24 @@ ccl_device bool shader_transparent_shadow(KernelGlobals *kg, Intersection *isect int prim = kernel_tex_fetch(__prim_index, isect->prim); int shader = 0; + /* TODO: dedup shader fetch? */ # ifdef __HAIR__ - if (isect->type & PRIMITIVE_ALL_TRIANGLE) { -# endif - shader = kernel_tex_fetch(__tri_shader, prim); -# ifdef __HAIR__ - } - else { + if (isect->type & PRIMITIVE_ALL_CURVE) { float4 str = kernel_tex_fetch(__curves, prim); shader = __float_as_int(str.z); } + else +# endif +# ifdef __POINTCLOUD__ + if (isect->type & PRIMITIVE_ALL_POINT) { + shader = kernel_tex_fetch(__points_shader, prim); + } + else # endif + { + shader = kernel_tex_fetch(__tri_shader, prim); + } + int flag = kernel_tex_fetch(__shaders, (shader & SHADER_MASK)).flags; return (flag & SD_HAS_TRANSPARENT_SHADOW) != 0; diff --git a/intern/cycles/kernel/kernel_textures.h b/intern/cycles/kernel/kernel_textures.h index c8e0167..ab50d39 100644 --- a/intern/cycles/kernel/kernel_textures.h +++ b/intern/cycles/kernel/kernel_textures.h @@ -47,12 +47,16 @@ KERNEL_TEX(uint4, __tri_vindex) KERNEL_TEX(uint, __tri_patch) KERNEL_TEX(float2, __tri_patch_uv) +/* patches */ +KERNEL_TEX(uint, __patches) + /* curves */ KERNEL_TEX(float4, __curves) KERNEL_TEX(float4, __curve_keys) -/* patches */ -KERNEL_TEX(uint, __patches) +/* curves */ +KERNEL_TEX(float4, __points) +KERNEL_TEX(uint, __points_shader) /* attributes */ KERNEL_TEX(uint4, __attributes_map) diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h index fc9cc73..d5ecec2 100644 --- a/intern/cycles/kernel/kernel_types.h +++ b/intern/cycles/kernel/kernel_types.h @@ -99,6 +99,7 @@ CCL_NAMESPACE_BEGIN #define __AO__ #define __PASSES__ #define __HAIR__ +#define __POINTCLOUD__ /* Without these we get an AO render, used by OpenCL preview kernel. */ #ifndef __KERNEL_AO_PREVIEW__ @@ -156,6 +157,9 @@ CCL_NAMESPACE_BEGIN #ifdef __NO_HAIR__ # undef __HAIR__ #endif +#ifdef __NO_POINTCLOUD__ +# undef __POINTCLOUD__ +#endif #ifdef __NO_VOLUME__ # undef __VOLUME__ # undef __VOLUME_SCATTER__ @@ -695,22 +699,25 @@ typedef enum PrimitiveType { PRIMITIVE_MOTION_CURVE_THICK = (1 << 3), PRIMITIVE_CURVE_RIBBON = (1 << 4), PRIMITIVE_MOTION_CURVE_RIBBON = (1 << 5), + PRIMITIVE_POINT = (1 << 6), + PRIMITIVE_MOTION_POINT = (1 << 7), /* Lamp primitive is not included below on purpose, * since it is no real traceable primitive. */ - PRIMITIVE_LAMP = (1 << 6), + PRIMITIVE_LAMP = (1 << 8), PRIMITIVE_ALL_TRIANGLE = (PRIMITIVE_TRIANGLE | PRIMITIVE_MOTION_TRIANGLE), PRIMITIVE_ALL_CURVE = (PRIMITIVE_CURVE_THICK | PRIMITIVE_MOTION_CURVE_THICK | PRIMITIVE_CURVE_RIBBON | PRIMITIVE_MOTION_CURVE_RIBBON), + PRIMITIVE_ALL_POINT = (PRIMITIVE_POINT | PRIMITIVE_MOTION_POINT), PRIMITIVE_ALL_MOTION = (PRIMITIVE_MOTION_TRIANGLE | PRIMITIVE_MOTION_CURVE_THICK | - PRIMITIVE_MOTION_CURVE_RIBBON), - PRIMITIVE_ALL = (PRIMITIVE_ALL_TRIANGLE | PRIMITIVE_ALL_CURVE), + PRIMITIVE_MOTION_CURVE_RIBBON | PRIMITIVE_MOTION_POINT), + PRIMITIVE_ALL = (PRIMITIVE_ALL_TRIANGLE | PRIMITIVE_ALL_CURVE | PRIMITIVE_ALL_POINT), /* Total number of different traceable primitives. * NOTE: This is an actual value, not a bitflag. */ - PRIMITIVE_NUM_TOTAL = 6, + PRIMITIVE_NUM_TOTAL = 8, } PrimitiveType; #define PRIMITIVE_PACK_SEGMENT(type, segment) ((segment << PRIMITIVE_NUM_TOTAL) | (type)) @@ -764,6 +771,7 @@ typedef enum AttributeStandard { ATTR_STD_PARTICLE, ATTR_STD_CURVE_INTERCEPT, ATTR_STD_CURVE_RANDOM, + ATTR_STD_POINT_RANDOM, ATTR_STD_PTEX_FACE_ID, ATTR_STD_PTEX_UV, ATTR_STD_VOLUME_DENSITY, @@ -1409,7 +1417,7 @@ typedef struct KernelBVH { /* Own BVH */ int root; int have_motion; - int have_curves; + int have_curves_or_points; int bvh_layout; int use_bvh_steps; int curve_subdivisions; diff --git a/intern/cycles/kernel/osl/osl_services.cpp b/intern/cycles/kernel/osl/osl_services.cpp index aee1e3a..5603eaa 100644 --- a/intern/cycles/kernel/osl/osl_services.cpp +++ b/intern/cycles/kernel/osl/osl_services.cpp @@ -109,6 +109,8 @@ ustring OSLRenderServices::u_is_curve("geom:is_curve"); ustring OSLRenderServices::u_curve_thickness("geom:curve_thickness"); ustring OSLRenderServices::u_curve_tangent_normal("geom:curve_tangent_normal"); ustring OSLRenderServices::u_curve_random("geom:curve_random"); +ustring OSLRenderServices::u_is_point("geom:is_point"); +ustring OSLRenderServices::u_point_radius("geom:point_radius"); ustring OSLRenderServices::u_path_ray_length("path:ray_length"); ustring OSLRenderServices::u_path_ray_depth("path:ray_depth"); ustring OSLRenderServices::u_path_diffuse_depth("path:diffuse_depth"); @@ -854,6 +856,14 @@ bool OSLRenderServices::get_object_standard_attribute( float3 f = curve_tangent_normal(kg, sd); return set_attribute_float3(f, type, derivatives, val); } + else if (name == u_is_point) { + float f = (sd->type & PRIMITIVE_ALL_POINT) != 0; + return set_attribute_float(f, type, derivatives, val); + } + else if (name == u_point_radius) { + float f = point_radius(kg, sd); + return set_attribute_float(f, type, derivatives, val); + } else return false; } diff --git a/intern/cycles/kernel/osl/osl_services.h b/intern/cycles/kernel/osl/osl_services.h index 894d6e4..9fa391d 100644 --- a/intern/cycles/kernel/osl/osl_services.h +++ b/intern/cycles/kernel/osl/osl_services.h @@ -287,6 +287,8 @@ class OSLRenderServices : public OSL::RendererServices { static ustring u_curve_thickness; static ustring u_curve_tangent_normal; static ustring u_curve_random; + static ustring u_is_point; + static ustring u_point_radius; static ustring u_path_ray_length; static ustring u_path_ray_depth; static ustring u_path_diffuse_depth; diff --git a/intern/cycles/kernel/svm/svm_geometry.h b/intern/cycles/kernel/svm/svm_geometry.h index 77df19b..c411bfd 100644 --- a/intern/cycles/kernel/svm/svm_geometry.h +++ b/intern/cycles/kernel/svm/svm_geometry.h @@ -195,6 +195,7 @@ ccl_device void svm_node_particle_info( } } +/* TODO: add point info? */ #ifdef __HAIR__ /* Hair Info */ diff --git a/intern/cycles/kernel/svm/svm_wireframe.h b/intern/cycles/kernel/svm/svm_wireframe.h index 49158bd..6b8f402 100644 --- a/intern/cycles/kernel/svm/svm_wireframe.h +++ b/intern/cycles/kernel/svm/svm_wireframe.h @@ -37,7 +37,7 @@ CCL_NAMESPACE_BEGIN ccl_device_inline float wireframe( KernelGlobals *kg, ShaderData *sd, float size, int pixel_size, float3 *P) { -#ifdef __HAIR__ +#if defined(__HAIR__) || defined(__POINTCLOUD__) if (sd->prim != PRIM_NONE && sd->type & PRIMITIVE_ALL_TRIANGLE) #else if (sd->prim != PRIM_NONE) diff --git a/intern/cycles/render/CMakeLists.txt b/intern/cycles/render/CMakeLists.txt index 46d9b50..1bbd92b 100644 --- a/intern/cycles/render/CMakeLists.txt +++ b/intern/cycles/render/CMakeLists.txt @@ -18,6 +18,7 @@ set(SRC colorspace.cpp constant_fold.cpp coverage.cpp + curves.cpp denoising.cpp film.cpp geometry.cpp @@ -38,7 +39,7 @@ set(SRC object.cpp osl.cpp particles.cpp - curves.cpp + pointcloud.cpp scene.cpp session.cpp shader.cpp @@ -59,6 +60,7 @@ set(SRC_HEADERS colorspace.h constant_fold.h coverage.h + curves.h denoising.h film.h geometry.h @@ -77,7 +79,7 @@ set(SRC_HEADERS object.h osl.h particles.h - curves.h + pointcloud.h scene.h session.h shader.h diff --git a/intern/cycles/render/attribute.cpp b/intern/cycles/render/attribute.cpp index cdef103..5108a8e 100644 --- a/intern/cycles/render/attribute.cpp +++ b/intern/cycles/render/attribute.cpp @@ -18,6 +18,7 @@ #include "render/hair.h" #include "render/image.h" #include "render/mesh.h" +#include "render/pointcloud.h" #include "util/util_foreach.h" #include "util/util_transform.h" @@ -174,6 +175,10 @@ size_t Attribute::element_size(Geometry *geom, AttributePrimitive prim) const size -= mesh->num_subd_verts; } } + else if (geom->type == Geometry::POINTCLOUD) { + PointCloud *pointcloud = static_cast(geom); + size = pointcloud->num_points(); + } break; case ATTR_ELEMENT_VERTEX_MOTION: if (geom->type == Geometry::MESH) { @@ -183,6 +188,10 @@ size_t Attribute::element_size(Geometry *geom, AttributePrimitive prim) const size -= mesh->num_subd_verts * (mesh->motion_steps - 1); } } + else if (geom->type == Geometry::POINTCLOUD) { + PointCloud *pointcloud = static_cast(geom); + size = pointcloud->num_points() * (pointcloud->motion_steps - 1); + } break; case ATTR_ELEMENT_FACE: if (geom->type == Geometry::MESH || geom->type == Geometry::VOLUME) { @@ -311,6 +320,8 @@ const char *Attribute::standard_name(AttributeStandard std) return "curve_intercept"; case ATTR_STD_CURVE_RANDOM: return "curve_random"; + case ATTR_STD_POINT_RANDOM: + return "point_random"; case ATTR_STD_PTEX_FACE_ID: return "ptex_face_id"; case ATTR_STD_PTEX_UV: @@ -552,6 +563,28 @@ Attribute *AttributeSet::add(AttributeStandard std, ustring name) break; } } + else if (geometry->type == Geometry::POINTCLOUD) { + switch (std) { + case ATTR_STD_UV: + attr = add(name, TypeFloat2, ATTR_ELEMENT_VERTEX); + break; + case ATTR_STD_GENERATED: + attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_VERTEX); + break; + case ATTR_STD_MOTION_VERTEX_POSITION: + attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_VERTEX_MOTION); + break; + case ATTR_STD_POINT_RANDOM: + attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_VERTEX); + break; + case ATTR_STD_GENERATED_TRANSFORM: + attr = add(name, TypeDesc::TypeMatrix, ATTR_ELEMENT_MESH); + break; + default: + assert(0); + break; + } + } attr->std = std; diff --git a/intern/cycles/render/geometry.cpp b/intern/cycles/render/geometry.cpp index 894adaf..51eab93 100644 --- a/intern/cycles/render/geometry.cpp +++ b/intern/cycles/render/geometry.cpp @@ -28,6 +28,7 @@ #include "render/mesh.h" #include "render/nodes.h" #include "render/object.h" +#include "render/pointcloud.h" #include "render/scene.h" #include "render/shader.h" #include "render/stats.h" @@ -207,10 +208,12 @@ void Geometry::compute_bvh( BVHParams bparams; bparams.use_spatial_split = params->use_bvh_spatial_split; bparams.bvh_layout = bvh_layout; - bparams.use_unaligned_nodes = dscene->data.bvh.have_curves && - params->use_bvh_unaligned_nodes; + bparams.use_unaligned_nodes = + dscene->data.bvh.have_curves_or_points && // TODO: not for points + params->use_bvh_unaligned_nodes; bparams.num_motion_triangle_steps = params->num_bvh_time_steps; bparams.num_motion_curve_steps = params->num_bvh_time_steps; + bparams.num_motion_point_steps = params->num_bvh_time_steps; bparams.bvh_type = params->bvh_type; bparams.curve_subdivisions = params->curve_subdivisions(); @@ -622,6 +625,12 @@ static void update_attribute_element_offset(Geometry *geom, else if (element == ATTR_ELEMENT_CURVE_KEY_MOTION) offset -= hair->curvekey_offset; } + else if (geom->type == Geometry::POINTCLOUD) { + if (element == ATTR_ELEMENT_VERTEX) + offset -= geom->prim_offset; + else if (element == ATTR_ELEMENT_VERTEX_MOTION) + offset -= geom->prim_offset; + } } else { /* attribute not found */ @@ -790,6 +799,8 @@ void GeometryManager::mesh_calc_offset(Scene *scene) size_t curve_key_size = 0; size_t curve_size = 0; + size_t point_size = 0; + size_t patch_size = 0; size_t face_size = 0; size_t corner_size = 0; @@ -839,6 +850,16 @@ void GeometryManager::mesh_calc_offset(Scene *scene) hair->optix_prim_offset = optix_prim_size; optix_prim_size += hair->num_segments(); } + else if (geom->type == Geometry::POINTCLOUD) { + PointCloud *pointcloud = static_cast(geom); + + pointcloud->prim_offset = point_size; + + point_size += pointcloud->num_points(); + + pointcloud->optix_prim_offset = optix_prim_size; + optix_prim_size += pointcloud->num_points(); + } } } @@ -852,6 +873,8 @@ void GeometryManager::device_update_mesh( size_t curve_key_size = 0; size_t curve_size = 0; + size_t point_size = 0; + size_t patch_size = 0; foreach (Geometry *geom, scene->geometry) { @@ -874,10 +897,13 @@ void GeometryManager::device_update_mesh( } else if (geom->type == Geometry::HAIR) { Hair *hair = static_cast(geom); - curve_key_size += hair->curve_keys.size(); curve_size += hair->num_curves(); } + else if (geom->type == Geometry::POINTCLOUD) { + PointCloud *pointcloud = static_cast(geom); + point_size += pointcloud->num_points(); + } } /* Create mapping from triangle to primitive triangle array. */ @@ -964,6 +990,26 @@ void GeometryManager::device_update_mesh( dscene->curves.copy_to_device(); } + if (point_size != 0) { + progress.set_status("Updating Mesh", "Copying Strands to device"); + + float4 *points = dscene->points.alloc(point_size); + uint *points_shader = dscene->points_shader.alloc(point_size); + + foreach (Geometry *geom, scene->geometry) { + if (geom->type == Geometry::POINTCLOUD) { + PointCloud *pointcloud = static_cast(geom); + pointcloud->pack( + scene, &points[pointcloud->prim_offset], &points_shader[pointcloud->prim_offset]); + if (progress.get_cancel()) + return; + } + } + + dscene->points.copy_to_device(); + dscene->points_shader.copy_to_device(); + } + if (patch_size != 0) { progress.set_status("Updating Mesh", "Copying Patches to device"); @@ -1021,10 +1067,11 @@ void GeometryManager::device_update_bvh(Device *device, bparams.bvh_layout = BVHParams::best_bvh_layout(scene->params.bvh_layout, device->get_bvh_layout_mask()); bparams.use_spatial_split = scene->params.use_bvh_spatial_split; - bparams.use_unaligned_nodes = dscene->data.bvh.have_curves && + bparams.use_unaligned_nodes = dscene->data.bvh.have_curves_or_points && // TODO: not for points! scene->params.use_bvh_unaligned_nodes; bparams.num_motion_triangle_steps = scene->params.num_bvh_time_steps; bparams.num_motion_curve_steps = scene->params.num_bvh_time_steps; + bparams.num_motion_point_steps = scene->params.num_bvh_time_steps; bparams.bvh_type = scene->params.bvh_type; bparams.curve_subdivisions = scene->params.curve_subdivisions(); @@ -1434,9 +1481,11 @@ void GeometryManager::device_free(Device *device, DeviceScene *dscene) dscene->tri_vindex.free(); dscene->tri_patch.free(); dscene->tri_patch_uv.free(); + dscene->patches.free(); dscene->curves.free(); dscene->curve_keys.free(); - dscene->patches.free(); + dscene->points.free(); + dscene->points_shader.free(); dscene->attributes_map.free(); dscene->attributes_float.free(); dscene->attributes_float2.free(); diff --git a/intern/cycles/render/geometry.h b/intern/cycles/render/geometry.h index bcadb3a..399b8dc 100644 --- a/intern/cycles/render/geometry.h +++ b/intern/cycles/render/geometry.h @@ -54,6 +54,7 @@ class Geometry : public Node { MESH, HAIR, VOLUME, + POINTCLOUD, }; Type type; diff --git a/intern/cycles/render/hair.cpp b/intern/cycles/render/hair.cpp index 816c15c..0f18c12 100644 --- a/intern/cycles/render/hair.cpp +++ b/intern/cycles/render/hair.cpp @@ -347,6 +347,7 @@ void Hair::add_curve(int first_key, int shader) void Hair::copy_center_to_motion_step(const int motion_step) { + /* TODO: radius */ Attribute *attr_mP = attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); if (attr_mP) { float3 *keys = &curve_keys[0]; diff --git a/intern/cycles/render/object.cpp b/intern/cycles/render/object.cpp index 9396ae4..9f6216b 100644 --- a/intern/cycles/render/object.cpp +++ b/intern/cycles/render/object.cpp @@ -23,6 +23,7 @@ #include "render/light.h" #include "render/mesh.h" #include "render/particles.h" +#include "render/pointcloud.h" #include "render/scene.h" #include "render/volume.h" @@ -73,6 +74,7 @@ struct UpdateObjectTransformState { /* Flags which will be synchronized to Integrator. */ bool have_motion; bool have_curves; + bool have_pointcloud; /* ** Scheduling queue. ** */ @@ -526,8 +528,11 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s kobject.dupli_generated[0] = ob->dupli_generated[0]; kobject.dupli_generated[1] = ob->dupli_generated[1]; kobject.dupli_generated[2] = ob->dupli_generated[2]; - kobject.numkeys = (geom->type == Geometry::HAIR) ? static_cast(geom)->curve_keys.size() : - 0; + kobject.numkeys = (geom->type == Geometry::HAIR) ? + static_cast(geom)->curve_keys.size() : + (geom->type == Geometry::POINTCLOUD) ? + static_cast(geom)->points.size() : + 0; kobject.dupli_uv[0] = ob->dupli_uv[0]; kobject.dupli_uv[1] = ob->dupli_uv[1]; int totalsteps = geom->motion_steps; @@ -554,6 +559,9 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s if (geom->type == Geometry::HAIR) { state->have_curves = true; } + if (geom->type == Geometry::POINTCLOUD) { + state->have_pointcloud = true; + } } void ObjectManager::device_update_transforms(DeviceScene *dscene, Scene *scene, Progress &progress) @@ -625,7 +633,7 @@ void ObjectManager::device_update_transforms(DeviceScene *dscene, Scene *scene, } dscene->data.bvh.have_motion = state.have_motion; - dscene->data.bvh.have_curves = state.have_curves; + dscene->data.bvh.have_curves_or_points = state.have_curves || state.have_pointcloud; } void ObjectManager::device_update(Device *device, diff --git a/intern/cycles/render/pointcloud.cpp b/intern/cycles/render/pointcloud.cpp new file mode 100644 index 0000000..2f083be --- /dev/null +++ b/intern/cycles/render/pointcloud.cpp @@ -0,0 +1,347 @@ +/* + * Copyright 2011-2020 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "render/pointcloud.h" +#include "render/scene.h" + +CCL_NAMESPACE_BEGIN + +/* PointCloud Point */ + +void PointCloud::Point::bounds_grow(const float3 *points, + const float *radius, + BoundBox &bounds) const +{ + bounds.grow(points[index], radius[index]); +} + +void PointCloud::Point::bounds_grow(const float3 *points, + const float *radius, + const Transform &aligned_space, + BoundBox &bounds) const +{ + float3 P = transform_point(&aligned_space, points[index]); + bounds.grow(P, radius[index]); +} + +#if 0 +void Mesh::Triangle::motion_verts(const float3 *verts, + const float3 *vert_steps, + size_t num_verts, + size_t num_steps, + float time, + float3 r_verts[3]) const +{ + /* Figure out which steps we need to fetch and their interpolation factor. */ + const size_t max_step = num_steps - 1; + const size_t step = min((int)(time * max_step), max_step - 1); + const float t = time * max_step - step; + /* Fetch vertex coordinates. */ + float3 curr_verts[3]; + float3 next_verts[3]; + verts_for_step(verts, vert_steps, num_verts, num_steps, step, curr_verts); + verts_for_step(verts, vert_steps, num_verts, num_steps, step + 1, next_verts); + /* Interpolate between steps. */ + r_verts[0] = (1.0f - t) * curr_verts[0] + t * next_verts[0]; + r_verts[1] = (1.0f - t) * curr_verts[1] + t * next_verts[1]; + r_verts[2] = (1.0f - t) * curr_verts[2] + t * next_verts[2]; +} + +void Mesh::Triangle::verts_for_step(const float3 *verts, + const float3 *vert_steps, + size_t num_verts, + size_t num_steps, + size_t step, + float3 r_verts[3]) const +{ + const size_t center_step = ((num_steps - 1) / 2); + if (step == center_step) { + /* Center step: regular vertex location. */ + r_verts[0] = verts[v[0]]; + r_verts[1] = verts[v[1]]; + r_verts[2] = verts[v[2]]; + } + else { + /* Center step not stored in the attribute array array. */ + if (step > center_step) { + step--; + } + size_t offset = step * num_verts; + r_verts[0] = vert_steps[offset + v[0]]; + r_verts[1] = vert_steps[offset + v[1]]; + r_verts[2] = vert_steps[offset + v[2]]; + } +} +#endif + +#if 0 +void PointCloud::Point::motion_keys(const float3 *points, + const float *radius, + const float3 *key_steps, + size_t num_points, + size_t num_steps, + float time, + size_t k0, + size_t k1, + float4 r_keys[2]) const +{ + /* Figure out which steps we need to fetch and their interpolation factor. */ + const size_t max_step = num_steps - 1; + const size_t step = min((int)(time * max_step), max_step - 1); + const float t = time * max_step - step; + /* Fetch vertex coordinates. */ + float4 curr_keys[2]; + float4 next_keys[2]; + keys_for_step(points, radius, key_steps, num_points, num_steps, step, k0, k1, curr_keys); + keys_for_step(points, radius, key_steps, num_points, num_steps, step + 1, k0, k1, next_keys); + /* Interpolate between steps. */ + r_keys[0] = (1.0f - t) * curr_keys[0] + t * next_keys[0]; + r_keys[1] = (1.0f - t) * curr_keys[1] + t * next_keys[1]; +} + +void PointCloud::Point::keys_for_step(const float3 *points, + const float *radius, + const float3 *key_steps, + size_t num_points, + size_t num_steps, + size_t step, + size_t k0, + size_t k1, + float4 r_keys[2]) const +{ + k0 = max(k0, 0); + k1 = min(k1, num_keys - 1); + const size_t center_step = ((num_steps - 1) / 2); + if (step == center_step) { + /* Center step: regular key location. */ + /* TODO(sergey): Consider adding make_float4(float3, float) + * function. + */ + r_keys[0] = make_float4(points[first_key + k0].x, + points[first_key + k0].y, + points[first_key + k0].z, + radius[first_key + k0]); + r_keys[1] = make_float4(points[first_key + k1].x, + points[first_key + k1].y, + points[first_key + k1].z, + radius[first_key + k1]); + } + else { + /* Center step is not stored in this array. */ + if (step > center_step) { + step--; + } + const size_t offset = first_key + step * num_points; + r_keys[0] = make_float4(key_steps[offset + k0].x, + key_steps[offset + k0].y, + key_steps[offset + k0].z, + radius[first_key + k0]); + r_keys[1] = make_float4(key_steps[offset + k1].x, + key_steps[offset + k1].y, + key_steps[offset + k1].z, + radius[first_key + k1]); + } +} +#endif + +/* PointCloud */ + +NODE_DEFINE(PointCloud) +{ + NodeType *type = NodeType::add("pointcloud", create, NodeType::NONE, Geometry::node_base_type); + + SOCKET_POINT_ARRAY(points, "Points", array()); + SOCKET_FLOAT_ARRAY(radius, "Radius", array()); + + return type; +} + +PointCloud::PointCloud() : Geometry(node_type, Geometry::POINTCLOUD) +{ +} + +PointCloud::~PointCloud() +{ +} + +void PointCloud::resize(int numpoints) +{ + points.resize(numpoints); + radius.resize(numpoints); + shader.resize(numpoints); + attributes.resize(); +} + +void PointCloud::reserve(int numpoints) +{ + points.reserve(numpoints); + radius.reserve(numpoints); + shader.reserve(numpoints); + attributes.resize(true); +} + +void PointCloud::clear() +{ + Geometry::clear(); + + points.clear(); + radius.clear(); + shader.clear(); + attributes.clear(); +} + +void PointCloud::add_point(float3 co, float r, int shader_index) +{ + points.push_back_reserved(co); + radius.push_back_reserved(r); + shader.push_back_reserved(shader_index); +} + +void PointCloud::copy_center_to_motion_step(const int motion_step) +{ + Attribute *attr_mP = attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); + if (attr_mP) { + float3 *points_data = points.data(); + size_t numpoints = points.size(); + memcpy( + attr_mP->data_float3() + motion_step * numpoints, points_data, sizeof(float3) * numpoints); + } +} + +void PointCloud::get_uv_tiles(ustring map, unordered_set &tiles) +{ + Attribute *attr; + + if (map.empty()) { + attr = attributes.find(ATTR_STD_UV); + } + else { + attr = attributes.find(map); + } + + if (attr) { + attr->get_uv_tiles(this, ATTR_PRIM_GEOMETRY, tiles); + } +} + +void PointCloud::compute_bounds() +{ + BoundBox bnds = BoundBox::empty; + size_t numpoints = points.size(); + + if (numpoints > 0) { + for (size_t i = 0; i < numpoints; i++) { + bnds.grow(points[i], radius[i]); + } + + Attribute *attr = attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); + if (use_motion_blur && attr) { + size_t steps_size = points.size() * (motion_steps - 1); + float3 *key_steps = attr->data_float3(); + + for (size_t i = 0; i < steps_size; i++) + bnds.grow(key_steps[i]); + } + + if (!bnds.valid()) { + bnds = BoundBox::empty; + + /* skip nan or inf coordinates */ + for (size_t i = 0; i < numpoints; i++) + bnds.grow_safe(points[i], radius[i]); + + if (use_motion_blur && attr) { + size_t steps_size = points.size() * (motion_steps - 1); + float3 *key_steps = attr->data_float3(); + + for (size_t i = 0; i < steps_size; i++) + bnds.grow_safe(key_steps[i]); + } + } + } + + if (!bnds.valid()) { + /* empty mesh */ + bnds.grow(make_float3(0.0f, 0.0f, 0.0f)); + } + + bounds = bnds; +} + +void PointCloud::apply_transform(const Transform &tfm, const bool apply_to_motion) +{ + /* compute uniform scale */ + float3 c0 = transform_get_column(&tfm, 0); + float3 c1 = transform_get_column(&tfm, 1); + float3 c2 = transform_get_column(&tfm, 2); + float scalar = powf(fabsf(dot(cross(c0, c1), c2)), 1.0f / 3.0f); + + /* apply transform to curve keys */ + for (size_t i = 0; i < points.size(); i++) { + float3 co = transform_point(&tfm, points[i]); + float r = radius[i] * scalar; + + /* scale for curve radius is only correct for uniform scale */ + points[i] = co; + radius[i] = r; + } + + if (apply_to_motion) { + Attribute *attr = attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); + + if (attr) { + /* apply transform to motion curve keys */ + size_t steps_size = points.size() * (motion_steps - 1); + float4 *key_steps = attr->data_float4(); + + for (size_t i = 0; i < steps_size; i++) { + float3 co = transform_point(&tfm, float4_to_float3(key_steps[i])); + float radius = key_steps[i].w * scalar; + + /* scale for curve radius is only correct for uniform scale */ + key_steps[i] = float3_to_float4(co); + key_steps[i].w = radius; + } + } + } +} + +void PointCloud::pack(Scene *scene, float4 *packed_points, uint *packed_shader) +{ + size_t numpoints = points.size(); + float3 *points_data = points.data(); + float *radius_data = radius.data(); + int *shader_data = shader.data(); + + for (size_t i = 0; i < numpoints; i++) { + packed_points[i] = make_float4( + points_data[i].x, points_data[i].y, points_data[i].z, radius_data[i]); + } + + uint shader_id = 0; + uint last_shader = -1; + for (size_t i = 0; i < numpoints; i++) { + if (last_shader != shader_data[i]) { + last_shader = shader_data[i]; + Shader *shader = (last_shader < used_shaders.size()) ? used_shaders[last_shader] : + scene->default_surface; + shader_id = scene->shader_manager->get_shader_id(shader); + } + packed_shader[i] = shader_id; + } +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/render/pointcloud.h b/intern/cycles/render/pointcloud.h new file mode 100644 index 0000000..bcb3f67 --- /dev/null +++ b/intern/cycles/render/pointcloud.h @@ -0,0 +1,101 @@ +/* + * Copyright 2011-2020 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __POINTCLOUD_H__ +#define __POINTCLOUD_H__ + +#include "render/geometry.h" + +CCL_NAMESPACE_BEGIN + +class PointCloud : public Geometry { + public: + NODE_DECLARE + + /* PointCloud Point */ + struct Point { + int index; + + void bounds_grow(const float3 *points, const float *radius, BoundBox &bounds) const; + void bounds_grow(const float3 *points, + const float *radius, + const Transform &aligned_space, + BoundBox &bounds) const; + +#if 0 + void motion_keys(const float3 *points, + const float *radius, + const float3 *key_steps, + size_t num_points, + size_t num_steps, + float time, + size_t k0, + size_t k1, + float4 r_keys[2]) const; + void keys_for_step(const float3 *points, + const float *radius, + const float3 *key_steps, + size_t num_points, + size_t num_steps, + size_t step, + size_t k0, + size_t k1, + float4 r_keys[2]) const; +#endif + }; + + array points; + array radius; + array shader; + + /* Constructor/Destructor */ + PointCloud(); + ~PointCloud(); + + /* Geometry */ + void clear() override; + + void resize(int numpoints); + void reserve(int numpoints); + void add_point(float3 loc, float radius, int shader = 0); + + void copy_center_to_motion_step(const int motion_step); + + void compute_bounds() override; + void apply_transform(const Transform &tfm, const bool apply_to_motion) override; + + /* Points */ + Point get_point(int i) const + { + Point point = {i}; + return point; + } + + size_t num_points() const + { + return points.size(); + } + + /* UDIM */ + void get_uv_tiles(ustring map, unordered_set &tiles) override; + + /* BVH */ + void pack(Scene *scene, float4 *packed_points, uint *packed_shader); +}; + +CCL_NAMESPACE_END + +#endif /* __POINTCLOUD_H__ */ diff --git a/intern/cycles/render/scene.cpp b/intern/cycles/render/scene.cpp index 8f863b5..67f5a3d 100644 --- a/intern/cycles/render/scene.cpp +++ b/intern/cycles/render/scene.cpp @@ -28,6 +28,7 @@ #include "render/object.h" #include "render/osl.h" #include "render/particles.h" +#include "render/pointcloud.h" #include "render/scene.h" #include "render/session.h" #include "render/shader.h" @@ -58,9 +59,11 @@ DeviceScene::DeviceScene(Device *device) tri_vindex(device, "__tri_vindex", MEM_GLOBAL), tri_patch(device, "__tri_patch", MEM_GLOBAL), tri_patch_uv(device, "__tri_patch_uv", MEM_GLOBAL), + patches(device, "__patches", MEM_GLOBAL), curves(device, "__curves", MEM_GLOBAL), curve_keys(device, "__curve_keys", MEM_GLOBAL), - patches(device, "__patches", MEM_GLOBAL), + points(device, "__points", MEM_GLOBAL), + points_shader(device, "__points_shader", MEM_GLOBAL), objects(device, "__objects", MEM_GLOBAL), object_motion_pass(device, "__object_motion_pass", MEM_GLOBAL), object_motion(device, "__object_motion", MEM_GLOBAL), @@ -439,6 +442,9 @@ DeviceRequestedFeatures Scene::get_requested_device_features() else if (geom->type == Geometry::HAIR) { requested_features.use_hair = true; } + else if (geom->type == Geometry::POINTCLOUD) { + requested_features.use_pointcloud = true; + } } requested_features.use_background_light = light_manager->has_background_light(this); @@ -597,6 +603,15 @@ template<> Volume *Scene::create_node() return node; } +template<> PointCloud *Scene::create_node() +{ + PointCloud *node = new PointCloud(); + node->set_owner(this); + geometry.push_back(node); + geometry_manager->tag_update(this); + return node; +} + template<> Object *Scene::create_node() { Object *node = new Object(); @@ -661,6 +676,12 @@ template<> void Scene::delete_node_impl(Volume *node) geometry_manager->tag_update(this); } +template<> void Scene::delete_node_impl(PointCloud *node) +{ + delete_node_from_array(geometry, static_cast(node)); + geometry_manager->tag_update(this); +} + template<> void Scene::delete_node_impl(Geometry *node) { delete_node_from_array(geometry, node); diff --git a/intern/cycles/render/scene.h b/intern/cycles/render/scene.h index 0e32a70..ca46fdb 100644 --- a/intern/cycles/render/scene.h +++ b/intern/cycles/render/scene.h @@ -52,6 +52,7 @@ class Object; class ObjectManager; class ParticleSystemManager; class ParticleSystem; +class PointCloud; class CurveSystemManager; class Shader; class ShaderManager; @@ -84,10 +85,15 @@ class DeviceScene { device_vector tri_patch; device_vector tri_patch_uv; + device_vector patches; + + /* hair */ device_vector curves; device_vector curve_keys; - device_vector patches; + /* pointcloud */ + device_vector points; + device_vector points_shader; /* objects */ device_vector objects; @@ -355,6 +361,8 @@ template<> Hair *Scene::create_node(); template<> Volume *Scene::create_node(); +template<> PointCloud *Scene::create_node(); + template<> ParticleSystem *Scene::create_node(); template<> Shader *Scene::create_node(); @@ -365,6 +373,8 @@ template<> void Scene::delete_node_impl(Mesh *node); template<> void Scene::delete_node_impl(Volume *node); +template<> void Scene::delete_node_impl(PointCloud *node); + template<> void Scene::delete_node_impl(Hair *node); template<> void Scene::delete_node_impl(Geometry *node);