7#ifndef EXT_RMANPKG_PLUGIN_RENDERMAN_PLUGIN_HD_PRMAN_GPRIM_H
8#define EXT_RMANPKG_PLUGIN_RENDERMAN_PLUGIN_HD_PRMAN_GPRIM_H
11#include "pxr/imaging/hd/version.h"
15#include "hdPrman/gprimbase.h"
16#include "hdPrman/renderParam.h"
17#include "hdPrman/instancer.h"
18#include "hdPrman/material.h"
19#include "hdPrman/rixStrings.h"
20#include "hdPrman/utils.h"
24PXR_NAMESPACE_OPEN_SCOPE
28template <
typename BASE>
32 using BaseType = BASE;
44 HdPrman_RenderParam *param =
45 static_cast<HdPrman_RenderParam*
>(renderParam);
46 const SdfPath&
id = BASE::GetId();
47 riley::Riley *riley = param->AcquireRiley();
53 param->ReleaseCoordSysBindings(
id);
56 for (
const auto &instId: _instanceIds) {
57 if (instId != riley::GeometryInstanceId::InvalidId()) {
58 riley->DeleteGeometryInstance(
59 riley::GeometryPrototypeId::InvalidId(), instId);
65 if (HdPrmanInstancer* instancer = param->GetInstancer(
66 BASE::GetInstancerId())) {
67 instancer->Depopulate(renderParam,
id);
70 for (
const auto &protoId: _prototypeIds) {
71 if (protoId != riley::GeometryPrototypeId::InvalidId()) {
72 riley->DeleteGeometryPrototype(protoId);
75 _prototypeIds.clear();
80 HdDirtyBits* dirtyBits,
81 TfToken const &reprToken)
override;
84 HdDirtyBits GetInitialDirtyBitsMask()
const override = 0;
87 _PropagateDirtyBits(HdDirtyBits bits)
const override
94 _InitRepr(
TfToken const &reprToken,
95 HdDirtyBits *dirtyBits)
override
112 virtual riley::MaterialId
113 _GetFallbackMaterial(HdPrman_RenderParam *renderParam)
115 return renderParam->GetFallbackMaterialId();
122 HdPrman_RenderParam *renderParam,
126 RtPrimVarList *primvars,
127 std::vector<HdGeomSubset> *geomSubsets,
128 std::vector<RtPrimVarList> *geomSubsetPrimvars) = 0;
132 _AddPrimvars(RtPrimVarList*)
const
138 virtual const std::vector<riley::CoordinateSystemId>&
139 _GetAdditionalCoordSysIds()
const
141 static const std::vector<riley::CoordinateSystemId> empty;
151template <
typename BASE>
155 HdDirtyBits* dirtyBits,
159 HF_MALLOC_TAG_FUNCTION();
165 static const HdDirtyBits internalDirtyBits =
166 HdChangeTracker::InitRepr |
167 HdChangeTracker::Varying |
168 HdChangeTracker::NewRepr |
169 HdChangeTracker::CustomBitsMask;
171 *dirtyBits &= ~(HdChangeTracker::NewRepr | HdChangeTracker::CustomBitsMask);
174 if (((*dirtyBits & ~internalDirtyBits)
175 & HdChangeTracker::AllSceneDirtyBits) == 0) {
179 HdPrman_RenderParam *param =
180 static_cast<HdPrman_RenderParam*
>(renderParam);
183 riley::Riley *riley = param->AcquireRiley();
186 BASE::_UpdateInstancer(sceneDelegate, dirtyBits);
189 SdfPath const&
id = BASE::GetId();
190 SdfPath const& instancerId = BASE::GetInstancerId();
191 const bool isHdInstance = !instancerId.
IsEmpty();
198 const int32_t primId = BASE::GetPrimId() + 1;
203#
if HD_API_VERSION >= 68
204 param->GetShutterInterval()[0],
205 param->GetShutterInterval()[1],
211 BASE::_UpdateVisibility(sceneDelegate, dirtyBits);
215 if (*dirtyBits & HdChangeTracker::DirtyMaterialId) {
216#if HD_API_VERSION < 37
217 BASE::_SetMaterialId(sceneDelegate->
GetRenderIndex().GetChangeTracker(),
223 riley::MaterialId materialId = _GetFallbackMaterial(param);
224 riley::DisplacementId dispId = riley::DisplacementId::InvalidId();
225 const SdfPath & hdMaterialId = BASE::GetMaterialId();
226 HdPrman_ResolveMaterial(sceneDelegate, hdMaterialId, riley, &materialId, &dispId);
229 riley::CoordinateSystemList coordSysList = {0,
nullptr};
230 std::vector<riley::CoordinateSystemId> allCoordSysIds;
231 if (HdPrman_RenderParam::RileyCoordSysIdVecRefPtr convertedCoordSys =
232 param->ConvertAndRetainCoordSysBindings(sceneDelegate,
id)) {
233 allCoordSysIds.insert(allCoordSysIds.end(),
234 convertedCoordSys->begin(),
235 convertedCoordSys->end());
238 const auto& additionalCoordSysIds = _GetAdditionalCoordSysIds();
239 allCoordSysIds.insert(allCoordSysIds.end(),
240 additionalCoordSysIds.begin(),
241 additionalCoordSysIds.end());
242 coordSysList.count = allCoordSysIds.size();
243 coordSysList.ids = allCoordSysIds.data();
248 static const HdDirtyBits prmanProtoAttrBits =
249 HdChangeTracker::DirtyPoints |
250 HdChangeTracker::DirtyNormals |
251 HdChangeTracker::DirtyWidths |
252 HdChangeTracker::DirtyVolumeField |
253 HdChangeTracker::DirtyTopology |
254 HdChangeTracker::DirtyPrimvar;
258 static const HdDirtyBits prmanInstAttrBits =
259 HdChangeTracker::DirtyMaterialId |
260 HdChangeTracker::DirtyTransform |
261 HdChangeTracker::DirtyVisibility |
262 HdChangeTracker::DirtyDoubleSided |
263 HdChangeTracker::DirtySubdivTags |
264 HdChangeTracker::DirtyVolumeField |
265 HdChangeTracker::DirtyCategories |
266 HdChangeTracker::DirtyPrimvar;
270 const bool prmanProtoAttrBitsWereSet(*dirtyBits & prmanProtoAttrBits);
271 const bool prmanInstAttrBitsWereSet(*dirtyBits & prmanInstAttrBits);
276 std::vector<riley::MaterialId> subsetMaterialIds;
277 std::vector<SdfPath> subsetPaths;
280 RtPrimVarList primvars;
281 HdGeomSubsets geomSubsets;
282 std::vector<RtPrimVarList> geomSubsetPrimvars;
283 bool ok = _ConvertGeometry(param, sceneDelegate,
id,
284 &primType, &primvars,
285 &geomSubsets, &geomSubsetPrimvars);
292 primvars.SetString(RixStr.k_identifier_object,
293 RtUString(
id.GetName().c_str()));
294 for (
size_t i=0, n=geomSubsets.size(); i<n; ++i) {
295 primvars.SetString(RixStr.k_identifier_object,
296 RtUString(geomSubsets[i].
id.GetName().c_str()));
301#if PXR_VERSION < 2311
303 HdPrman_TransferMaterialPrimvarOpinions(sceneDelegate, hdMaterialId,
308 const size_t oldCount = _prototypeIds.size();
309 const size_t newCount = std::max((
size_t) 1, geomSubsets.size());
310 if (newCount != oldCount) {
311 for (
const auto &oldPrototypeId: _prototypeIds) {
312 if (oldPrototypeId != riley::GeometryPrototypeId::InvalidId()) {
313 riley->DeleteGeometryPrototype(oldPrototypeId);
316 _prototypeIds.resize(newCount,
317 riley::GeometryPrototypeId::InvalidId());
320 _AddPrimvars(&primvars);
323 if (geomSubsets.empty()) {
327 primvars.SetString(RixStr.k_stats_prototypeIdentifier,
328 RtUString(primPath.
GetText()));
329 if (_prototypeIds[0] == riley::GeometryPrototypeId::InvalidId()) {
330 TRACE_SCOPE(
"riley::CreateGeometryPrototype");
331 _prototypeIds[0] = riley->CreateGeometryPrototype(
333 stats::AddDataLocation(primPath.
GetText()).GetValue()),
334 primType, dispId, primvars);
335 }
else if (prmanProtoAttrBitsWereSet) {
336 TRACE_SCOPE(
"riley::ModifyGeometryPrototype");
337 riley->ModifyGeometryPrototype(primType, _prototypeIds[0],
345 subsetMaterialIds.reserve(geomSubsets.size());
349 subsetPaths.reserve(geomSubsets.size());
351 for (
size_t j=0; j < geomSubsets.size(); ++j) {
352 auto& prototypeId = _prototypeIds[j];
354 RtPrimVarList &subsetPrimvars = geomSubsetPrimvars[j];
357 std::vector<int32_t> int32Indices(subset.
indices.cbegin(),
359 subsetPrimvars.SetIntegerArray(RixStr.k_shade_faceset,
361 int32Indices.size());
363 riley::MaterialId subsetMaterialId = materialId;
364 riley::DisplacementId subsetDispId = dispId;
368 HdPrman_ResolveMaterial(
370 riley, &subsetMaterialId, &subsetDispId);
371 subsetMaterialIds.push_back(subsetMaterialId);
376 subsetPaths.push_back(subsetPath);
377 subsetPrimvars.SetString(
378 RixStr.k_stats_prototypeIdentifier,
379 RtUString(subsetPath.
GetText()));
381 if (prototypeId == riley::GeometryPrototypeId::InvalidId()) {
382 TRACE_SCOPE(
"riley::CreateGeometryPrototype");
384 riley->CreateGeometryPrototype(
386 stats::AddDataLocation(
387 subsetPath.
GetText()).GetValue()),
388 primType, subsetDispId, subsetPrimvars);
389 }
else if (prmanProtoAttrBitsWereSet) {
390 TRACE_SCOPE(
"riley::ModifyGeometryPrototype");
391 riley->ModifyGeometryPrototype(
392 primType, prototypeId,
393 &subsetDispId, &subsetPrimvars);
397 *dirtyBits &= ~prmanProtoAttrBits;
403 if (_PrototypeOnly()) {
413 RtParamList attrs = param->ConvertAttributes(sceneDelegate,
id,
true);
416 attrs.SetInteger(RixStr.k_identifier_id, primId);
420 attrs.SetString(RtUString(
"user:__materialid"), RtUString(hdMaterialId.
GetText()));
427 for (
size_t i=0; i < xf.count; ++i) {
428 xf_rt[i] = HdPrman_Utils::GfMatrixToRtMatrix(xf.values[i]);
430 const riley::Transform xform = {
437 attrs.SetInteger(RixStr.k_identifier_id2, 0);
440 const size_t oldCount = _instanceIds.size();
441 const size_t newCount = _prototypeIds.size();
442 if (newCount != oldCount) {
443 for (
const auto &oldInstanceId: _instanceIds) {
444 if (oldInstanceId != riley::GeometryInstanceId::InvalidId()) {
445 riley->DeleteGeometryInstance(
446 riley::GeometryPrototypeId::InvalidId(), oldInstanceId);
451 riley::GeometryInstanceId::InvalidId());
455 param->AddRenderTagToGroupingMembership(
460 TF_VERIFY(_instanceIds.size() == _prototypeIds.size());
461 for (
size_t j=0; j < _prototypeIds.size(); ++j) {
462 auto const& prototypeId = _prototypeIds[j];
463 auto& instanceId = _instanceIds[j];
464 auto instanceMaterialId = materialId;
465 RtParamList finalAttrs = attrs;
468 SdfPath* subsetPath(&primPath);
469 if (!subsetPaths.empty()) {
470 subsetPath = &subsetPaths[j];
473 finalAttrs.SetString(RixStr.k_identifier_name,
474 RtUString(subsetPath->
GetText()));
477 if (!subsetMaterialIds.empty()) {
479 instanceMaterialId = subsetMaterialIds[j];
482 if (instanceId == riley::GeometryInstanceId::InvalidId()) {
483 TRACE_SCOPE(
"riley::CreateGeometryInstance");
484 instanceId = riley->CreateGeometryInstance(
486 stats::AddDataLocation(subsetPath->
GetText()).GetValue()),
487 riley::GeometryPrototypeId::InvalidId(), prototypeId,
488 instanceMaterialId, coordSysList, xform, finalAttrs);
489 }
else if (prmanInstAttrBitsWereSet) {
490 TRACE_SCOPE(
"riley::ModifyGeometryInstance");
491 riley->ModifyGeometryInstance(
492 riley::GeometryPrototypeId::InvalidId(),
493 instanceId, &instanceMaterialId, &coordSysList, &xform,
497 *dirtyBits &= ~prmanInstAttrBits;
498 }
else if (prmanInstAttrBitsWereSet
515 HdInstancer::_SyncInstancerAndParents(renderIndex, instancerId);
517 if (subsetMaterialIds.size() == 0) {
518 subsetMaterialIds.push_back(materialId);
520 if (subsetPaths.size() == 0) {
521 subsetPaths.push_back(primPath);
523 TF_VERIFY(_prototypeIds.size() == subsetMaterialIds.size() &&
524 _prototypeIds.size() == subsetPaths.size(),
525 "size mismatch (%lu, %lu, %lu)\n", _prototypeIds.size(),
526 subsetMaterialIds.size(), subsetPaths.size());
534 if (std::any_of(_prototypeIds.begin(), _prototypeIds.end(),
536 return id == riley::GeometryPrototypeId::InvalidId();
538 TF_WARN(
"Riley geometry prototype creation failed for "
539 "instanced gprim <%s>; the prim will not be instanced.",
543 HdPrmanInstancer *instancer =
static_cast<HdPrmanInstancer*
>(
561PXR_NAMESPACE_CLOSE_SCOPE
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.
A mix-in template that adds shared gprim behavior to support various HdRprim types.
The Hydra render index is a flattened representation of the client scene graph, which may be composed...
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.
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()).
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.
#define TF_WARN(...)
Issue a warning, but continue execution.
#define TF_VERIFY(cond, format,...)
Checks a condition and reports an error if it evaluates false.
#define TF_UNUSED(x)
Stops compiler from producing unused argument or variable warnings.
Describes a subset of a piece of geometry as a set of indices.
VtIntArray indices
The list of element indices contained in the subset.
SdfPath id
The path used to identify this subset in the scene.
SdfPath materialId
The path used to identify this material bound to the subset.
An array of a value sampled over time, in struct-of-arrays layout.