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/usd/usdShade/material.h"
25 #include "pxr/usd/usd/schemaRegistry.h"
26 #include "pxr/usd/usd/typed.h"
27
28 #include "pxr/usd/sdf/types.h"
29 #include "pxr/usd/sdf/assetPath.h"
30
31 PXR_NAMESPACE_OPEN_SCOPE
32
33 // Register the schema with the TfType system.
TF_REGISTRY_FUNCTION(TfType)34 TF_REGISTRY_FUNCTION(TfType)
35 {
36 TfType::Define<UsdShadeMaterial,
37 TfType::Bases< UsdShadeNodeGraph > >();
38
39 // Register the usd prim typename as an alias under UsdSchemaBase. This
40 // enables one to call
41 // TfType::Find<UsdSchemaBase>().FindDerivedByName("Material")
42 // to find TfType<UsdShadeMaterial>, which is how IsA queries are
43 // answered.
44 TfType::AddAlias<UsdSchemaBase, UsdShadeMaterial>("Material");
45 }
46
47 /* virtual */
~UsdShadeMaterial()48 UsdShadeMaterial::~UsdShadeMaterial()
49 {
50 }
51
52 /* static */
53 UsdShadeMaterial
Get(const UsdStagePtr & stage,const SdfPath & path)54 UsdShadeMaterial::Get(const UsdStagePtr &stage, const SdfPath &path)
55 {
56 if (!stage) {
57 TF_CODING_ERROR("Invalid stage");
58 return UsdShadeMaterial();
59 }
60 return UsdShadeMaterial(stage->GetPrimAtPath(path));
61 }
62
63 /* static */
64 UsdShadeMaterial
Define(const UsdStagePtr & stage,const SdfPath & path)65 UsdShadeMaterial::Define(
66 const UsdStagePtr &stage, const SdfPath &path)
67 {
68 static TfToken usdPrimTypeName("Material");
69 if (!stage) {
70 TF_CODING_ERROR("Invalid stage");
71 return UsdShadeMaterial();
72 }
73 return UsdShadeMaterial(
74 stage->DefinePrim(path, usdPrimTypeName));
75 }
76
77 /* virtual */
_GetSchemaKind() const78 UsdSchemaKind UsdShadeMaterial::_GetSchemaKind() const
79 {
80 return UsdShadeMaterial::schemaKind;
81 }
82
83 /* static */
84 const TfType &
_GetStaticTfType()85 UsdShadeMaterial::_GetStaticTfType()
86 {
87 static TfType tfType = TfType::Find<UsdShadeMaterial>();
88 return tfType;
89 }
90
91 /* static */
92 bool
_IsTypedSchema()93 UsdShadeMaterial::_IsTypedSchema()
94 {
95 static bool isTyped = _GetStaticTfType().IsA<UsdTyped>();
96 return isTyped;
97 }
98
99 /* virtual */
100 const TfType &
_GetTfType() const101 UsdShadeMaterial::_GetTfType() const
102 {
103 return _GetStaticTfType();
104 }
105
106 UsdAttribute
GetSurfaceAttr() const107 UsdShadeMaterial::GetSurfaceAttr() const
108 {
109 return GetPrim().GetAttribute(UsdShadeTokens->outputsSurface);
110 }
111
112 UsdAttribute
CreateSurfaceAttr(VtValue const & defaultValue,bool writeSparsely) const113 UsdShadeMaterial::CreateSurfaceAttr(VtValue const &defaultValue, bool writeSparsely) const
114 {
115 return UsdSchemaBase::_CreateAttr(UsdShadeTokens->outputsSurface,
116 SdfValueTypeNames->Token,
117 /* custom = */ false,
118 SdfVariabilityVarying,
119 defaultValue,
120 writeSparsely);
121 }
122
123 UsdAttribute
GetDisplacementAttr() const124 UsdShadeMaterial::GetDisplacementAttr() const
125 {
126 return GetPrim().GetAttribute(UsdShadeTokens->outputsDisplacement);
127 }
128
129 UsdAttribute
CreateDisplacementAttr(VtValue const & defaultValue,bool writeSparsely) const130 UsdShadeMaterial::CreateDisplacementAttr(VtValue const &defaultValue, bool writeSparsely) const
131 {
132 return UsdSchemaBase::_CreateAttr(UsdShadeTokens->outputsDisplacement,
133 SdfValueTypeNames->Token,
134 /* custom = */ false,
135 SdfVariabilityVarying,
136 defaultValue,
137 writeSparsely);
138 }
139
140 UsdAttribute
GetVolumeAttr() const141 UsdShadeMaterial::GetVolumeAttr() const
142 {
143 return GetPrim().GetAttribute(UsdShadeTokens->outputsVolume);
144 }
145
146 UsdAttribute
CreateVolumeAttr(VtValue const & defaultValue,bool writeSparsely) const147 UsdShadeMaterial::CreateVolumeAttr(VtValue const &defaultValue, bool writeSparsely) const
148 {
149 return UsdSchemaBase::_CreateAttr(UsdShadeTokens->outputsVolume,
150 SdfValueTypeNames->Token,
151 /* custom = */ false,
152 SdfVariabilityVarying,
153 defaultValue,
154 writeSparsely);
155 }
156
157 namespace {
158 static inline TfTokenVector
_ConcatenateAttributeNames(const TfTokenVector & left,const TfTokenVector & right)159 _ConcatenateAttributeNames(const TfTokenVector& left,const TfTokenVector& right)
160 {
161 TfTokenVector result;
162 result.reserve(left.size() + right.size());
163 result.insert(result.end(), left.begin(), left.end());
164 result.insert(result.end(), right.begin(), right.end());
165 return result;
166 }
167 }
168
169 /*static*/
170 const TfTokenVector&
GetSchemaAttributeNames(bool includeInherited)171 UsdShadeMaterial::GetSchemaAttributeNames(bool includeInherited)
172 {
173 static TfTokenVector localNames = {
174 UsdShadeTokens->outputsSurface,
175 UsdShadeTokens->outputsDisplacement,
176 UsdShadeTokens->outputsVolume,
177 };
178 static TfTokenVector allNames =
179 _ConcatenateAttributeNames(
180 UsdShadeNodeGraph::GetSchemaAttributeNames(true),
181 localNames);
182
183 if (includeInherited)
184 return allNames;
185 else
186 return localNames;
187 }
188
189 PXR_NAMESPACE_CLOSE_SCOPE
190
191 // ===================================================================== //
192 // Feel free to add custom code below this line. It will be preserved by
193 // the code generator.
194 //
195 // Just remember to wrap code in the appropriate delimiters:
196 // 'PXR_NAMESPACE_OPEN_SCOPE', 'PXR_NAMESPACE_CLOSE_SCOPE'.
197 // ===================================================================== //
198 // --(BEGIN CUSTOM CODE)--
199
200 #include "pxr/base/tf/token.h"
201
202 #include "pxr/usd/pcp/mapExpression.h"
203
204 #include "pxr/usd/sdf/path.h"
205
206 #include "pxr/usd/usd/editContext.h"
207 #include "pxr/usd/usd/specializes.h"
208 #include "pxr/usd/usd/primRange.h"
209 #include "pxr/usd/usd/variantSets.h"
210
211 #include "pxr/usd/usdShade/connectableAPI.h"
212 #include "pxr/usd/usdShade/connectableAPIBehavior.h"
213 #include "pxr/usd/usdShade/materialBindingAPI.h"
214 #include "pxr/usd/usdShade/output.h"
215 #include "pxr/usd/usdShade/tokens.h"
216 #include "pxr/usd/usdShade/utils.h"
217
218 #include <string>
219 #include <utility>
220 #include <vector>
221
222 PXR_NAMESPACE_OPEN_SCOPE
223
224 TF_DEFINE_PRIVATE_TOKENS(
225 _tokens,
226 (material)
227 );
228
229
230 std::pair<UsdStagePtr, UsdEditTarget >
GetEditContextForVariant(const TfToken & materialVariation,const SdfLayerHandle & layer) const231 UsdShadeMaterial::GetEditContextForVariant(const TfToken &materialVariation,
232 const SdfLayerHandle &layer) const
233 {
234 // First make sure localLayer belongs to the prim's stage
235 UsdPrim prim = GetPrim();
236 UsdStageWeakPtr stage = prim.GetStage();
237
238 UsdVariantSet materialVariant = prim.GetVariantSet(
239 UsdShadeTokens->materialVariant);
240 UsdEditTarget target = stage->GetEditTarget();
241 if (materialVariant.AddVariant(materialVariation) &&
242 materialVariant.SetVariantSelection(materialVariation)) {
243 target = materialVariant.GetVariantEditTarget(layer);
244 }
245
246 return std::make_pair(GetPrim().GetStage(), target);
247 }
248
249 // Somewhat surprised this isn't a method of SdfPath...
250 static
251 SdfPath
_GetRootPath(const UsdPrim & prim)252 _GetRootPath(const UsdPrim & prim)
253 {
254 SdfPath path = prim.GetPrimPath();
255
256 // special-case pseudo-root
257 if (path == SdfPath::AbsoluteRootPath())
258 return path;
259
260 while (!path.IsRootPrimPath())
261 path = path.GetParentPath();
262
263 return path;
264 }
265
266 UsdVariantSet
GetMaterialVariant() const267 UsdShadeMaterial::GetMaterialVariant() const
268 {
269 return GetPrim().GetVariantSet(UsdShadeTokens->materialVariant);
270 }
271
272 /* static */
273 bool
CreateMasterMaterialVariant(const UsdPrim & masterPrim,const std::vector<UsdPrim> & materials,const TfToken & masterVariantSetName)274 UsdShadeMaterial::CreateMasterMaterialVariant(const UsdPrim &masterPrim,
275 const std::vector<UsdPrim> &materials,
276 const TfToken &masterVariantSetName)
277 {
278 if (!masterPrim){
279 TF_CODING_ERROR("MasterPrim is not a valid UsdPrim.");
280 return false;
281 }
282 TfToken masterSetName = masterVariantSetName.IsEmpty() ?
283 UsdShadeTokens->materialVariant : masterVariantSetName;
284 UsdStagePtr stage = masterPrim.GetStage();
285 std::vector<std::string> allMaterialVariants;
286
287 // Error Checking!
288 if (materials.size() == 0){
289 TF_CODING_ERROR("No material prims specified on which to operate.");
290 return false;
291 }
292 TF_FOR_ALL(material, materials){
293 if (!*material){
294 TF_CODING_ERROR("Unable to process invalid material: %s",
295 material->GetDescription().c_str());
296 return false;
297 }
298 if (stage != material->GetStage()){
299 TF_CODING_ERROR("All material prims to be controlled by masterPrim "
300 "%s must originate on the same UsdStage as "
301 "masterPrim. Prim %s does not.",
302 masterPrim.GetPath().GetText(),
303 material->GetPrimPath().GetText());
304 return false;
305 }
306
307 std::vector<std::string> materialVariants =
308 material->GetVariantSet(
309 UsdShadeTokens->materialVariant).GetVariantNames();
310 if (materialVariants.size() == 0){
311 TF_CODING_ERROR("All Material prims to be switched by master "
312 "materialVariant must actually possess a "
313 "non-empty materialVariant themselves. %s does not.",
314 material->GetPrimPath().GetText());
315 return false;
316 }
317
318 if (allMaterialVariants.size() == 0){
319 allMaterialVariants.swap(materialVariants);
320 }
321 else if (allMaterialVariants != materialVariants){
322 TF_CODING_ERROR("All Material prims to be switched by master "
323 "materialVariant must possess the SAME material variants. "
324 "%s has a different set of variants.",
325 material->GetPrimPath().GetText());
326 return false;
327 }
328 }
329
330 UsdVariantSet masterSet = masterPrim.GetVariantSet(masterSetName);
331 TF_FOR_ALL(varName, allMaterialVariants){
332 if (!masterSet.AddVariant(*varName)){
333 TF_RUNTIME_ERROR("Unable to create Material variant %s on prim %s. "
334 "Aborting master materialVariant creation.",
335 varName->c_str(),
336 masterPrim.GetPath().GetText());
337 return false;
338 }
339 masterSet.SetVariantSelection(*varName);
340
341 {
342 UsdEditContext ctxt(masterSet.GetVariantEditContext());
343
344 TF_FOR_ALL(material, materials){
345 if (!*material){
346 // Somehow, switching the variant caused this prim
347 // to expire.
348 TF_RUNTIME_ERROR("Switching master variant %s to %s "
349 "caused one or more material prims to "
350 "expire. First such: %s.",
351 masterSetName.GetText(),
352 varName->c_str(),
353 material->GetDescription().c_str());
354 return false;
355 }
356
357 // Here's the heart of the whole thing
358 if (material->GetPath().HasPrefix(masterPrim.GetPath())){
359 material->GetVariantSet(
360 UsdShadeTokens->materialVariant).
361 SetVariantSelection(*varName);
362 }
363 else {
364 SdfPath derivedPath = material->GetPrimPath().
365 ReplacePrefix(_GetRootPath(*material), masterPrim.GetPath());
366 if (UsdPrim over = stage->OverridePrim(derivedPath)) {
367 over.GetVariantSet(
368 UsdShadeTokens->materialVariant).
369 SetVariantSelection(*varName);
370 }
371 else {
372 TF_RUNTIME_ERROR("Unable to create over for Material prim "
373 "%s, so cannot set its materialVariant",
374 derivedPath.GetText());
375 return false;
376 }
377 }
378 }
379 }
380 }
381
382 return true;
383 }
384
385 // --------------------------------------------------------------------- //
386
387 static
388 UsdShadeMaterial
_GetMaterialAtPath(const UsdPrim & prim,const SdfPath & path)389 _GetMaterialAtPath(
390 const UsdPrim & prim,
391 const SdfPath & path)
392 {
393 if (prim && !path.IsEmpty()) {
394 auto material =
395 UsdShadeMaterial(prim.GetStage()->GetPrimAtPath(path));
396 if (material) {
397 return material;
398 }
399 }
400 return UsdShadeMaterial();
401
402 }
403
404 UsdShadeMaterial
GetBaseMaterial() const405 UsdShadeMaterial::GetBaseMaterial() const
406 {
407 return _GetMaterialAtPath(GetPrim(), GetBaseMaterialPath());
408 }
409
410 SdfPath
GetBaseMaterialPath() const411 UsdShadeMaterial::GetBaseMaterialPath() const
412 {
413 SdfPath parentMaterialPath = FindBaseMaterialPathInPrimIndex(
414 GetPrim().GetPrimIndex(), [this](const SdfPath &p) {
415 return bool(_GetMaterialAtPath(GetPrim(), p));
416 });
417
418 if (parentMaterialPath != SdfPath::EmptyPath()) {
419 UsdPrim p = GetPrim().GetStage()->GetPrimAtPath(parentMaterialPath);
420 if (p.IsInstanceProxy()) {
421 // this looks like an instance but it's acting as the prototype path
422 // Return the prototype path
423 parentMaterialPath = p.GetPrimInPrototype().GetPath();
424 }
425 }
426 return parentMaterialPath;
427 }
428
429 /* static */
430 SdfPath
FindBaseMaterialPathInPrimIndex(const PcpPrimIndex & primIndex,const PathPredicate & pathIsMaterialPredicate)431 UsdShadeMaterial::FindBaseMaterialPathInPrimIndex(
432 const PcpPrimIndex & primIndex,
433 const PathPredicate & pathIsMaterialPredicate)
434 {
435 for(const PcpNodeRef &node: primIndex.GetNodeRange()) {
436 if (PcpIsSpecializeArc(node.GetArcType())) {
437 // We only consider children of the prim's root node because any
438 // specializes arc we care about that is authored inside referenced
439 // scene description will "imply" up into the root layer stack.
440 // This enables us to trim our search space, potentially
441 // significantly.
442 if (node.GetParentNode() != node.GetRootNode()) {
443 continue;
444 }
445
446 if (node.GetMapToParent().MapSourceToTarget(
447 SdfPath::AbsoluteRootPath()).IsEmpty()) {
448 // Skip this child node because it crosses a reference arc.
449 // (Reference mappings never map the absolute root path </>.)
450 continue;
451 }
452
453 // stop at the first one that's a material
454 const SdfPath & path = node.GetPath();
455 if (pathIsMaterialPredicate(path)) {
456 return path;
457 }
458 }
459 }
460 return SdfPath();
461 }
462
463 void
SetBaseMaterialPath(const SdfPath & baseMaterialPath) const464 UsdShadeMaterial::SetBaseMaterialPath(const SdfPath& baseMaterialPath) const
465 {
466 UsdSpecializes specializes = GetPrim().GetSpecializes();
467 if (baseMaterialPath.IsEmpty()) {
468 specializes.ClearSpecializes();
469 return;
470 }
471 // Only one specialize is allowed
472 SdfPathVector v = { baseMaterialPath };
473 specializes.SetSpecializes(v);
474 }
475
476 void
SetBaseMaterial(const UsdShadeMaterial & baseMaterial) const477 UsdShadeMaterial::SetBaseMaterial(const UsdShadeMaterial& baseMaterial) const
478 {
479 UsdPrim basePrim = baseMaterial.GetPrim();
480 if (basePrim.IsValid()) {
481 SdfPath basePath = basePrim.GetPath();
482 SetBaseMaterialPath(basePath);
483 } else {
484 SetBaseMaterialPath(SdfPath());
485 }
486 }
487
488 void
ClearBaseMaterial() const489 UsdShadeMaterial::ClearBaseMaterial() const
490 {
491 SetBaseMaterialPath(SdfPath());
492 }
493
494 bool
HasBaseMaterial() const495 UsdShadeMaterial::HasBaseMaterial() const
496 {
497 return !GetBaseMaterialPath().IsEmpty();
498 }
499
500 // --------------------------------------------------------------------- //
501 static
502 TfToken
_GetOutputName(const TfToken & baseName,const TfToken & renderContext)503 _GetOutputName(const TfToken &baseName, const TfToken &renderContext)
504 {
505 return TfToken(SdfPath::JoinIdentifier(renderContext, baseName));
506 }
507
508 UsdShadeAttributeVector
_ComputeNamedOutputSources(const TfToken & baseName,const TfTokenVector & contextVector) const509 UsdShadeMaterial::_ComputeNamedOutputSources(
510 const TfToken &baseName,
511 const TfTokenVector &contextVector) const
512 {
513 TRACE_FUNCTION();
514 bool universalRenderContextComputed = false;
515 for (TfToken const& renderContext : contextVector) {
516
517 universalRenderContextComputed |=
518 (renderContext == UsdShadeTokens->universalRenderContext);
519
520 const TfToken outputName = _GetOutputName(baseName, renderContext);
521 UsdShadeOutput output = GetOutput(outputName);
522 if (output) {
523 if (renderContext == UsdShadeTokens->universalRenderContext &&
524 !output.GetAttr().IsAuthored()) {
525 return {};
526 }
527
528 // See if this material output is connected to an upstream output
529 // of a shader.
530 // Note, by setting shaderOutputsOnly=true we do not accept upstream
531 // constant values, which can't be used by a renderer as a terminal
532 // node of the network. This also makes this call quite a bit cheaper.
533 UsdShadeAttributeVector valueAttrs =
534 UsdShadeUtils::GetValueProducingAttributes(
535 output, /*shaderOutputsOnly*/true);
536
537 // XXX To remove this limitation we need to change the APIs for the
538 // Compute*Source calls to forward multiple result attributes
539 if (valueAttrs.size() > 1) {
540 TF_WARN("Multiple connected sources for output %s:%s on material"
541 " %s. Only the first will be consider as a terminal.",
542 renderContext.GetText(), baseName.GetText(),
543 GetPath().GetText());
544 }
545 // If we didn't find any connected attributes continue checking the
546 // renderContexts, then as a fallback we will check the universal
547 // context below
548 if (!valueAttrs.empty()) {
549 return valueAttrs;
550 }
551 }
552 }
553
554 if (!universalRenderContextComputed) {
555 const TfToken universalOutputName = _GetOutputName(
556 baseName, UsdShadeTokens->universalRenderContext);
557 UsdShadeOutput universalOutput = GetOutput(universalOutputName);
558 if (TF_VERIFY(universalOutput)) {
559 return UsdShadeUtils::GetValueProducingAttributes(
560 universalOutput, /*shaderOutputsOnly*/true);
561 }
562 }
563
564 return {};
565 }
566
567 UsdShadeShader
_ComputeNamedOutputShader(const TfToken & baseName,const TfTokenVector & contextVector,TfToken * sourceName,UsdShadeAttributeType * sourceType) const568 UsdShadeMaterial::_ComputeNamedOutputShader(
569 const TfToken &baseName,
570 const TfTokenVector &contextVector,
571 TfToken *sourceName,
572 UsdShadeAttributeType *sourceType) const
573 {
574 UsdShadeAttributeVector valueAttrs =
575 _ComputeNamedOutputSources(baseName, contextVector);
576
577 if (valueAttrs.empty()) {
578 return UsdShadeShader();
579 }
580
581 if (sourceName || sourceType) {
582 TfToken srcName;
583 UsdShadeAttributeType srcType;
584 std::tie(srcName, srcType) =
585 UsdShadeUtils::GetBaseNameAndType(valueAttrs[0].GetName());
586 if (sourceName) {
587 *sourceName = srcName;
588 }
589 if (sourceType) {
590 *sourceType = srcType;
591 }
592 }
593
594 return UsdShadeShader(valueAttrs[0].GetPrim());
595 }
596
597 std::vector<UsdShadeOutput>
_GetOutputsForTerminalName(const TfToken & terminalName) const598 UsdShadeMaterial::_GetOutputsForTerminalName(const TfToken& terminalName) const
599 {
600 std::vector<UsdShadeOutput> outputs;
601
602 UsdShadeOutput universalOutput = GetOutput(
603 _GetOutputName(terminalName, UsdShadeTokens->universalRenderContext));
604 if (universalOutput) {
605 outputs.push_back(std::move(universalOutput));
606 }
607
608 for (const UsdShadeOutput& output : GetOutputs()) {
609 // For an output to be considered specific to a renderContext, its base
610 // name should be of the form "<renderContext>:...", so there must be
611 // at least two components to the base name.
612 const std::vector<std::string> baseNameComponents =
613 SdfPath::TokenizeIdentifier(output.GetBaseName());
614 if (baseNameComponents.size() < 2u) {
615 continue;
616 }
617
618 if (baseNameComponents.back() == terminalName) {
619 outputs.push_back(output);
620 }
621 }
622
623 return outputs;
624 }
625
626 UsdShadeOutput
CreateSurfaceOutput(const TfToken & renderContext) const627 UsdShadeMaterial::CreateSurfaceOutput(const TfToken &renderContext) const
628 {
629 return CreateOutput(_GetOutputName(UsdShadeTokens->surface, renderContext),
630 SdfValueTypeNames->Token);
631 }
632
633 UsdShadeOutput
GetSurfaceOutput(const TfToken & renderContext) const634 UsdShadeMaterial::GetSurfaceOutput(const TfToken &renderContext) const
635 {
636 return GetOutput(_GetOutputName(UsdShadeTokens->surface, renderContext));
637 }
638
639 std::vector<UsdShadeOutput>
GetSurfaceOutputs() const640 UsdShadeMaterial::GetSurfaceOutputs() const
641 {
642 return _GetOutputsForTerminalName(UsdShadeTokens->surface);
643 }
644
645 UsdShadeShader
ComputeSurfaceSource(const TfToken & renderContext,TfToken * sourceName,UsdShadeAttributeType * sourceType) const646 UsdShadeMaterial::ComputeSurfaceSource(
647 const TfToken &renderContext,
648 TfToken *sourceName,
649 UsdShadeAttributeType *sourceType) const
650 {
651 TRACE_FUNCTION();
652 return _ComputeNamedOutputShader(UsdShadeTokens->surface,
653 {renderContext}, sourceName, sourceType);
654 }
655
656 UsdShadeShader
ComputeSurfaceSource(const TfTokenVector & contextVector,TfToken * sourceName,UsdShadeAttributeType * sourceType) const657 UsdShadeMaterial::ComputeSurfaceSource(
658 const TfTokenVector &contextVector,
659 TfToken *sourceName,
660 UsdShadeAttributeType *sourceType) const
661 {
662 TRACE_FUNCTION();
663 return _ComputeNamedOutputShader(UsdShadeTokens->surface,
664 contextVector, sourceName, sourceType);
665 }
666
667 UsdShadeOutput
CreateDisplacementOutput(const TfToken & renderContext) const668 UsdShadeMaterial::CreateDisplacementOutput(const TfToken &renderContext) const
669 {
670 return CreateOutput(_GetOutputName(UsdShadeTokens->displacement, renderContext),
671 SdfValueTypeNames->Token);
672 }
673
674 UsdShadeOutput
GetDisplacementOutput(const TfToken & renderContext) const675 UsdShadeMaterial::GetDisplacementOutput(const TfToken &renderContext) const
676 {
677 return GetOutput(_GetOutputName(UsdShadeTokens->displacement, renderContext));
678 }
679
680 std::vector<UsdShadeOutput>
GetDisplacementOutputs() const681 UsdShadeMaterial::GetDisplacementOutputs() const
682 {
683 return _GetOutputsForTerminalName(UsdShadeTokens->displacement);
684 }
685
686 UsdShadeShader
ComputeDisplacementSource(const TfToken & renderContext,TfToken * sourceName,UsdShadeAttributeType * sourceType) const687 UsdShadeMaterial::ComputeDisplacementSource(
688 const TfToken &renderContext,
689 TfToken *sourceName,
690 UsdShadeAttributeType *sourceType) const
691 {
692 TRACE_FUNCTION();
693 return _ComputeNamedOutputShader(UsdShadeTokens->displacement,
694 {renderContext}, sourceName, sourceType);
695 }
696
697 UsdShadeShader
ComputeDisplacementSource(const TfTokenVector & contextVector,TfToken * sourceName,UsdShadeAttributeType * sourceType) const698 UsdShadeMaterial::ComputeDisplacementSource(
699 const TfTokenVector &contextVector,
700 TfToken *sourceName,
701 UsdShadeAttributeType *sourceType) const
702 {
703 TRACE_FUNCTION();
704 return _ComputeNamedOutputShader(UsdShadeTokens->displacement,
705 contextVector, sourceName, sourceType);
706 }
707
708 UsdShadeOutput
CreateVolumeOutput(const TfToken & renderContext) const709 UsdShadeMaterial::CreateVolumeOutput(const TfToken &renderContext) const
710 {
711 return CreateOutput(_GetOutputName(UsdShadeTokens->volume, renderContext),
712 SdfValueTypeNames->Token);
713 }
714
715 UsdShadeOutput
GetVolumeOutput(const TfToken & renderContext) const716 UsdShadeMaterial::GetVolumeOutput(const TfToken &renderContext) const
717 {
718 return GetOutput(_GetOutputName(UsdShadeTokens->volume, renderContext));
719 }
720
721 std::vector<UsdShadeOutput>
GetVolumeOutputs() const722 UsdShadeMaterial::GetVolumeOutputs() const
723 {
724 return _GetOutputsForTerminalName(UsdShadeTokens->volume);
725 }
726
727 UsdShadeShader
ComputeVolumeSource(const TfToken & renderContext,TfToken * sourceName,UsdShadeAttributeType * sourceType) const728 UsdShadeMaterial::ComputeVolumeSource(
729 const TfToken &renderContext,
730 TfToken *sourceName,
731 UsdShadeAttributeType *sourceType) const
732 {
733 TRACE_FUNCTION();
734 return _ComputeNamedOutputShader(UsdShadeTokens->volume, {renderContext},
735 sourceName, sourceType);
736 }
737
738 UsdShadeShader
ComputeVolumeSource(const TfTokenVector & contextVector,TfToken * sourceName,UsdShadeAttributeType * sourceType) const739 UsdShadeMaterial::ComputeVolumeSource(
740 const TfTokenVector &contextVector,
741 TfToken *sourceName,
742 UsdShadeAttributeType *sourceType) const
743 {
744 TRACE_FUNCTION();
745 return _ComputeNamedOutputShader(UsdShadeTokens->volume, contextVector,
746 sourceName, sourceType);
747 }
748
749 class UsdShadeMaterial_ConnectableAPIBehavior :
750 public UsdShadeConnectableAPIBehavior
751 {
752 public:
753 // By default all Material Connectable Behavior should be
754 // container (of nodes) and exhibit encapsulation behavior.
UsdShadeMaterial_ConnectableAPIBehavior()755 UsdShadeMaterial_ConnectableAPIBehavior() : UsdShadeConnectableAPIBehavior(
756 true /*isContainer*/, true /*requiresEncapsulation*/) {}
757 bool
CanConnectInputToSource(const UsdShadeInput & input,const UsdAttribute & source,std::string * reason) const758 CanConnectInputToSource(const UsdShadeInput &input,
759 const UsdAttribute &source,
760 std::string *reason) const override
761 {
762 return _CanConnectInputToSource(input, source, reason,
763 ConnectableNodeTypes::DerivedContainerNodes);
764 }
765
766 bool
CanConnectOutputToSource(const UsdShadeOutput & output,const UsdAttribute & source,std::string * reason) const767 CanConnectOutputToSource(const UsdShadeOutput &output,
768 const UsdAttribute &source,
769 std::string *reason) const override
770 {
771 return _CanConnectOutputToSource(output, source, reason,
772 ConnectableNodeTypes::DerivedContainerNodes);
773 }
774 };
775
TF_REGISTRY_FUNCTION(UsdShadeConnectableAPI)776 TF_REGISTRY_FUNCTION(UsdShadeConnectableAPI)
777 {
778 UsdShadeRegisterConnectableAPIBehavior<UsdShadeMaterial,
779 UsdShadeMaterial_ConnectableAPIBehavior>();
780 }
781
782
783 PXR_NAMESPACE_CLOSE_SCOPE
784