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