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/meshAdapter.h"
25 
26 #include "pxr/usdImaging/usdImaging/debugCodes.h"
27 #include "pxr/usdImaging/usdImaging/delegate.h"
28 #include "pxr/usdImaging/usdImaging/indexProxy.h"
29 #include "pxr/usdImaging/usdImaging/tokens.h"
30 
31 #include "pxr/imaging/hd/mesh.h"
32 #include "pxr/imaging/hd/geomSubset.h"
33 #include "pxr/imaging/hd/perfLog.h"
34 
35 #include "pxr/imaging/pxOsd/meshTopology.h"
36 #include "pxr/imaging/pxOsd/tokens.h"
37 
38 #include "pxr/usd/usdGeom/mesh.h"
39 #include "pxr/usd/usdGeom/primvarsAPI.h"
40 #include "pxr/usd/usdGeom/subset.h"
41 #include "pxr/usd/usdGeom/xformCache.h"
42 
43 #include "pxr/base/tf/type.h"
44 
45 PXR_NAMESPACE_OPEN_SCOPE
46 
47 
TF_REGISTRY_FUNCTION(TfType)48 TF_REGISTRY_FUNCTION(TfType)
49 {
50     typedef UsdImagingMeshAdapter Adapter;
51     TfType t = TfType::Define<Adapter, TfType::Bases<Adapter::BaseAdapter> >();
52     t.SetFactory< UsdImagingPrimAdapterFactory<Adapter> >();
53 }
54 
~UsdImagingMeshAdapter()55 UsdImagingMeshAdapter::~UsdImagingMeshAdapter()
56 {
57 }
58 
59 bool
IsSupported(UsdImagingIndexProxy const * index) const60 UsdImagingMeshAdapter::IsSupported(UsdImagingIndexProxy const* index) const
61 {
62     return index->IsRprimTypeSupported(HdPrimTypeTokens->mesh);
63 }
64 
65 SdfPath
Populate(UsdPrim const & prim,UsdImagingIndexProxy * index,UsdImagingInstancerContext const * instancerContext)66 UsdImagingMeshAdapter::Populate(UsdPrim const& prim,
67                             UsdImagingIndexProxy* index,
68                             UsdImagingInstancerContext const* instancerContext)
69 {
70     SdfPath cachePath = _AddRprim(HdPrimTypeTokens->mesh, prim, index,
71                                   GetMaterialUsdPath(prim), instancerContext);
72 
73     // Check for any UsdGeomSubset children of familyType
74     // UsdShadeTokens->materialBind and record dependencies for them.
75     for (const UsdGeomSubset &subset:
76          UsdShadeMaterialBindingAPI(prim).GetMaterialBindSubsets()) {
77         index->AddDependency(cachePath, subset.GetPrim());
78 
79         // Ensure the bound material has been populated.
80         UsdPrim materialPrim = prim.GetStage()->GetPrimAtPath(
81                 GetMaterialUsdPath(subset.GetPrim()));
82         if (materialPrim) {
83             UsdImagingPrimAdapterSharedPtr materialAdapter =
84                 index->GetMaterialAdapter(materialPrim);
85             if (materialAdapter) {
86                 materialAdapter->Populate(materialPrim, index, nullptr);
87             }
88         }
89     }
90 
91     return cachePath;
92 }
93 
94 
95 void
TrackVariability(UsdPrim const & prim,SdfPath const & cachePath,HdDirtyBits * timeVaryingBits,UsdImagingInstancerContext const * instancerContext) const96 UsdImagingMeshAdapter::TrackVariability(UsdPrim const& prim,
97                                         SdfPath const& cachePath,
98                                         HdDirtyBits* timeVaryingBits,
99                                         UsdImagingInstancerContext const*
100                                             instancerContext) const
101 {
102     BaseAdapter::TrackVariability(
103         prim, cachePath, timeVaryingBits, instancerContext);
104 
105     // WARNING: This method is executed from multiple threads, the value cache
106     // has been carefully pre-populated to avoid mutating the underlying
107     // container during update.
108 
109     // Discover time-varying points.
110     _IsVarying(prim,
111                UsdGeomTokens->points,
112                HdChangeTracker::DirtyPoints,
113                UsdImagingTokens->usdVaryingPrimvar,
114                timeVaryingBits,
115                /*isInherited*/false);
116 
117     // Discover time-varying primvars:normals, and if that attribute
118     // doesn't exist also check for time-varying normals.
119     // Only do this for polygonal meshes.
120 
121     TfToken schemeToken;
122     _GetPtr(prim, UsdGeomTokens->subdivisionScheme,
123             UsdTimeCode::EarliestTime(), &schemeToken);
124 
125     if (schemeToken == PxOsdOpenSubdivTokens->none) {
126         bool normalsExists = false;
127         _IsVarying(prim,
128                 UsdImagingTokens->primvarsNormals,
129                 HdChangeTracker::DirtyNormals,
130                 UsdImagingTokens->usdVaryingNormals,
131                 timeVaryingBits,
132                 /*isInherited*/false,
133                 &normalsExists);
134         if (!normalsExists) {
135             UsdGeomPrimvar pv = _GetInheritedPrimvar(prim, HdTokens->normals);
136             if (pv && pv.ValueMightBeTimeVarying()) {
137                 *timeVaryingBits |= HdChangeTracker::DirtyNormals;
138                 HD_PERF_COUNTER_INCR(UsdImagingTokens->usdVaryingNormals);
139                 normalsExists = true;
140             }
141         }
142         if (!normalsExists) {
143             _IsVarying(prim,
144                     UsdGeomTokens->normals,
145                     HdChangeTracker::DirtyNormals,
146                     UsdImagingTokens->usdVaryingNormals,
147                     timeVaryingBits,
148                     /*isInherited*/false);
149         }
150     }
151 
152     // Discover time-varying topology.
153     if (!_IsVarying(prim,
154                        UsdGeomTokens->faceVertexCounts,
155                        HdChangeTracker::DirtyTopology,
156                        UsdImagingTokens->usdVaryingTopology,
157                        timeVaryingBits,
158                        /*isInherited*/false)) {
159         // Only do this check if the faceVertexCounts is not already known
160         // to be varying.
161         if (!_IsVarying(prim,
162                            UsdGeomTokens->faceVertexIndices,
163                            HdChangeTracker::DirtyTopology,
164                            UsdImagingTokens->usdVaryingTopology,
165                            timeVaryingBits,
166                            /*isInherited*/false)) {
167             // Only do this check if both faceVertexCounts and
168             // faceVertexIndices are not known to be varying.
169             _IsVarying(prim,
170                        UsdGeomTokens->holeIndices,
171                        HdChangeTracker::DirtyTopology,
172                        UsdImagingTokens->usdVaryingTopology,
173                        timeVaryingBits,
174                        /*isInherited*/false);
175         }
176     }
177 
178     // Discover time-varying UsdGeomSubset children, which indicates that the
179     // topology must be treated as time varying. Only do these checks until
180     // we determine the topology is time varying, because each call to
181     // _IsVarying will clear the topology dirty bit if it's already set.
182     if (((*timeVaryingBits) & HdChangeTracker::DirtyTopology) == 0) {
183         for (const UsdGeomSubset &subset:
184              UsdShadeMaterialBindingAPI(prim).GetMaterialBindSubsets()) {
185 
186             // If the topology dirty flag is already set, exit the loop.
187             if (((*timeVaryingBits) & HdChangeTracker::DirtyTopology) != 0){
188                 break;
189             }
190 
191             if (!_IsVarying(subset.GetPrim(),
192                             UsdGeomTokens->elementType,
193                             HdChangeTracker::DirtyTopology,
194                             UsdImagingTokens->usdVaryingPrimvar,
195                             timeVaryingBits,
196                             /*isInherited*/false)) {
197                 // Only do this check if the elementType is not already
198                 // known to be varying.
199                 _IsVarying(subset.GetPrim(),
200                            UsdGeomTokens->indices,
201                            HdChangeTracker::DirtyTopology,
202                            UsdImagingTokens->usdVaryingPrimvar,
203                            timeVaryingBits,
204                            /*isInherited*/false);
205             }
206         }
207     }
208 }
209 
210 bool
_IsBuiltinPrimvar(TfToken const & primvarName) const211 UsdImagingMeshAdapter::_IsBuiltinPrimvar(TfToken const& primvarName) const
212 {
213     return (primvarName == HdTokens->normals) ||
214         UsdImagingGprimAdapter::_IsBuiltinPrimvar(primvarName);
215 }
216 
217 void
UpdateForTime(UsdPrim const & prim,SdfPath const & cachePath,UsdTimeCode time,HdDirtyBits requestedBits,UsdImagingInstancerContext const * instancerContext) const218 UsdImagingMeshAdapter::UpdateForTime(UsdPrim const& prim,
219                                      SdfPath const& cachePath,
220                                      UsdTimeCode time,
221                                      HdDirtyBits requestedBits,
222                                      UsdImagingInstancerContext const*
223                                          instancerContext) const
224 {
225     TF_DEBUG(USDIMAGING_CHANGES).Msg("[UpdateForTime] Mesh path: <%s>\n",
226                                      prim.GetPath().GetText());
227 
228     BaseAdapter::UpdateForTime(
229         prim, cachePath, time, requestedBits, instancerContext);
230 
231     if (requestedBits & HdChangeTracker::DirtyNormals) {
232         UsdImagingPrimvarDescCache* primvarDescCache = _GetPrimvarDescCache();
233         HdPrimvarDescriptorVector& primvars =
234             primvarDescCache->GetPrimvars(cachePath);
235 
236         TfToken schemeToken;
237         _GetPtr(prim, UsdGeomTokens->subdivisionScheme, time, &schemeToken);
238         // Only populate normals for polygonal meshes.
239         if (schemeToken == PxOsdOpenSubdivTokens->none) {
240             // First check for "primvars:normals"
241             UsdGeomPrimvarsAPI primvarsApi(prim);
242             UsdGeomPrimvar pv = primvarsApi.GetPrimvar(
243                     UsdImagingTokens->primvarsNormals);
244             if (!pv) {
245                 // If it's not found locally, see if it's inherited
246                 pv = _GetInheritedPrimvar(prim, HdTokens->normals);
247             }
248 
249             if (pv) {
250                 _ComputeAndMergePrimvar(prim, pv, time, &primvars);
251             } else {
252                 UsdGeomMesh mesh(prim);
253                 VtVec3fArray normals;
254                 if (mesh.GetNormalsAttr().Get(&normals, time)) {
255                     _MergePrimvar(&primvars,
256                         UsdGeomTokens->normals,
257                         _UsdToHdInterpolation(mesh.GetNormalsInterpolation()),
258                         HdPrimvarRoleTokens->normal);
259                 } else {
260                     _RemovePrimvar(&primvars, UsdGeomTokens->normals);
261                 }
262             }
263         }
264     }
265 }
266 
267 HdDirtyBits
ProcessPropertyChange(UsdPrim const & prim,SdfPath const & cachePath,TfToken const & propertyName)268 UsdImagingMeshAdapter::ProcessPropertyChange(UsdPrim const& prim,
269                                              SdfPath const& cachePath,
270                                              TfToken const& propertyName)
271 {
272     if(propertyName == UsdGeomTokens->points)
273         return HdChangeTracker::DirtyPoints;
274 
275     // Check for UsdGeomSubset changes.
276     // XXX: Verify that this is being called on a GeomSubset prim?
277     if (propertyName == UsdGeomTokens->elementType ||
278         propertyName == UsdGeomTokens->indices) {
279         return HdChangeTracker::DirtyTopology;
280     }
281 
282     if (propertyName == UsdGeomTokens->subdivisionScheme) {
283         // (Note that a change in subdivision scheme means we need to re-track
284         // the variability of the normals...)
285         return HdChangeTracker::DirtyTopology | HdChangeTracker::DirtyNormals;
286     }
287 
288     if (propertyName == UsdGeomTokens->faceVertexCounts ||
289         propertyName == UsdGeomTokens->faceVertexIndices ||
290         propertyName == UsdGeomTokens->holeIndices ||
291         propertyName == UsdGeomTokens->orientation) {
292         return HdChangeTracker::DirtyTopology;
293     }
294 
295     if (propertyName == UsdGeomTokens->interpolateBoundary ||
296         propertyName == UsdGeomTokens->faceVaryingLinearInterpolation ||
297         propertyName == UsdGeomTokens->triangleSubdivisionRule ||
298         propertyName == UsdGeomTokens->creaseIndices ||
299         propertyName == UsdGeomTokens->creaseLengths ||
300         propertyName == UsdGeomTokens->creaseSharpnesses ||
301         propertyName == UsdGeomTokens->cornerIndices ||
302         propertyName == UsdGeomTokens->cornerSharpnesses) {
303         // XXX UsdGeomTokens->creaseMethod, when we add support for that.
304         return HdChangeTracker::DirtySubdivTags;
305     }
306 
307     if (propertyName == UsdGeomTokens->normals) {
308         UsdGeomPointBased pb(prim);
309         return UsdImagingPrimAdapter::_ProcessNonPrefixedPrimvarPropertyChange(
310             prim, cachePath, propertyName, HdTokens->normals,
311             _UsdToHdInterpolation(pb.GetNormalsInterpolation()),
312             HdChangeTracker::DirtyNormals);
313     }
314     if (propertyName == UsdImagingTokens->primvarsNormals) {
315         return UsdImagingPrimAdapter::_ProcessPrefixedPrimvarPropertyChange(
316                 prim, cachePath, propertyName, HdChangeTracker::DirtyNormals);
317     }
318 
319     // Handle attributes that are treated as "built-in" primvars.
320     if (propertyName == UsdGeomTokens->normals) {
321         UsdGeomMesh mesh(prim);
322         return UsdImagingPrimAdapter::_ProcessNonPrefixedPrimvarPropertyChange(
323             prim, cachePath, propertyName, HdTokens->normals,
324             _UsdToHdInterpolation(mesh.GetNormalsInterpolation()),
325             HdChangeTracker::DirtyNormals);
326     }
327     // Handle prefixed primvars that use special dirty bits.
328     else if (propertyName == UsdImagingTokens->primvarsNormals) {
329         return UsdImagingPrimAdapter::_ProcessPrefixedPrimvarPropertyChange(
330                 prim, cachePath, propertyName, HdChangeTracker::DirtyNormals);
331     }
332 
333     // Allow base class to handle change processing.
334     return BaseAdapter::ProcessPropertyChange(prim, cachePath, propertyName);
335 }
336 
337 /*virtual*/
338 VtValue
GetTopology(UsdPrim const & prim,SdfPath const & cachePath,UsdTimeCode time) const339 UsdImagingMeshAdapter::GetTopology(UsdPrim const& prim,
340                                    SdfPath const& cachePath,
341                                    UsdTimeCode time) const
342 {
343     TRACE_FUNCTION();
344     HF_MALLOC_TAG_FUNCTION();
345 
346     TfToken schemeToken;
347     _GetPtr(prim, UsdGeomTokens->subdivisionScheme, time, &schemeToken);
348 
349     HdMeshTopology meshTopo(
350         schemeToken,
351         _Get<TfToken>(prim, UsdGeomTokens->orientation, time),
352         _Get<VtIntArray>(prim, UsdGeomTokens->faceVertexCounts, time),
353         _Get<VtIntArray>(prim, UsdGeomTokens->faceVertexIndices, time),
354         _Get<VtIntArray>(prim, UsdGeomTokens->holeIndices, time));
355 
356     // Convert UsdGeomSubsets to HdGeomSubsets.
357     HdGeomSubsets geomSubsets;
358     for (const UsdGeomSubset &subset:
359          UsdShadeMaterialBindingAPI(prim).GetMaterialBindSubsets()) {
360         VtIntArray indices;
361         TfToken elementType;
362         if (subset.GetElementTypeAttr().Get(&elementType) &&
363             subset.GetIndicesAttr().Get(&indices, time)) {
364             if (elementType == UsdGeomTokens->face) {
365                 geomSubsets.emplace_back(
366                    HdGeomSubset {
367                        HdGeomSubset::TypeFaceSet,
368                        subset.GetPath(),
369                        GetMaterialUsdPath(subset.GetPrim()),
370                        indices });
371             }
372         }
373     }
374     if (!geomSubsets.empty()) {
375         meshTopo.SetGeomSubsets(geomSubsets);
376     }
377 
378     return VtValue(meshTopo);
379 }
380 
381 PxOsdSubdivTags
GetSubdivTags(UsdPrim const & prim,SdfPath const & cachePath,UsdTimeCode time) const382 UsdImagingMeshAdapter::GetSubdivTags(UsdPrim const& prim,
383                                      SdfPath const& cachePath,
384                                      UsdTimeCode time) const
385 {
386     HD_TRACE_FUNCTION();
387     HF_MALLOC_TAG_FUNCTION();
388 
389     PxOsdSubdivTags tags;
390 
391     if(!prim.IsA<UsdGeomMesh>()) {
392         return tags;
393     }
394 
395     TfToken interpolationRule =
396         _Get<TfToken>(prim, UsdGeomTokens->interpolateBoundary, time);
397     if (interpolationRule.IsEmpty()) {
398         interpolationRule = UsdGeomTokens->edgeAndCorner;
399     }
400     tags.SetVertexInterpolationRule(interpolationRule);
401 
402     TfToken faceVaryingRule = _Get<TfToken>(
403         prim, UsdGeomTokens->faceVaryingLinearInterpolation, time);
404     if (faceVaryingRule.IsEmpty()) {
405         faceVaryingRule = UsdGeomTokens->cornersPlus1;
406     }
407     tags.SetFaceVaryingInterpolationRule(faceVaryingRule);
408 
409     // XXX uncomment after fixing USD schema
410     // TfToken creaseMethod =
411     //     _Get<TfToken>(prim, UsdGeomTokens->creaseMethod, time);
412     // tags->SetCreaseMethod(creaseMethod);
413 
414     TfToken triangleRule =
415         _Get<TfToken>(prim, UsdGeomTokens->triangleSubdivisionRule, time);
416     if (triangleRule.IsEmpty()) {
417         triangleRule = UsdGeomTokens->catmullClark;
418     }
419     tags.SetTriangleSubdivision(triangleRule);
420 
421     VtIntArray creaseIndices =
422         _Get<VtIntArray>(prim, UsdGeomTokens->creaseIndices, time);
423     tags.SetCreaseIndices(creaseIndices);
424 
425     VtIntArray creaseLengths =
426         _Get<VtIntArray>(prim, UsdGeomTokens->creaseLengths, time);
427     tags.SetCreaseLengths(creaseLengths);
428 
429     VtFloatArray creaseSharpnesses =
430         _Get<VtFloatArray>(prim, UsdGeomTokens->creaseSharpnesses, time);
431     tags.SetCreaseWeights(creaseSharpnesses);
432 
433     VtIntArray cornerIndices =
434         _Get<VtIntArray>(prim, UsdGeomTokens->cornerIndices, time);
435     tags.SetCornerIndices(cornerIndices);
436 
437     VtFloatArray cornerSharpnesses =
438         _Get<VtFloatArray>(prim, UsdGeomTokens->cornerSharpnesses, time);
439     tags.SetCornerWeights(cornerSharpnesses);
440 
441     return tags;
442 }
443 
444 /*virtual*/
445 VtValue
Get(UsdPrim const & prim,SdfPath const & cachePath,TfToken const & key,UsdTimeCode time,VtIntArray * outIndices) const446 UsdImagingMeshAdapter::Get(UsdPrim const& prim,
447                            SdfPath const& cachePath,
448                            TfToken const &key,
449                            UsdTimeCode time,
450                            VtIntArray *outIndices) const
451 {
452     TRACE_FUNCTION();
453     HF_MALLOC_TAG_FUNCTION();
454 
455     if (key == HdTokens->normals) {
456         TfToken schemeToken;
457         _GetPtr(prim, UsdGeomTokens->subdivisionScheme, time, &schemeToken);
458 
459         // Only populate normals for polygonal meshes.
460         if (schemeToken == PxOsdOpenSubdivTokens->none) {
461             // First check for "primvars:normals"
462             UsdGeomPrimvarsAPI primvarsApi(prim);
463             UsdGeomPrimvar pv = primvarsApi.GetPrimvar(
464                     UsdImagingTokens->primvarsNormals);
465             if (!pv) {
466                 // If it's not found locally, see if it's inherited
467                 pv = _GetInheritedPrimvar(prim, HdTokens->normals);
468             }
469 
470             VtValue value;
471 
472             if (outIndices) {
473                 if (pv && pv.Get(&value, time)) {
474                     pv.GetIndices(outIndices, time);
475                     return value;
476                 }
477             } else if (pv && pv.ComputeFlattened(&value, time)) {
478                 return value;
479             }
480 
481             // If there's no "primvars:normals",
482             // fall back to UsdGeomMesh's "normals" attribute.
483             UsdGeomMesh mesh(prim);
484             VtVec3fArray normals;
485             if (mesh && mesh.GetNormalsAttr().Get(&normals, time)) {
486                 value = normals;
487                 return value;
488             }
489         }
490     }
491 
492     return BaseAdapter::Get(prim, cachePath, key, time, outIndices);
493 }
494 
495 PXR_NAMESPACE_CLOSE_SCOPE
496