24#include <pxr/base/gf/quatf.h>
25#include <pxr/base/gf/vec3d.h>
26#include <pxr/base/gf/vec3f.h>
27#include <pxr/base/vt/array.h>
28#include <pxr/usd/usdGeom/pointInstancer.h>
29#include <pxr/usd/usdGeom/primvarsAPI.h>
37 const Set<std::pair<pxr::SdfPath, Object *>> &prototype_paths,
38 std::unique_ptr<USDAbstractWriter> base_writer)
40 base_writer_(std::move(base_writer)),
41 prototype_paths_(prototype_paths)
49 base_writer_->write(context);
60 const Object *object_eval = context.object;
70 const pxr::UsdGeomPointInstancer usd_instancer = pxr::UsdGeomPointInstancer::Define(stage,
77 if (transforms.
size() != instance_num) {
80 "Instances number '%d' does not match transforms size '%d'",
82 int(transforms.
size()));
87 pxr::UsdAttribute position_attr = usd_instancer.CreatePositionsAttr();
88 pxr::VtArray<pxr::GfVec3f> positions(instance_num);
89 for (
int i = 0;
i < instance_num;
i++) {
91 positions[
i] = pxr::GfVec3f(
pos.x,
pos.y,
pos.z);
96 pxr::UsdAttribute orientations_attr = usd_instancer.CreateOrientationsAttr();
97 pxr::VtArray<pxr::GfQuath> orientation(instance_num);
98 for (
int i = 0;
i < instance_num;
i++) {
101 orientation[
i] = pxr::GfQuath(quat.
w, pxr::GfVec3h(quat.
x, quat.
y, quat.
z));
106 pxr::UsdAttribute scales_attr = usd_instancer.CreateScalesAttr();
107 pxr::VtArray<pxr::GfVec3f> scales(instance_num);
108 for (
int i = 0;
i < instance_num;
i++) {
111 scales[
i] = pxr::GfVec3f(scale_vec.x, scale_vec.y, scale_vec.z);
126 this->write_attribute_data(iter, usd_instancer, time);
130 const pxr::SdfPath protoParentPath =
usd_path.AppendChild(pxr::TfToken(
"Prototypes"));
131 pxr::UsdPrim prototypesOver = stage->DefinePrim(protoParentPath);
132 pxr::SdfPathVector proto_wrapper_paths;
137 if (!prototype_paths_.is_empty() && usd_instancer) {
140 for (
const std::pair<pxr::SdfPath, Object *> &entry : prototype_paths_) {
141 const pxr::SdfPath &source_path = entry.first;
144 if (source_path.IsEmpty()) {
148 const pxr::SdfPath proto_path = protoParentPath.AppendChild(
149 pxr::TfToken(
"Prototype_" + std::to_string(iter)));
151 pxr::UsdPrim prim = stage->DefinePrim(proto_path);
155 stage->DefinePrim(source_path);
156 prim.GetReferences().AddReference(pxr::SdfReference(
"", source_path));
157 proto_wrapper_paths.push_back(proto_path);
160 proto_index_map.
add_new(ob_name, iter);
161 proto_path_map.
add_new(ob_name, proto_path);
165 usd_instancer.GetPrototypesRel().SetTargets(proto_wrapper_paths);
170 pxr::UsdAttribute proto_indices_attr = usd_instancer.CreateProtoIndicesAttr();
171 pxr::VtArray<int> proto_indices;
178 for (
int i = 0;
i < instance_num;
i++) {
181 process_instance_reference(reference,
184 final_proto_index_map,
188 collection_instance_object_count_map);
194 if (!collection_instance_object_count_map.
is_empty()) {
195 handle_collection_prototypes(
196 usd_instancer, time, instance_num, collection_instance_object_count_map);
204 compact_prototypes(usd_instancer, time, proto_wrapper_paths);
207void USDPointInstancerWriter::process_instance_reference(
213 pxr::UsdStageRefPtr stage,
214 pxr::VtArray<int> &proto_indices,
215 Vector<std::pair<int, int>> &collection_instance_object_count_map)
220 switch (reference.
type()) {
225 if (proto_index_map.
contains(ob_name)) {
226 proto_indices.push_back(proto_index_map.
lookup(ob_name));
243 if (proto_index_map.
contains(ob_name)) {
245 proto_indices.push_back(proto_index_map.
lookup(ob_name));
251 collection_instance_object_count_map.append(std::make_pair(instance_index, object_num));
256 bke::GeometrySet geometry_set = reference.
geometry_set();
257 std::string set_name = geometry_set.
name;
259 if (proto_index_map.
contains(set_name)) {
260 proto_indices.push_back(proto_index_map.
lookup(set_name));
265 Vector<const bke::GeometryComponent *> components = geometry_set.get_components();
266 for (
const bke::GeometryComponent *comp : components) {
267 if (
const bke::Instances *instances =
268 static_cast<const bke::InstancesComponent &
>(*comp).get())
270 Span<int> ref_handles = instances->reference_handles();
271 Span<bke::InstanceReference> refs = instances->references();
277 if (!proto_index_map.
contains(set_name)) {
278 for (
int index = 0; index < ref_handles.
size(); ++index) {
279 const bke::InstanceReference &child_ref = refs[ref_handles[index]];
283 process_instance_reference(child_ref,
286 final_proto_index_map,
290 collection_instance_object_count_map);
296 Span<float4x4> transforms = instances->transforms();
297 if (transforms.
size() == 1) {
298 if (proto_path_map.
contains(set_name)) {
299 override_transform(stage, proto_path_map.
lookup(set_name), transforms[0]);
313void USDPointInstancerWriter::compact_prototypes(
const pxr::UsdGeomPointInstancer &usd_instancer,
314 const pxr::UsdTimeCode time,
315 const pxr::SdfPathVector &proto_paths)
const
317 pxr::UsdAttribute proto_indices_attr = usd_instancer.GetProtoIndicesAttr();
318 pxr::VtArray<int> proto_indices;
319 if (!proto_indices_attr.Get(&proto_indices, time)) {
324 Set<int> used_proto_indices;
325 used_proto_indices.
add_multiple(
Span(proto_indices.cbegin(), proto_indices.size()));
329 for (
int i = 0;
i < proto_paths.size(); ++
i) {
331 remap.
add(
i, new_index++);
336 for (
int &idx : proto_indices) {
339 proto_indices_attr.Set(proto_indices, time);
341 pxr::SdfPathVector compact_proto_paths;
342 for (
int i = 0;
i < proto_paths.size(); ++
i) {
344 compact_proto_paths.push_back(proto_paths[
i]);
348 usd_instancer.GetPrototypesRel().SetTargets(compact_proto_paths);
351void USDPointInstancerWriter::override_transform(
const pxr::UsdStageRefPtr stage,
352 const pxr::SdfPath &proto_path,
355 pxr::UsdPrim prim = stage->GetPrimAtPath(proto_path);
362 pxr::GfVec3d override_position(
pos.x,
pos.y,
pos.z);
366 pxr::GfVec3f override_rotation(euler.
x, euler.
y, euler.
z);
370 pxr::GfVec3f override_scale(scale_vec.
x, scale_vec.
y, scale_vec.
z);
372 pxr::UsdGeomXformable xformable(prim);
373 xformable.ClearXformOpOrder();
374 xformable.AddTranslateOp().Set(override_position);
375 xformable.AddRotateXYZOp().Set(override_rotation);
376 xformable.AddScaleOp().Set(override_scale);
380static pxr::VtArray<T>
DuplicateArray(
const pxr::VtArray<T> &original,
size_t copies)
382 pxr::VtArray<T> newArray;
383 size_t originalSize = original.size();
384 newArray.resize(originalSize * copies);
385 for (
size_t i = 0;
i < copies; ++
i) {
386 std::copy(original.begin(), original.end(), newArray.begin() +
i * originalSize);
391template<
typename T,
typename GetterFunc,
typename CreatorFunc>
393 const CreatorFunc &creator,
395 const pxr::UsdTimeCode &time)
397 pxr::VtArray<T> values;
398 if (getter().Get(&values, time) && !values.empty()) {
400 creator().Set(newValues, time);
404template<
typename T,
typename GetterFunc,
typename CreatorFunc>
406 const CreatorFunc &creator,
407 const Span<std::pair<int, int>> instance_object_map,
408 const pxr::UsdTimeCode &time)
419 pxr::VtArray<T> original_values;
420 if (!getter().Get(&original_values, time) || original_values.empty()) {
424 pxr::VtArray<T> expanded_values;
425 for (
const auto &[instance_index, object_count] : instance_object_map) {
426 if (instance_index <
int(original_values.size())) {
427 for (
int i = 0;
i < object_count; ++
i) {
428 expanded_values.push_back(original_values[instance_index]);
433 creator().Set(expanded_values, time);
436void USDPointInstancerWriter::handle_collection_prototypes(
437 const pxr::UsdGeomPointInstancer &usd_instancer,
438 const pxr::UsdTimeCode time,
439 const int instance_num,
440 const Span<std::pair<int, int>> collection_instance_object_count_map)
const
443 if (usd_instancer.GetPositionsAttr().HasAuthoredValue()) {
445 [&]() {
return usd_instancer.CreatePositionsAttr(); },
446 collection_instance_object_count_map,
449 if (usd_instancer.GetOrientationsAttr().HasAuthoredValue()) {
451 [&]() {
return usd_instancer.GetOrientationsAttr(); },
452 [&]() {
return usd_instancer.CreateOrientationsAttr(); },
453 collection_instance_object_count_map,
456 if (usd_instancer.GetScalesAttr().HasAuthoredValue()) {
458 [&]() {
return usd_instancer.CreateScalesAttr(); },
459 collection_instance_object_count_map,
462 if (usd_instancer.GetVelocitiesAttr().HasAuthoredValue()) {
464 [&]() {
return usd_instancer.GetVelocitiesAttr(); },
465 [&]() {
return usd_instancer.CreateVelocitiesAttr(); },
466 collection_instance_object_count_map,
469 if (usd_instancer.GetAngularVelocitiesAttr().HasAuthoredValue()) {
471 [&]() {
return usd_instancer.GetAngularVelocitiesAttr(); },
472 [&]() {
return usd_instancer.CreateAngularVelocitiesAttr(); },
473 collection_instance_object_count_map,
478 const pxr::UsdGeomPrimvarsAPI primvars_api(usd_instancer);
479 for (
const pxr::UsdGeomPrimvar &primvar : primvars_api.GetPrimvars()) {
480 if (!primvar.HasAuthoredValue()) {
483 const pxr::TfToken pv_name = primvar.GetPrimvarName();
484 const pxr::SdfValueTypeName pv_type = primvar.GetTypeName();
485 const pxr::TfToken pv_interp = primvar.GetInterpolation();
486 auto create = [&]() {
return primvars_api.CreatePrimvar(pv_name, pv_type, pv_interp); };
488 if (pv_type == pxr::SdfValueTypeNames->FloatArray) {
490 [&]() {
return primvar; },
create, collection_instance_object_count_map, time);
492 else if (pv_type == pxr::SdfValueTypeNames->IntArray) {
494 [&]() {
return primvar; },
create, collection_instance_object_count_map, time);
496 else if (pv_type == pxr::SdfValueTypeNames->UCharArray) {
498 [&]() {
return primvar; },
create, collection_instance_object_count_map, time);
500 else if (pv_type == pxr::SdfValueTypeNames->Float2Array) {
502 [&]() {
return primvar; },
create, collection_instance_object_count_map, time);
504 else if (
ELEM(pv_type,
505 pxr::SdfValueTypeNames->Float3Array,
506 pxr::SdfValueTypeNames->Color3fArray,
507 pxr::SdfValueTypeNames->Color4fArray))
510 [&]() {
return primvar; },
create, collection_instance_object_count_map, time);
512 else if (pv_type == pxr::SdfValueTypeNames->QuatfArray) {
514 [&]() {
return primvar; },
create, collection_instance_object_count_map, time);
516 else if (pv_type == pxr::SdfValueTypeNames->BoolArray) {
518 [&]() {
return primvar; },
create, collection_instance_object_count_map, time);
520 else if (pv_type == pxr::SdfValueTypeNames->StringArray) {
522 [&]() {
return primvar; },
create, collection_instance_object_count_map, time);
531 pxr::UsdAttribute proto_indices_attr = usd_instancer.GetProtoIndicesAttr();
532 if (!proto_indices_attr.HasAuthoredValue()) {
534 for (
int i = 0;
i < prototype_paths_.size();
i++) {
538 proto_indices_attr.Set(pxr::VtArray<int>(index.
begin(), index.
end()));
542void USDPointInstancerWriter::write_attribute_data(
const bke::AttributeIter &attr,
543 const pxr::UsdGeomPointInstancer &usd_instancer,
544 const pxr::UsdTimeCode time)
551 "Attribute '%s' (Blender domain %d, type %d) cannot be converted to USD",
554 int(attr.data_type));
558 const GVArray attribute = *attr.get();
559 if (attribute.is_empty()) {
563 if (attr.name ==
"mask") {
564 pxr::UsdAttribute idsAttr = usd_instancer.GetIdsAttr();
566 idsAttr = usd_instancer.CreateIdsAttr();
569 pxr::UsdAttribute invisibleIdsAttr = usd_instancer.GetInvisibleIdsAttr();
570 if (!invisibleIdsAttr) {
571 invisibleIdsAttr = usd_instancer.CreateInvisibleIdsAttr();
574 Vector<bool> mask_values(attribute.size());
575 attribute.materialize(IndexMask(attribute.size()), mask_values.data());
577 pxr::VtArray<int64_t> ids;
578 pxr::VtArray<int64_t> invisibleIds;
579 ids.reserve(mask_values.size());
581 for (
int64_t i = 0;
i < mask_values.size();
i++) {
583 if (!mask_values[
i]) {
584 invisibleIds.push_back(
i);
592 const pxr::TfToken pv_name(
594 const pxr::UsdGeomPrimvarsAPI pv_api = pxr::UsdGeomPrimvarsAPI(usd_instancer);
596 pxr::UsdGeomPrimvar pv_attr = pv_api.CreatePrimvar(pv_name, *pv_type);
#define FOREACH_COLLECTION_OBJECT_RECURSIVE_END
#define FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(_collection, _object)
const char * BKE_id_name(const ID &id)
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
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
bool add(const Key &key, const Value &value)
const Value & lookup(const Key &key) const
bool contains(const Key &key) const
void add_multiple(Span< Key > keys)
constexpr int64_t size() const
void append_n_times(const T &value, const int64_t n)
bool add_overwrite(const Key &key, const Value &value)
const Value & lookup(const Key &key) const
void add_new(const Key &key, const Value &value)
bool contains(const Key &key) const
constexpr int64_t size() const
void foreach_attribute(const FunctionRef< void(const AttributeIter &)> fn) const
virtual std::optional< AttributeAccessor > attributes() const
GeometrySet & geometry_set()
Collection & collection() const
const Instances * get() const
Span< int > reference_handles() const
Span< float4x4 > transforms() const
Span< InstanceReference > references() const
int instances_num() const
const pxr::SdfPath & usd_path() const
ReportList * reports() 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, const blender::Set< std::pair< pxr::SdfPath, Object * > > &prototype_paths, std::unique_ptr< USDAbstractWriter > base_writer)
void do_write(HierarchyContext &context) override
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)
void copy_blender_attribute_to_primvar(const GVArray &attribute, const bke::AttrType data_type, const pxr::UsdTimeCode time, const pxr::UsdGeomPrimvar &primvar, pxr::UsdUtilsSparseValueWriter &value_writer)
std::optional< pxr::SdfValueTypeName > convert_blender_type_to_usd(const bke::AttrType blender_type, bool use_color3f_type)
static pxr::VtArray< T > DuplicateArray(const pxr::VtArray< T > &original, size_t copies)
std::string make_safe_name(const StringRef name, bool allow_unicode)
void set_attribute(const pxr::UsdAttribute &attr, const USDT value, pxr::UsdTimeCode time, pxr::UsdUtilsSparseValueWriter &value_writer)
static void ExpandAttributePerInstance(const GetterFunc &getter, const CreatorFunc &creator, const Span< std::pair< int, int > > instance_object_map, const pxr::UsdTimeCode &time)
static void DuplicatePerInstanceAttribute(const GetterFunc &getter, const CreatorFunc &creator, size_t copies, const pxr::UsdTimeCode &time)
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
static MatBase identity()
const GeometryComponent * get_component(GeometryComponent::Type component_type) const