Skip to content

Commit

Permalink
Merge from internal changes (#8)
Browse files Browse the repository at this point in the history
* Katana:
  USD PointInstancer support.
  It is creating a walter procedural location with its
  prim path starting at the point instancer.

Arnold Procedural:
  Force scan of "/materials" location before anything else
  in order to support location starting at a PointInstancer prim
  (for Katana support).

  Add support for USD constant attibuts in Arnold
  (fixing error on usd kitchen set).

MtoA extension:
 jsoncpp library not needed anymore.
  • Loading branch information
rodeo authored Aug 30, 2018
1 parent 9baff9a commit 90c07ae
Show file tree
Hide file tree
Showing 53 changed files with 2,209 additions and 621 deletions.
97 changes: 73 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,28 @@
Open Walter
===========================
![Open Walter](https://www.rodeofx.com/uploads/images/tech/Walter_logo_mini-01.png)

Walter is an open source suite of plugins using USD for various DCCs and renderer.
Walter is suite of plugins using USD for various DCCs and renderer.

It's main goal is to stay as much as possible in the [*USD Stage*](http://graphics.pixar.com/usd/docs/USD-Glossary.html#USDGlossary-Stage)
loaded through a DCC in order to increase the interactivity and limit the import/export time.

The DCC communicate with the *USD Stage* to access or modify specific [*USD prim*](http://graphics.pixar.com/usd/docs/USD-Glossary.html#USDGlossary-Prim)
or properties. Modifications are stored in specific [*session layers*](http://graphics.pixar.com/usd/docs/USD-Glossary.html#USDGlossary-SessionLayer)
like for example transform, variant or visibility layers.

The [*Hydra Renderer*](http://graphics.pixar.com/usd/docs/USD-Glossary.html#USDGlossary-HydraRenderer) is used to display the stage in DCC like Houdini or Maya.

Walter provide a portable lookdev workflow. From Maya, artists can assign Arnold shaders directly on the *USD prims*
of the loaded stage. Those *lookdev edits* can then be exported as Alembic layers to be loaded
in Houdini or Katana.

Walter let you interact with prims transforms directly from Maya. It is *connecting* Maya locator(s) to the expose prim(s), in order
to push any static or animated transforms to the *USD stage*. This is the way to exchange layout and rigid animations between DCCs using Walter.

Walter include a modified version of the Embree raytracer for Hydra. It is able to blend any rendered prims with native Maya or Houdini objects displayed in the viewport.
This raytracer is dedicated to fast display. On scenes with millions of polygons, it will be much faster that the default Hydra renderer plugin (called *Stream*).
You can mix Walter nodes using *Embree* and *Stream* in the same scene. For example, the main character could be displayed using *Stream* and the environment using *Embree*.

Finally Walter extend USD itself by providing additional schemas (like WalterVolume or Expression), file format plugin (Arnold Scene Sources) and resolver (Alembic 1.7 CoreLayer allowing to load more than one *main file* in the stage).


Supported Platforms
Expand Down Expand Up @@ -31,6 +52,15 @@ Finally, the walterViewer application is a standalone viewer that can load Walte
It is mostly used for development purpose, as it let you load layers without launching a DCC.


Trying Walter
------------

Compiled versions for Centos7 can be downloaded from (https://github.com/rodeofx/OpenWalter/releases).
You will need to add the plugins to your application environment.
Take a look at the Houdini, Katana, Kick and Maya wrappers in (https://github.com/rodeofx/OpenWalter/tree/dev/walter/utils)
to see how to get a proper configuration to load Walter plugins.


Building Walter
------------

Expand Down Expand Up @@ -65,13 +95,11 @@ For example to build only the Houdini plugin:

##### Arnold Procedural

*walter* node:

Render a list of USD or Alembic files.
Walter **materials** and **assignations** can be loaded directly, including assignations using Walter Expression.
**Materials** and **assignations** can be loaded directly, including assignations using **expressions**.
Session layers like transforms, variants, purposes, etc... can be passed as parameters too.

You must set the Arnold install path in your environment.
You must set the Arnold root path in your environment.

| Variable Name | Description | Version |
| ----------------- | ----------------------------------- | --------- |
Expand All @@ -80,16 +108,15 @@ You must set the Arnold install path in your environment.

##### Houdini Plugin

*Walter SOP* node:

It is using an **Hydra** display to visualise a stack of USD/Alembic layers in the viewport as **Packed Walter** primitives.
* *Walter SOP* node:
It is using an **Hydra** display to visualize a stack of USD/Alembic layers in the viewport as **Packed Walter** primitives.
You can unpack them using standard Houdini Unpack node.

*Walter Procedural OBJ* node:
* *Walter Procedural OBJ* node:
Create a Walter procedural node in Arnold (via HtoA) to render USD/Alembic layers.
It is supporting layers comming from Walter for Maya (like materials, assignations, overrides or transforms).
It is supporting layers coming from Walter for Maya (like materials, assignations, overrides or transforms).

You must set the Houdini and HtoA install paths in your environment.
You must set the Houdini and HtoA root paths in your environment.

| Variable Name | Description | Version |
| ----------------- | ----------------------------------- | --------- |
Expand All @@ -99,12 +126,11 @@ You must set the Houdini and HtoA install paths in your environment.

##### Katana Plugin

*Walter_In* node:
* *Walter_In* node:
Create a Katana scene graph from a stack of USD/Alembic/Arnold Scene Sources layers.
It is supporting materials, assignations, overrides and transforms layers coming from Walter for Maya.

Create a Katana scene graph from a stack of USD/Alembic layers.
It is supporting materials, assignations, overrides and transforms layers comming from Walter for Maya.

You must set the Maya and MtoA install paths in your environment.
You must set the Maya and MtoA root paths in your environment.

| Variable Name | Description | Version |
| ----------------- | ----------------------------------- | --------- |
Expand All @@ -113,13 +139,27 @@ You must set the Maya and MtoA install paths in your environment.

##### Maya Plugin

*Walter Standin* node:
* *Walter Standin* node:

From the WalterStandin Attribute Editor you can:
* open the Walter Tree Widget
* select any variants available in the stage.
* select the purpose to use in the viewport (proxy or render)
* switch between bounding box and full representatin (disabled in the open source version for the moment)
* choose the Hydra Renderer plugin

You can select *USD prims* directly from the viewport like a standard Maya object or from the Walter Tree Widget (aka the *Walter outliner*).
You can drag and drop materials from the Hypershader directly on any prims in the Walter Tree Widget and override Arnold attributes.
Shader drag and drop can be done on Walter Expression items in the Tree Widget (using regular expression to assign shaders to prims).

By righ clicking on a prim in the Walter Tree Widget you can:
* show or hide prims
* expose prims transforms as Maya locators
* override prim purpose.


Finally edits can be saved on disk as specific layers.

It is using an **Hydra** display to visualise a stack of USD/Alembic layers in the viewport as one Maya shape node.
You can select USD prims from the viewport or from the Walter tree widget.
You can modify the loaded USD stage, like adding materials, assignations or attributes. You can animate USD prims
by exposing their transforms to Maya as locator objects. You can select any variants available in the composed stage.
Finally all those edits can be saved on disk in specific layers.

*Walter Translator* for MtoA:

Expand Down Expand Up @@ -167,3 +207,12 @@ If you run ```make clean && make``` it will re-build only Walter (and so it will
##### Build Options

Run ```make help``` for more info on the various targets available.


Contributing
------------

Since the open source version of Walter is in its early days, we did not yet created any forum or documentation pages.

[![Join the chat at https://gitter.im/OpenWalter/Lobby](https://badges.gitter.im/OpenWalter/Lobby.svg)](https://gitter.im/OpenWalter/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)

1 change: 1 addition & 0 deletions walter/arnold/procedural/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ if(BUILD_TESTS)
arnold_test(09-b365c58f35b1-broken-regex.ass)
arnold_test(10-6722c1d-aiComposite.ass)
arnold_test(11-matrix-param_support.ass)
arnold_test(12-point-instancer.ass)
endif()

install(TARGETS ${PROC} DESTINATION ${CMAKE_INSTALL_PREFIX}/arnold)
41 changes: 34 additions & 7 deletions walter/arnold/procedural/delegate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ RendererDelegate::RendererDelegate(
void RendererDelegate::populate(const UsdPrim& root)
{
const SdfPath rootPath = root.GetPath();


bool childrenKnown = mIndex.isChildrenKnown(rootPath);

// This accessor will freeze if there is another accessor in different
Expand All @@ -49,15 +47,25 @@ void RendererDelegate::populate(const UsdPrim& root)

const SdfPath primPath = prim.GetPath();

// This will check if, in the hierarchy of the root path, a parent prim
// of primPath has already been added to the index.
// If it's the case, it means that a walter procedural will be created
// for it (the parent) and so children will be populate at this time.
if (mIndex.isParentKnown(rootPath, primPath))
{
continue;
}

// In some cases like a bbox generated from a "point instance" a path could
// already by added to the index, but not from the same parent. In this case
// already be added to the index, but not from the same parent. In this case
// we can't skip to early.
bool skipLater = false;
// Skip it it's already cached. In USD it's possible to have several

// Skip if it's already cached. In USD it's possible to have several
// parents. We need to be sure that we output the object only once.
if (rootPath != primPath && mIndex.isProcessed(primPath))
{
if(childrenKnown)
if (childrenKnown)
{
continue;
}
Expand All @@ -76,7 +84,7 @@ void RendererDelegate::populate(const UsdPrim& root)
mIndex.insertPrim(rootPath, primPath);
}

if(skipLater)
if (skipLater)
{
continue;
}
Expand Down Expand Up @@ -148,6 +156,24 @@ void RendererDelegate::populate(const UsdPrim& root)
}
}

// If the locations '/' or '/materials' were not already "scanned" we don't
// want to check for expression and assignment as materials may not be
// retrieved to do it properly. So skip the Expression scan until
// '/materials' has been scanned in the loop above.
//
// If materials are retrieved and the check for expression and assignment
// are already done there is nothing else to do and we can skip the last
// loop on WalterExpression.
if (!mIndex.hasGlobalMaterials() || mIndex.isAssignmentDone())
{
return;
}

// Always check assignment from the pseudo root "/" whatever the given
// root prim was as material are usually under "/" directly.
UsdPrim pseudoRoot = root.GetStage()->GetPseudoRoot();
range = UsdPrimRange(pseudoRoot);

for (const UsdPrim& prim : range)
{
// We already processed everything and since all the materials are
Expand All @@ -161,8 +187,9 @@ void RendererDelegate::populate(const UsdPrim& root)
WalterExpression expression(prim);
std::string expressionText = expression.GetExpression();
WalterExpression::AssignmentLayers layers = expression.GetLayers();

// Insert them into a cache.
mIndex.insertExpression(
prim.GetPath(), rootPath, expressionText, layers);
prim.GetPath(), pseudoRoot.GetPath(), expressionText, layers);
}
}
48 changes: 43 additions & 5 deletions walter/arnold/procedural/engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,18 @@ int RendererEngine::getNumNodes(
const UsdPrim prim = mStage->GetPrimAtPath(path);
if (prim)
{
// If the given path is not the root path or a children of /materials
// and if global materials are not already found we need to force
// the check of materials location, which will produce one more
// procedural node set to the '/materials' location.
int numNodes = 0;
if (path != SdfPath("/") &&
!boost::starts_with(path.GetString(), "/materials") &&
!mIndex.hasGlobalMaterials())
{
numNodes = 1;
}

if (prim.IsA<UsdGeomPointInstancer>())
{
UsdGeomPointInstancer instancer(prim);
Expand All @@ -144,13 +156,15 @@ int RendererEngine::getNumNodes(
VtVec3fArray positions;
positionsAttr.Get(&positions, static_cast<double>(averageTime));

return static_cast<int>(positions.size());
int pointInstancerNumNodes = static_cast<int>(positions.size());
mIndex.insertNumNodes(prim.GetPath(), pointInstancerNumNodes);
return numNodes + pointInstancerNumNodes;
}

prepare(prim);
// 2x because we need to output a reference and an inctance for each
// object.
return 2 * mIndex.getNumNodes(path);
return numNodes + 2 * mIndex.getNumNodes(path);
}
return 0;
}
Expand All @@ -161,22 +175,46 @@ void* RendererEngine::render(
const std::vector<float>& times,
const void* userData)
{
// If the locations '/' or '/materials' are not in the hierarchy map,
// create a walter procedural for /materials. This happend when the first
// "objectPath" given to the procedural was a children of '/'.
//
// If '/materials' need to be scanned we force it to be the first
// thing done.
if (!mIndex.hasGlobalMaterials() && id == 0)
{
SdfPath materialPath("/materials");
UsdPrim materialPrim = mStage->GetPrimAtPath(materialPath);
if (materialPrim)
{
return mPlugin.output(materialPrim, times, userData);
}
}

const UsdPrim parentPrim = mStage->GetPrimAtPath(path);
if (parentPrim.IsA<UsdGeomPointInstancer>())
{
int realID = id % mIndex.getNumNodes(path);

return mPlugin.outputBBoxFromPoint(
parentPrim, id, times, userData, mIndex);
parentPrim, realID, times, userData, mIndex);
}

// TODO: Can be slow.
int numNodes = mIndex.getNumNodes(path);

// It's impossible that numNodes is 0 at this point because render() is
// called from arnoldProceduralGetNode. And arnoldProceduralGetNode is
// called after arnoldProceduralNumNodes. If the number of nodes is 0,
// render() should never be called.
assert(numNodes > 0);

// Since we output a reference and an inctance for each object, the real id
// This is to ensure the id we get is independant of whether material
// were forced to be scanned or not. In any other case than point instancer
// the number of nodes returned to arnold was multiply by 2, that explain
// the manipulation bellow.
id = id % (numNodes * 2);

// Since we output a reference and an instance for each object, the real id
// is id % numNodes. With this we can use variants if variant is 0, we need
// to output a reference object. Otherwise we need to output an instance. We
// use following terminology: a reference is an invisible object that
Expand Down
Loading

0 comments on commit 90c07ae

Please sign in to comment.