2 # -*- coding: utf-8 -*-
5 Defines objects creating the *ACES* configuration.
8 from __future__ import division
15 import PyOpenColorIO as ocio
16 from aces_ocio.colorspaces import aces
17 from aces_ocio.colorspaces import arri
18 from aces_ocio.colorspaces import canon
19 from aces_ocio.colorspaces import general
20 from aces_ocio.colorspaces import gopro
21 from aces_ocio.colorspaces import panasonic
22 from aces_ocio.colorspaces import red
23 from aces_ocio.colorspaces import sony
24 from aces_ocio.process import Process
26 from aces_ocio.utilities import replace, ColorSpace, compact
28 __author__ = 'ACES Developers'
29 __copyright__ = 'Copyright (C) 2014 - 2015 - ACES Developers'
31 __maintainer__ = 'ACES Developers'
32 __email__ = 'aces@oscars.org'
33 __status__ = 'Production'
35 __all__ = ['ACES_OCIO_CTL_DIRECTORY_ENVIRON',
36 'ACES_OCIO_CONFIGURATION_DIRECTORY_ENVIRON',
37 'set_config_default_roles',
39 'generate_OCIO_transform',
40 'add_colorspace_alias',
43 'generate_baked_LUTs',
48 ACES_OCIO_CTL_DIRECTORY_ENVIRON = 'ACES_OCIO_CTL_DIRECTORY'
49 ACES_OCIO_CONFIGURATION_DIRECTORY_ENVIRON = 'ACES_OCIO_CONFIGURATION_DIRECTORY'
52 def set_config_default_roles(config,
63 compositing_linear=''):
65 Sets given *OCIO* configuration default roles.
71 color_picking : str or unicode
72 Color picking role title.
73 color_timing : str or unicode
74 Color timing role title.
75 compositing_log : str or unicode
76 Compositing log role title.
79 default : str or unicode
81 matte_paint : str or unicode
82 Matte painting role title.
83 reference : str or unicode
85 scene_linear : str or unicode
86 Scene linear role title.
87 texture_paint : str or unicode
88 Texture painting role title.
97 config.setRole(ocio.Constants.ROLE_COLOR_PICKING, color_picking)
99 config.setRole(ocio.Constants.ROLE_COLOR_TIMING, color_timing)
101 config.setRole(ocio.Constants.ROLE_COMPOSITING_LOG, compositing_log)
103 config.setRole(ocio.Constants.ROLE_DATA, data)
105 config.setRole(ocio.Constants.ROLE_DEFAULT, default)
107 config.setRole(ocio.Constants.ROLE_MATTE_PAINT, matte_paint)
109 config.setRole(ocio.Constants.ROLE_REFERENCE, reference)
111 config.setRole(ocio.Constants.ROLE_TEXTURE_PAINT, texture_paint)
113 # 'rendering' and 'compositing_linear' roles default to the 'scene_linear'
114 # value if not set explicitly
116 config.setRole("rendering", rendering)
117 if compositing_linear:
118 config.setRole("compositing_linear", compositing_linear)
120 config.setRole(ocio.Constants.ROLE_SCENE_LINEAR, scene_linear)
122 config.setRole("rendering", scene_linear)
123 if not compositing_linear:
124 config.setRole("compositing_linear", scene_linear)
129 def write_config(config, config_path, sanity_check=True):
131 Writes the configuration to given path.
136 Parameter description.
141 Return value description.
149 print 'Configuration was not written due to a failed Sanity Check'
152 with open(config_path, mode='w') as fp:
153 fp.write(config.serialize())
156 def generate_OCIO_transform(transforms):
163 Parameter description.
168 Return value description.
171 interpolation_options = {
172 'linear': ocio.Constants.INTERP_LINEAR,
173 'nearest': ocio.Constants.INTERP_NEAREST,
174 'tetrahedral': ocio.Constants.INTERP_TETRAHEDRAL}
176 direction_options = {
177 'forward': ocio.Constants.TRANSFORM_DIR_FORWARD,
178 'inverse': ocio.Constants.TRANSFORM_DIR_INVERSE}
182 for transform in transforms:
185 if transform['type'] == 'lutFile':
187 ocio_transform = ocio.FileTransform()
189 if 'path' in transform:
190 ocio_transform.setSrc(transform['path'])
192 if 'cccid' in transform:
193 ocio_transform.setCCCId(transform['cccid'])
195 if 'interpolation' in transform:
196 ocio_transform.setInterpolation(transform['interpolation'])
198 ocio_transform.setInterpolation(ocio.Constants.INTERP_BEST)
200 if 'direction' in transform:
201 ocio_transform.setDirection(
202 direction_options[transform['direction']])
204 ocio_transforms.append(ocio_transform)
207 elif transform['type'] == 'matrix':
208 ocio_transform = ocio.MatrixTransform()
209 # MatrixTransform member variables can't be initialized directly.
210 # Each must be set individually.
211 ocio_transform.setMatrix(transform['matrix'])
213 if 'offset' in transform:
214 ocio_transform.setOffset(transform['offset'])
216 if 'direction' in transform:
217 ocio_transform.setDirection(
218 direction_options[transform['direction']])
220 ocio_transforms.append(ocio_transform)
223 elif transform['type'] == 'exponent':
224 ocio_transform = ocio.ExponentTransform()
226 if 'value' in transform:
227 ocio_transform.setValue(transform['value'])
229 ocio_transforms.append(ocio_transform)
232 elif transform['type'] == 'log':
233 ocio_transform = ocio.LogTransform()
235 if 'base' in transform:
236 ocio_transform.setBase(transform['base'])
238 if 'direction' in transform:
239 ocio_transform.setDirection(
240 direction_options[transform['direction']])
242 ocio_transforms.append(ocio_transform)
244 # color space transform
245 elif transform['type'] == 'colorspace':
246 ocio_transform = ocio.ColorSpaceTransform()
248 if 'src' in transform:
249 ocio_transform.setSrc(transform['src'])
251 if 'dst' in transform:
252 ocio_transform.setDst(transform['dst'])
254 if 'direction' in transform:
255 ocio_transform.setDirection(
256 direction_options[transform['direction']])
258 ocio_transforms.append(ocio_transform)
261 elif transform['type'] == 'look':
262 ocio_transform = ocio.LookTransform()
263 if 'look' in transform:
264 ocio_transform.setLooks(transform['look'])
266 if 'src' in transform:
267 ocio_transform.setSrc(transform['src'])
269 if 'dst' in transform:
270 ocio_transform.setDst(transform['dst'])
272 if 'direction' in transform:
273 ocio_transform.setDirection(
274 direction_options[transform['direction']])
276 ocio_transforms.append(ocio_transform)
280 print("Ignoring unknown transform type : %s" % transform['type'])
282 if len(ocio_transforms) > 1:
283 group_transform = ocio.GroupTransform()
284 for transform in ocio_transforms:
285 group_transform.push_back(transform)
286 transform = group_transform
288 transform = ocio_transforms[0]
293 def add_colorspace_alias(config,
294 reference_colorspace,
296 colorspace_alias_names):
303 Parameter description.
308 Return value description.
311 for alias_name in colorspace_alias_names:
312 if alias_name.lower() == colorspace.name.lower():
313 print('Skipping alias creation for %s, alias %s, because lower cased names match' % (
314 colorspace.name, alias_name) )
317 print('Adding alias colorspace space %s, alias to %s' % (
318 alias_name, colorspace.name))
320 compact_family_name = 'Aliases'
322 ocio_colorspace_alias = ocio.ColorSpace(
324 bitDepth=colorspace.bit_depth,
325 description=colorspace.description,
326 equalityGroup=colorspace.equality_group,
327 family=compact_family_name,
328 isData=colorspace.is_data,
329 allocation=colorspace.allocation_type,
330 allocationVars=colorspace.allocation_vars)
332 if colorspace.to_reference_transforms:
333 print('\tGenerating To-Reference transforms')
334 ocio_transform = generate_OCIO_transform(
335 [{'type': 'colorspace',
336 'src': colorspace.name,
337 'dst': reference_colorspace.name,
338 'direction': 'forward'}])
339 ocio_colorspace_alias.setTransform(
341 ocio.Constants.COLORSPACE_DIR_TO_REFERENCE)
343 if colorspace.from_reference_transforms:
344 print('\tGenerating From-Reference transforms')
345 ocio_transform = generate_OCIO_transform(
346 [{'type': 'colorspace',
347 'src': reference_colorspace.name,
348 'dst': colorspace.name,
349 'direction': 'forward'}])
350 ocio_colorspace_alias.setTransform(
352 ocio.Constants.COLORSPACE_DIR_FROM_REFERENCE)
354 config.addColorSpace(ocio_colorspace_alias)
356 def colorspace_prefixed_name(colorspace):
357 prefix = colorspace.family.replace("/", " - ")
358 return "%s - %s" % (prefix, colorspace.name)
366 multiple_displays=False):
373 Parameter description.
378 Return value description.
382 look_colorspace = look[1]
388 print('Adding look %s - %s' % (look_name, ", ".join(look)) )
394 if not '$' in look_lut:
395 print( "Getting ready to copy look lut : %s" % look_lut )
396 shutil.copy2(look_lut, custom_lut_dir)
397 look_lut = os.path.split(look_lut)[1]
399 print( "Skipping LUT copy because path contains a context variable" )
405 print('Adding look to config' )
407 lk1.setName( look_name )
408 lk1.setProcessSpace( look_colorspace )
410 keys = {'type': 'lutFile',
412 'direction': 'forward'}
414 keys['cccid'] = look_cccid
416 ocio_transform = generate_OCIO_transform([keys])
417 lk1.setTransform( ocio_transform )
420 config.addLook( lk1 )
422 print( "Creating aliased colorspace")
425 # Create OCIO colorspace that references that look
426 # - Needed for some implementations that don't process looks well
427 # - Also needed for some implementations that don't expose looks well
429 look_aliases = ["look_%s" % compact(look_name)]
430 colorspace = ColorSpace(look_name,
431 aliases=look_aliases,
432 description="The %s Look colorspace" % look_name,
435 colorspace.from_reference_transforms = [{'type': 'look',
437 'src': reference_name,
438 'dst': reference_name,
439 'direction': 'forward'}]
441 print('Adding colorspace %s, alias to look %s to config data' % (
442 look_name, look_name))
444 # Add this colorspace into the main list of colorspaces
445 config_data['colorSpaces'].append(colorspace)
449 def integrate_looks_into_views(config,
453 multiple_displays=False):
460 Parameter description.
465 Return value description.
467 look_names = [look[0] for look in looks]
469 # Option 1 - Add a 'look' to each Display
470 # - Assumes there is a Display for each ACES Output Transform
471 if multiple_displays:
472 for look_name in look_names:
473 config_data['looks'].append(look_name)
476 # - Copy each Output Transform colorspace
477 # - For each copy, add a LookTransform at the head of the from_reference
479 # - Add these new copied colorspaces for the Displays / Views
481 for display, view_list in config_data['displays'].iteritems():
482 output_colorspace_copy = None
483 look_names_string = ""
484 for view_name, output_colorspace in view_list.iteritems():
485 if view_name == "Output Transform":
487 print( "Adding new View that incorporates looks" )
489 # Make a copy of the output colorspace
490 output_colorspace_copy = copy.deepcopy(output_colorspace)
492 #for look_name in look_names:
493 for i in range(len(look_names)):
494 look_name = look_names[i]
496 # Add the LookTransform to the head of the from_reference transform list
497 if output_colorspace_copy.from_reference_transforms:
498 output_colorspace_copy.from_reference_transforms.insert(i, {'type': 'look',
500 'src': reference_name,
501 'dst': reference_name,
502 'direction': 'forward'})
504 # Add the LookTransform to the end of the to_reference transform list
505 if output_colorspace_copy.to_reference_transforms:
506 inverse_look_name = look_names[len(look_names) -1 -i]
508 output_colorspace_copy.to_reference_transforms.append({'type': 'look',
509 'look': inverse_look_name,
510 'src': reference_name,
511 'dst': reference_name,
512 'direction': 'inverse'})
514 if not look_name in config_data['looks']:
515 config_data['looks'].append(look_name)
517 look_names_string = ", ".join(look_names)
518 output_colorspace_copy.name = "%s with %s" % (output_colorspace.name, look_names_string)
519 output_colorspace_copy.aliases = ["out_%s" % compact(output_colorspace_copy.name)]
521 print( "Colorspace that incorporates looks created : %s" % output_colorspace_copy.name )
523 config_data['colorSpaces'].append(output_colorspace_copy)
525 if output_colorspace_copy:
526 print( "Adding colorspace that incorporates looks into view list" )
528 # Change the name of the View
529 view_list["Output Transform with %s" % look_names_string] = output_colorspace_copy
530 config_data['displays'][display] = view_list
532 #print( "Display : %s, View List : %s" % (display, ", ".join(view_list)) )
534 def create_config(config_data,
537 multiple_displays=False,
539 custom_lut_dir=None):
546 Parameter description.
551 Return value description.
555 alias_colorspaces = []
557 # Creating the *OCIO* configuration.
558 config = ocio.Config()
560 # Setting configuration description.
561 config.setDescription('An ACES config generated from python')
563 # Setting configuration search path.
564 searchPath = ['luts']
566 searchPath.append('custom')
567 config.setSearchPath(':'.join(searchPath))
569 # Defining the reference colorspace.
570 reference_data = config_data['referenceColorSpace']
572 # Adding the color space Family into the name
573 # Helps with applications that present colorspaces as one long list
575 prefixed_name = colorspace_prefixed_name(reference_data)
576 prefixed_names[reference_data.name] = prefixed_name
577 reference_data.name = prefixed_name
579 print('Adding the reference color space : %s' % reference_data.name)
581 reference = ocio.ColorSpace(
582 name=reference_data.name,
583 bitDepth=reference_data.bit_depth,
584 description=reference_data.description,
585 equalityGroup=reference_data.equality_group,
586 family=reference_data.family,
587 isData=reference_data.is_data,
588 allocation=reference_data.allocation_type,
589 allocationVars=reference_data.allocation_vars)
591 config.addColorSpace(reference)
595 if reference_data.aliases != []:
596 #add_colorspace_alias(config, reference_data,
597 # reference_data, reference_data.aliases)
598 # defer adding alias colorspaces until end. Helps with some applications
599 alias_colorspaces.append([reference_data, reference_data, reference_data.aliases])
604 #print( "color spaces : %s" % [x.name for x in sorted(config_data['colorSpaces'])])
607 # Add Looks and Look colorspaces
610 print('Adding looks')
612 config_data['looks'] = []
614 # Add looks and colorspaces
615 for look in look_info:
623 # Integrate looks with displays, views
624 integrate_looks_into_views(config,
632 print('Adding the regular color spaces')
634 # Creating the remaining colorspaces.
635 for colorspace in sorted(config_data['colorSpaces']):
636 # Adding the color space Family into the name
637 # Helps with applications that present colorspaces as one long list
639 prefixed_name = colorspace_prefixed_name(colorspace)
640 prefixed_names[colorspace.name] = prefixed_name
641 colorspace.name = prefixed_name
643 print('Creating new color space : %s' % colorspace.name)
645 ocio_colorspace = ocio.ColorSpace(
646 name=colorspace.name,
647 bitDepth=colorspace.bit_depth,
648 description=colorspace.description,
649 equalityGroup=colorspace.equality_group,
650 family=colorspace.family,
651 isData=colorspace.is_data,
652 allocation=colorspace.allocation_type,
653 allocationVars=colorspace.allocation_vars)
655 if colorspace.to_reference_transforms:
656 print('\tGenerating To-Reference transforms')
657 ocio_transform = generate_OCIO_transform(
658 colorspace.to_reference_transforms)
659 ocio_colorspace.setTransform(
661 ocio.Constants.COLORSPACE_DIR_TO_REFERENCE)
663 if colorspace.from_reference_transforms:
664 print('\tGenerating From-Reference transforms')
665 ocio_transform = generate_OCIO_transform(
666 colorspace.from_reference_transforms)
667 ocio_colorspace.setTransform(
669 ocio.Constants.COLORSPACE_DIR_FROM_REFERENCE)
671 config.addColorSpace(ocio_colorspace)
674 # Add alias to normal colorspace, using compact name
677 if colorspace.aliases != []:
678 #add_colorspace_alias(config, reference_data,
679 # colorspace, colorspace.aliases)
680 # defer adding alias colorspaces until end. Helps with some applications
681 alias_colorspaces.append([reference_data, colorspace, colorspace.aliases])
687 # We add these at the end as some applications use the order of the colorspaces
688 # definitions in the config to order the colorspaces in their selection lists.
689 # Other go alphabetically. This should keep the alias colorspaces out of the way
690 # for the apps that use the order of definition in the config.
691 print('Adding the alias colorspaces')
692 for reference, colorspace, aliases in alias_colorspaces:
693 add_colorspace_alias(config, reference, colorspace, aliases)
697 print('Adding the diplays and views')
699 # Defining the *views* and *displays*.
704 # Defining a *generic* *display* and *view* setup.
705 if multiple_displays:
706 # Built list of looks to add to Displays
707 looks = config_data['looks'] if ('looks' in config_data) else []
708 looks = ", ".join(looks)
709 print( "Creating multiple displays, with looks : %s" % looks)
711 # Create Displays, Views
712 for display, view_list in config_data['displays'].iteritems():
713 for view_name, colorspace in view_list.iteritems():
714 config.addDisplay(display, view_name, colorspace.name, looks)
715 if 'Output Transform' in view_name and looks != "":
716 # Add normal View, without looks
717 config.addDisplay(display, view_name, colorspace.name)
719 # Add View with looks
720 view_name_with_looks = "%s with %s" % (view_name, looks)
721 config.addDisplay(display, view_name_with_looks, colorspace.name, looks)
723 config.addDisplay(display, view_name, colorspace.name)
724 if not (view_name in views):
725 views.append(view_name)
726 displays.append(display)
729 # Defining the set of *views* and *displays* useful in a *GUI* context.
730 #display_name = 'ACES'
731 single_display_name = config_data['roles']['scene_linear']
732 displays.append(single_display_name)
734 display_names = sorted(config_data['displays'])
736 # Make sure the default display is first
737 default_display = config_data['defaultDisplay']
738 display_names.insert(0, display_names.pop(display_names.index(default_display)))
740 # Built list of looks to add to Displays
741 looks = config_data['looks'] if ('looks' in config_data) else []
742 look_names = ", ".join(looks)
744 displays_views_colorspaces = []
746 # Create Displays, Views
747 for display in display_names:
748 view_list = config_data['displays'][display]
749 for view_name, colorspace in view_list.iteritems():
750 if 'Output Transform' in view_name:
751 #print( "Adding view for %s" % view_name )
753 # Maya 2016 doesn't like parentheses in View names
754 display_cleaned = replace(display, {')': '', '(': ''})
756 # We use the Display names as the View names in this case
757 # as there is a single Display that contains all views.
758 # This works for more applications than not, as of the time of this implementation.
760 # If View includes looks
761 if 'with' in view_name:
762 # Integrate looks into view name
763 display_cleaned = "%s with %s" % (display_cleaned, look_names)
765 viewsWithLooksAtEnd = False
766 # Storing combo of display, view and colorspace name in a list so we can
767 # add them to the end of the list
768 if viewsWithLooksAtEnd:
769 displays_views_colorspaces.append([single_display_name, display_cleaned, colorspace.name])
773 config.addDisplay(single_display_name, display_cleaned, colorspace.name)
776 if not (display_cleaned in views):
777 views.append(display_cleaned)
781 config.addDisplay(single_display_name, display_cleaned, colorspace.name)
784 if not (display_cleaned in views):
785 views.append(display_cleaned)
787 # Add to config any display, view combinations that were saved for later
788 for display_view_colorspace in displays_views_colorspaces:
789 single_display_name, display_cleaned, colorspace_name = display_view_colorspace
792 config.addDisplay(single_display_name, display_cleaned, colorspace_name)
795 if not (display_cleaned in views):
796 views.append(display_cleaned)
799 # Works with Nuke Studio and Mari, but not Nuke
800 # single_display_name = 'Utility'
801 # displays.append(single_display_name)
803 linear_display_space_name = config_data['roles']['scene_linear']
804 log_display_space_name = config_data['roles']['compositing_log']
806 # Find the newly-prefixed colorspace names
808 #print( prefixed_names )
809 linear_display_space_name = prefixed_names[linear_display_space_name]
810 log_display_space_name = prefixed_names[log_display_space_name]
812 config.addDisplay(single_display_name, 'Raw', linear_display_space_name)
814 config.addDisplay(single_display_name, 'Log', log_display_space_name)
817 # Setting the active *displays* and *views*.
818 config.setActiveDisplays(','.join(sorted(displays)))
819 config.setActiveViews(','.join(views))
823 print('Setting the roles')
826 set_config_default_roles(
828 color_picking=prefixed_names[config_data['roles']['color_picking']],
829 color_timing=prefixed_names[config_data['roles']['color_timing']],
830 compositing_log=prefixed_names[config_data['roles']['compositing_log']],
831 data=prefixed_names[config_data['roles']['data']],
832 default=prefixed_names[config_data['roles']['default']],
833 matte_paint=prefixed_names[config_data['roles']['matte_paint']],
834 reference=prefixed_names[config_data['roles']['reference']],
835 scene_linear=prefixed_names[config_data['roles']['scene_linear']],
836 texture_paint=prefixed_names[config_data['roles']['texture_paint']])
838 set_config_default_roles(
840 color_picking=config_data['roles']['color_picking'],
841 color_timing=config_data['roles']['color_timing'],
842 compositing_log=config_data['roles']['compositing_log'],
843 data=config_data['roles']['data'],
844 default=config_data['roles']['default'],
845 matte_paint=config_data['roles']['matte_paint'],
846 reference=config_data['roles']['reference'],
847 scene_linear=config_data['roles']['scene_linear'],
848 texture_paint=config_data['roles']['texture_paint'])
852 # Make sure we didn't create a bad config
855 # Reset the colorspace names back to their non-prefixed versions
857 # Build the reverse lookup
858 prefixed_names_inverse = {}
859 for original, prefixed in prefixed_names.iteritems():
860 prefixed_names_inverse[prefixed] = original
862 # Reet the reference colorspace name
863 reference_data.name = prefixed_names_inverse[reference_data.name]
865 # Reset the rest of the colorspace names
866 for colorspace in config_data['colorSpaces']:
867 colorspace.name = prefixed_names_inverse[colorspace.name]
872 def generate_LUTs(odt_info,
877 lut_resolution_1d=4096,
878 lut_resolution_3d=64,
886 Parameter description.
891 Colorspaces and transforms converting between those colorspaces and
892 the reference colorspace, *ACES*.
895 print('generateLUTs - begin')
898 # Initialize a few variables
899 config_data['displays'] = {}
900 config_data['colorSpaces'] = []
902 # -------------------------------------------------------------------------
903 # *ACES Color Spaces*
904 # -------------------------------------------------------------------------
910 aces_log_display_space,
912 aces_default_display) = aces.create_colorspaces(aces_ctl_directory,
921 config_data['referenceColorSpace'] = aces_reference
922 config_data['roles'] = aces_roles
924 for cs in aces_colorspaces:
925 config_data['colorSpaces'].append(cs)
927 for name, data in aces_displays.iteritems():
928 config_data['displays'][name] = data
930 config_data['defaultDisplay'] = aces_default_display
931 config_data['linearDisplaySpace'] = aces_reference
932 config_data['logDisplaySpace'] = aces_log_display_space
934 # -------------------------------------------------------------------------
935 # *Camera Input Transforms*
936 # -------------------------------------------------------------------------
938 # *ARRI Log-C* to *ACES*.
939 arri_colorSpaces = arri.create_colorspaces(lut_directory,
941 for cs in arri_colorSpaces:
942 config_data['colorSpaces'].append(cs)
944 # *Canon-Log* to *ACES*.
945 canon_colorspaces = canon.create_colorspaces(lut_directory,
947 for cs in canon_colorspaces:
948 config_data['colorSpaces'].append(cs)
950 # *GoPro Protune* to *ACES*.
951 gopro_colorspaces = gopro.create_colorspaces(lut_directory,
953 for cs in gopro_colorspaces:
954 config_data['colorSpaces'].append(cs)
956 # *Panasonic V-Log* to *ACES*.
957 panasonic_colorSpaces = panasonic.create_colorspaces(lut_directory,
959 for cs in panasonic_colorSpaces:
960 config_data['colorSpaces'].append(cs)
962 # *RED* colorspaces to *ACES*.
963 red_colorspaces = red.create_colorspaces(lut_directory,
965 for cs in red_colorspaces:
966 config_data['colorSpaces'].append(cs)
969 sony_colorSpaces = sony.create_colorspaces(lut_directory,
971 for cs in sony_colorSpaces:
972 config_data['colorSpaces'].append(cs)
974 # -------------------------------------------------------------------------
975 # General Color Spaces
976 # -------------------------------------------------------------------------
977 general_colorSpaces = general.create_colorspaces(lut_directory,
980 for cs in general_colorSpaces:
981 config_data['colorSpaces'].append(cs)
983 # The *Raw* color space
984 raw = general.create_raw()
985 config_data['colorSpaces'].append(raw)
987 # Override certain roles, for now
988 config_data['roles']['data'] = raw.name
989 config_data['roles']['reference'] = raw.name
990 config_data['roles']['texture_paint'] = raw.name
992 print('generateLUTs - end')
996 def generate_baked_LUTs(odt_info,
1002 lut_resolution_shaper=1024,
1010 Parameter description.
1015 Return value description.
1018 # Create two entries for ODTs that have full and legal range support
1019 odt_info_C = dict(odt_info)
1020 for odt_ctl_name, odt_values in odt_info.iteritems():
1021 if odt_values['transformHasFullLegalSwitch']:
1022 odt_name = odt_values['transformUserName']
1024 odt_values_legal = dict(odt_values)
1025 odt_values_legal['transformUserName'] = '%s - Legal' % odt_name
1026 odt_info_C['%s - Legal' % odt_ctl_name] = odt_values_legal
1028 odt_values_full = dict(odt_values)
1029 odt_values_full['transformUserName'] = '%s - Full' % odt_name
1030 odt_info_C['%s - Full' % odt_ctl_name] = odt_values_full
1032 del (odt_info_C[odt_ctl_name])
1034 # Generate appropriate LUTs for each ODT
1035 for odt_ctl_name, odt_values in odt_info_C.iteritems():
1036 odt_prefix = odt_values['transformUserNamePrefix']
1037 odt_name = odt_values['transformUserName']
1040 for input_space in ['ACEScc', 'ACESproxy']:
1041 args = ['--iconfig', config_path,
1044 args += ['--inputspace', "ACES - %s" % input_space]
1045 args += ['--outputspace', "Output - %s" % odt_name]
1047 args += ['--inputspace', input_space]
1048 args += ['--outputspace', odt_name]
1050 args += ['--description',
1051 '%s - %s for %s data' % (odt_prefix,
1055 args += ['--shaperspace', "Utility - %s" % shaper_name,
1056 '--shapersize', str(lut_resolution_shaper)]
1058 args += ['--shaperspace', shaper_name,
1059 '--shapersize', str(lut_resolution_shaper)]
1060 args += ['--cubesize', str(lut_resolution_3d)]
1061 args += ['--format',
1063 os.path.join(baked_directory,
1065 '%s for %s.icc' % (odt_name, input_space))]
1067 bake_lut = Process(description='bake a LUT',
1073 for input_space in ['ACEScc', 'ACESproxy']:
1074 args = ['--iconfig', config_path,
1077 args += ['--inputspace', "ACES - %s" % input_space]
1078 args += ['--outputspace', "Output - %s" % odt_name]
1080 args += ['--inputspace', input_space]
1081 args += ['--outputspace', odt_name]
1082 args += ['--description',
1083 '%s - %s for %s data' % (
1084 odt_prefix, odt_name, input_space)]
1086 args += ['--shaperspace', "Utility - %s" % shaper_name,
1087 '--shapersize', str(lut_resolution_shaper)]
1089 args += ['--shaperspace', shaper_name,
1090 '--shapersize', str(lut_resolution_shaper)]
1091 args += ['--cubesize', str(lut_resolution_3d)]
1093 fargs = ['--format',
1098 '%s for %s Flame.3dl' % (odt_name, input_space))]
1099 bake_lut = Process(description='bake a LUT',
1101 args=(args + fargs))
1104 largs = ['--format',
1109 '%s for %s Lustre.3dl' % (odt_name, input_space))]
1110 bake_lut = Process(description='bake a LUT',
1112 args=(args + largs))
1116 for input_space in ['ACEScg', 'ACES2065-1']:
1117 args = ['--iconfig', config_path,
1120 args += ['--inputspace', "ACES - %s" % input_space]
1121 args += ['--outputspace', "Output - %s" % odt_name]
1123 args += ['--inputspace', input_space]
1124 args += ['--outputspace', odt_name]
1125 args += ['--description',
1126 '%s - %s for %s data' % (
1127 odt_prefix, odt_name, input_space)]
1128 if input_space == 'ACEScg':
1129 lin_shaper_name = "%s - AP1" % shaper_name
1131 lin_shaper_name = shaper_name
1133 lin_shaper_name = "Utility - %s" % lin_shaper_name
1134 args += ['--shaperspace', lin_shaper_name,
1135 '--shapersize', str(lut_resolution_shaper)]
1137 args += ['--cubesize', str(lut_resolution_3d)]
1139 margs = ['--format',
1144 '%s for %s Maya.csp' % (odt_name, input_space))]
1145 bake_lut = Process(description='bake a LUT',
1147 args=(args + margs))
1150 hargs = ['--format',
1155 '%s for %s Houdini.lut' % (odt_name, input_space))]
1156 bake_lut = Process(description='bake a LUT',
1158 args=(args + hargs))
1162 def create_config_dir(config_directory,
1163 bake_secondary_LUTs=False,
1164 custom_lut_dir=None):
1171 Parameter description.
1176 Return value description.
1179 lut_directory = os.path.join(config_directory, 'luts')
1180 dirs = [config_directory, lut_directory]
1182 if bake_secondary_LUTs:
1183 dirs.extend([os.path.join(config_directory, 'baked'),
1184 os.path.join(config_directory, 'baked', 'flame'),
1185 os.path.join(config_directory, 'baked', 'photoshop'),
1186 os.path.join(config_directory, 'baked', 'houdini'),
1187 os.path.join(config_directory, 'baked', 'lustre'),
1188 os.path.join(config_directory, 'baked', 'maya')])
1191 dirs.append(os.path.join(config_directory, 'custom'))
1194 not os.path.exists(d) and os.mkdir(d)
1196 return lut_directory
1199 def create_ACES_config(aces_ctl_directory,
1201 lut_resolution_1d=4096,
1202 lut_resolution_3d=64,
1203 bake_secondary_LUTs=True,
1204 multiple_displays=False,
1206 copy_custom_luts=True,
1208 prefix_colorspaces_with_family_names=True):
1210 Creates the ACES configuration.
1215 Parameter description.
1220 Return value description.
1223 # Directory for custom LUTs
1224 custom_lut_dir = None
1225 if copy_custom_luts:
1226 custom_lut_dir = os.path.join(config_directory, "custom")
1228 lut_directory = create_config_dir(config_directory,
1229 bake_secondary_LUTs,
1232 odt_info = aces.get_ODTs_info(aces_ctl_directory)
1233 lmt_info = aces.get_LMTs_info(aces_ctl_directory)
1235 shaper_name = 'Output Shaper'
1236 config_data = generate_LUTs(odt_info,
1245 print('Creating config - with prefixes, with aliases')
1246 config = create_config(config_data,
1247 prefix=prefix_colorspaces_with_family_names,
1249 multiple_displays=multiple_displays,
1250 look_info=look_info,
1251 custom_lut_dir=custom_lut_dir)
1254 write_config(config,
1255 os.path.join(config_directory, 'config.ocio'))
1257 if bake_secondary_LUTs:
1258 generate_baked_LUTs(odt_info,
1260 os.path.join(config_directory, 'baked'),
1261 os.path.join(config_directory, 'config.ocio'),
1265 prefix=prefix_colorspaces_with_family_names)
1277 Parameter description.
1282 Return value description.
1287 usage = '%prog [options]\n'
1289 usage += 'An OCIO config generation script for ACES 1.0\n'
1291 usage += 'Command line examples'
1293 usage += 'Create a GUI-friendly ACES 1.0 config with no secondary, baked LUTs : \n'
1294 usage += '\tcreate_aces_config -a /path/to/aces-dev/transforms/ctl --lutResolution1d 1024 --lutResolution3d 33 -c aces_1.0.0 --dontBakeSecondaryLUTs'
1296 usage += 'Create a more OCIO-compliant ACES 1.0 config : \n'
1297 usage += '\tcreate_aces_config -a /path/to/aces-dev/transforms/ctl --lutResolution1d 1024 --lutResolution3d 33 -c aces_1.0.0 --createMultipleDisplays'
1300 usage += 'Adding custom looks'
1302 usage += 'Create a GUI-friendly ACES 1.0 config with an ACES-style CDL (will be applied in the ACEScc colorspace): \n'
1303 usage += '\tcreate_aces_config -a /path/to/aces-dev/transforms/ctl --lutResolution1d 1024 --lutResolution3d 33 -c aces_1.0.0 \n\t\t--addACESLookCDL ACESCDLName /path/to/SampleCDL.ccc cc03345'
1305 usage += 'Create a GUI-friendly ACES 1.0 config with an general CDL: \n'
1306 usage += '\tcreate_aces_config -a /path/to/aces-dev/transforms/ctl --lutResolution1d 1024 --lutResolution3d 33 -c aces_1.0.0 \n\t\t--addCustomLookCDL CustomCDLName "ACES - ACEScc" /path/to/SampleCDL.ccc cc03345'
1308 usage += '\tIn this example, the CDL will be applied in the ACEScc colorspace, but the user could choose other spaces by changing the argument after the name of the look. \n'
1310 usage += 'Create a GUI-friendly ACES 1.0 config with an ACES-style LUT (will be applied in the ACEScc colorspace): \n'
1311 usage += '\tcreate_aces_config -a /path/to/aces-dev/transforms/ctl --lutResolution1d 1024 --lutResolution3d 33 -c aces_1.0.0 \n\t\t--addACESLookLUT ACESLUTName /path/to/SampleCDL.ccc cc03345'
1313 usage += 'Create a GUI-friendly ACES 1.0 config with an general LUT: \n'
1314 usage += '\tcreate_aces_config -a /path/to/aces-dev/transforms/ctl --lutResolution1d 1024 --lutResolution3d 33 -c aces_1.0.0 \n\t\t--addCustomLookLUT CustomLUTName "ACES - ACEScc" /path/to/SampleCDL.ccc cc03345'
1316 usage += '\tIn this example, the LUT will be applied in the ACEScc colorspace, but the user could choose other spaces by changing the argument after the name of the look. \n'
1320 def look_info_callback(option, opt_str, value, parser):
1321 print( "look_info_callback" )
1322 print( option, opt_str, value, parser )
1323 if opt_str == "--addCustomLookCDL":
1324 look_info.append(value)
1325 elif opt_str == "--addCustomLookLUT":
1326 look_info.append(value)
1327 elif opt_str == "--addACESLookCDL":
1328 look_info.append([value[0], "ACES - ACEScc", value[1], value[2]])
1329 elif opt_str == "--addACESLookLUT":
1330 look_info.append([value[0], "ACES - ACEScc", value[1]])
1332 p = optparse.OptionParser(description='',
1333 prog='create_aces_config',
1334 version='create_aces_config 1.0',
1336 p.add_option('--acesCTLDir', '-a', default=os.environ.get(
1337 ACES_OCIO_CTL_DIRECTORY_ENVIRON, None))
1338 p.add_option('--configDir', '-c', default=os.environ.get(
1339 ACES_OCIO_CONFIGURATION_DIRECTORY_ENVIRON, None))
1340 p.add_option('--lutResolution1d', default=4096)
1341 p.add_option('--lutResolution3d', default=64)
1342 p.add_option('--dontBakeSecondaryLUTs', action='store_true', default=False)
1343 p.add_option('--keepTempImages', action='store_true', default=False)
1345 p.add_option('--createMultipleDisplays', action='store_true', default=False)
1347 p.add_option('--addCustomLookLUT', '', type='string', nargs=3,
1348 action="callback", callback=look_info_callback)
1349 p.add_option('--addCustomLookCDL', '', type='string', nargs=4,
1350 action="callback", callback=look_info_callback)
1351 p.add_option('--addACESLookLUT', '', type='string', nargs=2,
1352 action="callback", callback=look_info_callback)
1353 p.add_option('--addACESLookCDL', '', type='string', nargs=3,
1354 action="callback", callback=look_info_callback)
1355 p.add_option('--copyCustomLUTs', action='store_true', default=False)
1357 options, arguments = p.parse_args()
1359 aces_ctl_directory = options.acesCTLDir
1360 config_directory = options.configDir
1361 lut_resolution_1d = int(options.lutResolution1d)
1362 lut_resolution_3d = int(options.lutResolution3d)
1363 bake_secondary_luts = not options.dontBakeSecondaryLUTs
1364 cleanup_temp_images = not options.keepTempImages
1365 multiple_displays = options.createMultipleDisplays
1366 copy_custom_luts = options.copyCustomLUTs
1370 # TODO: Investigate the following statements.
1372 args_start = sys.argv.index('--') + 1
1373 args = sys.argv[args_start:]
1375 args_start = len(sys.argv) + 1
1378 print('command line : \n%s\n' % ' '.join(sys.argv))
1380 assert aces_ctl_directory is not None, (
1381 'process: No "{0}" environment variable defined or no "ACES CTL" '
1382 'directory specified'.format(
1383 ACES_OCIO_CTL_DIRECTORY_ENVIRON))
1385 assert config_directory is not None, (
1386 'process: No "{0}" environment variable defined or no configuration '
1387 'directory specified'.format(
1388 ACES_OCIO_CONFIGURATION_DIRECTORY_ENVIRON))
1390 return create_ACES_config(aces_ctl_directory,
1394 bake_secondary_luts,
1398 cleanup_temp_images)
1400 if __name__ == '__main__':