Loading...
Searching...
No Matches
gprim.h
1//
2// Copyright 2019 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#ifndef EXT_RMANPKG_25_0_PLUGIN_RENDERMAN_PLUGIN_HD_PRMAN_GPRIM_H
25#define EXT_RMANPKG_25_0_PLUGIN_RENDERMAN_PLUGIN_HD_PRMAN_GPRIM_H
26
27#include "pxr/pxr.h"
28#include "pxr/usd/sdf/types.h"
30
31#include "hdPrman/gprimbase.h"
32#include "hdPrman/renderParam.h"
33#include "hdPrman/instancer.h"
34#include "hdPrman/material.h"
35#include "hdPrman/rixStrings.h"
36#include "hdPrman/utils.h"
37
38#include "Riley.h"
39
40PXR_NAMESPACE_OPEN_SCOPE
41
44template <typename BASE>
45class HdPrman_Gprim : public BASE, public HdPrman_GprimBase
46{
47public:
48 using BaseType = BASE;
49
50 HdPrman_Gprim(SdfPath const& id)
51 : BaseType(id)
52 {
53 }
54
55 ~HdPrman_Gprim() override = default;
56
57 void
58 Finalize(HdRenderParam *renderParam) override
59 {
60 HdPrman_RenderParam *param =
61 static_cast<HdPrman_RenderParam*>(renderParam);
62 const SdfPath& id = BASE::GetId();
63 riley::Riley *riley = param->AcquireRiley();
64
65 // Release retained conversions of coordSys bindings.
66 param->ReleaseCoordSysBindings(id);
67
68 // Delete instances before deleting the prototypes they use.
69 for (const auto &instId: _instanceIds) {
70 if (instId != riley::GeometryInstanceId::InvalidId()) {
71 riley->DeleteGeometryInstance(
72 riley::GeometryPrototypeId::InvalidId(), instId);
73 }
74 }
75 _instanceIds.clear();
76
77 // delete instances owned by the instancer.
78 if (HdPrmanInstancer* instancer = param->GetInstancer(
79 BASE::GetInstancerId())) {
80 instancer->Depopulate(renderParam, id);
81 }
82
83 for (const auto &protoId: _prototypeIds) {
84 if (protoId != riley::GeometryPrototypeId::InvalidId()) {
85 riley->DeleteGeometryPrototype(protoId);
86 }
87 }
88 _prototypeIds.clear();
89 }
90
91 void Sync(HdSceneDelegate* sceneDelegate,
92 HdRenderParam* renderParam,
93 HdDirtyBits* dirtyBits,
94 TfToken const &reprToken) override;
95
96protected:
97 HdDirtyBits GetInitialDirtyBitsMask() const override = 0;
98
99 HdDirtyBits
100 _PropagateDirtyBits(HdDirtyBits bits) const override
101 {
102 // By default, just return the same dirty bits we recieved.
103 return bits;
104 }
105
106 void
107 _InitRepr(TfToken const &reprToken,
108 HdDirtyBits *dirtyBits) override
109 {
110 TF_UNUSED(reprToken);
111 TF_UNUSED(dirtyBits);
112 // No-op
113 }
114
115 // We override this member function in mesh.cpp to support the creation
116 // of mesh light prototype geometry.
117 virtual bool
118 _PrototypeOnly()
119 {
120 return false;
121 }
122
123 // Provide a fallback material. Default grabs _fallbackMaterial
124 // from the context.
125 virtual riley::MaterialId
126 _GetFallbackMaterial(HdPrman_RenderParam *renderParam)
127 {
128 return renderParam->GetFallbackMaterialId();
129 }
130
131 // Populate primType and primvars.
132 virtual RtPrimVarList
133 _ConvertGeometry(HdPrman_RenderParam *renderParam,
134 HdSceneDelegate *sceneDelegate,
135 const SdfPath &id,
136 RtUString *primType,
137 std::vector<HdGeomSubset> *geomSubsets) = 0;
138
139 // This class does not support copying.
140 HdPrman_Gprim(const HdPrman_Gprim&) = delete;
141 HdPrman_Gprim &operator =(const HdPrman_Gprim&) = delete;
142
143};
144
145template <typename BASE>
146void
148 HdRenderParam* renderParam,
149 HdDirtyBits* dirtyBits,
150 TfToken const &reprToken)
151{
152 HD_TRACE_FUNCTION();
153 HF_MALLOC_TAG_FUNCTION();
154 TF_UNUSED(reprToken);
155
156 HdPrman_RenderParam *param =
157 static_cast<HdPrman_RenderParam*>(renderParam);
158
159 // Riley API.
160 riley::Riley *riley = param->AcquireRiley();
161
162 // Update instance bindings.
163 BASE::_UpdateInstancer(sceneDelegate, dirtyBits);
164
165 // Prim id
166 SdfPath const& id = BASE::GetId();
167 SdfPath const& instancerId = BASE::GetInstancerId();
168 const bool isHdInstance = !instancerId.IsEmpty();
169 SdfPath primPath = sceneDelegate->GetScenePrimPath(id, 0, nullptr);
170
171 // Prman has a default value for identifier:id of 0 (in case of ray miss),
172 // while Hydra treats id -1 as the clear value. We map Prman primId as
173 // (Hydra primId + 1) to get around this, here and in
174 // hdPrman/framebuffer.cpp.
175 const int32_t primId = BASE::GetPrimId() + 1;
176
177 // Sample transform
179 sceneDelegate->SampleTransform(id, &xf);
180
181 // Update visibility so thet rprim->IsVisible() will work in render pass
182 if (HdChangeTracker::IsVisibilityDirty(*dirtyBits, id)) {
183 BASE::_UpdateVisibility(sceneDelegate, dirtyBits);
184 }
185
186 // Resolve material binding. Default to fallbackGprimMaterial.
187 if (*dirtyBits & HdChangeTracker::DirtyMaterialId) {
188#if HD_API_VERSION < 37
189 BASE::_SetMaterialId(sceneDelegate->GetRenderIndex().GetChangeTracker(),
190 sceneDelegate->GetMaterialId(id));
191#else
192 BASE::SetMaterialId(sceneDelegate->GetMaterialId(id));
193#endif
194 }
195 riley::MaterialId materialId = _GetFallbackMaterial(param);
196 riley::DisplacementId dispId = riley::DisplacementId::InvalidId();
197 const SdfPath & hdMaterialId = BASE::GetMaterialId();
198 HdPrman_ResolveMaterial(sceneDelegate, hdMaterialId, riley, &materialId, &dispId);
199
200 // Convert (and cache) coordinate systems.
201 riley::CoordinateSystemList coordSysList = {0, nullptr};
202 if (HdPrman_RenderParam::RileyCoordSysIdVecRefPtr convertedCoordSys =
203 param->ConvertAndRetainCoordSysBindings(sceneDelegate, id)) {
204 coordSysList.count = convertedCoordSys->size();
205 coordSysList.ids = convertedCoordSys->data();
206 }
207
208 // Hydra dirty bits corresponding to PRMan prototype attributes (also called
209 // "primitive variables" but not synonymous with USD primvars). See prman
210 // docs at https://rmanwiki.pixar.com/display/REN24/Primitive+Variables.
211 static const int prmanProtoAttrBits =
212 HdChangeTracker::DirtyPoints |
213 HdChangeTracker::DirtyNormals |
214 HdChangeTracker::DirtyWidths |
215 HdChangeTracker::DirtyTopology;
216
217 // Hydra dirty bits corresponding to prman instance attributes. See prman
218 // docs at https://rmanwiki.pixar.com/display/REN24/Instance+Attributes.
219 static const int prmanInstAttrBits =
220 HdChangeTracker::DirtyMaterialId |
221 HdChangeTracker::DirtyTransform |
222 HdChangeTracker::DirtyVisibility |
223 HdChangeTracker::DirtyDoubleSided |
224 HdChangeTracker::DirtySubdivTags |
225 HdChangeTracker::DirtyVolumeField |
226 HdChangeTracker::DirtyCategories |
227 HdChangeTracker::DirtyPrimvar;
228
229 //
230 // Create or modify Riley geometry prototype(s).
231 //
232 std::vector<riley::MaterialId> subsetMaterialIds;
233 std::vector<SdfPath> subsetPaths;
234 {
235 RtUString primType;
236 HdGeomSubsets geomSubsets;
237 RtPrimVarList primvars = _ConvertGeometry(param, sceneDelegate, id,
238 &primType, &geomSubsets);
239
240 // Transfer material opinions of primvars.
241 HdPrman_TransferMaterialPrimvarOpinions(sceneDelegate, hdMaterialId,
242 primvars);
243
244 // Adjust _prototypeIds array.
245 const size_t oldCount = _prototypeIds.size();
246 const size_t newCount = std::max((size_t) 1, geomSubsets.size());
247 if (newCount != oldCount) {
248 for (const auto &oldPrototypeId: _prototypeIds) {
249 if (oldPrototypeId != riley::GeometryPrototypeId::InvalidId()) {
250 riley->DeleteGeometryPrototype(oldPrototypeId);
251 }
252 }
253 _prototypeIds.resize(newCount,
254 riley::GeometryPrototypeId::InvalidId());
255 }
256
257 // Update Riley geom prototypes.
258 if (geomSubsets.empty()) {
259 // Common case: no subsets.
260 TF_VERIFY(newCount == 1);
261 TF_VERIFY(_prototypeIds.size() == 1);
262 primvars.SetString(RixStr.k_stats_prototypeIdentifier,
263 RtUString(primPath.GetText()));
264 if (_prototypeIds[0] == riley::GeometryPrototypeId::InvalidId()) {
265 TRACE_SCOPE("riley::CreateGeometryPrototype");
266 _prototypeIds[0] = riley->CreateGeometryPrototype(
267 riley::UserId(
268 stats::AddDataLocation(primPath.GetText()).GetValue()),
269 primType, dispId, primvars);
270 } else if (*dirtyBits & prmanProtoAttrBits) {
271 TRACE_SCOPE("riley::ModifyGeometryPrototype");
272 riley->ModifyGeometryPrototype(primType, _prototypeIds[0],
273 &dispId, &primvars);
274 }
275 } else {
276 // Subsets case.
277 // We resolve materials here, and hold them in subsetMaterialIds:
278 // Displacement networks are passed to the geom prototype;
279 // material networks are passed to the instances.
280 subsetMaterialIds.reserve(geomSubsets.size());
281
282 // We also cache the subset paths for re-use when creating the instances
283 subsetPaths.reserve(geomSubsets.size());
284
285 for (size_t j=0; j < geomSubsets.size(); ++j) {
286 auto& prototypeId = _prototypeIds[j];
287 HdGeomSubset &subset = geomSubsets[j];
288
289 // Convert indices to int32_t and set as k_shade_faceset.
290 std::vector<int32_t> int32Indices(subset.indices.cbegin(),
291 subset.indices.cend());
292 primvars.SetIntegerArray(RixStr.k_shade_faceset,
293 int32Indices.data(),
294 int32Indices.size());
295 // Look up material override for the subset (if any)
296 riley::MaterialId subsetMaterialId = materialId;
297 riley::DisplacementId subsetDispId = dispId;
298 if (subset.materialId.IsEmpty()) {
299 subset.materialId = hdMaterialId;
300 }
301 HdPrman_ResolveMaterial(sceneDelegate, subset.materialId,
302 riley, &subsetMaterialId, &subsetDispId);
303 subsetMaterialIds.push_back(subsetMaterialId);
304
305 // Look up the path for the subset
306 SdfPath subsetPath = sceneDelegate->GetScenePrimPath(subset.id, 0, nullptr);
307 subsetPaths.push_back(subsetPath);
308 primvars.SetString(RixStr.k_stats_prototypeIdentifier,
309 RtUString(subsetPath.GetText()));
310
311 if (prototypeId == riley::GeometryPrototypeId::InvalidId()) {
312 TRACE_SCOPE("riley::CreateGeometryPrototype");
313 prototypeId =
314 riley->CreateGeometryPrototype(
315 riley::UserId(
316 stats::AddDataLocation(subsetPath.GetText()).GetValue()),
317 primType, dispId, primvars);
318 } else if (*dirtyBits & prmanProtoAttrBits) {
319 TRACE_SCOPE("riley::ModifyGeometryPrototype");
320 riley->ModifyGeometryPrototype(primType, prototypeId,
321 &subsetDispId, &primvars);
322 }
323 }
324 }
325 *dirtyBits &= ~prmanProtoAttrBits;
326 }
327
328 //
329 // Stop here, or also create geometry instances?
330 //
331 if (_PrototypeOnly()) {
332 *dirtyBits &= ~HdChangeTracker::AllSceneDirtyBits;
333 return;
334 }
335
336 //
337 // Create or modify Riley geometry instances.
338 //
339
340 // Resolve attributes.
341 bool sceneVisibility = true;
342 RtParamList attrs = param->ConvertAttributes(sceneDelegate, id, true,
343 &sceneVisibility);
344 _sceneVisibility = sceneVisibility;
345
346 // Add "identifier:id" with the prim id.
347 attrs.SetInteger(RixStr.k_identifier_id, primId);
348
349 if (!isHdInstance) {
350 // Simple case: Singleton instance.
351 // Convert transform.
353 for (size_t i=0; i < xf.count; ++i) {
354 xf_rt[i] = HdPrman_Utils::GfMatrixToRtMatrix(xf.values[i]);
355 }
356 const riley::Transform xform = {
357 unsigned(xf.count),
358 xf_rt.data(),
359 xf.times.data()};
360
361 // Add "identifier:id2" with the instance number.
362 // XXX Do we want to distinguish facesets here?
363 attrs.SetInteger(RixStr.k_identifier_id2, 0);
364
365 // Adjust _instanceIds array.
366 const size_t oldCount = _instanceIds.size();
367 const size_t newCount = _prototypeIds.size();
368 if (newCount != oldCount) {
369 for (const auto &oldInstanceId: _instanceIds) {
370 if (oldInstanceId != riley::GeometryInstanceId::InvalidId()) {
371 riley->DeleteGeometryInstance(
372 riley::GeometryPrototypeId::InvalidId(), oldInstanceId);
373 }
374 }
375 _instanceIds.resize(
376 newCount,
377 riley::GeometryInstanceId::InvalidId());
378 }
379
380 // Create or modify Riley instances corresponding to a
381 // singleton Hydra instance.
382 TF_VERIFY(_instanceIds.size() == _prototypeIds.size());
383 for (size_t j=0; j < _prototypeIds.size(); ++j) {
384 auto const& prototypeId = _prototypeIds[j];
385 auto& instanceId = _instanceIds[j];
386 auto instanceMaterialId = materialId;
387 RtParamList finalAttrs = attrs; // copy
388
389 // If a subset path was cached, use it. If not, use the prim path.
390 SdfPath* subsetPath(&primPath);
391 if (!subsetPaths.empty()) {
392 subsetPath = &subsetPaths[j];
393 }
394
395 finalAttrs.SetString(RixStr.k_identifier_name,
396 RtUString(subsetPath->GetText()));
397
398 // If a valid subset material was bound, use it.
399 if (!subsetMaterialIds.empty()) {
400 TF_VERIFY(j < subsetMaterialIds.size());
401 instanceMaterialId = subsetMaterialIds[j];
402 }
403
404 if (instanceId == riley::GeometryInstanceId::InvalidId()) {
405 TRACE_SCOPE("riley::CreateGeometryInstance");
406 instanceId = riley->CreateGeometryInstance(
407 riley::UserId(
408 stats::AddDataLocation(subsetPath->GetText()).GetValue()),
409 riley::GeometryPrototypeId::InvalidId(), prototypeId,
410 instanceMaterialId, coordSysList, xform, finalAttrs);
411 } else if (*dirtyBits & prmanInstAttrBits) {
412 TRACE_SCOPE("riley::ModifyGeometryInstance");
413 riley->ModifyGeometryInstance(
414 riley::GeometryPrototypeId::InvalidId(),
415 instanceId, &instanceMaterialId, &coordSysList, &xform,
416 &finalAttrs);
417 }
418 }
419 *dirtyBits &= ~prmanInstAttrBits;
420 } else if ((*dirtyBits & prmanInstAttrBits)
421 || HdChangeTracker::IsInstancerDirty(*dirtyBits, instancerId)) {
422 // This gprim is a prototype of a hydra instancer. (It is not itself an
423 // instancer because it is a gprim.) The riley geometry prototypes have
424 // already been synced above, and those are owned by this gprim instance.
425 // We need to tell the hdprman instancer to sync its riley instances for
426 // these riley prototypes.
427 //
428 // We won't make any riley instances here. The hdprman instancer will
429 // own the riley instances instead.
430 //
431 // We only need to do this if dirtyBits says the instancer is dirty.
432
433 HdRenderIndex &renderIndex = sceneDelegate->GetRenderIndex();
434
435 // first, sync the hydra instancer and its parents, from the bottom up.
436 // (note: this is transitional code, it should be done by the render index...)
437 HdInstancer::_SyncInstancerAndParents(renderIndex, instancerId);
438
439 if (subsetMaterialIds.size() == 0) {
440 subsetMaterialIds.push_back(materialId);
441 }
442 if (subsetPaths.size() == 0) {
443 subsetPaths.push_back(primPath);
444 }
445 TF_VERIFY(_prototypeIds.size() == subsetMaterialIds.size() &&
446 _prototypeIds.size() == subsetPaths.size(),
447 "size mismatch (%lu, %lu, %lu)\n", _prototypeIds.size(),
448 subsetMaterialIds.size(), subsetPaths.size());
449
450 // next, tell the hdprman instancer to sync the riley instances
451 HdPrmanInstancer *instancer = static_cast<HdPrmanInstancer*>(
452 renderIndex.GetInstancer(instancerId));
453 if (instancer) {
454 instancer->Populate(
455 renderParam,
456 dirtyBits,
457 id,
458 _prototypeIds,
459 coordSysList,
460 attrs, xf,
461 subsetMaterialIds,
462 subsetPaths);
463 }
464 }
465 *dirtyBits &= ~HdChangeTracker::AllSceneDirtyBits;
466}
467
468PXR_NAMESPACE_CLOSE_SCOPE
469
470#endif // EXT_RMANPKG_25_0_PLUGIN_RENDERMAN_PLUGIN_HD_PRMAN_GPRIM_H
Tracks changes from the HdSceneDelegate, providing invalidation cues to the render engine.
Definition: changeTracker.h:52
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:38
A mix-in template that adds shared gprim behavior to support various HdRprim types.
Definition: gprim.h:46
The Hydra render index is a flattened representation of the client scene graph, which may be composed...
Definition: renderIndex.h:121
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 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:290
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:414
This is a small-vector class with local storage optimization, the local storage can be specified via ...
Definition: smallVector.h:179
value_type * data()
Direct access to the underlying array.
Definition: smallVector.h:768
Token for efficient comparison, assignment, and hashing of known strings.
Definition: token.h:88
#define TF_VERIFY(cond, format,...)
Checks a condition and reports an error if it evaluates false.
Definition: diagnostic.h:283
#define TF_UNUSED(x)
Stops compiler from producing unused argument or variable warnings.
Definition: tf.h:185
Describes a subset of a piece of geometry as a set of indices.
Definition: geomSubset.h:40
VtIntArray indices
The list of element indices contained in the subset.
Definition: geomSubset.h:56
SdfPath id
The path used to identify this subset in the scene.
Definition: geomSubset.h:52
SdfPath materialId
The path used to identify this material bound to the subset.
Definition: geomSubset.h:54
An array of a value sampled over time, in struct-of-arrays layout.
#define TRACE_SCOPE(name)
Records a timestamp when constructed and a timespan event when destructed, using name as the key.
Definition: trace.h:48
Basic Sdf data types.