Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MAYA-104987 Allows converting preview surface to Maya native shaders #707

Merged
merged 4 commits into from
Aug 26, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions lib/mayaUsd/commands/baseImportCommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ MayaUSDImportCommand::createSyntax()
syntax.addFlag(kShadingModeFlag,
UsdMayaJobImportArgsTokens->shadingMode.GetText(),
MSyntax::kString);
syntax.addFlag(kShadingConversionFlag,
UsdMayaJobImportArgsTokens->shadingConversion.GetText(),
MSyntax::kString);
syntax.addFlag(kAssemblyRepFlag,
UsdMayaJobImportArgsTokens->assemblyRep.GetText(),
MSyntax::kString);
Expand Down
1 change: 1 addition & 0 deletions lib/mayaUsd/commands/baseImportCommand.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class MAYAUSD_CORE_PUBLIC MayaUSDImportCommand : public MPxCommand
//
// The list of short forms of flags defined as Arg Tokens:
static constexpr auto kShadingModeFlag = "shd";
static constexpr auto kShadingConversionFlag = "shc";
static constexpr auto kAssemblyRepFlag = "ar";
static constexpr auto kMetadataFlag = "md";
static constexpr auto kApiSchemaFlag = "api";
Expand Down
8 changes: 8 additions & 0 deletions lib/mayaUsd/fileio/jobs/jobArgs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -561,6 +561,11 @@ UsdMayaJobImportArgs::UsdMayaJobImportArgs(
UsdMayaJobImportArgsTokens->shadingMode,
UsdMayaShadingModeTokens->none,
UsdMayaShadingModeRegistry::ListImporters())),
shadingConversion(
_Token(userArgs,
UsdMayaJobImportArgsTokens->shadingConversion,
UsdMayaShadingConversionTokens->none,
UsdMayaShadingConversionTokens->allTokens)),
useAsAnimationCache(
_Boolean(userArgs,
UsdMayaJobImportArgsTokens->useAsAnimationCache)),
Expand Down Expand Up @@ -601,6 +606,8 @@ const VtDictionary& UsdMayaJobImportArgs::GetDefaultDictionary()
});
d[UsdMayaJobImportArgsTokens->shadingMode] =
UsdMayaShadingModeTokens->displayColor.GetString();
d[UsdMayaJobImportArgsTokens->shadingConversion] =
UsdMayaShadingConversionTokens->lambert.GetString();
d[UsdMayaJobImportArgsTokens->useAsAnimationCache] = false;

// plugInfo.json site defaults.
Expand All @@ -619,6 +626,7 @@ std::ostream&
operator <<(std::ostream& out, const UsdMayaJobImportArgs& importArgs)
{
out << "shadingMode: " << importArgs.shadingMode << std::endl
<< "shadingConversion: " << importArgs.shadingConversion << std::endl
<< "assemblyRep: " << importArgs.assemblyRep << std::endl
<< "timeInterval: " << importArgs.timeInterval << std::endl
<< "useAsAnimationCache: " << TfStringify(importArgs.useAsAnimationCache) << std::endl
Expand Down
2 changes: 2 additions & 0 deletions lib/mayaUsd/fileio/jobs/jobArgs.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ TF_DECLARE_PUBLIC_TOKENS(
(excludePrimvar) \
(metadata) \
(shadingMode) \
(shadingConversion) \
(useAsAnimationCache) \
/* assemblyRep values */ \
(Collapsed) \
Expand Down Expand Up @@ -248,6 +249,7 @@ struct UsdMayaJobImportArgs
const TfToken::Set includeAPINames;
const TfToken::Set includeMetadataKeys;
TfToken shadingMode; // XXX can we make this const?
const TfToken shadingConversion;
JGamache-autodesk marked this conversation as resolved.
Show resolved Hide resolved
const bool useAsAnimationCache;

const bool importWithProxyShapes;
Expand Down
8 changes: 8 additions & 0 deletions lib/mayaUsd/fileio/shaderReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,14 @@ UsdMayaShaderReader::UsdMayaShaderReader(const UsdMayaPrimReaderArgs& readArgs)
{
}

/* static */
UsdMayaShaderReader::ContextSupport UsdMayaShaderReader::CanImport(const UsdMayaJobImportArgs&)
{
// Default value for all readers is Fallback. More specialized writers can
// override the base CanImport to report Supported/Unsupported as necessary.
return ContextSupport::Fallback;
}

/* virtual */
TfToken UsdMayaShaderReader::GetMayaNameForUsdAttrName(const TfToken& usdAttrName) const
{
Expand Down
13 changes: 13 additions & 0 deletions lib/mayaUsd/fileio/shaderReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,19 @@ class UsdMayaShaderReader : public UsdMayaPrimReader {
MAYAUSD_CORE_PUBLIC
UsdMayaShaderReader(const UsdMayaPrimReaderArgs&);

/// The level of support a reader can offer for a given context
///
/// A basic reader that gives correct results across most contexts should
/// report `Fallback`, while a specialized reader that really shines in a
/// given context should report `Supported` when the context is right and
/// `Unsupported` if the context is not as expected.
enum class ContextSupport { Supported, Fallback, Unsupported };

/// This static function is expected for all shader readers and allows
/// declaring how well this class can support the current context:
MAYAUSD_CORE_PUBLIC
static ContextSupport CanImport(const UsdMayaJobImportArgs& importArgs);

/// Get the name of the Maya shading attribute that corresponds to the
/// USD attribute named \p usdAttrName.
///
Expand Down
103 changes: 77 additions & 26 deletions lib/mayaUsd/fileio/shaderReaderRegistry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@
#include <pxr/base/tf/token.h>
#include <pxr/pxr.h>

#include <map>
#include <string>
#include <unordered_map>
#include <utility>

PXR_NAMESPACE_OPEN_SCOPE
Expand All @@ -40,51 +40,102 @@ TF_DEFINE_PRIVATE_TOKENS(
(ShaderReader)
);

typedef TfHashMap<TfToken, UsdMayaShaderReaderRegistry::ReaderFactoryFn, TfToken::HashFunctor>
_Registry;
JGamache-autodesk marked this conversation as resolved.
Show resolved Hide resolved
namespace {
struct _RegistryEntry {
UsdMayaShaderReaderRegistry::ContextPredicateFn _pred;
UsdMayaShaderReaderRegistry::ReaderFactoryFn _fn;
int _index;
};

typedef std::unordered_multimap<TfToken, _RegistryEntry, TfToken::HashFunctor> _Registry;
static _Registry _reg;
static int _indexCounter = 0;

_Registry::const_iterator _Find(
const TfToken& usdInfoId,
const UsdMayaJobImportArgs& importArgs) {
using ContextSupport = UsdMayaShaderReader::ContextSupport;

_Registry::const_iterator ret = _reg.cend();
_Registry::const_iterator first, last;
std::tie(first, last) = _reg.equal_range(usdInfoId);
while (first != last) {
ContextSupport support = first->second._pred(importArgs);
if (support == ContextSupport::Supported) {
ret = first;
JGamache-autodesk marked this conversation as resolved.
Show resolved Hide resolved
break;
} else if (support == ContextSupport::Fallback && ret == _reg.end()) {
ret = first;
}
++first;
}

return ret;
}
} // namespace

/* static */
void UsdMayaShaderReaderRegistry::Register(
TfToken usdInfoId,
UsdMayaShaderReaderRegistry::ReaderFactoryFn fn)
TfToken usdInfoId,
UsdMayaShaderReaderRegistry::ContextPredicateFn pred,
UsdMayaShaderReaderRegistry::ReaderFactoryFn fn)
{
int index = _indexCounter++;
TF_DEBUG(PXRUSDMAYA_REGISTRY)
.Msg("Registering UsdMayaShaderReader for info:id %s.\n", usdInfoId.GetText());
.Msg(
"Registering UsdMayaShaderReader for info:id %s with index %d.\n",
usdInfoId.GetText(),
index);

std::pair<_Registry::iterator, bool> insertStatus = _reg.insert(std::make_pair(usdInfoId, fn));
if (insertStatus.second) {
UsdMaya_RegistryHelper::AddUnloader([usdInfoId]() { _reg.erase(usdInfoId); });
} else {
TF_CODING_ERROR("Multiple readers for id %s", usdInfoId.GetText());
}
_reg.insert(std::make_pair(usdInfoId, _RegistryEntry{pred, fn, index}));

// The unloader uses the index to know which entry to erase when there are
// more than one for the same usdInfoId.
UsdMaya_RegistryHelper::AddUnloader([usdInfoId, index]() {
_Registry::const_iterator it, itEnd;
std::tie(it, itEnd) = _reg.equal_range(usdInfoId);
for (; it != itEnd; ++it) {
if (it->second._index == index) {
_reg.erase(it);
break;
}
}
});
}

/* static */
UsdMayaShaderReaderRegistry::ReaderFactoryFn
UsdMayaShaderReaderRegistry::Find(const TfToken& usdInfoId)
UsdMayaShaderReaderRegistry::ReaderFactoryFn UsdMayaShaderReaderRegistry::Find(
const TfToken& usdInfoId,
const UsdMayaJobImportArgs& importArgs)
{
using ContextSupport = UsdMayaShaderReader::ContextSupport;
TfRegistryManager::GetInstance().SubscribeTo<UsdMayaShaderReaderRegistry>();

ReaderFactoryFn ret = nullptr;
if (TfMapLookup(_reg, usdInfoId, &ret)) {
return ret;
_Registry::const_iterator it = _Find(usdInfoId, importArgs);

if (it != _reg.end()) {
return it->second._fn;
}

// Try adding more writers via plugin load:
static const TfTokenVector SCOPE = { _tokens->UsdMaya, _tokens->ShaderReader };
UsdMaya_RegistryHelper::FindAndLoadMayaPlug(SCOPE, usdInfoId);
JGamache-autodesk marked this conversation as resolved.
Show resolved Hide resolved

// ideally something just registered itself. if not, we at least put it in
// the registry in case we encounter it again.
if (!TfMapLookup(_reg, usdInfoId, &ret)) {
TF_DEBUG(PXRUSDMAYA_REGISTRY)
.Msg(
"No usdMaya reader plugin for info:id %s. No maya plugin found.\n",
usdInfoId.GetText());
_reg[usdInfoId] = nullptr;
it = _Find(usdInfoId, importArgs);

if (it != _reg.end()) {
return it->second._fn;
}

return ret;
if (_reg.count(usdInfoId) == 0) {
// Nothing registered at all, remember that:
Register(
usdInfoId,
[](const UsdMayaJobImportArgs&) { return ContextSupport::Fallback; },
nullptr);
}

return nullptr;
}

PXR_NAMESPACE_CLOSE_SCOPE
37 changes: 25 additions & 12 deletions lib/mayaUsd/fileio/shaderReaderRegistry.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,14 +58,14 @@ PXR_NAMESPACE_OPEN_SCOPE
/// reader plugin for some Maya built-in type, you can register your own
/// plugin for that Maya built-in type.
struct UsdMayaShaderReaderRegistry {
/// Predicate function, i.e. a function that can tell the level of support
/// the reader function will provide for a given context.
using ContextPredicateFn
= std::function<UsdMayaShaderReader::ContextSupport(const UsdMayaJobImportArgs&)>;

/// Reader factory function, i.e. a function that creates a prim reader
/// for the given prim reader args.
typedef std::function<UsdMayaPrimReaderSharedPtr(const UsdMayaPrimReaderArgs&)> ReaderFactoryFn;

/// Reader function, i.e. a function that reads a prim. This is the
/// signature of the function declared in the PXRUSDMAYA_DEFINE_READER
/// macro.
typedef std::function<bool(const UsdMayaPrimReaderArgs&, UsdMayaPrimReaderContext*)> ReaderFn;
JGamache-autodesk marked this conversation as resolved.
Show resolved Hide resolved
using ReaderFactoryFn = std::function<UsdMayaPrimReaderSharedPtr(const UsdMayaPrimReaderArgs&)>;

/// \brief Register \p fn as a factory function providing a
/// UsdMayaShaderReader subclass that can be used to read \p usdInfoId.
Expand All @@ -77,20 +77,27 @@ struct UsdMayaShaderReaderRegistry {
/// class MyReader : public UsdMayaShaderReader {
/// static UsdMayaPrimReaderSharedPtr Create(
/// const UsdMayaPrimReaderArgs&);
/// static CanImport(const UsdMayaJobImportArgs& importArgs) {
/// return Supported; // After consulting the arguments
/// }
/// };
/// TF_REGISTRY_FUNCTION_WITH_TAG(UsdMayaShaderReaderRegistry, MyReader) {
/// UsdMayaShaderReaderRegistry::Register("myCustomInfoId",
/// MyReader::CanImport,
/// MyReader::Create);
/// }
/// \endcode
MAYAUSD_CORE_PUBLIC
static void Register(TfToken usdInfoId, ReaderFactoryFn fn);
static void Register(TfToken usdInfoId, ContextPredicateFn pred, ReaderFactoryFn fn);

/// \brief Finds a reader if one exists for \p usdInfoId.
/// \brief Finds a reader if one exists for \p usdInfoId. The returned reader will have declared
/// support given the current \p importArgs.
///
/// If there is no reader plugin for \p usdInfoId, returns nullptr.
/// If there is no supported reader plugin for \p usdInfoId, returns nullptr.
MAYAUSD_CORE_PUBLIC
static ReaderFactoryFn Find(const TfToken& usdInfoId);
static ReaderFactoryFn Find(
const TfToken& usdInfoId,
const UsdMayaJobImportArgs& importArgs);
};

/// \brief Registers a pre-existing reader class for the given USD info:id;
Expand All @@ -105,16 +112,22 @@ struct UsdMayaShaderReaderRegistry {
/// const UsdMayaPrimReaderArgs& readerArgs) {
/// // ...
/// }
/// static CanImport(const UsdMayaJobImportArgs& importArgs) {
/// return Supported; // After consulting the arguments
/// }
/// };
/// PXRUSDMAYA_REGISTER_SHADER_READER(myCustomInfoId, MyReader);
/// \endcode
#define PXRUSDMAYA_REGISTER_SHADER_READER(usdInfoId, readerClass) \
TF_REGISTRY_FUNCTION_WITH_TAG(UsdMayaShaderReaderRegistry, usdInfoId##_##readerClass) \
{ \
static_assert(std::is_base_of<UsdMayaShaderReader, readerClass>::value, \
static_assert( \
std::is_base_of<UsdMayaShaderReader, readerClass>::value, \
#readerClass " must derive from UsdMayaShaderReader"); \
UsdMayaShaderReaderRegistry::Register( \
TfToken(#usdInfoId), [](const UsdMayaPrimReaderArgs& readerArgs) { \
TfToken(#usdInfoId), \
readerClass::CanImport, \
[](const UsdMayaPrimReaderArgs& readerArgs) { \
return std::make_shared<readerClass>(readerArgs); \
}); \
}
Expand Down
Loading