void UsdImagingGprimAdapter::_DiscoverPrimvars(UsdGeomGprim const& gprim, SdfPath const& cachePath, UsdShadeShader const& shader, UsdTimeCode time, UsdImagingValueCache* valueCache) { // TODO: It might be convenient to implicitly wire up PtexFaceOffset and // PtexFaceIndex primvars. TF_DEBUG(USDIMAGING_SHADERS).Msg("\t Looking for <%s> primvars at <%s>\n", gprim.GetPrim().GetPath().GetText(), shader.GetPrim().GetPath().GetText()); for (UsdShadeParameter const& param : shader.GetParameters()) { UsdShadeShader source; TfToken outputName; if (param.GetConnectedSource(&source, &outputName)) { UsdAttribute attr = source.GetIdAttr(); TfToken id; if (not attr or not attr.Get(&id)) { continue; } TF_DEBUG(USDIMAGING_SHADERS).Msg("\t\t Param <%s> connected <%s>(%s)\n", param.GetAttr().GetName().GetText(), source.GetPath().GetText(), id.GetText()); if (id == UsdHydraTokens->HwPrimvar_1) { TfToken t; VtValue v; UsdGeomPrimvar primvarAttr; if (UsdHydraPrimvar(source).GetVarnameAttr().Get(&t, UsdTimeCode::Default())) { primvarAttr = gprim.GetPrimvar(t); if (primvarAttr.ComputeFlattened(&v, time)) { TF_DEBUG(USDIMAGING_SHADERS).Msg("Found primvar %s\n", t.GetText()); UsdImagingValueCache::PrimvarInfo primvar; primvar.name = t; primvar.interpolation = primvarAttr.GetInterpolation(); valueCache->GetPrimvar(cachePath, t) = v; _MergePrimvar(primvar, &valueCache->GetPrimvars(cachePath)); } else { TF_DEBUG(USDIMAGING_SHADERS).Msg( "\t\t No primvar on <%s> named %s\n", gprim.GetPath().GetText(), t.GetText()); } } } else { // Recursively look for more primvars _DiscoverPrimvars(gprim, cachePath, source, time, valueCache); } } } }
// Walk the shader graph and emit nodes in topological order // to avoid forward-references. static void _WalkGraph(UsdShadeShader const & shadeNode, HdMaterialNetwork *materialNetwork, const TfTokenVector &shaderSourceTypes) { // Store the path of the node HdMaterialNode node; node.path = shadeNode.GetPath(); if (!TF_VERIFY(node.path != SdfPath::EmptyPath())) { return; } // If this node has already been found via another path, we do // not need to add it again. for (HdMaterialNode const& existingNode: materialNetwork->nodes) { if (existingNode.path == node.path) { return; } } // Visit the inputs of this node to ensure they are emitted first. const std::vector<UsdShadeInput> shadeNodeInputs = shadeNode.GetInputs(); for (UsdShadeInput const& input: shadeNodeInputs) { // Check if this input is a connection and if so follow the path UsdShadeConnectableAPI source; TfToken sourceName; UsdShadeAttributeType sourceType; if (UsdShadeConnectableAPI::GetConnectedSource(input, &source, &sourceName, &sourceType)) { // When we find a connection to a shading node output, // walk the upstream shading node. Do not do this for // other sources (ex: a connection to a material // public interface parameter), since they are not // part of the shading node graph. if (sourceType == UsdShadeAttributeType::Output) { UsdShadeShader connectedNode(source); _WalkGraph(connectedNode, materialNetwork, shaderSourceTypes); } } } // Extract the identifier of the node TfToken id; if (!shadeNode.GetShaderId(&id)) { for (auto &sourceType : shaderSourceTypes) { if (SdrShaderNodeConstPtr n = shadeNode.GetShaderNodeForSourceType(sourceType)) { id = n->GetIdentifier(); break; } } } if (!id.IsEmpty()) { node.identifier = id; // If a node is recognizable, we will try to extract the primvar // names that is using since this can help render delegates // optimize what what is needed from a prim when making data // accessible for renderers. _ExtractPrimvarsFromNode(shadeNode, node, materialNetwork); } else { TF_WARN("UsdShade Shader without an id: %s.", node.path.GetText()); node.identifier = TfToken("PbsNetworkMaterialStandIn_2"); } // Add the parameters and the relationships of this node VtValue value; for (UsdShadeInput const& input: shadeNodeInputs) { // Check if this input is a connection and if so follow the path UsdShadeConnectableAPI source; TfToken sourceName; UsdShadeAttributeType sourceType; if (UsdShadeConnectableAPI::GetConnectedSource(input, &source, &sourceName, &sourceType)) { if (sourceType == UsdShadeAttributeType::Output) { // Store the relationship HdMaterialRelationship relationship; relationship.outputId = shadeNode.GetPath(); relationship.outputName = input.GetBaseName(); relationship.inputId = source.GetPath(); relationship.inputName = sourceName; materialNetwork->relationships.push_back(relationship); } else if (sourceType == UsdShadeAttributeType::Input) { // Connected to an input on the public interface. // The source is not a node in the shader network, so // pull the value and pass it in as a parameter. if (UsdShadeInput connectedInput = source.GetInput(sourceName)) { if (connectedInput.Get(&value)) { node.parameters[input.GetBaseName()] = value; } } } } else { // Parameters detected, let's store it if (input.Get(&value)) { node.parameters[input.GetBaseName()] = value; } } } materialNetwork->nodes.push_back(node); }