APEX Changes - Houdini 20.0.592

   2503   7   2
User Avatar
Staff
31 posts
Joined: March 2020
Offline
In Houdini 20.0.592, we’ve introduced a series of substantial changes and bug fixes to the APEX toolset including callback changes, new APEX Edit Graph parameters and buttons, and preliminary graph compilation changes.

Below, we will go into more detail on each of these changes but here is a quick overview:

Callback Changes:
- Signatures of many callbacks have been changed to replace Int ports with Bool ports where appropriate. We’ve added an APEX Edit Graph button to resolve any graph compilation issue that arise from this.
- Bug fixes.

APEX Edit Graph Changes:
- The Error Handling Mode menu from APEX Invoke Graph is now present on APEX Edit Graph as well.
- There is a new Add Missing Convert Callbacks utility button.
- There is a new Add Missing In-Place Input Connections utility button.

Compilation:
In the next major Houdini release, there will be a series of new graph compilation requirements to ensure that node execution order is well defined and that the result of a graph is never dependent upon previous evaluations of the graph. The new rules are:
- In-place ports must have an input wire.
- An output port cannot be connected to more than one in-place input port.
- Wires cannot extend between ports in different scopes (such as ForEach and If blocks).
- Node parameter types must match the data type of their corresponding ports.

Lucha, Chicken, and Pillow:
Updated version of the subgraphs and example files for the lucha, chicken, and pillow rigs have been added to the content library to respect the changes in this update.

Immediate Changes:

Boolean Ports:

The signature of many APEX callbacks have changed to replace Int ports with Bool ports. This sweep had been planned since before the H20 release but unfortunately we did not have time to get this change in prior to release.
This change will cause many graphs which had previously been compilable to fail.
To resolve the graph compilation errors caused by these changes, we’ve added an Add Missing Convert Callbacks button to APEX Edit Graph and a corresponding python function:
apex.editgraphutils.addConvertCallbacksToGraph(<apex.Graph>)

Bug Fixes on Callbacks:

string::Split:
When the separators port is given an empty string, the default behaviour is now to split the string on all whitespace.

APEX Edit Graph:

To help resolve compilation errors on your graphs, a new parameter and 2 new action buttons have been added to APEX Edit Graph:

Error Handling Mode:
This menu parameter can be used to report graph compilation warnings and errors.
This will also report errors that will cause graph compilation to fail in the next major Houdini release to aid in a smooth transition.

Add Missing Convert Callbacks:
This button will identify every wire in your graph that wire 2 ports with different types together. It will then add the proper Convert<T> callback along that wire if that callback is defined.
All changes made by this button will be written to the comment on the node.

If you wish to automate this process, this button uses the following python function:
apex.editgraphutils.addConvertCallbacksToGraph(<apex.Graph>)

Add Missing In-Place Input Connections:
This button will identify every in-place port that does not have an input connection.
It will then attempt to wire the input port (P) according to the following heuristic:
• If P is the array input port on a ForEachEnd<T> callback, then the scope port will be followed back to the corresponding ForEachBegin<T> callback and its array output port will be wired to P.
• Else if P is the geo input port on a geo::ForEach*End callback (ex. geo::ForEachPointEnd), then the scope port will be followed back to the corresponding geo::ForEach*Begin callback and its geo output port will be wire to P.
• Else, a Value<A> callback (where A is the type of P) will be added and its value port will be wired into P.
All changes made by this button will be written to the comment on the node.

If you wish to automate this process, this button uses the following python function:
apex.editgraphutils.fixMissingInPlaceConnectionsInGraph(<apex.Graph>)

Changes Coming in the Next Major Houdini Release:

The next major Houdini release is going to bring several changes to graph compilation to enforce new requirements for in-place ports, graph scope, and node parameters.
These changes are being made to ensure that the evaluation of graphs are well defined and so that the results of evaluating a graph will never depend on whether the graph had previously been evaluated.

To aid in a smooth transition, you can use the new Error Handling Mode parameter on APEX Edit Graph to report these new requirements as graph compilation errors.
Alternatively, you can use the apex.graph.setStrictCompile(<bool>)function in python to enforce these requirements on the graph.
NOTE: Strict compilation cannot be saved back onto a graph’s geometry. This function will only have an effect on the python graph object.

In-Place Port Changes:

In-place ports are the shorthand for ports which pass an object through the callback, altering its data along the way rather than making a copy of the object.
The graph port on graph::AddNode and the geo port on geo::ForEachPointBegin/End are examples of these types of ports.

In the next major Houdini release there will be 2 major changes to the requirements for the compilation of these ports.

First, in-place ports will be required to have an input connection.
This is done to ensure that the buffer for the object shared by the in-place ports is reset on each evaluation of the graph.
Without enforcing this, the buffer for objects such as graphs and arrays can continue to accumulate nodes/entries after each evaluation of a graph if it is not reloaded.
To assist in fulfilling this requirement, a new button named Add Missing In-Place Connections as been added to APEX Edit Graph.

Second, output ports cannot be connected to more than one in-place input port.
Instead, these callbacks should be sequenced to avoid ambiguity in execution order. Any branching will prevent the compilation of your graph.
As an example, a graph output port cannot be wired into 2 graph::AddNode callbacks. Instead, it must flow through one to the other.
We are enforcing this rule so that the order in which to execute in-place connections on the same object is no longer ambiguous.

Graph Scope Changes:

In the next major Houdini release, wires will not be allowed pass between a port in one scope (such as within an If or ForEach block) to a port in another scope.
Instead, they must be routed through the block Begin and End callbacks.

Node Parameter Changes:

In the next major Houdini release, the type of a node’s parameter in its parameter dictionary must match the type of the port corresponding to the parameter.
If it does not, the graph will still compile and run but this will be reported as an error.
We are enforcing this rule so that it is reported when this case occurs.
Prior to this, the value of the parameter was ignored without warning and the issue became very difficult to debug.
Edited by jonathangardner - Jan. 20, 2024 14:38:58
User Avatar
Member
28 posts
Joined: Jan. 2017
Offline
jonathangardner
- An output port cannot be connected to more than one in-place input port.

Thanks Jonathan for the heads up on these changes. For this particular issue, is there a node to split the output, so I can keep sending the results of nodes through multiple streams? Does each split need to go through it's own Value<Type> node? (I've been using the Value nodes in my rigs but I'm still sort of guessing about when I need to use them!)
https://www.noad.co [www.noad.co]
User Avatar
Member
236 posts
Joined: March 2023
Offline
danfitz82
Thanks Jonathan for the heads up on these changes. For this particular issue, is there a node to split the output, so I can keep sending the results of nodes through multiple streams? Does each split need to go through it's own Value<Type> node? (I've been using the Value nodes in my rigs but I'm still sort of guessing about when I need to use them!)

That probably what will end up happening, if you sent a in-place output to 2 in place input, both node would work on the same piece of memory and that will mess thing up
Value<Geometry> create a copy of their input, so they wouldn't be considered in-place input plug.
Head of Pipeline @ LightVFX
User Avatar
Member
236 posts
Joined: March 2023
Offline
Hey! So I recently updated to a version of houdini introducing these change.
I had a concern about the dict::Build node, which use a in-place memory input, this node is often used to build dictionary from scratch, but now it require a Value<Dict> input systematically connected to it, I feel like this could be avoided completely if apex could simply detect that the port is not connected and automatically add an 'invisible' Value<Dict> node to it ?

we also really need a way to differentiate in-place port and having the search (ctrl+f) feature working if we're gonna be forced to fix any missing or wrong connection.

Thanks !

PS: I think the luchador & Chicken Rig scene example is completely broken now.
Edited by ASquirrel - Jan. 28, 2024 18:54:03
Head of Pipeline @ LightVFX
User Avatar
Staff
31 posts
Joined: March 2020
Offline
Jacquesf
Hey! So I recently updated to a version of houdini introducing these change.
I had a concern about the dict::Build node, which use a in-place memory input, this node is often used to build dictionary from scratch, but now it require a Value<Dict> input systematically connected to it, I feel like this could be avoided completely if apex could simply detect that the port is not connected and automatically add an 'invisible' Value<Dict> node to it ?

Hey Jacquesf!

First, thanks for downloading the changes and giving feedback!
We've gone back and forth on this one ourselves and I do agree with a lot of what you've said. We had to update 40+ of Houdini's internal graphs because of the in-place input on dict::Build.
The primary argument I have for keeping it the way it is right now is just to ensure that in-place inputs are being used correctly. Although it would make a lot of sense for dict::Build to create its own dictionary when it doesn't have an input dictionary, I feel like that's the exception to the rule.
As an example, for the graph editing callbacks like graph::AddNode, I'd expect the callback to be adjusting a graph in the vast majority of cases rather than simply creating a graph with a single node. Since the burden of putting down a single Value<Graph> callback is pretty minimal, I think it would avoid a lot of potential headache to treat the missing in-place input as an error rather than to allow a potentially faulty graph to run.
That's just my two cents though. Part of the reason for bringing this change back now was to get feedback and if the community feels differently, this is one where I could see us using the invisible Value<T> solution and downgrading this to a warning.


Jacquesf
we also really need a way to differentiate in-place port and having the search (ctrl+f) feature working if we're gonna be forced to fix any missing or wrong connection.

Agreed! These are being worked on/on the TODO list.


Jacquesf
PS: I think the luchador & Chicken Rig scene example is completely broken now.

There should be a new version of that file in the content library for Houdini 20.0.592 and beyond.
User Avatar
Member
8777 posts
Joined: July 2007
Offline
I'd be all up for this being solved robustly behind the scenes during APEX evaluation

since APEX graphs are already very messy so having to deal with all extra value nodes, just to init data seems very unnecessary from user POV and also from TD POV when editing graph geo procedurally using other graphs etc

the inplace-ness of the input/output can be sorted out visually on the node for example
assuming nodes with inplace inputs always have corresponding in place output
so in place inputs/outputs may not only have distinguished port shape, but also there can be a line connecting input/output on the node suggesting that the same data flows through or with some icon in the middle that suggests its being modified

- then when something is plugged into such input you will see the ports full, with inplace port shape and internal line and modify icon visible
- if nothing is plugged in, the inptut port can be drawn empty still as inplace port shape and line would not be visible, so only output port can be drawn full and maybe in regular shape instead of inplace port shape, since the data is implicitly created by the callback

I assume that with such visual feedback and a bit of understanding what it means the ports would be used correctly, for me it would provide much better experience than having to create a value node

EDIT: attached rough mockup of how UI could show the inplace vs inplicit creaion state of te node as described above
Edited by tamte - Jan. 29, 2024 18:14:52

Attachments:
inplace_connections_ui_notconnected_conneced.png (8.6 KB)

Tomas Slancik
FX Supervisor
Method Studios, NY
User Avatar
Member
236 posts
Joined: March 2023
Offline
jonathangardner
First, thanks for downloading the changes and giving feedback!
We've gone back and forth on this one ourselves and I do agree with a lot of what you've said. We had to update 40+ of Houdini's internal graphs because of the in-place input on dict::Build.
The primary argument I have for keeping it the way it is right now is just to ensure that in-place inputs are being used correctly. Although it would make a lot of sense for dict::Build to create its own dictionary when it doesn't have an input dictionary, I feel like that's the exception to the rule.
As an example, for the graph editing callbacks like graph::AddNode, I'd expect the callback to be adjusting a graph in the vast majority of cases rather than simply creating a graph with a single node. Since the burden of putting down a single Value<Graph> callback is pretty minimal, I think it would avoid a lot of potential headache to treat the missing in-place input as an error rather than to allow a potentially faulty graph to run.
That's just my two cents though. Part of the reason for bringing this change back now was to get feedback and if the community feels differently, this is one where I could see us using the invisible Value<T> solution and downgrading this to a warning.

I'm wondering if the rules simply couldn't be "if not connected, then create the memory for it"


I fully understand the point of having an AddNode not being connected to a graph creating itself a graph from scratch wouldn't make sense, but.. it actually sorta do ?

the point is, if I do want to create a graph starting out of an AddNode, if I then use the output of that AddNode and connect it to the subgraph Output, I would expect a graph with a node.
I think every node should systematically create the missing memory if the in-place input is not connected, regardless of what the node do, because that what the user would expect to have, the node is connected ? modify the input memory in place, the node is not connected ? create that memory! I think what really matter is if you use the result of that node, and that if that node is connected or not do not matter.
I'd like to know any reason where not creating the memory when the input is missing would cause any issues, if anything, apex could simply under the hood (during the evaluation or converstion from geo->graph) automatically add any Value<T> node to every single missing connection, simply because it make sense to do so, even if it don't make sense to use a node that would, in 99% of the case, modify something that already exist.

when talking about in-place memory, think make sense when you look at the perspective of the output of a node, not it input :
you don't want the output of a node to be connected to more than 1 input that will modify memory in-place, but you don't care about the input being connected or not as this rules we be enforced by the output side of a node, if the input is not connected, just create the memory.
Edited by ASquirrel - Jan. 29, 2024 18:19:01
Head of Pipeline @ LightVFX
User Avatar
Member
8777 posts
Joined: July 2007
Offline
I agree that this should happen under the hood during evaluation

there should be no issue having Add node or Merge node with first input empty
APEX should just assume implicit data there, should initialize the "value" and then Add to it or merge etc.

I see no reason why user is forced to handhold APEX through that process, it should be the other way around, APEX and its nodegraph UI should show user what's gonna happen
Edited by tamte - Jan. 29, 2024 18:29:15
Tomas Slancik
FX Supervisor
Method Studios, NY
  • Quick Links