Fix T103354: Author extents on UsdGeomMesh #104676
|
@ -154,18 +154,22 @@ bool USDAbstractWriter::mark_as_instance(const HierarchyContext &context, const
|
|||
|
||||
void USDAbstractWriter::author_extent(const pxr::UsdTimeCode timecode, pxr::UsdGeomBoundable &prim)
|
||||
{
|
||||
/* Do not use any existing `extentsHint` that may be authored, instead recompute the extent when authoring it. */
|
||||
/* Do not use any existing `extentsHint` that may be 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());
|
||||
WM_reportf(RPT_ERROR,
|
||||
wave marked this conversation as resolved
|
||||
"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() };
|
||||
pxr::VtArray<pxr::GfVec3f> extent{(pxr::GfVec3f)bounds.GetRange().GetMin(),
|
||||
(pxr::GfVec3f)bounds.GetRange().GetMax()};
|
||||
prim.CreateExtentAttr().Set(extent);
|
||||
}
|
||||
|
||||
|
|
|
@ -7,9 +7,9 @@
|
|||
|
||||
#include <pxr/usd/sdf/path.h>
|
||||
#include <pxr/usd/usd/stage.h>
|
||||
#include <pxr/usd/usdGeom/boundable.h>
|
||||
#include <pxr/usd/usdShade/material.h>
|
||||
#include <pxr/usd/usdUtils/sparseValueWriter.h>
|
||||
#include <pxr/usd/usdGeom/boundable.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
|
@ -76,9 +76,9 @@ class USDAbstractWriter : public AbstractHierarchyWriter {
|
|||
* 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.
|
||||
* 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.
|
||||
*
|
||||
* Note that this hint is only useful when importing or inspecting layers, and should not be
|
||||
* taken into account when computing extents during export.
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
#include "usd_writer_mesh.h"
|
||||
#include "usd_hierarchy_iterator.h"
|
||||
|
||||
#include <pxr/usd/usdGeom/bboxCache.h>
|
||||
#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>
|
||||
|
||||
|
|
|
@ -5,7 +5,10 @@ import pprint
|
|||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
from pxr import Usd
|
||||
from pxr import UsdUtils
|
||||
from pxr import UsdGeom
|
||||
from pxr import Gf
|
||||
|
||||
import bpy
|
||||
|
||||
|
@ -74,6 +77,55 @@ class USDExportTest(AbstractUSDTest):
|
|||
|
||||
self.assertFalse(collection, pprint.pformat(collection))
|
||||
|
||||
def compareVec3d(self, first, second):
|
||||
places = 5
|
||||
self.assertAlmostEqual(first[0], second[0], places)
|
||||
self.assertAlmostEqual(first[1], second[1], places)
|
||||
self.assertAlmostEqual(first[2], second[2], places)
|
||||
|
||||
def test_export_extents(self):
|
||||
"""Test that exported scenes contain have a properly authored extent attribute on each boundable prim"""
|
||||
bpy.ops.wm.open_mainfile(filepath=str(self.testdir / "usd_extent_test.blend"))
|
||||
export_path = self.tempdir / "usd_extent_test.usda"
|
||||
res = bpy.ops.wm.usd_export(
|
||||
filepath=str(export_path),
|
||||
export_materials=True,
|
||||
evaluation_mode="RENDER",
|
||||
)
|
||||
self.assertEqual({Result.finished}, res, f"Unable to export to {export_path}")
|
||||
|
||||
# if prims are missing, the exporter must have skipped some objects
|
||||
stats = UsdUtils.ComputeUsdStageStats(str(export_path))
|
||||
self.assertEqual(stats["totalPrimCount"], 15, "Unexpected number of prims")
|
||||
|
||||
# validate the overall world bounds of the scene
|
||||
stage = Usd.Stage.Open(str(export_path))
|
||||
scenePrim = stage.GetPrimAtPath("/scene")
|
||||
bboxcache = UsdGeom.BBoxCache(Usd.TimeCode.Default(), [UsdGeom.Tokens.default_])
|
||||
bounds = bboxcache.ComputeWorldBound(scenePrim)
|
||||
bound_min = bounds.GetRange().GetMin()
|
||||
bound_max = bounds.GetRange().GetMax()
|
||||
self.compareVec3d(bound_min, Gf.Vec3d(-5.752975881, -1, -2.798513651))
|
||||
self.compareVec3d(bound_max, Gf.Vec3d(1, 2.9515805244, 2.7985136508))
|
||||
|
||||
# validate the locally authored extents
|
||||
prim = stage.GetPrimAtPath("/scene/BigCube/BigCubeMesh")
|
||||
extent = UsdGeom.Boundable(prim).GetExtentAttr().Get()
|
||||
self.compareVec3d(Gf.Vec3d(extent[0]), Gf.Vec3d(-1, -1, -2.7985137))
|
||||
self.compareVec3d(Gf.Vec3d(extent[1]), Gf.Vec3d(1, 1, 2.7985137))
|
||||
prim = stage.GetPrimAtPath("/scene/LittleCube/LittleCubeMesh")
|
||||
extent = UsdGeom.Boundable(prim).GetExtentAttr().Get()
|
||||
self.compareVec3d(Gf.Vec3d(extent[0]), Gf.Vec3d(-1, -1, -1))
|
||||
self.compareVec3d(Gf.Vec3d(extent[1]), Gf.Vec3d(1, 1, 1))
|
||||
prim = stage.GetPrimAtPath("/scene/Volume/Volume")
|
||||
extent = UsdGeom.Boundable(prim).GetExtentAttr().Get()
|
||||
self.compareVec3d(
|
||||
Gf.Vec3d(extent[0]), Gf.Vec3d(-0.7313742, -0.68043584, -0.5801515)
|
||||
)
|
||||
self.compareVec3d(
|
||||
Gf.Vec3d(extent[1]), Gf.Vec3d(0.7515701, 0.5500924, 0.9027928)
|
||||
)
|
||||
|
||||
|
||||
def main():
|
||||
global args
|
||||
|
|
Loading…
Reference in New Issue
Since this situation doesn't seem to abort the export itself, I think
RPT_WARNING
would be more suitable here.