Blender  V3.3
alembic_read.cpp
Go to the documentation of this file.
1 /* SPDX-License-Identifier: Apache-2.0
2  * Copyright 2021-2022 Blender Foundation */
3 
4 #include "scene/alembic_read.h"
5 #include "scene/alembic.h"
6 #include "scene/mesh.h"
7 
8 #include "util/color.h"
9 #include "util/progress.h"
10 
11 #ifdef WITH_ALEMBIC
12 
13 using namespace Alembic::AbcGeom;
14 
16 
17 static float3 make_float3_from_yup(const V3f &v)
18 {
19  return make_float3(v.x, -v.z, v.y);
20 }
21 
22 /* get the sample times to load data for the given the start and end frame of the procedural */
23 static set<chrono_t> get_relevant_sample_times(AlembicProcedural *proc,
24  const TimeSampling &time_sampling,
25  size_t num_samples)
26 {
27  set<chrono_t> result;
28 
29  if (num_samples < 2) {
30  result.insert(0.0);
31  return result;
32  }
33 
34  double start_frame;
35  double end_frame;
36 
37  if (proc->get_use_prefetch()) {
38  // load the data for the entire animation
39  start_frame = static_cast<double>(proc->get_start_frame());
40  end_frame = static_cast<double>(proc->get_end_frame());
41  }
42  else {
43  // load the data for the current frame
44  start_frame = static_cast<double>(proc->get_frame());
45  end_frame = start_frame;
46  }
47 
48  const double frame_rate = static_cast<double>(proc->get_frame_rate());
49  const double start_time = start_frame / frame_rate;
50  const double end_time = (end_frame + 1) / frame_rate;
51 
52  const size_t start_index = time_sampling.getFloorIndex(start_time, num_samples).first;
53  const size_t end_index = time_sampling.getCeilIndex(end_time, num_samples).first;
54 
55  for (size_t i = start_index; i < end_index; ++i) {
56  result.insert(time_sampling.getSampleTime(i));
57  }
58 
59  return result;
60 }
61 
62 /* Main function to read data, this will iterate over all the relevant sample times for the
63  * duration of the requested animation, and call the DataReadingFunc for each of those sample time.
64  */
65 template<typename Params, typename DataReadingFunc>
66 static void read_data_loop(AlembicProcedural *proc,
67  CachedData &cached_data,
68  const Params &params,
69  DataReadingFunc &&func,
70  Progress &progress)
71 {
72  const std::set<chrono_t> times = get_relevant_sample_times(
73  proc, *params.time_sampling, params.num_samples);
74 
75  cached_data.set_time_sampling(*params.time_sampling);
76 
77  for (chrono_t time : times) {
78  if (progress.get_cancel()) {
79  return;
80  }
81 
82  func(cached_data, params, time);
83  }
84 }
85 
86 /* Polygon Mesh Geometries. */
87 
88 /* Compute the vertex normals in case none are present in the IPolyMeshSchema, this is mostly used
89  * to avoid computing them in the GeometryManager in order to speed up data updates. */
90 static void compute_vertex_normals(CachedData &cache, double current_time)
91 {
92  if (cache.vertices.size() == 0) {
93  return;
94  }
95 
96  CachedData::CachedAttribute &attr_normal = cache.add_attribute(
97  ustring("N"), cache.vertices.get_time_sampling());
98  attr_normal.std = ATTR_STD_VERTEX_NORMAL;
99  attr_normal.element = ATTR_ELEMENT_VERTEX;
100  attr_normal.type_desc = TypeNormal;
101 
102  const array<float3> *vertices =
103  cache.vertices.data_for_time_no_check(current_time).get_data_or_null();
104  const array<int3> *triangles =
105  cache.triangles.data_for_time_no_check(current_time).get_data_or_null();
106 
107  if (!vertices || !triangles) {
108  attr_normal.data.add_no_data(current_time);
109  return;
110  }
111 
112  array<char> attr_data(vertices->size() * sizeof(float3));
113  float3 *attr_ptr = reinterpret_cast<float3 *>(attr_data.data());
114  memset(attr_ptr, 0, vertices->size() * sizeof(float3));
115 
116  for (size_t t = 0; t < triangles->size(); ++t) {
117  const int3 tri_int3 = triangles->data()[t];
118  Mesh::Triangle tri{};
119  tri.v[0] = tri_int3[0];
120  tri.v[1] = tri_int3[1];
121  tri.v[2] = tri_int3[2];
122 
123  const float3 tri_N = tri.compute_normal(vertices->data());
124 
125  for (int v = 0; v < 3; ++v) {
126  attr_ptr[tri_int3[v]] += tri_N;
127  }
128  }
129 
130  for (size_t v = 0; v < vertices->size(); ++v) {
131  attr_ptr[v] = normalize(attr_ptr[v]);
132  }
133 
134  attr_normal.data.add_data(attr_data, current_time);
135 }
136 
137 static void add_normals(const Int32ArraySamplePtr face_indices,
138  const IN3fGeomParam &normals,
139  double time,
140  CachedData &cached_data)
141 {
142  switch (normals.getScope()) {
143  case kFacevaryingScope: {
144  const ISampleSelector iss = ISampleSelector(time);
145  const IN3fGeomParam::Sample sample = normals.getExpandedValue(iss);
146 
147  if (!sample.valid()) {
148  return;
149  }
150 
151  CachedData::CachedAttribute &attr = cached_data.add_attribute(ustring(normals.getName()),
152  *normals.getTimeSampling());
153  attr.std = ATTR_STD_VERTEX_NORMAL;
154 
155  const array<float3> *vertices =
156  cached_data.vertices.data_for_time_no_check(time).get_data_or_null();
157 
158  if (!vertices) {
159  return;
160  }
161 
163  data.resize(vertices->size() * sizeof(float3));
164 
165  float3 *data_float3 = reinterpret_cast<float3 *>(data.data());
166 
167  const int *face_indices_array = face_indices->get();
168  const N3fArraySamplePtr values = sample.getVals();
169 
170  for (size_t i = 0; i < face_indices->size(); ++i) {
171  int point_index = face_indices_array[i];
172  data_float3[point_index] = make_float3_from_yup(values->get()[i]);
173  }
174 
175  attr.data.add_data(data, time);
176  break;
177  }
178  case kVaryingScope:
179  case kVertexScope: {
180  const ISampleSelector iss = ISampleSelector(time);
181  const IN3fGeomParam::Sample sample = normals.getExpandedValue(iss);
182 
183  if (!sample.valid()) {
184  return;
185  }
186 
187  CachedData::CachedAttribute &attr = cached_data.add_attribute(ustring(normals.getName()),
188  *normals.getTimeSampling());
189  attr.std = ATTR_STD_VERTEX_NORMAL;
190 
191  const array<float3> *vertices =
192  cached_data.vertices.data_for_time_no_check(time).get_data_or_null();
193 
194  if (!vertices) {
195  return;
196  }
197 
199  data.resize(vertices->size() * sizeof(float3));
200 
201  float3 *data_float3 = reinterpret_cast<float3 *>(data.data());
202 
203  const Imath::V3f *values = sample.getVals()->get();
204 
205  for (size_t i = 0; i < vertices->size(); ++i) {
206  data_float3[i] = make_float3_from_yup(values[i]);
207  }
208 
209  attr.data.add_data(data, time);
210 
211  break;
212  }
213  default: {
214  break;
215  }
216  }
217 }
218 
219 static void add_positions(const P3fArraySamplePtr positions, double time, CachedData &cached_data)
220 {
221  if (!positions) {
222  return;
223  }
224 
225  array<float3> vertices;
226  vertices.reserve(positions->size());
227 
228  for (size_t i = 0; i < positions->size(); i++) {
229  V3f f = positions->get()[i];
230  vertices.push_back_reserved(make_float3_from_yup(f));
231  }
232 
233  cached_data.vertices.add_data(vertices, time);
234 }
235 
236 static void add_triangles(const Int32ArraySamplePtr face_counts,
237  const Int32ArraySamplePtr face_indices,
238  double time,
239  CachedData &cached_data,
240  const array<int> &polygon_to_shader)
241 {
242  if (!face_counts || !face_indices) {
243  return;
244  }
245 
246  const size_t num_faces = face_counts->size();
247  const int *face_counts_array = face_counts->get();
248  const int *face_indices_array = face_indices->get();
249 
250  size_t num_triangles = 0;
251  for (size_t i = 0; i < face_counts->size(); i++) {
252  num_triangles += face_counts_array[i] - 2;
253  }
254 
255  array<int> shader;
256  array<int3> triangles;
257  array<int> uv_loops;
258  shader.reserve(num_triangles);
259  triangles.reserve(num_triangles);
260  uv_loops.reserve(num_triangles * 3);
261  int index_offset = 0;
262 
263  for (size_t i = 0; i < num_faces; i++) {
264  int current_shader = 0;
265 
266  if (!polygon_to_shader.empty()) {
267  current_shader = polygon_to_shader[i];
268  }
269 
270  for (int j = 0; j < face_counts_array[i] - 2; j++) {
271  int v0 = face_indices_array[index_offset];
272  int v1 = face_indices_array[index_offset + j + 1];
273  int v2 = face_indices_array[index_offset + j + 2];
274 
275  shader.push_back_reserved(current_shader);
276 
277  /* Alembic orders the loops following the RenderMan convention, so need to go in reverse. */
278  triangles.push_back_reserved(make_int3(v2, v1, v0));
279  uv_loops.push_back_reserved(index_offset + j + 2);
280  uv_loops.push_back_reserved(index_offset + j + 1);
281  uv_loops.push_back_reserved(index_offset);
282  }
283 
284  index_offset += face_counts_array[i];
285  }
286 
287  cached_data.triangles.add_data(triangles, time);
288  cached_data.uv_loops.add_data(uv_loops, time);
289  cached_data.shader.add_data(shader, time);
290 }
291 
292 static array<int> compute_polygon_to_shader_map(
293  const Int32ArraySamplePtr &face_counts,
294  const vector<FaceSetShaderIndexPair> &face_set_shader_index,
295  ISampleSelector sample_sel)
296 {
297  if (face_set_shader_index.empty()) {
298  return {};
299  }
300 
301  if (!face_counts) {
302  return {};
303  }
304 
305  if (face_counts->size() == 0) {
306  return {};
307  }
308 
309  array<int> polygon_to_shader(face_counts->size());
310 
311  for (const FaceSetShaderIndexPair &pair : face_set_shader_index) {
312  const IFaceSet &face_set = pair.face_set;
313  const IFaceSetSchema face_schem = face_set.getSchema();
314  const IFaceSetSchema::Sample face_sample = face_schem.getValue(sample_sel);
315  const Int32ArraySamplePtr group_faces = face_sample.getFaces();
316  const size_t num_group_faces = group_faces->size();
317 
318  for (size_t l = 0; l < num_group_faces; l++) {
319  size_t pos = (*group_faces)[l];
320 
321  if (pos >= polygon_to_shader.size()) {
322  continue;
323  }
324 
325  polygon_to_shader[pos] = pair.shader_index;
326  }
327  }
328 
329  return polygon_to_shader;
330 }
331 
332 static void read_poly_mesh_geometry(CachedData &cached_data,
333  const PolyMeshSchemaData &data,
334  chrono_t time)
335 {
336  const ISampleSelector iss = ISampleSelector(time);
337 
338  add_positions(data.positions.getValue(iss), time, cached_data);
339 
340  const Int32ArraySamplePtr face_counts = data.face_counts.getValue(iss);
341  const Int32ArraySamplePtr face_indices = data.face_indices.getValue(iss);
342 
343  /* Only copy triangles for other frames if the topology is changing over time as well. */
344  if (data.topology_variance != kHomogeneousTopology || cached_data.triangles.size() == 0) {
345  bool do_triangles = true;
346 
347  /* Compare key with last one to check whether the topology changed. */
348  if (cached_data.triangles.size() > 0) {
349  const ArraySample::Key key = face_indices->getKey();
350 
351  if (key == cached_data.triangles.key1) {
352  do_triangles = false;
353  }
354 
355  cached_data.triangles.key1 = key;
356  }
357 
358  if (do_triangles) {
359  const array<int> polygon_to_shader = compute_polygon_to_shader_map(
360  face_counts, data.shader_face_sets, iss);
361  add_triangles(face_counts, face_indices, time, cached_data, polygon_to_shader);
362  }
363  else {
364  cached_data.triangles.reuse_data_for_last_time(time);
365  cached_data.uv_loops.reuse_data_for_last_time(time);
366  cached_data.shader.reuse_data_for_last_time(time);
367  }
368 
369  /* Initialize the first key. */
370  if (data.topology_variance != kHomogeneousTopology && cached_data.triangles.size() == 1) {
371  cached_data.triangles.key1 = face_indices->getKey();
372  }
373  }
374 
375  if (data.normals.valid()) {
376  add_normals(face_indices, data.normals, time, cached_data);
377  }
378  else {
379  compute_vertex_normals(cached_data, time);
380  }
381 }
382 
383 void read_geometry_data(AlembicProcedural *proc,
384  CachedData &cached_data,
385  const PolyMeshSchemaData &data,
386  Progress &progress)
387 {
388  read_data_loop(proc, cached_data, data, read_poly_mesh_geometry, progress);
389 }
390 
391 /* Subdivision Geometries */
392 
393 static void add_subd_polygons(CachedData &cached_data, const SubDSchemaData &data, chrono_t time)
394 {
395  const ISampleSelector iss = ISampleSelector(time);
396 
397  const Int32ArraySamplePtr face_counts = data.face_counts.getValue(iss);
398  const Int32ArraySamplePtr face_indices = data.face_indices.getValue(iss);
399 
400  array<int> subd_start_corner;
401  array<int> shader;
402  array<int> subd_num_corners;
403  array<bool> subd_smooth;
404  array<int> subd_ptex_offset;
405  array<int> subd_face_corners;
406  array<int> uv_loops;
407 
408  const size_t num_faces = face_counts->size();
409  const int *face_counts_array = face_counts->get();
410  const int *face_indices_array = face_indices->get();
411 
412  int num_ngons = 0;
413  int num_corners = 0;
414  for (size_t i = 0; i < face_counts->size(); i++) {
415  num_ngons += (face_counts_array[i] == 4 ? 0 : 1);
416  num_corners += face_counts_array[i];
417  }
418 
419  subd_start_corner.reserve(num_faces);
420  subd_num_corners.reserve(num_faces);
421  subd_smooth.reserve(num_faces);
422  subd_ptex_offset.reserve(num_faces);
423  shader.reserve(num_faces);
424  subd_face_corners.reserve(num_corners);
425  uv_loops.reserve(num_corners);
426 
427  int start_corner = 0;
428  int current_shader = 0;
429  int ptex_offset = 0;
430 
431  const array<int> polygon_to_shader = compute_polygon_to_shader_map(
432  face_counts, data.shader_face_sets, iss);
433 
434  for (size_t i = 0; i < face_counts->size(); i++) {
435  num_corners = face_counts_array[i];
436 
437  if (!polygon_to_shader.empty()) {
438  current_shader = polygon_to_shader[i];
439  }
440 
441  subd_start_corner.push_back_reserved(start_corner);
442  subd_num_corners.push_back_reserved(num_corners);
443 
444  for (int j = 0; j < num_corners; ++j) {
445  subd_face_corners.push_back_reserved(face_indices_array[start_corner + j]);
446  uv_loops.push_back_reserved(start_corner + j);
447  }
448 
449  shader.push_back_reserved(current_shader);
450  subd_smooth.push_back_reserved(1);
451  subd_ptex_offset.push_back_reserved(ptex_offset);
452 
453  ptex_offset += (num_corners == 4 ? 1 : num_corners);
454 
455  start_corner += num_corners;
456  }
457 
458  cached_data.shader.add_data(shader, time);
459  cached_data.subd_start_corner.add_data(subd_start_corner, time);
460  cached_data.subd_num_corners.add_data(subd_num_corners, time);
461  cached_data.subd_smooth.add_data(subd_smooth, time);
462  cached_data.subd_ptex_offset.add_data(subd_ptex_offset, time);
463  cached_data.subd_face_corners.add_data(subd_face_corners, time);
464  cached_data.num_ngons.add_data(num_ngons, time);
465  cached_data.uv_loops.add_data(uv_loops, time);
466 }
467 
468 static void add_subd_edge_creases(CachedData &cached_data,
469  const SubDSchemaData &data,
470  chrono_t time)
471 {
472  if (!(data.crease_indices.valid() && data.crease_lengths.valid() &&
473  data.crease_sharpnesses.valid())) {
474  return;
475  }
476 
477  const ISampleSelector iss = ISampleSelector(time);
478 
479  const Int32ArraySamplePtr creases_length = data.crease_lengths.getValue(iss);
480  const Int32ArraySamplePtr creases_indices = data.crease_indices.getValue(iss);
481  const FloatArraySamplePtr creases_sharpnesses = data.crease_sharpnesses.getValue(iss);
482 
483  if (creases_length && creases_indices && creases_sharpnesses) {
484  array<int> creases_edge;
485  array<float> creases_weight;
486 
487  creases_edge.reserve(creases_sharpnesses->size() * 2);
488  creases_weight.reserve(creases_sharpnesses->size());
489 
490  int length_offset = 0;
491  int weight_offset = 0;
492  for (size_t c = 0; c < creases_length->size(); ++c) {
493  const int crease_length = creases_length->get()[c];
494 
495  for (size_t j = 0; j < crease_length - 1; ++j) {
496  creases_edge.push_back_reserved(creases_indices->get()[length_offset + j]);
497  creases_edge.push_back_reserved(creases_indices->get()[length_offset + j + 1]);
498  creases_weight.push_back_reserved(creases_sharpnesses->get()[weight_offset++]);
499  }
500 
501  length_offset += crease_length;
502  }
503 
504  cached_data.subd_creases_edge.add_data(creases_edge, time);
505  cached_data.subd_creases_weight.add_data(creases_weight, time);
506  }
507 }
508 
509 static void add_subd_vertex_creases(CachedData &cached_data,
510  const SubDSchemaData &data,
511  chrono_t time)
512 {
513  if (!(data.corner_indices.valid() && data.crease_sharpnesses.valid())) {
514  return;
515  }
516 
517  const ISampleSelector iss = ISampleSelector(time);
518  const Int32ArraySamplePtr creases_indices = data.crease_indices.getValue(iss);
519  const FloatArraySamplePtr creases_sharpnesses = data.crease_sharpnesses.getValue(iss);
520 
521  if (!(creases_indices && creases_sharpnesses) ||
522  creases_indices->size() != creases_sharpnesses->size()) {
523  return;
524  }
525 
526  array<float> sharpnesses;
527  sharpnesses.reserve(creases_indices->size());
529  indices.reserve(creases_indices->size());
530 
531  for (size_t i = 0; i < creases_indices->size(); i++) {
532  indices.push_back_reserved((*creases_indices)[i]);
533  sharpnesses.push_back_reserved((*creases_sharpnesses)[i]);
534  }
535 
536  cached_data.subd_vertex_crease_indices.add_data(indices, time);
537  cached_data.subd_vertex_crease_weights.add_data(sharpnesses, time);
538 }
539 
540 static void read_subd_geometry(CachedData &cached_data, const SubDSchemaData &data, chrono_t time)
541 {
542  const ISampleSelector iss = ISampleSelector(time);
543 
544  add_positions(data.positions.getValue(iss), time, cached_data);
545 
546  if (data.topology_variance != kHomogeneousTopology || cached_data.shader.size() == 0) {
547  add_subd_polygons(cached_data, data, time);
548  add_subd_edge_creases(cached_data, data, time);
549  add_subd_vertex_creases(cached_data, data, time);
550  }
551 }
552 
553 void read_geometry_data(AlembicProcedural *proc,
554  CachedData &cached_data,
555  const SubDSchemaData &data,
556  Progress &progress)
557 {
558  read_data_loop(proc, cached_data, data, read_subd_geometry, progress);
559 }
560 
561 /* Curve Geometries. */
562 
563 static void read_curves_data(CachedData &cached_data, const CurvesSchemaData &data, chrono_t time)
564 {
565  const ISampleSelector iss = ISampleSelector(time);
566 
567  const Int32ArraySamplePtr curves_num_vertices = data.num_vertices.getValue(iss);
568  const P3fArraySamplePtr position = data.positions.getValue(iss);
569 
570  FloatArraySamplePtr radiuses;
571 
572  if (data.widths.valid()) {
573  IFloatGeomParam::Sample wsample = data.widths.getExpandedValue(iss);
574  radiuses = wsample.getVals();
575  }
576 
577  const bool do_radius = (radiuses != nullptr) && (radiuses->size() > 1);
578  float radius = (radiuses && radiuses->size() == 1) ? (*radiuses)[0] : data.default_radius;
579 
580  array<float3> curve_keys;
581  array<float> curve_radius;
582  array<int> curve_first_key;
583  array<int> curve_shader;
584 
585  const bool is_homogeneous = data.topology_variance == kHomogeneousTopology;
586 
587  curve_keys.reserve(position->size());
588  curve_radius.reserve(position->size());
589  curve_first_key.reserve(curves_num_vertices->size());
590  curve_shader.reserve(curves_num_vertices->size());
591 
592  int offset = 0;
593  for (size_t i = 0; i < curves_num_vertices->size(); i++) {
594  const int num_vertices = curves_num_vertices->get()[i];
595 
596  for (int j = 0; j < num_vertices; j++) {
597  const V3f &f = position->get()[offset + j];
598  // todo(@kevindietrich): we are reading too much data?
599  curve_keys.push_back_slow(make_float3_from_yup(f));
600 
601  if (do_radius) {
602  radius = (*radiuses)[offset + j];
603  }
604 
605  curve_radius.push_back_slow(radius * data.radius_scale);
606  }
607 
608  if (!is_homogeneous || cached_data.curve_first_key.size() == 0) {
609  curve_first_key.push_back_reserved(offset);
610  curve_shader.push_back_reserved(0);
611  }
612 
613  offset += num_vertices;
614  }
615 
616  cached_data.curve_keys.add_data(curve_keys, time);
617  cached_data.curve_radius.add_data(curve_radius, time);
618 
619  if (!is_homogeneous || cached_data.curve_first_key.size() == 0) {
620  cached_data.curve_first_key.add_data(curve_first_key, time);
621  cached_data.curve_shader.add_data(curve_shader, time);
622  }
623 }
624 
625 void read_geometry_data(AlembicProcedural *proc,
626  CachedData &cached_data,
627  const CurvesSchemaData &data,
628  Progress &progress)
629 {
630  read_data_loop(proc, cached_data, data, read_curves_data, progress);
631 }
632 
633 /* Points Geometries. */
634 
635 static void read_points_data(CachedData &cached_data, const PointsSchemaData &data, chrono_t time)
636 {
637  const ISampleSelector iss = ISampleSelector(time);
638 
639  const P3fArraySamplePtr position = data.positions.getValue(iss);
640  FloatArraySamplePtr radiuses;
641 
642  array<float3> a_positions;
643  array<float> a_radius;
644  array<int> a_shader;
645  a_positions.reserve(position->size());
646  a_radius.reserve(position->size());
647  a_shader.reserve(position->size());
648 
649  if (data.radiuses.valid()) {
650  IFloatGeomParam::Sample wsample = data.radiuses.getExpandedValue(iss);
651  radiuses = wsample.getVals();
652  }
653 
654  const bool do_radius = (radiuses != nullptr) && (radiuses->size() > 1);
655  float radius = (radiuses && radiuses->size() == 1) ? (*radiuses)[0] : data.default_radius;
656 
657  int offset = 0;
658  for (size_t i = 0; i < position->size(); i++) {
659  const V3f &f = position->get()[offset + i];
660  a_positions.push_back_slow(make_float3_from_yup(f));
661 
662  if (do_radius) {
663  radius = (*radiuses)[offset + i];
664  a_radius.push_back_slow(radius);
665  }
666 
667  a_shader.push_back_slow((int)0);
668  }
669 
670  cached_data.points.add_data(a_positions, time);
671  cached_data.radiuses.add_data(a_radius, time);
672  cached_data.points_shader.add_data(a_shader, time);
673 }
674 
675 void read_geometry_data(AlembicProcedural *proc,
676  CachedData &cached_data,
677  const PointsSchemaData &data,
678  Progress &progress)
679 {
680  read_data_loop(proc, cached_data, data, read_points_data, progress);
681 }
682 /* Attributes conversions. */
683 
684 /* Type traits for converting between Alembic and Cycles types.
685  */
686 
687 template<typename T> struct value_type_converter {
688  using cycles_type = float;
689  /* Use `TypeDesc::FLOAT` instead of `TypeFloat` to work around a compiler bug in gcc 11. */
690  static constexpr TypeDesc type_desc = TypeDesc::FLOAT;
691  static constexpr const char *type_name = "float (default)";
692 
693  static cycles_type convert_value(T value)
694  {
695  return static_cast<float>(value);
696  }
697 };
698 
699 template<> struct value_type_converter<Imath::V2f> {
700  using cycles_type = float2;
701  static constexpr TypeDesc type_desc = TypeFloat2;
702  static constexpr const char *type_name = "float2";
703 
704  static cycles_type convert_value(Imath::V2f value)
705  {
706  return make_float2(value.x, value.y);
707  }
708 };
709 
710 template<> struct value_type_converter<Imath::V3f> {
711  using cycles_type = float3;
712  static constexpr TypeDesc type_desc = TypeVector;
713  static constexpr const char *type_name = "float3";
714 
715  static cycles_type convert_value(Imath::V3f value)
716  {
717  return make_float3_from_yup(value);
718  }
719 };
720 
721 template<> struct value_type_converter<Imath::C3f> {
722  using cycles_type = uchar4;
723  static constexpr TypeDesc type_desc = TypeRGBA;
724  static constexpr const char *type_name = "rgb";
725 
726  static cycles_type convert_value(Imath::C3f value)
727  {
728  return color_float_to_byte(make_float3(value.x, value.y, value.z));
729  }
730 };
731 
732 template<> struct value_type_converter<Imath::C4f> {
733  using cycles_type = uchar4;
734  static constexpr TypeDesc type_desc = TypeRGBA;
735  static constexpr const char *type_name = "rgba";
736 
737  static cycles_type convert_value(Imath::C4f value)
738  {
739  return color_float4_to_uchar4(make_float4(value.r, value.g, value.b, value.a));
740  }
741 };
742 
743 /* Main function used to read attributes of any type. */
744 template<typename TRAIT>
745 static void process_attribute(CachedData &cache,
746  CachedData::CachedAttribute &attribute,
747  GeometryScope scope,
748  const typename ITypedGeomParam<TRAIT>::Sample &sample,
749  double time)
750 {
751  using abc_type = typename TRAIT::value_type;
752  using cycles_type = typename value_type_converter<abc_type>::cycles_type;
753 
754  const TypedArraySample<TRAIT> &values = *sample.getVals();
755 
756  switch (scope) {
757  case kConstantScope:
758  case kVertexScope: {
759  const array<float3> *vertices =
760  cache.vertices.data_for_time_no_check(time).get_data_or_null();
761 
762  if (!vertices) {
763  attribute.data.add_no_data(time);
764  return;
765  }
766 
767  if (vertices->size() != values.size()) {
768  attribute.data.add_no_data(time);
769  return;
770  }
771 
772  array<char> data(vertices->size() * sizeof(cycles_type));
773 
774  cycles_type *pod_typed_data = reinterpret_cast<cycles_type *>(data.data());
775 
776  for (size_t i = 0; i < values.size(); ++i) {
777  *pod_typed_data++ = value_type_converter<abc_type>::convert_value(values[i]);
778  }
779 
780  attribute.data.add_data(data, time);
781  break;
782  }
783  case kVaryingScope: {
784  const array<int3> *triangles =
785  cache.triangles.data_for_time_no_check(time).get_data_or_null();
786 
787  if (!triangles) {
788  attribute.data.add_no_data(time);
789  return;
790  }
791 
792  array<char> data(triangles->size() * 3 * sizeof(cycles_type));
793 
794  cycles_type *pod_typed_data = reinterpret_cast<cycles_type *>(data.data());
795 
796  for (const int3 &tri : *triangles) {
797  *pod_typed_data++ = value_type_converter<abc_type>::convert_value(values[tri.x]);
798  *pod_typed_data++ = value_type_converter<abc_type>::convert_value(values[tri.y]);
799  *pod_typed_data++ = value_type_converter<abc_type>::convert_value(values[tri.z]);
800  }
801 
802  attribute.data.add_data(data, time);
803  break;
804  }
805  default: {
806  break;
807  }
808  }
809 }
810 
811 /* UVs are processed separately as their indexing is based on loops, instead of vertices or
812  * corners. */
813 static void process_uvs(CachedData &cache,
814  CachedData::CachedAttribute &attribute,
815  GeometryScope scope,
816  const IV2fGeomParam::Sample &sample,
817  double time)
818 {
819  if (scope != kFacevaryingScope && scope != kVaryingScope && scope != kVertexScope) {
820  return;
821  }
822 
823  const array<int> *uv_loops = cache.uv_loops.data_for_time_no_check(time).get_data_or_null();
824 
825  /* It's ok to not have loop indices, as long as the scope is not face-varying. */
826  if (!uv_loops && scope == kFacevaryingScope) {
827  return;
828  }
829 
830  const array<int3> *triangles = cache.triangles.data_for_time_no_check(time).get_data_or_null();
831  const array<int> *corners =
832  cache.subd_face_corners.data_for_time_no_check(time).get_data_or_null();
833 
835  if (triangles) {
836  data.resize(triangles->size() * 3 * sizeof(float2));
837  }
838  else if (corners) {
839  data.resize(corners->size() * sizeof(float2));
840  }
841  else {
842  return;
843  }
844 
845  float2 *data_float2 = reinterpret_cast<float2 *>(data.data());
846 
847  const uint32_t *indices = sample.getIndices()->get();
848  const V2f *values = sample.getVals()->get();
849 
850  if (scope == kFacevaryingScope) {
851  for (const int uv_loop_index : *uv_loops) {
852  const uint32_t index = indices[uv_loop_index];
853  *data_float2++ = make_float2(values[index][0], values[index][1]);
854  }
855  }
856  else if (scope == kVaryingScope || scope == kVertexScope) {
857  if (triangles) {
858  for (size_t i = 0; i < triangles->size(); i++) {
859  const int3 t = (*triangles)[i];
860  *data_float2++ = make_float2(values[t.x][0], values[t.x][1]);
861  *data_float2++ = make_float2(values[t.y][0], values[t.y][1]);
862  *data_float2++ = make_float2(values[t.z][0], values[t.z][1]);
863  }
864  }
865  else if (corners) {
866  for (size_t i = 0; i < corners->size(); i++) {
867  const int c = (*corners)[i];
868  *data_float2++ = make_float2(values[c][0], values[c][1]);
869  }
870  }
871  }
872 
873  attribute.data.add_data(data, time);
874 }
875 
876 /* Type of the function used to parse one time worth of data, either process_uvs or
877  * process_attribute_generic. */
878 template<typename TRAIT>
879 using process_callback_type = void (*)(CachedData &,
880  CachedData::CachedAttribute &,
881  GeometryScope,
882  const typename ITypedGeomParam<TRAIT>::Sample &,
883  double);
884 
885 /* Main loop to process the attributes, this will look at the given param's TimeSampling and
886  * extract data based on which frame time is requested by the procedural and execute the callback
887  * for each of those requested time. */
888 template<typename TRAIT>
889 static void read_attribute_loop(AlembicProcedural *proc,
890  CachedData &cache,
891  const ITypedGeomParam<TRAIT> &param,
892  process_callback_type<TRAIT> callback,
893  Progress &progress,
895 {
896  const std::set<chrono_t> times = get_relevant_sample_times(
897  proc, *param.getTimeSampling(), param.getNumSamples());
898 
899  if (times.empty()) {
900  return;
901  }
902 
903  std::string name = param.getName();
904 
905  if (std == ATTR_STD_UV) {
906  std::string uv_source_name = Alembic::Abc::GetSourceName(param.getMetaData());
907 
908  /* According to the convention, primary UVs should have had their name
909  * set using Alembic::Abc::SetSourceName, but you can't expect everyone
910  * to follow it! :) */
911  if (!uv_source_name.empty()) {
912  name = uv_source_name;
913  }
914  }
915 
916  CachedData::CachedAttribute &attribute = cache.add_attribute(ustring(name),
917  *param.getTimeSampling());
918 
919  using abc_type = typename TRAIT::value_type;
920 
921  attribute.data.set_time_sampling(*param.getTimeSampling());
922  attribute.std = std;
923  attribute.type_desc = value_type_converter<abc_type>::type_desc;
924 
925  if (attribute.type_desc == TypeRGBA) {
927  }
928  else {
929  if (param.getScope() == kVaryingScope || param.getScope() == kFacevaryingScope) {
930  attribute.element = ATTR_ELEMENT_CORNER;
931  }
932  else {
933  attribute.element = ATTR_ELEMENT_VERTEX;
934  }
935  }
936 
937  for (const chrono_t time : times) {
938  if (progress.get_cancel()) {
939  return;
940  }
941 
942  ISampleSelector iss = ISampleSelector(time);
943  typename ITypedGeomParam<TRAIT>::Sample sample;
944  param.getIndexed(sample, iss);
945 
946  if (!sample.valid()) {
947  continue;
948  }
949 
950  if (!sample.getVals()) {
951  attribute.data.add_no_data(time);
952  continue;
953  }
954 
955  /* Check whether we already loaded constant data. */
956  if (attribute.data.size() != 0) {
957  if (param.isConstant()) {
958  return;
959  }
960 
961  const ArraySample::Key indices_key = sample.getIndices()->getKey();
962  const ArraySample::Key values_key = sample.getVals()->getKey();
963 
964  const bool is_same_as_last_time = (indices_key == attribute.data.key1 &&
965  values_key == attribute.data.key2);
966 
967  attribute.data.key1 = indices_key;
968  attribute.data.key2 = values_key;
969 
970  if (is_same_as_last_time) {
971  attribute.data.reuse_data_for_last_time(time);
972  continue;
973  }
974  }
975 
976  callback(cache, attribute, param.getScope(), sample, time);
977  }
978 }
979 
980 /* Attributes requests. */
981 
982 /* This structure is used to tell which ICoumpoundProperty the PropertyHeader comes from, as we
983  * need the parent when downcasting to the proper type. */
984 struct PropHeaderAndParent {
985  const PropertyHeader *prop;
986  ICompoundProperty parent;
987 };
988 
989 /* Parse the ICompoundProperty to look for properties whose names appear in the
990  * AttributeRequestSet. This also looks into any child ICompoundProperty of the given
991  * ICompoundProperty. If no property of the given name is found, let it be that way, Cycles will
992  * use a zero value for the missing attribute. */
993 static void parse_requested_attributes_recursive(const AttributeRequestSet &requested_attributes,
994  const ICompoundProperty &arb_geom_params,
995  vector<PropHeaderAndParent> &requested_properties)
996 {
997  if (!arb_geom_params.valid()) {
998  return;
999  }
1000 
1001  for (const AttributeRequest &req : requested_attributes.requests) {
1002  const PropertyHeader *property_header = arb_geom_params.getPropertyHeader(req.name.c_str());
1003 
1004  if (!property_header) {
1005  continue;
1006  }
1007 
1008  requested_properties.push_back({property_header, arb_geom_params});
1009  }
1010 
1011  /* Look into children compound properties. */
1012  for (size_t i = 0; i < arb_geom_params.getNumProperties(); ++i) {
1013  const PropertyHeader &property_header = arb_geom_params.getPropertyHeader(i);
1014 
1015  if (property_header.isCompound()) {
1016  ICompoundProperty compound_property = ICompoundProperty(arb_geom_params,
1017  property_header.getName());
1018  parse_requested_attributes_recursive(
1019  requested_attributes, compound_property, requested_properties);
1020  }
1021  }
1022 }
1023 
1024 /* Main entry point for parsing requested attributes from an ICompoundProperty, this exists so that
1025  * we can simply return the list of properties instead of allocating it on the stack and passing it
1026  * as a parameter. */
1027 static vector<PropHeaderAndParent> parse_requested_attributes(
1028  const AttributeRequestSet &requested_attributes, const ICompoundProperty &arb_geom_params)
1029 {
1030  vector<PropHeaderAndParent> requested_properties;
1031  parse_requested_attributes_recursive(
1032  requested_attributes, arb_geom_params, requested_properties);
1033  return requested_properties;
1034 }
1035 
1036 /* Read the attributes requested by the shaders from the archive. This will recursively find named
1037  * attributes from the AttributeRequestSet in the ICompoundProperty and any of its compound child.
1038  * The attributes are added to the CachedData's attribute list. For each attribute we will try to
1039  * deduplicate data across consecutive frames. */
1040 void read_attributes(AlembicProcedural *proc,
1041  CachedData &cache,
1042  const ICompoundProperty &arb_geom_params,
1043  const IV2fGeomParam &default_uvs_param,
1044  const AttributeRequestSet &requested_attributes,
1045  Progress &progress)
1046 {
1047  if (default_uvs_param.valid()) {
1048  /* Only the default UVs should be treated as the standard UV attribute. */
1049  read_attribute_loop(proc, cache, default_uvs_param, process_uvs, progress, ATTR_STD_UV);
1050  }
1051 
1052  vector<PropHeaderAndParent> requested_properties = parse_requested_attributes(
1053  requested_attributes, arb_geom_params);
1054 
1055  for (const PropHeaderAndParent &prop_and_parent : requested_properties) {
1056  if (progress.get_cancel()) {
1057  return;
1058  }
1059 
1060  const PropertyHeader *prop = prop_and_parent.prop;
1061  const ICompoundProperty &parent = prop_and_parent.parent;
1062 
1063  if (IBoolGeomParam::matches(*prop)) {
1064  const IBoolGeomParam &param = IBoolGeomParam(parent, prop->getName());
1065  read_attribute_loop(proc, cache, param, process_attribute<BooleanTPTraits>, progress);
1066  }
1067  else if (IInt32GeomParam::matches(*prop)) {
1068  const IInt32GeomParam &param = IInt32GeomParam(parent, prop->getName());
1069  read_attribute_loop(proc, cache, param, process_attribute<Int32TPTraits>, progress);
1070  }
1071  else if (IFloatGeomParam::matches(*prop)) {
1072  const IFloatGeomParam &param = IFloatGeomParam(parent, prop->getName());
1073  read_attribute_loop(proc, cache, param, process_attribute<Float32TPTraits>, progress);
1074  }
1075  else if (IV2fGeomParam::matches(*prop)) {
1076  const IV2fGeomParam &param = IV2fGeomParam(parent, prop->getName());
1077  if (Alembic::AbcGeom::isUV(*prop)) {
1078  read_attribute_loop(proc, cache, param, process_uvs, progress);
1079  }
1080  else {
1081  read_attribute_loop(proc, cache, param, process_attribute<V2fTPTraits>, progress);
1082  }
1083  }
1084  else if (IV3fGeomParam::matches(*prop)) {
1085  const IV3fGeomParam &param = IV3fGeomParam(parent, prop->getName());
1086  read_attribute_loop(proc, cache, param, process_attribute<V3fTPTraits>, progress);
1087  }
1088  else if (IN3fGeomParam::matches(*prop)) {
1089  const IN3fGeomParam &param = IN3fGeomParam(parent, prop->getName());
1090  read_attribute_loop(proc, cache, param, process_attribute<N3fTPTraits>, progress);
1091  }
1092  else if (IC3fGeomParam::matches(*prop)) {
1093  const IC3fGeomParam &param = IC3fGeomParam(parent, prop->getName());
1094  read_attribute_loop(proc, cache, param, process_attribute<C3fTPTraits>, progress);
1095  }
1096  else if (IC4fGeomParam::matches(*prop)) {
1097  const IC4fGeomParam &param = IC4fGeomParam(parent, prop->getName());
1098  read_attribute_loop(proc, cache, param, process_attribute<C4fTPTraits>, progress);
1099  }
1100  }
1101 
1102  cache.invalidate_last_loaded_time(true);
1103 }
1104 
1106 
1107 #endif
typedef float(TangentPoint)[2]
typedef double(DMatrix)[4][4]
struct Key Key
_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
_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 v1
float float2[2]
float float3[3]
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 Retrieve a color attribute
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert * v
vector< AttributeRequest > requests
bool get_cancel() const
Definition: progress.h:90
size_t size() const
size_t empty() const
void push_back_reserved(const T &t)
void reserve(size_t newcapacity)
void push_back_slow(const T &t)
#define CCL_NAMESPACE_END
Definition: cuda/compat.h:9
double time
DEGForeachIDComponentCallback callback
SyclQueue void void size_t num_bytes void
uint pos
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
ccl_gpu_kernel_postfix ccl_global float int int int int float bool int offset
ccl_gpu_kernel_postfix int ccl_global int * indices
ccl_gpu_kernel_postfix ccl_global float int int int int ccl_global const float int int int int int int int int int int int int num_samples
AttributeStandard
Definition: kernel/types.h:612
@ ATTR_STD_UV
Definition: kernel/types.h:616
@ ATTR_STD_VERTEX_NORMAL
Definition: kernel/types.h:614
@ ATTR_STD_NONE
Definition: kernel/types.h:613
@ ATTR_ELEMENT_CORNER_BYTE
Definition: kernel/types.h:605
@ ATTR_ELEMENT_CORNER
Definition: kernel/types.h:604
@ ATTR_ELEMENT_VERTEX
Definition: kernel/types.h:602
#define T
#define make_float2(x, y)
Definition: metal/compat.h:203
#define make_float4(x, y, z, w)
Definition: metal/compat.h:205
#define make_int3(x, y, z)
Definition: metal/compat.h:207
#define make_float3(x, y, z)
Definition: metal/compat.h:204
static unsigned c
Definition: RandGen.cpp:83
vec_base< T, Size > normalize(const vec_base< T, Size > &v)
MutableSpan< float3 > positions
MutableSpan< float3 > normals
static constexpr TypeDesc TypeRGBA(TypeDesc::FLOAT, TypeDesc::VEC4, TypeDesc::COLOR)
CCL_NAMESPACE_BEGIN static constexpr OIIO_NAMESPACE_USING TypeDesc TypeFloat2(TypeDesc::FLOAT, TypeDesc::VEC2)
@ FLOAT
unsigned int uint32_t
Definition: stdint.h:80
float size
Definition: particles.h:27
ccl_device uchar4 color_float4_to_uchar4(float4 c)
Definition: util/color.h:33
ccl_device uchar4 color_float_to_byte(float3 c)
Definition: util/color.h:22