Skip to content

Commit 93dce5e

Browse files
authored
Merge pull request #1572 from ericmehl/gSplatsWrite
Gaussian Splats Writing
2 parents 85bd052 + ca72db1 commit 93dce5e

4 files changed

Lines changed: 338 additions & 17 deletions

File tree

‎Changes‎

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

4+
Improvements
5+
------------
46

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

611
10.7.3.1 (relative to 10.7.3.0)
712
========

‎contrib/IECoreUSD/src/IECoreUSD/GaussianSplatAlgo.cpp‎

Lines changed: 36 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -113,33 +113,53 @@ IECore::ObjectPtr readGaussianSplat( pxr::UsdVolParticleField3DGaussianSplat &sp
113113

114114
Canceller::check( canceller );
115115
pxr::UsdAttribute degreeAttr = splats.GetRadianceSphericalHarmonicsDegreeAttr();
116-
auto degreeData = boost::static_pointer_cast<IntData>( DataAlgo::fromUSD( degreeAttr, time, false ) );
117-
newPoints->variables["radiance:sphericalHarmonicsDegree"] = PrimitiveVariable( PrimitiveVariable::Interpolation::Constant, degreeData );
118-
119-
const int degree = degreeData->readable();
120-
const int coefficientCount = ( degree + 1 ) * ( degree + 1 );
116+
PrimitiveAlgo::readPrimitiveVariable( degreeAttr, time, newPoints.get(), "radiance:sphericalHarmonicsDegree", PrimitiveVariable::Interpolation::Constant );
121117

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

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

130-
for( int i = 0; i < coefficientCount; ++i )
125+
if( allCoefficients.size() % newPoints->getNumPoints() == 0 )
131126
{
132-
Canceller::check( canceller );
133-
134-
V3fVectorDataPtr coefficientsData = new V3fVectorData();
135-
std::vector<Imath::V3f> &coefficients = coefficientsData->writable();
136-
coefficients.resize( newPoints->getNumPoints() );
137-
for( size_t j = 0, eJ = newPoints->getNumPoints(); j < eJ; ++j )
127+
const int coefficientsCount = allCoefficients.size() / newPoints->getNumPoints();
128+
int degree;
129+
degreeAttr.Get( &degree, time );
130+
if( coefficientsCount != ( degree + 1 ) * ( degree + 1 ) )
138131
{
139-
coefficients[j] = allCoefficients[j * coefficientCount + i];
132+
IECore::msg(
133+
IECore::Msg::Warning,
134+
"GaussianSplatAlgo::readGaussianSplat",
135+
"Attribute \"radiance:sphericalHarmonicsCoefficients\" size does not match that expected by \"radiance:sphericalHarmonicsDegree\" at location \"{}\".",
136+
splats.GetPrim().GetPath().GetAsString()
137+
);
140138
}
141139

142-
newPoints->variables[fmt::format( "radiance:sphericalHarmonicsCoefficients:{}", i )] = PrimitiveVariable( PrimitiveVariable::Interpolation::Vertex, coefficientsData );
140+
for( int i = 0; i < coefficientsCount; ++i )
141+
{
142+
Canceller::check( canceller );
143+
144+
V3fVectorDataPtr coefficientsData = new V3fVectorData();
145+
std::vector<Imath::V3f> &coefficients = coefficientsData->writable();
146+
coefficients.resize( newPoints->getNumPoints() );
147+
for( size_t j = 0, eJ = newPoints->getNumPoints(); j < eJ; ++j )
148+
{
149+
coefficients[j] = allCoefficients[j * coefficientsCount + i];
150+
}
151+
152+
newPoints->variables[fmt::format( "radiance:sphericalHarmonicsCoefficients:{}", i )] = PrimitiveVariable( PrimitiveVariable::Interpolation::Vertex, coefficientsData );
153+
}
154+
}
155+
else
156+
{
157+
IECore::msg(
158+
IECore::Msg::Warning,
159+
"GaussianSplatAlgo::readGaussianSplat",
160+
"Attribute \"radiance:sphericalHarmonicsCoefficients\" has invalid length at location \"{}\".",
161+
splats.GetPrim().GetPath().GetAsString()
162+
);
143163
}
144164
}
145165

‎contrib/IECoreUSD/src/IECoreUSD/PointsAlgo.cpp‎

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,13 @@
4040

4141
#include "IECore/SimpleTypedData.h"
4242

43+
#include "boost/algorithm/string/predicate.hpp"
44+
4345
IECORE_PUSH_DEFAULT_VISIBILITY
4446
#include "pxr/usd/usdGeom/points.h"
47+
#if PXR_VERSION >= 2603
48+
#include "pxr/usd/usdVol/particleField3DGaussianSplat.h"
49+
#endif
4550
IECORE_POP_DEFAULT_VISIBILITY
4651

4752
using namespace IECore;
@@ -94,6 +99,104 @@ namespace
9499

95100
bool writePoints( const IECoreScene::PointsPrimitive *points, const pxr::UsdStagePtr &stage, const pxr::SdfPath &path, pxr::UsdTimeCode time )
96101
{
102+
#if PXR_VERSION >= 2603
103+
auto type = points->variableData<const StringData>( "type", PrimitiveVariable::Constant );
104+
if( type && type->readable() == "gaussianSplat" )
105+
{
106+
auto usdSplats = pxr::UsdVolParticleField3DGaussianSplat::Define( stage, path );
107+
108+
int maxCoefficientsIndex = -1;
109+
std::unordered_map<int, const V3fVectorData *> coefficientsMap;
110+
111+
for( const auto &p : points->variables )
112+
{
113+
if( p.first == "P" )
114+
{
115+
usdSplats.CreatePositionsAttr().Set( PrimitiveAlgo::toUSDExpanded( p.second ), time );
116+
}
117+
else if( p.first == "orientations" )
118+
{
119+
usdSplats.CreateOrientationsAttr().Set( PrimitiveAlgo::toUSDExpanded( p.second ), time );
120+
}
121+
else if( p.first == "scales" )
122+
{
123+
usdSplats.CreateScalesAttr().Set( PrimitiveAlgo::toUSDExpanded( p.second ), time );
124+
}
125+
else if( p.first == "opacities" )
126+
{
127+
usdSplats.CreateOpacitiesAttr().Set( PrimitiveAlgo::toUSDExpanded( p.second ), time );
128+
}
129+
else if( p.first == "radiance:sphericalHarmonicsDegree" )
130+
{
131+
usdSplats.CreateRadianceSphericalHarmonicsDegreeAttr().Set( DataAlgo::toUSD( p.second.data.get() ), time );
132+
}
133+
else if( p.first == "projectionModeHint" )
134+
{
135+
usdSplats.CreateProjectionModeHintAttr().Set( DataAlgo::toUSD( p.second.data.get() ), time );
136+
}
137+
else if( p.first == "sortingModeHint" )
138+
{
139+
usdSplats.CreateSortingModeHintAttr().Set( DataAlgo::toUSD( p.second.data.get() ), time );
140+
}
141+
else if( boost::starts_with( p.first, "radiance:sphericalHarmonicsCoefficients:" ) )
142+
{
143+
try
144+
{
145+
const int coefficientsIndex = std::stoi( p.first.substr( 40 ) ); // 40 = length of `radiance:...` prefix
146+
147+
if( p.second.data->typeId() != V3fVectorDataTypeId || p.second.interpolation != PrimitiveVariable::Interpolation::Vertex )
148+
{
149+
IECore::msg(
150+
IECore::Msg::Warning,
151+
"PointsAlgo::writePoints",
152+
"Invalid primitive variable \"{}\" on location \"{}\". Spherical harmonics coefficients must be of type V3fVectorData with Vertex interpolation.",
153+
p.first, path.GetAsString()
154+
);
155+
continue;
156+
}
157+
158+
coefficientsMap[coefficientsIndex] = static_cast<const V3fVectorData *>( p.second.data.get() );
159+
maxCoefficientsIndex = std::max( maxCoefficientsIndex, coefficientsIndex );
160+
}
161+
catch( ... )
162+
{
163+
PrimitiveAlgo::writePrimitiveVariable( p.first, p.second, usdSplats, time );
164+
}
165+
}
166+
else if( p.first == "type" )
167+
{
168+
// This is intrinsic to `UsdVolParticleField3DGaussianSplat`
169+
continue;
170+
}
171+
else
172+
{
173+
PrimitiveAlgo::writePrimitiveVariable( p.first, p.second, usdSplats, time );
174+
}
175+
}
176+
177+
if( !coefficientsMap.empty() )
178+
{
179+
const int coefficientsCount = maxCoefficientsIndex + 1;
180+
pxr::VtArray<pxr::GfVec3f> allCoefficients( coefficientsCount * points->getNumPoints() );
181+
182+
for( const auto &[i, coefficientsData] : coefficientsMap )
183+
{
184+
const std::vector<Imath::V3f> &coefficients = coefficientsData->readable();
185+
186+
for( size_t j = 0, eJ = points->getNumPoints(); j < eJ; ++j )
187+
{
188+
allCoefficients[j * coefficientsCount + i] = DataAlgo::toUSD( coefficients[j] );
189+
}
190+
}
191+
192+
usdSplats.CreateRadianceSphericalHarmonicsCoefficientsAttr().Set( allCoefficients, time );
193+
}
194+
195+
return true;
196+
}
197+
198+
#endif
199+
97200
auto usdPoints = pxr::UsdGeomPoints::Define( stage, path );
98201
for( const auto &p : points->variables )
99202
{

0 commit comments

Comments
 (0)