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/usdImagingGL/drawModeAdapter.h"
25 #include "pxr/usdImaging/usdImagingGL/package.h"
26
27 #include "pxr/usdImaging/usdImaging/gprimAdapter.h"
28 #include "pxr/usdImaging/usdImaging/indexProxy.h"
29 #include "pxr/usdImaging/usdImaging/instancerContext.h"
30 #include "pxr/usdImaging/usdImaging/tokens.h"
31
32 #include "pxr/imaging/hd/material.h"
33
34 #include "pxr/imaging/hio/glslfx.h"
35 #include "pxr/imaging/hio/image.h"
36 #include "pxr/imaging/pxOsd/tokens.h"
37
38 #include "pxr/usd/usdGeom/modelAPI.h"
39 #include "pxr/usd/sdr/registry.h"
40 #include "pxr/usd/sdr/shaderNode.h"
41
42 #include "pxr/base/gf/matrix4f.h"
43 #include "pxr/base/tf/type.h"
44
45 PXR_NAMESPACE_OPEN_SCOPE
46
47 TF_DEFINE_PRIVATE_TOKENS(
48 _tokens,
49
50 (material)
51
52 (cardsUv)
53 (cardsTexAssign)
54
55 (textureXPosColor)
56 (textureYPosColor)
57 (textureZPosColor)
58 (textureXNegColor)
59 (textureYNegColor)
60 (textureZNegColor)
61 (textureXPosOpacity)
62 (textureYPosOpacity)
63 (textureZPosOpacity)
64 (textureXNegOpacity)
65 (textureYNegOpacity)
66 (textureZNegOpacity)
67
68 (worldtoscreen)
69
70 (displayRoughness)
71
72 (file)
73 (st)
74 (rgb)
75 (a)
76 (fallback)
77 (minFilter)
78 (magFilter)
79 (linear)
80 (linearMipmapLinear)
81
82 (varname)
83 (result)
84 (activeTexCard)
85 );
86
87 namespace {
88 enum AxesMask : uint8_t {
89 xPos = (1 << 0),
90 yPos = (1 << 1),
91 zPos = (1 << 2),
92 xNeg = (1 << 3),
93 yNeg = (1 << 4),
94 zNeg = (1 << 5),
95 xAxis = (xPos | xNeg),
96 yAxis = (yPos | yNeg),
97 zAxis = (zPos | zNeg),
98 };
99 }
100
TF_REGISTRY_FUNCTION(TfType)101 TF_REGISTRY_FUNCTION(TfType)
102 {
103 typedef UsdImagingGLDrawModeAdapter Adapter;
104 TfType t = TfType::Define<Adapter, TfType::Bases<Adapter::BaseAdapter> >();
105 t.SetFactory< UsdImagingPrimAdapterFactory<Adapter> >();
106 }
107
108 static SdfPath
_GetMaterialPath(UsdPrim const & prim)109 _GetMaterialPath(UsdPrim const& prim)
110 {
111 const SdfPath matPath = SdfPath(_tokens->material.GetString());
112 return prim.GetPath().AppendPath(matPath);
113 }
114
UsdImagingGLDrawModeAdapter()115 UsdImagingGLDrawModeAdapter::UsdImagingGLDrawModeAdapter()
116 : UsdImagingPrimAdapter()
117 , _schemaColor(0)
118 {
119 // Look up the default color in the schema registry.
120 const UsdPrimDefinition *primDef =
121 UsdSchemaRegistry::GetInstance()
122 .FindAppliedAPIPrimDefinition(TfToken("GeomModelAPI"));
123 if (primDef) {
124 primDef->GetAttributeFallbackValue(
125 UsdGeomTokens->modelDrawModeColor, &_schemaColor);
126 }
127 }
128
~UsdImagingGLDrawModeAdapter()129 UsdImagingGLDrawModeAdapter::~UsdImagingGLDrawModeAdapter()
130 {
131 }
132
133 bool
ShouldCullChildren() const134 UsdImagingGLDrawModeAdapter::ShouldCullChildren() const
135 {
136 return true;
137 }
138
139 bool
CanPopulateUsdInstance() const140 UsdImagingGLDrawModeAdapter::CanPopulateUsdInstance() const
141 {
142 return true;
143 }
144
145 bool
IsSupported(UsdImagingIndexProxy const * index) const146 UsdImagingGLDrawModeAdapter::IsSupported(
147 UsdImagingIndexProxy const* index) const
148 {
149 return true;
150 }
151
152 SdfPath
Populate(UsdPrim const & prim,UsdImagingIndexProxy * index,UsdImagingInstancerContext const * instancerContext)153 UsdImagingGLDrawModeAdapter::Populate(UsdPrim const& prim,
154 UsdImagingIndexProxy* index,
155 UsdImagingInstancerContext const*
156 instancerContext)
157 {
158 SdfPath cachePath = UsdImagingGprimAdapter::_ResolveCachePath(
159 prim.GetPath(), instancerContext);
160
161 // The draw mode adapter only supports models or unloaded prims.
162 // This is enforced in UsdImagingDelegate::_IsDrawModeApplied.
163 if (!TF_VERIFY(prim.IsModel() || !prim.IsLoaded(), "<%s>",
164 prim.GetPath().GetText())) {
165 return SdfPath();
166 }
167
168 // There should have been a non-default draw mode applied for this
169 // adapter to be called; this is enforced in
170 // UsdImagingDelegate::_IsDrawModeApplied.
171 TfToken drawMode = GetModelDrawMode(prim);
172 if (drawMode == UsdGeomTokens->default_ && instancerContext) {
173 drawMode = instancerContext->instanceDrawMode;
174 }
175 if (!TF_VERIFY(drawMode != UsdGeomTokens->default_, "<%s>",
176 prim.GetPath().GetText())) {
177 return SdfPath();
178 }
179
180 // If this object is instanced, we need to use the instancer adapter for the
181 // rprim, which will forward to the draw mode adapter but additionally
182 // handle instancer attributes like instance index.
183 UsdImagingPrimAdapterSharedPtr rprimAdapter =
184 (instancerContext && instancerContext->instancerAdapter) ?
185 instancerContext->instancerAdapter :
186 shared_from_this();
187
188 // If this prim isn't instanced, cachePrim will be the same as "prim", but
189 // if it is instanced the instancer adapters expect us to pass in this
190 // prim, which should point to the instancer.
191 UsdPrim cachePrim = _GetPrim(cachePath.GetAbsoluteRootOrPrimPath());
192
193 if (drawMode == UsdGeomTokens->origin ||
194 drawMode == UsdGeomTokens->bounds) {
195 // Origin and bounds both draw as basis curves
196 if (!index->IsRprimTypeSupported(HdPrimTypeTokens->basisCurves)) {
197 TF_WARN("Unable to display origin or bounds draw mode for model "
198 "%s, basis curves not supported", cachePath.GetText());
199 return SdfPath();
200 }
201 index->InsertRprim(HdPrimTypeTokens->basisCurves,
202 cachePath, cachePrim, rprimAdapter);
203 HD_PERF_COUNTER_INCR(UsdImagingTokens->usdPopulatedPrimCount);
204 } else if (drawMode == UsdGeomTokens->cards) {
205 // Cards draw as a mesh
206 if (!index->IsRprimTypeSupported(HdPrimTypeTokens->mesh)) {
207 TF_WARN("Unable to display cards draw mode for model %s, "
208 "meshes not supported", cachePath.GetText());
209 return SdfPath();
210 }
211 index->InsertRprim(HdPrimTypeTokens->mesh,
212 cachePath, cachePrim, rprimAdapter);
213 HD_PERF_COUNTER_INCR(UsdImagingTokens->usdPopulatedPrimCount);
214 } else {
215 TF_CODING_ERROR("Model <%s> has unsupported drawMode '%s'",
216 prim.GetPath().GetText(), drawMode.GetText());
217 return SdfPath();
218 }
219
220 // As long as we're passing cachePrim to InsertRprim, we need to fix up
221 // the dependency map ourselves. For USD edit purposes, we depend on the
222 // prototype prim ("prim"), rather than the instancer prim.
223 // See similar code in GprimAdapter::_AddRprim.
224 if (instancerContext != nullptr) {
225 index->RemovePrimInfoDependency(cachePath);
226 index->AddDependency(cachePath, prim);
227 }
228
229 // Additionally, insert the material.
230 SdfPath materialPath = _GetMaterialPath(prim);
231 if (index->IsSprimTypeSupported(HdPrimTypeTokens->material) &&
232 !index->IsPopulated(materialPath)) {
233 index->InsertSprim(HdPrimTypeTokens->material,
234 materialPath, prim, shared_from_this());
235 HD_PERF_COUNTER_INCR(UsdImagingTokens->usdPopulatedPrimCount);
236 }
237
238 // Record the drawmode for use in UpdateForTime().
239 _drawModeMap.insert(std::make_pair(cachePath, drawMode));
240
241 return cachePath;
242 }
243
244 bool
_IsMaterialPath(SdfPath const & path) const245 UsdImagingGLDrawModeAdapter::_IsMaterialPath(SdfPath const& path) const
246 {
247 return path.GetNameToken() == _tokens->material;
248 }
249
250 void
_RemovePrim(SdfPath const & cachePath,UsdImagingIndexProxy * index)251 UsdImagingGLDrawModeAdapter::_RemovePrim(SdfPath const& cachePath,
252 UsdImagingIndexProxy* index)
253 {
254 if (_IsMaterialPath(cachePath)) {
255 index->RemoveSprim(HdPrimTypeTokens->material, cachePath);
256 } else {
257 _drawModeMap.erase(cachePath);
258 index->RemoveRprim(cachePath);
259 }
260 }
261
262 void
MarkDirty(UsdPrim const & prim,SdfPath const & cachePath,HdDirtyBits dirty,UsdImagingIndexProxy * index)263 UsdImagingGLDrawModeAdapter::MarkDirty(UsdPrim const& prim,
264 SdfPath const& cachePath,
265 HdDirtyBits dirty,
266 UsdImagingIndexProxy* index)
267 {
268 if (_IsMaterialPath(cachePath)) {
269 index->MarkSprimDirty(cachePath, dirty);
270 } else {
271 index->MarkRprimDirty(cachePath, dirty);
272 }
273 }
274
275 void
MarkTransformDirty(UsdPrim const & prim,SdfPath const & cachePath,UsdImagingIndexProxy * index)276 UsdImagingGLDrawModeAdapter::MarkTransformDirty(UsdPrim const& prim,
277 SdfPath const& cachePath,
278 UsdImagingIndexProxy* index)
279 {
280 if (!_IsMaterialPath(cachePath)) {
281 index->MarkRprimDirty(cachePath, HdChangeTracker::DirtyTransform);
282 }
283 }
284
285 void
MarkVisibilityDirty(UsdPrim const & prim,SdfPath const & cachePath,UsdImagingIndexProxy * index)286 UsdImagingGLDrawModeAdapter::MarkVisibilityDirty(UsdPrim const& prim,
287 SdfPath const& cachePath,
288 UsdImagingIndexProxy* index)
289 {
290 if (!_IsMaterialPath(cachePath)) {
291 index->MarkRprimDirty(cachePath, HdChangeTracker::DirtyVisibility);
292 }
293 }
294
295 void
MarkMaterialDirty(UsdPrim const & prim,SdfPath const & cachePath,UsdImagingIndexProxy * index)296 UsdImagingGLDrawModeAdapter::MarkMaterialDirty(UsdPrim const& prim,
297 SdfPath const& cachePath,
298 UsdImagingIndexProxy* index)
299 {
300 if (_IsMaterialPath(cachePath)) {
301 index->MarkSprimDirty(cachePath, HdMaterial::DirtyResource);
302 } else {
303 // If the Usd material changed, it could mean the primvar set also
304 // changed Hydra doesn't currently manage detection and propagation of
305 // these changes, so we must mark the rprim dirty.
306 index->MarkRprimDirty(cachePath, HdChangeTracker::DirtyMaterialId);
307 }
308 }
309
310 bool
_HasVaryingExtent(UsdPrim const & prim) const311 UsdImagingGLDrawModeAdapter::_HasVaryingExtent(UsdPrim const& prim) const
312 {
313 UsdAttribute attr;
314
315 attr = prim.GetAttribute(UsdGeomTokens->extent);
316 if (attr && attr.ValueMightBeTimeVarying())
317 return true;
318
319 attr = prim.GetAttribute(UsdGeomTokens->extentsHint);
320 if (attr && attr.ValueMightBeTimeVarying())
321 return true;
322
323 return false;
324 }
325
326 void
_ComputeGeometryData(UsdPrim const & prim,SdfPath const & cachePath,UsdTimeCode time,TfToken const & drawMode,VtValue * topology,VtValue * points,GfRange3d * extent,VtValue * uv,VtValue * assign) const327 UsdImagingGLDrawModeAdapter::_ComputeGeometryData(
328 UsdPrim const& prim,
329 SdfPath const& cachePath,
330 UsdTimeCode time,
331 TfToken const& drawMode,
332 VtValue* topology,
333 VtValue* points,
334 GfRange3d* extent,
335 VtValue* uv,
336 VtValue* assign) const
337 {
338 if (drawMode == UsdGeomTokens->origin) {
339 *extent = _ComputeExtent(prim,
340 _HasVaryingExtent(prim) ? time : UsdTimeCode::EarliestTime());
341 _GenerateOriginGeometry(topology, points, *extent);
342
343 } else if (drawMode == UsdGeomTokens->bounds) {
344 *extent = _ComputeExtent(prim,
345 _HasVaryingExtent(prim) ? time : UsdTimeCode::EarliestTime());
346 _GenerateBoundsGeometry(topology, points, *extent);
347
348 } else if (drawMode == UsdGeomTokens->cards) {
349 UsdGeomModelAPI model(prim);
350 if (!model) {
351 // The population rules in UsdImagingDelegate disallow this.
352 TF_CODING_ERROR("Prim has draw mode 'cards' but geom model "
353 "API schema is not applied.");
354 return;
355 }
356
357 TfToken cardGeometry;
358 model.GetModelCardGeometryAttr().Get(&cardGeometry);
359 if (cardGeometry == UsdGeomTokens->fromTexture) {
360 // In "fromTexture" mode, read all the geometry data in from
361 // the textures.
362 _GenerateCardsFromTextureGeometry(topology, points,
363 uv, assign, extent, prim);
364
365 } else {
366 // First compute the extents.
367 *extent = _ComputeExtent(prim,
368 _HasVaryingExtent(prim) ? time : UsdTimeCode::EarliestTime());
369
370 // Generate mask for suppressing axes with no textures
371 uint8_t axes_mask = 0;
372 const TfToken textureAttrs[6] = {
373 UsdGeomTokens->modelCardTextureXPos,
374 UsdGeomTokens->modelCardTextureYPos,
375 UsdGeomTokens->modelCardTextureZPos,
376 UsdGeomTokens->modelCardTextureXNeg,
377 UsdGeomTokens->modelCardTextureYNeg,
378 UsdGeomTokens->modelCardTextureZNeg,
379 };
380 const uint8_t mask[6] = {
381 xPos, yPos, zPos, xNeg, yNeg, zNeg,
382 };
383 for (int i = 0; i < 6; ++i) {
384 SdfAssetPath asset;
385 prim.GetAttribute(textureAttrs[i]).Get(&asset, time);
386 if (!asset.GetAssetPath().empty()) {
387 axes_mask |= mask[i];
388 }
389 }
390
391 // If no textures are bound, generate the full geometry.
392 if (axes_mask == 0) { axes_mask = xAxis | yAxis | zAxis; }
393
394 // Generate UVs.
395 _GenerateTextureCoordinates(uv, assign, axes_mask);
396
397 // Generate geometry based on card type.
398 if (cardGeometry == UsdGeomTokens->cross) {
399 _GenerateCardsCrossGeometry(topology, points, *extent,
400 axes_mask);
401 } else if (cardGeometry == UsdGeomTokens->box) {
402 _GenerateCardsBoxGeometry(topology, points, *extent,
403 axes_mask);
404 } else {
405 TF_CODING_ERROR("<%s> Unexpected card geometry mode %s",
406 cachePath.GetText(), cardGeometry.GetText());
407 }
408
409 // Issue warnings for zero-area faces that we're supposedly
410 // drawing.
411 _SanityCheckFaceSizes(cachePath, *extent, axes_mask);
412 }
413 } else {
414 TF_CODING_ERROR("<%s> Unexpected draw mode %s",
415 cachePath.GetText(), drawMode.GetText());
416 }
417 }
418
419 /*virtual*/
420 VtValue
GetTopology(UsdPrim const & prim,SdfPath const & cachePath,UsdTimeCode time) const421 UsdImagingGLDrawModeAdapter::GetTopology(UsdPrim const& prim,
422 SdfPath const& cachePath,
423 UsdTimeCode time) const
424 {
425 TRACE_FUNCTION();
426 HF_MALLOC_TAG_FUNCTION();
427
428 TfToken drawMode = UsdGeomTokens->default_;
429 _DrawModeMap::const_iterator it = _drawModeMap.find(cachePath);
430 if (TF_VERIFY(it != _drawModeMap.end())) {
431 drawMode = it->second;
432 }
433
434 VtValue topology;
435 VtValue points;
436 VtValue uv;
437 VtValue assign;
438 GfRange3d extent;
439 _ComputeGeometryData(prim, cachePath, time, drawMode, &topology,
440 &points, &extent, &uv, &assign);
441 return topology;
442 }
443
444 /*virtual*/
445 GfRange3d
GetExtent(UsdPrim const & prim,SdfPath const & cachePath,UsdTimeCode time) const446 UsdImagingGLDrawModeAdapter::GetExtent(UsdPrim const& prim,
447 SdfPath const& cachePath,
448 UsdTimeCode time) const
449 {
450 TRACE_FUNCTION();
451 HF_MALLOC_TAG_FUNCTION();
452
453 TfToken drawMode = UsdGeomTokens->default_;
454 _DrawModeMap::const_iterator it = _drawModeMap.find(cachePath);
455 if (TF_VERIFY(it != _drawModeMap.end())) {
456 drawMode = it->second;
457 }
458
459 VtValue topology;
460 VtValue points;
461 VtValue uv;
462 VtValue assign;
463 GfRange3d extent;
464 _ComputeGeometryData(prim, cachePath, time, drawMode, &topology,
465 &points, &extent, &uv, &assign);
466 return extent;
467 }
468
469
470 /*virtual*/
471 bool
GetDoubleSided(UsdPrim const & prim,SdfPath const & cachePath,UsdTimeCode time) const472 UsdImagingGLDrawModeAdapter::GetDoubleSided(UsdPrim const& prim,
473 SdfPath const& cachePath,
474 UsdTimeCode time) const
475 {
476 return false;
477 }
478
479 /*virtual*/
480 VtValue
Get(UsdPrim const & prim,SdfPath const & cachePath,TfToken const & key,UsdTimeCode time,VtIntArray * outIndices) const481 UsdImagingGLDrawModeAdapter::Get(UsdPrim const& prim,
482 SdfPath const& cachePath,
483 TfToken const& key,
484 UsdTimeCode time,
485 VtIntArray *outIndices) const
486 {
487 TRACE_FUNCTION();
488
489 VtValue value;
490 UsdGeomModelAPI model(prim);
491
492 if (key == HdTokens->displayColor) {
493 VtVec3fArray color = VtVec3fArray(1);
494 GfVec3f drawModeColor;
495 if (model) {
496 model.GetModelDrawModeColorAttr().Get(&drawModeColor);
497 } else {
498 drawModeColor = _schemaColor;
499 }
500
501 color[0] = drawModeColor;
502 value = color;
503
504 } else if (key == HdTokens->displayOpacity) {
505 VtFloatArray opacity = VtFloatArray(1);
506
507 // Full opacity.
508 opacity[0] = 1.0f;
509 value = opacity;
510
511 } else if (key == HdTokens->widths) {
512 VtFloatArray widths = VtFloatArray(1);
513 widths[0] = 1.0f;
514 value = widths;
515
516 } else if (key == HdTokens->points) {
517 TRACE_FUNCTION_SCOPE("points");
518 TfToken drawMode = UsdGeomTokens->default_;
519 _DrawModeMap::const_iterator it = _drawModeMap.find(cachePath);
520 if (TF_VERIFY(it != _drawModeMap.end())) {
521 drawMode = it->second;
522 }
523
524 VtValue topology;
525 VtValue points;
526 VtValue uv;
527 VtValue assign;
528 GfRange3d extent;
529 _ComputeGeometryData(prim, cachePath, time, drawMode, &topology,
530 &points, &extent, &uv, &assign);
531 return points;
532
533 } else if (key == _tokens->cardsUv) {
534 TRACE_FUNCTION_SCOPE("cardsUV");
535 TfToken drawMode = UsdGeomTokens->default_;
536 _DrawModeMap::const_iterator it = _drawModeMap.find(cachePath);
537 if (TF_VERIFY(it != _drawModeMap.end())) {
538 drawMode = it->second;
539 }
540
541 VtValue topology;
542 VtValue points;
543 VtValue uv;
544 VtValue assign;
545 GfRange3d extent;
546 _ComputeGeometryData(prim, cachePath, time, drawMode, &topology,
547 &points, &extent, &uv, &assign);
548 return uv;
549
550 } else if (key == _tokens->cardsTexAssign) {
551 TRACE_FUNCTION_SCOPE("cardsTexAssign");
552 TfToken drawMode = UsdGeomTokens->default_;
553 _DrawModeMap::const_iterator it = _drawModeMap.find(cachePath);
554 if (TF_VERIFY(it != _drawModeMap.end())) {
555 drawMode = it->second;
556 }
557
558 VtValue topology;
559 VtValue points;
560 VtValue uv;
561 VtValue assign;
562 GfRange3d extent;
563 _ComputeGeometryData(prim, cachePath, time, drawMode, &topology,
564 &points, &extent, &uv, &assign);
565 return assign;
566
567 } else if (key == _tokens->displayRoughness) {
568 return VtValue(1.0f);
569 }
570
571 return value;
572 }
573
574 /*virtual*/
575 SdfPath
GetMaterialId(UsdPrim const & prim,SdfPath const & cachePath,UsdTimeCode time) const576 UsdImagingGLDrawModeAdapter::GetMaterialId(UsdPrim const& prim,
577 SdfPath const& cachePath,
578 UsdTimeCode time) const
579 {
580 return _GetMaterialPath(prim);
581 }
582
583 /*virtual*/
584 VtValue
GetMaterialResource(UsdPrim const & prim,SdfPath const & cachePath,UsdTimeCode time) const585 UsdImagingGLDrawModeAdapter::GetMaterialResource(UsdPrim const& prim,
586 SdfPath const& cachePath,
587 UsdTimeCode time) const
588 {
589 if (!_IsMaterialPath(cachePath)) {
590 return BaseAdapter::GetMaterialResource(prim, cachePath, time);
591 }
592
593 UsdGeomModelAPI model(prim);
594
595 SdfAssetPath path(UsdImagingGLPackageDrawModeShader());
596
597 SdrRegistry &shaderReg = SdrRegistry::GetInstance();
598 SdrShaderNodeConstPtr sdrNode =
599 shaderReg.GetShaderNodeFromAsset(
600 path,
601 NdrTokenMap(),
602 TfToken(),
603 HioGlslfxTokens->glslfx);
604
605 // An sdr node representing the drawCards.glslfx should be added
606 // to the registry, so we don't expect this to fail.
607 if (!TF_VERIFY(sdrNode)) {
608 return VtValue();
609 }
610
611 // Generate material network with a terminal that points to
612 // the DrawMode glslfx shader.
613 TfToken const& terminalType = HdMaterialTerminalTokens->surface;
614 HdMaterialNetworkMap networkMap;
615 HdMaterialNetwork& network = networkMap.map[terminalType];
616 HdMaterialNode terminal;
617 terminal.path = cachePath;
618 terminal.identifier = sdrNode->GetIdentifier();
619
620 const TfToken textureNames[12] = {
621 _tokens->textureXPosColor,
622 _tokens->textureYPosColor,
623 _tokens->textureZPosColor,
624 _tokens->textureXNegColor,
625 _tokens->textureYNegColor,
626 _tokens->textureZNegColor,
627 _tokens->textureXPosOpacity,
628 _tokens->textureYPosOpacity,
629 _tokens->textureZPosOpacity,
630 _tokens->textureXNegOpacity,
631 _tokens->textureYNegOpacity,
632 _tokens->textureZNegOpacity
633 };
634
635 if (model) {
636 const TfToken textureAttrs[6] = {
637 UsdGeomTokens->modelCardTextureXPos,
638 UsdGeomTokens->modelCardTextureYPos,
639 UsdGeomTokens->modelCardTextureZPos,
640 UsdGeomTokens->modelCardTextureXNeg,
641 UsdGeomTokens->modelCardTextureYNeg,
642 UsdGeomTokens->modelCardTextureZNeg,
643 };
644
645 GfVec3f drawModeColor;
646 model.GetModelDrawModeColorAttr().Get(&drawModeColor);
647 VtValue fallback = VtValue(GfVec4f(
648 drawModeColor[0], drawModeColor[1], drawModeColor[2],
649 1.0f));
650
651 for (int i = 0; i < 6; ++i) {
652 SdfAssetPath textureFile;
653 prim.GetAttribute(textureAttrs[i]).Get(&textureFile, time);
654 if (!textureFile.GetAssetPath().empty()) {
655 SdfPath textureNodePath = _GetMaterialPath(prim)
656 .AppendProperty(textureAttrs[i]);
657
658 // Make texture node
659 HdMaterialNode textureNode;
660 textureNode.path = textureNodePath;
661 textureNode.identifier = UsdImagingTokens->UsdUVTexture;
662 textureNode.parameters[_tokens->st] = _tokens->cardsUv;
663 textureNode.parameters[_tokens->fallback] = fallback;
664 textureNode.parameters[_tokens->file] = textureFile;
665 textureNode.parameters[_tokens->minFilter] =
666 _tokens->linearMipmapLinear;
667 textureNode.parameters[_tokens->magFilter] =
668 _tokens->linear;
669
670 // Insert connection between texture node and terminal color
671 // input
672 HdMaterialRelationship colorRel;
673 colorRel.inputId = textureNode.path;
674 colorRel.inputName = _tokens->rgb;
675 colorRel.outputId = terminal.path;
676 colorRel.outputName = textureNames[i];
677 network.relationships.emplace_back(std::move(colorRel));
678
679 // Insert connection between texture node and terminal
680 // opacity input
681 HdMaterialRelationship opacityRel;
682 opacityRel.inputId = textureNode.path;
683 opacityRel.inputName = _tokens->a;
684 opacityRel.outputId = terminal.path;
685 opacityRel.outputName = textureNames[i + 6];
686 network.relationships.emplace_back(std::move(opacityRel));
687
688 // Insert texture node
689 network.nodes.emplace_back(std::move(textureNode));
690 } else {
691 terminal.parameters[textureNames[i]] = drawModeColor;
692 terminal.parameters[textureNames[i + 6]] = VtValue(1.f);
693 }
694 }
695 } else {
696 for (int i = 0; i < 6; ++i) {
697 terminal.parameters[textureNames[i]] = _schemaColor;
698 terminal.parameters[textureNames[i + 6]] = VtValue(1.f);
699 }
700 }
701
702 // Adding a primvar reader for the card assignment
703 // Make primvar reader node
704 SdfPath primvarNodePath = _GetMaterialPath(prim)
705 .AppendProperty(_tokens->cardsTexAssign);
706 HdMaterialNode primvarNode;
707 primvarNode.path = primvarNodePath;
708 primvarNode.identifier = UsdImagingTokens->UsdPrimvarReader_int;
709 primvarNode.parameters[_tokens->varname] = _tokens->cardsTexAssign;
710 primvarNode.parameters[_tokens->fallback] = VtValue(0);
711
712 // Insert connection between primvar reader node and terminal
713 HdMaterialRelationship relPrimvar;
714 relPrimvar.inputId = primvarNode.path;
715 relPrimvar.inputName = _tokens->result;
716 relPrimvar.outputId = terminal.path;
717 relPrimvar.outputName = _tokens->activeTexCard;
718 network.relationships.emplace_back(std::move(relPrimvar));
719
720 // Insert primvar reader node
721 network.nodes.emplace_back(std::move(primvarNode));
722
723 // Insert terminal and update material network
724 networkMap.terminals.push_back(terminal.path);
725 network.nodes.emplace_back(std::move(terminal));
726
727 return VtValue(networkMap);
728 }
729
730 void
_CheckForTextureVariability(UsdPrim const & prim,HdDirtyBits dirtyBits,HdDirtyBits * timeVaryingBits) const731 UsdImagingGLDrawModeAdapter::_CheckForTextureVariability(
732 UsdPrim const& prim, HdDirtyBits dirtyBits,
733 HdDirtyBits *timeVaryingBits) const
734 {
735 const std::array<TfToken, 6> textureAttrs = {
736 UsdGeomTokens->modelCardTextureXPos,
737 UsdGeomTokens->modelCardTextureYPos,
738 UsdGeomTokens->modelCardTextureZPos,
739 UsdGeomTokens->modelCardTextureXNeg,
740 UsdGeomTokens->modelCardTextureYNeg,
741 UsdGeomTokens->modelCardTextureZNeg,
742 };
743
744 for (const TfToken& attr: textureAttrs) {
745 if (_IsVarying(prim, attr, dirtyBits,
746 UsdImagingTokens->usdVaryingTexture,
747 timeVaryingBits, false)) {
748 break;
749 }
750 }
751 }
752
753 void
TrackVariability(UsdPrim const & prim,SdfPath const & cachePath,HdDirtyBits * timeVaryingBits,UsdImagingInstancerContext const * instancerContext) const754 UsdImagingGLDrawModeAdapter::TrackVariability(UsdPrim const& prim,
755 SdfPath const& cachePath,
756 HdDirtyBits* timeVaryingBits,
757 UsdImagingInstancerContext const*
758 instancerContext) const
759 {
760 if (_IsMaterialPath(cachePath)) {
761 _CheckForTextureVariability(prim, HdMaterial::DirtyResource,
762 timeVaryingBits);
763 return;
764 }
765
766 // Discover time-varying transforms. If this card is instantiated on an
767 // instance, skip since the instance adapter will handle transforms
768 // and master roots always have identity transform.
769 if (!prim.IsInstance()) {
770 _IsTransformVarying(prim,
771 HdChangeTracker::DirtyTransform,
772 UsdImagingTokens->usdVaryingXform,
773 timeVaryingBits);
774 }
775
776 // Discover time-varying visibility.
777 _IsVarying(prim,
778 UsdGeomTokens->visibility,
779 HdChangeTracker::DirtyVisibility,
780 UsdImagingTokens->usdVaryingVisibility,
781 timeVaryingBits,
782 true);
783
784 // Discover time-varying extents. Look for time samples on either the
785 // extent or extentsHint attribute.
786 if (!_IsVarying(prim,
787 UsdGeomTokens->extent,
788 HdChangeTracker::DirtyPoints | HdChangeTracker::DirtyExtent,
789 UsdImagingTokens->usdVaryingExtent,
790 timeVaryingBits,
791 false)) {
792 _IsVarying(prim,
793 UsdGeomTokens->extentsHint,
794 HdChangeTracker::DirtyPoints | HdChangeTracker::DirtyExtent,
795 UsdImagingTokens->usdVaryingExtent,
796 timeVaryingBits,
797 false);
798 }
799 }
800
801 void
UpdateForTime(UsdPrim const & prim,SdfPath const & cachePath,UsdTimeCode time,HdDirtyBits requestedBits,UsdImagingInstancerContext const * instancerContext) const802 UsdImagingGLDrawModeAdapter::UpdateForTime(UsdPrim const& prim,
803 SdfPath const& cachePath,
804 UsdTimeCode time,
805 HdDirtyBits requestedBits,
806 UsdImagingInstancerContext const*
807 instancerContext) const
808 {
809 if (_IsMaterialPath(cachePath)) {
810 // The draw mode material doesn't make use of UpdateForTime.
811 return;
812 }
813
814 UsdImagingPrimvarDescCache* primvarDescCache = _GetPrimvarDescCache();
815 UsdGeomModelAPI model(prim);
816
817 // Geometry aspect
818 HdPrimvarDescriptorVector& primvars =
819 primvarDescCache->GetPrimvars(cachePath);
820
821 if (requestedBits & HdChangeTracker::DirtyWidths) {
822 _MergePrimvar(&primvars, UsdGeomTokens->widths,
823 HdInterpolationConstant);
824 }
825
826 if (requestedBits & HdChangeTracker::DirtyPrimvar) {
827 _MergePrimvar(&primvars, HdTokens->displayColor,
828 HdInterpolationConstant, HdPrimvarRoleTokens->color);
829 _MergePrimvar(&primvars, HdTokens->displayOpacity,
830 HdInterpolationConstant);
831 }
832
833 // We compute all of the below items together, since their derivations
834 // aren't easily separable.
835 HdDirtyBits geometryBits = HdChangeTracker::DirtyTopology |
836 HdChangeTracker::DirtyPoints |
837 HdChangeTracker::DirtyPrimvar |
838 HdChangeTracker::DirtyExtent;
839
840 if (requestedBits & geometryBits) {
841 TfToken drawMode = UsdGeomTokens->default_;
842 _DrawModeMap::const_iterator it = _drawModeMap.find(cachePath);
843 if (TF_VERIFY(it != _drawModeMap.end())) {
844 drawMode = it->second;
845 }
846
847 VtValue topology;
848 GfRange3d extent;
849 VtValue points;
850 VtValue uv;
851 VtValue assign;
852 _ComputeGeometryData(prim, cachePath, time, drawMode, &topology,
853 &points, &extent, &uv, &assign);
854
855 if (drawMode == UsdGeomTokens->cards) {
856 // Merge "cardsUv" and "cardsTexAssign" primvars
857 _MergePrimvar(&primvars, _tokens->cardsUv,
858 HdInterpolationVertex);
859 _MergePrimvar(&primvars, _tokens->cardsTexAssign,
860 HdInterpolationUniform);
861
862 // XXX: backdoor into the material system.
863 _MergePrimvar(&primvars, _tokens->displayRoughness,
864 HdInterpolationConstant);
865 }
866
867 // Merge "points" primvar
868 _MergePrimvar(&primvars,
869 HdTokens->points,
870 HdInterpolationVertex,
871 HdPrimvarRoleTokens->point);
872 }
873 }
874
875 HdDirtyBits
ProcessPropertyChange(UsdPrim const & prim,SdfPath const & cachePath,TfToken const & propertyName)876 UsdImagingGLDrawModeAdapter::ProcessPropertyChange(UsdPrim const& prim,
877 SdfPath const& cachePath,
878 TfToken const& propertyName)
879 {
880 const std::array<TfToken, 6> textureAttrs = {
881 UsdGeomTokens->modelCardTextureXPos,
882 UsdGeomTokens->modelCardTextureYPos,
883 UsdGeomTokens->modelCardTextureZPos,
884 UsdGeomTokens->modelCardTextureXNeg,
885 UsdGeomTokens->modelCardTextureYNeg,
886 UsdGeomTokens->modelCardTextureZNeg,
887 };
888
889 if (_IsMaterialPath(cachePath)) {
890 // Check if a texture has been changed.
891 for (const TfToken& attr : textureAttrs) {
892 if (propertyName == attr) {
893 return HdMaterial::DirtyResource;
894 }
895 }
896 return HdChangeTracker::Clean;
897 }
898
899 HdDirtyBits dirtyGeo =
900 HdChangeTracker::DirtyTopology | HdChangeTracker::DirtyPoints |
901 HdChangeTracker::DirtyPrimvar | HdChangeTracker::DirtyExtent;
902
903 if (propertyName == UsdGeomTokens->modelDrawModeColor)
904 return HdChangeTracker::DirtyPrimvar;
905 else if (propertyName == UsdGeomTokens->modelCardGeometry ||
906 propertyName == UsdGeomTokens->extent ||
907 propertyName == UsdGeomTokens->extentsHint)
908 return dirtyGeo;
909 else if (propertyName == UsdGeomTokens->visibility ||
910 propertyName == UsdGeomTokens->purpose)
911 return HdChangeTracker::DirtyVisibility;
912 else if (UsdGeomXformable::IsTransformationAffectedByAttrNamed(
913 propertyName))
914 return HdChangeTracker::DirtyTransform;
915
916 // In "cards" mode the texture assignments change what geometry
917 // is generated.
918 for (const TfToken& attr : textureAttrs) {
919 if (propertyName == attr) {
920 return dirtyGeo;
921 }
922 }
923
924 return HdChangeTracker::Clean;
925 }
926
927 void
_GenerateOriginGeometry(VtValue * topo,VtValue * points,GfRange3d const & extents) const928 UsdImagingGLDrawModeAdapter::_GenerateOriginGeometry(
929 VtValue *topo, VtValue *points, GfRange3d const& extents) const
930 {
931 // Origin: vertices are (0,0,0); (1,0,0); (0,1,0); (0,0,1)
932 VtVec3fArray pt = VtVec3fArray(4);
933 pt[0] = GfVec3f(0,0,0);
934 pt[1] = GfVec3f(1,0,0);
935 pt[2] = GfVec3f(0,1,0);
936 pt[3] = GfVec3f(0,0,1);
937 *points = VtValue(pt);
938
939 // segments are +X, +Y, +Z.
940 VtIntArray curveVertexCounts = VtIntArray(1);
941 curveVertexCounts[0] = 6;
942 VtIntArray curveIndices = VtIntArray(6);
943 const int indices[] = { 0, 1, 0, 2, 0, 3 };
944 for (int i = 0; i < 6; ++i) { curveIndices[i] = indices[i]; }
945
946 HdBasisCurvesTopology topology(
947 HdTokens->linear, HdTokens->bezier, HdTokens->segmented,
948 curveVertexCounts, curveIndices);
949 *topo = VtValue(topology);
950 }
951
952 void
_GenerateBoundsGeometry(VtValue * topo,VtValue * points,GfRange3d const & extents) const953 UsdImagingGLDrawModeAdapter::_GenerateBoundsGeometry(
954 VtValue *topo, VtValue *points, GfRange3d const& extents) const
955 {
956 // Bounding box: vertices are for(i: 0 -> 7) {
957 // ((i & 1) ? z : -z) +
958 // ((i & 2) ? y : -y) +
959 // ((i & 4) ? x : -x)
960 // } ... where x is extents[1].x, -x is extents[0].x
961 GfVec3f min = GfVec3f(extents.GetMin()),
962 max = GfVec3f(extents.GetMax());
963 VtVec3fArray pt = VtVec3fArray(8);
964 for(int i = 0; i < 8; ++i) {
965 pt[i] = GfVec3f((i & 4) ? max[0] : min[0],
966 (i & 2) ? max[1] : min[1],
967 (i & 1) ? max[2] : min[2]);
968 }
969 *points = VtValue(pt);
970
971 // Segments: CCW bottom face starting at (-x, -y, -z)
972 // CCW top face starting at (-x, -y, z)
973 // CCW vertical edges, starting at (-x, -y)
974 VtIntArray curveVertexCounts = VtIntArray(1);
975 curveVertexCounts[0] = 24;
976 VtIntArray curveIndices = VtIntArray(24);
977 const int indices[] = { /* bottom face */ 0, 4, 4, 6, 6, 2, 2, 0,
978 /* top face */ 1, 5, 5, 7, 7, 3, 3, 1,
979 /* edge pairs */ 0, 1, 4, 5, 6, 7, 2, 3 };
980 for (int i = 0; i < 24; ++i) { curveIndices[i] = indices[i]; }
981
982 HdBasisCurvesTopology topology(
983 HdTokens->linear, HdTokens->bezier, HdTokens->segmented,
984 curveVertexCounts, curveIndices);
985 *topo = VtValue(topology);
986 }
987
988 void
_GenerateCardsCrossGeometry(VtValue * topo,VtValue * points,GfRange3d const & extents,uint8_t axes_mask) const989 UsdImagingGLDrawModeAdapter::_GenerateCardsCrossGeometry(
990 VtValue *topo, VtValue *points, GfRange3d const& extents,
991 uint8_t axes_mask) const
992 {
993 // Generate one face per axis direction, for included axes.
994 const int numFaces = ((axes_mask & xAxis) ? 2 : 0) +
995 ((axes_mask & yAxis) ? 2 : 0) +
996 ((axes_mask & zAxis) ? 2 : 0);
997
998 // Cards (Cross) vertices:
999 // - +/-X vertices (CCW wrt +X)
1000 // - +/-Y vertices (CCW wrt +Y)
1001 // - +/-Z vertices (CCW wrt +Z)
1002 GfVec3f min = GfVec3f(extents.GetMin()),
1003 max = GfVec3f(extents.GetMax()),
1004 mid = (min+max)/2.0f;
1005
1006 VtVec3fArray pt = VtVec3fArray(numFaces * 4);
1007 int ptIdx = 0;
1008
1009 if (axes_mask & xAxis) {
1010 // +X
1011 pt[ptIdx++] = GfVec3f(mid[0], max[1], max[2]);
1012 pt[ptIdx++] = GfVec3f(mid[0], min[1], max[2]);
1013 pt[ptIdx++] = GfVec3f(mid[0], min[1], min[2]);
1014 pt[ptIdx++] = GfVec3f(mid[0], max[1], min[2]);
1015
1016 // -X
1017 pt[ptIdx++] = GfVec3f(mid[0], min[1], max[2]);
1018 pt[ptIdx++] = GfVec3f(mid[0], max[1], max[2]);
1019 pt[ptIdx++] = GfVec3f(mid[0], max[1], min[2]);
1020 pt[ptIdx++] = GfVec3f(mid[0], min[1], min[2]);
1021 }
1022
1023 if (axes_mask & yAxis) {
1024 // +Y
1025 pt[ptIdx++] = GfVec3f(min[0], mid[1], max[2]);
1026 pt[ptIdx++] = GfVec3f(max[0], mid[1], max[2]);
1027 pt[ptIdx++] = GfVec3f(max[0], mid[1], min[2]);
1028 pt[ptIdx++] = GfVec3f(min[0], mid[1], min[2]);
1029
1030 // -Y
1031 pt[ptIdx++] = GfVec3f(max[0], mid[1], max[2]);
1032 pt[ptIdx++] = GfVec3f(min[0], mid[1], max[2]);
1033 pt[ptIdx++] = GfVec3f(min[0], mid[1], min[2]);
1034 pt[ptIdx++] = GfVec3f(max[0], mid[1], min[2]);
1035 }
1036
1037 if (axes_mask & zAxis) {
1038 // +Z
1039 pt[ptIdx++] = GfVec3f(max[0], max[1], mid[2]);
1040 pt[ptIdx++] = GfVec3f(min[0], max[1], mid[2]);
1041 pt[ptIdx++] = GfVec3f(min[0], min[1], mid[2]);
1042 pt[ptIdx++] = GfVec3f(max[0], min[1], mid[2]);
1043
1044 // -Z
1045 pt[ptIdx++] = GfVec3f(min[0], max[1], mid[2]);
1046 pt[ptIdx++] = GfVec3f(max[0], max[1], mid[2]);
1047 pt[ptIdx++] = GfVec3f(max[0], min[1], mid[2]);
1048 pt[ptIdx++] = GfVec3f(min[0], min[1], mid[2]);
1049 }
1050
1051 VtIntArray faceCounts = VtIntArray(numFaces);
1052 VtIntArray faceIndices = VtIntArray(numFaces * 4);
1053 for (int i = 0; i < numFaces; ++i) {
1054 faceCounts[i] = 4;
1055 faceIndices[i*4+0] = i*4+0;
1056 faceIndices[i*4+1] = i*4+1;
1057 faceIndices[i*4+2] = i*4+2;
1058 faceIndices[i*4+3] = i*4+3;
1059 }
1060
1061 VtIntArray holeIndices(0);
1062
1063 HdMeshTopology topology(
1064 PxOsdOpenSubdivTokens->none, PxOsdOpenSubdivTokens->rightHanded,
1065 faceCounts, faceIndices, holeIndices);
1066
1067 *points = VtValue(pt);
1068 *topo = VtValue(topology);
1069 }
1070
1071 void
_SanityCheckFaceSizes(SdfPath const & cachePath,GfRange3d const & extents,uint8_t axes_mask) const1072 UsdImagingGLDrawModeAdapter::_SanityCheckFaceSizes(SdfPath const& cachePath,
1073 GfRange3d const& extents, uint8_t axes_mask) const
1074 {
1075 GfVec3d min = extents.GetMin(),
1076 max = extents.GetMax();
1077 bool zeroX = (min[0] == max[0]);
1078 bool zeroY = (min[1] == max[1]);
1079 bool zeroZ = (min[2] == max[2]);
1080
1081 if ((axes_mask & xAxis) && (zeroY || zeroZ)) {
1082 // XXX: validation
1083 TF_WARN("Cards rendering for <%s>: X+/X- faces have zero area.",
1084 cachePath.GetText());
1085 }
1086 if ((axes_mask & yAxis) && (zeroX || zeroZ)) {
1087 // XXX: validation
1088 TF_WARN("Cards rendering for <%s>: Y+/Y- faces have zero area.",
1089 cachePath.GetText());
1090 }
1091 if ((axes_mask & zAxis) && (zeroX || zeroY)) {
1092 // XXX: validation
1093 TF_WARN("Cards rendering for <%s>: Z+/Z- faces have zero area.",
1094 cachePath.GetText());
1095 }
1096 }
1097
1098 void
_GenerateCardsBoxGeometry(VtValue * topo,VtValue * points,GfRange3d const & extents,uint8_t axes_mask) const1099 UsdImagingGLDrawModeAdapter::_GenerateCardsBoxGeometry(
1100 VtValue *topo, VtValue *points, GfRange3d const& extents,
1101 uint8_t axes_mask) const
1102 {
1103 // Generate one face per axis direction, for included axes.
1104 const int numFaces = ((axes_mask & xAxis) ? 2 : 0) +
1105 ((axes_mask & yAxis) ? 2 : 0) +
1106 ((axes_mask & zAxis) ? 2 : 0);
1107
1108 // Bounding box: vertices are for(i: 0 -> 7) {
1109 // ((i & 1) ? z : -z) +
1110 // ((i & 2) ? y : -y) +
1111 // ((i & 4) ? x : -x)
1112 // } ... where x is extents[1].x, -x is extents[0].x
1113 GfVec3f min = GfVec3f(extents.GetMin()),
1114 max = GfVec3f(extents.GetMax());
1115
1116 VtVec3fArray pt = VtVec3fArray(numFaces * 4);
1117 int ptIdx = 0;
1118
1119 VtVec3fArray corners = VtVec3fArray(8);
1120 for(int i = 0; i < 8; ++i) {
1121 corners[i] = GfVec3f((i & 4) ? max[0] : min[0],
1122 (i & 2) ? max[1] : min[1],
1123 (i & 1) ? max[2] : min[2]);
1124 }
1125
1126 if (axes_mask & xAxis) {
1127 // +X
1128 pt[ptIdx++] = corners[7];
1129 pt[ptIdx++] = corners[5];
1130 pt[ptIdx++] = corners[4];
1131 pt[ptIdx++] = corners[6];
1132
1133 // -X
1134 pt[ptIdx++] = corners[1];
1135 pt[ptIdx++] = corners[3];
1136 pt[ptIdx++] = corners[2];
1137 pt[ptIdx++] = corners[0];
1138 }
1139
1140 if (axes_mask & yAxis) {
1141 // +Y
1142 pt[ptIdx++] = corners[3];
1143 pt[ptIdx++] = corners[7];
1144 pt[ptIdx++] = corners[6];
1145 pt[ptIdx++] = corners[2];
1146
1147 // -Y
1148 pt[ptIdx++] = corners[5];
1149 pt[ptIdx++] = corners[1];
1150 pt[ptIdx++] = corners[0];
1151 pt[ptIdx++] = corners[4];
1152 }
1153
1154 if (axes_mask & zAxis) {
1155 // +Z
1156 pt[ptIdx++] = corners[7];
1157 pt[ptIdx++] = corners[3];
1158 pt[ptIdx++] = corners[1];
1159 pt[ptIdx++] = corners[5];
1160
1161 // -Z
1162 pt[ptIdx++] = corners[2];
1163 pt[ptIdx++] = corners[6];
1164 pt[ptIdx++] = corners[4];
1165 pt[ptIdx++] = corners[0];
1166 }
1167
1168 *points = VtValue(pt);
1169
1170 VtIntArray faceCounts = VtIntArray(numFaces);
1171 VtIntArray faceIndices = VtIntArray(numFaces * 4);
1172 for (int i = 0; i < numFaces; ++i) {
1173 faceCounts[i] = 4;
1174 faceIndices[i*4+0] = i*4+0;
1175 faceIndices[i*4+1] = i*4+1;
1176 faceIndices[i*4+2] = i*4+2;
1177 faceIndices[i*4+3] = i*4+3;
1178 }
1179
1180 VtIntArray holeIndices(0);
1181
1182 HdMeshTopology topology(
1183 UsdGeomTokens->none, UsdGeomTokens->rightHanded,
1184 faceCounts, faceIndices, holeIndices);
1185
1186 *points = VtValue(pt);
1187 *topo = VtValue(topology);
1188 }
1189
1190 void
_GenerateCardsFromTextureGeometry(VtValue * topo,VtValue * points,VtValue * uv,VtValue * assign,GfRange3d * extents,UsdPrim const & prim) const1191 UsdImagingGLDrawModeAdapter::_GenerateCardsFromTextureGeometry(
1192 VtValue *topo, VtValue *points, VtValue *uv, VtValue *assign,
1193 GfRange3d *extents, UsdPrim const& prim) const
1194 {
1195 UsdGeomModelAPI model(prim);
1196 std::vector<std::pair<GfMatrix4d, int>> faces;
1197
1198 // Compute the face matrix/texture assignment pairs.
1199 GfMatrix4d mat;
1200 if (_GetMatrixFromImageMetadata(
1201 model.GetModelCardTextureXPosAttr(), &mat))
1202 faces.push_back(std::make_pair(mat, xPos));
1203 if (_GetMatrixFromImageMetadata(
1204 model.GetModelCardTextureYPosAttr(), &mat))
1205 faces.push_back(std::make_pair(mat, yPos));
1206 if (_GetMatrixFromImageMetadata(
1207 model.GetModelCardTextureZPosAttr(), &mat))
1208 faces.push_back(std::make_pair(mat, zPos));
1209 if (_GetMatrixFromImageMetadata(
1210 model.GetModelCardTextureXNegAttr(), &mat))
1211 faces.push_back(std::make_pair(mat, xNeg));
1212 if (_GetMatrixFromImageMetadata(
1213 model.GetModelCardTextureYNegAttr(), &mat))
1214 faces.push_back(std::make_pair(mat, yNeg));
1215 if (_GetMatrixFromImageMetadata(
1216 model.GetModelCardTextureZNegAttr(), &mat))
1217 faces.push_back(std::make_pair(mat, zNeg));
1218
1219 // Generate points, UV, and assignment primvars, plus index data.
1220 VtVec3fArray arr_pt = VtVec3fArray(faces.size() * 4);
1221 VtVec2fArray arr_uv = VtVec2fArray(faces.size() * 4);
1222 VtIntArray arr_assign = VtIntArray(faces.size());
1223 VtIntArray faceCounts = VtIntArray(faces.size());
1224 VtIntArray faceIndices = VtIntArray(faces.size() * 4);
1225
1226 static const std::array<GfVec3f, 4> corners = {
1227 GfVec3f(-1, -1, 0), GfVec3f(-1, 1, 0),
1228 GfVec3f( 1, 1, 0), GfVec3f( 1, -1, 0) };
1229 static const std::array<GfVec2f, 4> std_uvs =
1230 std::array<GfVec2f, 4>(
1231 {GfVec2f(0,1), GfVec2f(0,0), GfVec2f(1,0), GfVec2f(1,1) });
1232
1233 for(size_t i = 0; i < faces.size(); ++i) {
1234 GfMatrix4d screenToWorld = faces[i].first.GetInverse();
1235 faceCounts[i] = 4;
1236 arr_assign[i] = faces[i].second;
1237 for (size_t j = 0; j < 4; ++j) {
1238 faceIndices[i*4+j] = i*4+j;
1239 arr_pt[i*4+j] = screenToWorld.Transform(corners[j]);
1240 arr_uv[i*4+j] = std_uvs[j];
1241 }
1242 }
1243
1244 // Create the topology object, and put our buffers in the out-values.
1245 VtIntArray holeIndices(0);
1246 HdMeshTopology topology(
1247 UsdGeomTokens->none, UsdGeomTokens->rightHanded,
1248 faceCounts, faceIndices, holeIndices);
1249
1250 *topo = VtValue(topology);
1251 *points = VtValue(arr_pt);
1252 *uv = VtValue(arr_uv);
1253 *assign = VtValue(arr_assign);
1254
1255 // Compute extents from points.
1256 extents->SetEmpty();
1257 for (size_t i = 0; i < faces.size()*4; ++i) {
1258 extents->UnionWith(arr_pt[i]);
1259 }
1260 }
1261
1262 namespace
1263 {
1264
1265 template <class Vec>
1266 bool
_ConvertToMatrix(const Vec & mvec,GfMatrix4d * mat)1267 _ConvertToMatrix(const Vec &mvec, GfMatrix4d *mat)
1268 {
1269 if (mvec.size() == 16) {
1270 mat->Set(mvec[ 0], mvec[ 1], mvec[ 2], mvec[ 3],
1271 mvec[ 4], mvec[ 5], mvec[ 6], mvec[ 7],
1272 mvec[ 8], mvec[ 9], mvec[10], mvec[11],
1273 mvec[12], mvec[13], mvec[14], mvec[15]);
1274 return true;
1275 }
1276
1277 TF_WARN(
1278 "worldtoscreen metadata expected 16 values, got %zu",
1279 mvec.size());
1280 return false;
1281 };
1282
1283 }
1284
1285 bool
_GetMatrixFromImageMetadata(UsdAttribute const & attr,GfMatrix4d * mat) const1286 UsdImagingGLDrawModeAdapter::_GetMatrixFromImageMetadata(
1287 UsdAttribute const& attr, GfMatrix4d *mat) const
1288 {
1289 // This function expects the input attribute to be an image asset path.
1290 SdfAssetPath asset;
1291 attr.Get(&asset);
1292
1293 // If the literal path is empty, ignore this attribute.
1294 if (asset.GetAssetPath().empty()) {
1295 return false;
1296 }
1297
1298 std::string file = asset.GetResolvedPath();
1299 // Fallback to the literal path if it couldn't be resolved.
1300 if (file.empty()) {
1301 file = asset.GetAssetPath();
1302 }
1303
1304 HioImageSharedPtr img = HioImage::OpenForReading(file);
1305 if (!img) {
1306 return false;
1307 }
1308
1309 // Read the "worldtoscreen" metadata. This metadata specifies a 4x4
1310 // matrix but may be given as any the following data types, since
1311 // some image formats may support certain metadata types but not others.
1312 //
1313 // - std::vector<float> or std::vector<double> with 16 elements
1314 // in row major order.
1315 // - GfMatrix4f or GfMatrix4d
1316 VtValue worldtoscreen;
1317 if (img->GetMetadata(_tokens->worldtoscreen, &worldtoscreen)) {
1318 if (worldtoscreen.IsHolding<std::vector<float>>()) {
1319 return _ConvertToMatrix(
1320 worldtoscreen.UncheckedGet<std::vector<float>>(), mat);
1321 }
1322 else if (worldtoscreen.IsHolding<std::vector<double>>()) {
1323 return _ConvertToMatrix(
1324 worldtoscreen.UncheckedGet<std::vector<double>>(), mat);
1325 }
1326 else if (worldtoscreen.IsHolding<GfMatrix4f>()) {
1327 *mat = GfMatrix4d(worldtoscreen.UncheckedGet<GfMatrix4f>());
1328 return true;
1329 }
1330 else if (worldtoscreen.IsHolding<GfMatrix4d>()) {
1331 *mat = worldtoscreen.UncheckedGet<GfMatrix4d>();
1332 return true;
1333 }
1334 else {
1335 TF_WARN(
1336 "worldtoscreen metadata holding unexpected type '%s'",
1337 worldtoscreen.GetTypeName().c_str());
1338 }
1339 }
1340
1341 return false;
1342 }
1343
1344 static
1345 std::array<GfVec2f, 4>
_GetUVsForQuad(const bool flipU,bool flipV)1346 _GetUVsForQuad(const bool flipU, bool flipV)
1347 {
1348 return {
1349 GfVec2f(flipU ? 0.0 : 1.0, flipV ? 0.0 : 1.0),
1350 GfVec2f(flipU ? 1.0 : 0.0, flipV ? 0.0 : 1.0),
1351 GfVec2f(flipU ? 1.0 : 0.0, flipV ? 1.0 : 0.0),
1352 GfVec2f(flipU ? 0.0 : 1.0, flipV ? 1.0 : 0.0) };
1353 }
1354
1355 void
_GenerateTextureCoordinates(VtValue * uv,VtValue * assign,uint8_t axes_mask) const1356 UsdImagingGLDrawModeAdapter::_GenerateTextureCoordinates(
1357 VtValue *uv, VtValue *assign, uint8_t axes_mask) const
1358 {
1359 // This function generates a UV quad per face, with the correct orientation,
1360 // and also uniform indices for each face specifying which texture to
1361 // sample. The order is [X+, X-, Y+, Y-, Z+, Z-], possibly with some of
1362 // the axes omitted.
1363
1364 static const std::array<GfVec2f, 4> uv_normal =
1365 _GetUVsForQuad(false, false);
1366 static const std::array<GfVec2f, 4> uv_flipped_s =
1367 _GetUVsForQuad(true, false);
1368 static const std::array<GfVec2f, 4> uv_flipped_t =
1369 _GetUVsForQuad(false, true);
1370 static const std::array<GfVec2f, 4> uv_flipped_st =
1371 _GetUVsForQuad(true, true);
1372
1373 std::vector<const GfVec2f *> uv_faces;
1374 std::vector<int> face_assign;
1375 if (axes_mask & xAxis) {
1376 uv_faces.push_back(
1377 (axes_mask & xPos) ? uv_normal.data() : uv_flipped_s.data());
1378 face_assign.push_back((axes_mask & xPos) ? xPos : xNeg);
1379 uv_faces.push_back(
1380 (axes_mask & xNeg) ? uv_normal.data() : uv_flipped_s.data());
1381 face_assign.push_back((axes_mask & xNeg) ? xNeg : xPos);
1382 }
1383 if (axes_mask & yAxis) {
1384 uv_faces.push_back(
1385 (axes_mask & yPos) ? uv_normal.data() : uv_flipped_s.data());
1386 face_assign.push_back((axes_mask & yPos) ? yPos : yNeg);
1387 uv_faces.push_back(
1388 (axes_mask & yNeg) ? uv_normal.data() : uv_flipped_s.data());
1389 face_assign.push_back((axes_mask & yNeg) ? yNeg : yPos);
1390 }
1391 if (axes_mask & zAxis) {
1392 // (Z+) and (Z-) need to be flipped on the (t) axis instead of the (s)
1393 // axis when we're borrowing a texture from the other side of the axis.
1394 uv_faces.push_back(
1395 (axes_mask & zPos) ? uv_normal.data() : uv_flipped_t.data());
1396 face_assign.push_back((axes_mask & zPos) ? zPos : zNeg);
1397 uv_faces.push_back(
1398 (axes_mask & zNeg) ? uv_flipped_st.data() : uv_flipped_s.data());
1399 face_assign.push_back((axes_mask & zNeg) ? zNeg : zPos);
1400 }
1401
1402 VtVec2fArray faceUV = VtVec2fArray(uv_faces.size() * 4);
1403 for (size_t i = 0; i < uv_faces.size(); ++i) {
1404 memcpy(&faceUV[i*4], uv_faces[i], 4 * sizeof(GfVec2f));
1405 }
1406 *uv = VtValue(faceUV);
1407
1408 VtIntArray faceAssign = VtIntArray(face_assign.size());
1409 for (size_t i = 0; i < face_assign.size(); ++i) {
1410 faceAssign[i] = face_assign[i];
1411 }
1412 *assign = VtValue(faceAssign);
1413 }
1414
1415 GfRange3d
_ComputeExtent(UsdPrim const & prim,const UsdTimeCode & timecode) const1416 UsdImagingGLDrawModeAdapter::_ComputeExtent(UsdPrim const& prim,
1417 const UsdTimeCode& timecode) const
1418 {
1419 HD_TRACE_FUNCTION();
1420 HF_MALLOC_TAG_FUNCTION();
1421
1422 TfTokenVector purposes = { UsdGeomTokens->default_, UsdGeomTokens->proxy,
1423 UsdGeomTokens->render };
1424
1425 if (prim.IsLoaded()) {
1426 UsdGeomBBoxCache bboxCache(timecode, purposes, true);
1427 return bboxCache.ComputeUntransformedBound(prim).ComputeAlignedBox();
1428 } else {
1429 GfRange3d extent;
1430 UsdAttribute attr;
1431 VtVec3fArray extentsHint;
1432 // Get the extent either from the authored extent attribute of a
1433 // UsdGeomBoundable prim, or get the extentsHint attribute from the
1434 // prim.
1435 if (prim.IsA<UsdGeomBoundable>() &&
1436 (attr = UsdGeomBoundable(prim).GetExtentAttr()) &&
1437 attr.Get(&extentsHint, timecode) &&
1438 extentsHint.size() == 2) {
1439 extent = GfRange3d(extentsHint[0], extentsHint[1]);
1440 }
1441 else if ((attr = UsdGeomModelAPI(prim).GetExtentsHintAttr()) &&
1442 attr.Get(&extentsHint, timecode) &&
1443 extentsHint.size() >= 2) {
1444 // XXX: This code to merge the extentsHint values over a set of
1445 // purposes probably belongs in UsdGeomBBoxCache.
1446 const TfTokenVector &purposeTokens =
1447 UsdGeomImageable::GetOrderedPurposeTokens();
1448 for (size_t i = 0; i < purposeTokens.size(); ++i) {
1449 size_t idx = i*2;
1450 // If extents are not available for the value of purpose,
1451 // it implies that the rest of the bounds are empty.
1452 if ((idx + 2) > extentsHint.size())
1453 break;
1454 // If this purpose isn't one we are interested in, skip it.
1455 if (std::find(purposes.begin(), purposes.end(),
1456 purposeTokens[i]) == purposes.end())
1457 continue;
1458
1459 GfRange3d purposeExtent =
1460 GfRange3d(extentsHint[idx], extentsHint[idx+1]);
1461 // Extents for an unauthored geometry purpose may be empty,
1462 // even though the extent for a later purpose may exist.
1463 if (!purposeExtent.IsEmpty()) {
1464 extent.ExtendBy(purposeExtent);
1465 }
1466 }
1467 }
1468 return extent;
1469 }
1470 }
1471
1472 /*virtual*/
1473 HdCullStyle
GetCullStyle(UsdPrim const & prim,SdfPath const & cachePath,UsdTimeCode time) const1474 UsdImagingGLDrawModeAdapter::GetCullStyle(UsdPrim const& prim,
1475 SdfPath const& cachePath,
1476 UsdTimeCode time) const
1477 {
1478 return HdCullStyleBack;
1479 }
1480
1481 /*virtual*/
1482 GfMatrix4d
GetTransform(UsdPrim const & prim,SdfPath const & cachePath,UsdTimeCode time,bool ignoreRootTransform) const1483 UsdImagingGLDrawModeAdapter::GetTransform(UsdPrim const& prim,
1484 SdfPath const& cachePath,
1485 UsdTimeCode time,
1486 bool ignoreRootTransform) const
1487 {
1488 // If the draw mode is instantiated on an instance, prim will be
1489 // the instance prim, but we want to ignore transforms on that
1490 // prim since the instance adapter will handle them.
1491 if (prim.IsInstance()) {
1492 return GfMatrix4d(1.0);
1493 } else {
1494 return BaseAdapter::GetTransform(
1495 prim, prim.GetPath(), time, ignoreRootTransform);
1496 }
1497 }
1498
1499 PXR_NAMESPACE_CLOSE_SCOPE
1500