-
Notifications
You must be signed in to change notification settings - Fork 207
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
3Delight extended outputs - outputlayers, lightsets, multilayer EXRs #5641
Conversation
Synced to the latest main branch revision and updated the 3Delight outputs to have |
@johnhaddon since the current PR has conflicts with some of the recently added changes, would you prefer for me to close this one and split the intended changes/features from it into several smaller new PRs? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for the extended delay in getting to this one @gkocov. In truth I've been avoiding it a little because outputs are a bit of a thorny area and I'm unsure how best to proceed.
Part of the problem is that the Outputs system is one of Gaffer's weakest areas, desperately needing better alignment among renderers and improved definition/management for users. This is coming to a head a bit as we continue push on the Render Pass Editor, and find the Output system lacking for what we want to do. Continuing to have the renderers diverge isn't ideal if we want to pull them all back into alignment soon. Through no fault of your own, this PR is somewhat caught up in that mess.
I have to confess that I also find the lightset
implementation unconvincing in its current form - I can't see it scaling sufficiently to be useful in many production scenarios. Doing better would be a fair bit more work, but I think might be preferable.
would you prefer for me to close this one and split the intended changes/features from it into several smaller new PRs?
Yes please, I think that would be useful. It would also be great to include unit tests this time, so we have some coverage for when we hopefully start refactoring all the renderers into alignment.
Perhaps we could break it down in this order :
- Custom layer params, scalarformat, quantize fix. Although these represent divergence from a theoretical future where we've defined standard cross-renderer names for everything, I don't think that's a good enough reason to hobble 3Delight when we've already done it for Cycles/Arnold. Of the three, I think 3Delight's parameterisation may be closer to something we might want to standardise on anyway.
- Multipart, based on filename, along with output presets for cryptomatte.
- Light groups, after a bit of head scratching about what that might look like in an ideal world.
Hopefully that sounds OK?
Cheers...
John
@@ -361,6 +360,8 @@ void Render::executeInternal( bool flushCaches ) const | |||
GafferScene::Private::RendererAlgo::outputObjects( adaptedInPlug(), renderOptions, renderSets, &lightLinks, renderer.get() ); | |||
} | |||
|
|||
GafferScene::Private::RendererAlgo::outputOutputs( inPlug(), renderOptions.globals.get(), renderer.get() ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm a bit wary of this change, and any effects it might have on other renderer backends. It's also a bit of a departure from what I think is pretty logical - outputting all the globals before the scene itself.
If we were to keep this, it seems we'd need to do the same in InteractiveRender/RenderController to maintain feature parity?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll look into what other options we might have. Since this change is related only to the light groups implementation, not having it for the moment won't affect any of the other changes.
const string colorProfile = scalarFormat == "float" ? "linear" : "sRGB"; | ||
layerParams.add( "scalarformat", scalarFormat ); | ||
layerParams.add( "colorprofile", colorProfile ); | ||
const double filterSize = parameter<float>( output->parameters(), "filtersize", 3.0 ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the reason for taking filtersize
here when the NSI name is filterwidth
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TBH, I don't remember at the moment :) It probably was related to me trying what would be the best way to get a Gaffer float plug converted to a double type for the NSI filterwidth attribute. I'll double check once I revisit the code for the individual smaller PRs, but I'm pretty sure we can use filterwidth
instead of filtersize
here.
const string customDriverName = parameter<string>( output->parameters(), "customdrivername", "" ); | ||
if( customDriverName == "" ) | ||
{ | ||
m_driverHandle = DelightHandle( context, "outputDriver:" + name, ownership, "outputdriver", driverParams ); | ||
} | ||
else | ||
{ | ||
m_driverHandle = DelightHandle( context, "outputDriver:" + customDriverName, ownership, "outputdriver", driverParams ); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When talking about supporting multi-part for Arnold, I think we've concluded that we wanted to do it by automatically sharing drivers for outputs that had the same filename. Perhaps we could take the same approach here by just keeping a map of filename->driver?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good. The customdrivername
was a first pass attempt to get the multipart output running and it just stuck for the PR. Completely agreed that the approach to use the filename
plug value as a base for the multipart output setup would work better.
if( lightGroup != "" ) | ||
{ | ||
for( string lightGroupToken : lightGroupTokens ) | ||
{ | ||
NSIConnect( | ||
m_context, | ||
lightGroupToken.c_str(), "", | ||
m_layerHandle.name(), "lightset", | ||
0, nullptr | ||
); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I fear that this won't scale to real production scenarios - there will just be too many lights for it to be practical to manage them as a list of individual locations. It's also really vulnerable to lights changing names, being pruned etc.
I think a production-proof solution would either have to use Gaffer sets to define light groups, or a sort of "virtual parameter" on the light to say what groups it was in (mimicking the Arnold approach).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Completely agreed. Similar to customdrivername
this was a first pass setup to get light groups running with 3Delight and it definitely isn't an elegant solution.
I did want to see what it would take to get Gaffer sets translated to NSI sets, since that would not only help light groups, but any future attempt at light linking implementation as well. Once we have sets working well, I'll revisit light groups and any other potentially needed changes like the above mentioned GafferScene/Render.cpp
outputs order.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not very well documented, but any sets with names matching render:*
are exported to renderers as a string attribute with the list of sets an object belongs to. It would be possible to map that to connections to set nodes in the NSI backend. Maybe that's a starting point?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's great to know. Thanks for the info!
( "diffuse.indirect", "Diffuse (indirect)", "shader", "color" ), | ||
( "hair", "Hair and Fur", "shader", "color" ), | ||
( "subsurface", "Subsurface Scattering", "shader", "color" ), | ||
( "diffuse.direct", "Diffuse_(direct)", "shader", "color" ), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the reason for the " " -> "_" changes here? Is it to align with the other outputs, or is there a technical reason as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The customdrivername
implementation didn't work with spaces in the output name, so I had to replace them with _
. With multipart output getting changed from using customdrivername
to using the file name, there is no need for this change any more.
Thanks so much for looking into this @johnhaddon ! Everything you mentioned sounds good and I'll look into setting up individual smaller PRs along with tests for the changes. Replying inline on the specific code comments/questions. |
Great, thanks Goran! I'll close this PR now then, in anticipation of the future PRs... |
Generally describe what this PR will do, and why it is needed
Support for exporting Gaffer output parameters as both 3Delight outputdriver and outputlayer attributes. This enables direct control of 3Delight's outputlayer attributes like scalarformat and colorprofile (to set the rendered image bit-depth format and color space without the limitations of the quantize Gaffer parameter), filter type, filter width size, etc.
Support for rendering to multilayer EXRs by using the customdrivername output parameter. The updated Cryptomatte presets showcase how this is used. Drag and dropping the Name parameter from one output into the customdrivername parameter of another output is the easiest way to get the multilayer EXRs set up.
Support for light groups (lightsets in 3Delight terminology) using the lightgroup output parameter. The lightgroup output parameter accepts a space separated list of light objects that will determine which lights will be used for the rendering of the given output. Drag and drop from the Hierarchy View to the lightgroup output parameter is the easiest way to populate it.
In order for the lightgroups to work I had to change the order when outputs are generated in
src/GafferScene/Render.cpp
by moving them from second place after options to last place after objects. This is because the NSI scene needs to have the light object node defined in order to create a connection between it and the outputlayer node.Updated output presets to expose all of the above functionality, including fully functional multilayer Cryptomatte presets.
Breaking changes
src/GafferScene/Render.cpp
is a potential breaking change, not sure. I tested Cycles and everything seemed to work as expected, but I don't have access to Arnold, so I can't test it unfortunately.Checklist