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