Closed mottosso closed 8 years ago
Continuing from #14
And according to Maya they would belong to ViewportOptions because they are related to the Viewport, see modelEditor.
Ah, yes that makes more sense, let's go for that.
They seem to be rather cryptic.
Hm, what do you suggest? We could do e.g. viewport = ViewportOptions.VIEWPORT2
? Or version them viewport = 0 # legacy
, viewport = 1 # high quality
, viewport = 2 # 2.0
?
Maybe we can provide our own enum like that indeed for clarity and still allow to pass in a string to accommodate for custom renderers.
I think it's clear if they are:
Or whatever is close to how they show in the UI.
Note that the options for Viewport 2.0 are set on a node called hardwareRenderingGlobals
(so setAttr
and getAttr
should get us there.)
These are some of the default settings:
class Viewport2Options:
# Transparency Algorithm
# 0: simple, 1: object sorting, 2: weighted average, 3: depth peeling
transparencyAlghorithm = 1
# Motion Blur
motionBlurEnable = 0
motionBlurType = 0 # transform (currently there is no other option)
motionBlurShutterOpenFraction = 0.2
motionBlurSampleCount = 8
# Anti-aliasing
lineAAEnable = 0
multiSampleEnable = 0
multiSampleCount = 8
# Screen Space Ambient Occlusion
ssaoEnable = 1
ssaoRadius = 16
ssaoFilterRadius = 16
ssaoAmount = 1.0
ssaoSamples = 8
There are much more settings that could be of interest.
I'm having a bit of trouble keeping up with the changes to be honest, but I think it sounds good and I trust your judgement.
did you guys ever get around to this?
Passing the ball to @BigRoy
With separate classes this actually easy to implement. I can set that up and show it off a bit.
@mkolar what specifically do you need?
I can set that up and show it off a bit.
Awesome I though I'd look at it myself if no one tried yet.
what specifically do you need?
Practically I need to be able to capture exactly what animator sees in the viewport including dof, motion blur, AA, AO, lights, shadows.
With the range of models we're doing now, we prefer giving artist control over how they present it, because different scenarios ask for different approaches.
Ideally I'd like capture
to take all the settings from current viewport, with any options passed to it acting as overrides.
exactly what animator sees in the viewport.. Ideally I'd like capture to take all the settings from current viewport, with any options passed to it acting as overrides.
Sorry, that isn't what I had in mind for this module. It needs to be reliable and produce identical results across runs. It can't be dependent on the current state of the scene, but instead capture it exactly as specified and otherwise resort to internal defaults, defaults based on the original Maya defaults on a clean install.
What you could do though, is write a little "collector" to gather the current state, and pass that to capture
.
Ideally I'd like capture to take all the settings from current viewport, with any options passed to it acting as overrides.
This is what I had in mind as well.
Sorry, that isn't what I had in mind for this module. It needs to be reliable and produce identical results across runs. It can't be dependent on the current state of the scene, but instead capture it exactly as specified and otherwise resort to internal defaults, defaults based on the original Maya defaults on a clean install.
It'd make much more sense if the package would provide presets for anyone to use: default, low, high. These could be used for reliability?
capture(preset="default")
Just as reliable as it is now, yet much more explicit.
I have no problem with that, however there are not enough options in capture to do that currently, at least to my knowledge.
It needs to be reliable and produce identical results across runs.
Absolutely reasonable for certain productions. Not very desirable with multiple smaller project in the pipeline, where each requires something else. For example we have a show, where everything needs to be capture with flat lighting and constant shaders, and another, where director wants to see nicely lit viewport captures to get closer to better see the model details.
defaults based on the original Maya defaults on a clean install
I've yet to see where the defaults would produce result acceptable for production reviews.
Maybe having 2 modes would work. Default would stay as it is now, and artist
mode would work based of current viewport settings?
By the way this is what I was testing before class based options.
They would all be triggered through a context manager that first retrieves the "current" to store the state the artist is working with and then applies the "overrides" that were passed in to the capture()
command.
Similarly this could also mean that playblasting with the current settings would become something like passing along: options.current()
I was separating these out into different classes because some of the commands need to be triggered differently cmds.modelEditor
vs cmds.setAttr
for camera attributes, etc. And it kept the code base simpler. Of course this could be one single class that would know which command to trigger based on the "option" name.
Maybe having 2 modes would work. Default would stay as it is now, and artist mode would work based of current viewport settings?
That's a good idea!
Maybe a flag set on the module itself, to not continue to pollute the already overpopulated argument list?
import capture
capture.defaults = capture.FromActiveView
capture.defaults = capture.MayaDefaults
I've yet to see where the defaults would produce result acceptable for production reviews.
To be honest, I'd expect production reviews to be consistent, and not at all depend on how any particular artist had his Maya set up at any particular time of the day. Production reviews is the primary goal of this module, the idea is that you wouldn't use any of the defaults, but when you do, you can count on them being consistent.
To be honest, I'd expect production reviews to be consistent, and not at all depend on how any particular artist had his Maya set up at any particular time of the day. Production reviews is the primary goal of this module, the idea is that you wouldn't use any of the defaults, but when you do, you can count on them being consistent.
Sure. But one production might need that "specific background color" just to have the production review look good. These same "reviews" should be consistent but also good enough to possibly be share-worthy with a client. We've had productions where we set the background color to a dark blue shade to represent night time of the scene. Even though it's an alteration it was intended as a consistency within that project decided upon by the creative artists. I'd rather not interfere too much here and having to make some new lines of code to support each new project like that.
I'd rather be able to make "presets" for a project that at some point could be managed by the creative lead instead of being pushed to a TA/TD.
Maybe a flag set on the module itself, to not continue to pollute the already overpopulated argument list?
sure that works.
I'd expect production reviews to be consistent,
Maybe we got a misunderstanding :). Consistent within a project, mostly yes, But it can vary wildly between projects or even sequences.
edit: @BigRoy was a tiny bit faster :)
I'd rather be able to make "presets" for a project that at some point could be managed by the creative lead.
How about something like this?
# mycapture.py
def capture():
from capture import capture
capture( ... ) # My settings
That's your "preset". To use it, you:
import mycapture
mycapture.capture()
That way, you get what you want, and capture
remains minimal.
Sure. Could definitely work. I think the important bit is just that capture
has a way to get the current settings so it becomes easy to build a current preset or even define settings. Especially because future releases might expand on features (like viewport 2.0 support).
I'm also fine with it defaulting to some "default" that seems to be somewhat arbitrarily chosen. (Or at least will never fit everyone's needs, so why bother trying to?). Yet it should be as easy as something like:
capture(options=capture.current_options())
Similarly I think we mentioned before revamping the options into something like a dictionary. I think that's a very neat idea, since it'd be easy to store presets (save/load even!) into JSON.
def save(path):
data = capture.current_options()
with open(path, "w") as f:
json.dump(data, f)
And loading it as options:
def load(path):
with open(path, "r") as f:
return json.load(f)
Using it like:
capture(options=load(path))
Similarly the default settings could be just a dictionary.
I think the important bit is just that capture has a way to get the current settings so it becomes easy to build a current preset or even define settings.
I like that idea. Like a capture.parse_active_view()
command which inspects the currently active view and returns a dictionary capable of being expanded into the capture
command.
import capture
settings = capture.parse_active_view()
capture.capture(**settings)
That way, you could, as you say, save it out to a JSON or YAML and edit away. making your own "preset".
import json
import capture
with open("mypreset.json") as f:
settings = json.load(f)
capture.capture(**settings)
I think that sounds great. We will need to convert the current CameraOptions and similar option classes into pure dictionaries, which is a good direction overall as well.
Sweet!
We just need a mapping somewhere on how specific sets of attributes need to be handled. As stated before managing these attributes is different for some settings, some are attributes on the camera. Some are values on the modelEditor
. Similarly we'll need a counterpart on how to retrieve the current value. (If we're changing the value we need to revert to the current value afterwards).
This is somewhat what I did with the class-based system for the options. For each attribute type you'd need to know what "setting names" there are and what commands are related, e.g. this is what I had before :
class DisplayOptions(Options):
"""Display options for :func:`capture`
Use this struct for background color, anti-alias and other
display-related options.
"""
displayGradient = True
background = (0.631, 0.631, 0.631)
backgroundTop = (0.535, 0.617, 0.702)
backgroundBottom = (0.052, 0.052, 0.052)
_colors = ['background', 'backgroundTop', 'backgroundBottom']
_prefs = ['displayGradient']
@staticmethod
def current():
"""Return the currently set options."""
from maya import cmds
options = DisplayOptions()
for clr in options._colors:
value = cmds.displayRGBColor(clr, query=True)
setattr(options, clr, value)
for pref in options._prefs:
value = cmds.displayPref(query=True, **{pref: True})
setattr(options, pref, value)
def set(self):
"""Applies the options."""
from maya import cmds
for clr in self._colors:
value = getattr(self, clr)
cmds.displayRGBColor(clr, *value)
for pref in self._prefs:
value = getattr(self, pref)
cmds.displayPref(**{pref: value})
And to set the values we need to set attributes on the hardwareRendering
node
Theoretically we could just make a dictionary for all attribute settings that exists that coincide with a getter and setter.
settings = {
'background': (displayRGBColorGetter, displayRGBColorSetter),
'backgroundTop ': (displayRGBColorGetter, displayRGBColorSetter),
'backgroundBottom ': (displayRGBColorGetter, displayRGBColorSetter)
}
And so forth.
The applying of the settings in a context manager could be along the lines of:
@contextlib.contextmanager
def apply_options(options):
original= {}
for opt, value in options.iteritems():
getter, setter = settings[opt]
original[opt] = getter()
setter(value)
try:
yield
finally:
for opt, value in original.iteritems():
setter = settings[opt][1]
setter(value)
Tricky bit there being that some of the commands require access to the camera, others to the modelPanel, etc, etc.
We just need a mapping somewhere on how specific sets of attributes need to be handled.
Here's how I'm thinking.
The argument signature for capture
looks like this.
def capture(camera=None,
width=None,
height=None,
filename=None,
start_frame=None,
end_frame=None,
frame=None,
format='qt',
compression='h264',
quality=100,
off_screen=False,
viewer=True,
isolate=None,
maintain_aspect_ratio=True,
overwrite=False,
raw_frame_numbers=False,
camera_options=None,
viewport_options=None,
display_options=None,
complete_filename=None):
A "preset" then, could be a dictionary of exactly this.
{
"camera": "persp",
"width": "512",
"height": "256",
"filename": "default",
# ...
}
Where the currently complex options are just an additional level of keys.
{
"camera": "persp",
# ...
"camera_options": {
"displayGateMask": false,
"displayResolution": false,
"displayFilmGate": false
}
}
I feel classes can get complex fast, and I'd rather not introduce more complexity unless we must.
Sure. I wanted to step away from classes as well. It's just that there are "options" not yet currently implemented that need a new argument in that case.
As such mentioned simplifying the interface to the user, just options
and the parser/retriever of the options to manage how to go about it for a certain option/setting.
The separation for "camera_options", etc could still stay and could be the abstraction of what needs to be passed to the methods. E.g. "panel_options" will be given the modelPanel along with it. "camera_options" the camera.
Could that make sense?
And there should then still be a way to retrieve the current state of "camera_options", etc.
From an artist perspective just "options" would be the simplest one. Even though we need some handling in the parser of current settings and applying them.
I don't know what you mean @BigRoy, but I've mocked up an example of something that works.
Let's continue the discussion about presets in there.
Presets aside, was it straightforward to setup a PR for this?
Presets aside, was it straightforward to setup a PR for this?
It shouldn't be that hard. It might introduce another "options" type though, since this uses another command again.
That's other commands than what the camera_options
, display_options
, viewport_options
require to operate. Would this just become viewport2_options
?
For clarity sakes it would become something like:
Viewport2Options = {
transparencyAlghorithm: 1,
motionBlurEnable: 0,
motionBlurType: 0 ,
motionBlurShutterOpenFraction: 0.2,
motionBlurSampleCount: 8,
lineAAEnable: 0,
multiSampleEnable: 0,
multiSampleCount: 8,
ssaoEnable: 1,
ssaoRadius: 16,
ssaoFilterRadius: 16,
ssaoAmount: 1.0,
ssaoSamples: 8
}
And more parameters.
Ah, yeah, that looks intuitive enough. Good thinking!
So had a quick look at the available attributes on the hardwareRenderingGlobals
and here's a quick capture from it:
{
"bloomAmount": 1.0,
"bloomEnable": False,
"bloomFilterAux": 0.0,
"bloomFilterRadius": 0.0,
"bloomThreshold": 0.0,
"bumpBakeResolution": 64,
"colorBakeResolution": 64,
"compressSharedVertexData": True,
"consolidateWorld": True,
"enableTextureMaxRes": False,
"floatingPointRTEnable": True,
"floatingPointRTFormat": 1,
"gammaCorrectionEnable": False,
"gammaValue": 2.2,
"holdOutDetailMode": 1,
"holdOutMode": True,
"hwFogAlpha": 1.0,
"hwFogColorB": 0.5,
"hwFogColorG": 0.5,
"hwFogColorR": 0.5,
"hwFogDensity": 0.1,
"hwFogEnable": False,
"hwFogEnd": 100.0,
"hwFogFalloff": 0,
"hwFogStart": 0.0,
"hwInstancing": False,
"lightingMode": 1,
"lineAAEnable": False,
"maxHardwareLights": 8,
"motionBlurAtlasSizeX": 8,
"motionBlurAtlasSizeY": 4,
"motionBlurCurved": False,
"motionBlurEnable": False,
"motionBlurFadeAmount": 0.5,
"motionBlurFadeEmphasis": 0.0,
"motionBlurFadeTintA": 1.0,
"motionBlurFadeTintB": 0.0,
"motionBlurFadeTintG": 0.0,
"motionBlurFadeTintR": 0.0,
"motionBlurMultiframeChartSizeX": 256,
"motionBlurMultiframeChartSizeY": 256,
"motionBlurMultiframeEnable": False,
"motionBlurSampleCount": 8,
"motionBlurShutterOpenFraction": 0.2,
"motionBlurType": 0,
"multiSampleCount": 8,
"multiSampleEnable": False,
"multiSampleQuality": 0,
"renderDepthOfField": True,
"renderMode": 4,
"singleSidedLighting": False,
"ssaoAmount": 1.0,
"ssaoEnable": False,
"ssaoFilterRadius": 16,
"ssaoRadius": 16,
"ssaoSamples": 16,
"textureMaxResolution": 4096,
"threadDGEvaluation": False,
"transparencyAlgorithm": 1,
"transparencyQuality": 0.33,
"useMaximumHardwareLights": True,
"vertexAnimationCache": 0,
"xrayJointDisplay": False,
"xrayMode": False
}
Quite the amount. Is there anything we want to filter out?
Most of this just came from doing a listAttr
on the node and removing things like the frozen
, isHistoricallyInteresting
, etc. attribtues that all nodes have in Maya.
This is also with the default values in a new scene.
Some might only be used for a hardware render and not for a Viewport 2.0 setting, whereas others are actually used for Viewport 2.0. I can go through them mostly manually to find those... (e.g. I haven't seen "bloom" in viewport 2.0 anywhere).
Yeah, we probably only want to keep those relevant to vp2.0.
Maybe as a test, to find which belong to vp2.0, you could run each through the command, and collect those that don't error out?
Maybe as a test, to find which belong to vp2.0, you could run each through the command, and collect those that don't error out?
They are all real attributes. How would they "error out"? Anyway, will quickly filter manually. Should be fine.
Sorry, wasn't there a viewport2 command? If the all work, then I'd keep them. The less personal choice and more reproducibility we can get the better. Odds are they will appear in VP2.0 sometime later.
Sorry, wasn't there a viewport2 command?
Basically the settings are different from the other settings, because these are housed on another node. In this case the hardwareRenderingGlobals
where e.g. camera attributes are on the camera, the viewport options are on the modelEditor. etc.
The less personal choice and more reproducibility we can get the better. Odds are they will appear in VP2.0 sometime later.
I'll just put in the full list for now and ensure it doesn't error out on anything. Good thinking.
It's quite confusing though, since the xrayJointDisplay
and xrayMode
don't do anything in the viewport. For that you'd use modelEditor
command. Maybe still filter it a little?
Seeing as the user can provide options that aren't already in these dicts, yeah, maybe let's just include what we think is right so it can be used for reference.
Adding or removing would basically only be for documentation and shouldn't break anything.
Pick the ones you think are a good fit; don't sweat accuracy.
Ok, filtered to this:
{
"bumpBakeResolution": 64,
"colorBakeResolution": 64,
"consolidateWorld": True,
"enableTextureMaxRes": False,
"floatingPointRTEnable": True,
"floatingPointRTFormat": 1,
"gammaCorrectionEnable": False,
"gammaValue": 2.2,
"holdOutDetailMode": 1,
"holdOutMode": True,
"hwFogAlpha": 1.0,
"hwFogColorR": 0.5,
"hwFogColorG": 0.5,
"hwFogColorB": 0.5,
"hwFogDensity": 0.1,
"hwFogEnable": False,
"hwFogEnd": 100.0,
"hwFogFalloff": 0,
"hwFogStart": 0.0,
"lineAAEnable": False,
"maxHardwareLights": 8,
"motionBlurEnable": False,
"motionBlurSampleCount": 8,
"motionBlurShutterOpenFraction": 0.2,
"motionBlurType": 0,
"multiSampleCount": 8,
"multiSampleEnable": False,
"singleSidedLighting": False,
"ssaoAmount": 1.0,
"ssaoEnable": False,
"ssaoFilterRadius": 16,
"ssaoRadius": 16,
"ssaoSamples": 16,
"textureMaxResolution": 4096,
"threadDGEvaluation": False,
"transparencyAlgorithm": 1,
"transparencyQuality": 0.33,
"useMaximumHardwareLights": True,
"vertexAnimationCache": 0
}
Coming up in a bit.
:+1:
Noticed some other missing settings on ViewportOptions
that were giving me inconsistent results in the playblasts. So I'm adding those in as well at the same time. (Allowed me to debug it easier)...
We all like options.
Closed with #31
Including simply using it, but also specifying flags such as anti-alias, motion-blur etc.