Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'intern/cycles/scene')
-rw-r--r--intern/cycles/scene/CMakeLists.txt2
-rw-r--r--intern/cycles/scene/alembic.cpp87
-rw-r--r--intern/cycles/scene/alembic.h10
-rw-r--r--intern/cycles/scene/alembic_read.cpp49
-rw-r--r--intern/cycles/scene/alembic_read.h20
-rw-r--r--intern/cycles/scene/attribute.cpp33
-rw-r--r--intern/cycles/scene/camera.cpp10
-rw-r--r--intern/cycles/scene/camera.h6
-rw-r--r--intern/cycles/scene/geometry.cpp97
-rw-r--r--intern/cycles/scene/geometry.h12
-rw-r--r--intern/cycles/scene/integrator.cpp2
-rw-r--r--intern/cycles/scene/object.cpp36
-rw-r--r--intern/cycles/scene/object.h1
-rw-r--r--intern/cycles/scene/pointcloud.cpp304
-rw-r--r--intern/cycles/scene/pointcloud.h114
-rw-r--r--intern/cycles/scene/scene.cpp29
-rw-r--r--intern/cycles/scene/scene.h10
-rw-r--r--intern/cycles/scene/shader_nodes.cpp73
-rw-r--r--intern/cycles/scene/shader_nodes.h15
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)