Loading...
Searching...
No Matches
gprim.h
1//
2// Copyright 2019 Pixar
3//
4// Licensed under the terms set forth in the LICENSE.txt file available at
5// https://openusd.org/license.
6//
7#ifndef EXT_RMANPKG_PLUGIN_RENDERMAN_PLUGIN_HD_PRMAN_GPRIM_H
8#define EXT_RMANPKG_PLUGIN_RENDERMAN_PLUGIN_HD_PRMAN_GPRIM_H
9
10#include "pxr/pxr.h"
11#include "pxr/imaging/hd/version.h"
12#include "pxr/usd/sdf/types.h"
14
15#include "hdPrman/gprimbase.h"
16#include "hdPrman/idMap.h"
17#include "hdPrman/renderParam.h"
18#include "hdPrman/instancer.h"
19#include "hdPrman/material.h"
20#include "hdPrman/rixStrings.h"
21#include "hdPrman/utils.h"
22
23#include "Riley.h"
24
25PXR_NAMESPACE_OPEN_SCOPE
26
29template <typename BASE>
30class HdPrman_Gprim : public BASE, public HdPrman_GprimBase
31{
32public:
33 using BaseType = BASE;
34
35 HdPrman_Gprim(SdfPath const& id)
36 : BaseType(id)
37 {
38 }
39
40 ~HdPrman_Gprim() override = default;
41
42 void
43 Finalize(HdRenderParam *renderParam) override
44 {
45 HdPrman_RenderParam *param =
46 static_cast<HdPrman_RenderParam*>(renderParam);
47 const SdfPath& id = BASE::GetId();
48 riley::Riley *riley = param->AcquireRiley();
49 if (!riley) {
50 return;
51 }
52
53 // Release retained conversions of coordSys bindings.
54 param->ReleaseCoordSysBindings(id);
55
56 // Delete instances before deleting the prototypes they use.
57 for (const auto &instId: _instanceIds) {
58 if (instId != riley::GeometryInstanceId::InvalidId()) {
59 riley->DeleteGeometryInstance(
60 riley::GeometryPrototypeId::InvalidId(), instId);
61 }
62 }
63 _instanceIds.clear();
64
65 // delete instances owned by the instancer.
66 if (HdPrmanInstancer* instancer = param->GetInstancer(
67 BASE::GetInstancerId())) {
68 instancer->Depopulate(renderParam, id);
69 }
70
71 for (const auto &protoId: _prototypeIds) {
72 if (protoId != riley::GeometryPrototypeId::InvalidId()) {
73 riley->DeleteGeometryPrototype(protoId);
74 }
75 }
76 _prototypeIds.clear();
77 }
78
79 void Sync(HdSceneDelegate* sceneDelegate,
80 HdRenderParam* renderParam,
81 HdDirtyBits* dirtyBits,
82 TfToken const &reprToken) override;
83
84protected:
85 HdDirtyBits GetInitialDirtyBitsMask() const override = 0;
86
87 HdDirtyBits
88 _PropagateDirtyBits(HdDirtyBits bits) const override
89 {
90 // By default, just return the same dirty bits we recieved.
91 return bits;
92 }
93
94 void
95 _InitRepr(TfToken const &reprToken,
96 HdDirtyBits *dirtyBits) override
97 {
98 TF_UNUSED(reprToken);
99 TF_UNUSED(dirtyBits);
100 // No-op
101 }
102
103 // We override this member function in mesh.cpp to support the creation
104 // of mesh light prototype geometry.
105 virtual bool
106 _PrototypeOnly()
107 {
108 return false;
109 }
110
111 // Provide a fallback material. Default grabs _fallbackMaterial
112 // from the context.
113 virtual riley::MaterialId
114 _GetFallbackMaterial(HdPrman_RenderParam *renderParam)
115 {
116 return renderParam->GetFallbackMaterialId();
117 }
118
119 // Populate primType, primvars, and geometry subsets.
120 // Returns true if successful.
121 virtual bool
122 _ConvertGeometry(
123 HdPrman_RenderParam *renderParam,
124 HdSceneDelegate *sceneDelegate,
125 const SdfPath &id,
126 RtUString *primType,
127 RtPrimVarList *primvars,
128 std::vector<HdGeomSubset> *geomSubsets,
129 std::vector<RtPrimVarList> *geomSubsetPrimvars) = 0;
130
131 // Allow subclasses to inject additional geometry primvars.
132 virtual void
133 _AddPrimvars(RtPrimVarList*) const
134 {
135 // Add nothing by default.
136 }
137
138 // Allow subclasses to contribute additional coordinate system IDs.
139 virtual const std::vector<riley::CoordinateSystemId>&
140 _GetAdditionalCoordSysIds() const
141 {
142 static const std::vector<riley::CoordinateSystemId> empty;
143 return empty;
144 }
145
146 // This class does not support copying.
147 HdPrman_Gprim(const HdPrman_Gprim&) = delete;
148 HdPrman_Gprim &operator =(const HdPrman_Gprim&) = delete;
149
150};
151
152template <typename BASE>
153void
155 HdRenderParam* renderParam,
156 HdDirtyBits* dirtyBits,
157 TfToken const &reprToken)
158{
159 HD_TRACE_FUNCTION();
160 HF_MALLOC_TAG_FUNCTION();
161 TF_UNUSED(reprToken);
162
163 // Check if there are any relevant dirtyBits.
164 // (See the HdChangeTracker::MarkRprimDirty() note regarding
165 // internalDirtyBits used for internal signaling in Hydra.)
166 static const HdDirtyBits internalDirtyBits =
167 HdChangeTracker::InitRepr |
168 HdChangeTracker::Varying |
169 HdChangeTracker::NewRepr |
170 HdChangeTracker::CustomBitsMask;
171 // HdPrman does not make use of the repr concept or customBits.
172 *dirtyBits &= ~(HdChangeTracker::NewRepr | HdChangeTracker::CustomBitsMask);
173 // If no relevant dirtyBits remain, return early to avoid acquiring write
174 // access to Riley, which requires a pause and restart of rendering.
175 if (((*dirtyBits & ~internalDirtyBits)
176 & HdChangeTracker::AllSceneDirtyBits) == 0) {
177 return;
178 }
179
180 HdPrman_RenderParam *param =
181 static_cast<HdPrman_RenderParam*>(renderParam);
182
183 // Riley API.
184 riley::Riley *riley = param->AcquireRiley();
185
186 // Update instance bindings.
187 BASE::_UpdateInstancer(sceneDelegate, dirtyBits);
188
189 // Prim id
190 SdfPath const& id = BASE::GetId();
191 SdfPath const& instancerId = BASE::GetInstancerId();
192 const bool isHdInstance = !instancerId.IsEmpty();
193 SdfPath primPath = sceneDelegate->GetScenePrimPath(id, 0, nullptr);
194
195 // Sample transform
197 sceneDelegate->SampleTransform(id,
198#if HD_API_VERSION >= 68
199 param->GetShutterInterval()[0],
200 param->GetShutterInterval()[1],
201#endif
202 &xf);
203
204 // Update visibility so thet rprim->IsVisible() will work in render pass
205 if (HdChangeTracker::IsVisibilityDirty(*dirtyBits, id)) {
206 BASE::_UpdateVisibility(sceneDelegate, dirtyBits);
207 }
208
209 // Resolve material binding. Default to fallbackGprimMaterial.
210 if (*dirtyBits & HdChangeTracker::DirtyMaterialId) {
211#if HD_API_VERSION < 37
212 BASE::_SetMaterialId(sceneDelegate->GetRenderIndex().GetChangeTracker(),
213 sceneDelegate->GetMaterialId(id));
214#else
215 BASE::SetMaterialId(sceneDelegate->GetMaterialId(id));
216#endif
217 }
218 riley::MaterialId materialId = _GetFallbackMaterial(param);
219 riley::DisplacementId dispId = riley::DisplacementId::InvalidId();
220 const SdfPath & hdMaterialId = BASE::GetMaterialId();
221 HdPrman_ResolveMaterial(sceneDelegate, hdMaterialId, riley, &materialId, &dispId);
222
223 // Convert (and cache) coordinate systems.
224 riley::CoordinateSystemList coordSysList = {0, nullptr};
225 std::vector<riley::CoordinateSystemId> allCoordSysIds;
226 if (HdPrman_RenderParam::RileyCoordSysIdVecRefPtr convertedCoordSys =
227 param->ConvertAndRetainCoordSysBindings(sceneDelegate, id)) {
228 allCoordSysIds.insert(allCoordSysIds.end(),
229 convertedCoordSys->begin(),
230 convertedCoordSys->end());
231 }
232 // Append any additional coordinate system IDs from subclasses.
233 const auto& additionalCoordSysIds = _GetAdditionalCoordSysIds();
234 allCoordSysIds.insert(allCoordSysIds.end(),
235 additionalCoordSysIds.begin(),
236 additionalCoordSysIds.end());
237 coordSysList.count = allCoordSysIds.size();
238 coordSysList.ids = allCoordSysIds.data();
239
240 // Hydra dirty bits corresponding to PRMan prototype attributes (also called
241 // "primitive variables" but not synonymous with USD primvars). See prman
242 // docs at https://rmanwiki.pixar.com/display/REN24/Primitive+Variables.
243 static const HdDirtyBits prmanProtoAttrBits =
244 HdChangeTracker::DirtyPoints |
245 HdChangeTracker::DirtyNormals |
246 HdChangeTracker::DirtyWidths |
247 HdChangeTracker::DirtyVolumeField |
248 HdChangeTracker::DirtyTopology |
249 HdChangeTracker::DirtyPrimvar;
250
251 // Hydra dirty bits corresponding to prman instance attributes. See prman
252 // docs at https://rmanwiki.pixar.com/display/REN24/Instance+Attributes.
253 static const HdDirtyBits prmanInstAttrBits =
254 HdChangeTracker::DirtyMaterialId |
255 HdChangeTracker::DirtyTransform |
256 HdChangeTracker::DirtyVisibility |
257 HdChangeTracker::DirtyDoubleSided |
258 HdChangeTracker::DirtySubdivTags |
259 HdChangeTracker::DirtyVolumeField |
260 HdChangeTracker::DirtyCategories |
261 HdChangeTracker::DirtyPrimvar |
262 HdChangeTracker::DirtyRenderTag;
263
264 // These two bitmasks intersect, so we check them against dirtyBits
265 // prior to clearing either mask.
266 const bool prmanProtoAttrBitsWereSet(*dirtyBits & prmanProtoAttrBits);
267 const bool prmanInstAttrBitsWereSet(*dirtyBits & prmanInstAttrBits);
268
269 //
270 // Create or modify Riley geometry prototype(s).
271 //
272 std::vector<riley::MaterialId> subsetMaterialIds;
273 std::vector<SdfPath> subsetPaths;
274 {
275 RtUString primType;
276 RtPrimVarList primvars;
277 HdGeomSubsets geomSubsets;
278 std::vector<RtPrimVarList> geomSubsetPrimvars;
279 bool ok = _ConvertGeometry(param, sceneDelegate, id,
280 &primType, &primvars,
281 &geomSubsets, &geomSubsetPrimvars);
282 if (!ok) {
283 // We expect a specific error will have already been issued.
284 return;
285 }
286
287 // identifier:object is useful for cryptomatte
288 primvars.SetString(RixStr.k_identifier_object,
289 RtUString(id.GetName().c_str()));
290 for (size_t i=0, n=geomSubsets.size(); i<n; ++i) {
291 geomSubsetPrimvars[i]
292 .SetString(RixStr.k_identifier_object,
293 RtUString(geomSubsets[i].id.GetName().c_str()));
294 }
295
296// In 2311 and beyond, we can use
297// HdPrman_PreviewSurfacePrimvarsSceneIndexPlugin.
298#if PXR_VERSION < 2311
299 // Transfer material opinions of primvars.
300 HdPrman_TransferMaterialPrimvarOpinions(sceneDelegate, hdMaterialId,
301 primvars);
302#endif // PXR_VERSION < 2311
303
304 // Adjust _prototypeIds array.
305 const size_t oldCount = _prototypeIds.size();
306 const size_t newCount = std::max((size_t) 1, geomSubsets.size());
307 if (newCount != oldCount) {
308 for (const auto &oldPrototypeId: _prototypeIds) {
309 if (oldPrototypeId != riley::GeometryPrototypeId::InvalidId()) {
310 riley->DeleteGeometryPrototype(oldPrototypeId);
311 }
312 }
313 _prototypeIds.resize(newCount,
314 riley::GeometryPrototypeId::InvalidId());
315 }
316
317 _AddPrimvars(&primvars);
318
319 // Update Riley geom prototypes.
320 if (geomSubsets.empty()) {
321 // Common case: no subsets.
322 TF_VERIFY(newCount == 1);
323 TF_VERIFY(_prototypeIds.size() == 1);
324 primvars.SetString(RixStr.k_stats_prototypeIdentifier,
325 RtUString(primPath.GetText()));
326 if (_prototypeIds[0] == riley::GeometryPrototypeId::InvalidId()) {
327 TRACE_SCOPE("riley::CreateGeometryPrototype");
328 _prototypeIds[0] = riley->CreateGeometryPrototype(
329 riley::UserId(
330 stats::AddDataLocation(primPath.GetText()).GetValue()),
331 primType, dispId, primvars);
332 } else if (prmanProtoAttrBitsWereSet) {
333 TRACE_SCOPE("riley::ModifyGeometryPrototype");
334 riley->ModifyGeometryPrototype(primType, _prototypeIds[0],
335 &dispId, &primvars);
336 }
337 } else {
338 // Subsets case.
339 // We resolve materials here, and hold them in subsetMaterialIds:
340 // Displacement networks are passed to the geom prototype;
341 // material networks are passed to the instances.
342 subsetMaterialIds.reserve(geomSubsets.size());
343
344 // We also cache the subset paths for re-use when creating
345 // the instances
346 subsetPaths.reserve(geomSubsets.size());
347
348 for (size_t j=0; j < geomSubsets.size(); ++j) {
349 auto& prototypeId = _prototypeIds[j];
350 HdGeomSubset &subset = geomSubsets[j];
351 RtPrimVarList &subsetPrimvars = geomSubsetPrimvars[j];
352
353 // Convert indices to int32_t and set as k_shade_faceset.
354 std::vector<int32_t> int32Indices(subset.indices.cbegin(),
355 subset.indices.cend());
356 subsetPrimvars.SetIntegerArray(RixStr.k_shade_faceset,
357 int32Indices.data(),
358 int32Indices.size());
359 // Look up material override for the subset (if any)
360 riley::MaterialId subsetMaterialId = materialId;
361 riley::DisplacementId subsetDispId = dispId;
362 if (subset.materialId.IsEmpty()) {
363 subset.materialId = hdMaterialId;
364 }
365 HdPrman_ResolveMaterial(
366 sceneDelegate, subset.materialId,
367 riley, &subsetMaterialId, &subsetDispId);
368 subsetMaterialIds.push_back(subsetMaterialId);
369
370 // Look up the path for the subset
371 const SdfPath subsetPath =
372 sceneDelegate->GetScenePrimPath(subset.id, 0, nullptr);
373 subsetPaths.push_back(subsetPath);
374 subsetPrimvars.SetString(
375 RixStr.k_stats_prototypeIdentifier,
376 RtUString(subsetPath.GetText()));
377
378 if (prototypeId == riley::GeometryPrototypeId::InvalidId()) {
379 TRACE_SCOPE("riley::CreateGeometryPrototype");
380 prototypeId =
381 riley->CreateGeometryPrototype(
382 riley::UserId(
383 stats::AddDataLocation(
384 subsetPath.GetText()).GetValue()),
385 primType, subsetDispId, subsetPrimvars);
386 } else if (prmanProtoAttrBitsWereSet) {
387 TRACE_SCOPE("riley::ModifyGeometryPrototype");
388 riley->ModifyGeometryPrototype(
389 primType, prototypeId,
390 &subsetDispId, &subsetPrimvars);
391 }
392 }
393 }
394 *dirtyBits &= ~prmanProtoAttrBits;
395 }
396
397 //
398 // Stop here, or also create geometry instances?
399 //
400 if (_PrototypeOnly()) {
401 *dirtyBits &= ~HdChangeTracker::AllSceneDirtyBits;
402 return;
403 }
404
405 //
406 // Create or modify Riley geometry instances.
407 //
408
409 // Resolve attributes.
410 RtParamList attrs = param->ConvertAttributes(sceneDelegate, id, true);
411
412 // user:__materialid is useful for cryptomatte
413 if(!hdMaterialId.IsEmpty()) {
414 attrs.SetString(RtUString("user:__materialid"), RtUString(hdMaterialId.GetText()));
415 }
416
417 if (!isHdInstance) {
418 // Simple case: Singleton instance.
419 // Convert transform.
421 for (size_t i=0; i < xf.count; ++i) {
422 xf_rt[i] = HdPrman_Utils::GfMatrixToRtMatrix(xf.values[i]);
423 }
424 const riley::Transform xform = {
425 unsigned(xf.count),
426 xf_rt.data(),
427 xf.times.data()};
428
429 // Adjust _instanceIds array.
430 const size_t oldCount = _instanceIds.size();
431 const size_t newCount = _prototypeIds.size();
432 if (newCount != oldCount) {
433 for (const auto &oldInstanceId: _instanceIds) {
434 if (oldInstanceId != riley::GeometryInstanceId::InvalidId()) {
435 riley->DeleteGeometryInstance(
436 riley::GeometryPrototypeId::InvalidId(), oldInstanceId);
437 }
438 }
439 _instanceIds.resize(
440 newCount,
441 riley::GeometryInstanceId::InvalidId());
442 }
443
444 // Prepend renderTag to grouping:membership
445 param->AddRenderTagToGroupingMembership(
446 sceneDelegate->GetRenderTag(id), attrs);
447
448 // Create or modify Riley instances corresponding to a
449 // singleton Hydra instance.
450 TF_VERIFY(_instanceIds.size() == _prototypeIds.size());
451 for (size_t j=0; j < _prototypeIds.size(); ++j) {
452 auto const& prototypeId = _prototypeIds[j];
453 auto& instanceId = _instanceIds[j];
454 auto instanceMaterialId = materialId;
455 RtParamList finalAttrs = attrs; // copy
456
457 // To uniquely identiy this geometry instance, use either
458 // the prim path or geometry subset path (if given).
459 SdfPath* idPath(&primPath);
460 if (!subsetPaths.empty()) {
461 idPath = &subsetPaths[j];
462 }
463
464 // Assign & register ID.
465 param->GetIdMap()->RegisterId(
466 { idPath->GetString(),
467 /* primId = */ BASE::GetPrimId(),
468 /*instanceId = */ 0 },
469 &finalAttrs);
470
471 // If a valid subset material was bound, use it.
472 if (!subsetMaterialIds.empty()) {
473 TF_VERIFY(j < subsetMaterialIds.size());
474 instanceMaterialId = subsetMaterialIds[j];
475 }
476
477 // Create or modify Riley geometry instance.
478 if (instanceId == riley::GeometryInstanceId::InvalidId()) {
479 TRACE_SCOPE("riley::CreateGeometryInstance");
480 instanceId = riley->CreateGeometryInstance(
481 riley::UserId(
482 stats::AddDataLocation(idPath->GetText()).GetValue()),
483 riley::GeometryPrototypeId::InvalidId(), prototypeId,
484 instanceMaterialId, coordSysList, xform, finalAttrs);
485 } else if (prmanInstAttrBitsWereSet) {
486 TRACE_SCOPE("riley::ModifyGeometryInstance");
487 riley->ModifyGeometryInstance(
488 riley::GeometryPrototypeId::InvalidId(),
489 instanceId, &instanceMaterialId, &coordSysList, &xform,
490 &finalAttrs);
491 }
492 }
493 *dirtyBits &= ~prmanInstAttrBits;
494 } else if (prmanInstAttrBitsWereSet
495 || HdChangeTracker::IsInstancerDirty(*dirtyBits, instancerId)) {
496 // This gprim is a prototype of a hydra instancer. (It is not itself an
497 // instancer because it is a gprim.) The riley geometry prototypes have
498 // already been synced above, and those are owned by this gprim instance.
499 // We need to tell the hdprman instancer to sync its riley instances for
500 // these riley prototypes.
501 //
502 // We won't make any riley instances here. The hdprman instancer will
503 // own the riley instances instead.
504 //
505 // We only need to do this if dirtyBits says the instancer is dirty.
506
507 HdRenderIndex &renderIndex = sceneDelegate->GetRenderIndex();
508
509 // first, sync the hydra instancer and its parents, from the bottom up.
510 // (note: this is transitional code, it should be done by the render index...)
511 HdInstancer::_SyncInstancerAndParents(renderIndex, instancerId);
512
513 if (subsetMaterialIds.size() == 0) {
514 subsetMaterialIds.push_back(materialId);
515 }
516 if (subsetPaths.size() == 0) {
517 subsetPaths.push_back(primPath);
518 }
519 TF_VERIFY(_prototypeIds.size() == subsetMaterialIds.size() &&
520 _prototypeIds.size() == subsetPaths.size(),
521 "size mismatch (%lu, %lu, %lu)\n", _prototypeIds.size(),
522 subsetMaterialIds.size(), subsetPaths.size());
523
524 // XXX: To avoid a failed verify inside Populate(), we will check the
525 // prototype ids for validity here. We don't usually do this, relying on
526 // Riley to report invalid prototype ids on instance creation. But
527 // Populate() allows and expects an invalid prototype id when instancing
528 // lights, so doing this check here lets us make a more informative
529 // warning. HYD-3206
530 if (std::any_of(_prototypeIds.begin(), _prototypeIds.end(),
531 [](const auto& id){
532 return id == riley::GeometryPrototypeId::InvalidId();
533 })) {
534 TF_WARN("Riley geometry prototype creation failed for "
535 "instanced gprim <%s>; the prim will not be instanced.",
536 id.GetText());
537 } else {
538 // next, tell the hdprman instancer to sync the riley instances
539 HdPrmanInstancer *instancer = static_cast<HdPrmanInstancer*>(
540 renderIndex.GetInstancer(instancerId));
541 if (instancer) {
542 instancer->Populate(
543 renderParam,
544 *dirtyBits,
545 id,
546 _prototypeIds,
547 coordSysList,
548 attrs, xf,
549 subsetMaterialIds,
550 subsetPaths);
551 }
552 }
553 }
554 *dirtyBits &= ~HdChangeTracker::AllSceneDirtyBits;
555}
556
557PXR_NAMESPACE_CLOSE_SCOPE
558
559#endif // EXT_RMANPKG_PLUGIN_RENDERMAN_PLUGIN_HD_PRMAN_GPRIM_H
Tracks changes from the HdSceneDelegate, providing invalidation cues to the render engine.
static HD_API bool IsInstancerDirty(HdDirtyBits dirtyBits, SdfPath const &id)
Returns true if the dirtyBits has a dirty instancer. id is for perflog.
HD_API bool IsVisibilityDirty(SdfPath const &id)
Returns true if the rprim identified by id has dirty visibility.
A common base class for HdPrman_Gprim types.
Definition gprimbase.h:22
A mix-in template that adds shared gprim behavior to support various HdRprim types.
Definition gprim.h:31
The render index is part of the Hydra 1.0 API and is only used for emulation purposes so that HdScene...
HD_API HdInstancer * GetInstancer(SdfPath const &id) const
Returns the instancer of id.
The HdRenderParam is an opaque (to core Hydra) handle, to an object that is obtained from the render ...
Adapter class providing data exchange with the client scene graph.
virtual HD_API TfToken GetRenderTag(SdfPath const &id)
Returns the render tag that will be used to bucket prims during render pass bucketing.
virtual HD_API SdfPath GetMaterialId(SdfPath const &rprimId)
Returns the material ID bound to the rprim rprimId.
virtual HD_API size_t SampleTransform(SdfPath const &id, size_t maxSampleCount, float *sampleTimes, GfMatrix4d *sampleValues)
Store up to maxSampleCount transform samples in *sampleValues.
HdRenderIndex & GetRenderIndex()
Returns the RenderIndex owned by this delegate.
virtual HD_API SdfPath GetScenePrimPath(SdfPath const &rprimId, int instanceIndex, HdInstancerContext *instancerContext=nullptr)
Returns the scene address of the prim corresponding to the given rprim/instance index.
A path value used to locate objects in layers or scenegraphs.
Definition path.h:281
SDF_API const char * GetText() const
Returns the string representation of this path as a c string.
bool IsEmpty() const noexcept
Returns true if this is the empty path (SdfPath::EmptyPath()).
Definition path.h:405
This is a small-vector class with local storage optimization, the local storage can be specified via ...
Token for efficient comparison, assignment, and hashing of known strings.
Definition token.h:71
#define TF_WARN(...)
Issue a warning, but continue execution.
Definition diagnostic.h:132
#define TF_VERIFY(cond, format,...)
Checks a condition and reports an error if it evaluates false.
Definition diagnostic.h:266
#define TF_UNUSED(x)
Stops compiler from producing unused argument or variable warnings.
Definition tf.h:168
Describes a subset of a piece of geometry as a set of indices.
Definition geomSubset.h:23
VtIntArray indices
The list of element indices contained in the subset.
Definition geomSubset.h:39
SdfPath id
The path used to identify this subset in the scene.
Definition geomSubset.h:35
SdfPath materialId
The path used to identify this material bound to the subset.
Definition geomSubset.h:37
An array of a value sampled over time, in struct-of-arrays layout.
Basic Sdf data types.