Blender  V2.93
blender_curves.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2011-2013 Blender Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "render/attribute.h"
18 #include "render/camera.h"
19 #include "render/curves.h"
20 #include "render/hair.h"
21 #include "render/object.h"
22 #include "render/scene.h"
23 
24 #include "blender/blender_sync.h"
25 #include "blender/blender_util.h"
26 
27 #include "util/util_foreach.h"
28 #include "util/util_hash.h"
29 #include "util/util_logging.h"
30 
32 
34 {
35 }
36 
38 {
39 }
40 
41 static float shaperadius(float shape, float root, float tip, float time)
42 {
43  assert(time >= 0.0f);
44  assert(time <= 1.0f);
45  float radius = 1.0f - time;
46 
47  if (shape != 0.0f) {
48  if (shape < 0.0f)
49  radius = powf(radius, 1.0f + shape);
50  else
51  radius = powf(radius, 1.0f / (1.0f - shape));
52  }
53  return (radius * (root - tip)) + tip;
54 }
55 
56 /* curve functions */
57 
59  Hair *hair, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background)
60 {
61  int curvenum = 0;
62  int keyno = 0;
63 
64  if (!(hair && b_mesh && b_ob && CData))
65  return false;
66 
67  Transform tfm = get_transform(b_ob->matrix_world());
69 
70  for (BL::Modifier &b_mod : b_ob->modifiers) {
71  if ((b_mod.type() == b_mod.type_PARTICLE_SYSTEM) &&
72  (background ? b_mod.show_render() : b_mod.show_viewport())) {
73  BL::ParticleSystemModifier psmd((const PointerRNA)b_mod.ptr);
74  BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
75  BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
76 
77  if ((b_part.render_type() == BL::ParticleSettings::render_type_PATH) &&
78  (b_part.type() == BL::ParticleSettings::type_HAIR)) {
79  int shader = clamp(b_part.material() - 1, 0, hair->get_used_shaders().size() - 1);
80  int display_step = background ? b_part.render_step() : b_part.display_step();
81  int totparts = b_psys.particles.length();
82  int totchild = background ? b_psys.child_particles.length() :
83  (int)((float)b_psys.child_particles.length() *
84  (float)b_part.display_percentage() / 100.0f);
85  int totcurves = totchild;
86 
87  if (b_part.child_type() == 0 || totchild == 0)
88  totcurves += totparts;
89 
90  if (totcurves == 0)
91  continue;
92 
93  int ren_step = (1 << display_step) + 1;
94  if (b_part.kink() == BL::ParticleSettings::kink_SPIRAL)
95  ren_step += b_part.kink_extra_steps();
96 
97  CData->psys_firstcurve.push_back_slow(curvenum);
98  CData->psys_curvenum.push_back_slow(totcurves);
100 
101  float radius = b_part.radius_scale() * 0.5f;
102 
103  CData->psys_rootradius.push_back_slow(radius * b_part.root_radius());
104  CData->psys_tipradius.push_back_slow(radius * b_part.tip_radius());
105  CData->psys_shape.push_back_slow(b_part.shape());
106  CData->psys_closetip.push_back_slow(b_part.use_close_tip());
107 
108  int pa_no = 0;
109  if (!(b_part.child_type() == 0) && totchild != 0)
110  pa_no = totparts;
111 
112  int num_add = (totparts + totchild - pa_no);
113  CData->curve_firstkey.reserve(CData->curve_firstkey.size() + num_add);
114  CData->curve_keynum.reserve(CData->curve_keynum.size() + num_add);
115  CData->curve_length.reserve(CData->curve_length.size() + num_add);
116  CData->curvekey_co.reserve(CData->curvekey_co.size() + num_add * ren_step);
117  CData->curvekey_time.reserve(CData->curvekey_time.size() + num_add * ren_step);
118 
119  for (; pa_no < totparts + totchild; pa_no++) {
120  int keynum = 0;
121  CData->curve_firstkey.push_back_slow(keyno);
122 
123  float curve_length = 0.0f;
124  float3 prev_co_world = zero_float3();
125  float3 prev_co_object = zero_float3();
126  for (int step_no = 0; step_no < ren_step; step_no++) {
127  float3 co_world = prev_co_world;
128  b_psys.co_hair(*b_ob, pa_no, step_no, &co_world.x);
129  float3 co_object = transform_point(&itfm, co_world);
130  if (step_no > 0) {
131  const float step_length = len(co_object - prev_co_object);
132  curve_length += step_length;
133  }
134  CData->curvekey_co.push_back_slow(co_object);
135  CData->curvekey_time.push_back_slow(curve_length);
136  prev_co_object = co_object;
137  prev_co_world = co_world;
138  keynum++;
139  }
140  keyno += keynum;
141 
142  CData->curve_keynum.push_back_slow(keynum);
143  CData->curve_length.push_back_slow(curve_length);
144  curvenum++;
145  }
146  }
147  }
148  }
149 
150  return true;
151 }
152 
153 static bool ObtainCacheParticleUV(Hair *hair,
154  BL::Mesh *b_mesh,
155  BL::Object *b_ob,
156  ParticleCurveData *CData,
157  bool background,
158  int uv_num)
159 {
160  if (!(hair && b_mesh && b_ob && CData))
161  return false;
162 
163  CData->curve_uv.clear();
164 
165  for (BL::Modifier &b_mod : b_ob->modifiers) {
166  if ((b_mod.type() == b_mod.type_PARTICLE_SYSTEM) &&
167  (background ? b_mod.show_render() : b_mod.show_viewport())) {
168  BL::ParticleSystemModifier psmd((const PointerRNA)b_mod.ptr);
169  BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
170  BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
171 
172  if ((b_part.render_type() == BL::ParticleSettings::render_type_PATH) &&
173  (b_part.type() == BL::ParticleSettings::type_HAIR)) {
174  int totparts = b_psys.particles.length();
175  int totchild = background ? b_psys.child_particles.length() :
176  (int)((float)b_psys.child_particles.length() *
177  (float)b_part.display_percentage() / 100.0f);
178  int totcurves = totchild;
179 
180  if (b_part.child_type() == 0 || totchild == 0)
181  totcurves += totparts;
182 
183  if (totcurves == 0)
184  continue;
185 
186  int pa_no = 0;
187  if (!(b_part.child_type() == 0) && totchild != 0)
188  pa_no = totparts;
189 
190  int num_add = (totparts + totchild - pa_no);
191  CData->curve_uv.reserve(CData->curve_uv.size() + num_add);
192 
193  BL::ParticleSystem::particles_iterator b_pa;
194  b_psys.particles.begin(b_pa);
195  for (; pa_no < totparts + totchild; pa_no++) {
196  /* Add UVs */
197  BL::Mesh::uv_layers_iterator l;
198  b_mesh->uv_layers.begin(l);
199 
200  float2 uv = zero_float2();
201  if (b_mesh->uv_layers.length())
202  b_psys.uv_on_emitter(psmd, *b_pa, pa_no, uv_num, &uv.x);
203  CData->curve_uv.push_back_slow(uv);
204 
205  if (pa_no < totparts && b_pa != b_psys.particles.end())
206  ++b_pa;
207  }
208  }
209  }
210  }
211 
212  return true;
213 }
214 
215 static bool ObtainCacheParticleVcol(Hair *hair,
216  BL::Mesh *b_mesh,
217  BL::Object *b_ob,
218  ParticleCurveData *CData,
219  bool background,
220  int vcol_num)
221 {
222  if (!(hair && b_mesh && b_ob && CData))
223  return false;
224 
225  CData->curve_vcol.clear();
226 
227  for (BL::Modifier &b_mod : b_ob->modifiers) {
228  if ((b_mod.type() == b_mod.type_PARTICLE_SYSTEM) &&
229  (background ? b_mod.show_render() : b_mod.show_viewport())) {
230  BL::ParticleSystemModifier psmd((const PointerRNA)b_mod.ptr);
231  BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
232  BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
233 
234  if ((b_part.render_type() == BL::ParticleSettings::render_type_PATH) &&
235  (b_part.type() == BL::ParticleSettings::type_HAIR)) {
236  int totparts = b_psys.particles.length();
237  int totchild = background ? b_psys.child_particles.length() :
238  (int)((float)b_psys.child_particles.length() *
239  (float)b_part.display_percentage() / 100.0f);
240  int totcurves = totchild;
241 
242  if (b_part.child_type() == 0 || totchild == 0)
243  totcurves += totparts;
244 
245  if (totcurves == 0)
246  continue;
247 
248  int pa_no = 0;
249  if (!(b_part.child_type() == 0) && totchild != 0)
250  pa_no = totparts;
251 
252  int num_add = (totparts + totchild - pa_no);
253  CData->curve_vcol.reserve(CData->curve_vcol.size() + num_add);
254 
255  BL::ParticleSystem::particles_iterator b_pa;
256  b_psys.particles.begin(b_pa);
257  for (; pa_no < totparts + totchild; pa_no++) {
258  /* Add vertex colors */
259  BL::Mesh::vertex_colors_iterator l;
260  b_mesh->vertex_colors.begin(l);
261 
262  float4 vcol = make_float4(0.0f, 0.0f, 0.0f, 1.0f);
263  if (b_mesh->vertex_colors.length())
264  b_psys.mcol_on_emitter(psmd, *b_pa, pa_no, vcol_num, &vcol.x);
265  CData->curve_vcol.push_back_slow(vcol);
266 
267  if (pa_no < totparts && b_pa != b_psys.particles.end())
268  ++b_pa;
269  }
270  }
271  }
272  }
273 
274  return true;
275 }
276 
278 {
279  int num_keys = 0;
280  int num_curves = 0;
281 
282  if (hair->num_curves())
283  return;
284 
285  Attribute *attr_intercept = NULL;
286  Attribute *attr_random = NULL;
287 
289  attr_intercept = hair->attributes.add(ATTR_STD_CURVE_INTERCEPT);
291  attr_random = hair->attributes.add(ATTR_STD_CURVE_RANDOM);
292 
293  /* compute and reserve size of arrays */
294  for (int sys = 0; sys < CData->psys_firstcurve.size(); sys++) {
295  for (int curve = CData->psys_firstcurve[sys];
296  curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys];
297  curve++) {
298  num_keys += CData->curve_keynum[curve];
299  num_curves++;
300  }
301  }
302 
303  if (num_curves > 0) {
304  VLOG(1) << "Exporting curve segments for mesh " << hair->name;
305  }
306 
307  hair->reserve_curves(hair->num_curves() + num_curves, hair->get_curve_keys().size() + num_keys);
308 
309  num_keys = 0;
310  num_curves = 0;
311 
312  /* actually export */
313  for (int sys = 0; sys < CData->psys_firstcurve.size(); sys++) {
314  for (int curve = CData->psys_firstcurve[sys];
315  curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys];
316  curve++) {
317  size_t num_curve_keys = 0;
318 
319  for (int curvekey = CData->curve_firstkey[curve];
320  curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve];
321  curvekey++) {
322  const float3 ickey_loc = CData->curvekey_co[curvekey];
323  const float curve_time = CData->curvekey_time[curvekey];
324  const float curve_length = CData->curve_length[curve];
325  const float time = (curve_length > 0.0f) ? curve_time / curve_length : 0.0f;
326  float radius = shaperadius(
327  CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time);
328  if (CData->psys_closetip[sys] &&
329  (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)) {
330  radius = 0.0f;
331  }
332  hair->add_curve_key(ickey_loc, radius);
333  if (attr_intercept)
334  attr_intercept->add(time);
335 
336  num_curve_keys++;
337  }
338 
339  if (attr_random != NULL) {
340  attr_random->add(hash_uint2_to_float(num_curves, 0));
341  }
342 
343  hair->add_curve(num_keys, CData->psys_shader[sys]);
344  num_keys += num_curve_keys;
345  num_curves++;
346  }
347  }
348 
349  /* check allocation */
350  if ((hair->get_curve_keys().size() != num_keys) || (hair->num_curves() != num_curves)) {
351  VLOG(1) << "Allocation failed, clearing data";
352  hair->clear(true);
353  }
354 }
355 
356 static float4 CurveSegmentMotionCV(ParticleCurveData *CData, int sys, int curve, int curvekey)
357 {
358  const float3 ickey_loc = CData->curvekey_co[curvekey];
359  const float curve_time = CData->curvekey_time[curvekey];
360  const float curve_length = CData->curve_length[curve];
361  float time = (curve_length > 0.0f) ? curve_time / curve_length : 0.0f;
362  float radius = shaperadius(
363  CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time);
364 
365  if (CData->psys_closetip[sys] &&
366  (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1))
367  radius = 0.0f;
368 
369  /* curve motion keys store both position and radius in float4 */
370  float4 mP = float3_to_float4(ickey_loc);
371  mP.w = radius;
372  return mP;
373 }
374 
375 static float4 LerpCurveSegmentMotionCV(ParticleCurveData *CData, int sys, int curve, float step)
376 {
377  assert(step >= 0.0f);
378  assert(step <= 1.0f);
379  const int first_curve_key = CData->curve_firstkey[curve];
380  const float curve_key_f = step * (CData->curve_keynum[curve] - 1);
381  int curvekey = (int)floorf(curve_key_f);
382  const float remainder = curve_key_f - curvekey;
383  if (remainder == 0.0f) {
384  return CurveSegmentMotionCV(CData, sys, curve, first_curve_key + curvekey);
385  }
386  int curvekey2 = curvekey + 1;
387  if (curvekey2 >= (CData->curve_keynum[curve] - 1)) {
388  curvekey2 = (CData->curve_keynum[curve] - 1);
389  curvekey = curvekey2 - 1;
390  }
391  const float4 mP = CurveSegmentMotionCV(CData, sys, curve, first_curve_key + curvekey);
392  const float4 mP2 = CurveSegmentMotionCV(CData, sys, curve, first_curve_key + curvekey2);
393  return lerp(mP, mP2, remainder);
394 }
395 
397  int motion_step,
398  int num_motion_keys,
399  bool have_motion)
400 {
402  const int num_keys = hair->get_curve_keys().size();
403 
404  if (num_motion_keys != num_keys || !have_motion) {
405  /* No motion or hair "topology" changed, remove attributes again. */
406  if (num_motion_keys != num_keys) {
407  VLOG(1) << "Hair topology changed, removing attribute.";
408  }
409  else {
410  VLOG(1) << "No motion, removing attribute.";
411  }
413  }
414  else if (motion_step > 0) {
415  VLOG(1) << "Filling in new motion vertex position for motion_step " << motion_step;
416 
417  /* Motion, fill up previous steps that we might have skipped because
418  * they had no motion, but we need them anyway now. */
419  for (int step = 0; step < motion_step; step++) {
420  float4 *mP = attr_mP->data_float4() + step * num_keys;
421 
422  for (int key = 0; key < num_keys; key++) {
423  mP[key] = float3_to_float4(hair->get_curve_keys()[key]);
424  mP[key].w = hair->get_curve_radius()[key];
425  }
426  }
427  }
428 }
429 
430 static void ExportCurveSegmentsMotion(Hair *hair, ParticleCurveData *CData, int motion_step)
431 {
432  VLOG(1) << "Exporting curve motion segments for hair " << hair->name << ", motion step "
433  << motion_step;
434 
435  /* find attribute */
437  bool new_attribute = false;
438 
439  /* add new attribute if it doesn't exist already */
440  if (!attr_mP) {
441  VLOG(1) << "Creating new motion vertex position attribute";
443  new_attribute = true;
444  }
445 
446  /* export motion vectors for curve keys */
447  size_t numkeys = hair->get_curve_keys().size();
448  float4 *mP = attr_mP->data_float4() + motion_step * numkeys;
449  bool have_motion = false;
450  int i = 0;
451  int num_curves = 0;
452 
453  for (int sys = 0; sys < CData->psys_firstcurve.size(); sys++) {
454  for (int curve = CData->psys_firstcurve[sys];
455  curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys];
456  curve++) {
457  /* Curve lengths may not match! Curves can be clipped. */
458  int curve_key_end = (num_curves + 1 < (int)hair->get_curve_first_key().size() ?
459  hair->get_curve_first_key()[num_curves + 1] :
460  (int)hair->get_curve_keys().size());
461  const int num_center_curve_keys = curve_key_end - hair->get_curve_first_key()[num_curves];
462  const int is_num_keys_different = CData->curve_keynum[curve] - num_center_curve_keys;
463 
464  if (!is_num_keys_different) {
465  for (int curvekey = CData->curve_firstkey[curve];
466  curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve];
467  curvekey++) {
468  if (i < hair->get_curve_keys().size()) {
469  mP[i] = CurveSegmentMotionCV(CData, sys, curve, curvekey);
470  if (!have_motion) {
471  /* unlike mesh coordinates, these tend to be slightly different
472  * between frames due to particle transforms into/out of object
473  * space, so we use an epsilon to detect actual changes */
474  float4 curve_key = float3_to_float4(hair->get_curve_keys()[i]);
475  curve_key.w = hair->get_curve_radius()[i];
476  if (len_squared(mP[i] - curve_key) > 1e-5f * 1e-5f)
477  have_motion = true;
478  }
479  }
480  i++;
481  }
482  }
483  else {
484  /* Number of keys has changed. Generate an interpolated version
485  * to preserve motion blur. */
486  const float step_size = num_center_curve_keys > 1 ? 1.0f / (num_center_curve_keys - 1) :
487  0.0f;
488  for (int step_index = 0; step_index < num_center_curve_keys; ++step_index) {
489  const float step = step_index * step_size;
490  mP[i] = LerpCurveSegmentMotionCV(CData, sys, curve, step);
491  i++;
492  }
493  have_motion = true;
494  }
495  num_curves++;
496  }
497  }
498 
499  /* In case of new attribute, we verify if there really was any motion. */
500  if (new_attribute) {
501  export_hair_motion_validate_attribute(hair, motion_step, i, have_motion);
502  }
503 }
504 
505 /* Hair Curve Sync */
506 
507 bool BlenderSync::object_has_particle_hair(BL::Object b_ob)
508 {
509  /* Test if the object has a particle modifier with hair. */
510  for (BL::Modifier &b_mod : b_ob.modifiers) {
511  if ((b_mod.type() == b_mod.type_PARTICLE_SYSTEM) &&
512  (preview ? b_mod.show_viewport() : b_mod.show_render())) {
513  BL::ParticleSystemModifier psmd((const PointerRNA)b_mod.ptr);
514  BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
515  BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
516 
517  if ((b_part.render_type() == BL::ParticleSettings::render_type_PATH) &&
518  (b_part.type() == BL::ParticleSettings::type_HAIR)) {
519  return true;
520  }
521  }
522  }
523 
524  return false;
525 }
526 
527 /* Old particle hair. */
528 void BlenderSync::sync_particle_hair(
529  Hair *hair, BL::Mesh &b_mesh, BL::Object &b_ob, bool motion, int motion_step)
530 {
531  /* obtain general settings */
532  if (b_ob.mode() == b_ob.mode_PARTICLE_EDIT || b_ob.mode() == b_ob.mode_EDIT) {
533  return;
534  }
535 
536  /* extract particle hair data - should be combined with connecting to mesh later*/
537 
538  ParticleCurveData CData;
539 
540  ObtainCacheParticleData(hair, &b_mesh, &b_ob, &CData, !preview);
541 
542  /* add hair geometry */
543  if (motion)
544  ExportCurveSegmentsMotion(hair, &CData, motion_step);
545  else
546  ExportCurveSegments(scene, hair, &CData);
547 
548  /* generated coordinates from first key. we should ideally get this from
549  * blender to handle deforming objects */
550  if (!motion) {
551  if (hair->need_attribute(scene, ATTR_STD_GENERATED)) {
552  float3 loc, size;
553  mesh_texture_space(b_mesh, loc, size);
554 
555  Attribute *attr_generated = hair->attributes.add(ATTR_STD_GENERATED);
556  float3 *generated = attr_generated->data_float3();
557 
558  for (size_t i = 0; i < hair->num_curves(); i++) {
559  float3 co = hair->get_curve_keys()[hair->get_curve(i).first_key];
560  generated[i] = co * size - loc;
561  }
562  }
563  }
564 
565  /* create vertex color attributes */
566  if (!motion) {
567  BL::Mesh::vertex_colors_iterator l;
568  int vcol_num = 0;
569 
570  for (b_mesh.vertex_colors.begin(l); l != b_mesh.vertex_colors.end(); ++l, vcol_num++) {
571  if (!hair->need_attribute(scene, ustring(l->name().c_str())))
572  continue;
573 
574  ObtainCacheParticleVcol(hair, &b_mesh, &b_ob, &CData, !preview, vcol_num);
575 
576  Attribute *attr_vcol = hair->attributes.add(
577  ustring(l->name().c_str()), TypeRGBA, ATTR_ELEMENT_CURVE);
578 
579  float4 *fdata = attr_vcol->data_float4();
580 
581  if (fdata) {
582  size_t i = 0;
583 
584  /* Encode vertex color using the sRGB curve. */
585  for (size_t curve = 0; curve < CData.curve_vcol.size(); curve++) {
586  fdata[i++] = color_srgb_to_linear_v4(CData.curve_vcol[curve]);
587  }
588  }
589  }
590  }
591 
592  /* create UV attributes */
593  if (!motion) {
594  BL::Mesh::uv_layers_iterator l;
595  int uv_num = 0;
596 
597  for (b_mesh.uv_layers.begin(l); l != b_mesh.uv_layers.end(); ++l, uv_num++) {
598  bool active_render = l->active_render();
599  AttributeStandard std = (active_render) ? ATTR_STD_UV : ATTR_STD_NONE;
600  ustring name = ustring(l->name().c_str());
601 
602  /* UV map */
603  if (hair->need_attribute(scene, name) || hair->need_attribute(scene, std)) {
604  Attribute *attr_uv;
605 
606  ObtainCacheParticleUV(hair, &b_mesh, &b_ob, &CData, !preview, uv_num);
607 
608  if (active_render)
609  attr_uv = hair->attributes.add(std, name);
610  else
611  attr_uv = hair->attributes.add(name, TypeFloat2, ATTR_ELEMENT_CURVE);
612 
613  float2 *uv = attr_uv->data_float2();
614 
615  if (uv) {
616  size_t i = 0;
617 
618  for (size_t curve = 0; curve < CData.curve_uv.size(); curve++) {
619  uv[i++] = CData.curve_uv[curve];
620  }
621  }
622  }
623  }
624  }
625 }
626 
627 #ifdef WITH_HAIR_NODES
628 static float4 hair_point_as_float4(BL::HairPoint b_point)
629 {
630  float4 mP = float3_to_float4(get_float3(b_point.co()));
631  mP.w = b_point.radius();
632  return mP;
633 }
634 
635 static float4 interpolate_hair_points(BL::Hair b_hair,
636  const int first_point_index,
637  const int num_points,
638  const float step)
639 {
640  const float curve_t = step * (num_points - 1);
641  const int point_a = clamp((int)curve_t, 0, num_points - 1);
642  const int point_b = min(point_a + 1, num_points - 1);
643  const float t = curve_t - (float)point_a;
644  return lerp(hair_point_as_float4(b_hair.points[first_point_index + point_a]),
645  hair_point_as_float4(b_hair.points[first_point_index + point_b]),
646  t);
647 }
648 
649 static void export_hair_curves(Scene *scene, Hair *hair, BL::Hair b_hair)
650 {
651  /* TODO: optimize so we can straight memcpy arrays from Blender? */
652 
653  /* Add requested attributes. */
654  Attribute *attr_intercept = NULL;
655  Attribute *attr_random = NULL;
656 
658  attr_intercept = hair->attributes.add(ATTR_STD_CURVE_INTERCEPT);
659  }
661  attr_random = hair->attributes.add(ATTR_STD_CURVE_RANDOM);
662  }
663 
664  /* Reserve memory. */
665  const int num_keys = b_hair.points.length();
666  const int num_curves = b_hair.curves.length();
667 
668  if (num_curves > 0) {
669  VLOG(1) << "Exporting curve segments for hair " << hair->name;
670  }
671 
672  hair->reserve_curves(num_curves, num_keys);
673 
674  /* Export curves and points. */
675  vector<float> points_length;
676 
677  for (BL::HairCurve &b_curve : b_hair.curves) {
678  const int first_point_index = b_curve.first_point_index();
679  const int num_points = b_curve.num_points();
680 
681  float3 prev_co = zero_float3();
682  float length = 0.0f;
683  if (attr_intercept) {
684  points_length.clear();
685  points_length.reserve(num_points);
686  }
687 
688  /* Position and radius. */
689  for (int i = 0; i < num_points; i++) {
690  BL::HairPoint b_point = b_hair.points[first_point_index + i];
691 
692  const float3 co = get_float3(b_point.co());
693  const float radius = b_point.radius();
694  hair->add_curve_key(co, radius);
695 
696  if (attr_intercept) {
697  if (i > 0) {
698  length += len(co - prev_co);
699  points_length.push_back(length);
700  }
701  prev_co = co;
702  }
703  }
704 
705  /* Normalized 0..1 attribute along curve. */
706  if (attr_intercept) {
707  for (int i = 0; i < num_points; i++) {
708  attr_intercept->add((length == 0.0f) ? 0.0f : points_length[i] / length);
709  }
710  }
711 
712  /* Random number per curve. */
713  if (attr_random != NULL) {
714  attr_random->add(hash_uint2_to_float(b_curve.index(), 0));
715  }
716 
717  /* Curve. */
718  const int shader_index = 0;
719  hair->add_curve(first_point_index, shader_index);
720  }
721 }
722 
723 static void export_hair_curves_motion(Hair *hair, BL::Hair b_hair, int motion_step)
724 {
725  VLOG(1) << "Exporting curve motion segments for hair " << hair->name << ", motion step "
726  << motion_step;
727 
728  /* Find or add attribute. */
730  bool new_attribute = false;
731 
732  if (!attr_mP) {
733  VLOG(1) << "Creating new motion vertex position attribute";
735  new_attribute = true;
736  }
737 
738  /* Export motion keys. */
739  const int num_keys = hair->get_curve_keys().size();
740  float4 *mP = attr_mP->data_float4() + motion_step * num_keys;
741  bool have_motion = false;
742  int num_motion_keys = 0;
743  int curve_index = 0;
744 
745  for (BL::HairCurve &b_curve : b_hair.curves) {
746  const int first_point_index = b_curve.first_point_index();
747  const int num_points = b_curve.num_points();
748 
749  Hair::Curve curve = hair->get_curve(curve_index);
750  curve_index++;
751 
752  if (num_points == curve.num_keys) {
753  /* Number of keys matches. */
754  for (int i = 0; i < num_points; i++) {
755  int point_index = first_point_index + i;
756 
757  if (point_index < num_keys) {
758  mP[num_motion_keys] = hair_point_as_float4(b_hair.points[point_index]);
759  num_motion_keys++;
760 
761  if (!have_motion) {
762  /* TODO: use epsilon for comparison? Was needed for particles due to
763  * transform, but ideally should not happen anymore. */
764  float4 curve_key = float3_to_float4(hair->get_curve_keys()[i]);
765  curve_key.w = hair->get_curve_radius()[i];
766  have_motion = !(mP[i] == curve_key);
767  }
768  }
769  }
770  }
771  else {
772  /* Number of keys has changed. Generate an interpolated version
773  * to preserve motion blur. */
774  const float step_size = curve.num_keys > 1 ? 1.0f / (curve.num_keys - 1) : 0.0f;
775  for (int i = 0; i < curve.num_keys; i++) {
776  const float step = i * step_size;
777  mP[num_motion_keys] = interpolate_hair_points(b_hair, first_point_index, num_points, step);
778  num_motion_keys++;
779  }
780  have_motion = true;
781  }
782  }
783 
784  /* In case of new attribute, we verify if there really was any motion. */
785  if (new_attribute) {
786  export_hair_motion_validate_attribute(hair, motion_step, num_motion_keys, have_motion);
787  }
788 }
789 
790 /* Hair object. */
791 void BlenderSync::sync_hair(Hair *hair, BL::Object &b_ob, bool motion, int motion_step)
792 {
793  /* Convert Blender hair to Cycles curves. */
794  BL::Hair b_hair(b_ob.data());
795  if (motion) {
796  export_hair_curves_motion(hair, b_hair, motion_step);
797  }
798  else {
799  export_hair_curves(scene, hair, b_hair);
800  }
801 }
802 #else
803 void BlenderSync::sync_hair(Hair *hair, BL::Object &b_ob, bool motion, int motion_step)
804 {
805  (void)hair;
806  (void)b_ob;
807  (void)motion;
808  (void)motion_step;
809 }
810 #endif
811 
812 void BlenderSync::sync_hair(BL::Depsgraph b_depsgraph, BL::Object b_ob, Hair *hair)
813 {
814  /* make a copy of the shaders as the caller in the main thread still need them for syncing the
815  * attributes */
816  array<Node *> used_shaders = hair->get_used_shaders();
817 
818  Hair new_hair;
819  new_hair.set_used_shaders(used_shaders);
820 
821  if (view_layer.use_hair) {
822  if (b_ob.type() == BL::Object::type_HAIR) {
823  /* Hair object. */
824  sync_hair(&new_hair, b_ob, false);
825  }
826  else {
827  /* Particle hair. */
828  bool need_undeformed = new_hair.need_attribute(scene, ATTR_STD_GENERATED);
829  BL::Mesh b_mesh = object_to_mesh(
830  b_data, b_ob, b_depsgraph, need_undeformed, Mesh::SUBDIVISION_NONE);
831 
832  if (b_mesh) {
833  sync_particle_hair(&new_hair, b_mesh, b_ob, false);
834  free_object_to_mesh(b_data, b_ob, b_mesh);
835  }
836  }
837  }
838 
839  /* update original sockets */
840 
841  for (const SocketType &socket : new_hair.type->inputs) {
842  /* Those sockets are updated in sync_object, so do not modify them. */
843  if (socket.name == "use_motion_blur" || socket.name == "motion_steps" ||
844  socket.name == "used_shaders") {
845  continue;
846  }
847  hair->set_value(socket, new_hair, socket);
848  }
849 
850  hair->attributes.update(std::move(new_hair.attributes));
851 
852  /* tag update */
853 
854  /* Compares curve_keys rather than strands in order to handle quick hair
855  * adjustments in dynamic BVH - other methods could probably do this better. */
856  const bool rebuild = (hair->curve_keys_is_modified() || hair->curve_radius_is_modified());
857 
858  hair->tag_update(scene, rebuild);
859 }
860 
861 void BlenderSync::sync_hair_motion(BL::Depsgraph b_depsgraph,
862  BL::Object b_ob,
863  Hair *hair,
864  int motion_step)
865 {
866  /* Skip if nothing exported. */
867  if (hair->num_keys() == 0) {
868  return;
869  }
870 
871  /* Export deformed coordinates. */
872  if (ccl::BKE_object_is_deform_modified(b_ob, b_scene, preview)) {
873  if (b_ob.type() == BL::Object::type_HAIR) {
874  /* Hair object. */
875  sync_hair(hair, b_ob, true, motion_step);
876  return;
877  }
878  else {
879  /* Particle hair. */
880  BL::Mesh b_mesh = object_to_mesh(b_data, b_ob, b_depsgraph, false, Mesh::SUBDIVISION_NONE);
881  if (b_mesh) {
882  sync_particle_hair(hair, b_mesh, b_ob, true, motion_step);
883  free_object_to_mesh(b_data, b_ob, b_mesh);
884  return;
885  }
886  }
887  }
888 
889  /* No deformation on this frame, copy coordinates if other frames did have it. */
890  hair->copy_center_to_motion_step(motion_step);
891 }
892 
typedef float(TangentPoint)[2]
int BKE_object_is_deform_modified(struct Scene *scene, struct Object *ob)
Definition: object.c:5018
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:51
struct HairCurve HairCurve
struct Hair Hair
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
static bool ObtainCacheParticleData(Hair *hair, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background)
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 ExportCurveSegments(Scene *scene, Hair *hair, ParticleCurveData *CData)
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 float3 get_float3(const BL::Array< float, 2 > &array)
Definition: blender_util.h:295
static BL::Mesh object_to_mesh(BL::BlendData &, BL::Object &object, BL::Depsgraph &, bool, Mesh::SubdivisionType subdivision_type)
Definition: blender_util.h:49
static void free_object_to_mesh(BL::BlendData &, BL::Object &object, BL::Mesh &mesh)
Definition: blender_util.h:110
static Transform get_transform(const BL::Array< float, 16 > &array)
Definition: blender_util.h:277
static void mesh_texture_space(BL::Mesh &b_mesh, float3 &loc, float3 &size)
Definition: blender_util.h:473
ATTR_WARN_UNUSED_RESULT const BMLoop * l
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
SIMD_FORCE_INLINE btScalar length(const btQuaternion &q)
Return the length of a quaternion.
Definition: btQuaternion.h:895
Attribute * add(ustring name, TypeDesc type, AttributeElement element)
Definition: attribute.cpp:428
void update(AttributeSet &&new_attributes)
Definition: attribute.cpp:663
Attribute * find(ustring name) const
Definition: attribute.cpp:447
void remove(ustring name)
Definition: attribute.cpp:456
float4 * data_float4()
Definition: attribute.h:91
void add(const float &f)
Definition: attribute.cpp:76
float3 * data_float3()
Definition: attribute.h:86
float2 * data_float2()
Definition: attribute.h:81
bool need_attribute(Scene *scene, AttributeStandard std)
Definition: geometry.cpp:102
void tag_update(Scene *scene, bool rebuild)
Definition: geometry.cpp:271
AttributeSet attributes
Definition: geometry.h:81
array< int > curve_firstkey
Definition: curves.h:49
array< bool > psys_closetip
Definition: curves.h:47
array< float > psys_tipradius
Definition: curves.h:45
array< int > psys_shader
Definition: curves.h:42
array< float > curve_length
Definition: curves.h:51
array< float4 > curve_vcol
Definition: curves.h:53
array< float > curvekey_time
Definition: curves.h:56
array< float > psys_rootradius
Definition: curves.h:44
array< int > psys_firstcurve
Definition: curves.h:40
array< int > psys_curvenum
Definition: curves.h:41
array< float2 > curve_uv
Definition: curves.h:52
array< float > psys_shape
Definition: curves.h:46
array< int > curve_keynum
Definition: curves.h:50
array< float3 > curvekey_co
Definition: curves.h:55
size_t size() const
Definition: util_array.h:203
void reserve(size_t newcapacity)
Definition: util_array.h:244
void push_back_slow(const T &t)
Definition: util_array.h:263
void clear()
Definition: util_array.h:188
double time
Scene scene
Curve curve
#define powf(x, y)
#define CCL_NAMESPACE_END
#define floorf(x)
#define make_float4(x, y, z, w)
void KERNEL_FUNCTION_FULL_NAME() shader(KernelGlobals *kg, uint4 *input, float4 *output, int type, int filter, int i, int offset, int sample)
AttributeStandard
Definition: kernel_types.h:744
@ ATTR_STD_CURVE_INTERCEPT
Definition: kernel_types.h:759
@ ATTR_STD_UV
Definition: kernel_types.h:748
@ ATTR_STD_NONE
Definition: kernel_types.h:745
@ ATTR_STD_MOTION_VERTEX_POSITION
Definition: kernel_types.h:756
@ ATTR_STD_CURVE_RANDOM
Definition: kernel_types.h:760
@ ATTR_STD_GENERATED
Definition: kernel_types.h:752
@ ATTR_ELEMENT_CURVE
Definition: kernel_types.h:738
static float lerp(float t, float a, float b)
#define min(a, b)
Definition: sort.c:51
int first_key
Definition: hair.h:30
void add_curve(int first_key, int shader)
Definition: hair.cpp:347
Curve get_curve(size_t i) const
Definition: hair.h:119
void reserve_curves(int numcurves, int numkeys)
Definition: hair.cpp:316
size_t num_curves() const
Definition: hair.h:133
void copy_center_to_motion_step(const int motion_step)
Definition: hair.cpp:356
void clear(bool preserve_shaders=false) override
Definition: hair.cpp:326
size_t num_keys() const
Definition: hair.h:128
void add_curve_key(float3 loc, float radius)
Definition: hair.cpp:338
@ SUBDIVISION_NONE
Definition: mesh.h:133
vector< SocketType, std::allocator< SocketType > > inputs
Definition: node_type.h:131
const NodeType * type
Definition: node.h:175
void set_value(const SocketType &input, const Node &other, const SocketType &other_input)
Definition: node.cpp:385
ustring name
Definition: node.h:174
ustring name
Definition: node_type.h:85
float x
Definition: sky_float3.h:35
ccl_device float4 color_srgb_to_linear_v4(float4 c)
Definition: util_color.h:263
ccl_device_inline float hash_uint2_to_float(uint kx, uint ky)
Definition: util_hash.h:135
#define VLOG(severity)
Definition: util_logging.h:50
ccl_device_inline float4 float3_to_float4(const float3 a)
Definition: util_math.h:420
ccl_device_inline int clamp(int a, int mn, int mx)
Definition: util_math.h:283
ccl_device_inline float2 zero_float2()
ccl_device_inline float3 zero_float3()
ccl_device_inline float len_squared(const float3 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)
ccl_device_inline float3 transform_point(const Transform *t, const float3 a)
ccl_device_inline Transform transform_quick_inverse(Transform M)
uint len