Skip to content

Commit

Permalink
Updates to the SdrShaderNodes that are generated for concrete UsdLux …
Browse files Browse the repository at this point in the history
…types

1. SdrShaderNodes are only generated for concrete UsdLux library light types. We no longer generate nodes for the empty UsdLuxLightFilter and therefore any light filters.
2. ShadowAPI and ShapingAPI input attributes are now included in every light type's shader node.
3. The shader nodes for these lights will no longer include inputs that come from auto-applied API schemas (like the auto applied rman API schemas).

(Internal change: 2189986)
  • Loading branch information
pixar-oss committed Sep 23, 2021
1 parent 82981a9 commit 2c060ec
Show file tree
Hide file tree
Showing 5 changed files with 207 additions and 108 deletions.
31 changes: 9 additions & 22 deletions pxr/usd/usdLux/discoveryPlugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,9 @@

#include "pxr/usd/usdLux/boundableLightBase.h"
#include "pxr/usd/usdLux/lightDefParser.h"
#include "pxr/usd/usdLux/lightFilter.h"
#include "pxr/usd/usdLux/nonboundableLightBase.h"

#include "pxr/base/plug/registry.h"
#include "pxr/base/plug/thisPlugin.h"
#include "pxr/base/plug/plugin.h"
#include "pxr/base/tf/staticTokens.h"

Expand All @@ -43,42 +42,30 @@ UsdLux_DiscoveryPlugin::GetSearchURIs() const
return empty;
}

TF_DEFINE_PRIVATE_TOKENS(
_tokens,

(usdLux)
);

NdrNodeDiscoveryResultVec
UsdLux_DiscoveryPlugin::DiscoverNodes(const Context &context)
{
NdrNodeDiscoveryResultVec result;

// We want to discover nodes for all concrete schema types that derive from
// UsdLuxBoundableLightBase, UsdLuxNonboundableLightBase, and
// UsdLuxLightFilter.
// UsdLuxBoundableLightBase and UsdLuxNonboundableLightBase. We'll filter
// out types that aren't defined in UsdLux as we process them.
static const TfType boundableLightType =
TfType::Find<UsdLuxBoundableLightBase>();
static const TfType nonboundableLightType =
TfType::Find<UsdLuxNonboundableLightBase>();
static const TfType lightFilterType = TfType::Find<UsdLuxLightFilter>();
// LightFilter is a concrete type and is legit to instantiate while light
// base types are abstract and cannot be instantiated. LightFilter must be
// included in the discovery types.
std::set<TfType> types({lightFilterType});

std::set<TfType> types;
PlugRegistry::GetAllDerivedTypes(boundableLightType, &types);
PlugRegistry::GetAllDerivedTypes(nonboundableLightType, &types);
PlugRegistry::GetAllDerivedTypes(lightFilterType, &types);

for (const TfType &type : types) {
static const PlugRegistry &plugRegistry = PlugRegistry::GetInstance();
const PlugPluginPtr &plugin = plugRegistry.GetPluginForType(type);
if (!plugin) {
continue;
}
if (_tokens->usdLux != plugin->GetName()) {
// Filter out types that weren't declared in the UsdLux library itself.
static PlugPluginPtr thisPlugin = PLUG_THIS_PLUGIN;
if (!thisPlugin->DeclaresType(type)) {
continue;
}

const TfToken name = UsdSchemaRegistry::GetConcreteSchemaTypeName(type);
// The type name from the schema registry will be empty if the type is
// not concrete (i.e. abstract); we skip abstract types.
Expand Down
5 changes: 2 additions & 3 deletions pxr/usd/usdLux/discoveryPlugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,8 @@ PXR_NAMESPACE_OPEN_SCOPE

/// \class UsdLux_DiscoveryPlugin
///
/// Discovers nodes for corresponding concrete light and light filter types that
/// come from derived UsdLuxBoundableLightBase, UsdLuxNonboundableLightBase, and
/// UsdLuxLightFilter schema classes.
/// Discovers nodes for corresponding concrete light types that are defined in
/// the UsdLux library.
///
class UsdLux_DiscoveryPlugin : public NdrDiscoveryPlugin {
public:
Expand Down
143 changes: 108 additions & 35 deletions pxr/usd/usdLux/lightDefParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,17 @@
#include "pxr/usd/usdLux/lightDefParser.h"

#include "pxr/usd/usdLux/boundableLightBase.h"
#include "pxr/usd/usdLux/lightFilter.h"
#include "pxr/usd/usdLux/nonboundableLightBase.h"

#include "pxr/usd/usdShade/connectableAPI.h"
#include "pxr/usd/usdShade/shaderDefUtils.h"
#include "pxr/usd/usdShade/tokens.h"
#include "pxr/usd/sdf/copyUtils.h"
#include "pxr/usd/sdr/shaderNode.h"

#include "pxr/base/plug/plugin.h"
#include "pxr/base/plug/thisPlugin.h"

PXR_NAMESPACE_OPEN_SCOPE

TF_DEFINE_PRIVATE_TOKENS(
Expand All @@ -40,6 +43,10 @@ TF_DEFINE_PRIVATE_TOKENS(
/* discoveryTypes */
((sourceType, "USD"))
((discoveryType, "usd-schema-gen"))

(LightAPI)
(ShadowAPI)
(ShapingAPI)
);

/*static*/
Expand Down Expand Up @@ -74,61 +81,127 @@ _GetSdrMetadata(const UsdShadeConnectableAPI &connectable,
return metadata;
}

NdrNodeUniquePtr
static SdfLayerRefPtr
_GetGeneratedSchema()
{
// Get the generateSchema file for this plugin and open it as a layer.
const std::string fname =
PLUG_THIS_PLUGIN->FindPluginResource("generatedSchema.usda", false);
SdfLayerRefPtr layer = SdfLayer::OpenAsAnonymous(fname);
return layer;
}

static bool
_CopyPropertiesFromSchema(
const SdfLayerRefPtr &schemaLayer, const TfToken &schemaName,
const SdfPrimSpecHandle &destPrimSpec)
{
// The path of schema prim in the generated schema layer is its schema name.
const SdfPath schemaPath =
SdfPath::AbsoluteRootPath().AppendChild(schemaName);
SdfPrimSpecHandle schemaSpec = schemaLayer->GetPrimAtPath(schemaPath);
if (!schemaSpec) {
TF_CODING_ERROR("The generatedSchema for UsdLux does not have a prim "
"spec for schema type '%s'.",
schemaName.GetText());
return false;
}

const SdfLayerHandle destLayer = destPrimSpec->GetLayer();
const SdfPath destPath = destPrimSpec->GetPath();
// Copy all the schema's properties to the destination.
for (const SdfPropertySpecHandle &propSpec : schemaSpec->GetProperties()) {
if (!SdfCopySpec(schemaLayer, propSpec->GetPath(),
destLayer, destPath.AppendProperty(propSpec->GetNameToken()))) {
TF_CODING_ERROR("Could not copy property spec '%s' from "
"generatedSchema for UsdLux schema '%s' to "
"destination layer.",
propSpec->GetPath().GetText(),
schemaName.GetText());
return false;
}
}
return true;
}

NdrNodeUniquePtr
UsdLux_LightDefParserPlugin::Parse(
const NdrNodeDiscoveryResult &discoveryResult)
{
TRACE_FUNCTION();

// This parser wants to pull all the shader properties from the schema
// defined properties for light or light filter type. The simplest way to
// do this is to create a stage with a single prim of the type and use the
// defined properties of the base UsdLux light type as well as the shader
// properties that can be included via applying the Shadow and Shaping APIs.
// However, it does NOT want to pull in any shader properties that could
// possibly come in from other plugins that may define API schemas that
// would auto apply to any of these lights (or to the LightAPI itself).
//
// Since the UsdSchemaRegistry doesn't keep track of what built-in API
// schemas a type's properties come from, we have to manually figure out the
// relevant properties from the UsdLux library's generatedSchema layer and
// compose them into a new prim that will represent the base light
// definition. This prim can then be opened on a stage in order to use the
// UsdShadeConnectableAPI to get all the inputs and outputs.

// Note, that we create the layer and author the prim spec using the Sdf API
// before opening a stage as opposed to creating a stage first and using
// the Usd DefinePrim API. This is to guard against any potential for this
// parser being called indirectly within an SdfChangeBlock which can cause
// DefinePrim to fail.
static const SdfPath primPath("/Prim");
// Find and open the generated schema layer.
SdfLayerRefPtr schemaLayer = _GetGeneratedSchema();
if (!schemaLayer) {
return NdrParserPlugin::GetInvalidNode(discoveryResult);
}

// Since we're composing the prim ourselves create a new layer and prim
// spec where we'll add all the properties.
SdfLayerRefPtr layer = SdfLayer::CreateAnonymous(".usd");
SdfPrimSpec::New(layer, primPath.GetName(),
SdfSpecifierDef, discoveryResult.identifier);
SdfPrimSpecHandle primSpec = SdfPrimSpec::New(
layer, discoveryResult.identifier, SdfSpecifierDef);

// All of the UsdLux intrinsic lights will directly include LightAPI so it
// will have all the properties from LightAPI as well as any it defines
// itself. We also need to include the ShadowAPI and ShapingAPI properties
// as these can be optionally applied to any light. We copy the properties
// from each of the schema type prim specs over to the composed prim spec.
// Note, that the order we copy is important as the light type itself may
// have properties that override properties that come from the LightAPI.
const TfTokenVector schemas({
_tokens->LightAPI,
discoveryResult.identifier,
_tokens->ShadowAPI,
_tokens->ShapingAPI});
for (const TfToken &schemaName : schemas) {
// It's important that we copy just the properties. Prim fields like
// the typeName, apiSchemas, and the property children can affect what
// properties are included when we open this prim on a USD stage.
if (!_CopyPropertiesFromSchema(schemaLayer, schemaName, primSpec)) {
return NdrParserPlugin::GetInvalidNode(discoveryResult);
}
}

// Open a stage with the layer and get the new prim as a UsdConnectableAPI
// which we'll create the node from.
UsdStageRefPtr stage = UsdStage::Open(layer, nullptr);
if (!stage) {
return NdrParserPlugin::GetInvalidNode(discoveryResult);
}

UsdPrim prim = stage->GetPrimAtPath(primPath);
UsdPrim prim = stage->GetPrimAtPath(primSpec->GetPath());
if (!prim) {
return NdrParserPlugin::GetInvalidNode(discoveryResult);
}

// Note that we don't check the "conformance" of this prim to the
// connectable API because the prim is untyped and will not conform. But
// conformance isn't necessary for using UsdShadeConnectableAPI in order
// to get input and output properties from a prim as is require in the
// functions called below.
UsdShadeConnectableAPI connectable(prim);
if (!connectable) {
return NdrParserPlugin::GetInvalidNode(discoveryResult);
}

TfToken context;
if (prim.IsA<UsdLuxBoundableLightBase>() ||
prim.IsA<UsdLuxNonboundableLightBase>()) {
context = SdrNodeContext->Light;
} else if (prim.IsA<UsdLuxLightFilter>()) {
context = SdrNodeContext->LightFilter;
} else {
TF_CODING_ERROR("Cannot parse a USD shader node for schema type '%s'; "
"schema type '%s' is not a light or light filter.",
discoveryResult.identifier.GetText(),
discoveryResult.identifier.GetText());
return nullptr;
}

return NdrNodeUniquePtr(new SdrShaderNode(
discoveryResult.identifier,
discoveryResult.identifier,
discoveryResult.version,
discoveryResult.name,
discoveryResult.family,
context,
SdrNodeContext->Light,
discoveryResult.sourceType,
/*nodeUriAssetPath=*/ std::string(),
/*nodeUriAssetPath=*/ std::string(),
/*resolvedImplementationUri=*/ std::string(),
UsdShadeShaderDefUtils::GetShaderProperties(connectable),
_GetSdrMetadata(connectable, discoveryResult.metadata),
Expand Down
3 changes: 1 addition & 2 deletions pxr/usd/usdLux/lightDefParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,7 @@ PXR_NAMESPACE_OPEN_SCOPE
/// \class UsdLux_LightDefParserPlugin
///
/// Parses shader definitions from the registered prim definitions for
/// UsdLuxBoundableLightBase, UsdLuxNonboundableLightBase, and UsdLuxLightFilter
/// derived schema classes.
/// the UsdLux intrinsic concrete light types.
///
class UsdLux_LightDefParserPlugin : public NdrParserPlugin
{
Expand Down
Loading

0 comments on commit 2c060ec

Please sign in to comment.