Blender  V3.3
blender/pointcloud.cpp
Go to the documentation of this file.
1 /* SPDX-License-Identifier: Apache-2.0
2  * Copyright 2011-2022 Blender Foundation */
3 
4 #include <optional>
5 
6 #include "scene/attribute.h"
7 #include "scene/pointcloud.h"
8 #include "scene/scene.h"
9 
10 #include "blender/sync.h"
11 #include "blender/util.h"
12 
13 #include "util/foreach.h"
14 #include "util/hash.h"
15 
17 
18 template<typename TypeInCycles, typename GetValueAtIndex>
19 static void fill_generic_attribute(BL::PointCloud &b_pointcloud,
20  TypeInCycles *data,
21  const GetValueAtIndex &get_value_at_index)
22 {
23  const int num_points = b_pointcloud.points.length();
24  for (int i = 0; i < num_points; i++) {
25  data[i] = get_value_at_index(i);
26  }
27 }
28 
29 static void attr_create_motion(PointCloud *pointcloud,
30  BL::Attribute &b_attribute,
31  const float motion_scale)
32 {
33  if (!(b_attribute.domain() == BL::Attribute::domain_POINT) &&
34  (b_attribute.data_type() == BL::Attribute::data_type_FLOAT_VECTOR)) {
35  return;
36  }
37 
38  BL::FloatVectorAttribute b_vector_attribute(b_attribute);
39  const int num_points = pointcloud->get_points().size();
40 
41  /* Find or add attribute */
42  float3 *P = &pointcloud->get_points()[0];
44 
45  if (!attr_mP) {
46  attr_mP = pointcloud->attributes.add(ATTR_STD_MOTION_VERTEX_POSITION);
47  }
48 
49  /* Only export previous and next frame, we don't have any in between data. */
50  float motion_times[2] = {-1.0f, 1.0f};
51  for (int step = 0; step < 2; step++) {
52  const float relative_time = motion_times[step] * 0.5f * motion_scale;
53  float3 *mP = attr_mP->data_float3() + step * num_points;
54 
55  for (int i = 0; i < num_points; i++) {
56  mP[i] = P[i] + get_float3(b_vector_attribute.data[i].vector()) * relative_time;
57  }
58  }
59 }
60 
61 static void copy_attributes(PointCloud *pointcloud,
62  BL::PointCloud b_pointcloud,
63  const bool need_motion,
64  const float motion_scale)
65 {
66  AttributeSet &attributes = pointcloud->attributes;
67  static const ustring u_velocity("velocity");
68  for (BL::Attribute &b_attribute : b_pointcloud.attributes) {
69  const ustring name{b_attribute.name().c_str()};
70 
71  if (need_motion && name == u_velocity) {
72  attr_create_motion(pointcloud, b_attribute, motion_scale);
73  }
74 
75  if (attributes.find(name)) {
76  continue;
77  }
78 
80  const BL::Attribute::data_type_enum b_data_type = b_attribute.data_type();
81  switch (b_data_type) {
82  case BL::Attribute::data_type_FLOAT: {
83  BL::FloatAttribute b_float_attribute{b_attribute};
84  Attribute *attr = attributes.add(name, TypeFloat, element);
85  float *data = attr->data_float();
87  b_pointcloud, data, [&](int i) { return b_float_attribute.data[i].value(); });
88  break;
89  }
90  case BL::Attribute::data_type_BOOLEAN: {
91  BL::BoolAttribute b_bool_attribute{b_attribute};
92  Attribute *attr = attributes.add(name, TypeFloat, element);
93  float *data = attr->data_float();
95  b_pointcloud, data, [&](int i) { return (float)b_bool_attribute.data[i].value(); });
96  break;
97  }
98  case BL::Attribute::data_type_INT: {
99  BL::IntAttribute b_int_attribute{b_attribute};
100  Attribute *attr = attributes.add(name, TypeFloat, element);
101  float *data = attr->data_float();
103  b_pointcloud, data, [&](int i) { return (float)b_int_attribute.data[i].value(); });
104  break;
105  }
106  case BL::Attribute::data_type_FLOAT_VECTOR: {
107  BL::FloatVectorAttribute b_vector_attribute{b_attribute};
108  Attribute *attr = attributes.add(name, TypeVector, element);
109  float3 *data = attr->data_float3();
110  fill_generic_attribute(b_pointcloud, data, [&](int i) {
111  BL::Array<float, 3> v = b_vector_attribute.data[i].vector();
112  return make_float3(v[0], v[1], v[2]);
113  });
114  break;
115  }
116  case BL::Attribute::data_type_FLOAT_COLOR: {
117  BL::FloatColorAttribute b_color_attribute{b_attribute};
118  Attribute *attr = attributes.add(name, TypeRGBA, element);
119  float4 *data = attr->data_float4();
120  fill_generic_attribute(b_pointcloud, data, [&](int i) {
121  BL::Array<float, 4> v = b_color_attribute.data[i].color();
122  return make_float4(v[0], v[1], v[2], v[3]);
123  });
124  break;
125  }
126  case BL::Attribute::data_type_FLOAT2: {
127  BL::Float2Attribute b_float2_attribute{b_attribute};
128  Attribute *attr = attributes.add(name, TypeFloat2, element);
129  float2 *data = attr->data_float2();
130  fill_generic_attribute(b_pointcloud, data, [&](int i) {
131  BL::Array<float, 2> v = b_float2_attribute.data[i].vector();
132  return make_float2(v[0], v[1]);
133  });
134  break;
135  }
136  default:
137  /* Not supported. */
138  break;
139  }
140  }
141 }
142 
143 static std::optional<BL::FloatAttribute> find_radius_attribute(BL::PointCloud b_pointcloud)
144 {
145  for (BL::Attribute &b_attribute : b_pointcloud.attributes) {
146  if (b_attribute.name() != "radius") {
147  continue;
148  }
149  if (b_attribute.data_type() != BL::Attribute::data_type_FLOAT) {
150  continue;
151  }
152  return BL::FloatAttribute{b_attribute};
153  }
154  return std::nullopt;
155 }
156 
157 static BL::FloatVectorAttribute find_position_attribute(BL::PointCloud b_pointcloud)
158 {
159  for (BL::Attribute &b_attribute : b_pointcloud.attributes) {
160  if (b_attribute.name() != "position") {
161  continue;
162  }
163  if (b_attribute.data_type() != BL::Attribute::data_type_FLOAT_VECTOR) {
164  continue;
165  }
166  return BL::FloatVectorAttribute{b_attribute};
167  }
168  /* The position attribute must exist. */
169  assert(false);
170  return BL::FloatVectorAttribute{b_pointcloud.attributes[0]};
171 }
172 
174  PointCloud *pointcloud,
175  BL::PointCloud b_pointcloud,
176  const bool need_motion,
177  const float motion_scale)
178 {
179  /* TODO: optimize so we can straight memcpy arrays from Blender? */
180 
181  /* Add requested attributes. */
182  Attribute *attr_random = NULL;
183  if (pointcloud->need_attribute(scene, ATTR_STD_POINT_RANDOM)) {
184  attr_random = pointcloud->attributes.add(ATTR_STD_POINT_RANDOM);
185  }
186 
187  /* Reserve memory. */
188  const int num_points = b_pointcloud.points.length();
189  pointcloud->reserve(num_points);
190 
191  BL::FloatVectorAttribute b_attr_position = find_position_attribute(b_pointcloud);
192  std::optional<BL::FloatAttribute> b_attr_radius = find_radius_attribute(b_pointcloud);
193 
194  /* Export points. */
195  for (int i = 0; i < num_points; i++) {
196  const float3 co = get_float3(b_attr_position.data[i].vector());
197  const float radius = b_attr_radius ? b_attr_radius->data[i].value() : 0.0f;
198  pointcloud->add_point(co, radius);
199 
200  /* Random number per point. */
201  if (attr_random != NULL) {
202  attr_random->add(hash_uint2_to_float(i, 0));
203  }
204  }
205 
206  /* Export attributes */
207  copy_attributes(pointcloud, b_pointcloud, need_motion, motion_scale);
208 }
209 
210 static void export_pointcloud_motion(PointCloud *pointcloud,
211  BL::PointCloud b_pointcloud,
212  int motion_step)
213 {
214  /* Find or add attribute. */
216  bool new_attribute = false;
217 
218  if (!attr_mP) {
219  attr_mP = pointcloud->attributes.add(ATTR_STD_MOTION_VERTEX_POSITION);
220  new_attribute = true;
221  }
222 
223  /* Export motion points. */
224  const int num_points = pointcloud->num_points();
225  float3 *mP = attr_mP->data_float3() + motion_step * num_points;
226  bool have_motion = false;
227  const array<float3> &pointcloud_points = pointcloud->get_points();
228 
229  const int b_points_num = b_pointcloud.points.length();
230  BL::FloatVectorAttribute b_attr_position = find_position_attribute(b_pointcloud);
231  std::optional<BL::FloatAttribute> b_attr_radius = find_radius_attribute(b_pointcloud);
232 
233  for (int i = 0; i < std::min(num_points, b_points_num); i++) {
234  const float3 co = get_float3(b_attr_position.data[i].vector());
235  const float radius = b_attr_radius ? b_attr_radius->data[i].value() : 0.0f;
236  float3 P = co;
237  P.w = radius;
238  mP[i] = P;
239  have_motion = have_motion || (P != pointcloud_points[i]);
240  }
241 
242  /* In case of new attribute, we verify if there really was any motion. */
243  if (new_attribute) {
244  if (b_points_num != num_points || !have_motion) {
246  }
247  else if (motion_step > 0) {
248  /* Motion, fill up previous steps that we might have skipped because
249  * they had no motion, but we need them anyway now. */
250  for (int step = 0; step < motion_step; step++) {
251  pointcloud->copy_center_to_motion_step(step);
252  }
253  }
254  }
255 
256  /* Export attributes */
257  copy_attributes(pointcloud, b_pointcloud, false, 0.0f);
258 }
259 
260 void BlenderSync::sync_pointcloud(PointCloud *pointcloud, BObjectInfo &b_ob_info)
261 {
262  size_t old_numpoints = pointcloud->num_points();
263 
264  array<Node *> used_shaders = pointcloud->get_used_shaders();
265 
266  PointCloud new_pointcloud;
267  new_pointcloud.set_used_shaders(used_shaders);
268 
269  /* TODO: add option to filter out points in the view layer. */
270  BL::PointCloud b_pointcloud(b_ob_info.object_data);
271  /* Motion blur attribute is relative to seconds, we need it relative to frames. */
272  const bool need_motion = object_need_motion_attribute(b_ob_info, scene);
273  const float motion_scale = (need_motion) ?
274  scene->motion_shutter_time() /
275  (b_scene.render().fps() / b_scene.render().fps_base()) :
276  0.0f;
277  export_pointcloud(scene, &new_pointcloud, b_pointcloud, need_motion, motion_scale);
278 
279  /* update original sockets */
280  for (const SocketType &socket : new_pointcloud.type->inputs) {
281  /* Those sockets are updated in sync_object, so do not modify them. */
282  if (socket.name == "use_motion_blur" || socket.name == "motion_steps" ||
283  socket.name == "used_shaders") {
284  continue;
285  }
286  pointcloud->set_value(socket, new_pointcloud, socket);
287  }
288 
289  pointcloud->attributes.clear();
290  foreach (Attribute &attr, new_pointcloud.attributes.attributes) {
291  pointcloud->attributes.attributes.push_back(std::move(attr));
292  }
293 
294  /* tag update */
295  const bool rebuild = (pointcloud && old_numpoints != pointcloud->num_points());
296  pointcloud->tag_update(scene, rebuild);
297 }
298 
299 void BlenderSync::sync_pointcloud_motion(PointCloud *pointcloud,
300  BObjectInfo &b_ob_info,
301  int motion_step)
302 {
303  /* Skip if nothing exported. */
304  if (pointcloud->num_points() == 0) {
305  return;
306  }
307 
308  /* Export deformed coordinates. */
309  if (ccl::BKE_object_is_deform_modified(b_ob_info, b_scene, preview)) {
310  /* PointCloud object. */
311  BL::PointCloud b_pointcloud(b_ob_info.object_data);
312  export_pointcloud_motion(pointcloud, b_pointcloud, motion_step);
313  }
314  else {
315  /* No deformation on this frame, copy coordinates if other frames did have it. */
316  pointcloud->copy_center_to_motion_step(motion_step);
317  }
318 }
319 
int BKE_object_is_deform_modified(struct Scene *scene, struct Object *ob)
Definition: object.cc:4982
struct PointCloud PointCloud
float float4[4]
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Sky Generate a procedural sky texture Noise Generate fractal Perlin noise Wave Generate procedural bands or rings with noise Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a or normal between and object coordinate space Combine Create a color from its and value channels Color Attribute
static void export_pointcloud_motion(PointCloud *pointcloud, BL::PointCloud b_pointcloud, int motion_step)
static std::optional< BL::FloatAttribute > find_radius_attribute(BL::PointCloud b_pointcloud)
static BL::FloatVectorAttribute find_position_attribute(BL::PointCloud b_pointcloud)
static void export_pointcloud(Scene *scene, PointCloud *pointcloud, BL::PointCloud b_pointcloud, const bool need_motion, const float motion_scale)
static CCL_NAMESPACE_BEGIN void fill_generic_attribute(BL::PointCloud &b_pointcloud, TypeInCycles *data, const GetValueAtIndex &get_value_at_index)
static void copy_attributes(PointCloud *pointcloud, BL::PointCloud b_pointcloud, const bool need_motion, const float motion_scale)
static void attr_create_motion(PointCloud *pointcloud, BL::Attribute &b_attribute, const float motion_scale)
ATTR_WARN_UNUSED_RESULT const void * element
ATTR_WARN_UNUSED_RESULT const BMVert * v
Attribute * add(ustring name, TypeDesc type, AttributeElement element)
list< Attribute > attributes
Attribute * find(ustring name) const
void remove(ustring name)
void clear(bool preserve_voxel_data=false)
float * data_float()
float4 * data_float4()
void add(const float &f)
float3 * data_float3()
float2 * data_float2()
bool need_attribute(Scene *scene, AttributeStandard std)
void tag_update(Scene *scene, bool rebuild)
AttributeSet attributes
#define CCL_NAMESPACE_END
Definition: cuda/compat.h:9
static float3 get_float3(const BL::Array< float, 2 > &array)
static bool object_need_motion_attribute(BObjectInfo &b_ob_info, Scene *scene)
Scene scene
ccl_device_inline float hash_uint2_to_float(uint kx, uint ky)
Definition: hash.h:122
@ ATTR_STD_POINT_RANDOM
Definition: kernel/types.h:630
@ ATTR_STD_MOTION_VERTEX_POSITION
Definition: kernel/types.h:624
AttributeElement
Definition: kernel/types.h:597
@ ATTR_ELEMENT_VERTEX
Definition: kernel/types.h:602
static float P(float k)
Definition: math_interp.c:25
#define make_float2(x, y)
Definition: metal/compat.h:203
#define make_float4(x, y, z, w)
Definition: metal/compat.h:205
#define make_float3(x, y, z)
Definition: metal/compat.h:204
static constexpr TypeDesc TypeRGBA(TypeDesc::FLOAT, TypeDesc::VEC4, TypeDesc::COLOR)
CCL_NAMESPACE_BEGIN static constexpr OIIO_NAMESPACE_USING TypeDesc TypeFloat2(TypeDesc::FLOAT, TypeDesc::VEC2)
#define min(a, b)
Definition: sort.c:35
vector< SocketType, std::allocator< SocketType > > inputs
Definition: node_type.h:118
const NodeType * type
Definition: graph/node.h:175
void set_value(const SocketType &input, const Node &other, const SocketType &other_input)
Definition: graph/node.cpp:388
void reserve(int numpoints)
size_t num_points() const
void copy_center_to_motion_step(const int motion_step)
void add_point(float3 loc, float radius, int shader=0)
float motion_shutter_time()
Definition: scene.cpp:397
ustring name
Definition: node_type.h:72