Skip to content

Commit 0efadaf

Browse files
committed
IECoreUSD : GeomSubsets support.
1 parent 59ebc40 commit 0efadaf

7 files changed

Lines changed: 776 additions & 36 deletions

File tree

Changes

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
10.7.x.x (relative to 10.7.0.0a9)
22
========
33

4+
Features
5+
--------
46

7+
- IECoreUSD : GeomSubsets support for meshes and material binds.
58

69
10.7.0.0a9 (relative to 10.7.0.0a8)
710
==========

contrib/IECoreUSD/include/IECoreUSD/PrimitiveAlgo.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ IECOREUSD_API void writePrimitiveVariable( const std::string &name, const IECore
6262
IECOREUSD_API void writePrimitiveVariable( const std::string &name, const IECoreScene::PrimitiveVariable &primitiveVariable, const pxr::UsdGeomGprim &gprim, pxr::UsdTimeCode time );
6363
/// As above, but redirects "P", "N" etc to the relevant attributes of `pointBased`.
6464
IECOREUSD_API void writePrimitiveVariable( const std::string &name, const IECoreScene::PrimitiveVariable &primitiveVariable, pxr::UsdGeomPointBased &pointBased, pxr::UsdTimeCode time );
65+
/// Writes a PrimitiveVariable with "geomSubset:<familyName>" to multiple UsdGeomSubsets found in the indexed StringVectorData name.
66+
IECOREUSD_API void writeGeomSubsets( const pxr::TfToken &familyName, const IECoreScene::PrimitiveVariable &primitiveVariable, pxr::UsdGeomPointBased &pointBased, pxr::UsdTimeCode time );
6567
/// Equivalent to `DataAlgo::toUSD( primitiveVariable.expandedData() )`, but avoiding
6668
/// the creation of the temporary expanded data.
6769
IECOREUSD_API pxr::VtValue toUSDExpanded( const IECoreScene::PrimitiveVariable &primitiveVariable, bool arrayRequired = false );
@@ -77,13 +79,17 @@ IECOREUSD_API void readPrimitiveVariables( const pxr::UsdGeomPrimvarsAPI &primva
7779
IECOREUSD_API void readPrimitiveVariables( const pxr::UsdGeomPointBased &pointBased, pxr::UsdTimeCode timeCode, IECoreScene::Primitive *primitive, const IECore::Canceller *canceller = nullptr );
7880
/// Reads the value for `attribute`, adding it as a primitive variable with the specified `name` and `interpolation`.
7981
IECOREUSD_API void readPrimitiveVariable( const pxr::UsdAttribute &attribute, pxr::UsdTimeCode timeCode, IECoreScene::Primitive *primitive, const std::string &name, IECoreScene::PrimitiveVariable::Interpolation interpolation = IECoreScene::PrimitiveVariable::Vertex );
82+
/// Reads all compatible UsdGeomSubsets, adding them to `primitive` under `geomSubset:familyName` with the UsdGeomSubset name in that family into an indexed StringVectorData.
83+
IECOREUSD_API void readGeomSubsets( const pxr::UsdGeomPointBased &pointBased, pxr::UsdTimeCode timeCode, IECoreScene::Primitive *primitive, const IECore::Canceller *canceller = nullptr );
8084
/// Returns true if any of the primitive variables might be animated.
8185
IECOREUSD_API bool primitiveVariablesMightBeTimeVarying( const pxr::UsdGeomPrimvarsAPI &primvarsAPI );
8286
/// Returns true if any of the primitive variables might be animated, including the
8387
/// "P", "N" etc that `readPrimitiveVariables()` creates.
8488
IECOREUSD_API bool primitiveVariablesMightBeTimeVarying( const pxr::UsdGeomPointBased &pointBased );
8589
/// Converts interpolation from USD.
8690
IECOREUSD_API IECoreScene::PrimitiveVariable::Interpolation fromUSD( pxr::TfToken interpolationToken );
91+
/// Converts element type from UsdGeomSubset to interpolation.
92+
IECOREUSD_API IECoreScene::PrimitiveVariable::Interpolation elementTypeFromUSD( pxr::TfToken elementType );
8793

8894
} // namespace PrimitiveAlgo
8995

contrib/IECoreUSD/src/IECoreUSD/PrimitiveAlgo.cpp

Lines changed: 230 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ IECORE_PUSH_DEFAULT_VISIBILITY
4646
#include "pxr/base/gf/matrix4f.h"
4747
#include "pxr/base/gf/matrix4d.h"
4848
#include "pxr/usd/usdGeom/mesh.h"
49+
#include "pxr/usd/usdGeom/subset.h"
4950
#include "pxr/usd/usdSkel/animQuery.h"
5051
#include "pxr/usd/usdSkel/bindingAPI.h"
5152
#include "pxr/usd/usdSkel/blendShapeQuery.h"
@@ -56,6 +57,10 @@ IECORE_PUSH_DEFAULT_VISIBILITY
5657
#include "pxr/usd/usdSkel/utils.h"
5758
IECORE_POP_DEFAULT_VISIBILITY
5859

60+
#include "boost/algorithm/string/classification.hpp"
61+
#include "boost/algorithm/string/predicate.hpp"
62+
#include "boost/algorithm/string/split.hpp"
63+
5964
#include "fmt/ostream.h"
6065

6166
using namespace std;
@@ -68,6 +73,47 @@ using namespace IECoreUSD;
6873
// Writing primitive variables
6974
//////////////////////////////////////////////////////////////////////////
7075

76+
namespace {
77+
78+
pxr::TfToken toUSDElementType( const pxr::UsdPrim &prim )
79+
{
80+
if( prim.IsA<pxr::UsdGeomMesh>() )
81+
{
82+
return pxr::UsdGeomTokens->face;
83+
}
84+
return pxr::TfToken();
85+
}
86+
87+
void writeGeomSubsetIndices( const pxr::TfToken &familyName, const StringVectorData *data, const IntVectorData *indicesData, const pxr::TfToken &elementType, pxr::UsdGeomPointBased &pointBased, pxr::UsdTimeCode time )
88+
{
89+
int32_t subsetNameIdx = 0;
90+
pxr::TfToken familyType = pxr::UsdGeomTokens->partition;
91+
92+
for( const std::string &subsetName : data->readable() )
93+
{
94+
if( subsetName.empty() && subsetNameIdx == 0 )
95+
{
96+
familyType = pxr::UsdGeomTokens->nonOverlapping;
97+
subsetNameIdx++;
98+
continue;
99+
}
100+
pxr::VtIntArray usdIndices;
101+
int32_t idx = 0;
102+
for( const int32_t &faceIdx : indicesData->readable() )
103+
{
104+
if( faceIdx == subsetNameIdx )
105+
{
106+
usdIndices.push_back( idx );
107+
}
108+
idx++;
109+
}
110+
pxr::UsdGeomSubset::CreateGeomSubset( pointBased, pxr::TfToken( subsetName ), elementType, usdIndices, familyName, familyType );
111+
++subsetNameIdx;
112+
}
113+
}
114+
115+
}; // namespace
116+
71117
void IECoreUSD::PrimitiveAlgo::writePrimitiveVariable( const IECoreScene::PrimitiveVariable &primitiveVariable, pxr::UsdGeomPrimvar &primVar, pxr::UsdTimeCode time )
72118
{
73119
const pxr::TfToken usdInterpolation = toUSD( primitiveVariable.interpolation );
@@ -124,6 +170,35 @@ void IECoreUSD::PrimitiveAlgo::writePrimitiveVariable( const std::string &name,
124170
writePrimitiveVariable( name, primitiveVariable, pxr::UsdGeomPrimvarsAPI( gPrim.GetPrim() ), time );
125171
}
126172

173+
void IECoreUSD::PrimitiveAlgo::writeGeomSubsets( const pxr::TfToken &familyName, const IECoreScene::PrimitiveVariable &primitiveVariable, pxr::UsdGeomPointBased &pointBased, pxr::UsdTimeCode time )
174+
{
175+
if( !primitiveVariable.indices )
176+
{
177+
IECore::msg( IECore::MessageHandler::Level::Warning, "IECoreUSD::PrimitiveAlgo", "No index data for UsdGeomSubset family {}", familyName.GetString() );
178+
return;
179+
}
180+
181+
if( pointBased.GetPrim().IsA<pxr::UsdGeomMesh>() &&
182+
primitiveVariable.interpolation != IECoreScene::PrimitiveVariable::Uniform )
183+
{
184+
IECore::msg( IECore::MessageHandler::Level::Warning, "IECoreUSD::PrimitiveAlgo", "Invalid Interpolation {} for UsdGeomSubset family {}", primitiveVariable.interpolation, familyName.GetString() );
185+
return;
186+
}
187+
188+
const pxr::TfToken elementType = toUSDElementType( pointBased.GetPrim() );
189+
190+
if( elementType.IsEmpty() )
191+
{
192+
IECore::msg( IECore::MessageHandler::Level::Warning, "IECoreUSD::PrimitiveAlgo", "Invalid elementType for GeomSubset family {}", familyName.GetString() );
193+
return;
194+
}
195+
196+
if( const StringVectorData *data = static_cast<const StringVectorData *>( primitiveVariable.data.get() ) )
197+
{
198+
writeGeomSubsetIndices( familyName, data, primitiveVariable.indices.get(), elementType, pointBased, time );
199+
}
200+
}
201+
127202
void IECoreUSD::PrimitiveAlgo::writePrimitiveVariable( const std::string &name, const IECoreScene::PrimitiveVariable &value, pxr::UsdGeomPointBased &pointBased, pxr::UsdTimeCode time )
128203
{
129204
if( name == "P" )
@@ -138,6 +213,15 @@ void IECoreUSD::PrimitiveAlgo::writePrimitiveVariable( const std::string &name,
138213
{
139214
pointBased.CreateAccelerationsAttr().Set( PrimitiveAlgo::toUSDExpanded( value ), time );
140215
}
216+
else if( boost::algorithm::starts_with( name, "geomSubset:" ) )
217+
{
218+
std::vector<std::string> split;
219+
boost::algorithm::split( split, name, boost::algorithm::is_any_of( ":" ) );
220+
if( split.size() > 1 )
221+
{
222+
writeGeomSubsets( pxr::TfToken( split[1] ), value, pointBased, time );
223+
}
224+
}
141225
else
142226
{
143227
writePrimitiveVariable( name, value, static_cast<pxr::UsdGeomGprim &>( pointBased ), time );
@@ -498,6 +582,74 @@ bool skelAnimMightBeTimeVarying( const pxr::UsdPrim &prim )
498582
return animQuery.JointTransformsMightBeTimeVarying() || animQuery.BlendShapeWeightsMightBeTimeVarying();
499583
}
500584

585+
bool geomSubsetsMightBeTimeVarying( const pxr::UsdGeomPointBased &pointBased )
586+
{
587+
for( const pxr::UsdGeomSubset &geomSubset : pxr::UsdGeomSubset::GetAllGeomSubsets( pointBased ) )
588+
{
589+
// We don't check ElementType here as it is considered invalid if it is TimeVarying.
590+
if( geomSubset.GetIndicesAttr().ValueMightBeTimeVarying() )
591+
{
592+
return true;
593+
}
594+
if( geomSubset.GetFamilyNameAttr().ValueMightBeTimeVarying() )
595+
{
596+
return true;
597+
}
598+
}
599+
return false;
600+
}
601+
602+
void readGeomSubsetNamesAndIndices(
603+
const pxr::UsdGeomPointBased &pointBased,
604+
const pxr::TfToken &elementType,
605+
const pxr::TfToken &familyName,
606+
pxr::UsdTimeCode time,
607+
const IECoreScene::Primitive *primitive,
608+
std::vector<std::string> &geomSubsetNames,
609+
std::vector<int> &geomSubsetIndices,
610+
const Canceller *canceller
611+
)
612+
{
613+
int32_t geomSubsetIdx = 0;
614+
615+
const pxr::TfToken familyType = pxr::UsdGeomSubset::GetFamilyType( pointBased, familyName );
616+
const pxr::VtIntArray unassignedIndices = pxr::UsdGeomSubset::GetUnassignedIndices( pointBased, elementType, familyName, time );
617+
if( unassignedIndices.size() && familyType == pxr::UsdGeomTokens->uniform )
618+
{
619+
// This shouldn't happen based on the ValidateFamily functions above, but leaving in here if it does happen.
620+
IECore::msg( IECore::MessageHandler::Level::Warning, "IECoreUSD::PrimitiveAlgo", "FamilyName: {} familyType: {} has unassigned indices.", familyName.GetString(), familyType.GetString() );
621+
}
622+
623+
const auto &geomSubsets = pxr::UsdGeomSubset::GetGeomSubsets( pointBased, elementType, familyName );
624+
geomSubsetNames.resize( unassignedIndices.size() || familyType == pxr::UsdGeomTokens->nonOverlapping ? geomSubsets.size() + 1 : geomSubsets.size() );
625+
geomSubsetIndices.resize( primitive->variableSize( IECoreUSD::PrimitiveAlgo::elementTypeFromUSD( elementType ) ) );
626+
627+
if( unassignedIndices.size() || familyType == pxr::UsdGeomTokens->nonOverlapping )
628+
{
629+
Canceller::check( canceller );
630+
geomSubsetNames[geomSubsetIdx] = std::string();
631+
for( const int &idx : unassignedIndices )
632+
{
633+
geomSubsetIndices[idx] = geomSubsetIdx;
634+
}
635+
++geomSubsetIdx;
636+
}
637+
638+
for( const pxr::UsdGeomSubset &geomSubset : geomSubsets )
639+
{
640+
Canceller::check( canceller );
641+
geomSubsetNames[geomSubsetIdx] = geomSubset.GetPrim().GetName().GetString();
642+
pxr::UsdAttribute indicesAttr = geomSubset.GetIndicesAttr();
643+
pxr::VtIntArray geomIndices;
644+
indicesAttr.Get( &geomIndices, time );
645+
for( const int &idx : geomIndices )
646+
{
647+
geomSubsetIndices[idx] = geomSubsetIdx;
648+
}
649+
++geomSubsetIdx;
650+
}
651+
}
652+
501653
} // namespace
502654

503655
void IECoreUSD::PrimitiveAlgo::readPrimitiveVariables( const pxr::UsdGeomPrimvarsAPI &primvarsAPI, pxr::UsdTimeCode time, IECoreScene::Primitive *primitive, const Canceller *canceller )
@@ -562,7 +714,72 @@ void IECoreUSD::PrimitiveAlgo::readPrimitiveVariables( const pxr::UsdGeomPrimvar
562714
primitive->variables.erase( it );
563715
}
564716
}
717+
}
718+
719+
void IECoreUSD::PrimitiveAlgo::readGeomSubsets( const pxr::UsdGeomPointBased &pointBased, pxr::UsdTimeCode time, IECoreScene::Primitive *primitive, const Canceller *canceller )
720+
{
721+
// We're only interested in a subset of element types based on UsdGeom types.
722+
const pxr::TfToken elementType = toUSDElementType( pointBased.GetPrim() );
723+
724+
if( elementType.IsEmpty() )
725+
{
726+
if( pxr::UsdGeomSubset::GetGeomSubsets( pointBased ).size() )
727+
{
728+
IECore::msg( IECore::MessageHandler::Level::Warning, "IECoreUSD::PrimitiveAlgo", "Prim {} with UsdGeomSubsets has unsupported elementType - skipping", pointBased.GetPrim().GetName().GetString() );
729+
}
730+
return;
731+
}
732+
733+
// Collect all valid family names.
734+
std::set<pxr::TfToken> validGeomSubsetFamilyNames;
565735

736+
// UsdGeomSubsets without a familyName always default to familyType unrestricted so we don't bother accessing those.
737+
for( const auto &geomSubset : pxr::UsdGeomSubset::GetGeomSubsets( pointBased, elementType ) )
738+
{
739+
if( !geomSubset.GetFamilyNameAttr().HasAuthoredValue() )
740+
{
741+
IECore::msg( IECore::MessageHandler::Level::Warning, "IECoreUSD::PrimitiveAlgo", "Prim {} has UsdGeomSubsets without familyName - skipping", pointBased.GetPrim().GetName().GetString() );
742+
break;
743+
}
744+
}
745+
746+
for( const auto &familyName : pxr::UsdGeomSubset::GetAllGeomSubsetFamilyNames( pointBased ) )
747+
{
748+
std::string reason;
749+
pxr::TfToken familyType = pxr::UsdGeomSubset::GetFamilyType( pointBased, familyName );
750+
if( familyType == pxr::UsdGeomTokens->unrestricted )
751+
{
752+
IECore::msg( IECore::MessageHandler::Level::Warning, "IECoreUSD::PrimitiveAlgo", "UsdGeomSubset family: {} familyType: {} not supported - skipping", familyName.GetString(), familyType.GetString() );
753+
continue;
754+
}
755+
else if( !pxr::UsdGeomSubset::ValidateFamily( pointBased, elementType, familyName, &reason ) )
756+
{
757+
IECore::msg( IECore::MessageHandler::Level::Warning, "IECoreUSD::PrimitiveAlgo", "UsdGeomSubset family: {} not supported - {}", familyName.GetString(), reason );
758+
continue;
759+
}
760+
else
761+
{
762+
validGeomSubsetFamilyNames.emplace( familyName );
763+
}
764+
}
765+
766+
// Convert family GeomSubsets to indexed string primitive variables under geomSubset or geomSubset:<familyName>.
767+
for( const auto &familyName : validGeomSubsetFamilyNames )
768+
{
769+
Canceller::check( canceller );
770+
771+
std::vector<std::string> geomSubsetNames;
772+
std::vector<int> geomSubsetIndices;
773+
readGeomSubsetNamesAndIndices( pointBased, elementType, familyName, time, primitive, geomSubsetNames, geomSubsetIndices, canceller );
774+
775+
const std::string geomSubsetPrimvarName = std::string( "geomSubset:" ) + familyName.GetString();
776+
777+
const StringVectorDataPtr data = new StringVectorData( geomSubsetNames );
778+
const IntVectorDataPtr indices = new IntVectorData( geomSubsetIndices );
779+
780+
// Note: Using the pointsBased points attribute for the error print log.
781+
addPrimitiveVariableIfValid( primitive, geomSubsetPrimvarName, IECoreScene::PrimitiveVariable( IECoreUSD::PrimitiveAlgo::elementTypeFromUSD( elementType ), data, indices ), pointBased.GetPointsAttr() );
782+
}
566783
}
567784

568785
void IECoreUSD::PrimitiveAlgo::readPrimitiveVariables( const pxr::UsdGeomPointBased &pointBased, pxr::UsdTimeCode time, IECoreScene::Primitive *primitive, const Canceller *canceller )
@@ -589,6 +806,8 @@ void IECoreUSD::PrimitiveAlgo::readPrimitiveVariables( const pxr::UsdGeomPointBa
589806

590807
Canceller::check( canceller );
591808
readPrimitiveVariable( pointBased.GetAccelerationsAttr(), time, primitive, "acceleration" );
809+
810+
readGeomSubsets( pointBased, time, primitive, canceller );
592811
}
593812

594813
void IECoreUSD::PrimitiveAlgo::readPrimitiveVariable( const pxr::UsdAttribute &attribute, pxr::UsdTimeCode timeCode, IECoreScene::Primitive *primitive, const std::string &name, IECoreScene::PrimitiveVariable::Interpolation interpolation )
@@ -619,7 +838,8 @@ bool IECoreUSD::PrimitiveAlgo::primitiveVariablesMightBeTimeVarying( const pxr::
619838
pointBased.GetVelocitiesAttr().ValueMightBeTimeVarying() ||
620839
pointBased.GetAccelerationsAttr().ValueMightBeTimeVarying() ||
621840
primitiveVariablesMightBeTimeVarying( pxr::UsdGeomPrimvarsAPI( pointBased.GetPrim() ) ) ||
622-
skelAnimMightBeTimeVarying( pointBased.GetPrim() )
841+
skelAnimMightBeTimeVarying( pointBased.GetPrim() ) ||
842+
geomSubsetsMightBeTimeVarying( pointBased )
623843
;
624844
}
625845

@@ -648,3 +868,12 @@ IECoreScene::PrimitiveVariable::Interpolation IECoreUSD::PrimitiveAlgo::fromUSD(
648868

649869
return IECoreScene::PrimitiveVariable::Invalid;
650870
}
871+
872+
IECoreScene::PrimitiveVariable::Interpolation IECoreUSD::PrimitiveAlgo::elementTypeFromUSD( pxr::TfToken elementType )
873+
{
874+
if( elementType == pxr::UsdGeomTokens->face )
875+
{
876+
return IECoreScene::PrimitiveVariable::Uniform;
877+
}
878+
return IECoreScene::PrimitiveVariable::Invalid;
879+
}

0 commit comments

Comments
 (0)