Skip to content

Commit 33d293c

Browse files
authored
Fix sampling of instancer matrices after a change of shutter value (#2272)
* resample the instancer matrices if the shutter has changed * fix incorrect initialization of the node indices array * add test * add changelog * add note * protect reading the sampled primvars with a lock
1 parent 9588c4e commit 33d293c

File tree

6 files changed

+487
-18
lines changed

6 files changed

+487
-18
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
### Bug fixes
77

88
- [usd#2269](https://github.com/Autodesk/arnold-usd/issues/2269) - Connections are not processed correctly during hydra procedural updates
9+
- [usd#2268](https://github.com/Autodesk/arnold-usd/issues/2268) - Reenable instancer motion blur on the first rendered frame by recomputing the transform matrices when the shutter is updated.
910

1011
## [7.4.1.0] - 2025-03-26
1112

libs/render_delegate/instancer.cpp

Lines changed: 51 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,17 @@ void HdArnoldInstancer::Sync(HdSceneDelegate* sceneDelegate, HdRenderParam* rend
9393
}
9494
}
9595

96+
// Sample a primvar, check that the keys have the correct number of instances otherwise get only the sample at the keyframe
97+
// We have to do this because hydra SamplePrimvar
98+
template <typename VectorT>
99+
static void SamplePrimvar(
100+
HdSceneDelegate* delegate, const SdfPath& id, const TfToken& key, const GfVec2f& shutterRange, VectorT& out)
101+
{
102+
HdArnoldSampledPrimvarType sample;
103+
delegate->SamplePrimvar(id, key, &sample);
104+
HdArnoldUnboxResample(sample, shutterRange, out);
105+
}
106+
96107
void HdArnoldInstancer::_SyncPrimvars(HdDirtyBits dirtyBits, HdArnoldRenderParam* renderParam)
97108
{
98109
auto& changeTracker = GetDelegate()->GetRenderIndex().GetChangeTracker();
@@ -120,21 +131,13 @@ void HdArnoldInstancer::_SyncPrimvars(HdDirtyBits dirtyBits, HdArnoldRenderParam
120131
continue;
121132
}
122133
if (primvar.name == GetInstanceTransformsToken()) {
123-
HdArnoldSampledPrimvarType sample;
124-
GetDelegate()->SamplePrimvar(id, GetInstanceTransformsToken(), &sample);
125-
HdArnoldUnboxResample(sample, renderParam->GetShutterRange(), _transforms);
134+
SamplePrimvar(GetDelegate(), id, primvar.name, renderParam->GetShutterRange(), _transforms);
126135
} else if (primvar.name == GetRotateToken()) {
127-
HdArnoldSampledPrimvarType sample;
128-
GetDelegate()->SamplePrimvar(id, GetRotateToken(), &sample);
129-
HdArnoldUnboxResample(sample, renderParam->GetShutterRange(), _rotates);
136+
SamplePrimvar(GetDelegate(), id, primvar.name, renderParam->GetShutterRange(), _rotates);
130137
} else if (primvar.name == GetScaleToken()) {
131-
HdArnoldSampledPrimvarType sample;
132-
GetDelegate()->SamplePrimvar(id, GetScaleToken(), &sample);
133-
HdArnoldUnboxResample(sample, renderParam->GetShutterRange(), _scales);
138+
SamplePrimvar(GetDelegate(), id, primvar.name, renderParam->GetShutterRange(), _scales);
134139
} else if (primvar.name == GetTranslateToken()) {
135-
HdArnoldSampledPrimvarType sample;
136-
GetDelegate()->SamplePrimvar(id, GetTranslateToken(), &sample);
137-
HdArnoldUnboxResample(sample, renderParam->GetShutterRange(), _translates);
140+
SamplePrimvar(GetDelegate(), id, primvar.name, renderParam->GetShutterRange(), _translates);
138141
} else {
139142
HdArnoldInsertPrimvar(
140143
_primvars, primvar.name, primvar.role, primvar.interpolation, GetDelegate()->Get(id, primvar.name),
@@ -143,13 +146,39 @@ void HdArnoldInstancer::_SyncPrimvars(HdDirtyBits dirtyBits, HdArnoldRenderParam
143146
}
144147
}
145148

149+
// NOTE: it shouldn't be necessary to mark the instancer clean as it is done later on by hydra
146150
changeTracker.MarkInstancerClean(id);
147151
}
148152

153+
void HdArnoldInstancer::ResampleInstancePrimvars()
154+
{
155+
const auto& id = GetId();
156+
std::lock_guard<std::mutex> lock(_mutex);
157+
// Recompute the sampled primvars only if they were previously sampled
158+
if (_transforms.count) {
159+
SamplePrimvar(GetDelegate(), id, GetInstanceTransformsToken(), _samplingInterval, _transforms);
160+
}
161+
if (_rotates.count) {
162+
SamplePrimvar(GetDelegate(), id, GetRotateToken(), _samplingInterval, _rotates);
163+
}
164+
if (_scales.count) {
165+
SamplePrimvar(GetDelegate(), id, GetScaleToken(), _samplingInterval, _scales);
166+
}
167+
if (_translates.count) {
168+
SamplePrimvar(GetDelegate(), id, GetTranslateToken(), _samplingInterval, _translates);
169+
}
170+
}
171+
149172
void HdArnoldInstancer::CalculateInstanceMatrices(HdArnoldRenderDelegate* renderDelegate,
150173
const SdfPath& prototypeId, std::vector<AtNode *> &instancers)
151174
{
152175
const SdfPath& instancerId = GetId();
176+
HdArnoldRenderParam * renderParam = reinterpret_cast<HdArnoldRenderParam*>(renderDelegate->GetRenderParam());
177+
178+
// If the sampling interval has changed we need to resample the translate, orientations and scales
179+
if (UpdateSamplingInterval(renderParam->GetShutterRange())){
180+
ResampleInstancePrimvars();
181+
}
153182

154183
const auto instanceIndices = GetDelegate()->GetInstanceIndices(instancerId, prototypeId);
155184
if (instanceIndices.empty()) {
@@ -166,10 +195,15 @@ void HdArnoldInstancer::CalculateInstanceMatrices(HdArnoldRenderDelegate* render
166195
// most samples and use its time range.
167196
// TODO(pal): Improve this further by using the widest time range and calculate sample count based on that.
168197
_AccumulateSampleTimes(instancerTransforms, sampleArray);
169-
_AccumulateSampleTimes(_transforms, sampleArray);
170-
_AccumulateSampleTimes(_translates, sampleArray);
171-
_AccumulateSampleTimes(_rotates, sampleArray);
172-
_AccumulateSampleTimes(_scales, sampleArray);
198+
{
199+
// Another mesh can be resampling the instances primvars, we need to lock
200+
std::lock_guard<std::mutex> lock(_mutex);
201+
_AccumulateSampleTimes(_transforms, sampleArray);
202+
_AccumulateSampleTimes(_translates, sampleArray);
203+
_AccumulateSampleTimes(_rotates, sampleArray);
204+
_AccumulateSampleTimes(_scales, sampleArray);
205+
}
206+
173207

174208
// By default _deformKeys will take over sample counts
175209
if (sampleArray.count <= 2 && _deformKeys < 2 && _deformKeys > -1 ) {
@@ -274,7 +308,7 @@ void HdArnoldInstancer::CalculateInstanceMatrices(HdArnoldRenderDelegate* render
274308
auto* nodeIdxsArray = AiArrayAllocate(instanceCount, sampleCount, AI_TYPE_UINT);
275309
auto* matrices = static_cast<AtMatrix*>(AiArrayMap(matrixArray));
276310
auto* nodeIdxs = static_cast<uint32_t*>(AiArrayMap(nodeIdxsArray));
277-
std::fill(nodeIdxs, nodeIdxs + instanceCount, 0);
311+
std::fill(nodeIdxs, nodeIdxs + instanceCount*sampleCount, 0);
278312
AiArrayUnmap(nodeIdxsArray);
279313
auto convertMatrices = [&](size_t sample) {
280314
std::transform(

libs/render_delegate/instancer.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,18 @@ class HdArnoldInstancer : public HdInstancer {
8383
/// Safe to call on multiple threads.
8484
HDARNOLD_API
8585
void _SyncPrimvars(HdDirtyBits dirtyBits, HdArnoldRenderParam* renderParam);
86+
87+
/// Saves the sampling interval used for sampling the primvars related to the transform
88+
/// Returns true if the value has changed
89+
inline bool UpdateSamplingInterval(GfVec2f samplingInterval)
90+
{
91+
bool hasChanged = samplingInterval != _samplingInterval;
92+
_samplingInterval = samplingInterval;
93+
return hasChanged;
94+
}
95+
/// @brief Resamples the stored sampled primvars. This is necessary when the sampling interval has changed
96+
void ResampleInstancePrimvars();
97+
8698
HdArnoldRenderDelegate* _delegate = nullptr;
8799
std::mutex _mutex; ///< Mutex to safe-guard calls to _SyncPrimvars.
88100
HdArnoldPrimvarMap _primvars; ///< Unordered map to store all the primvars.
@@ -91,8 +103,8 @@ class HdArnoldInstancer : public HdInstancer {
91103
// Newer versions use GfQuatH arrays instead of GfVec4f arrays.
92104
HdArnoldSampledType<VtQuathArray> _rotates; ///< Sampled instance rotate values.
93105
HdArnoldSampledType<VtVec3fArray> _scales; ///< Sampled instance scale values.
94-
95106
int _deformKeys = -1; ///< Number of samples to consider, -1 means deactivated
107+
GfVec2f _samplingInterval = {0.f, 0.f}; //< Keep track of the primvar sampling interval used
96108
};
97109

98110
PXR_NAMESPACE_CLOSE_SCOPE

testsuite/test_2268/README

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Instancer motion blur
2+
3+
see #2268
4+
5+
6+
7+
PARAMS: {'scene': 'test.usda', 'kick_params': '-frame 3'}

0 commit comments

Comments
 (0)