1 //
2 // Copyright 2016 Pixar
3 //
4 // Licensed under the Apache License, Version 2.0 (the "Apache License")
5 // with the following modification; you may not use this file except in
6 // compliance with the Apache License and the following modification to it:
7 // Section 6. Trademarks. is deleted and replaced with:
8 //
9 // 6. Trademarks. This License does not grant permission to use the trade
10 // names, trademarks, service marks, or product names of the Licensor
11 // and its affiliates, except as required to comply with Section 4(c) of
12 // the License and to reproduce the content of the NOTICE file.
13 //
14 // You may obtain a copy of the Apache License at
15 //
16 // http://www.apache.org/licenses/LICENSE-2.0
17 //
18 // Unless required by applicable law or agreed to in writing, software
19 // distributed under the Apache License with the above modification is
20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 // KIND, either express or implied. See the Apache License for the specific
22 // language governing permissions and limitations under the Apache License.
23 //
24 #include "pxr/usdImaging/usdImaging/gprimAdapter.h"
25
26 #include "pxr/usdImaging/usdImaging/coordSysAdapter.h"
27 #include "pxr/usdImaging/usdImaging/debugCodes.h"
28 #include "pxr/usdImaging/usdImaging/delegate.h"
29 #include "pxr/usdImaging/usdImaging/indexProxy.h"
30 #include "pxr/usdImaging/usdImaging/instancerContext.h"
31 #include "pxr/usdImaging/usdImaging/tokens.h"
32
33 #include "pxr/imaging/hd/perfLog.h"
34 #include "pxr/imaging/hd/material.h"
35 #include "pxr/imaging/hd/renderDelegate.h"
36 #include "pxr/imaging/hd/sceneDelegate.h"
37
38 #include "pxr/usd/usdGeom/gprim.h"
39 #include "pxr/usd/usdGeom/pointBased.h"
40 #include "pxr/usd/usdGeom/primvarsAPI.h"
41
42 #include "pxr/usd/usdShade/connectableAPI.h"
43 #include "pxr/usd/usdShade/material.h"
44 #include "pxr/usd/usdShade/shader.h"
45
46 #include "pxr/base/tf/type.h"
47
48 PXR_NAMESPACE_OPEN_SCOPE
49
50
TF_REGISTRY_FUNCTION(TfType)51 TF_REGISTRY_FUNCTION(TfType)
52 {
53 typedef UsdImagingGprimAdapter Adapter;
54 TfType::Define<Adapter, TfType::Bases<Adapter::BaseAdapter> >();
55 // No factory here, GprimAdapter is abstract.
56 }
57
58 static TfTokenVector
_GetPrimvarsForMaterial(const VtValue & vtMaterial)59 _GetPrimvarsForMaterial(const VtValue & vtMaterial)
60 {
61 TfTokenVector primvars;
62
63 if (vtMaterial.IsHolding<HdMaterialNetworkMap>()) {
64
65 HdMaterialNetworkMap const& networkMap =
66 vtMaterial.UncheckedGet<HdMaterialNetworkMap>();
67
68 // To simplify the logic so we do not have to pick between different
69 // networks (surface, displacement, volume), we merge all primvars.
70
71 for (auto const& itMap : networkMap.map) {
72 HdMaterialNetwork const& network = itMap.second;
73 primvars.insert(primvars.end(),
74 network.primvars.begin(), network.primvars.end());
75 }
76 }
77
78 return primvars;
79 }
80
~UsdImagingGprimAdapter()81 UsdImagingGprimAdapter::~UsdImagingGprimAdapter()
82 {
83 }
84
85 /* static */
86 SdfPath
_ResolveCachePath(SdfPath const & usdPath,UsdImagingInstancerContext const * instancerContext)87 UsdImagingGprimAdapter::_ResolveCachePath(SdfPath const& usdPath,
88 UsdImagingInstancerContext const*
89 instancerContext)
90 {
91 SdfPath cachePath = usdPath;
92
93 // For non-instanced prims, cachePath and usdPath will be the same, however
94 // for instanced prims, cachePath will be something like:
95 //
96 // primPath: /__Prototype_1/cube
97 // cachePath: /Models/cube_0.proto_cube_id0
98 //
99 // The name-mangling is so that multiple instancers/adapters can track the
100 // same underlying UsdPrim.
101
102 if (instancerContext != nullptr) {
103 SdfPath const& instancer = instancerContext->instancerCachePath;
104 TfToken const& childName = instancerContext->childName;
105
106 if (!instancer.IsEmpty()) {
107 cachePath = instancer;
108 }
109 if (!childName.IsEmpty()) {
110 cachePath = cachePath.AppendProperty(childName);
111 }
112 }
113 return cachePath;
114 }
115
116 SdfPath
_AddRprim(TfToken const & primType,UsdPrim const & usdPrim,UsdImagingIndexProxy * index,SdfPath const & materialUsdPath,UsdImagingInstancerContext const * instancerContext)117 UsdImagingGprimAdapter::_AddRprim(TfToken const& primType,
118 UsdPrim const& usdPrim,
119 UsdImagingIndexProxy* index,
120 SdfPath const& materialUsdPath,
121 UsdImagingInstancerContext const*
122 instancerContext)
123 {
124 SdfPath cachePath = _ResolveCachePath(usdPrim.GetPath(), instancerContext);
125
126 // For an instanced gprim, this is the instancer prim.
127 // For a non-instanced gprim, this is just the gprim.
128 UsdPrim proxyPrim = usdPrim.GetStage()->GetPrimAtPath(
129 cachePath.GetAbsoluteRootOrPrimPath());
130
131 index->InsertRprim(primType, cachePath, proxyPrim,
132 instancerContext ? instancerContext->instancerAdapter
133 : UsdImagingPrimAdapterSharedPtr());
134 HD_PERF_COUNTER_INCR(UsdImagingTokens->usdPopulatedPrimCount);
135
136 // As long as we're passing the proxyPrim in here, we need to add a
137 // manual dependency on usdPrim so that usd editing works correctly;
138 // also, get rid of the proxyPrim dependency.
139 // XXX: We should get rid of proxyPrim entirely.
140 if (instancerContext != nullptr) {
141 index->RemovePrimInfoDependency(cachePath);
142 index->AddDependency(cachePath, usdPrim);
143 }
144
145 // If there's no local material path, fall back to the instancer material.
146 SdfPath resolvedUsdMaterialPath = materialUsdPath;
147 if (materialUsdPath.IsEmpty() && instancerContext != nullptr) {
148 resolvedUsdMaterialPath = instancerContext->instancerMaterialUsdPath;
149 }
150 UsdPrim materialPrim =
151 usdPrim.GetStage()->GetPrimAtPath(resolvedUsdMaterialPath);
152
153 if (materialPrim) {
154 if (materialPrim.IsA<UsdShadeMaterial>()) {
155 UsdImagingPrimAdapterSharedPtr materialAdapter =
156 index->GetMaterialAdapter(materialPrim);
157 if (materialAdapter) {
158 materialAdapter->Populate(materialPrim, index, nullptr);
159 // We need to register a dependency on the material prim so
160 // that geometry is updated when the material is
161 // (specifically, DirtyMaterialId).
162 // XXX: Eventually, it would be great to push this into hydra.
163 index->AddDependency(cachePath, materialPrim);
164 }
165 } else {
166 TF_WARN("Gprim <%s> has illegal material reference to "
167 "prim <%s> of type (%s)", usdPrim.GetPath().GetText(),
168 materialPrim.GetPath().GetText(),
169 materialPrim.GetTypeName().GetText());
170 }
171 }
172
173 // Populate coordinate system sprims bound to rprims.
174 if (_DoesDelegateSupportCoordSys()) {
175 if (UsdImagingPrimAdapterSharedPtr coordSysAdapter =
176 _GetAdapter(HdPrimTypeTokens->coordSys)) {
177 coordSysAdapter->Populate(usdPrim, index, instancerContext);
178 }
179 }
180
181 return cachePath;
182 }
183
184 void
TrackVariability(UsdPrim const & prim,SdfPath const & cachePath,HdDirtyBits * timeVaryingBits,UsdImagingInstancerContext const * instancerContext) const185 UsdImagingGprimAdapter::TrackVariability(UsdPrim const& prim,
186 SdfPath const& cachePath,
187 HdDirtyBits* timeVaryingBits,
188 UsdImagingInstancerContext const*
189 instancerContext) const
190 {
191 // See if any of the inherited primvars are time-dependent.
192 UsdImaging_InheritedPrimvarStrategy::value_type inheritedPrimvarRecord =
193 _GetInheritedPrimvars(prim.GetParent());
194 if (inheritedPrimvarRecord && inheritedPrimvarRecord->variable) {
195 *timeVaryingBits |= HdChangeTracker::DirtyPrimvar;
196 HD_PERF_COUNTER_INCR(UsdImagingTokens->usdVaryingPrimvar);
197 }
198 if (!(*timeVaryingBits & HdChangeTracker::DirtyPrimvar)) {
199 // See if any local primvars are time-dependent.
200 UsdGeomPrimvarsAPI primvarsAPI(prim);
201 std::vector<UsdGeomPrimvar> primvars =
202 primvarsAPI.GetPrimvarsWithValues();
203 for (UsdGeomPrimvar const& pv : primvars) {
204 if (pv.ValueMightBeTimeVarying()) {
205 *timeVaryingBits |= HdChangeTracker::DirtyPrimvar;
206 HD_PERF_COUNTER_INCR(UsdImagingTokens->usdVaryingPrimvar);
207 break;
208 }
209 }
210 }
211
212 // Discover time-varying extent.
213 _IsVarying(prim,
214 UsdGeomTokens->extent,
215 HdChangeTracker::DirtyExtent,
216 UsdImagingTokens->usdVaryingExtent,
217 timeVaryingBits,
218 false);
219
220 // Discover time-varying transforms.
221 _IsTransformVarying(prim,
222 HdChangeTracker::DirtyTransform,
223 UsdImagingTokens->usdVaryingXform,
224 timeVaryingBits);
225
226 // Discover time-varying visibility.
227 _IsVarying(prim,
228 UsdGeomTokens->visibility,
229 HdChangeTracker::DirtyVisibility,
230 UsdImagingTokens->usdVaryingVisibility,
231 timeVaryingBits,
232 true);
233
234 // Discover time-varying points.
235 _IsVarying(prim,
236 UsdGeomTokens->velocities,
237 HdChangeTracker::DirtyPoints,
238 UsdImagingTokens->usdVaryingPrimvar,
239 timeVaryingBits,
240 false) ||
241 _IsVarying(prim,
242 UsdGeomTokens->accelerations,
243 HdChangeTracker::DirtyPoints,
244 UsdImagingTokens->usdVaryingPrimvar,
245 timeVaryingBits,
246 false);
247 // XXX: "points" is handled by derived classes.
248
249 // Discover time-varying double-sidedness.
250 _IsVarying(prim,
251 UsdGeomTokens->doubleSided,
252 HdChangeTracker::DirtyDoubleSided,
253 UsdImagingTokens->usdVaryingTopology,
254 timeVaryingBits,
255 false);
256 }
257
258 void
_RemovePrim(SdfPath const & cachePath,UsdImagingIndexProxy * index)259 UsdImagingGprimAdapter::_RemovePrim(SdfPath const& cachePath,
260 UsdImagingIndexProxy* index)
261 {
262 index->RemoveRprim(cachePath);
263 }
264
265 bool
_IsBuiltinPrimvar(TfToken const & primvarName) const266 UsdImagingGprimAdapter::_IsBuiltinPrimvar(TfToken const& primvarName) const
267 {
268 return (primvarName == HdTokens->displayColor ||
269 primvarName == HdTokens->displayOpacity);
270 }
271
272 void
UpdateForTime(UsdPrim const & prim,SdfPath const & cachePath,UsdTimeCode time,HdDirtyBits requestedBits,UsdImagingInstancerContext const * instancerContext) const273 UsdImagingGprimAdapter::UpdateForTime(UsdPrim const& prim,
274 SdfPath const& cachePath,
275 UsdTimeCode time,
276 HdDirtyBits requestedBits,
277 UsdImagingInstancerContext const*
278 instancerContext) const
279 {
280 UsdImagingPrimvarDescCache* primvarDescCache = _GetPrimvarDescCache();
281 HdPrimvarDescriptorVector& vPrimvars =
282 primvarDescCache->GetPrimvars(cachePath);
283
284 if (requestedBits & HdChangeTracker::DirtyPoints) {
285
286 // Expose points as a primvar.
287 _MergePrimvar(
288 &vPrimvars,
289 HdTokens->points,
290 HdInterpolationVertex,
291 HdPrimvarRoleTokens->point);
292
293 // Velocity information is expected to be authored at the same sample
294 // rate as points data, so use the points dirty bit to let us know when
295 // to publish velocities.
296 UsdGeomPointBased pointBased(prim);
297 VtVec3fArray velocities;
298 if (pointBased.GetVelocitiesAttr() &&
299 pointBased.GetVelocitiesAttr().Get(&velocities, time)) {
300 // Expose velocities as a primvar.
301 _MergePrimvar(
302 &vPrimvars,
303 HdTokens->velocities,
304 HdInterpolationVertex,
305 HdPrimvarRoleTokens->vector);
306 }
307
308 // Acceleration information is expected to be authored at the same sample
309 // rate as points data, so use the points dirty bit to let us know when
310 // to publish accelerations.
311 VtVec3fArray accelerations;
312 if (pointBased.GetAccelerationsAttr() &&
313 pointBased.GetAccelerationsAttr().Get(&accelerations, time)) {
314 // Expose accelerations as a primvar.
315 _MergePrimvar(
316 &vPrimvars,
317 HdTokens->accelerations,
318 HdInterpolationVertex,
319 HdPrimvarRoleTokens->vector);
320 }
321 }
322
323 SdfPathVector materialUsdPaths;
324 if (requestedBits & (HdChangeTracker::DirtyPrimvar |
325 HdChangeTracker::DirtyMaterialId)) {
326 SdfPath materialUsdPath = GetMaterialUsdPath(prim);
327 if (!materialUsdPath.IsEmpty()) {
328 materialUsdPaths.push_back(materialUsdPath);
329 } else if (instancerContext) {
330 // If we're processing this gprim on behalf of an instancer,
331 // use the material binding specified by the instancer if we
332 // aren't able to find a material binding for this prim itself.
333 materialUsdPaths.push_back(instancerContext->instancerMaterialUsdPath);
334 }
335 }
336
337 if (requestedBits & HdChangeTracker::DirtyPrimvar) {
338 if (UsdGeomImageable imageable = UsdGeomImageable(prim)) {
339 for (const UsdGeomSubset &subset: UsdGeomSubset::GetAllGeomSubsets(imageable)) {
340 SdfPath materialUsdPath = GetMaterialUsdPath(subset.GetPrim());
341 if (!materialUsdPath.IsEmpty()) {
342 materialUsdPaths.push_back(materialUsdPath);
343 }
344 }
345 }
346 }
347
348 if (requestedBits & HdChangeTracker::DirtyPrimvar) {
349 // Handle color/opacity specially, since they can be shadowed by
350 // material parameters. If we don't find them, check inherited
351 // primvars.
352 TfToken colorInterp;
353 VtValue color;
354 VtIntArray colorIndices(0);
355 if (GetColor(prim, time, &colorInterp, &color, &colorIndices)) {
356 _MergePrimvar(
357 &vPrimvars,
358 HdTokens->displayColor,
359 _UsdToHdInterpolation(colorInterp),
360 HdPrimvarRoleTokens->color,
361 !colorIndices.empty());
362 } else {
363 UsdGeomPrimvar pv =
364 _GetInheritedPrimvar(prim, HdTokens->displayColor);
365 if (pv) {
366 _ComputeAndMergePrimvar(prim, pv, time, &vPrimvars);
367 }
368 }
369
370 TfToken opacityInterp;
371 VtValue opacity;
372 VtIntArray opacityIndices(0);
373 if (GetOpacity(prim, time, &opacityInterp, &opacity, &opacityIndices)) {
374 _MergePrimvar(
375 &vPrimvars,
376 HdTokens->displayOpacity,
377 _UsdToHdInterpolation(opacityInterp),
378 TfToken(),
379 !opacityIndices.empty());
380 } else {
381 UsdGeomPrimvar pv =
382 _GetInheritedPrimvar(prim, HdTokens->displayOpacity);
383 if (pv) {
384 _ComputeAndMergePrimvar(prim, pv, time, &vPrimvars);
385 }
386 }
387
388 // Compile a list of primvars to check.
389 std::vector<UsdGeomPrimvar> primvars;
390 UsdImaging_InheritedPrimvarStrategy::value_type inheritedPrimvarRecord =
391 _GetInheritedPrimvars(prim.GetParent());
392 if (inheritedPrimvarRecord) {
393 primvars = inheritedPrimvarRecord->primvars;
394 }
395
396 UsdGeomPrimvarsAPI primvarsAPI(prim);
397 std::vector<UsdGeomPrimvar> local = primvarsAPI.GetPrimvarsWithValues();
398 primvars.insert(primvars.end(), local.begin(), local.end());
399
400 // Some backends may not want to load all primvars due to memory limits.
401 // We filter the list of primvars based on what the materials need.
402 TfTokenVector matPrimvarNames;
403 if (_IsPrimvarFilteringNeeded() && !materialUsdPaths.empty()) {
404 matPrimvarNames = _CollectMaterialPrimvars(materialUsdPaths, time);
405 }
406
407 for (auto const &pv : primvars) {
408 if (_IsBuiltinPrimvar(pv.GetPrimvarName())) {
409 continue;
410 }
411 if (_IsPrimvarFilteringNeeded() &&
412 std::find(matPrimvarNames.begin(),
413 matPrimvarNames.end(),
414 pv.GetPrimvarName()) == matPrimvarNames.end()) {
415 continue;
416 }
417
418 _ComputeAndMergePrimvar(prim, pv, time, &vPrimvars);
419 }
420 }
421 }
422
423 HdDirtyBits
ProcessPropertyChange(UsdPrim const & prim,SdfPath const & cachePath,TfToken const & propertyName)424 UsdImagingGprimAdapter::ProcessPropertyChange(UsdPrim const& prim,
425 SdfPath const& cachePath,
426 TfToken const& propertyName)
427 {
428 if (propertyName == UsdGeomTokens->visibility)
429 return HdChangeTracker::DirtyVisibility;
430
431 if (propertyName == UsdGeomTokens->purpose)
432 return HdChangeTracker::DirtyRenderTag;
433
434 if (UsdGeomXformable::IsTransformationAffectedByAttrNamed(propertyName))
435 return HdChangeTracker::DirtyTransform;
436
437 if (propertyName == UsdGeomTokens->extent)
438 return HdChangeTracker::DirtyExtent;
439
440 if (propertyName == UsdGeomTokens->doubleSided)
441 return HdChangeTracker::DirtyDoubleSided;
442
443 if (propertyName == UsdGeomTokens->velocities ||
444 propertyName == UsdGeomTokens->accelerations)
445 // XXX: "points" is handled by derived classes.
446 return HdChangeTracker::DirtyPoints;
447
448 if (UsdShadeMaterialBindingAPI::CanContainPropertyName(propertyName) ||
449 UsdCollectionAPI::CanContainPropertyName(propertyName)) {
450 return HdChangeTracker::DirtyMaterialId |
451 HdChangeTracker::DirtyPrimvar;
452 }
453
454 // Note: This doesn't handle "built-in" attributes that are treated as
455 // primvars. That responsibility falls on the child adapter.
456 if (UsdGeomPrimvarsAPI::CanContainPropertyName(propertyName)) {
457 return UsdImagingPrimAdapter::_ProcessPrefixedPrimvarPropertyChange(
458 prim, cachePath, propertyName);
459 }
460
461 return HdChangeTracker::Clean;
462 }
463
464 void
MarkDirty(UsdPrim const & prim,SdfPath const & cachePath,HdDirtyBits dirty,UsdImagingIndexProxy * index)465 UsdImagingGprimAdapter::MarkDirty(UsdPrim const& prim,
466 SdfPath const& cachePath,
467 HdDirtyBits dirty,
468 UsdImagingIndexProxy* index)
469 {
470 index->MarkRprimDirty(cachePath, dirty);
471 }
472
473 void
MarkRefineLevelDirty(UsdPrim const & prim,SdfPath const & cachePath,UsdImagingIndexProxy * index)474 UsdImagingGprimAdapter::MarkRefineLevelDirty(UsdPrim const& prim,
475 SdfPath const& cachePath,
476 UsdImagingIndexProxy* index)
477 {
478 index->MarkRprimDirty(cachePath, HdChangeTracker::DirtyDisplayStyle);
479 }
480
481 void
MarkReprDirty(UsdPrim const & prim,SdfPath const & cachePath,UsdImagingIndexProxy * index)482 UsdImagingGprimAdapter::MarkReprDirty(UsdPrim const& prim,
483 SdfPath const& cachePath,
484 UsdImagingIndexProxy* index)
485 {
486 index->MarkRprimDirty(cachePath, HdChangeTracker::DirtyRepr);
487 }
488
489 void
MarkCullStyleDirty(UsdPrim const & prim,SdfPath const & cachePath,UsdImagingIndexProxy * index)490 UsdImagingGprimAdapter::MarkCullStyleDirty(UsdPrim const& prim,
491 SdfPath const& cachePath,
492 UsdImagingIndexProxy* index)
493 {
494 index->MarkRprimDirty(cachePath, HdChangeTracker::DirtyCullStyle);
495 }
496
497 void
MarkRenderTagDirty(UsdPrim const & prim,SdfPath const & cachePath,UsdImagingIndexProxy * index)498 UsdImagingGprimAdapter::MarkRenderTagDirty(UsdPrim const& prim,
499 SdfPath const& cachePath,
500 UsdImagingIndexProxy* index)
501 {
502 index->MarkRprimDirty(cachePath, HdChangeTracker::DirtyRenderTag);
503 }
504
505 void
MarkTransformDirty(UsdPrim const & prim,SdfPath const & cachePath,UsdImagingIndexProxy * index)506 UsdImagingGprimAdapter::MarkTransformDirty(UsdPrim const& prim,
507 SdfPath const& cachePath,
508 UsdImagingIndexProxy* index)
509 {
510 index->MarkRprimDirty(cachePath, HdChangeTracker::DirtyTransform);
511 }
512
513 void
MarkVisibilityDirty(UsdPrim const & prim,SdfPath const & cachePath,UsdImagingIndexProxy * index)514 UsdImagingGprimAdapter::MarkVisibilityDirty(UsdPrim const& prim,
515 SdfPath const& cachePath,
516 UsdImagingIndexProxy* index)
517 {
518 index->MarkRprimDirty(cachePath, HdChangeTracker::DirtyVisibility);
519 }
520
521 void
MarkMaterialDirty(UsdPrim const & prim,SdfPath const & cachePath,UsdImagingIndexProxy * index)522 UsdImagingGprimAdapter::MarkMaterialDirty(UsdPrim const& prim,
523 SdfPath const& cachePath,
524 UsdImagingIndexProxy* index)
525 {
526 // If the Usd material changed, it could mean the primvar set also changed
527 // Hydra doesn't currently manage detection and propagation of these
528 // changes, so we must mark the rprim dirty.
529 index->MarkRprimDirty(cachePath, HdChangeTracker::DirtyMaterialId);
530 }
531
532 /*virtual*/
533 VtValue
GetPoints(UsdPrim const & prim,UsdTimeCode time) const534 UsdImagingGprimAdapter::GetPoints(UsdPrim const& prim,
535 UsdTimeCode time) const
536 {
537 HD_TRACE_FUNCTION();
538 HF_MALLOC_TAG_FUNCTION();
539
540 // Previously, we issued a warning if the points attribute wasn't
541 // authored, which resulted in a lot of logging.
542 // Handle it silently instead by returning an empty array.
543 return VtValue(_Get<VtVec3fArray>(prim, UsdGeomTokens->points, time));
544 }
545
546 /*virtual*/
547 GfRange3d
GetExtent(UsdPrim const & prim,SdfPath const & cachePath,UsdTimeCode time) const548 UsdImagingGprimAdapter::GetExtent(UsdPrim const& prim,
549 SdfPath const& cachePath,
550 UsdTimeCode time) const
551 {
552 HD_TRACE_FUNCTION();
553 HF_MALLOC_TAG_FUNCTION();
554 UsdGeomGprim gprim(prim);
555
556 if (!TF_VERIFY(gprim)) {
557 return GfRange3d();
558 }
559
560 VtVec3fArray extent;
561 if (gprim.GetExtentAttr().Get(&extent, time) && extent.size() == 2) {
562 // Note:
563 // Usd stores extent as 2 float vecs. We do an implicit
564 // conversion to doubles
565 return GfRange3d(extent[0], extent[1]);
566 } else {
567 // Return empty range if no value was found, or the wrong number of
568 // extent values were provided.
569 // Note: The default empty is [FLT_MAX,-FLT_MAX].
570 // TODO: Should this compute the extent based on the points instead?
571 return GfRange3d();
572 }
573 }
574
575 /*virtual*/
576 bool
GetDoubleSided(UsdPrim const & prim,SdfPath const & cachePath,UsdTimeCode time) const577 UsdImagingGprimAdapter::GetDoubleSided(UsdPrim const& prim,
578 SdfPath const& cachePath,
579 UsdTimeCode time) const
580 {
581 HD_TRACE_FUNCTION();
582 HF_MALLOC_TAG_FUNCTION();
583 UsdGeomGprim gprim(prim);
584
585 if (!TF_VERIFY(gprim)) {
586 return false;
587 }
588
589 bool doubleSided = false;
590 gprim.GetDoubleSidedAttr().Get(&doubleSided, time);
591 return doubleSided;
592 }
593
594 /*virtual*/
595 SdfPath
GetMaterialId(UsdPrim const & prim,SdfPath const & cachePath,UsdTimeCode time) const596 UsdImagingGprimAdapter::GetMaterialId(UsdPrim const& prim,
597 SdfPath const& cachePath,
598 UsdTimeCode time) const
599 {
600 return GetMaterialUsdPath(prim);
601 }
602
603 /*virtual*/
604 VtValue
Get(UsdPrim const & prim,SdfPath const & cachePath,TfToken const & key,UsdTimeCode time,VtIntArray * outIndices) const605 UsdImagingGprimAdapter::Get(UsdPrim const& prim,
606 SdfPath const& cachePath,
607 TfToken const& key,
608 UsdTimeCode time,
609 VtIntArray *outIndices) const
610 {
611 TRACE_FUNCTION();
612 HF_MALLOC_TAG_FUNCTION();
613
614 VtValue value;
615 UsdGeomGprim gprim(prim);
616 if (!TF_VERIFY(gprim)) {
617 return value;
618 }
619
620 if (key == HdTokens->displayColor) {
621 // First we try to obtain color from the prim,
622 // if not present, we try to get if through inheritance,
623 // and lastly, we use a fallback value.
624 TfToken interp;
625 if (GetColor(prim, time, &interp, &value, outIndices)) {
626 return value;
627 }
628
629 // Inheritance
630 UsdGeomPrimvar pv = _GetInheritedPrimvar(prim, HdTokens->displayColor);
631 if (outIndices) {
632 if (pv && pv.Get(&value, time)) {
633 pv.GetIndices(outIndices, time);
634 return value;
635 }
636 } else if (pv && pv.ComputeFlattened(&value, time)) {
637 return value;
638 }
639
640 // Fallback
641 VtVec3fArray vec(1, GfVec3f(.5,.5,.5));
642 value = vec;
643 return value;
644 } else if (key == HdTokens->displayOpacity) {
645 // First we try to obtain color from the prim,
646 // if not present, we try to get if through inheritance,
647 // and lastly, we use a fallback value.
648 TfToken interp;
649 if (GetOpacity(prim, time, &interp, &value, outIndices)) {
650 return value;
651 }
652
653 // Inheritance
654 UsdGeomPrimvar pv = _GetInheritedPrimvar(prim, HdTokens->displayOpacity);
655 if (outIndices) {
656 if (pv && pv.Get(&value, time)) {
657 pv.GetIndices(outIndices, time);
658 return value;
659 }
660 } else if (pv && pv.ComputeFlattened(&value, time)) {
661 return value;
662 }
663
664 // Fallback
665 VtFloatArray vec(1, 1.0f);
666 value = VtValue(vec);
667 return value;
668
669 } else if (key == HdTokens->normals) {
670 // Fallback
671 VtVec3fArray vec(1, GfVec3f(0,0,0));
672 value = VtValue(vec);
673 return value;
674
675 } else if (key == HdTokens->widths) {
676 // Fallback
677 VtFloatArray vec(1, 1.0f);
678 value = VtValue(vec);
679 return value;
680
681 } else if (key == HdTokens->points) {
682 return GetPoints(prim, time);
683
684 } else if (key == HdTokens->velocities) {
685 UsdGeomPointBased pointBased(prim);
686 VtVec3fArray velocities;
687 if (pointBased.GetVelocitiesAttr() &&
688 pointBased.GetVelocitiesAttr().Get(&velocities, time)) {
689 return VtValue(velocities);
690 }
691
692 } else if (key == HdTokens->accelerations) {
693 // Acceleration information is expected to be authored @ the same sample
694 // rate as points data, so use the points dirty bit to let us know when
695 // to publish accelerations.
696 UsdGeomPointBased pointBased(prim);
697 VtVec3fArray accelerations;
698 if (pointBased.GetAccelerationsAttr() &&
699 pointBased.GetAccelerationsAttr().Get(&accelerations, time)) {
700 return VtValue(accelerations);
701 }
702
703 } else if (UsdGeomPrimvar pv = gprim.GetPrimvar(key)) {
704 if (outIndices) {
705 if (pv && pv.Get(&value, time)) {
706 pv.GetIndices(outIndices, time);
707 return value;
708 }
709 } else if (pv && pv.ComputeFlattened(&value, time)) {
710 return value;
711 }
712 } else if (UsdGeomPrimvar pv = _GetInheritedPrimvar(prim, key)) {
713 if (outIndices) {
714 if (pv && pv.Get(&value, time)) {
715 pv.GetIndices(outIndices, time);
716 return value;
717 }
718 } else if (pv && pv.ComputeFlattened(&value, time)) {
719 return value;
720 }
721 }
722
723 return BaseAdapter::Get(prim, cachePath, key, time, outIndices);
724 }
725
726 // -------------------------------------------------------------------------- //
727
728 /* static */
729 bool
GetColor(UsdPrim const & prim,UsdTimeCode time,TfToken * interpolation,VtValue * color,VtIntArray * indices)730 UsdImagingGprimAdapter::GetColor(UsdPrim const& prim,
731 UsdTimeCode time,
732 TfToken* interpolation,
733 VtValue* color,
734 VtIntArray *indices)
735 {
736 TRACE_FUNCTION();
737 HF_MALLOC_TAG_FUNCTION();
738
739 VtVec3fArray result(1, GfVec3f(0.5f));
740 VtIntArray colorIndices(0);
741 TfToken colorInterp;
742 bool hasAuthoredColor = false;
743
744 // for a prim's color we use the following precedence:
745 // material rel > local prim var(s)
746 {
747 // -- Material --
748 // XXX: Primvar values that come from shaders should not be part of
749 // the Rprim data, it should live as part of the shader so it can be
750 // shared, though that poses some interesting questions for vertex &
751 // varying rate shader provided primvars.
752 UsdRelationship mat =
753 UsdShadeMaterialBindingAPI(prim).GetDirectBindingRel();
754 SdfPathVector matTargets;
755 if (mat.GetForwardedTargets(&matTargets)) {
756 if (!matTargets.empty()) {
757 if (matTargets.size() > 1) {
758 TF_WARN("<%s> has more than one material target; "\
759 "using first one found: <%s>",
760 prim.GetPath().GetText(),
761 matTargets.front().GetText());
762 }
763 UsdPrim matPrim(
764 prim.GetStage()->GetPrimAtPath(matTargets.front()));
765
766 if (matPrim &&
767 matPrim.GetAttribute(HdTokens->displayColor)
768 .Get(&result[0], time)) {
769 colorInterp = UsdGeomTokens->constant;
770 hasAuthoredColor = true;
771 }
772 }
773 }
774 }
775
776 {
777 // -- Prim local prim var --
778 if (!hasAuthoredColor) { // did not get color from material
779 UsdGeomGprim gprimSchema(prim);
780 const UsdGeomPrimvar& primvar =
781 gprimSchema.GetDisplayColorPrimvar();
782 colorInterp = primvar.GetInterpolation();
783
784 if (indices) {
785 if (primvar.Get(&result, time)) {
786 hasAuthoredColor = true;
787 primvar.GetIndices(&colorIndices, time);
788
789 if (colorInterp == UsdGeomTokens->constant &&
790 result.size() > 1) {
791 TF_WARN("Prim %s has %lu element(s) for %s even "
792 "though it is marked constant.",
793 prim.GetPath().GetText(), result.size(),
794 primvar.GetName().GetText());
795 result.resize(1);
796 colorIndices = VtIntArray(1, 0);
797 }
798 }
799 } else if (primvar.ComputeFlattened(&result, time)) {
800 hasAuthoredColor = true;
801
802 if (colorInterp == UsdGeomTokens->constant &&
803 result.size() > 1) {
804 TF_WARN("Prim %s has %lu element(s) for %s even "
805 "though it is marked constant.",
806 prim.GetPath().GetText(), result.size(),
807 primvar.GetName().GetText());
808 result.resize(1);
809 }
810 } else if (primvar.HasAuthoredValue()) {
811 // If the primvar exists and ComputeFlattened returns false,
812 // the value authored is None, in which case, we return an empty
813 // array.
814 hasAuthoredColor = true;
815 result = VtVec3fArray();
816 } else {
817 // All UsdGeomPointBased prims have the displayColor primvar
818 // by default. Suppress unauthored ones from being
819 // published to the backend.
820 }
821 }
822 }
823
824 if (!hasAuthoredColor) {
825 return false;
826 }
827
828 if (interpolation) {
829 *interpolation = colorInterp;
830 }
831 if (indices) {
832 *indices = colorIndices;
833 }
834 if (color) {
835 *color = VtValue(result);
836 }
837
838 return true;
839 }
840
841 /* static */
842 bool
GetOpacity(UsdPrim const & prim,UsdTimeCode time,TfToken * interpolation,VtValue * opacity,VtIntArray * indices)843 UsdImagingGprimAdapter::GetOpacity(UsdPrim const& prim,
844 UsdTimeCode time,
845 TfToken* interpolation,
846 VtValue* opacity,
847 VtIntArray *indices)
848 {
849 HD_TRACE_FUNCTION();
850 HF_MALLOC_TAG_FUNCTION();
851
852 VtFloatArray result(1, 1.0f);
853 VtIntArray opacityIndices(0);
854 TfToken opacityInterp;
855 bool hasAuthoredOpacity = false;
856
857 // for a prim's opacity, we use the following precedence:
858 // material rel > local prim var(s)
859 {
860 // -- Material --
861 // XXX: Primvar values that come from shaders should not be part of
862 // the Rprim data, it should live as part of the shader so it can be
863 // shared, though that poses some interesting questions for vertex &
864 // varying rate shader provided primvars.
865 UsdRelationship mat =
866 UsdShadeMaterialBindingAPI(prim).GetDirectBindingRel();
867 SdfPathVector matTargets;
868 if (mat.GetForwardedTargets(&matTargets)) {
869 if (!matTargets.empty()) {
870 if (matTargets.size() > 1) {
871 TF_WARN("<%s> has more than one material target; "\
872 "using first one found: <%s>",
873 prim.GetPath().GetText(),
874 matTargets.front().GetText());
875 }
876 UsdPrim matPrim(
877 prim.GetStage()->GetPrimAtPath(matTargets.front()));
878
879 if (matPrim &&
880 matPrim.GetAttribute(HdTokens->displayOpacity)
881 .Get(&result[0], time)) {
882 opacityInterp = UsdGeomTokens->constant;
883 hasAuthoredOpacity = true;
884 }
885 }
886 }
887 }
888
889 {
890 // -- Prim local prim var --
891 if (!hasAuthoredOpacity) { // did not get opacity from material
892 UsdGeomGprim gprimSchema(prim);
893 const UsdGeomPrimvar& primvar =
894 gprimSchema.GetDisplayOpacityPrimvar();
895 opacityInterp = primvar.GetInterpolation();
896
897 if (indices) {
898 if (primvar.Get(&result, time)) {
899 hasAuthoredOpacity = true;
900 primvar.GetIndices(&opacityIndices, time);
901
902 if (opacityInterp == UsdGeomTokens->constant &&
903 result.size() > 1) {
904 TF_WARN("Prim %s has %lu element(s) for %s even "
905 "though it is marked constant.",
906 prim.GetPath().GetText(), result.size(),
907 primvar.GetName().GetText());
908 result.resize(1);
909 opacityIndices = VtIntArray(1, 0);
910 }
911 }
912 } else if (primvar.ComputeFlattened(&result, time)) {
913 hasAuthoredOpacity = true;
914
915 if (opacityInterp == UsdGeomTokens->constant &&
916 result.size() > 1) {
917 TF_WARN("Prim %s has %lu element(s) for %s even "
918 "though it is marked constant.",
919 prim.GetPath().GetText(), result.size(),
920 primvar.GetName().GetText());
921 result.resize(1);
922 }
923 } else if (primvar.HasAuthoredValue()) {
924 // If the primvar exists and ComputeFlattened returns false,
925 // the value authored is None, in which case, we return an empty
926 // array,
927 hasAuthoredOpacity = true;
928 result = VtFloatArray();
929 } else {
930 // All UsdGeomPointBased prims have the displayOpacity primvar
931 // by default. Suppress unauthored ones from being
932 // published to the backend.
933 }
934 }
935 }
936
937 if (!hasAuthoredOpacity) {
938 return false;
939 }
940
941 if (interpolation) {
942 *interpolation = opacityInterp;
943 }
944 if (indices) {
945 *indices = opacityIndices;
946 }
947 if (opacity) {
948 *opacity = VtValue(result);
949 }
950 return true;
951 }
952
953 UsdGeomPrimvar
_GetInheritedPrimvar(UsdPrim const & prim,TfToken const & primvarName) const954 UsdImagingGprimAdapter::_GetInheritedPrimvar(UsdPrim const& prim,
955 TfToken const& primvarName) const
956 {
957 UsdImaging_InheritedPrimvarStrategy::value_type inheritedPrimvarRecord =
958 _GetInheritedPrimvars(prim.GetParent());
959 if (inheritedPrimvarRecord) {
960 for (UsdGeomPrimvar const& pv : inheritedPrimvarRecord->primvars) {
961 if (pv.GetPrimvarName() == primvarName) {
962 return pv;
963 }
964 }
965 }
966 return UsdGeomPrimvar();
967 }
968
969 TfTokenVector
_CollectMaterialPrimvars(SdfPathVector const & materialUsdPaths,UsdTimeCode time) const970 UsdImagingGprimAdapter::_CollectMaterialPrimvars(
971 SdfPathVector const& materialUsdPaths,
972 UsdTimeCode time) const
973 {
974 TfTokenVector primvars;
975
976 for (SdfPath const& materialUsdPath : materialUsdPaths) {
977 if (UsdPrim matPrim = _GetPrim(materialUsdPath)) {
978 // NOTE: We need to directly access the registered instance
979 // of UsdImagingMaterialAdapter in order to query its
980 // material resource. Those are registered to match
981 // the USD prim type name.
982 if (UsdImagingPrimAdapterSharedPtr materialAdapter
983 =_GetAdapter(matPrim.GetTypeName())) {
984 VtValue vtMaterial = materialAdapter->GetMaterialResource(
985 matPrim, matPrim.GetPath(), time);
986 TfTokenVector pvNames = _GetPrimvarsForMaterial(vtMaterial);
987 primvars.insert(primvars.end(), pvNames.begin(),
988 pvNames.end());
989 }
990 }
991 }
992
993 std::sort(primvars.begin(), primvars.end());
994 primvars.erase(std::unique(primvars.begin(), primvars.end()),
995 primvars.end());
996
997 return primvars;
998 }
999
1000 PXR_NAMESPACE_CLOSE_SCOPE
1001
1002