Blender  V3.3
blender/curves.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 "blender/sync.h"
7 #include "blender/util.h"
8 
9 #include "scene/attribute.h"
10 #include "scene/camera.h"
11 #include "scene/curves.h"
12 #include "scene/hair.h"
13 #include "scene/object.h"
14 #include "scene/scene.h"
15 
16 #include "util/color.h"
17 #include "util/foreach.h"
18 #include "util/hash.h"
19 #include "util/log.h"
20 
22 
24 {
25 }
26 
28 {
29 }
30 
31 static float shaperadius(float shape, float root, float tip, float time)
32 {
33  assert(time >= 0.0f);
34  assert(time <= 1.0f);
35  float radius = 1.0f - time;
36 
37  if (shape != 0.0f) {
38  if (shape < 0.0f)
39  radius = powf(radius, 1.0f + shape);
40  else
41  radius = powf(radius, 1.0f / (1.0f - shape));
42  }
43  return (radius * (root - tip)) + tip;
44 }
45 
46 /* curve functions */
47 
49  Hair *hair, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background)
50 {
51  int curvenum = 0;
52  int keyno = 0;
53 
54  if (!(hair && b_mesh && b_ob && CData))
55  return false;
56 
57  Transform tfm = get_transform(b_ob->matrix_world());
58  Transform itfm = transform_inverse(tfm);
59 
60  for (BL::Modifier &b_mod : b_ob->modifiers) {
61  if ((b_mod.type() == b_mod.type_PARTICLE_SYSTEM) &&
62  (background ? b_mod.show_render() : b_mod.show_viewport())) {
63  BL::ParticleSystemModifier psmd((const PointerRNA)b_mod.ptr);
64  BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
65  BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
66 
67  if ((b_part.render_type() == BL::ParticleSettings::render_type_PATH) &&
68  (b_part.type() == BL::ParticleSettings::type_HAIR)) {
69  int shader = clamp(b_part.material() - 1, 0, hair->get_used_shaders().size() - 1);
70  int display_step = background ? b_part.render_step() : b_part.display_step();
71  int totparts = b_psys.particles.length();
72  int totchild = background ? b_psys.child_particles.length() :
73  (int)((float)b_psys.child_particles.length() *
74  (float)b_part.display_percentage() / 100.0f);
75  int totcurves = totchild;
76 
77  if (b_part.child_type() == 0 || totchild == 0)
78  totcurves += totparts;
79 
80  if (totcurves == 0)
81  continue;
82 
83  int ren_step = (1 << display_step) + 1;
84  if (b_part.kink() == BL::ParticleSettings::kink_SPIRAL)
85  ren_step += b_part.kink_extra_steps();
86 
87  CData->psys_firstcurve.push_back_slow(curvenum);
88  CData->psys_curvenum.push_back_slow(totcurves);
89  CData->psys_shader.push_back_slow(shader);
90 
91  float radius = b_part.radius_scale() * 0.5f;
92 
93  CData->psys_rootradius.push_back_slow(radius * b_part.root_radius());
94  CData->psys_tipradius.push_back_slow(radius * b_part.tip_radius());
95  CData->psys_shape.push_back_slow(b_part.shape());
96  CData->psys_closetip.push_back_slow(b_part.use_close_tip());
97 
98  int pa_no = 0;
99  if (!(b_part.child_type() == 0) && totchild != 0)
100  pa_no = totparts;
101 
102  int num_add = (totparts + totchild - pa_no);
103  CData->curve_firstkey.reserve(CData->curve_firstkey.size() + num_add);
104  CData->curve_keynum.reserve(CData->curve_keynum.size() + num_add);
105  CData->curve_length.reserve(CData->curve_length.size() + num_add);
106  CData->curvekey_co.reserve(CData->curvekey_co.size() + num_add * ren_step);
107  CData->curvekey_time.reserve(CData->curvekey_time.size() + num_add * ren_step);
108 
109  for (; pa_no < totparts + totchild; pa_no++) {
110  int keynum = 0;
111  CData->curve_firstkey.push_back_slow(keyno);
112 
113  float curve_length = 0.0f;
114  float3 prev_co_world = zero_float3();
115  float3 prev_co_object = zero_float3();
116  for (int step_no = 0; step_no < ren_step; step_no++) {
117  float3 co_world = prev_co_world;
118  b_psys.co_hair(*b_ob, pa_no, step_no, &co_world.x);
119  float3 co_object = transform_point(&itfm, co_world);
120  if (step_no > 0) {
121  const float step_length = len(co_object - prev_co_object);
122  curve_length += step_length;
123  }
124  CData->curvekey_co.push_back_slow(co_object);
125  CData->curvekey_time.push_back_slow(curve_length);
126  prev_co_object = co_object;
127  prev_co_world = co_world;
128  keynum++;
129  }
130  keyno += keynum;
131 
132  CData->curve_keynum.push_back_slow(keynum);
133  CData->curve_length.push_back_slow(curve_length);
134  curvenum++;
135  }
136  }
137  }
138  }
139 
140  return true;
141 }
142 
143 static bool ObtainCacheParticleUV(Hair *hair,
144  BL::Mesh *b_mesh,
145  BL::Object *b_ob,
146  ParticleCurveData *CData,
147  bool background,
148  int uv_num)
149 {
150  if (!(hair && b_mesh && b_ob && CData))
151  return false;
152 
153  CData->curve_uv.clear();
154 
155  for (BL::Modifier &b_mod : b_ob->modifiers) {
156  if ((b_mod.type() == b_mod.type_PARTICLE_SYSTEM) &&
157  (background ? b_mod.show_render() : b_mod.show_viewport())) {
158  BL::ParticleSystemModifier psmd((const PointerRNA)b_mod.ptr);
159  BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
160  BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
161 
162  if ((b_part.render_type() == BL::ParticleSettings::render_type_PATH) &&
163  (b_part.type() == BL::ParticleSettings::type_HAIR)) {
164  int totparts = b_psys.particles.length();
165  int totchild = background ? b_psys.child_particles.length() :
166  (int)((float)b_psys.child_particles.length() *
167  (float)b_part.display_percentage() / 100.0f);
168  int totcurves = totchild;
169 
170  if (b_part.child_type() == 0 || totchild == 0)
171  totcurves += totparts;
172 
173  if (totcurves == 0)
174  continue;
175 
176  int pa_no = 0;
177  if (!(b_part.child_type() == 0) && totchild != 0)
178  pa_no = totparts;
179 
180  int num_add = (totparts + totchild - pa_no);
181  CData->curve_uv.reserve(CData->curve_uv.size() + num_add);
182 
183  BL::ParticleSystem::particles_iterator b_pa;
184  b_psys.particles.begin(b_pa);
185  for (; pa_no < totparts + totchild; pa_no++) {
186  /* Add UVs */
187  BL::Mesh::uv_layers_iterator l;
188  b_mesh->uv_layers.begin(l);
189 
190  float2 uv = zero_float2();
191  if (!b_mesh->uv_layers.empty())
192  b_psys.uv_on_emitter(psmd, *b_pa, pa_no, uv_num, &uv.x);
193  CData->curve_uv.push_back_slow(uv);
194 
195  if (pa_no < totparts && b_pa != b_psys.particles.end())
196  ++b_pa;
197  }
198  }
199  }
200  }
201 
202  return true;
203 }
204 
205 static bool ObtainCacheParticleVcol(Hair *hair,
206  BL::Mesh *b_mesh,
207  BL::Object *b_ob,
208  ParticleCurveData *CData,
209  bool background,
210  int vcol_num)
211 {
212  if (!(hair && b_mesh && b_ob && CData))
213  return false;
214 
215  CData->curve_vcol.clear();
216 
217  for (BL::Modifier &b_mod : b_ob->modifiers) {
218  if ((b_mod.type() == b_mod.type_PARTICLE_SYSTEM) &&
219  (background ? b_mod.show_render() : b_mod.show_viewport())) {
220  BL::ParticleSystemModifier psmd((const PointerRNA)b_mod.ptr);
221  BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
222  BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
223 
224  if ((b_part.render_type() == BL::ParticleSettings::render_type_PATH) &&
225  (b_part.type() == BL::ParticleSettings::type_HAIR)) {
226  int totparts = b_psys.particles.length();
227  int totchild = background ? b_psys.child_particles.length() :
228  (int)((float)b_psys.child_particles.length() *
229  (float)b_part.display_percentage() / 100.0f);
230  int totcurves = totchild;
231 
232  if (b_part.child_type() == 0 || totchild == 0)
233  totcurves += totparts;
234 
235  if (totcurves == 0)
236  continue;
237 
238  int pa_no = 0;
239  if (!(b_part.child_type() == 0) && totchild != 0)
240  pa_no = totparts;
241 
242  int num_add = (totparts + totchild - pa_no);
243  CData->curve_vcol.reserve(CData->curve_vcol.size() + num_add);
244 
245  BL::ParticleSystem::particles_iterator b_pa;
246  b_psys.particles.begin(b_pa);
247  for (; pa_no < totparts + totchild; pa_no++) {
248  /* Add vertex colors */
249  BL::Mesh::vertex_colors_iterator l;
250  b_mesh->vertex_colors.begin(l);
251 
252  float4 vcol = make_float4(0.0f, 0.0f, 0.0f, 1.0f);
253  if (!b_mesh->vertex_colors.empty())
254  b_psys.mcol_on_emitter(psmd, *b_pa, pa_no, vcol_num, &vcol.x);
255  CData->curve_vcol.push_back_slow(vcol);
256 
257  if (pa_no < totparts && b_pa != b_psys.particles.end())
258  ++b_pa;
259  }
260  }
261  }
262  }
263 
264  return true;
265 }
266 
268 {
269  int num_keys = 0;
270  int num_curves = 0;
271 
272  if (hair->num_curves())
273  return;
274 
275  Attribute *attr_intercept = NULL;
276  Attribute *attr_length = NULL;
277  Attribute *attr_random = NULL;
278 
280  attr_intercept = hair->attributes.add(ATTR_STD_CURVE_INTERCEPT);
282  attr_length = hair->attributes.add(ATTR_STD_CURVE_LENGTH);
284  attr_random = hair->attributes.add(ATTR_STD_CURVE_RANDOM);
285 
286  /* compute and reserve size of arrays */
287  for (int sys = 0; sys < CData->psys_firstcurve.size(); sys++) {
288  for (int curve = CData->psys_firstcurve[sys];
289  curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys];
290  curve++) {
291  num_keys += CData->curve_keynum[curve];
292  num_curves++;
293  }
294  }
295 
296  hair->reserve_curves(hair->num_curves() + num_curves, hair->get_curve_keys().size() + num_keys);
297 
298  num_keys = 0;
299  num_curves = 0;
300 
301  /* actually export */
302  for (int sys = 0; sys < CData->psys_firstcurve.size(); sys++) {
303  for (int curve = CData->psys_firstcurve[sys];
304  curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys];
305  curve++) {
306  size_t num_curve_keys = 0;
307 
308  for (int curvekey = CData->curve_firstkey[curve];
309  curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve];
310  curvekey++) {
311  const float3 ickey_loc = CData->curvekey_co[curvekey];
312  const float curve_time = CData->curvekey_time[curvekey];
313  const float curve_length = CData->curve_length[curve];
314  const float time = (curve_length > 0.0f) ? curve_time / curve_length : 0.0f;
315  float radius = shaperadius(
316  CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time);
317  if (CData->psys_closetip[sys] &&
318  (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)) {
319  radius = 0.0f;
320  }
321  hair->add_curve_key(ickey_loc, radius);
322  if (attr_intercept)
323  attr_intercept->add(time);
324 
325  num_curve_keys++;
326  }
327 
328  if (attr_length != NULL) {
329  attr_length->add(CData->curve_length[curve]);
330  }
331 
332  if (attr_random != NULL) {
333  attr_random->add(hash_uint2_to_float(num_curves, 0));
334  }
335 
336  hair->add_curve(num_keys, CData->psys_shader[sys]);
337  num_keys += num_curve_keys;
338  num_curves++;
339  }
340  }
341 
342  /* check allocation */
343  if ((hair->get_curve_keys().size() != num_keys) || (hair->num_curves() != num_curves)) {
344  VLOG_WARNING << "Hair memory allocation failed, clearing data.";
345  hair->clear(true);
346  }
347 }
348 
349 static float4 CurveSegmentMotionCV(ParticleCurveData *CData, int sys, int curve, int curvekey)
350 {
351  const float3 ickey_loc = CData->curvekey_co[curvekey];
352  const float curve_time = CData->curvekey_time[curvekey];
353  const float curve_length = CData->curve_length[curve];
354  float time = (curve_length > 0.0f) ? curve_time / curve_length : 0.0f;
355  float radius = shaperadius(
356  CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time);
357 
358  if (CData->psys_closetip[sys] &&
359  (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1))
360  radius = 0.0f;
361 
362  /* curve motion keys store both position and radius in float4 */
363  float4 mP = float3_to_float4(ickey_loc);
364  mP.w = radius;
365  return mP;
366 }
367 
368 static float4 LerpCurveSegmentMotionCV(ParticleCurveData *CData, int sys, int curve, float step)
369 {
370  assert(step >= 0.0f);
371  assert(step <= 1.0f);
372  const int first_curve_key = CData->curve_firstkey[curve];
373  const float curve_key_f = step * (CData->curve_keynum[curve] - 1);
374  int curvekey = (int)floorf(curve_key_f);
375  const float remainder = curve_key_f - curvekey;
376  if (remainder == 0.0f) {
377  return CurveSegmentMotionCV(CData, sys, curve, first_curve_key + curvekey);
378  }
379  int curvekey2 = curvekey + 1;
380  if (curvekey2 >= (CData->curve_keynum[curve] - 1)) {
381  curvekey2 = (CData->curve_keynum[curve] - 1);
382  curvekey = curvekey2 - 1;
383  }
384  const float4 mP = CurveSegmentMotionCV(CData, sys, curve, first_curve_key + curvekey);
385  const float4 mP2 = CurveSegmentMotionCV(CData, sys, curve, first_curve_key + curvekey2);
386  return lerp(mP, mP2, remainder);
387 }
388 
390  int motion_step,
391  int num_motion_keys,
392  bool have_motion)
393 {
395  const int num_keys = hair->get_curve_keys().size();
396 
397  if (num_motion_keys != num_keys || !have_motion) {
398  /* No motion or hair "topology" changed, remove attributes again. */
399  if (num_motion_keys != num_keys) {
400  VLOG_WORK << "Hair topology changed, removing motion attribute.";
401  }
403  }
404  else if (motion_step > 0) {
405  /* Motion, fill up previous steps that we might have skipped because
406  * they had no motion, but we need them anyway now. */
407  for (int step = 0; step < motion_step; step++) {
408  float4 *mP = attr_mP->data_float4() + step * num_keys;
409 
410  for (int key = 0; key < num_keys; key++) {
411  mP[key] = float3_to_float4(hair->get_curve_keys()[key]);
412  mP[key].w = hair->get_curve_radius()[key];
413  }
414  }
415  }
416 }
417 
418 static void ExportCurveSegmentsMotion(Hair *hair, ParticleCurveData *CData, int motion_step)
419 {
420  /* find attribute */
422  bool new_attribute = false;
423 
424  /* add new attribute if it doesn't exist already */
425  if (!attr_mP) {
427  new_attribute = true;
428  }
429 
430  /* export motion vectors for curve keys */
431  size_t numkeys = hair->get_curve_keys().size();
432  float4 *mP = attr_mP->data_float4() + motion_step * numkeys;
433  bool have_motion = false;
434  int i = 0;
435  int num_curves = 0;
436 
437  for (int sys = 0; sys < CData->psys_firstcurve.size(); sys++) {
438  for (int curve = CData->psys_firstcurve[sys];
439  curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys];
440  curve++) {
441  /* Curve lengths may not match! Curves can be clipped. */
442  int curve_key_end = (num_curves + 1 < (int)hair->get_curve_first_key().size() ?
443  hair->get_curve_first_key()[num_curves + 1] :
444  (int)hair->get_curve_keys().size());
445  const int num_center_curve_keys = curve_key_end - hair->get_curve_first_key()[num_curves];
446  const int is_num_keys_different = CData->curve_keynum[curve] - num_center_curve_keys;
447 
448  if (!is_num_keys_different) {
449  for (int curvekey = CData->curve_firstkey[curve];
450  curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve];
451  curvekey++) {
452  if (i < hair->get_curve_keys().size()) {
453  mP[i] = CurveSegmentMotionCV(CData, sys, curve, curvekey);
454  if (!have_motion) {
455  /* unlike mesh coordinates, these tend to be slightly different
456  * between frames due to particle transforms into/out of object
457  * space, so we use an epsilon to detect actual changes */
458  float4 curve_key = float3_to_float4(hair->get_curve_keys()[i]);
459  curve_key.w = hair->get_curve_radius()[i];
460  if (len_squared(mP[i] - curve_key) > 1e-5f * 1e-5f)
461  have_motion = true;
462  }
463  }
464  i++;
465  }
466  }
467  else {
468  /* Number of keys has changed. Generate an interpolated version
469  * to preserve motion blur. */
470  const float step_size = num_center_curve_keys > 1 ? 1.0f / (num_center_curve_keys - 1) :
471  0.0f;
472  for (int step_index = 0; step_index < num_center_curve_keys; ++step_index) {
473  const float step = step_index * step_size;
474  mP[i] = LerpCurveSegmentMotionCV(CData, sys, curve, step);
475  i++;
476  }
477  have_motion = true;
478  }
479  num_curves++;
480  }
481  }
482 
483  /* In case of new attribute, we verify if there really was any motion. */
484  if (new_attribute) {
485  export_hair_motion_validate_attribute(hair, motion_step, i, have_motion);
486  }
487 }
488 
489 /* Hair Curve Sync */
490 
491 bool BlenderSync::object_has_particle_hair(BL::Object b_ob)
492 {
493  /* Test if the object has a particle modifier with hair. */
494  for (BL::Modifier &b_mod : b_ob.modifiers) {
495  if ((b_mod.type() == b_mod.type_PARTICLE_SYSTEM) &&
496  (preview ? b_mod.show_viewport() : b_mod.show_render())) {
497  BL::ParticleSystemModifier psmd((const PointerRNA)b_mod.ptr);
498  BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
499  BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
500 
501  if ((b_part.render_type() == BL::ParticleSettings::render_type_PATH) &&
502  (b_part.type() == BL::ParticleSettings::type_HAIR)) {
503  return true;
504  }
505  }
506  }
507 
508  return false;
509 }
510 
511 /* Old particle hair. */
512 void BlenderSync::sync_particle_hair(
513  Hair *hair, BL::Mesh &b_mesh, BObjectInfo &b_ob_info, bool motion, int motion_step)
514 {
515  if (!b_ob_info.is_real_object_data()) {
516  return;
517  }
518  BL::Object b_ob = b_ob_info.real_object;
519 
520  /* obtain general settings */
521  if (b_ob.mode() == b_ob.mode_PARTICLE_EDIT || b_ob.mode() == b_ob.mode_EDIT) {
522  return;
523  }
524 
525  /* Extract particle hair data - should be combined with connecting to mesh later. */
526 
527  ParticleCurveData CData;
528 
529  ObtainCacheParticleData(hair, &b_mesh, &b_ob, &CData, !preview);
530 
531  /* add hair geometry */
532  if (motion)
533  ExportCurveSegmentsMotion(hair, &CData, motion_step);
534  else
535  ExportCurveSegments(scene, hair, &CData);
536 
537  /* generated coordinates from first key. we should ideally get this from
538  * blender to handle deforming objects */
539  if (!motion) {
540  if (hair->need_attribute(scene, ATTR_STD_GENERATED)) {
541  float3 loc, size;
542  mesh_texture_space(b_mesh, loc, size);
543 
544  Attribute *attr_generated = hair->attributes.add(ATTR_STD_GENERATED);
545  float3 *generated = attr_generated->data_float3();
546 
547  for (size_t i = 0; i < hair->num_curves(); i++) {
548  float3 co = hair->get_curve_keys()[hair->get_curve(i).first_key];
549  generated[i] = co * size - loc;
550  }
551  }
552  }
553 
554  /* create vertex color attributes */
555  if (!motion) {
556  BL::Mesh::vertex_colors_iterator l;
557  int vcol_num = 0;
558 
559  for (b_mesh.vertex_colors.begin(l); l != b_mesh.vertex_colors.end(); ++l, vcol_num++) {
560  if (!hair->need_attribute(scene, ustring(l->name().c_str())))
561  continue;
562 
563  ObtainCacheParticleVcol(hair, &b_mesh, &b_ob, &CData, !preview, vcol_num);
564 
565  Attribute *attr_vcol = hair->attributes.add(
566  ustring(l->name().c_str()), TypeRGBA, ATTR_ELEMENT_CURVE);
567 
568  float4 *fdata = attr_vcol->data_float4();
569 
570  if (fdata) {
571  size_t i = 0;
572 
573  /* Encode vertex color using the sRGB curve. */
574  for (size_t curve = 0; curve < CData.curve_vcol.size(); curve++) {
575  fdata[i++] = color_srgb_to_linear_v4(CData.curve_vcol[curve]);
576  }
577  }
578  }
579  }
580 
581  /* create UV attributes */
582  if (!motion) {
583  BL::Mesh::uv_layers_iterator l;
584  int uv_num = 0;
585 
586  for (b_mesh.uv_layers.begin(l); l != b_mesh.uv_layers.end(); ++l, uv_num++) {
587  bool active_render = l->active_render();
588  AttributeStandard std = (active_render) ? ATTR_STD_UV : ATTR_STD_NONE;
589  ustring name = ustring(l->name().c_str());
590 
591  /* UV map */
592  if (hair->need_attribute(scene, name) || hair->need_attribute(scene, std)) {
593  Attribute *attr_uv;
594 
595  ObtainCacheParticleUV(hair, &b_mesh, &b_ob, &CData, !preview, uv_num);
596 
597  if (active_render)
598  attr_uv = hair->attributes.add(std, name);
599  else
600  attr_uv = hair->attributes.add(name, TypeFloat2, ATTR_ELEMENT_CURVE);
601 
602  float2 *uv = attr_uv->data_float2();
603 
604  if (uv) {
605  size_t i = 0;
606 
607  for (size_t curve = 0; curve < CData.curve_uv.size(); curve++) {
608  uv[i++] = CData.curve_uv[curve];
609  }
610  }
611  }
612  }
613  }
614 }
615 
616 static std::optional<BL::FloatAttribute> find_curves_radius_attribute(BL::Curves b_curves)
617 {
618  for (BL::Attribute &b_attribute : b_curves.attributes) {
619  if (b_attribute.name() != "radius") {
620  continue;
621  }
622  if (b_attribute.domain() != BL::Attribute::domain_POINT) {
623  continue;
624  }
625  if (b_attribute.data_type() != BL::Attribute::data_type_FLOAT) {
626  continue;
627  }
628  return BL::FloatAttribute{b_attribute};
629  }
630  return std::nullopt;
631 }
632 
633 static BL::FloatVectorAttribute find_curves_position_attribute(BL::Curves b_curves)
634 {
635  for (BL::Attribute &b_attribute : b_curves.attributes) {
636  if (b_attribute.name() != "position") {
637  continue;
638  }
639  if (b_attribute.domain() != BL::Attribute::domain_POINT) {
640  continue;
641  }
642  if (b_attribute.data_type() != BL::Attribute::data_type_FLOAT_VECTOR) {
643  continue;
644  }
645  return BL::FloatVectorAttribute{b_attribute};
646  }
647  /* The position attribute must exist. */
648  assert(false);
649  return BL::FloatVectorAttribute{b_curves.attributes[0]};
650 }
651 
652 template<typename TypeInCycles, typename GetValueAtIndex>
653 static void fill_generic_attribute(BL::Curves &b_curves,
654  TypeInCycles *data,
656  const GetValueAtIndex &get_value_at_index)
657 {
658  switch (element) {
659  case ATTR_ELEMENT_CURVE_KEY: {
660  const int num_points = b_curves.points.length();
661  for (int i = 0; i < num_points; i++) {
662  data[i] = get_value_at_index(i);
663  }
664  break;
665  }
666  case ATTR_ELEMENT_CURVE: {
667  const int num_verts = b_curves.curves.length();
668  for (int i = 0; i < num_verts; i++) {
669  data[i] = get_value_at_index(i);
670  }
671  break;
672  }
673  default: {
674  assert(false);
675  break;
676  }
677  }
678 }
679 
680 static void attr_create_motion(Hair *hair, BL::Attribute &b_attribute, const float motion_scale)
681 {
682  if (!(b_attribute.domain() == BL::Attribute::domain_POINT) &&
683  (b_attribute.data_type() == BL::Attribute::data_type_FLOAT_VECTOR)) {
684  return;
685  }
686 
687  BL::FloatVectorAttribute b_vector_attribute(b_attribute);
688  const int num_curve_keys = hair->get_curve_keys().size();
689 
690  /* Find or add attribute */
691  float3 *P = &hair->get_curve_keys()[0];
693 
694  if (!attr_mP) {
696  }
697 
698  /* Only export previous and next frame, we don't have any in between data. */
699  float motion_times[2] = {-1.0f, 1.0f};
700  for (int step = 0; step < 2; step++) {
701  const float relative_time = motion_times[step] * 0.5f * motion_scale;
702  float3 *mP = attr_mP->data_float3() + step * num_curve_keys;
703 
704  for (int i = 0; i < num_curve_keys; i++) {
705  mP[i] = P[i] + get_float3(b_vector_attribute.data[i].vector()) * relative_time;
706  }
707  }
708 }
709 
710 static void attr_create_uv(AttributeSet &attributes,
711  BL::Curves &b_curves,
712  BL::Attribute &b_attribute,
713  const ustring name)
714 {
715  BL::Float2Attribute b_float2_attribute{b_attribute};
716  Attribute *attr = attributes.add(ATTR_STD_UV, name);
717 
718  float2 *data = attr->data_float2();
719  fill_generic_attribute(b_curves, data, ATTR_ELEMENT_CURVE, [&](int i) {
720  BL::Array<float, 2> v = b_float2_attribute.data[i].vector();
721  return make_float2(v[0], v[1]);
722  });
723 }
724 
726  Hair *hair,
727  BL::Curves &b_curves,
728  const bool need_motion,
729  const float motion_scale)
730 {
731  AttributeSet &attributes = hair->attributes;
732  static const ustring u_velocity("velocity");
733  const bool need_uv = hair->need_attribute(scene, ATTR_STD_UV);
734  bool have_uv = false;
735 
736  for (BL::Attribute &b_attribute : b_curves.attributes) {
737  const ustring name{b_attribute.name().c_str()};
738 
739  const BL::Attribute::domain_enum b_domain = b_attribute.domain();
740  const BL::Attribute::data_type_enum b_data_type = b_attribute.data_type();
741 
742  if (need_motion && name == u_velocity) {
743  attr_create_motion(hair, b_attribute, motion_scale);
744  continue;
745  }
746 
747  /* Weak, use first float2 attribute as standard UV. */
748  if (need_uv && !have_uv && b_data_type == BL::Attribute::data_type_FLOAT2 &&
749  b_domain == BL::Attribute::domain_CURVE) {
750  attr_create_uv(attributes, b_curves, b_attribute, name);
751  have_uv = true;
752  continue;
753  }
754 
755  if (!hair->need_attribute(scene, name)) {
756  continue;
757  }
758  if (attributes.find(name)) {
759  continue;
760  }
761 
763  switch (b_domain) {
764  case BL::Attribute::domain_POINT:
766  break;
767  case BL::Attribute::domain_CURVE:
769  break;
770  default:
771  break;
772  }
773  if (element == ATTR_ELEMENT_NONE) {
774  /* Not supported. */
775  continue;
776  }
777  switch (b_data_type) {
778  case BL::Attribute::data_type_FLOAT: {
779  BL::FloatAttribute b_float_attribute{b_attribute};
780  Attribute *attr = attributes.add(name, TypeFloat, element);
781  float *data = attr->data_float();
783  b_curves, data, element, [&](int i) { return b_float_attribute.data[i].value(); });
784  break;
785  }
786  case BL::Attribute::data_type_BOOLEAN: {
787  BL::BoolAttribute b_bool_attribute{b_attribute};
788  Attribute *attr = attributes.add(name, TypeFloat, element);
789  float *data = attr->data_float();
790  fill_generic_attribute(b_curves, data, element, [&](int i) {
791  return (float)b_bool_attribute.data[i].value();
792  });
793  break;
794  }
795  case BL::Attribute::data_type_INT: {
796  BL::IntAttribute b_int_attribute{b_attribute};
797  Attribute *attr = attributes.add(name, TypeFloat, element);
798  float *data = attr->data_float();
799  fill_generic_attribute(b_curves, data, element, [&](int i) {
800  return (float)b_int_attribute.data[i].value();
801  });
802  break;
803  }
804  case BL::Attribute::data_type_FLOAT_VECTOR: {
805  BL::FloatVectorAttribute b_vector_attribute{b_attribute};
806  Attribute *attr = attributes.add(name, TypeVector, element);
807  float3 *data = attr->data_float3();
808  fill_generic_attribute(b_curves, data, element, [&](int i) {
809  BL::Array<float, 3> v = b_vector_attribute.data[i].vector();
810  return make_float3(v[0], v[1], v[2]);
811  });
812  break;
813  }
814  case BL::Attribute::data_type_FLOAT_COLOR: {
815  BL::FloatColorAttribute b_color_attribute{b_attribute};
816  Attribute *attr = attributes.add(name, TypeRGBA, element);
817  float4 *data = attr->data_float4();
818  fill_generic_attribute(b_curves, data, element, [&](int i) {
819  BL::Array<float, 4> v = b_color_attribute.data[i].color();
820  return make_float4(v[0], v[1], v[2], v[3]);
821  });
822  break;
823  }
824  case BL::Attribute::data_type_FLOAT2: {
825  BL::Float2Attribute b_float2_attribute{b_attribute};
826  Attribute *attr = attributes.add(name, TypeFloat2, element);
827  float2 *data = attr->data_float2();
828  fill_generic_attribute(b_curves, data, element, [&](int i) {
829  BL::Array<float, 2> v = b_float2_attribute.data[i].vector();
830  return make_float2(v[0], v[1]);
831  });
832  break;
833  }
834  default:
835  /* Not supported. */
836  break;
837  }
838  }
839 }
840 
841 static float4 hair_point_as_float4(BL::FloatVectorAttribute b_attr_position,
842  std::optional<BL::FloatAttribute> b_attr_radius,
843  const int index)
844 {
845  float4 mP = float3_to_float4(get_float3(b_attr_position.data[index].vector()));
846  mP.w = b_attr_radius ? b_attr_radius->data[index].value() : 0.005f;
847  return mP;
848 }
849 
850 static float4 interpolate_hair_points(BL::FloatVectorAttribute b_attr_position,
851  std::optional<BL::FloatAttribute> b_attr_radius,
852  const int first_point_index,
853  const int num_points,
854  const float step)
855 {
856  const float curve_t = step * (num_points - 1);
857  const int point_a = clamp((int)curve_t, 0, num_points - 1);
858  const int point_b = min(point_a + 1, num_points - 1);
859  const float t = curve_t - (float)point_a;
860  return lerp(hair_point_as_float4(b_attr_position, b_attr_radius, first_point_index + point_a),
861  hair_point_as_float4(b_attr_position, b_attr_radius, first_point_index + point_b),
862  t);
863 }
864 
866  Hair *hair,
867  BL::Curves b_curves,
868  const bool need_motion,
869  const float motion_scale)
870 {
871  /* TODO: optimize so we can straight memcpy arrays from Blender? */
872 
873  const int num_keys = b_curves.points.length();
874  const int num_curves = b_curves.curves.length();
875 
876  hair->resize_curves(num_curves, num_keys);
877 
878  float3 *curve_keys = hair->get_curve_keys().data();
879  float *curve_radius = hair->get_curve_radius().data();
880  int *curve_first_key = hair->get_curve_first_key().data();
881  int *curve_shader = hair->get_curve_shader().data();
882 
883  /* Add requested attributes. */
884  float *attr_intercept = NULL;
885  float *attr_length = NULL;
886  float *attr_random = NULL;
887 
889  attr_intercept = hair->attributes.add(ATTR_STD_CURVE_INTERCEPT)->data_float();
890  }
892  attr_length = hair->attributes.add(ATTR_STD_CURVE_LENGTH)->data_float();
893  }
895  attr_random = hair->attributes.add(ATTR_STD_CURVE_RANDOM)->data_float();
896  }
897 
898  BL::FloatVectorAttribute b_attr_position = find_curves_position_attribute(b_curves);
899  std::optional<BL::FloatAttribute> b_attr_radius = find_curves_radius_attribute(b_curves);
900 
901  /* Export curves and points. */
902  for (int i = 0; i < num_curves; i++) {
903  const int first_point_index = b_curves.curve_offset_data[i].value();
904  const int num_points = b_curves.curve_offset_data[i + 1].value() - first_point_index;
905 
906  float3 prev_co = zero_float3();
907  float length = 0.0f;
908 
909  /* Position and radius. */
910  for (int j = 0; j < num_points; j++) {
911  const int point_offset = first_point_index + j;
912  const float3 co = get_float3(b_attr_position.data[point_offset].vector());
913  const float radius = b_attr_radius ? b_attr_radius->data[point_offset].value() : 0.005f;
914 
915  curve_keys[point_offset] = co;
916  curve_radius[point_offset] = radius;
917 
918  if (attr_length || attr_intercept) {
919  if (j > 0) {
920  length += len(co - prev_co);
921  }
922  prev_co = co;
923 
924  if (attr_intercept) {
925  attr_intercept[point_offset] = length;
926  }
927  }
928  }
929 
930  /* Normalized 0..1 attribute along curve. */
931  if (attr_intercept && length > 0.0f) {
932  for (int j = 1; j < num_points; j++) {
933  const int point_offset = first_point_index + j;
934  attr_intercept[point_offset] /= length;
935  }
936  }
937 
938  /* Curve length. */
939  if (attr_length) {
940  attr_length[i] = length;
941  }
942 
943  /* Random number per curve. */
944  if (attr_random != NULL) {
945  attr_random[i] = hash_uint2_to_float(i, 0);
946  }
947 
948  /* Curve. */
949  curve_shader[i] = 0;
950  curve_first_key[i] = first_point_index;
951  }
952 
953  attr_create_generic(scene, hair, b_curves, need_motion, motion_scale);
954 }
955 
956 static void export_hair_curves_motion(Hair *hair, BL::Curves b_curves, int motion_step)
957 {
958  /* Find or add attribute. */
960  bool new_attribute = false;
961 
962  if (!attr_mP) {
964  new_attribute = true;
965  }
966 
967  /* Export motion keys. */
968  const int num_keys = hair->num_keys();
969  const int num_motion_curves = b_curves.curves.length();
970  const int num_curves = hair->num_curves();
971  float4 *mP = attr_mP->data_float4() + motion_step * num_keys;
972  bool have_motion = false;
973  int num_motion_keys = 0;
974  int curve_index = 0;
975 
976  BL::FloatVectorAttribute b_attr_position = find_curves_position_attribute(b_curves);
977  std::optional<BL::FloatAttribute> b_attr_radius = find_curves_radius_attribute(b_curves);
978 
979  for (int i = 0; i < num_motion_curves; i++) {
980  if (curve_index >= num_curves) {
981  break;
982  }
983 
984  const int first_point_index = b_curves.curve_offset_data[i].value();
985  const int num_points = b_curves.curve_offset_data[i + 1].value() - first_point_index;
986 
987  Hair::Curve curve = hair->get_curve(curve_index);
988  curve_index++;
989 
990  if (num_points == curve.num_keys) {
991  /* Number of keys matches. */
992  for (int i = 0; i < num_points; i++) {
993  int point_index = first_point_index + i;
994 
995  if (point_index < num_keys) {
996  mP[num_motion_keys] = hair_point_as_float4(b_attr_position, b_attr_radius, point_index);
997  num_motion_keys++;
998 
999  if (!have_motion) {
1000  /* TODO: use epsilon for comparison? Was needed for particles due to
1001  * transform, but ideally should not happen anymore. */
1002  float4 curve_key = float3_to_float4(hair->get_curve_keys()[i]);
1003  curve_key.w = hair->get_curve_radius()[i];
1004  have_motion = !(mP[i] == curve_key);
1005  }
1006  }
1007  }
1008  }
1009  else {
1010  /* Number of keys has changed. Generate an interpolated version
1011  * to preserve motion blur. */
1012  const float step_size = curve.num_keys > 1 ? 1.0f / (curve.num_keys - 1) : 0.0f;
1013  for (int i = 0; i < curve.num_keys; i++) {
1014  const float step = i * step_size;
1015  mP[num_motion_keys] = interpolate_hair_points(
1016  b_attr_position, b_attr_radius, first_point_index, num_points, step);
1017  num_motion_keys++;
1018  }
1019  have_motion = true;
1020  }
1021  }
1022 
1023  /* In case of new attribute, we verify if there really was any motion. */
1024  if (new_attribute) {
1025  export_hair_motion_validate_attribute(hair, motion_step, num_motion_keys, have_motion);
1026  }
1027 }
1028 
1029 /* Hair object. */
1030 void BlenderSync::sync_hair(Hair *hair, BObjectInfo &b_ob_info, bool motion, int motion_step)
1031 {
1032  /* Motion blur attribute is relative to seconds, we need it relative to frames. */
1033  const bool need_motion = object_need_motion_attribute(b_ob_info, scene);
1034  const float motion_scale = (need_motion) ?
1035  scene->motion_shutter_time() /
1036  (b_scene.render().fps() / b_scene.render().fps_base()) :
1037  0.0f;
1038 
1039  /* Convert Blender hair to Cycles curves. */
1040  BL::Curves b_curves(b_ob_info.object_data);
1041  if (motion) {
1042  export_hair_curves_motion(hair, b_curves, motion_step);
1043  }
1044  else {
1045  export_hair_curves(scene, hair, b_curves, need_motion, motion_scale);
1046  }
1047 }
1048 
1049 void BlenderSync::sync_hair(BL::Depsgraph b_depsgraph, BObjectInfo &b_ob_info, Hair *hair)
1050 {
1051  /* make a copy of the shaders as the caller in the main thread still need them for syncing the
1052  * attributes */
1053  array<Node *> used_shaders = hair->get_used_shaders();
1054 
1055  Hair new_hair;
1056  new_hair.set_used_shaders(used_shaders);
1057 
1058  if (view_layer.use_hair) {
1059  if (b_ob_info.object_data.is_a(&RNA_Curves)) {
1060  /* Hair object. */
1061  sync_hair(&new_hair, b_ob_info, false);
1062  }
1063  else {
1064  /* Particle hair. */
1065  bool need_undeformed = new_hair.need_attribute(scene, ATTR_STD_GENERATED);
1066  BL::Mesh b_mesh = object_to_mesh(
1067  b_data, b_ob_info, b_depsgraph, need_undeformed, Mesh::SUBDIVISION_NONE);
1068 
1069  if (b_mesh) {
1070  sync_particle_hair(&new_hair, b_mesh, b_ob_info, false);
1071  free_object_to_mesh(b_data, b_ob_info, b_mesh);
1072  }
1073  }
1074  }
1075 
1076  /* update original sockets */
1077 
1078  for (const SocketType &socket : new_hair.type->inputs) {
1079  /* Those sockets are updated in sync_object, so do not modify them. */
1080  if (socket.name == "use_motion_blur" || socket.name == "motion_steps" ||
1081  socket.name == "used_shaders") {
1082  continue;
1083  }
1084  hair->set_value(socket, new_hair, socket);
1085  }
1086 
1087  hair->attributes.update(std::move(new_hair.attributes));
1088 
1089  /* tag update */
1090 
1091  /* Compares curve_keys rather than strands in order to handle quick hair
1092  * adjustments in dynamic BVH - other methods could probably do this better. */
1093  const bool rebuild = (hair->curve_keys_is_modified() || hair->curve_radius_is_modified());
1094 
1095  hair->tag_update(scene, rebuild);
1096 }
1097 
1098 void BlenderSync::sync_hair_motion(BL::Depsgraph b_depsgraph,
1099  BObjectInfo &b_ob_info,
1100  Hair *hair,
1101  int motion_step)
1102 {
1103  /* Skip if nothing exported. */
1104  if (hair->num_keys() == 0) {
1105  return;
1106  }
1107 
1108  /* Export deformed coordinates. */
1109  if (ccl::BKE_object_is_deform_modified(b_ob_info, b_scene, preview)) {
1110  if (b_ob_info.object_data.is_a(&RNA_Curves)) {
1111  /* Hair object. */
1112  sync_hair(hair, b_ob_info, true, motion_step);
1113  return;
1114  }
1115  else {
1116  /* Particle hair. */
1117  BL::Mesh b_mesh = object_to_mesh(
1118  b_data, b_ob_info, b_depsgraph, false, Mesh::SUBDIVISION_NONE);
1119  if (b_mesh) {
1120  sync_particle_hair(hair, b_mesh, b_ob_info, true, motion_step);
1121  free_object_to_mesh(b_data, b_ob_info, b_mesh);
1122  return;
1123  }
1124  }
1125  }
1126 
1127  /* No deformation on this frame, copy coordinates if other frames did have it. */
1128  hair->copy_center_to_motion_step(motion_step);
1129 }
1130 
typedef float(TangentPoint)[2]
int BKE_object_is_deform_modified(struct Scene *scene, struct Object *ob)
Definition: object.cc:4982
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:35
struct Curves Curves
struct Mesh Mesh
struct Object Object
struct ParticleSettings ParticleSettings
struct ParticleSystem ParticleSystem
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble y2 _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat y2 _GL_VOID_RET _GL_VOID GLint GLint GLint y2 _GL_VOID_RET _GL_VOID GLshort GLshort GLshort y2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLuint *buffer _GL_VOID_RET _GL_VOID GLdouble t _GL_VOID_RET _GL_VOID GLfloat t _GL_VOID_RET _GL_VOID GLint t _GL_VOID_RET _GL_VOID GLshort t _GL_VOID_RET _GL_VOID GLdouble t
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 bool ObtainCacheParticleData(Hair *hair, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background)
static void attr_create_uv(AttributeSet &attributes, BL::Curves &b_curves, BL::Attribute &b_attribute, const ustring name)
static float4 hair_point_as_float4(BL::FloatVectorAttribute b_attr_position, std::optional< BL::FloatAttribute > b_attr_radius, const int index)
static std::optional< BL::FloatAttribute > find_curves_radius_attribute(BL::Curves b_curves)
static float4 interpolate_hair_points(BL::FloatVectorAttribute b_attr_position, std::optional< BL::FloatAttribute > b_attr_radius, const int first_point_index, const int num_points, const float step)
static void export_hair_curves_motion(Hair *hair, BL::Curves b_curves, int motion_step)
static BL::FloatVectorAttribute find_curves_position_attribute(BL::Curves b_curves)
static float4 CurveSegmentMotionCV(ParticleCurveData *CData, int sys, int curve, int curvekey)
static void export_hair_motion_validate_attribute(Hair *hair, int motion_step, int num_motion_keys, bool have_motion)
static bool ObtainCacheParticleUV(Hair *hair, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background, int uv_num)
static bool ObtainCacheParticleVcol(Hair *hair, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background, int vcol_num)
static void fill_generic_attribute(BL::Curves &b_curves, TypeInCycles *data, const AttributeElement element, const GetValueAtIndex &get_value_at_index)
static void ExportCurveSegments(Scene *scene, Hair *hair, ParticleCurveData *CData)
static void attr_create_generic(Scene *scene, Hair *hair, BL::Curves &b_curves, const bool need_motion, const float motion_scale)
static float shaperadius(float shape, float root, float tip, float time)
static void ExportCurveSegmentsMotion(Hair *hair, ParticleCurveData *CData, int motion_step)
static float4 LerpCurveSegmentMotionCV(ParticleCurveData *CData, int sys, int curve, float step)
static void attr_create_motion(Hair *hair, BL::Attribute &b_attribute, const float motion_scale)
static void export_hair_curves(Scene *scene, Hair *hair, BL::Curves b_curves, const bool need_motion, const float motion_scale)
ATTR_WARN_UNUSED_RESULT const void * element
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert * v
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
Attribute * add(ustring name, TypeDesc type, AttributeElement element)
void update(AttributeSet &&new_attributes)
Attribute * find(ustring name) const
void remove(ustring name)
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
Definition: hair.h:13
void resize_curves(int numcurves, int numkeys)
Definition: hair.cpp:299
void add_curve(int first_key, int shader)
Definition: hair.cpp:340
Curve get_curve(size_t i) const
Definition: hair.h:109
void reserve_curves(int numcurves, int numkeys)
Definition: hair.cpp:309
size_t num_curves() const
Definition: hair.h:123
void copy_center_to_motion_step(const int motion_step)
Definition: hair.cpp:349
void clear(bool preserve_shaders=false) override
Definition: hair.cpp:319
size_t num_keys() const
Definition: hair.h:118
void add_curve_key(float3 loc, float radius)
Definition: hair.cpp:331
array< int > curve_firstkey
Definition: scene/curves.h:36
array< bool > psys_closetip
Definition: scene/curves.h:34
array< float > psys_tipradius
Definition: scene/curves.h:32
array< int > psys_shader
Definition: scene/curves.h:29
array< float > curve_length
Definition: scene/curves.h:38
array< float4 > curve_vcol
Definition: scene/curves.h:40
array< float > curvekey_time
Definition: scene/curves.h:43
array< float > psys_rootradius
Definition: scene/curves.h:31
array< int > psys_firstcurve
Definition: scene/curves.h:27
array< int > psys_curvenum
Definition: scene/curves.h:28
array< float2 > curve_uv
Definition: scene/curves.h:39
array< float > psys_shape
Definition: scene/curves.h:33
array< int > curve_keynum
Definition: scene/curves.h:37
array< float3 > curvekey_co
Definition: scene/curves.h:42
size_t size() const
void reserve(size_t newcapacity)
void push_back_slow(const T &t)
void clear()
#define powf(x, y)
Definition: cuda/compat.h:103
#define CCL_NAMESPACE_END
Definition: cuda/compat.h:9
static void free_object_to_mesh(BL::BlendData &, BObjectInfo &b_ob_info, BL::Mesh &mesh)
static BL::Mesh object_to_mesh(BL::BlendData &, BObjectInfo &b_ob_info, BL::Depsgraph &, bool, Mesh::SubdivisionType subdivision_type)
static float3 get_float3(const BL::Array< float, 2 > &array)
static bool object_need_motion_attribute(BObjectInfo &b_ob_info, Scene *scene)
static Transform get_transform(const BL::Array< float, 16 > &array)
static void mesh_texture_space(BL::Mesh &b_mesh, float3 &loc, float3 &size)
double time
Scene scene
Curve curve
int len
Definition: draw_manager.c:108
ccl_device_inline float hash_uint2_to_float(uint kx, uint ky)
Definition: hash.h:122
ccl_device_inline Transform transform_inverse(const Transform tfm)
CCL_NAMESPACE_END CCL_NAMESPACE_BEGIN ccl_device_inline float3 transform_point(ccl_private const Transform *t, const float3 a)
AttributeStandard
Definition: kernel/types.h:612
@ ATTR_STD_CURVE_INTERCEPT
Definition: kernel/types.h:627
@ ATTR_STD_UV
Definition: kernel/types.h:616
@ ATTR_STD_NONE
Definition: kernel/types.h:613
@ ATTR_STD_MOTION_VERTEX_POSITION
Definition: kernel/types.h:624
@ ATTR_STD_CURVE_RANDOM
Definition: kernel/types.h:629
@ ATTR_STD_GENERATED
Definition: kernel/types.h:620
@ ATTR_STD_CURVE_LENGTH
Definition: kernel/types.h:628
AttributeElement
Definition: kernel/types.h:597
@ ATTR_ELEMENT_NONE
Definition: kernel/types.h:598
@ ATTR_ELEMENT_CURVE_KEY
Definition: kernel/types.h:607
@ ATTR_ELEMENT_CURVE
Definition: kernel/types.h:606
#define VLOG_WARNING
Definition: log.h:75
#define VLOG_WORK
Definition: log.h:80
ccl_device_inline float2 zero_float2()
Definition: math_float2.h:62
ccl_device_inline float3 zero_float3()
Definition: math_float3.h:80
ccl_device_inline float len_squared(const float3 a)
Definition: math_float3.h:423
static float P(float k)
Definition: math_interp.c:25
#define make_float2(x, y)
Definition: metal/compat.h:203
#define floorf(x)
Definition: metal/compat.h:224
#define make_float4(x, y, z, w)
Definition: metal/compat.h:205
#define make_float3(x, y, z)
Definition: metal/compat.h:204
static float lerp(float t, float a, float b)
T clamp(const T &a, const T &min, const T &max)
T length(const vec_base< T, Size > &a)
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
BL::Object real_object
bool is_real_object_data() const
int first_key
Definition: hair.h:19
@ SUBDIVISION_NONE
Definition: scene/mesh.h:120
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
float motion_shutter_time()
Definition: scene.cpp:397
ustring name
Definition: node_type.h:72
float x
Definition: types_float2.h:15
float x
ccl_device float4 color_srgb_to_linear_v4(float4 c)
Definition: util/color.h:302
ccl_device_inline float4 float3_to_float4(const float3 a)
Definition: util/math.h:505