Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Changes
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
10.7.x.x (relative to 10.7.3.1)
========

Improvements
------------

- USD :
- All `radiance:sphericalHarmonicsCoefficients` are now loaded for `ParticleField3DGaussianSplat` objects, regardless of the `radiance:sphericalHarmonicsDegree`.
- Added write support for `ParticleField3DGaussianSplat`.

10.7.3.1 (relative to 10.7.3.0)
========
Expand Down
52 changes: 36 additions & 16 deletions contrib/IECoreUSD/src/IECoreUSD/GaussianSplatAlgo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,33 +113,53 @@ IECore::ObjectPtr readGaussianSplat( pxr::UsdVolParticleField3DGaussianSplat &sp

Canceller::check( canceller );
pxr::UsdAttribute degreeAttr = splats.GetRadianceSphericalHarmonicsDegreeAttr();
auto degreeData = boost::static_pointer_cast<IntData>( DataAlgo::fromUSD( degreeAttr, time, false ) );
newPoints->variables["radiance:sphericalHarmonicsDegree"] = PrimitiveVariable( PrimitiveVariable::Interpolation::Constant, degreeData );

const int degree = degreeData->readable();
const int coefficientCount = ( degree + 1 ) * ( degree + 1 );
PrimitiveAlgo::readPrimitiveVariable( degreeAttr, time, newPoints.get(), "radiance:sphericalHarmonicsDegree", PrimitiveVariable::Interpolation::Constant );

pxr::UsdAttribute coefficientsAttr;
splats.UsesFloatRadianceCoefficients( &coefficientsAttr );
auto allCoefficientsData = runTimeCast<V3fVectorData>( DataAlgo::fromUSD( coefficientsAttr, time ) );

if( allCoefficientsData && allCoefficientsData->readable().size() >= coefficientCount * newPoints->getNumPoints() )
if( auto allCoefficientsData = runTimeCast<V3fVectorData>( DataAlgo::fromUSD( coefficientsAttr, time ) ) )
{
const std::vector<Imath::V3f> &allCoefficients = allCoefficientsData->readable();

for( int i = 0; i < coefficientCount; ++i )
if( allCoefficients.size() % newPoints->getNumPoints() == 0 )
{
Canceller::check( canceller );

V3fVectorDataPtr coefficientsData = new V3fVectorData();
std::vector<Imath::V3f> &coefficients = coefficientsData->writable();
coefficients.resize( newPoints->getNumPoints() );
for( size_t j = 0, eJ = newPoints->getNumPoints(); j < eJ; ++j )
const int coefficientsCount = allCoefficients.size() / newPoints->getNumPoints();
int degree;
degreeAttr.Get( &degree, time );
if( coefficientsCount != ( degree + 1 ) * ( degree + 1 ) )
{
coefficients[j] = allCoefficients[j * coefficientCount + i];
IECore::msg(
IECore::Msg::Warning,
"GaussianSplatAlgo::readGaussianSplat",
"Attribute \"radiance:sphericalHarmonicsCoefficients\" size does not match that expected by \"radiance:sphericalHarmonicsDegree\" at location \"{}\".",
splats.GetPrim().GetPath().GetAsString()
);
}

newPoints->variables[fmt::format( "radiance:sphericalHarmonicsCoefficients:{}", i )] = PrimitiveVariable( PrimitiveVariable::Interpolation::Vertex, coefficientsData );
for( int i = 0; i < coefficientsCount; ++i )
{
Canceller::check( canceller );

V3fVectorDataPtr coefficientsData = new V3fVectorData();
std::vector<Imath::V3f> &coefficients = coefficientsData->writable();
coefficients.resize( newPoints->getNumPoints() );
for( size_t j = 0, eJ = newPoints->getNumPoints(); j < eJ; ++j )
{
coefficients[j] = allCoefficients[j * coefficientsCount + i];
}

newPoints->variables[fmt::format( "radiance:sphericalHarmonicsCoefficients:{}", i )] = PrimitiveVariable( PrimitiveVariable::Interpolation::Vertex, coefficientsData );
}
}
else
{
IECore::msg(
IECore::Msg::Warning,
"GaussianSplatAlgo::readGaussianSplat",
"Attribute \"radiance:sphericalHarmonicsCoefficients\" has invalid length at location \"{}\".",
splats.GetPrim().GetPath().GetAsString()
);
}
}

Expand Down
103 changes: 103 additions & 0 deletions contrib/IECoreUSD/src/IECoreUSD/PointsAlgo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,13 @@

#include "IECore/SimpleTypedData.h"

#include "boost/algorithm/string/predicate.hpp"

IECORE_PUSH_DEFAULT_VISIBILITY
#include "pxr/usd/usdGeom/points.h"
#if PXR_VERSION >= 2603
#include "pxr/usd/usdVol/particleField3DGaussianSplat.h"
#endif
IECORE_POP_DEFAULT_VISIBILITY

using namespace IECore;
Expand Down Expand Up @@ -94,6 +99,104 @@ namespace

bool writePoints( const IECoreScene::PointsPrimitive *points, const pxr::UsdStagePtr &stage, const pxr::SdfPath &path, pxr::UsdTimeCode time )
{
#if PXR_VERSION >= 2603
auto type = points->variableData<const StringData>( "type", PrimitiveVariable::Constant );
if( type && type->readable() == "gaussianSplat" )
{
auto usdSplats = pxr::UsdVolParticleField3DGaussianSplat::Define( stage, path );

int maxCoefficientsIndex = -1;
std::unordered_map<int, const V3fVectorData *> coefficientsMap;

for( const auto &p : points->variables )
{
if( p.first == "P" )
{
usdSplats.CreatePositionsAttr().Set( PrimitiveAlgo::toUSDExpanded( p.second ), time );
}
else if( p.first == "orientations" )
{
usdSplats.CreateOrientationsAttr().Set( PrimitiveAlgo::toUSDExpanded( p.second ), time );
}
else if( p.first == "scales" )
{
usdSplats.CreateScalesAttr().Set( PrimitiveAlgo::toUSDExpanded( p.second ), time );
}
else if( p.first == "opacities" )
{
usdSplats.CreateOpacitiesAttr().Set( PrimitiveAlgo::toUSDExpanded( p.second ), time );
}
else if( p.first == "radiance:sphericalHarmonicsDegree" )
{
usdSplats.CreateRadianceSphericalHarmonicsDegreeAttr().Set( DataAlgo::toUSD( p.second.data.get() ), time );
}
else if( p.first == "projectionModeHint" )
{
usdSplats.CreateProjectionModeHintAttr().Set( DataAlgo::toUSD( p.second.data.get() ), time );
}
else if( p.first == "sortingModeHint" )
{
usdSplats.CreateSortingModeHintAttr().Set( DataAlgo::toUSD( p.second.data.get() ), time );
}
else if( boost::starts_with( p.first, "radiance:sphericalHarmonicsCoefficients:" ) )
{
try
{
const int coefficientsIndex = std::stoi( p.first.substr( 40 ) ); // 40 = length of `radiance:...` prefix

if( p.second.data->typeId() != V3fVectorDataTypeId || p.second.interpolation != PrimitiveVariable::Interpolation::Vertex )
{
IECore::msg(
IECore::Msg::Warning,
"PointsAlgo::writePoints",
"Invalid primitive variable \"{}\" on location \"{}\". Spherical harmonics coefficients must be of type V3fVectorData with Vertex interpolation.",
p.first, path.GetAsString()
);
continue;
}

coefficientsMap[coefficientsIndex] = static_cast<const V3fVectorData *>( p.second.data.get() );
maxCoefficientsIndex = std::max( maxCoefficientsIndex, coefficientsIndex );
}
catch( ... )
{
PrimitiveAlgo::writePrimitiveVariable( p.first, p.second, usdSplats, time );
}
}
else if( p.first == "type" )
{
// This is intrinsic to `UsdVolParticleField3DGaussianSplat`
continue;
}
else
{
PrimitiveAlgo::writePrimitiveVariable( p.first, p.second, usdSplats, time );
}
}

if( !coefficientsMap.empty() )
{
const int coefficientsCount = maxCoefficientsIndex + 1;
pxr::VtArray<pxr::GfVec3f> allCoefficients( coefficientsCount * points->getNumPoints() );

for( const auto &[i, coefficientsData] : coefficientsMap )
{
const std::vector<Imath::V3f> &coefficients = coefficientsData->readable();

for( size_t j = 0, eJ = points->getNumPoints(); j < eJ; ++j )
{
allCoefficients[j * coefficientsCount + i] = DataAlgo::toUSD( coefficients[j] );
}
}

usdSplats.CreateRadianceSphericalHarmonicsCoefficientsAttr().Set( allCoefficients, time );
}

return true;
}

#endif

auto usdPoints = pxr::UsdGeomPoints::Define( stage, path );
for( const auto &p : points->variables )
{
Expand Down
Loading
Loading