Fix: USD export: missing prototype proxies

The scene graph instancing export code contains logic for
determining which instances need to be converted to prototypes
because the original prototypes are not included in the export
(e.g., because they are not visible).

This commit fixes an error in this logic, which incorrectly
assumed that if the root of the original prototype is included
in the export, then the entire original hierarchy beneath the
root is included as well.

To fix this, the logic in AbstractHierarchyIterator::
determine_duplication_references was updated so that if any
descendants of an instance are converted to prototypes, the
parent instance is converted to a prototype as well.

This addresses the bug noted by Brecht in
https://projects.blender.org/blender/blender/pulls/131707#issuecomment-1403309

Pull Request: https://projects.blender.org/blender/blender/pulls/133750
This commit is contained in:
Michael Kowalski
2025-01-29 14:05:52 +01:00
committed by Michael Kowalski
parent 9135929063
commit e021cf0491
4 changed files with 17 additions and 23 deletions

View File

@@ -281,7 +281,7 @@ class AbstractHierarchyIterator {
const ExportGraph::key_type &graph_index) const;
void determine_export_paths(const HierarchyContext *parent_context);
void determine_duplication_references(const HierarchyContext *parent_context,
bool determine_duplication_references(const HierarchyContext *parent_context,
const std::string &indent);
/* These three functions create writers and call their write() method. */
@@ -365,14 +365,6 @@ class AbstractHierarchyIterator {
AbstractHierarchyWriter *get_writer(const std::string &export_path) const;
ExportChildren &graph_children(const HierarchyContext *context);
/* Return true if duplication references should be resolved for the children of the given
* context. */
virtual bool should_determine_duplication_references(
const HierarchyContext *parent_context) const
{
return parent_context != nullptr;
}
};
} // namespace blender::io

View File

@@ -543,11 +543,15 @@ void AbstractHierarchyIterator::determine_export_paths(const HierarchyContext *p
}
}
void AbstractHierarchyIterator::determine_duplication_references(
bool AbstractHierarchyIterator::determine_duplication_references(
const HierarchyContext *parent_context, const std::string &indent)
{
ExportChildren children = graph_children(parent_context);
/* Will be set to true if any child contexts are instances that were designated
* as proxies for the original prototype.*/
bool contains_proxy_prototype = false;
for (HierarchyContext *context : children) {
if (context->duplicator != nullptr) {
ID *source_id = &context->object->id;
@@ -557,6 +561,7 @@ void AbstractHierarchyIterator::determine_duplication_references(
/* The original was not found, so mark this instance as "the original". */
context->mark_as_not_instanced();
duplisource_export_path_[source_id] = context->export_path;
contains_proxy_prototype = true;
}
else {
context->mark_as_instance_of(it->second);
@@ -583,10 +588,18 @@ void AbstractHierarchyIterator::determine_duplication_references(
}
}
if (should_determine_duplication_references(context)) {
determine_duplication_references(context, indent + " ");
if (determine_duplication_references(context, indent + " ")) {
/* A descendant was designated a prototype proxy. If the current context
* is an instance, we must change it to a prototype proxy as well. */
if (context->is_instance()) {
context->mark_as_not_instanced();
ID *source_id = &context->object->id;
duplisource_export_path_[source_id] = context->export_path;
}
contains_proxy_prototype = true;
}
}
return contains_proxy_prototype;
}
void AbstractHierarchyIterator::make_writers(const HierarchyContext *parent_context)

View File

@@ -263,12 +263,6 @@ bool USDHierarchyIterator::include_child_writers(const HierarchyContext *context
return !(params_.use_instancing && context->is_instance());
}
bool USDHierarchyIterator::should_determine_duplication_references(
const HierarchyContext *parent_context) const
{
return !(params_.use_instancing && parent_context->is_instance());
}
void USDHierarchyIterator::add_usd_skel_export_mapping(const Object *obj, const pxr::SdfPath &path)
{
if (params_.export_shapekeys && is_mesh_with_shape_keys(obj)) {

View File

@@ -60,11 +60,6 @@ class USDHierarchyIterator : public AbstractHierarchyIterator {
virtual bool include_data_writers(const HierarchyContext *context) const override;
virtual bool include_child_writers(const HierarchyContext *context) const override;
/* Return true if duplication references should be resolved for the children of the given
* context. */
virtual bool should_determine_duplication_references(
const HierarchyContext *parent_context) const override;
private:
USDExporterContext create_usd_export_context(const HierarchyContext *context);