Open portsmouth opened 1 month ago
Oops, that pseudocode is not legit Python. Will fix. (Fixed, and in comment above).
I also put together a Python script which will run the exact Python pseudocode given in the spec, and report which parameters should be disabled based on their current state. We could maybe ship this with the spec, to show how it might be done in a plugin? (Can be improved to make it a tiny Python API that could be slotted in, giving the enable state of all controls given the parameter values dict).
Output:
$ python scripts/disabling.py
Non-default params
specular_weight = 0.0
transmission_weight = 1.0
=> Resulting enable state:
base_color : **disabled**
base_diffuse_roughness : **disabled**
base_metalness : enabled
base_weight : **disabled**
coat_color : disabled
coat_darkening : disabled
coat_ior : disabled
coat_roughness : disabled
coat_roughness_anisotropy : disabled
coat_weight : enabled
emission_color : enabled
emission_luminance : enabled
fuzz_color : disabled
fuzz_roughness : disabled
fuzz_weight : enabled
geometry_opacity : enabled
geometry_thin_walled : enabled
specular_color : **disabled**
specular_ior : **disabled**
specular_roughness : **disabled**
specular_roughness_anisotropy : **disabled**
specular_weight : enabled
subsurface_color : disabled
subsurface_radius : disabled
subsurface_radius_scale : disabled
subsurface_scatter_anisotropy : disabled
subsurface_weight : enabled
thin_film_ior : disabled
thin_film_thickness : disabled
thin_film_weight : enabled
transmission_color : **enabled**
transmission_depth : **enabled**
transmission_dispersion_abbe_number : **enabled**
transmission_dispersion_scale : **enabled**
transmission_scatter : **enabled**
transmission_scatter_anisotropy : **enabled**
transmission_weight : enabled
Script:
openpbr_params = {
'base_weight' : 1.0,
'base_color' : (0.8, 0.8, 0.8),
'base_metalness' : 0.0,
'base_diffuse_roughness' : 0.0,
'specular_weight' : 1.0,
'specular_color' : (1.0, 1.0, 1.0),
'specular_roughness' : 0.3,
'specular_roughness_anisotropy' : 0.0,
'specular_ior' : 1.5,
'transmission_weight' : 0.0,
'transmission_color' : (1.0, 1.0, 1.0),
'transmission_depth' : 0.0,
'transmission_scatter' : (0.0, 0.0, 0.0),
'transmission_scatter_anisotropy' : 0.0,
'transmission_dispersion_scale' : 0.0,
'transmission_dispersion_abbe_number': 20.0,
'subsurface_weight' : 0.0,
'subsurface_color' : (0.8, 0.8, 0.8),
'subsurface_radius' : 1.0,
'subsurface_radius_scale' : (1.0, 0.5, 0.25),
'subsurface_scatter_anisotropy' : 0.0,
'coat_weight' : 0.0,
'coat_color' : (1.0, 1.0, 1.0),
'coat_roughness' : 0.0,
'coat_roughness_anisotropy' : 0.0,
'coat_ior' : 1.6,
'coat_darkening' : 1.0,
'fuzz_weight' : 0.0,
'fuzz_color' : (1.0, 1.0, 1.0),
'fuzz_roughness' : 0.5,
'emission_luminance' : 0.0,
'emission_color' : (1.0, 1.0, 1.0),
'thin_film_weight' : 0.0,
'thin_film_thickness' : 0.5,
'thin_film_ior' : 1.4,
'geometry_opacity' : 1.0,
'geometry_thin_walled' : False
}
def got_match(p, prefixes):
if not prefixes: return False
if not isinstance(prefixes, list): P = [prefixes]
else: P = prefixes
for prefix in P:
if p.startswith(prefix):
return True
return False
def disable(P, skip=None):
for p in openpbr_params:
if got_match(p, P) and not got_match(p, skip):
param_states[p] = False
param_states = {}
def ui_logic(openpbr_params):
global param_states
for P in openpbr_params:
param_states[P] = True
fuzz_weight = openpbr_params['fuzz_weight']
coat_weight = openpbr_params['coat_weight']
base_metalness = openpbr_params['base_metalness']
transmission_weight = openpbr_params['transmission_weight']
subsurface_weight = openpbr_params['subsurface_weight']
specular_weight = openpbr_params['specular_weight']
thin_film_weight = openpbr_params['thin_film_weight']
geometry_thin_walled = openpbr_params['geometry_thin_walled']
############################################################################################################
# spec pseudo-code
############################################################################################################
has_fuzz = (fuzz_weight > 0.0)
has_coat = (coat_weight > 0.0)
has_metal = (base_metalness > 0.0)
has_dielectric = (base_metalness < 1.0)
has_dielectric_transp = has_dielectric and (transmission_weight > 0.0)
has_dielectric_opaque = has_dielectric and (transmission_weight < 1.0)
has_subsurface = has_dielectric_opaque and (subsurface_weight > 0.0)
has_diffuse = has_dielectric_opaque and (subsurface_weight < 1.0)
if not has_fuzz: disable("fuzz", skip="fuzz_weight")
if not has_coat:
disable("coat", skip="coat_weight")
disable("geometry_coat_tangent")
if not has_dielectric: disable("specular_ior")
if not has_dielectric_transp: disable("transmission", skip="transmission_weight")
if not has_dielectric_opaque and not has_metal: disable(["base_weight", "base_color"])
if not has_subsurface: disable("subsurface", skip="subsurface_weight")
if not has_diffuse: disable("base_diffuse_roughness")
if (specular_weight == 0): disable("specular", skip="specular_weight")
if (thin_film_weight == 0): disable("thin_film", skip="thin_film_weight")
# In thin-walled mode, the volumetric medium is infinitesimally thin so the parameters controlling
# the MFP of the medium are irrelevant
if (geometry_thin_walled):
disable("transmission", skip=["transmission_weight", "transmission_color"])
disable("subsurface_radius") # (NB, also disables subsurface_radius_scale)
############################################################################################################
return param_states
if __name__ == '__main__':
openpbr_params_default = openpbr_params.copy()
default_states = ui_logic(openpbr_params).copy()
#############################################
# Param modifications
#############################################
openpbr_params['specular_weight'] = 0.0
openpbr_params['transmission_weight'] = 1.0
# Print non-default params
print("Non-default params")
for P in openpbr_params:
val = openpbr_params[P]
default_val = openpbr_params_default[P]
if val != default_val:
print(' %s = %s' % (P, val))
# Run disabling logic
param_states = ui_logic(openpbr_params)
# Show resulting states, with non-default values highlighted
print('\n=> Resulting enable state:')
for P in sorted(openpbr_params.keys()):
s = 'enabled' if param_states[P] else 'disabled'
if param_states[P] != default_states[P]:
s = '**' + s + '**'
print(" {0:40}: {1}".format(P, s))
Add section describing the "recommended logic needed to determine which of the parameters can be disabled".
This describes the parameters which can safely be disabled (e.g. their UI element greyed out) in the current configuration, according to which parts of the material graph are excised, which can be read off from the tree diagram.
This is given in the form of some fairly self-explanatory Python pseudocode, which is easier to understand and more concise than a wordy verbal description. (And probably translates quite easily into the corresponding UI code in whatever form each DCC implements it).
(All of the Arnold plugin integrations will implement such logic).
(NB, the wrong 4.18 numbering in the heading is an unrelated bug which we're trying to figure out).