Exporting a scene to USD or Alembic would fail when there are multiple duplicates of parent & child objects, duplicated by the same object. For example, this happens when such a hierarchy of objects is contained in a collection, and that collection is instanced multiple times by mesh vertices. The problem here is that the 'parent' pointer of each duplicated object points to the real parent; Blender would not figure out properly which duplicated parent should be used. This is now resolved by keeping track of the persistent ID of each duplicated instance, which makes it possible to reconstruct the parent-child relations of duplicated objects. This does use up some memory for each dupli, so it could be heavy to export a Spring scene (with all the pebbles and leaves), but it's only a small addition on top of the USD/Alembic writer objects that have to be created anyway. At least with this patch, they're created correctly. Code-wise, the following changes are made: - The export graph (that maps export parent to its export children) used to have as its key (Object, Duplicator). This is insufficient to correctly distinguish between multiple duplis of the same object by the same duplicator, so this is now extended to (Object, Duplicator, Persistent ID). To make this possible, new classes `ObjectIdentifier` and `PersistentID` are introduced. - Finding the parent of a duplicated object is done via its persistent ID. In Python notation, the code first tries to find the parent instance where `child_persistent_id[1:] == parent_persistent_id[1:]`. If that fails, the dupli with persistent ID `child_persistent_id[1:]` is used as parent. Reviewed By: sergey Differential Revision: https://developer.blender.org/D8233
105 lines
2.9 KiB
C++
105 lines
2.9 KiB
C++
/*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
* The Original Code is Copyright (C) 2020 Blender Foundation.
|
|
* All rights reserved.
|
|
*/
|
|
|
|
#include "dupli_parent_finder.hh"
|
|
|
|
#include "BLI_utildefines.h"
|
|
|
|
#include <iostream>
|
|
|
|
namespace blender::io {
|
|
|
|
DupliParentFinder::DupliParentFinder()
|
|
{
|
|
}
|
|
|
|
DupliParentFinder::~DupliParentFinder()
|
|
{
|
|
}
|
|
|
|
void DupliParentFinder::insert(const DupliObject *dupli_ob)
|
|
{
|
|
dupli_set_.insert(dupli_ob->ob);
|
|
|
|
PersistentID dupli_pid(dupli_ob);
|
|
pid_to_dupli_[dupli_pid] = dupli_ob;
|
|
instancer_pid_to_duplis_[dupli_pid.instancer_pid()].insert(dupli_ob);
|
|
}
|
|
|
|
bool DupliParentFinder::is_duplicated(const Object *object) const
|
|
{
|
|
return dupli_set_.find(object) != dupli_set_.end();
|
|
}
|
|
|
|
const DupliObject *DupliParentFinder::find_suitable_export_parent(
|
|
const DupliObject *dupli_ob) const
|
|
{
|
|
if (dupli_ob->ob->parent != nullptr) {
|
|
const DupliObject *parent = find_duplicated_parent(dupli_ob);
|
|
if (parent != nullptr) {
|
|
return parent;
|
|
}
|
|
}
|
|
|
|
return find_instancer(dupli_ob);
|
|
}
|
|
|
|
const DupliObject *DupliParentFinder::find_duplicated_parent(const DupliObject *dupli_ob) const
|
|
{
|
|
const PersistentID dupli_pid(dupli_ob);
|
|
PersistentID parent_pid = dupli_pid.instancer_pid();
|
|
|
|
const Object *parent_ob = dupli_ob->ob->parent;
|
|
BLI_assert(parent_ob != nullptr);
|
|
|
|
InstancerPIDToDuplisMap::const_iterator found = instancer_pid_to_duplis_.find(parent_pid);
|
|
if (found == instancer_pid_to_duplis_.end()) {
|
|
/* Unexpected, as there should be at least one entry here, for the dupli_ob itself. */
|
|
return nullptr;
|
|
}
|
|
|
|
for (const DupliObject *potential_parent_dupli : found->second) {
|
|
if (potential_parent_dupli->ob != parent_ob) {
|
|
continue;
|
|
}
|
|
|
|
PersistentID potential_parent_pid(potential_parent_dupli);
|
|
if (potential_parent_pid.is_from_same_instancer_as(dupli_pid)) {
|
|
return potential_parent_dupli;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
const DupliObject *DupliParentFinder::find_instancer(const DupliObject *dupli_ob) const
|
|
{
|
|
PersistentID dupli_pid(dupli_ob);
|
|
PersistentID parent_pid = dupli_pid.instancer_pid();
|
|
|
|
PIDToDupliMap::const_iterator found = pid_to_dupli_.find(parent_pid);
|
|
if (found == pid_to_dupli_.end()) {
|
|
return nullptr;
|
|
}
|
|
|
|
const DupliObject *instancer_dupli = found->second;
|
|
return instancer_dupli;
|
|
}
|
|
|
|
} // namespace blender::io
|