diff options
Diffstat (limited to 'intern/cycles/scene')
-rw-r--r-- | intern/cycles/scene/CMakeLists.txt | 2 | ||||
-rw-r--r-- | intern/cycles/scene/alembic.cpp | 87 | ||||
-rw-r--r-- | intern/cycles/scene/alembic.h | 10 | ||||
-rw-r--r-- | intern/cycles/scene/alembic_read.cpp | 49 | ||||
-rw-r--r-- | intern/cycles/scene/alembic_read.h | 20 | ||||
-rw-r--r-- | intern/cycles/scene/attribute.cpp | 33 | ||||
-rw-r--r-- | intern/cycles/scene/camera.cpp | 10 | ||||
-rw-r--r-- | intern/cycles/scene/camera.h | 6 | ||||
-rw-r--r-- | intern/cycles/scene/geometry.cpp | 97 | ||||
-rw-r--r-- | intern/cycles/scene/geometry.h | 12 | ||||
-rw-r--r-- | intern/cycles/scene/integrator.cpp | 2 | ||||
-rw-r--r-- | intern/cycles/scene/object.cpp | 36 | ||||
-rw-r--r-- | intern/cycles/scene/object.h | 1 | ||||
-rw-r--r-- | intern/cycles/scene/pointcloud.cpp | 304 | ||||
-rw-r--r-- | intern/cycles/scene/pointcloud.h | 114 | ||||
-rw-r--r-- | intern/cycles/scene/scene.cpp | 29 | ||||
-rw-r--r-- | intern/cycles/scene/scene.h | 10 | ||||
-rw-r--r-- | intern/cycles/scene/shader_nodes.cpp | 73 | ||||
-rw-r--r-- | intern/cycles/scene/shader_nodes.h | 15 |
19 files changed, 894 insertions, 16 deletions
diff --git a/intern/cycles/scene/CMakeLists.txt b/intern/cycles/scene/CMakeLists.txt index a3fde99306b..6f8b97a4998 100644 --- a/intern/cycles/scene/CMakeLists.txt +++ b/intern/cycles/scene/CMakeLists.txt @@ -40,6 +40,7 @@ set(SRC mesh_displace.cpp mesh_subdivision.cpp procedural.cpp + pointcloud.cpp object.cpp osl.cpp particles.cpp @@ -81,6 +82,7 @@ set(SRC_HEADERS particles.h pass.h procedural.h + pointcloud.h curves.h scene.h shader.h diff --git a/intern/cycles/scene/alembic.cpp b/intern/cycles/scene/alembic.cpp index 39b5f467736..71fa1863b8b 100644 --- a/intern/cycles/scene/alembic.cpp +++ b/intern/cycles/scene/alembic.cpp @@ -21,6 +21,7 @@ #include "scene/curves.h" #include "scene/mesh.h" #include "scene/object.h" +#include "scene/pointcloud.h" #include "scene/scene.h" #include "scene/shader.h" @@ -99,6 +100,9 @@ void CachedData::clear() triangles.clear(); uv_loops.clear(); vertices.clear(); + points.clear(); + radiuses.clear(); + points_shader.clear(); for (CachedAttribute &attr : attributes) { attr.data.clear(); @@ -146,6 +150,9 @@ bool CachedData::is_constant() const CHECK_IF_CONSTANT(triangles) CHECK_IF_CONSTANT(uv_loops) CHECK_IF_CONSTANT(vertices) + CHECK_IF_CONSTANT(points) + CHECK_IF_CONSTANT(radiuses) + CHECK_IF_CONSTANT(points_shader) for (const CachedAttribute &attr : attributes) { if (!attr.data.is_constant()) { @@ -185,6 +192,9 @@ void CachedData::invalidate_last_loaded_time(bool attributes_only) triangles.invalidate_last_loaded_time(); uv_loops.invalidate_last_loaded_time(); vertices.invalidate_last_loaded_time(); + points.invalidate_last_loaded_time(); + radiuses.invalidate_last_loaded_time(); + points_shader.invalidate_last_loaded_time(); } void CachedData::set_time_sampling(TimeSampling time_sampling) @@ -206,6 +216,9 @@ void CachedData::set_time_sampling(TimeSampling time_sampling) triangles.set_time_sampling(time_sampling); uv_loops.set_time_sampling(time_sampling); vertices.set_time_sampling(time_sampling); + points.set_time_sampling(time_sampling); + radiuses.set_time_sampling(time_sampling); + points_shader.set_time_sampling(time_sampling); for (CachedAttribute &attr : attributes) { attr.data.set_time_sampling(time_sampling); @@ -233,6 +246,9 @@ size_t CachedData::memory_used() const mem_used += triangles.memory_used(); mem_used += uv_loops.memory_used(); mem_used += vertices.memory_used(); + mem_used += points.memory_used(); + mem_used += radiuses.memory_used(); + mem_used += points_shader.memory_used(); for (const CachedAttribute &attr : attributes) { mem_used += attr.data.memory_used(); @@ -901,6 +917,9 @@ void AlembicProcedural::generate(Scene *scene, Progress &progress) else if (object->schema_type == AlembicObject::CURVES) { read_curves(object, frame_time); } + else if (object->schema_type == AlembicObject::POINTS) { + read_points(object, frame_time); + } else if (object->schema_type == AlembicObject::SUBD) { read_subd(object, frame_time); } @@ -970,6 +989,9 @@ void AlembicProcedural::load_objects(Progress &progress) if (abc_object->schema_type == AlembicObject::CURVES) { geometry = scene_->create_node<Hair>(); } + else if (abc_object->schema_type == AlembicObject::POINTS) { + geometry = scene_->create_node<PointCloud>(); + } else if (abc_object->schema_type == AlembicObject::POLY_MESH || abc_object->schema_type == AlembicObject::SUBD) { geometry = scene_->create_node<Mesh>(); @@ -1202,6 +1224,45 @@ void AlembicProcedural::read_curves(AlembicObject *abc_object, Abc::chrono_t fra hair->tag_update(scene_, rebuild); } +void AlembicProcedural::read_points(AlembicObject *abc_object, Abc::chrono_t frame_time) +{ + CachedData &cached_data = abc_object->get_cached_data(); + + /* update sockets */ + + Object *object = abc_object->get_object(); + cached_data.transforms.copy_to_socket(frame_time, object, object->get_tfm_socket()); + + if (object->is_modified()) { + object->tag_update(scene_); + } + + /* Only update sockets for the original Geometry. */ + if (abc_object->instance_of) { + return; + } + + PointCloud *point_cloud = static_cast<PointCloud *>(object->get_geometry()); + + /* Make sure shader ids are also updated. */ + if (point_cloud->used_shaders_is_modified()) { + point_cloud->tag_shader_modified(); + } + + cached_data.points.copy_to_socket(frame_time, point_cloud, point_cloud->get_points_socket()); + cached_data.radiuses.copy_to_socket(frame_time, point_cloud, point_cloud->get_radius_socket()); + cached_data.points_shader.copy_to_socket( + frame_time, point_cloud, point_cloud->get_shader_socket()); + + /* update attributes */ + + update_attributes(point_cloud->attributes, cached_data, frame_time); + + const bool rebuild = (point_cloud->points_is_modified() || point_cloud->radius_is_modified() || + point_cloud->shader_is_modified()); + point_cloud->tag_update(scene_, rebuild); +} + void AlembicProcedural::walk_hierarchy( IObject parent, const ObjectHeader &header, @@ -1314,7 +1375,23 @@ void AlembicProcedural::walk_hierarchy( // ignore the face set, it will be read along with the data } else if (IPoints::matches(header)) { - // unsupported for now + IPoints points(parent, header.getName()); + + unordered_map<std::string, AlembicObject *>::const_iterator iter; + iter = object_map.find(points.getFullName()); + + if (iter != object_map.end()) { + AlembicObject *abc_object = iter->second; + abc_object->iobject = points; + abc_object->schema_type = AlembicObject::POINTS; + + if (matrix_samples_data.samples) { + abc_object->xform_samples = *matrix_samples_data.samples; + abc_object->xform_time_sampling = matrix_samples_data.time_sampling; + } + } + + next_object = points; } else if (INuPatch::matches(header)) { // unsupported for now @@ -1391,6 +1468,14 @@ void AlembicProcedural::build_caches(Progress &progress) object->load_data_in_cache(object->get_cached_data(), this, schema, progress); } } + else if (object->schema_type == AlembicObject::POINTS) { + if (!object->has_data_loaded() || default_radius_is_modified() || + object->radius_scale_is_modified()) { + IPoints points(object->iobject, Alembic::Abc::kWrapExisting); + IPointsSchema schema = points.getSchema(); + object->load_data_in_cache(object->get_cached_data(), this, schema, progress); + } + } else if (object->schema_type == AlembicObject::SUBD) { if (!object->has_data_loaded()) { ISubD subd_mesh(object->iobject, Alembic::Abc::kWrapExisting); diff --git a/intern/cycles/scene/alembic.h b/intern/cycles/scene/alembic.h index 77aafd0ab32..3a4d37da3ff 100644 --- a/intern/cycles/scene/alembic.h +++ b/intern/cycles/scene/alembic.h @@ -327,6 +327,11 @@ struct CachedData { DataStore<array<int>> curve_first_key; DataStore<array<int>> curve_shader; + /* point data */ + DataStore<array<float3>> points; + DataStore<array<float>> radiuses; + DataStore<array<int>> points_shader; + struct CachedAttribute { AttributeStandard std; AttributeElement element; @@ -414,6 +419,7 @@ class AlembicObject : public Node { POLY_MESH, SUBD, CURVES, + POINTS, }; bool need_shader_update = true; @@ -550,6 +556,10 @@ class AlembicProcedural : public Procedural { * Object Nodes in the Cycles scene if none exist yet. */ void read_curves(AlembicObject *abc_object, Alembic::AbcGeom::Abc::chrono_t frame_time); + /* Read the data for an IPoints at the specified frame_time. Creates corresponding Geometry and + * Object Nodes in the Cycles scene if none exist yet. */ + void read_points(AlembicObject *abc_object, Alembic::AbcGeom::Abc::chrono_t frame_time); + /* Read the data for an ISubD at the specified frame_time. Creates corresponding Geometry and * Object Nodes in the Cycles scene if none exist yet. */ void read_subd(AlembicObject *abc_object, Alembic::AbcGeom::Abc::chrono_t frame_time); diff --git a/intern/cycles/scene/alembic_read.cpp b/intern/cycles/scene/alembic_read.cpp index 35f4854127a..07874b7528e 100644 --- a/intern/cycles/scene/alembic_read.cpp +++ b/intern/cycles/scene/alembic_read.cpp @@ -609,6 +609,55 @@ void read_geometry_data(AlembicProcedural *proc, read_data_loop(proc, cached_data, data, read_curves_data, progress); } +/* Points Geometries. */ + +static void read_points_data(CachedData &cached_data, const PointsSchemaData &data, chrono_t time) +{ + const ISampleSelector iss = ISampleSelector(time); + + const P3fArraySamplePtr position = data.positions.getValue(iss); + FloatArraySamplePtr radiuses; + + array<float3> a_positions; + array<float> a_radius; + array<int> a_shader; + a_positions.reserve(position->size()); + a_radius.reserve(position->size()); + a_shader.reserve(position->size()); + + if (data.radiuses.valid()) { + IFloatGeomParam::Sample wsample = data.radiuses.getExpandedValue(iss); + radiuses = wsample.getVals(); + } + + const bool do_radius = (radiuses != nullptr) && (radiuses->size() > 1); + float radius = (radiuses && radiuses->size() == 1) ? (*radiuses)[0] : data.default_radius; + + int offset = 0; + for (size_t i = 0; i < position->size(); i++) { + const V3f &f = position->get()[offset + i]; + a_positions.push_back_slow(make_float3_from_yup(f)); + + if (do_radius) { + radius = (*radiuses)[offset + i]; + a_radius.push_back_slow(radius); + } + + a_shader.push_back_slow((int)0); + } + + cached_data.points.add_data(a_positions, time); + cached_data.radiuses.add_data(a_radius, time); + cached_data.points_shader.add_data(a_shader, time); +} + +void read_geometry_data(AlembicProcedural *proc, + CachedData &cached_data, + const PointsSchemaData &data, + Progress &progress) +{ + read_data_loop(proc, cached_data, data, read_points_data, progress); +} /* Attributes conversions. */ /* Type traits for converting between Alembic and Cycles types. diff --git a/intern/cycles/scene/alembic_read.h b/intern/cycles/scene/alembic_read.h index 6b656b59481..e95750ce691 100644 --- a/intern/cycles/scene/alembic_read.h +++ b/intern/cycles/scene/alembic_read.h @@ -122,6 +122,26 @@ void read_geometry_data(AlembicProcedural *proc, const CurvesSchemaData &data, Progress &progress); +/* Data of a ICurvesSchema that we need to read. */ +struct PointsSchemaData { + Alembic::AbcGeom::TimeSamplingPtr time_sampling; + size_t num_samples; + + float default_radius; + float radius_scale; + + Alembic::AbcGeom::IP3fArrayProperty positions; + Alembic::AbcGeom::IInt32ArrayProperty num_points; + Alembic::AbcGeom::IFloatGeomParam radiuses; + // Those are unsupported for now. + Alembic::AbcGeom::IV3fArrayProperty velocities; +}; + +void read_geometry_data(AlembicProcedural *proc, + CachedData &cached_data, + const PointsSchemaData &data, + Progress &progress); + void read_attributes(AlembicProcedural *proc, CachedData &cache, const Alembic::AbcGeom::ICompoundProperty &arb_geom_params, diff --git a/intern/cycles/scene/attribute.cpp b/intern/cycles/scene/attribute.cpp index 6d15f3325f7..f1021a26e8a 100644 --- a/intern/cycles/scene/attribute.cpp +++ b/intern/cycles/scene/attribute.cpp @@ -18,6 +18,7 @@ #include "scene/hair.h" #include "scene/image.h" #include "scene/mesh.h" +#include "scene/pointcloud.h" #include "util/foreach.h" #include "util/log.h" @@ -205,6 +206,10 @@ size_t Attribute::element_size(Geometry *geom, AttributePrimitive prim) const size -= mesh->get_num_subd_verts(); } } + else if (geom->geometry_type == Geometry::POINTCLOUD) { + PointCloud *pointcloud = static_cast<PointCloud *>(geom); + size = pointcloud->num_points(); + } break; case ATTR_ELEMENT_VERTEX_MOTION: if (geom->geometry_type == Geometry::MESH) { @@ -215,6 +220,10 @@ size_t Attribute::element_size(Geometry *geom, AttributePrimitive prim) const size -= mesh->get_num_subd_verts() * (mesh->get_motion_steps() - 1); } } + else if (geom->geometry_type == Geometry::POINTCLOUD) { + PointCloud *pointcloud = static_cast<PointCloud *>(geom); + size = pointcloud->num_points() * (pointcloud->get_motion_steps() - 1); + } break; case ATTR_ELEMENT_FACE: if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) { @@ -346,6 +355,8 @@ const char *Attribute::standard_name(AttributeStandard std) return "curve_length"; 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: @@ -555,6 +566,28 @@ Attribute *AttributeSet::add(AttributeStandard std, ustring name) break; } } + else if (geometry->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::TypeFloat4, 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; + } + } else if (geometry->geometry_type == Geometry::VOLUME) { switch (std) { case ATTR_STD_VERTEX_NORMAL: diff --git a/intern/cycles/scene/camera.cpp b/intern/cycles/scene/camera.cpp index 5bafe736fb5..2f3b55f887f 100644 --- a/intern/cycles/scene/camera.cpp +++ b/intern/cycles/scene/camera.cpp @@ -100,6 +100,7 @@ NODE_DEFINE(Camera) panorama_type_enum.insert("mirrorball", PANORAMA_MIRRORBALL); panorama_type_enum.insert("fisheye_equidistant", PANORAMA_FISHEYE_EQUIDISTANT); panorama_type_enum.insert("fisheye_equisolid", PANORAMA_FISHEYE_EQUISOLID); + panorama_type_enum.insert("fisheye_lens_polynomial", PANORAMA_FISHEYE_LENS_POLYNOMIAL); SOCKET_ENUM(panorama_type, "Panorama Type", panorama_type_enum, PANORAMA_EQUIRECTANGULAR); SOCKET_FLOAT(fisheye_fov, "Fisheye FOV", M_PI_F); @@ -112,6 +113,12 @@ NODE_DEFINE(Camera) SOCKET_FLOAT(fov_pre, "FOV Pre", M_PI_4_F); SOCKET_FLOAT(fov_post, "FOV Post", M_PI_4_F); + SOCKET_FLOAT(fisheye_polynomial_k0, "Fisheye Polynomial K0", 0.0f); + SOCKET_FLOAT(fisheye_polynomial_k1, "Fisheye Polynomial K1", 0.0f); + SOCKET_FLOAT(fisheye_polynomial_k2, "Fisheye Polynomial K2", 0.0f); + SOCKET_FLOAT(fisheye_polynomial_k3, "Fisheye Polynomial K3", 0.0f); + SOCKET_FLOAT(fisheye_polynomial_k4, "Fisheye Polynomial K4", 0.0f); + static NodeEnum stereo_eye_enum; stereo_eye_enum.insert("none", STEREO_NONE); stereo_eye_enum.insert("left", STEREO_LEFT); @@ -418,6 +425,9 @@ void Camera::update(Scene *scene) -longitude_min, latitude_min - latitude_max, -latitude_min + M_PI_2_F); + kcam->fisheye_lens_polynomial_bias = fisheye_polynomial_k0; + kcam->fisheye_lens_polynomial_coefficients = make_float4( + fisheye_polynomial_k1, fisheye_polynomial_k2, fisheye_polynomial_k3, fisheye_polynomial_k4); switch (stereo_eye) { case STEREO_LEFT: diff --git a/intern/cycles/scene/camera.h b/intern/cycles/scene/camera.h index 58e39599267..50586287bea 100644 --- a/intern/cycles/scene/camera.h +++ b/intern/cycles/scene/camera.h @@ -105,6 +105,12 @@ class Camera : public Node { NODE_SOCKET_API(float, longitude_min) NODE_SOCKET_API(float, longitude_max) + NODE_SOCKET_API(float, fisheye_polynomial_k0) + NODE_SOCKET_API(float, fisheye_polynomial_k1) + NODE_SOCKET_API(float, fisheye_polynomial_k2) + NODE_SOCKET_API(float, fisheye_polynomial_k3) + NODE_SOCKET_API(float, fisheye_polynomial_k4) + /* panorama stereo */ NODE_SOCKET_API(StereoEye, stereo_eye) NODE_SOCKET_API(bool, use_spherical_stereo) diff --git a/intern/cycles/scene/geometry.cpp b/intern/cycles/scene/geometry.cpp index bf426fc49f6..558b0e13b0f 100644 --- a/intern/cycles/scene/geometry.cpp +++ b/intern/cycles/scene/geometry.cpp @@ -26,6 +26,7 @@ #include "scene/light.h" #include "scene/mesh.h" #include "scene/object.h" +#include "scene/pointcloud.h" #include "scene/scene.h" #include "scene/shader.h" #include "scene/shader_nodes.h" @@ -165,7 +166,8 @@ int Geometry::motion_step(float time) const bool Geometry::need_build_bvh(BVHLayout layout) const { return is_instanced() || layout == BVH_LAYOUT_OPTIX || layout == BVH_LAYOUT_MULTI_OPTIX || - layout == BVH_LAYOUT_MULTI_OPTIX_EMBREE; + layout == BVH_LAYOUT_METAL || layout == BVH_LAYOUT_MULTI_OPTIX_EMBREE || + layout == BVH_LAYOUT_MULTI_METAL || layout == BVH_LAYOUT_MULTI_METAL_EMBREE; } bool Geometry::is_instanced() const @@ -239,6 +241,7 @@ void Geometry::compute_bvh( 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(); @@ -722,6 +725,12 @@ void GeometryManager::update_attribute_element_offset(Geometry *geom, else if (element == ATTR_ELEMENT_CURVE_KEY_MOTION) offset -= hair->curve_key_offset; } + else if (geom->is_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 */ @@ -1005,6 +1014,8 @@ void GeometryManager::mesh_calc_offset(Scene *scene, BVHLayout bvh_layout) size_t curve_key_size = 0; size_t curve_segment_size = 0; + size_t point_size = 0; + size_t patch_size = 0; size_t face_size = 0; size_t corner_size = 0; @@ -1053,6 +1064,14 @@ void GeometryManager::mesh_calc_offset(Scene *scene, BVHLayout bvh_layout) curve_key_size += hair->get_curve_keys().size(); curve_segment_size += hair->num_segments(); } + else if (geom->is_pointcloud()) { + PointCloud *pointcloud = static_cast<PointCloud *>(geom); + + prim_offset_changed = (pointcloud->prim_offset != point_size); + + pointcloud->prim_offset = point_size; + point_size += pointcloud->num_points(); + } if (prim_offset_changed) { /* Need to rebuild BVH in OptiX, since refit only allows modified mesh data there */ @@ -1078,6 +1097,8 @@ void GeometryManager::device_update_mesh(Device *, size_t curve_size = 0; size_t curve_segment_size = 0; + size_t point_size = 0; + size_t patch_size = 0; foreach (Geometry *geom, scene->geometry) { @@ -1105,6 +1126,10 @@ void GeometryManager::device_update_mesh(Device *, curve_size += hair->num_curves(); curve_segment_size += hair->num_segments(); } + else if (geom->is_pointcloud()) { + PointCloud *pointcloud = static_cast<PointCloud *>(geom); + point_size += pointcloud->num_points(); + } } /* Fill in all the arrays. */ @@ -1200,6 +1225,26 @@ void GeometryManager::device_update_mesh(Device *, dscene->curve_segments.copy_to_device_if_modified(); } + if (point_size != 0) { + progress.set_status("Updating Mesh", "Copying Point clouds 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->is_pointcloud()) { + PointCloud *pointcloud = static_cast<PointCloud *>(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 && dscene->patches.need_realloc()) { progress.set_status("Updating Mesh", "Copying Patches to device"); @@ -1241,13 +1286,15 @@ void GeometryManager::device_update_bvh(Device *device, 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(); VLOG(1) << "Using " << bvh_layout_name(bparams.bvh_layout) << " layout."; const bool can_refit = scene->bvh != nullptr && - (bparams.bvh_layout == BVHLayout::BVH_LAYOUT_OPTIX); + (bparams.bvh_layout == BVHLayout::BVH_LAYOUT_OPTIX || + bparams.bvh_layout == BVHLayout::BVH_LAYOUT_METAL); BVH *bvh = scene->bvh; if (!scene->bvh) { @@ -1321,6 +1368,7 @@ void GeometryManager::device_update_bvh(Device *device, enum { DEVICE_CURVE_DATA_MODIFIED = (1 << 0), DEVICE_MESH_DATA_MODIFIED = (1 << 1), + DEVICE_POINT_DATA_MODIFIED = (1 << 2), ATTR_FLOAT_MODIFIED = (1 << 2), ATTR_FLOAT2_MODIFIED = (1 << 3), @@ -1330,17 +1378,20 @@ enum { CURVE_DATA_NEED_REALLOC = (1 << 7), MESH_DATA_NEED_REALLOC = (1 << 8), + POINT_DATA_NEED_REALLOC = (1 << 9), + + ATTR_FLOAT_NEEDS_REALLOC = (1 << 10), + ATTR_FLOAT2_NEEDS_REALLOC = (1 << 11), + ATTR_FLOAT3_NEEDS_REALLOC = (1 << 12), + ATTR_FLOAT4_NEEDS_REALLOC = (1 << 13), - ATTR_FLOAT_NEEDS_REALLOC = (1 << 9), - ATTR_FLOAT2_NEEDS_REALLOC = (1 << 10), - ATTR_FLOAT3_NEEDS_REALLOC = (1 << 11), - ATTR_FLOAT4_NEEDS_REALLOC = (1 << 12), - ATTR_UCHAR4_NEEDS_REALLOC = (1 << 13), + ATTR_UCHAR4_NEEDS_REALLOC = (1 << 14), ATTRS_NEED_REALLOC = (ATTR_FLOAT_NEEDS_REALLOC | ATTR_FLOAT2_NEEDS_REALLOC | ATTR_FLOAT3_NEEDS_REALLOC | ATTR_FLOAT4_NEEDS_REALLOC | ATTR_UCHAR4_NEEDS_REALLOC), DEVICE_MESH_DATA_NEEDS_REALLOC = (MESH_DATA_NEED_REALLOC | ATTRS_NEED_REALLOC), + DEVICE_POINT_DATA_NEEDS_REALLOC = (POINT_DATA_NEED_REALLOC | ATTRS_NEED_REALLOC), DEVICE_CURVE_DATA_NEEDS_REALLOC = (CURVE_DATA_NEED_REALLOC | ATTRS_NEED_REALLOC), }; @@ -1527,6 +1578,17 @@ void GeometryManager::device_update_preprocess(Device *device, Scene *scene, Pro device_update_flags |= DEVICE_MESH_DATA_MODIFIED; } } + + if (geom->is_pointcloud()) { + PointCloud *pointcloud = static_cast<PointCloud *>(geom); + + if (pointcloud->need_update_rebuild) { + device_update_flags |= DEVICE_POINT_DATA_NEEDS_REALLOC; + } + else if (pointcloud->is_modified()) { + device_update_flags |= DEVICE_POINT_DATA_MODIFIED; + } + } } if (update_flags & (MESH_ADDED | MESH_REMOVED)) { @@ -1537,10 +1599,15 @@ void GeometryManager::device_update_preprocess(Device *device, Scene *scene, Pro device_update_flags |= DEVICE_CURVE_DATA_NEEDS_REALLOC; } + if (update_flags & (POINT_ADDED | POINT_REMOVED)) { + device_update_flags |= DEVICE_POINT_DATA_NEEDS_REALLOC; + } + /* tag the device arrays for reallocation or modification */ DeviceScene *dscene = &scene->dscene; - if (device_update_flags & (DEVICE_MESH_DATA_NEEDS_REALLOC | DEVICE_CURVE_DATA_NEEDS_REALLOC)) { + if (device_update_flags & (DEVICE_MESH_DATA_NEEDS_REALLOC | DEVICE_CURVE_DATA_NEEDS_REALLOC | + DEVICE_POINT_DATA_NEEDS_REALLOC)) { delete scene->bvh; scene->bvh = nullptr; @@ -1568,6 +1635,11 @@ void GeometryManager::device_update_preprocess(Device *device, Scene *scene, Pro dscene->curve_keys.tag_realloc(); dscene->curve_segments.tag_realloc(); } + + if (device_update_flags & DEVICE_POINT_DATA_NEEDS_REALLOC) { + dscene->points.tag_realloc(); + dscene->points_shader.tag_realloc(); + } } if ((update_flags & VISIBILITY_MODIFIED) != 0) { @@ -1628,6 +1700,11 @@ void GeometryManager::device_update_preprocess(Device *device, Scene *scene, Pro dscene->curve_segments.tag_modified(); } + if (device_update_flags & DEVICE_POINT_DATA_MODIFIED) { + dscene->points.tag_modified(); + dscene->points_shader.tag_modified(); + } + need_flags_update = false; } @@ -2062,6 +2139,8 @@ void GeometryManager::device_update(Device *device, dscene->curves.clear_modified(); dscene->curve_keys.clear_modified(); dscene->curve_segments.clear_modified(); + dscene->points.clear_modified(); + dscene->points_shader.clear_modified(); dscene->patches.clear_modified(); dscene->attributes_map.clear_modified(); dscene->attributes_float.clear_modified(); @@ -2090,6 +2169,8 @@ void GeometryManager::device_free(Device *device, DeviceScene *dscene, bool forc dscene->curves.free_if_need_realloc(force_free); dscene->curve_keys.free_if_need_realloc(force_free); dscene->curve_segments.free_if_need_realloc(force_free); + dscene->points.free_if_need_realloc(force_free); + dscene->points_shader.free_if_need_realloc(force_free); dscene->patches.free_if_need_realloc(force_free); dscene->attributes_map.free_if_need_realloc(force_free); dscene->attributes_float.free_if_need_realloc(force_free); diff --git a/intern/cycles/scene/geometry.h b/intern/cycles/scene/geometry.h index 91799d7fde8..b02387c3020 100644 --- a/intern/cycles/scene/geometry.h +++ b/intern/cycles/scene/geometry.h @@ -55,6 +55,7 @@ class Geometry : public Node { MESH, HAIR, VOLUME, + POINTCLOUD, }; Type geometry_type; @@ -155,6 +156,11 @@ class Geometry : public Node { return geometry_type == HAIR; } + bool is_pointcloud() const + { + return geometry_type == POINTCLOUD; + } + bool is_volume() const { return geometry_type == VOLUME; @@ -181,12 +187,14 @@ class GeometryManager { MESH_REMOVED = (1 << 5), HAIR_ADDED = (1 << 6), HAIR_REMOVED = (1 << 7), + POINT_ADDED = (1 << 12), + POINT_REMOVED = (1 << 13), SHADER_ATTRIBUTE_MODIFIED = (1 << 8), SHADER_DISPLACEMENT_MODIFIED = (1 << 9), - GEOMETRY_ADDED = MESH_ADDED | HAIR_ADDED, - GEOMETRY_REMOVED = MESH_REMOVED | HAIR_REMOVED, + GEOMETRY_ADDED = MESH_ADDED | HAIR_ADDED | POINT_ADDED, + GEOMETRY_REMOVED = MESH_REMOVED | HAIR_REMOVED | POINT_REMOVED, TRANSFORM_MODIFIED = (1 << 10), diff --git a/intern/cycles/scene/integrator.cpp b/intern/cycles/scene/integrator.cpp index 31e645c1f3a..31901707c35 100644 --- a/intern/cycles/scene/integrator.cpp +++ b/intern/cycles/scene/integrator.cpp @@ -180,7 +180,7 @@ void Integrator::device_update(Device *device, DeviceScene *dscene, Scene *scene kintegrator->transparent_min_bounce = transparent_min_bounce + 1; kintegrator->transparent_max_bounce = transparent_max_bounce + 1; - kintegrator->ao_bounces = ao_bounces; + kintegrator->ao_bounces = (ao_factor != 0.0f) ? ao_bounces : 0; kintegrator->ao_bounces_distance = ao_distance; kintegrator->ao_bounces_factor = ao_factor; kintegrator->ao_additive_factor = ao_additive_factor; diff --git a/intern/cycles/scene/object.cpp b/intern/cycles/scene/object.cpp index 69a2365f17c..f8110b20d6e 100644 --- a/intern/cycles/scene/object.cpp +++ b/intern/cycles/scene/object.cpp @@ -23,6 +23,7 @@ #include "scene/light.h" #include "scene/mesh.h" #include "scene/particles.h" +#include "scene/pointcloud.h" #include "scene/scene.h" #include "scene/stats.h" #include "scene/volume.h" @@ -69,6 +70,7 @@ struct UpdateObjectTransformState { /* Flags which will be synchronized to Integrator. */ bool have_motion; bool have_curves; + // bool have_points; /* ** Scheduling queue. ** */ Scene *scene; @@ -435,7 +437,7 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s state->have_motion = true; } - if (geom->geometry_type == Geometry::MESH) { + if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::POINTCLOUD) { /* TODO: why only mesh? */ Mesh *mesh = static_cast<Mesh *>(geom); if (mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION)) { @@ -491,6 +493,8 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s kobject.dupli_generated[2] = ob->dupli_generated[2]; kobject.numkeys = (geom->geometry_type == Geometry::HAIR) ? static_cast<Hair *>(geom)->get_curve_keys().size() : + (geom->geometry_type == Geometry::POINTCLOUD) ? + static_cast<PointCloud *>(geom)->num_points() : 0; kobject.dupli_uv[0] = ob->dupli_uv[0]; kobject.dupli_uv[1] = ob->dupli_uv[1]; @@ -530,6 +534,35 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s } } +void ObjectManager::device_update_prim_offsets(Device *device, DeviceScene *dscene, Scene *scene) +{ + BVHLayoutMask layout_mask = device->get_bvh_layout_mask(); + if (layout_mask != BVH_LAYOUT_METAL && layout_mask != BVH_LAYOUT_MULTI_METAL && + layout_mask != BVH_LAYOUT_MULTI_METAL_EMBREE) { + return; + } + + /* On MetalRT, primitive / curve segment offsets can't be baked at BVH build time. Intersection + * handlers need to apply the offset manually. */ + uint *object_prim_offset = dscene->object_prim_offset.alloc(scene->objects.size()); + foreach (Object *ob, scene->objects) { + uint32_t prim_offset = 0; + if (Geometry *const geom = ob->geometry) { + if (geom->geometry_type == Geometry::HAIR) { + prim_offset = ((Hair *const)geom)->curve_segment_offset; + } + else { + prim_offset = geom->prim_offset; + } + } + uint obj_index = ob->get_device_index(); + object_prim_offset[obj_index] = prim_offset; + } + + dscene->object_prim_offset.copy_to_device(); + dscene->object_prim_offset.clear_modified(); +} + void ObjectManager::device_update_transforms(DeviceScene *dscene, Scene *scene, Progress &progress) { UpdateObjectTransformState state; @@ -840,6 +873,7 @@ void ObjectManager::device_free(Device *, DeviceScene *dscene, bool force_free) dscene->object_motion.free_if_need_realloc(force_free); dscene->object_flag.free_if_need_realloc(force_free); dscene->object_volume_step.free_if_need_realloc(force_free); + dscene->object_prim_offset.free_if_need_realloc(force_free); } void ObjectManager::apply_static_transforms(DeviceScene *dscene, Scene *scene, Progress &progress) diff --git a/intern/cycles/scene/object.h b/intern/cycles/scene/object.h index f6dc57ee8b9..f983b58b59c 100644 --- a/intern/cycles/scene/object.h +++ b/intern/cycles/scene/object.h @@ -155,6 +155,7 @@ class ObjectManager { void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress); void device_update_transforms(DeviceScene *dscene, Scene *scene, Progress &progress); + void device_update_prim_offsets(Device *device, DeviceScene *dscene, Scene *scene); void device_update_flags(Device *device, DeviceScene *dscene, diff --git a/intern/cycles/scene/pointcloud.cpp b/intern/cycles/scene/pointcloud.cpp new file mode 100644 index 00000000000..4f88fe9db3d --- /dev/null +++ b/intern/cycles/scene/pointcloud.cpp @@ -0,0 +1,304 @@ +/* + * 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 "bvh/bvh.h" + +#include "scene/pointcloud.h" +#include "scene/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]); +} + +void PointCloud::Point::bounds_grow(const float4 &point, BoundBox &bounds) const +{ + bounds.grow(float4_to_float3(point), point.w); +} + +float4 PointCloud::Point::motion_key(const float3 *points, + const float *radius, + const float3 *point_steps, + size_t num_points, + size_t num_steps, + float time, + size_t p) 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. */ + const float4 curr_key = point_for_step( + points, radius, point_steps, num_points, num_steps, step, p); + const float4 next_key = point_for_step( + points, radius, point_steps, num_points, num_steps, step + 1, p); + /* Interpolate between steps. */ + return (1.0f - t) * curr_key + t * next_key; +} + +float4 PointCloud::Point::point_for_step(const float3 *points, + const float *radius, + const float3 *point_steps, + size_t num_points, + size_t num_steps, + size_t step, + size_t p) const +{ + const size_t center_step = ((num_steps - 1) / 2); + if (step == center_step) { + /* Center step: regular key location. */ + return make_float4(points[p].x, points[p].y, points[p].z, radius[p]); + } + else { + /* Center step is not stored in this array. */ + if (step > center_step) { + step--; + } + const size_t offset = step * num_points; + return make_float4(point_steps[offset + p].x, + point_steps[offset + p].y, + point_steps[offset + p].z, + radius[offset + p]); + } +} + +/* PointCloud */ + +NODE_DEFINE(PointCloud) +{ + NodeType *type = NodeType::add( + "pointcloud", create, NodeType::NONE, Geometry::get_node_base_type()); + + SOCKET_POINT_ARRAY(points, "Points", array<float3>()); + SOCKET_FLOAT_ARRAY(radius, "Radius", array<float>()); + SOCKET_INT_ARRAY(shader, "Shader", array<int>()); + + 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(); + + tag_points_modified(); + tag_radius_modified(); + tag_shader_modified(); +} + +void PointCloud::reserve(int numpoints) +{ + points.reserve(numpoints); + radius.reserve(numpoints); + shader.reserve(numpoints); + attributes.resize(true); +} + +void PointCloud::clear(const bool preserve_shaders) +{ + Geometry::clear(preserve_shaders); + + points.clear(); + radius.clear(); + shader.clear(); + attributes.clear(); + + tag_points_modified(); + tag_radius_modified(); + tag_shader_modified(); +} + +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); + + tag_points_modified(); + tag_radius_modified(); + tag_shader_modified(); +} + +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<int> &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 *point_steps = attr->data_float3(); + + for (size_t i = 0; i < steps_size; i++) + bnds.grow(point_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 *point_steps = attr->data_float3(); + + for (size_t i = 0; i < steps_size; i++) + bnds.grow_safe(point_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 *point_steps = attr->data_float4(); + + for (size_t i = 0; i < steps_size; i++) { + float3 co = transform_point(&tfm, float4_to_float3(point_steps[i])); + float radius = point_steps[i].w * scalar; + + /* scale for curve radius is only correct for uniform + * scale */ + point_steps[i] = float3_to_float4(co); + point_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()) ? + static_cast<Shader *>(used_shaders[last_shader]) : + scene->default_surface; + shader_id = scene->shader_manager->get_shader_id(shader); + } + packed_shader[i] = shader_id; + } +} + +PrimitiveType PointCloud::primitive_type() const +{ + return has_motion_blur() ? PRIMITIVE_MOTION_POINT : PRIMITIVE_POINT; +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/scene/pointcloud.h b/intern/cycles/scene/pointcloud.h new file mode 100644 index 00000000000..08987ee6c44 --- /dev/null +++ b/intern/cycles/scene/pointcloud.h @@ -0,0 +1,114 @@ +/* + * 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. + */ + +#pragma once + +#ifndef __POINTCLOUD_H__ +# define __POINTCLOUD_H__ + +# include "scene/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; + void bounds_grow(const float4 &point, BoundBox &bounds) const; + + float4 motion_key(const float3 *points, + const float *radius, + const float3 *point_steps, + size_t num_points, + size_t num_steps, + float time, + size_t p) const; + float4 point_for_step(const float3 *points, + const float *radius, + const float3 *point_steps, + size_t num_points, + size_t num_steps, + size_t step, + size_t p) const; + }; + + NODE_SOCKET_API_ARRAY(array<float3>, points) + NODE_SOCKET_API_ARRAY(array<float>, radius) + NODE_SOCKET_API_ARRAY(array<int>, shader) + + /* Constructor/Destructor */ + PointCloud(); + ~PointCloud(); + + /* Geometry */ + void clear(const bool preserver_shaders = false) 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(); + } + + size_t num_attributes() const + { + return 1; + } + + /* UDIM */ + void get_uv_tiles(ustring map, unordered_set<int> &tiles) override; + + PrimitiveType primitive_type() const override; + + /* BVH */ + void pack(Scene *scene, float4 *packed_points, uint *packed_shader); + + private: + friend class BVH2; + friend class BVHBuild; + friend class BVHSpatialSplit; + friend class DiagSplit; + friend class EdgeDice; + friend class GeometryManager; + friend class ObjectManager; +}; + +CCL_NAMESPACE_END + +#endif /* __POINTCLOUD_H__ */ diff --git a/intern/cycles/scene/scene.cpp b/intern/cycles/scene/scene.cpp index 4230abe9a1b..1963ebbbb19 100644 --- a/intern/cycles/scene/scene.cpp +++ b/intern/cycles/scene/scene.cpp @@ -30,6 +30,7 @@ #include "scene/object.h" #include "scene/osl.h" #include "scene/particles.h" +#include "scene/pointcloud.h" #include "scene/procedural.h" #include "scene/scene.h" #include "scene/shader.h" @@ -64,11 +65,14 @@ DeviceScene::DeviceScene(Device *device) curve_keys(device, "__curve_keys", MEM_GLOBAL), curve_segments(device, "__curve_segments", 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), object_flag(device, "__object_flag", MEM_GLOBAL), object_volume_step(device, "__object_volume_step", MEM_GLOBAL), + object_prim_offset(device, "__object_prim_offset", MEM_GLOBAL), camera_motion(device, "__camera_motion", MEM_GLOBAL), attributes_map(device, "__attributes_map", MEM_GLOBAL), attributes_float(device, "__attributes_float", MEM_GLOBAL), @@ -312,6 +316,12 @@ void Scene::device_update(Device *device_, Progress &progress) if (progress.get_cancel() || device->have_error()) return; + progress.set_status("Updating Primitive Offsets"); + object_manager->device_update_prim_offsets(device, &dscene, this); + + if (progress.get_cancel() || device->have_error()) + return; + progress.set_status("Updating Images"); image_manager->device_update(device, this, progress); @@ -516,6 +526,9 @@ void Scene::update_kernel_features() else if (geom->is_hair()) { kernel_features |= KERNEL_FEATURE_HAIR; } + else if (geom->is_pointcloud()) { + kernel_features |= KERNEL_FEATURE_POINTCLOUD; + } } if (bake_manager->get_baking()) { @@ -568,6 +581,7 @@ static void log_kernel_features(const uint features) VLOG(2) << "Use Path Tracing " << string_from_bool(features & KERNEL_FEATURE_PATH_TRACING) << "\n"; VLOG(2) << "Use Hair " << string_from_bool(features & KERNEL_FEATURE_HAIR) << "\n"; + VLOG(2) << "Use Pointclouds " << string_from_bool(features & KERNEL_FEATURE_POINTCLOUD) << "\n"; VLOG(2) << "Use Object Motion " << string_from_bool(features & KERNEL_FEATURE_OBJECT_MOTION) << "\n"; VLOG(2) << "Use Camera Motion " << string_from_bool(features & KERNEL_FEATURE_CAMERA_MOTION) @@ -750,6 +764,15 @@ template<> Volume *Scene::create_node<Volume>() return node; } +template<> PointCloud *Scene::create_node<PointCloud>() +{ + PointCloud *node = new PointCloud(); + node->set_owner(this); + geometry.push_back(node); + geometry_manager->tag_update(this, GeometryManager::POINT_ADDED); + return node; +} + template<> Object *Scene::create_node<Object>() { Object *node = new Object(); @@ -837,6 +860,12 @@ template<> void Scene::delete_node_impl(Volume *node) geometry_manager->tag_update(this, GeometryManager::MESH_REMOVED); } +template<> void Scene::delete_node_impl(PointCloud *node) +{ + delete_node_from_array(geometry, static_cast<Geometry *>(node)); + geometry_manager->tag_update(this, GeometryManager::POINT_REMOVED); +} + template<> void Scene::delete_node_impl(Geometry *node) { uint flag; diff --git a/intern/cycles/scene/scene.h b/intern/cycles/scene/scene.h index 4af05349dd3..ec935b41be6 100644 --- a/intern/cycles/scene/scene.h +++ b/intern/cycles/scene/scene.h @@ -54,6 +54,7 @@ class Object; class ObjectManager; class ParticleSystemManager; class ParticleSystem; +class PointCloud; class Procedural; class ProceduralManager; class CurveSystemManager; @@ -94,12 +95,17 @@ class DeviceScene { device_vector<uint> patches; + /* pointcloud */ + device_vector<float4> points; + device_vector<uint> points_shader; + /* objects */ device_vector<KernelObject> objects; device_vector<Transform> object_motion_pass; device_vector<DecomposedTransform> object_motion; device_vector<uint> object_flag; device_vector<float> object_volume_step; + device_vector<uint> object_prim_offset; /* cameras */ device_vector<DecomposedTransform> camera_motion; @@ -364,6 +370,8 @@ template<> Hair *Scene::create_node<Hair>(); template<> Volume *Scene::create_node<Volume>(); +template<> PointCloud *Scene::create_node<PointCloud>(); + template<> ParticleSystem *Scene::create_node<ParticleSystem>(); template<> Shader *Scene::create_node<Shader>(); @@ -378,6 +386,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); diff --git a/intern/cycles/scene/shader_nodes.cpp b/intern/cycles/scene/shader_nodes.cpp index 8c20807a52b..c345d5bbc9a 100644 --- a/intern/cycles/scene/shader_nodes.cpp +++ b/intern/cycles/scene/shader_nodes.cpp @@ -2399,7 +2399,7 @@ void GlossyBsdfNode::simplify_settings(Scene *scene) ShaderInput *roughness_input = input("Roughness"); if (integrator->get_filter_glossy() == 0.0f) { /* Fallback to Sharp closure for Roughness close to 0. - * Note: Keep the epsilon in sync with kernel! + * NOTE: Keep the epsilon in sync with kernel! */ if (!roughness_input->link && roughness <= 1e-4f) { VLOG(3) << "Using sharp glossy BSDF."; @@ -2492,7 +2492,7 @@ void GlassBsdfNode::simplify_settings(Scene *scene) ShaderInput *roughness_input = input("Roughness"); if (integrator->get_filter_glossy() == 0.0f) { /* Fallback to Sharp closure for Roughness close to 0. - * Note: Keep the epsilon in sync with kernel! + * NOTE: Keep the epsilon in sync with kernel! */ if (!roughness_input->link && roughness <= 1e-4f) { VLOG(3) << "Using sharp glass BSDF."; @@ -2585,7 +2585,7 @@ void RefractionBsdfNode::simplify_settings(Scene *scene) ShaderInput *roughness_input = input("Roughness"); if (integrator->get_filter_glossy() == 0.0f) { /* Fallback to Sharp closure for Roughness close to 0. - * Note: Keep the epsilon in sync with kernel! + * NOTE: Keep the epsilon in sync with kernel! */ if (!roughness_input->link && roughness <= 1e-4f) { VLOG(3) << "Using sharp refraction BSDF."; @@ -5871,6 +5871,73 @@ void MapRangeNode::compile(OSLCompiler &compiler) compiler.add(this, "node_map_range"); } +/* Vector Map Range Node */ + +NODE_DEFINE(VectorMapRangeNode) +{ + NodeType *type = NodeType::add("vector_map_range", create, NodeType::SHADER); + + static NodeEnum type_enum; + type_enum.insert("linear", NODE_MAP_RANGE_LINEAR); + type_enum.insert("stepped", NODE_MAP_RANGE_STEPPED); + type_enum.insert("smoothstep", NODE_MAP_RANGE_SMOOTHSTEP); + type_enum.insert("smootherstep", NODE_MAP_RANGE_SMOOTHERSTEP); + SOCKET_ENUM(range_type, "Type", type_enum, NODE_MAP_RANGE_LINEAR); + + SOCKET_IN_VECTOR(vector, "Vector", zero_float3()); + SOCKET_IN_VECTOR(from_min, "From_Min_FLOAT3", zero_float3()); + SOCKET_IN_VECTOR(from_max, "From_Max_FLOAT3", one_float3()); + SOCKET_IN_VECTOR(to_min, "To_Min_FLOAT3", zero_float3()); + SOCKET_IN_VECTOR(to_max, "To_Max_FLOAT3", one_float3()); + SOCKET_IN_VECTOR(steps, "Steps_FLOAT3", make_float3(4.0f)); + SOCKET_BOOLEAN(use_clamp, "Use Clamp", false); + + SOCKET_OUT_VECTOR(vector, "Vector"); + + return type; +} + +VectorMapRangeNode::VectorMapRangeNode() : ShaderNode(get_node_type()) +{ +} + +void VectorMapRangeNode::expand(ShaderGraph *graph) +{ +} + +void VectorMapRangeNode::compile(SVMCompiler &compiler) +{ + ShaderInput *vector_in = input("Vector"); + ShaderInput *from_min_in = input("From_Min_FLOAT3"); + ShaderInput *from_max_in = input("From_Max_FLOAT3"); + ShaderInput *to_min_in = input("To_Min_FLOAT3"); + ShaderInput *to_max_in = input("To_Max_FLOAT3"); + ShaderInput *steps_in = input("Steps_FLOAT3"); + ShaderOutput *vector_out = output("Vector"); + + int value_stack_offset = compiler.stack_assign(vector_in); + int from_min_stack_offset = compiler.stack_assign(from_min_in); + int from_max_stack_offset = compiler.stack_assign(from_max_in); + int to_min_stack_offset = compiler.stack_assign(to_min_in); + int to_max_stack_offset = compiler.stack_assign(to_max_in); + int steps_stack_offset = compiler.stack_assign(steps_in); + int result_stack_offset = compiler.stack_assign(vector_out); + + compiler.add_node( + NODE_VECTOR_MAP_RANGE, + value_stack_offset, + compiler.encode_uchar4( + from_min_stack_offset, from_max_stack_offset, to_min_stack_offset, to_max_stack_offset), + compiler.encode_uchar4(steps_stack_offset, use_clamp, range_type, result_stack_offset)); +} + +void VectorMapRangeNode::compile(OSLCompiler &compiler) +{ + compiler.parameter(this, "range_type"); + compiler.parameter(this, "use_clamp"); + compiler.add(this, "node_vector_map_range"); +} + /* Clamp Node */ NODE_DEFINE(ClampNode) diff --git a/intern/cycles/scene/shader_nodes.h b/intern/cycles/scene/shader_nodes.h index 64a2b1c7843..0faefd3041f 100644 --- a/intern/cycles/scene/shader_nodes.h +++ b/intern/cycles/scene/shader_nodes.h @@ -1263,6 +1263,21 @@ class BlackbodyNode : public ShaderNode { NODE_SOCKET_API(float, temperature) }; +class VectorMapRangeNode : public ShaderNode { + public: + SHADER_NODE_CLASS(VectorMapRangeNode) + void expand(ShaderGraph *graph); + + NODE_SOCKET_API(float3, vector) + NODE_SOCKET_API(float3, from_min) + NODE_SOCKET_API(float3, from_max) + NODE_SOCKET_API(float3, to_min) + NODE_SOCKET_API(float3, to_max) + NODE_SOCKET_API(float3, steps) + NODE_SOCKET_API(NodeMapRangeType, range_type) + NODE_SOCKET_API(bool, use_clamp) +}; + class MapRangeNode : public ShaderNode { public: SHADER_NODE_CLASS(MapRangeNode) |