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 description = colorspace.description
323 if colorspace.aces_transform_id:
324 description += "\n\nACES Transform ID : %s" % colorspace.aces_transform_id
326 ocio_colorspace_alias = ocio.ColorSpace(
328 bitDepth=colorspace.bit_depth,
329 description=description,
330 equalityGroup=colorspace.equality_group,
331 family=compact_family_name,
332 isData=colorspace.is_data,
333 allocation=colorspace.allocation_type,
334 allocationVars=colorspace.allocation_vars)
336 if colorspace.to_reference_transforms:
337 print('\tGenerating To-Reference transforms')
338 ocio_transform = generate_OCIO_transform(
339 [{'type': 'colorspace',
340 'src': colorspace.name,
341 'dst': reference_colorspace.name,
342 'direction': 'forward'}])
343 ocio_colorspace_alias.setTransform(
345 ocio.Constants.COLORSPACE_DIR_TO_REFERENCE)
347 if colorspace.from_reference_transforms:
348 print('\tGenerating From-Reference transforms')
349 ocio_transform = generate_OCIO_transform(
350 [{'type': 'colorspace',
351 'src': reference_colorspace.name,
352 'dst': colorspace.name,
353 'direction': 'forward'}])
354 ocio_colorspace_alias.setTransform(
356 ocio.Constants.COLORSPACE_DIR_FROM_REFERENCE)
358 config.addColorSpace(ocio_colorspace_alias)
360 def colorspace_prefixed_name(colorspace):
361 prefix = colorspace.family.replace("/", " - ")
362 return "%s - %s" % (prefix, colorspace.name)
370 multiple_displays=False):
377 Parameter description.
382 Return value description.
386 look_colorspace = look[1]
392 print('Adding look %s - %s' % (look_name, ", ".join(look)) )
398 if not '$' in look_lut:
399 print( "Getting ready to copy look lut : %s" % look_lut )
400 shutil.copy2(look_lut, custom_lut_dir)
401 look_lut = os.path.split(look_lut)[1]
403 print( "Skipping LUT copy because path contains a context variable" )
409 print('Adding look to config' )
411 lk1.setName( look_name )
412 lk1.setProcessSpace( look_colorspace )
414 keys = {'type': 'lutFile',
416 'direction': 'forward'}
418 keys['cccid'] = look_cccid
420 ocio_transform = generate_OCIO_transform([keys])
421 lk1.setTransform( ocio_transform )
424 config.addLook( lk1 )
426 print( "Creating aliased colorspace")
429 # Create OCIO colorspace that references that look
430 # - Needed for some implementations that don't process looks well
431 # - Also needed for some implementations that don't expose looks well
433 look_aliases = ["look_%s" % compact(look_name)]
434 colorspace = ColorSpace(look_name,
435 aliases=look_aliases,
436 description="The %s Look colorspace" % look_name,
439 colorspace.from_reference_transforms = [{'type': 'look',
441 'src': reference_name,
442 'dst': reference_name,
443 'direction': 'forward'}]
445 print('Adding colorspace %s, alias to look %s to config data' % (
446 look_name, look_name))
448 # Add this colorspace into the main list of colorspaces
449 config_data['colorSpaces'].append(colorspace)
453 def integrate_looks_into_views(config,
457 multiple_displays=False):
464 Parameter description.
469 Return value description.
471 look_names = [look[0] for look in looks]
473 # Option 1 - Add a 'look' to each Display
474 # - Assumes there is a Display for each ACES Output Transform
475 if multiple_displays:
476 for look_name in look_names:
477 config_data['looks'].append(look_name)
480 # - Copy each Output Transform colorspace
481 # - For each copy, add a LookTransform at the head of the from_reference
483 # - Add these new copied colorspaces for the Displays / Views
485 for display, view_list in config_data['displays'].iteritems():
486 output_colorspace_copy = None
487 look_names_string = ""
488 for view_name, output_colorspace in view_list.iteritems():
489 if view_name == "Output Transform":
491 print( "Adding new View that incorporates looks" )
493 # Make a copy of the output colorspace
494 output_colorspace_copy = copy.deepcopy(output_colorspace)
496 #for look_name in look_names:
497 for i in range(len(look_names)):
498 look_name = look_names[i]
500 # Add the LookTransform to the head of the from_reference transform list
501 if output_colorspace_copy.from_reference_transforms:
502 output_colorspace_copy.from_reference_transforms.insert(i, {'type': 'look',
504 'src': reference_name,
505 'dst': reference_name,
506 'direction': 'forward'})
508 # Add the LookTransform to the end of the to_reference transform list
509 if output_colorspace_copy.to_reference_transforms:
510 inverse_look_name = look_names[len(look_names) -1 -i]
512 output_colorspace_copy.to_reference_transforms.append({'type': 'look',
513 'look': inverse_look_name,
514 'src': reference_name,
515 'dst': reference_name,
516 'direction': 'inverse'})
518 if not look_name in config_data['looks']:
519 config_data['looks'].append(look_name)
521 look_names_string = ", ".join(look_names)
522 output_colorspace_copy.name = "%s with %s" % (output_colorspace.name, look_names_string)
523 output_colorspace_copy.aliases = ["out_%s" % compact(output_colorspace_copy.name)]
525 print( "Colorspace that incorporates looks created : %s" % output_colorspace_copy.name )
527 config_data['colorSpaces'].append(output_colorspace_copy)
529 if output_colorspace_copy:
530 print( "Adding colorspace that incorporates looks into view list" )
532 # Change the name of the View
533 view_list["Output Transform with %s" % look_names_string] = output_colorspace_copy
534 config_data['displays'][display] = view_list
536 #print( "Display : %s, View List : %s" % (display, ", ".join(view_list)) )
538 def create_config(config_data,
541 multiple_displays=False,
543 custom_lut_dir=None):
550 Parameter description.
555 Return value description.
559 alias_colorspaces = []
561 # Creating the *OCIO* configuration.
562 config = ocio.Config()
564 # Setting configuration description.
565 config.setDescription('An ACES config generated from python')
567 # Setting configuration search path.
568 searchPath = ['luts']
570 searchPath.append('custom')
571 config.setSearchPath(':'.join(searchPath))
573 # Defining the reference colorspace.
574 reference_data = config_data['referenceColorSpace']
576 # Adding the color space Family into the name
577 # Helps with applications that present colorspaces as one long list
579 prefixed_name = colorspace_prefixed_name(reference_data)
580 prefixed_names[reference_data.name] = prefixed_name
581 reference_data.name = prefixed_name
583 print('Adding the reference color space : %s' % reference_data.name)
585 reference = ocio.ColorSpace(
586 name=reference_data.name,
587 bitDepth=reference_data.bit_depth,
588 description=reference_data.description,
589 equalityGroup=reference_data.equality_group,
590 family=reference_data.family,
591 isData=reference_data.is_data,
592 allocation=reference_data.allocation_type,
593 allocationVars=reference_data.allocation_vars)
595 config.addColorSpace(reference)
599 if reference_data.aliases != []:
600 #add_colorspace_alias(config, reference_data,
601 # reference_data, reference_data.aliases)
602 # defer adding alias colorspaces until end. Helps with some applications
603 alias_colorspaces.append([reference_data, reference_data, reference_data.aliases])
608 #print( "color spaces : %s" % [x.name for x in sorted(config_data['colorSpaces'])])
611 # Add Looks and Look colorspaces
614 print('Adding looks')
616 config_data['looks'] = []
618 # Add looks and colorspaces
619 for look in look_info:
627 # Integrate looks with displays, views
628 integrate_looks_into_views(config,
636 print('Adding the regular color spaces')
638 # Creating the remaining colorspaces.
639 for colorspace in sorted(config_data['colorSpaces']):
640 # Adding the color space Family into the name
641 # Helps with applications that present colorspaces as one long list
643 prefixed_name = colorspace_prefixed_name(colorspace)
644 prefixed_names[colorspace.name] = prefixed_name
645 colorspace.name = prefixed_name
647 print('Creating new color space : %s' % colorspace.name)
649 description = colorspace.description
650 if colorspace.aces_transform_id:
651 description += "\n\nACES Transform ID : %s" % colorspace.aces_transform_id
653 ocio_colorspace = ocio.ColorSpace(
654 name=colorspace.name,
655 bitDepth=colorspace.bit_depth,
656 description=description,
657 equalityGroup=colorspace.equality_group,
658 family=colorspace.family,
659 isData=colorspace.is_data,
660 allocation=colorspace.allocation_type,
661 allocationVars=colorspace.allocation_vars)
663 if colorspace.to_reference_transforms:
664 print('\tGenerating To-Reference transforms')
665 ocio_transform = generate_OCIO_transform(
666 colorspace.to_reference_transforms)
667 ocio_colorspace.setTransform(
669 ocio.Constants.COLORSPACE_DIR_TO_REFERENCE)
671 if colorspace.from_reference_transforms:
672 print('\tGenerating From-Reference transforms')
673 ocio_transform = generate_OCIO_transform(
674 colorspace.from_reference_transforms)
675 ocio_colorspace.setTransform(
677 ocio.Constants.COLORSPACE_DIR_FROM_REFERENCE)
679 config.addColorSpace(ocio_colorspace)
682 # Add alias to normal colorspace, using compact name
685 if colorspace.aliases != []:
686 #add_colorspace_alias(config, reference_data,
687 # colorspace, colorspace.aliases)
688 # defer adding alias colorspaces until end. Helps with some applications
689 alias_colorspaces.append([reference_data, colorspace, colorspace.aliases])
695 # We add these at the end as some applications use the order of the colorspaces
696 # definitions in the config to order the colorspaces in their selection lists.
697 # Other go alphabetically. This should keep the alias colorspaces out of the way
698 # for the apps that use the order of definition in the config.
699 print('Adding the alias colorspaces')
700 for reference, colorspace, aliases in alias_colorspaces:
701 add_colorspace_alias(config, reference, colorspace, aliases)
705 print('Adding the diplays and views')
707 # Defining the *views* and *displays*.
712 # Defining a *generic* *display* and *view* setup.
713 if multiple_displays:
714 # Built list of looks to add to Displays
715 looks = config_data['looks'] if ('looks' in config_data) else []
716 looks = ", ".join(looks)
717 print( "Creating multiple displays, with looks : %s" % looks)
719 # Create Displays, Views
720 for display, view_list in config_data['displays'].iteritems():
721 for view_name, colorspace in view_list.iteritems():
722 config.addDisplay(display, view_name, colorspace.name, looks)
723 if 'Output Transform' in view_name and looks != "":
724 # Add normal View, without looks
725 config.addDisplay(display, view_name, colorspace.name)
727 # Add View with looks
728 view_name_with_looks = "%s with %s" % (view_name, looks)
729 config.addDisplay(display, view_name_with_looks, colorspace.name, looks)
731 config.addDisplay(display, view_name, colorspace.name)
732 if not (view_name in views):
733 views.append(view_name)
734 displays.append(display)
737 # Defining the set of *views* and *displays* useful in a *GUI* context.
738 #display_name = 'ACES'
739 single_display_name = config_data['roles']['scene_linear']
740 displays.append(single_display_name)
742 display_names = sorted(config_data['displays'])
744 # Make sure the default display is first
745 default_display = config_data['defaultDisplay']
746 display_names.insert(0, display_names.pop(display_names.index(default_display)))
748 # Built list of looks to add to Displays
749 looks = config_data['looks'] if ('looks' in config_data) else []
750 look_names = ", ".join(looks)
752 displays_views_colorspaces = []
754 # Create Displays, Views
755 for display in display_names:
756 view_list = config_data['displays'][display]
757 for view_name, colorspace in view_list.iteritems():
758 if 'Output Transform' in view_name:
759 #print( "Adding view for %s" % view_name )
761 # Maya 2016 doesn't like parentheses in View names
762 display_cleaned = replace(display, {')': '', '(': ''})
764 # We use the Display names as the View names in this case
765 # as there is a single Display that contains all views.
766 # This works for more applications than not, as of the time of this implementation.
768 # If View includes looks
769 if 'with' in view_name:
770 # Integrate looks into view name
771 display_cleaned = "%s with %s" % (display_cleaned, look_names)
773 viewsWithLooksAtEnd = False
774 # Storing combo of display, view and colorspace name in a list so we can
775 # add them to the end of the list
776 if viewsWithLooksAtEnd:
777 displays_views_colorspaces.append([single_display_name, display_cleaned, colorspace.name])
781 config.addDisplay(single_display_name, display_cleaned, colorspace.name)
784 if not (display_cleaned in views):
785 views.append(display_cleaned)
789 config.addDisplay(single_display_name, display_cleaned, colorspace.name)
792 if not (display_cleaned in views):
793 views.append(display_cleaned)
795 # Add to config any display, view combinations that were saved for later
796 for display_view_colorspace in displays_views_colorspaces:
797 single_display_name, display_cleaned, colorspace_name = display_view_colorspace
800 config.addDisplay(single_display_name, display_cleaned, colorspace_name)
803 if not (display_cleaned in views):
804 views.append(display_cleaned)
807 # Works with Nuke Studio and Mari, but not Nuke
808 # single_display_name = 'Utility'
809 # displays.append(single_display_name)
811 raw_display_space_name = config_data['roles']['data']
812 log_display_space_name = config_data['roles']['compositing_log']
814 # Find the newly-prefixed colorspace names
816 #print( prefixed_names )
817 raw_display_space_name = prefixed_names[raw_display_space_name]
818 log_display_space_name = prefixed_names[log_display_space_name]
820 config.addDisplay(single_display_name, 'Raw', raw_display_space_name)
822 config.addDisplay(single_display_name, 'Log', log_display_space_name)
825 # Setting the active *displays* and *views*.
826 config.setActiveDisplays(','.join(sorted(displays)))
827 config.setActiveViews(','.join(views))
831 print('Setting the roles')
834 set_config_default_roles(
836 color_picking=prefixed_names[config_data['roles']['color_picking']],
837 color_timing=prefixed_names[config_data['roles']['color_timing']],
838 compositing_log=prefixed_names[config_data['roles']['compositing_log']],
839 data=prefixed_names[config_data['roles']['data']],
840 default=prefixed_names[config_data['roles']['default']],
841 matte_paint=prefixed_names[config_data['roles']['matte_paint']],
842 reference=prefixed_names[config_data['roles']['reference']],
843 scene_linear=prefixed_names[config_data['roles']['scene_linear']],
844 texture_paint=prefixed_names[config_data['roles']['texture_paint']])
846 set_config_default_roles(
848 color_picking=config_data['roles']['color_picking'],
849 color_timing=config_data['roles']['color_timing'],
850 compositing_log=config_data['roles']['compositing_log'],
851 data=config_data['roles']['data'],
852 default=config_data['roles']['default'],
853 matte_paint=config_data['roles']['matte_paint'],
854 reference=config_data['roles']['reference'],
855 scene_linear=config_data['roles']['scene_linear'],
856 texture_paint=config_data['roles']['texture_paint'])
860 # Make sure we didn't create a bad config
863 # Reset the colorspace names back to their non-prefixed versions
865 # Build the reverse lookup
866 prefixed_names_inverse = {}
867 for original, prefixed in prefixed_names.iteritems():
868 prefixed_names_inverse[prefixed] = original
870 # Reet the reference colorspace name
871 reference_data.name = prefixed_names_inverse[reference_data.name]
873 # Reset the rest of the colorspace names
874 for colorspace in config_data['colorSpaces']:
875 colorspace.name = prefixed_names_inverse[colorspace.name]
880 def generate_LUTs(odt_info,
885 lut_resolution_1d=4096,
886 lut_resolution_3d=64,
894 Parameter description.
899 Colorspaces and transforms converting between those colorspaces and
900 the reference colorspace, *ACES*.
903 print('generateLUTs - begin')
906 # Initialize a few variables
907 config_data['displays'] = {}
908 config_data['colorSpaces'] = []
910 # -------------------------------------------------------------------------
911 # *ACES Color Spaces*
912 # -------------------------------------------------------------------------
918 aces_log_display_space,
920 aces_default_display) = aces.create_colorspaces(aces_ctl_directory,
929 config_data['referenceColorSpace'] = aces_reference
930 config_data['roles'] = aces_roles
932 for cs in aces_colorspaces:
933 config_data['colorSpaces'].append(cs)
935 for name, data in aces_displays.iteritems():
936 config_data['displays'][name] = data
938 config_data['defaultDisplay'] = aces_default_display
939 config_data['linearDisplaySpace'] = aces_reference
940 config_data['logDisplaySpace'] = aces_log_display_space
942 # -------------------------------------------------------------------------
943 # *Camera Input Transforms*
944 # -------------------------------------------------------------------------
946 # *ARRI Log-C* to *ACES*.
947 arri_colorSpaces = arri.create_colorspaces(lut_directory,
949 for cs in arri_colorSpaces:
950 config_data['colorSpaces'].append(cs)
952 # *Canon-Log* to *ACES*.
953 canon_colorspaces = canon.create_colorspaces(lut_directory,
955 for cs in canon_colorspaces:
956 config_data['colorSpaces'].append(cs)
958 # *GoPro Protune* to *ACES*.
959 gopro_colorspaces = gopro.create_colorspaces(lut_directory,
961 for cs in gopro_colorspaces:
962 config_data['colorSpaces'].append(cs)
964 # *Panasonic V-Log* to *ACES*.
965 panasonic_colorSpaces = panasonic.create_colorspaces(lut_directory,
967 for cs in panasonic_colorSpaces:
968 config_data['colorSpaces'].append(cs)
970 # *RED* colorspaces to *ACES*.
971 red_colorspaces = red.create_colorspaces(lut_directory,
973 for cs in red_colorspaces:
974 config_data['colorSpaces'].append(cs)
977 sony_colorSpaces = sony.create_colorspaces(lut_directory,
979 for cs in sony_colorSpaces:
980 config_data['colorSpaces'].append(cs)
982 # -------------------------------------------------------------------------
983 # General Color Spaces
984 # -------------------------------------------------------------------------
985 general_colorSpaces = general.create_colorspaces(lut_directory,
988 for cs in general_colorSpaces:
989 config_data['colorSpaces'].append(cs)
991 # The *Raw* color space
992 raw = general.create_raw()
993 config_data['colorSpaces'].append(raw)
995 # Override certain roles, for now
996 config_data['roles']['data'] = raw.name
997 config_data['roles']['reference'] = raw.name
998 config_data['roles']['texture_paint'] = raw.name
1000 print('generateLUTs - end')
1004 def generate_baked_LUTs(odt_info,
1010 lut_resolution_shaper=1024,
1018 Parameter description.
1023 Return value description.
1026 # Create two entries for ODTs that have full and legal range support
1027 odt_info_C = dict(odt_info)
1028 for odt_ctl_name, odt_values in odt_info.iteritems():
1029 if odt_values['transformHasFullLegalSwitch']:
1030 odt_name = odt_values['transformUserName']
1032 odt_values_legal = dict(odt_values)
1033 odt_values_legal['transformUserName'] = '%s - Legal' % odt_name
1034 odt_info_C['%s - Legal' % odt_ctl_name] = odt_values_legal
1036 odt_values_full = dict(odt_values)
1037 odt_values_full['transformUserName'] = '%s - Full' % odt_name
1038 odt_info_C['%s - Full' % odt_ctl_name] = odt_values_full
1040 del (odt_info_C[odt_ctl_name])
1042 # Generate appropriate LUTs for each ODT
1043 for odt_ctl_name, odt_values in odt_info_C.iteritems():
1044 odt_prefix = odt_values['transformUserNamePrefix']
1045 odt_name = odt_values['transformUserName']
1048 for input_space in ['ACEScc', 'ACESproxy']:
1049 args = ['--iconfig', config_path,
1052 args += ['--inputspace', "ACES - %s" % input_space]
1053 args += ['--outputspace', "Output - %s" % odt_name]
1055 args += ['--inputspace', input_space]
1056 args += ['--outputspace', odt_name]
1058 args += ['--description',
1059 '%s - %s for %s data' % (odt_prefix,
1063 args += ['--shaperspace', "Utility - %s" % shaper_name,
1064 '--shapersize', str(lut_resolution_shaper)]
1066 args += ['--shaperspace', shaper_name,
1067 '--shapersize', str(lut_resolution_shaper)]
1068 args += ['--cubesize', str(lut_resolution_3d)]
1069 args += ['--format',
1071 os.path.join(baked_directory,
1073 '%s for %s.icc' % (odt_name, input_space))]
1075 bake_lut = Process(description='bake a LUT',
1081 for input_space in ['ACEScc', 'ACESproxy']:
1082 args = ['--iconfig', config_path,
1085 args += ['--inputspace', "ACES - %s" % input_space]
1086 args += ['--outputspace', "Output - %s" % odt_name]
1088 args += ['--inputspace', input_space]
1089 args += ['--outputspace', odt_name]
1090 args += ['--description',
1091 '%s - %s for %s data' % (
1092 odt_prefix, odt_name, input_space)]
1094 args += ['--shaperspace', "Utility - %s" % shaper_name,
1095 '--shapersize', str(lut_resolution_shaper)]
1097 args += ['--shaperspace', shaper_name,
1098 '--shapersize', str(lut_resolution_shaper)]
1099 args += ['--cubesize', str(lut_resolution_3d)]
1101 fargs = ['--format',
1106 '%s for %s Flame.3dl' % (odt_name, input_space))]
1107 bake_lut = Process(description='bake a LUT',
1109 args=(args + fargs))
1112 largs = ['--format',
1117 '%s for %s Lustre.3dl' % (odt_name, input_space))]
1118 bake_lut = Process(description='bake a LUT',
1120 args=(args + largs))
1124 for input_space in ['ACEScg', 'ACES2065-1']:
1125 args = ['--iconfig', config_path,
1128 args += ['--inputspace', "ACES - %s" % input_space]
1129 args += ['--outputspace', "Output - %s" % odt_name]
1131 args += ['--inputspace', input_space]
1132 args += ['--outputspace', odt_name]
1133 args += ['--description',
1134 '%s - %s for %s data' % (
1135 odt_prefix, odt_name, input_space)]
1136 if input_space == 'ACEScg':
1137 lin_shaper_name = "%s - AP1" % shaper_name
1139 lin_shaper_name = shaper_name
1141 lin_shaper_name = "Utility - %s" % lin_shaper_name
1142 args += ['--shaperspace', lin_shaper_name,
1143 '--shapersize', str(lut_resolution_shaper)]
1145 args += ['--cubesize', str(lut_resolution_3d)]
1147 margs = ['--format',
1152 '%s for %s Maya.csp' % (odt_name, input_space))]
1153 bake_lut = Process(description='bake a LUT',
1155 args=(args + margs))
1158 hargs = ['--format',
1163 '%s for %s Houdini.lut' % (odt_name, input_space))]
1164 bake_lut = Process(description='bake a LUT',
1166 args=(args + hargs))
1170 def create_config_dir(config_directory,
1171 bake_secondary_LUTs=False,
1172 custom_lut_dir=None):
1179 Parameter description.
1184 Return value description.
1187 lut_directory = os.path.join(config_directory, 'luts')
1188 dirs = [config_directory, lut_directory]
1190 if bake_secondary_LUTs:
1191 dirs.extend([os.path.join(config_directory, 'baked'),
1192 os.path.join(config_directory, 'baked', 'flame'),
1193 os.path.join(config_directory, 'baked', 'photoshop'),
1194 os.path.join(config_directory, 'baked', 'houdini'),
1195 os.path.join(config_directory, 'baked', 'lustre'),
1196 os.path.join(config_directory, 'baked', 'maya')])
1199 dirs.append(os.path.join(config_directory, 'custom'))
1202 not os.path.exists(d) and os.mkdir(d)
1204 return lut_directory
1207 def create_ACES_config(aces_ctl_directory,
1209 lut_resolution_1d=4096,
1210 lut_resolution_3d=64,
1211 bake_secondary_LUTs=True,
1212 multiple_displays=False,
1214 copy_custom_luts=True,
1216 prefix_colorspaces_with_family_names=True):
1218 Creates the ACES configuration.
1223 Parameter description.
1228 Return value description.
1231 # Directory for custom LUTs
1232 custom_lut_dir = None
1233 if copy_custom_luts:
1234 custom_lut_dir = os.path.join(config_directory, "custom")
1236 lut_directory = create_config_dir(config_directory,
1237 bake_secondary_LUTs,
1240 odt_info = aces.get_ODTs_info(aces_ctl_directory)
1241 lmt_info = aces.get_LMTs_info(aces_ctl_directory)
1243 shaper_name = 'Output Shaper'
1244 config_data = generate_LUTs(odt_info,
1253 print('Creating config - with prefixes, with aliases')
1254 config = create_config(config_data,
1255 prefix=prefix_colorspaces_with_family_names,
1257 multiple_displays=multiple_displays,
1258 look_info=look_info,
1259 custom_lut_dir=custom_lut_dir)
1262 write_config(config,
1263 os.path.join(config_directory, 'config.ocio'))
1265 if bake_secondary_LUTs:
1266 generate_baked_LUTs(odt_info,
1268 os.path.join(config_directory, 'baked'),
1269 os.path.join(config_directory, 'config.ocio'),
1273 prefix=prefix_colorspaces_with_family_names)
1285 Parameter description.
1290 Return value description.
1295 usage = '%prog [options]\n'
1297 usage += 'An OCIO config generation script for ACES 1.0\n'
1299 usage += 'Command line examples'
1301 usage += 'Create a GUI-friendly ACES 1.0 config with no secondary, baked LUTs : \n'
1302 usage += '\tcreate_aces_config -a /path/to/aces-dev/transforms/ctl --lutResolution1d 1024 --lutResolution3d 33 -c aces_1.0.0 --dontBakeSecondaryLUTs'
1304 usage += 'Create a more OCIO-compliant ACES 1.0 config : \n'
1305 usage += '\tcreate_aces_config -a /path/to/aces-dev/transforms/ctl --lutResolution1d 1024 --lutResolution3d 33 -c aces_1.0.0 --createMultipleDisplays'
1308 usage += 'Adding custom looks'
1310 usage += 'Create a GUI-friendly ACES 1.0 config with an ACES-style CDL (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--addACESLookCDL ACESCDLName /path/to/SampleCDL.ccc cc03345'
1313 usage += 'Create a GUI-friendly ACES 1.0 config with an general CDL: \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--addCustomLookCDL CustomCDLName "ACES - ACEScc" /path/to/SampleCDL.ccc cc03345'
1316 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'
1318 usage += 'Create a GUI-friendly ACES 1.0 config with an ACES-style LUT (will be applied in the ACEScc colorspace): \n'
1319 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'
1321 usage += 'Create a GUI-friendly ACES 1.0 config with an general LUT: \n'
1322 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'
1324 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'
1328 def look_info_callback(option, opt_str, value, parser):
1329 print( "look_info_callback" )
1330 print( option, opt_str, value, parser )
1331 if opt_str == "--addCustomLookCDL":
1332 look_info.append(value)
1333 elif opt_str == "--addCustomLookLUT":
1334 look_info.append(value)
1335 elif opt_str == "--addACESLookCDL":
1336 look_info.append([value[0], "ACES - ACEScc", value[1], value[2]])
1337 elif opt_str == "--addACESLookLUT":
1338 look_info.append([value[0], "ACES - ACEScc", value[1]])
1340 p = optparse.OptionParser(description='',
1341 prog='create_aces_config',
1342 version='create_aces_config 1.0',
1344 p.add_option('--acesCTLDir', '-a', default=os.environ.get(
1345 ACES_OCIO_CTL_DIRECTORY_ENVIRON, None))
1346 p.add_option('--configDir', '-c', default=os.environ.get(
1347 ACES_OCIO_CONFIGURATION_DIRECTORY_ENVIRON, None))
1348 p.add_option('--lutResolution1d', default=4096)
1349 p.add_option('--lutResolution3d', default=64)
1350 p.add_option('--dontBakeSecondaryLUTs', action='store_true', default=False)
1351 p.add_option('--keepTempImages', action='store_true', default=False)
1353 p.add_option('--createMultipleDisplays', action='store_true', default=False)
1355 p.add_option('--addCustomLookLUT', '', type='string', nargs=3,
1356 action="callback", callback=look_info_callback)
1357 p.add_option('--addCustomLookCDL', '', type='string', nargs=4,
1358 action="callback", callback=look_info_callback)
1359 p.add_option('--addACESLookLUT', '', type='string', nargs=2,
1360 action="callback", callback=look_info_callback)
1361 p.add_option('--addACESLookCDL', '', type='string', nargs=3,
1362 action="callback", callback=look_info_callback)
1363 p.add_option('--copyCustomLUTs', action='store_true', default=False)
1365 options, arguments = p.parse_args()
1367 aces_ctl_directory = options.acesCTLDir
1368 config_directory = options.configDir
1369 lut_resolution_1d = int(options.lutResolution1d)
1370 lut_resolution_3d = int(options.lutResolution3d)
1371 bake_secondary_luts = not options.dontBakeSecondaryLUTs
1372 cleanup_temp_images = not options.keepTempImages
1373 multiple_displays = options.createMultipleDisplays
1374 copy_custom_luts = options.copyCustomLUTs
1378 # TODO: Investigate the following statements.
1380 args_start = sys.argv.index('--') + 1
1381 args = sys.argv[args_start:]
1383 args_start = len(sys.argv) + 1
1386 print('command line : \n%s\n' % ' '.join(sys.argv))
1388 assert aces_ctl_directory is not None, (
1389 'process: No "{0}" environment variable defined or no "ACES CTL" '
1390 'directory specified'.format(
1391 ACES_OCIO_CTL_DIRECTORY_ENVIRON))
1393 assert config_directory is not None, (
1394 'process: No "{0}" environment variable defined or no configuration '
1395 'directory specified'.format(
1396 ACES_OCIO_CONFIGURATION_DIRECTORY_ENVIRON))
1398 return create_ACES_config(aces_ctl_directory,
1402 bake_secondary_luts,
1406 cleanup_temp_images)
1408 if __name__ == '__main__':