Blender V4.5
usd_writer_pointinstancer.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2025 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
7#include "usd_utils.hh"
9#include "usd_writer_mesh.hh"
10#include "usd_writer_points.hh"
11
13#include "BKE_collection.hh"
14#include "BKE_geometry_set.hh"
16#include "BKE_instances.hh"
17#include "BKE_lib_id.hh"
18#include "BKE_node.hh"
20#include "BKE_node_runtime.hh"
21#include "BKE_object.hh"
22#include "BKE_report.hh"
23
24#include "BLI_math_euler.hh"
25#include "BLI_math_matrix.hh"
26
28#include "DNA_layer_types.h"
29#include "DNA_mesh_types.h"
30#include "DNA_node_types.h"
31#include "DNA_object_types.h"
33
34#include <pxr/base/gf/math.h>
35#include <pxr/base/gf/matrix3f.h>
36#include <pxr/base/gf/quatd.h>
37#include <pxr/base/gf/quatf.h>
38#include <pxr/base/gf/range3f.h>
39#include <pxr/base/gf/rotation.h>
40#include <pxr/base/gf/vec3d.h>
41#include <pxr/base/gf/vec3f.h>
42#include <pxr/base/vt/array.h>
43#include <pxr/usd/usdGeom/pointInstancer.h>
44#include <pxr/usd/usdGeom/primvarsAPI.h>
45#include <pxr/usd/usdGeom/scope.h>
46#include <pxr/usd/usdGeom/xform.h>
47
50#include <fmt/format.h>
51
52namespace blender::io::usd {
53
55 const USDExporterContext &ctx,
56 std::set<std::pair<pxr::SdfPath, Object *>> &prototype_paths,
57 std::unique_ptr<USDAbstractWriter> base_writer)
58 : USDAbstractWriter(ctx),
59 base_writer_(std::move(base_writer)),
60 prototype_paths_(prototype_paths)
61{
62}
63
65{
66 /* Write the base data first (e.g., mesh, curves, points) */
67 if (base_writer_) {
68 base_writer_->write(context);
69
70 if (usd_export_context_.add_skel_mapping_fn &&
71 (usd_export_context_.export_params.export_armatures ||
72 usd_export_context_.export_params.export_shapekeys))
73 {
74 usd_export_context_.add_skel_mapping_fn(context.object, base_writer_->usd_path());
75 }
76 }
77
78 const pxr::UsdStageRefPtr stage = usd_export_context_.stage;
79 Object *object_eval = context.object;
80 bke::GeometrySet instance_geometry_set = bke::object_get_evaluated_geometry_set(*object_eval);
81
82 const bke::GeometryComponent *component = instance_geometry_set.get_component(
84
85 const bke::Instances *instances = static_cast<const bke::InstancesComponent &>(*component).get();
86
87 int instance_num = instances->instances_num();
88 const pxr::SdfPath &usd_path = usd_export_context_.usd_path;
89 const pxr::UsdGeomPointInstancer usd_instancer = pxr::UsdGeomPointInstancer::Define(stage,
90 usd_path);
91 const pxr::UsdTimeCode timecode = get_export_time_code();
92
93 Span<float4x4> transforms = instances->transforms();
94 BLI_assert(transforms.size() >= instance_num);
95
96 if (transforms.size() != instance_num) {
97 BKE_reportf(this->reports(),
99 "Instances number '%d' doesn't match transforms size '%d'",
100 instance_num,
101 int(transforms.size()));
102 return;
103 }
104
105 /* evaluated positions */
106 pxr::UsdAttribute position_attr = usd_instancer.CreatePositionsAttr();
107 pxr::VtArray<pxr::GfVec3f> positions(instance_num);
108 for (int i = 0; i < instance_num; i++) {
109 const float3 &pos = transforms[i].location();
110 positions[i] = pxr::GfVec3f(pos.x, pos.y, pos.z);
111 }
112 blender::io::usd::set_attribute(position_attr, positions, timecode, usd_value_writer_);
113
114 /* orientations */
115 pxr::UsdAttribute orientations_attr = usd_instancer.CreateOrientationsAttr();
116 pxr::VtArray<pxr::GfQuath> orientation(instance_num);
117 for (int i = 0; i < instance_num; i++) {
118 const float3 euler = float3(math::to_euler(math::normalize(transforms[i])));
120 orientation[i] = pxr::GfQuath(quat.w, pxr::GfVec3h(quat.x, quat.y, quat.z));
121 }
122 blender::io::usd::set_attribute(orientations_attr, orientation, timecode, usd_value_writer_);
123
124 /* scales */
125 pxr::UsdAttribute scales_attr = usd_instancer.CreateScalesAttr();
126 pxr::VtArray<pxr::GfVec3f> scales(instance_num);
127 for (int i = 0; i < instance_num; i++) {
128 const MatBase<float, 4, 4> &mat = transforms[i];
129 blender::float3 scale_vec = math::to_scale<true>(mat);
130 scales[i] = pxr::GfVec3f(scale_vec.x, scale_vec.y, scale_vec.z);
131 }
132 blender::io::usd::set_attribute(scales_attr, scales, timecode, usd_value_writer_);
133
134 /* other attr */
135 bke::AttributeAccessor attributes_eval = *component->attributes();
136 attributes_eval.foreach_attribute([&](const bke::AttributeIter &iter) {
137 if (iter.name[0] == '.' || blender::bke::attribute_name_is_anonymous(iter.name) ||
138 ELEM(iter.name, "instance_transform") || ELEM(iter.name, "scale") ||
139 ELEM(iter.name, "orientation") || ELEM(iter.name, "mask") ||
140 ELEM(iter.name, "proto_index") || ELEM(iter.name, "id"))
141 {
142 return;
143 }
144
145 this->write_attribute_data(iter, usd_instancer, timecode);
146 });
147
148 /* prototypes relations */
149 const pxr::SdfPath protoParentPath = usd_path.AppendChild(pxr::TfToken("Prototypes"));
150 pxr::UsdPrim prototypesOver = stage->DefinePrim(protoParentPath);
151 pxr::SdfPathVector proto_wrapper_paths;
152
153 std::map<std::string, int> proto_index_map;
154 std::map<std::string, pxr::SdfPath> proto_path_map;
155
156 if (!prototype_paths_.empty() && usd_instancer) {
157 int iter = 0;
158
159 for (const std::pair<pxr::SdfPath, Object *> &entry : prototype_paths_) {
160 const pxr::SdfPath &source_path = entry.first;
161 Object *obj = entry.second;
162
163 if (source_path.IsEmpty()) {
164 continue;
165 }
166
167 const pxr::SdfPath proto_path = protoParentPath.AppendChild(
168 pxr::TfToken(proto_name_ + "_" + std::to_string(iter)));
169
170 pxr::UsdPrim prim = stage->DefinePrim(proto_path);
171
172 /* To avoid USD error of Unresolved reference prim path, make sure the referenced path
173 * exists. */
174 stage->DefinePrim(source_path);
175 prim.GetReferences().AddReference(pxr::SdfReference("", source_path));
176 proto_wrapper_paths.push_back(proto_path);
177
178 std::string ob_name = BKE_id_name(obj->id);
179 proto_index_map[ob_name] = iter;
180 proto_path_map[ob_name] = proto_path;
181
182 ++iter;
183 }
184 usd_instancer.GetPrototypesRel().SetTargets(proto_wrapper_paths);
185 stage->GetRootLayer()->Save();
186 }
187
188 /* proto indices */
189 /* must be the last to populate */
190 pxr::UsdAttribute proto_indices_attr = usd_instancer.CreateProtoIndicesAttr();
191 pxr::VtArray<int> proto_indices;
192 std::vector<std::pair<int, int>> collection_instance_object_count_map;
193
194 Span<int> reference_handles = instances->reference_handles();
195 Span<bke::InstanceReference> references = instances->references();
196 std::map<std::string, int> final_proto_index_map;
197
198 for (int i = 0; i < instance_num; i++) {
199 bke::InstanceReference reference = references[reference_handles[i]];
200
201 process_instance_reference(reference,
202 i,
203 proto_index_map,
204 final_proto_index_map,
205 proto_path_map,
206 stage,
207 proto_indices,
208 collection_instance_object_count_map);
209 }
210
211 blender::io::usd::set_attribute(proto_indices_attr, proto_indices, timecode, usd_value_writer_);
212
213 /* Handle Collection Prototypes */
214 if (!collection_instance_object_count_map.empty()) {
215 handle_collection_prototypes(
216 usd_instancer, timecode, instance_num, collection_instance_object_count_map);
217 }
218
219 /* Clean unused prototype. When finding prototype paths under the context of a point instancer,
220 * all the prototypes are collected, even those used by lower-level nested child PointInstancers.
221 * It can happen that different levels in nested PointInstancers share the same prototypes, but
222 * if not, we need to clean the extra prototypes from the prototype relationship for a cleaner
223 * USD export. */
224 compact_prototypes(usd_instancer, timecode, proto_wrapper_paths);
225
226 stage->GetRootLayer()->Save();
227}
228
229void USDPointInstancerWriter::process_instance_reference(
230 const bke::InstanceReference &reference,
231 int instance_index,
232 std::map<std::string, int> &proto_index_map,
233 std::map<std::string, int> &final_proto_index_map,
234 std::map<std::string, pxr::SdfPath> &proto_path_map,
235 pxr::UsdStageRefPtr stage,
236 pxr::VtArray<int> &proto_indices,
237 std::vector<std::pair<int, int>> &collection_instance_object_count_map)
238{
239 switch (reference.type()) {
241 Object &object = reference.object();
242 std::string ob_name = BKE_id_name(object.id);
243
244 if (proto_index_map.find(ob_name) != proto_index_map.end()) {
245 proto_indices.push_back(proto_index_map[ob_name]);
246
247 final_proto_index_map[ob_name] = proto_index_map[ob_name];
248
249 /* If the reference is Object, clear prototype's local transform to identity to avoid
250 * double transforms. The PointInstancer will fully control instance placement. */
251 override_transform(stage, proto_path_map[ob_name], float4x4::identity());
252 }
253 break;
254 }
255
257 Collection &collection = reference.collection();
258 int object_num = 0;
259 FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (&collection, object) {
260 std::string ob_name = BKE_id_name(object->id);
261
262 if (proto_index_map.find(ob_name) != proto_index_map.end()) {
263 object_num += 1;
264 proto_indices.push_back(proto_index_map[ob_name]);
265
266 final_proto_index_map[ob_name] = proto_index_map[ob_name];
267 }
268 }
270 collection_instance_object_count_map.push_back(std::make_pair(instance_index, object_num));
271 break;
272 }
273
275 bke::GeometrySet geometry_set = reference.geometry_set();
276 std::string set_name = geometry_set.name;
277
278 if (proto_index_map.find(set_name) != proto_index_map.end()) {
279 proto_indices.push_back(proto_index_map[set_name]);
280
281 final_proto_index_map[set_name] = proto_index_map[set_name];
282 }
283
284 Vector<const bke::GeometryComponent *> components = geometry_set.get_components();
285 for (const bke::GeometryComponent *comp : components) {
286 if (const bke::Instances *instances =
287 static_cast<const bke::InstancesComponent &>(*comp).get())
288 {
289 Span<int> ref_handles = instances->reference_handles();
290 Span<bke::InstanceReference> refs = instances->references();
291
292 /* If the top-level GeometrySet is not in proto_index_map, recursively traverse child
293 * InstanceReferences to resolve prototype indices. If the name matches proto_index_map,
294 * skip traversal to avoid duplicates, since GeometrySet names may overlap with object
295 * names. */
296 if (proto_index_map.find(set_name) == proto_index_map.end()) {
297 for (int index = 0; index < ref_handles.size(); ++index) {
298 const bke::InstanceReference &child_ref = refs[ref_handles[index]];
299
300 /* Recursively traverse nested GeometrySets to resolve prototype indices for all
301 * instances. */
302 process_instance_reference(child_ref,
303 instance_index,
304 proto_index_map,
305 final_proto_index_map,
306 proto_path_map,
307 stage,
308 proto_indices,
309 collection_instance_object_count_map);
310 }
311 }
312
313 /* If the reference is GeometrySet, then override the transform with the transform of the
314 * Instance inside this GeometrySet. */
315 Span<float4x4> transforms = instances->transforms();
316 if (transforms.size() == 1) {
317 if (proto_path_map.find(set_name) != proto_path_map.end()) {
318 override_transform(stage, proto_path_map[set_name], transforms[0]);
319 }
320 }
321 }
322 }
323 break;
324 }
325
327 default:
328 break;
329 }
330}
331
332void USDPointInstancerWriter::compact_prototypes(const pxr::UsdGeomPointInstancer &usd_instancer,
333 const pxr::UsdTimeCode timecode,
334 const pxr::SdfPathVector &proto_paths)
335{
336 pxr::UsdAttribute proto_indices_attr = usd_instancer.GetProtoIndicesAttr();
337 pxr::VtArray<int> proto_indices;
338 if (!proto_indices_attr.Get(&proto_indices, timecode)) {
339 return;
340 }
341
343 std::set<int> used_proto_indices(proto_indices.begin(), proto_indices.end());
344
345 std::map<int, int> remap;
346 int new_index = 0;
347 for (int i = 0; i < proto_paths.size(); ++i) {
348 if (used_proto_indices.count(i)) {
349 remap[i] = new_index++;
350 }
351 }
352
354 for (int &idx : proto_indices) {
355 idx = remap[idx];
356 }
357 proto_indices_attr.Set(proto_indices, timecode);
358
359 pxr::SdfPathVector compact_proto_paths;
360 for (int i = 0; i < proto_paths.size(); ++i) {
361 if (used_proto_indices.count(i)) {
362 compact_proto_paths.push_back(proto_paths[i]);
363 }
364 }
365
366 usd_instancer.GetPrototypesRel().SetTargets(compact_proto_paths);
367}
368
369void USDPointInstancerWriter::override_transform(pxr::UsdStageRefPtr stage,
370 const pxr::SdfPath &proto_path,
371 const float4x4 &transform)
372{
373 // Extract translation
374 const float3 &pos = transform.location();
375 pxr::GfVec3d override_position(pos.x, pos.y, pos.z);
376
377 // Extract rotation
379 pxr::GfVec3f override_rotation(euler.x, euler.y, euler.z);
380
381 // Extract scale
382 const float3 scale_vec = math::to_scale<true>(transform);
383 pxr::GfVec3f override_scale(scale_vec.x, scale_vec.y, scale_vec.z);
384
385 pxr::UsdPrim prim = stage->GetPrimAtPath(proto_path);
386 if (!prim) {
387 return;
388 }
389
390 pxr::UsdGeomXformable xformable(prim);
391 xformable.ClearXformOpOrder();
392 xformable.AddTranslateOp().Set(override_position);
393 xformable.AddRotateXYZOp().Set(override_rotation);
394 xformable.AddScaleOp().Set(override_scale);
395}
396
397template<typename T>
398static pxr::VtArray<T> DuplicateArray(const pxr::VtArray<T> &original, size_t copies)
399{
400 pxr::VtArray<T> newArray;
401 size_t originalSize = original.size();
402 newArray.resize(originalSize * copies);
403 for (size_t i = 0; i < copies; ++i) {
404 std::copy(original.begin(), original.end(), newArray.begin() + i * originalSize);
405 }
406 return newArray;
407}
408
409template<typename T, typename GetterFunc, typename CreatorFunc>
410static void DuplicatePerInstanceAttribute(const GetterFunc &getter,
411 const CreatorFunc &creator,
412 size_t copies,
413 const pxr::UsdTimeCode &timecode)
414{
415 pxr::VtArray<T> values;
416 if (getter().Get(&values, timecode) && !values.empty()) {
417 auto newValues = DuplicateArray(values, copies);
418 creator().Set(newValues, timecode);
419 }
420}
421
422template<typename T, typename GetterFunc, typename CreatorFunc>
423static void ExpandAttributePerInstance(const GetterFunc &getter,
424 const CreatorFunc &creator,
425 const std::vector<std::pair<int, int>> &instance_object_map,
426 const pxr::UsdTimeCode &timecode)
427{
428 // MARK: Handle Collection Prototypes
429 // -----------------------------------------------------------------------------
430 // In Blender, a Collection is not an actual Object type. When exporting, the iterator
431 // flattens the Collection hierarchy, treating each object inside the Collection as an
432 // individual prototype. However, all these prototypes share the same instance attributes
433 // (e.g., positions, orientations, scales).
434 //
435 // To ensure correct arrangement, reading, and drawing in OpenUSD, we need to explicitly
436 // duplicate the instance attributes across all prototypes derived from the Collection.
437 pxr::VtArray<T> original_values;
438 if (!getter().Get(&original_values, timecode) || original_values.empty()) {
439 return;
440 }
441
442 pxr::VtArray<T> expanded_values;
443 for (const auto &[instance_index, object_count] : instance_object_map) {
444 if (instance_index < static_cast<int>(original_values.size())) {
445 for (int i = 0; i < object_count; ++i) {
446 expanded_values.push_back(original_values[instance_index]);
447 }
448 }
449 }
450
451 creator().Set(expanded_values, timecode);
452}
453
454void USDPointInstancerWriter::handle_collection_prototypes(
455 const pxr::UsdGeomPointInstancer &usd_instancer,
456 const pxr::UsdTimeCode timecode,
457 int instance_num,
458 const std::vector<std::pair<int, int>> &collection_instance_object_count_map)
459{
460 // Duplicate attributes
461 if (usd_instancer.GetPositionsAttr().HasAuthoredValue()) {
462 ExpandAttributePerInstance<pxr::GfVec3f>([&]() { return usd_instancer.GetPositionsAttr(); },
463 [&]() { return usd_instancer.CreatePositionsAttr(); },
464 collection_instance_object_count_map,
465 timecode);
466 }
467 if (usd_instancer.GetOrientationsAttr().HasAuthoredValue()) {
469 [&]() { return usd_instancer.GetOrientationsAttr(); },
470 [&]() { return usd_instancer.CreateOrientationsAttr(); },
471 collection_instance_object_count_map,
472 timecode);
473 }
474 if (usd_instancer.GetScalesAttr().HasAuthoredValue()) {
475 ExpandAttributePerInstance<pxr::GfVec3f>([&]() { return usd_instancer.GetScalesAttr(); },
476 [&]() { return usd_instancer.CreateScalesAttr(); },
477 collection_instance_object_count_map,
478 timecode);
479 }
480 if (usd_instancer.GetVelocitiesAttr().HasAuthoredValue()) {
482 [&]() { return usd_instancer.GetVelocitiesAttr(); },
483 [&]() { return usd_instancer.CreateVelocitiesAttr(); },
484 collection_instance_object_count_map,
485 timecode);
486 }
487 if (usd_instancer.GetAngularVelocitiesAttr().HasAuthoredValue()) {
489 [&]() { return usd_instancer.GetAngularVelocitiesAttr(); },
490 [&]() { return usd_instancer.CreateAngularVelocitiesAttr(); },
491 collection_instance_object_count_map,
492 timecode);
493 }
494
495 // Duplicate Primvars
496 const pxr::UsdGeomPrimvarsAPI primvars_api(usd_instancer);
497 std::vector<pxr::UsdGeomPrimvar> primvars = primvars_api.GetPrimvars();
498 for (const pxr::UsdGeomPrimvar &primvar : primvars) {
499 if (!primvar.HasAuthoredValue()) {
500 continue;
501 }
502 const pxr::TfToken name = primvar.GetPrimvarName();
503 const pxr::SdfValueTypeName type = primvar.GetTypeName();
504 const pxr::TfToken interp = primvar.GetInterpolation();
505 auto create = [&]() { return primvars_api.CreatePrimvar(name, type, interp); };
506
507 if (type == pxr::SdfValueTypeNames->FloatArray) {
509 [&]() { return primvar; }, create, collection_instance_object_count_map, timecode);
510 }
511 else if (type == pxr::SdfValueTypeNames->IntArray) {
513 [&]() { return primvar; }, create, collection_instance_object_count_map, timecode);
514 }
515 else if (type == pxr::SdfValueTypeNames->UCharArray) {
517 [&]() { return primvar; }, create, collection_instance_object_count_map, timecode);
518 }
519 else if (type == pxr::SdfValueTypeNames->Float2Array) {
521 [&]() { return primvar; }, create, collection_instance_object_count_map, timecode);
522 }
523 else if (type == pxr::SdfValueTypeNames->Float3Array ||
524 type == pxr::SdfValueTypeNames->Color3fArray ||
525 type == pxr::SdfValueTypeNames->Color4fArray)
526 {
528 [&]() { return primvar; }, create, collection_instance_object_count_map, timecode);
529 }
530 else if (type == pxr::SdfValueTypeNames->QuatfArray) {
532 [&]() { return primvar; }, create, collection_instance_object_count_map, timecode);
533 }
534 else if (type == pxr::SdfValueTypeNames->BoolArray) {
536 [&]() { return primvar; }, create, collection_instance_object_count_map, timecode);
537 }
538 else if (type == pxr::SdfValueTypeNames->StringArray) {
540 [&]() { return primvar; }, create, collection_instance_object_count_map, timecode);
541 }
542 }
543
544 // MARK: Ensure Instance Indices Exist
545 // -----------------------------------------------------------------------------
546 // If the PointInstancer has no authored instance indices, manually generate a default
547 // sequence of indices to ensure the PointInstancer functions correctly in OpenUSD.
548 // This guarantees that each instance can correctly reference its prototype.
549 pxr::UsdAttribute proto_indices_attr = usd_instancer.GetProtoIndicesAttr();
550 if (!proto_indices_attr.HasAuthoredValue()) {
551 std::vector<int> index;
552 for (int i = 0; i < prototype_paths_.size(); i++) {
553 std::vector<int> current_proto_index(instance_num, i);
554 index.insert(index.end(), current_proto_index.begin(), current_proto_index.end());
555 }
556
557 proto_indices_attr.Set(pxr::VtArray<int>(index.begin(), index.end()));
558 }
559}
560
561void USDPointInstancerWriter::write_attribute_data(const bke::AttributeIter &attr,
562 const pxr::UsdGeomPointInstancer &usd_instancer,
563 const pxr::UsdTimeCode timecode)
564{
565 const std::optional<pxr::SdfValueTypeName> pv_type = convert_blender_type_to_usd(attr.data_type);
566
567 if (!pv_type) {
568 BKE_reportf(this->reports(),
570 "Attribute '%s' (Blender domain %d, type %d) cannot be converted to USD",
571 attr.name.c_str(),
572 int(attr.domain),
573 attr.data_type);
574 return;
575 }
576
577 const GVArray attribute = *attr.get();
578 if (attribute.is_empty()) {
579 return;
580 }
581
582 if (attr.name == "mask") {
583 pxr::UsdAttribute idsAttr = usd_instancer.GetIdsAttr();
584 if (!idsAttr) {
585 idsAttr = usd_instancer.CreateIdsAttr();
586 }
587
588 pxr::UsdAttribute invisibleIdsAttr = usd_instancer.GetInvisibleIdsAttr();
589 if (!invisibleIdsAttr) {
590 invisibleIdsAttr = usd_instancer.CreateInvisibleIdsAttr();
591 }
592
593 const GVArray attribute = *attr.get();
595 std::vector<int8_t> mask_values(attribute.size());
596 attribute.materialize(IndexMask(attribute.size()), mask_values.data());
597
598 pxr::VtArray<int64_t> ids;
599 pxr::VtArray<int64_t> invisibleIds;
600 ids.reserve(mask_values.size());
601
602 for (int64_t i = 0; i < static_cast<int64_t>(mask_values.size()); ++i) {
603 ids.push_back(i);
604 if (mask_values[i] == 0) {
605 invisibleIds.push_back(i);
606 }
607 }
608
609 blender::io::usd::set_attribute(idsAttr, ids, timecode, usd_value_writer_);
610 blender::io::usd::set_attribute(invisibleIdsAttr, invisibleIds, timecode, usd_value_writer_);
611 }
612
613 const pxr::TfToken pv_name(
614 make_safe_name(attr.name, usd_export_context_.export_params.allow_unicode));
615 const pxr::UsdGeomPrimvarsAPI pv_api = pxr::UsdGeomPrimvarsAPI(usd_instancer);
616
617 pxr::UsdGeomPrimvar pv_attr = pv_api.CreatePrimvar(pv_name, *pv_type);
618
620 attribute, attr.data_type, timecode, pv_attr, usd_value_writer_);
621}
622
623} // namespace blender::io::usd
#define FOREACH_COLLECTION_OBJECT_RECURSIVE_END
#define FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(_collection, _object)
const char * BKE_id_name(const ID &id)
General operations, lookup, etc. for blender objects.
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
#define BLI_assert(a)
Definition BLI_assert.h:46
#define ELEM(...)
float[3] Vector
Object groups, one object can be in many groups at once.
Object is a sort of wrapper for general info.
SIMD_FORCE_INLINE btVector3 transform(const btVector3 &point) const
long long int int64_t
constexpr int64_t size() const
Definition BLI_span.hh:252
constexpr int64_t size() const
Definition BLI_span.hh:252
void foreach_attribute(const FunctionRef< void(const AttributeIter &)> fn) const
virtual std::optional< AttributeAccessor > attributes() const
Collection & collection() const
Span< int > reference_handles() const
Definition instances.cc:215
Span< float4x4 > transforms() const
Definition instances.cc:233
Span< InstanceReference > references() const
Definition instances.cc:285
int instances_num() const
Definition instances.cc:398
const pxr::SdfPath & usd_path() const
pxr::UsdTimeCode get_export_time_code() const
pxr::UsdUtilsSparseValueWriter usd_value_writer_
USDAbstractWriter(const USDExporterContext &usd_export_context)
const USDExporterContext usd_export_context_
USDPointInstancerWriter(const USDExporterContext &ctx, std::set< std::pair< pxr::SdfPath, Object * > > &prototype_paths, std::unique_ptr< USDAbstractWriter > base_writer)
virtual void do_write(HierarchyContext &context) override
uint pos
ccl_device_inline float interp(const float a, const float b, const float t)
Definition math_base.h:502
std::unique_ptr< IDProperty, IDPropertyDeleter > create(StringRef prop_name, int32_t value, eIDPropertyFlag flags={})
Allocate a new IDProperty of type IDP_INT, set its name and value.
bool attribute_name_is_anonymous(const StringRef name)
GeometrySet object_get_evaluated_geometry_set(const Object &object, bool apply_subdiv=true)
static void ExpandAttributePerInstance(const GetterFunc &getter, const CreatorFunc &creator, const std::vector< std::pair< int, int > > &instance_object_map, const pxr::UsdTimeCode &timecode)
void set_attribute(const pxr::UsdAttribute &attr, const USDT value, pxr::UsdTimeCode timecode, pxr::UsdUtilsSparseValueWriter &value_writer)
void copy_blender_attribute_to_primvar(const GVArray &attribute, const eCustomDataType data_type, const pxr::UsdTimeCode timecode, const pxr::UsdGeomPrimvar &primvar, pxr::UsdUtilsSparseValueWriter &value_writer)
static pxr::VtArray< T > DuplicateArray(const pxr::VtArray< T > &original, size_t copies)
std::string make_safe_name(const StringRef name, bool allow_unicode)
Definition usd_utils.cc:18
static void DuplicatePerInstanceAttribute(const GetterFunc &getter, const CreatorFunc &creator, size_t copies, const pxr::UsdTimeCode &timecode)
std::optional< pxr::SdfValueTypeName > convert_blender_type_to_usd(const eCustomDataType blender_type, bool use_color3f_type)
QuaternionBase< float > Quaternion
QuaternionBase< T > to_quaternion(const AxisAngleBase< T, AngleT > &axis_angle)
EulerXYZBase< float > EulerXYZ
MatBase< T, NumCol, NumRow > normalize(const MatBase< T, NumCol, NumRow > &a)
VecBase< T, 3 > to_scale(const MatBase< T, NumCol, NumRow > &mat)
Euler3Base< T > to_euler(const AxisAngleBase< T, AngleT > &axis_angle, EulerOrder order)
MatBase< float, 4, 4 > float4x4
VecBase< float, 3 > float3
const GeometryComponent * get_component(GeometryComponent::Type component_type) const
float z
Definition sky_float3.h:27
float y
Definition sky_float3.h:27
float x
Definition sky_float3.h:27
i
Definition text_draw.cc:230