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