Fix T103354: Author extents on UsdGeomMesh #104676

Merged
Sybren A. Stüvel merged 6 commits from wave/blender_wave_Apple:contribs/T103354_author_extents into main 2023-02-14 12:12:05 +01:00
4 changed files with 51 additions and 0 deletions
Showing only changes of commit 67136bfcfe - Show all commits

View File

@ -5,12 +5,15 @@
#include "usd_writer_material.h"
#include <pxr/base/tf/stringUtils.h>
#include <pxr/usd/usdGeom/bboxCache.h>
#include "BKE_customdata.h"
#include "BLI_assert.h"
#include "DNA_mesh_types.h"
#include "WM_api.h"
/* TfToken objects are not cheap to construct, so we do it once. */
namespace usdtokens {
/* Materials */
@ -149,4 +152,37 @@ bool USDAbstractWriter::mark_as_instance(const HierarchyContext &context, const
return true;
}
void USDAbstractWriter::author_extent(const pxr::UsdTimeCode timecode, pxr::UsdGeomBoundable &prim)
{
/* Compute the bounds for a boundable prim, and author the result as the extent attribute.
*
* Although this method works for any boundable prim, it is preferred to use Blender's own
* cached bounds when possible.
*
* This method does not author the extentsHint attribute, which is also important to provide.
* Whereas the extent attribute can only be authored on prims inheriting from UsdGeomBoundable,
* an extentsHint can be provided on any prim, including scopes. This extentsHint should be
* authored on every prim in a hierarchy being exported.
wave marked this conversation as resolved

Since this situation doesn't seem to abort the export itself, I think RPT_WARNING would be more suitable here.

Since this situation doesn't seem to abort the export itself, I think `RPT_WARNING` would be more suitable here.
*
* Note that this hint is only useful when importing or inspecting layers, and should not be
* taken into account when computing extents during export.
*
* TODO: also provide method for authoring extentsHint on every prim in a hierarchy.
*/
/* do not use any existing extentsHint that may authored, instead recompute the extent when authoring it */
const bool useExtentsHint = false;
const pxr::TfTokenVector includedPurposes{pxr::UsdGeomTokens->default_};
pxr::UsdGeomBBoxCache bboxCache(timecode, includedPurposes, useExtentsHint);
pxr::GfBBox3d bounds = bboxCache.ComputeLocalBound(prim.GetPrim());
if (pxr::GfBBox3d() == bounds) {
/* This will occur, for example, if a mesh does not have any vertices. */
WM_reportf(RPT_ERROR, "USD Export: no bounds could be computed for %s", prim.GetPrim().GetName().GetText());
return;
}
pxr::VtArray<pxr::GfVec3f> extent{ (pxr::GfVec3f)bounds.GetRange().GetMin(), (pxr::GfVec3f)bounds.GetRange().GetMax() };
prim.CreateExtentAttr().Set(extent);
}
} // namespace blender::io::usd

View File

@ -9,6 +9,7 @@
#include <pxr/usd/usd/stage.h>
#include <pxr/usd/usdShade/material.h>
#include <pxr/usd/usdUtils/sparseValueWriter.h>
#include <pxr/usd/usdGeom/boundable.h>
#include <vector>
@ -67,6 +68,8 @@ class USDAbstractWriter : public AbstractHierarchyWriter {
* Reference the original data instead of writing a copy.
*/
virtual bool mark_as_instance(const HierarchyContext &context, const pxr::UsdPrim &prim);
virtual void author_extent(const pxr::UsdTimeCode timecode, pxr::UsdGeomBoundable &prim);
};
} // namespace blender::io::usd

View File

@ -62,6 +62,8 @@ void USDHairWriter::do_write(HierarchyContext &context)
colors.push_back(pxr::GfVec3f(cache[0]->col));
curves.CreateDisplayColorAttr(pxr::VtValue(colors));
}
this->author_extent(timecode, curves);
}
bool USDHairWriter::check_is_animated(const HierarchyContext & /*context*/) const

View File

@ -5,6 +5,7 @@
#include <pxr/usd/usdGeom/mesh.h>
#include <pxr/usd/usdGeom/primvarsAPI.h>
#include <pxr/usd/usdGeom/bboxCache.h>
#include <pxr/usd/usdShade/material.h>
#include <pxr/usd/usdShade/materialBindingAPI.h>
@ -247,6 +248,15 @@ void USDGenericMeshWriter::write_mesh(HierarchyContext &context, Mesh *mesh)
if (usd_export_context_.export_params.export_materials) {
assign_materials(context, usd_mesh, usd_mesh_data.face_groups);
}
/* Blender grows its bounds cache to cover animated meshes, so only author once. */
float bound_min[3];
float bound_max[3];
INIT_MINMAX(bound_min, bound_max);
BKE_mesh_minmax(mesh, bound_min, bound_max);
pxr::VtArray<pxr::GfVec3f> extent{ pxr::GfVec3f{ bound_min[0], bound_min[1], bound_min[2]},
pxr::GfVec3f{ bound_max[0], bound_max[1], bound_max[2]} };
usd_mesh.CreateExtentAttr().Set(extent);
}
static void get_vertices(const Mesh *mesh, USDMeshData &usd_mesh_data)