MaterialXOCIO 0.1.39.5
Utilities for using OCIO to generate MaterialX definitions and graphs
Loading...
Searching...
No Matches
core.py
1#!/usr/bin/env python
2'''
3Utilities to generate MaterialX color transform definitions using OCIO.
4
5The minimum requirement is OCIO version 2.2 which is packaged with
6"ACES Cg Config" and "ACES Studio Config" configurations.
7'''
8
9import PyOpenColorIO as OCIO
10import MaterialX as mx
11import re
12
14 '''
15 A class to generate MaterialX color transform definitions using OCIO.
16 '''
17
19 '''
20 Get the OCIO built in configurations.
21 Returnes a dictionary of color spaces and the default "ACES Cg Config".
22 '''
23 # Get the OCIO built in configs
24 registry = OCIO.BuiltinConfigRegistry().getBuiltinConfigs()
25
26 # Create a dictionary of configs
27 configs = {}
28 for item in registry:
29 # The short_name is the URI-style name.
30 # The ui_name is the name to use in a user interface.
31 short_name, ui_name, isRecommended, isDefault = item
32
33 # Don't present built-in configs to users if they are no longer recommended.
34 if isRecommended:
35 # Create a config using the Cg config
36 config = OCIO.Config.CreateFromBuiltinConfig(short_name)
37 colorSpaces = None
38 if config:
39 colorSpaces = config.getColorSpaces()
40
41 if colorSpaces:
42 configs[short_name] = [config, colorSpaces]
43
44 acesCgConfigPath = 'ocio://default'
45 builtinCfgC = OCIO.Config.CreateFromFile(acesCgConfigPath)
46 print('Built-in config:', builtinCfgC.getName())
47 csnames = builtinCfgC.getColorSpaceNames()
48 print('- Number of color spaces: %d' % len(csnames))
49
50 return configs, builtinCfgC
51
52 def printConfigs(self, configs):
53 '''
54 Print the OCIO built in configurations as a markdown table.
55 @param configs: The OCIO configurations.
56 @return: A markdown string.
57 '''
58 title = '| Configuration | Color Space | Aliases |\n'
59 title = title + '| --- | --- | --- |\n'
60
61 rows = ''
62 for c in configs:
63 config = configs[c][0]
64 colorSpaces = configs[c][1]
65 for colorSpace in colorSpaces:
66 aliases = colorSpace.getAliases()
67 rows = rows + '| ' + c + ' | ' + colorSpace.getName() + ' | ' + ', '.join(aliases) + ' |\n'
68
69 return title + rows
70
71 def createValidName(self, name: str) -> str:
72 '''
73 Create a valid name MaterialX name. Remove ":" even though it's technically valid
74 for namespaced names.
75 @param str: The input string.
76 @return: The valid name string.
77 '''
78 name = mx.createValidName(name)
79 name = name.replace(':', '_')
80 return name
81
82 def createTransformName(self, sourceSpace, targetSpace, typeName, prefix = 'mx_'):
83 '''
84 Create a transform name from a source and target color space and a type name.
85 @param sourceSpace: The source color space.
86 @param targetSpace: The target color space.
87 @param typeName: The type name.
88 @param prefix: The prefix for the transform name. Default is 'mx_'.
89 '''
90 transformFunctionName = prefix + self.createValidName(sourceSpace) + "_to_" + self.createValidName(targetSpace) + "_" + typeName
91 return transformFunctionName
92
93 def setShaderDescriptionParameters(self, shaderDesc, sourceSpace, targetSpace, typeName):
94 '''
95 Set parameters on a shader description for a given source and target color space and type name.
96 @param shaderDesc: The shader description.
97 @param sourceSpace: The source color space.
98 @param targetSpace: The target color space.
99 @param typeName: The type name.
100 '''
101 transformFunctionName = self.createTransformName(sourceSpace, targetSpace, typeName)
102 shaderDesc.setFunctionName(transformFunctionName)
103 shaderDesc.setResourcePrefix(transformFunctionName)
104
105 def generateShaderCode(self, config, sourceColorSpace, destColorSpace, language):
106 '''
107 Generate shader for a transform from a source color space to a destination color space
108 for a given config and shader language.
109
110 @param config: The OCIO configuration.
111 @param sourceColorSpace: The source color space.
112 @param destColorSpace: The destination color space.
113 @param language: The OCIO GPU language.
114 @return: A tuple containing the shader code and the number of texture resources required.
115
116 Returns the shader code and the number of texture resources required.
117 '''
118 shaderCode = ''
119 textureCount = 0
120 if not config:
121 return shaderCode, textureCount
122
123 # Create a processor for a pair of colorspaces
124 processor = None
125 try:
126 processor = config.getProcessor(sourceColorSpace, destColorSpace)
127 except:
128 print('Skipping due to lack of support for transform: %s -> %s' % (sourceColorSpace, destColorSpace))
129 return shaderCode, textureCount
130
131 if processor:
132 gpuProcessor = processor.getDefaultGPUProcessor()
133 if gpuProcessor:
134 shaderDesc = OCIO.GpuShaderDesc.CreateShaderDesc()
135 if shaderDesc:
136 try:
137 shaderDesc.setLanguage(language)
138 if shaderDesc.getLanguage() == language:
139 self.setShaderDescriptionParameters(shaderDesc, sourceColorSpace, destColorSpace, "color4")
140 gpuProcessor.extractGpuShaderInfo(shaderDesc)
141 shaderCode = shaderDesc.getShaderText()
142
143 for t in shaderDesc.getTextures():
144 textureCount += 1
145
146 if shaderCode:
147 shaderCode = shaderCode.replace(
148 "// Declaration of the OCIO shader function\n",
149 "// " + sourceColorSpace + " to " + destColorSpace + " function. Texture count: %d\n" % textureCount)
150
151 except OCIO.Exception as err:
152 print(err)
153
154 return shaderCode, textureCount
155
156 def generateTransformGraph(self, config, sourceColorSpace, destColorSpace):
157 '''
158 Generate the group of transforms required to go from a source color space to a destination color space.
159 The group of transforms is output from an optimized OCIO processor.
160 @param config: The OCIO configuration.
161 @param sourceColorSpace: The source color space.
162 @param destColorSpace: The destination color space.
163 @return: The group of transforms.
164 '''
165 if not config:
166 return None
167
168 # Create a processor for a pair of colorspaces (namely to go to linear)
169 processor = None
170 groupTransform = None
171 try:
172 processor = config.getProcessor(sourceColorSpace, destColorSpace)
173 except:
174 #print('Failed to get processor for: %s -> %s' % (sourceColorSpace, destColorSpace))
175 return groupTransform
176
177 if processor:
178 processor = processor.getOptimizedProcessor(OCIO.OPTIMIZATION_ALL)
179 groupTransform = processor.createGroupTransform()
180
181 return groupTransform
182
183 def hasTextureResources(self, configs, targetColorSpace, language):
184 '''
185 Scan through all the color spaces on the configs to check for texture resource usage.
186 Returns a set of color spaces that require texture resources.
187
188 @param configs: The OCIO configurations.
189 @param targetColorSpace: The target color space.
190 @param language: The OCIO GPU language.
191 @return: A set of color spaces that require texture resources.
192 '''
193 testedSources = set()
194 textureSources = set()
195 for c in configs:
196 config = OCIO.Config.CreateFromBuiltinConfig(c)
197 colorSpaces = config.getColorSpaces()
198 for colorSpace in colorSpaces:
199 colorSpaceName = colorSpace.getName()
200 # Skip if the colorspace is already tested
201 if colorSpaceName in testedSources:
202 continue
203 testedSources.add(colorSpaceName)
204
205 # Test for texture resource usage
206 code, textureCount = self.generateShaderCode(config, colorSpace.getName(), targetColorSpace, language)
207 if textureCount:
208 print('- Transform "%s" to "%s" requires %d texture resources' % (colorSpace.getName(), targetColorSpace, textureCount))
209 textureSources.add(colorSpaceName)
210
211 return textureSources
212
213 def MSL(self, config, sourceColorSpace, targetColorSpace):
214 '''
215 Generate MSL shader code for a transform from a source color space to a destination color space
216 for a given config.
217 @param config: The OCIO configuration.
218 @param sourceColorSpace: The source color space.
219 @param targetColorSpace: The destination color space.
220 @return: The shader code.
221 '''
222 language = OCIO.GpuLanguage.GPU_LANGUAGE_MSL_2_0
223 code, textureCount = self.generateShaderCode(config, sourceColorSpace, targetColorSpace, language)
224 if code:
225 code = code.replace("// Declaration of the OCIO shader function\n", "// " + sourceColorSpace + " to " + targetColorSpace + " function\n")
226 code = '```c++\n' + code + '\n```\n'
227
228 def OSL(self, config, sourceColorSpace, targetColorSpace):
229 '''
230 Generate OSL shader code for a transform from a source color space to a destination color space
231 for a given config.
232 @param config: The OCIO configuration.
233 @param sourceColorSpace: The source color space.
234 @param targetColorSpace: The destination color space.
235 @return: The shader code.
236 '''
237 if OCIO.GpuLanguage.LANGUAGE_OSL_1:
238 language = OCIO.GpuLanguage.LANGUAGE_OSL_1
239 code, textureCount = self.generateShaderCode(config, sourceColorSpace, targetColorSpace, language)
240 if code:
241 # Bit of ugly patching to make the main function name consistent.
242 transformName = self.createTransformName(sourceColorSpace, targetColorSpace, 'color4')
243 code = code.replace('OSL_' + transformName, '__temp_name__')
244 code = code.replace(transformName, transformName + '_impl')
245 code = code.replace('__temp_name__', transformName)
246 code = code.replace("// Declaration of the OCIO shader function\n", "// " + sourceColorSpace + " to " + targetColorSpace + " function\n")
247 code = '```c++\n' + code + '\n```\n'
248
249 def generateMaterialXDefinition(self, doc, sourceColorSpace, targetColorSpace, inputName, type):
250 '''
251 Create a new definition in a document for a given color space transform.
252 Returns the definition.
253 '''
254 # Create a definition
255 transformName = self.createTransformName(sourceColorSpace, targetColorSpace, type)
256 nodeName = transformName.replace('mx_', 'ND_')
257
258 comment = doc.addChildOfCategory('comment')
259 docString = ' Color space %s to %s transform. Generated via OCIO. ' % (sourceColorSpace, targetColorSpace)
260 comment.setDocString(docString)
261
262 definition = doc.addNodeDef(nodeName, 'color4')
263 category = sourceColorSpace + '_to_' + targetColorSpace
264 category = self.createValidName(category)
265 definition.setNodeString(category)
266 definition.setNodeGroup('colortransform')
267 definition.setDocString(docString)
268 definition.setVersionString('1.0')
269
270 defaultValueString = '0.0 0.0 0.0 1.0'
271 defaultValue = mx.createValueFromStrings(defaultValueString, 'color4')
272 input = definition.addInput(inputName, type)
273 input.setValue(defaultValue)
274 output = definition.getOutput('out')
275 output.setAttribute('default', 'in')
276
277 return definition
278
279 def writeShaderCode(self, outputPath, code, transformName, extension, target):
280 '''
281 Write the shader code to a file.
282 @param outputPath: The output file path.
283 @param code: The shader code.
284 @param transformName: The transform name.
285 @param extension: The file extension.
286 @param target: The target language.
287 '''
288 # Write source code file
289 filename = outputPath / mx.FilePath(transformName + '.' + extension)
290 print('Write target[%s] source file %s' % (target,filename.asString()))
291 f = open(filename.asString(), 'w')
292 f.write(code)
293 f.close()
294
295 def createMaterialXImplementation(self, sourceColorSpace, targetColorSpace, doc, definition, transformName, extension, target):
296 '''
297 Create a new implementation in a document for a given definition.
298 @param sourceColorSpace: The source color space.
299 @param targetColorSpace: The target color space.
300 @param doc: The MaterialX document.
301 @param definition: The MaterialX definition.
302 @param transformName: The transform name.
303 @param extension: The file extension.
304 @param target: The target language.
305 '''
306 implName = transformName + '_' + target
307 filename = transformName + '.' + extension
308 implName = implName.replace('mx_', 'IM_')
309
310 # Check if implementation already exists
311 impl = doc.getImplementation(implName)
312 if impl:
313 print('Implementation already exists: %s' % implName)
314 return impl
315
316 comment = doc.addChildOfCategory('comment')
317 comment.setDocString(' Color space %s to %s transform. Generated via OCIO for target: %s'
318 % (sourceColorSpace, targetColorSpace, target))
319 impl = doc.addImplementation(implName)
320 impl.setFile(filename)
321 impl.setFunction(transformName)
322 impl.setTarget(target)
323 impl.setNodeDef(definition)
324
325 return impl
326
327 def generateOCIO(self, config, definitionDoc, implDoc, sourceColorSpace = 'acescg', targetColorSpace = 'lin_rec709',
328 type='color4', IN_PIXEL_STRING = 'in'):
329 '''
330 Generate a MaterialX definition and implementation for a given color space transform.
331 Returns the definition, implementation, source code, extension and target.
332 @param config: The OCIO configuration.
333 @param definitionDoc: The MaterialX document to add the definition to.
334 @param implDoc: The MaterialX document to add the implementation to.
335 @param sourceColorSpace: The source color space.
336 @param targetColorSpace: The destination color space.
337 @param type: The type of the transform.
338 @param IN_PIXEL_STRING: The input pixel string.
339 @return: A tuple containing the definition, transform name, source code, extension
340 '''
341
342 # List of MaterialX target language, source code extensions, and OCIO GPU languages
343 generationList = [
344 ['genglsl', 'glsl', OCIO.GpuLanguage.GPU_LANGUAGE_GLSL_4_0]
345 #, ['genmsl', 'metal', OCIO.GpuLanguage.GPU_LANGUAGE_MSL_2_0]
346 ]
347
348 definition = None
349 transformName = self.createTransformName(sourceColorSpace, targetColorSpace, type)
350 for gen in generationList:
351 target = gen[0]
352 extension = gen[1]
353 language = gen[2]
354
355 code, textureCount = self.generateShaderCode(config, sourceColorSpace, targetColorSpace, language)
356
357 # Skip if there are texture resources
358 if textureCount:
359 print('- Skip generation for transform: "%s" to "%s" which requires %d texture resources' % (sourceColorSpace, targetColorSpace, textureCount))
360 continue
361
362 if code:
363 # Create the definition once
364 if not definition:
365 # Create color4 variant
366 definition = self.generateMaterialXDefinition(definitionDoc, sourceColorSpace, targetColorSpace,
367 IN_PIXEL_STRING, type)
368 # Create color3 variant (nodegraph)
369 self.createColor3Variant(definition, definitionDoc, IN_PIXEL_STRING)
370
371 # Create the implementation
372 self.createMaterialXImplementation(sourceColorSpace, targetColorSpace, implDoc, definition, transformName, extension, target)
373
374 return definition, transformName, code, extension, target
375
376 def generateOCIOGraph(self, config, sourceColorSpace = 'acescg', targetColorSpace = 'lin_rec709',
377 type='color3'):
378 '''
379 Generate a MaterialX nodegraph for a given color space transform.
380 @param config: The OCIO configuration.
381 @param sourceColorSpace: The source color space.
382 @param targetColorSpace: The destination color space.
383 @param type: The type of the transform.
384 Returns a MaterialX document containing a functional nodegraph and nodedef pair.
385 '''
386 groupTransform = self.generateTransformGraph(config, sourceColorSpace, targetColorSpace)
387
388 # To add. Proper testing of unsupported transforms...
389 invalidTransforms = [ OCIO.TransformType.TRANSFORM_TYPE_LUT3D, OCIO.TransformType.TRANSFORM_TYPE_LUT1D,
390 OCIO.TransformType.TRANSFORM_TYPE_GRADING_PRIMARY ]
391
392 # Create a document, a nodedef and a functional graph.
393 graphDoc = mx.createDocument()
394 outputType = 'color3'
395 xformName = self.createValidName(sourceColorSpace) + '_to_' + self.createValidName(targetColorSpace) + '_' + outputType
396
397 nd = graphDoc.addNodeDef('ND_' + xformName )
398 nd.setNodeString(xformName)
399 ndInput = nd.addInput('in', 'color3')
400 ndInput.setValue([0.0, 0.0, 0.0], 'color3')
401 docString = f'Generated color space {sourceColorSpace} to {targetColorSpace} transform.'
402 result = f'{groupTransform}'
403 # Replace '<' and '>' with '()' and ')'
404 result = result.replace('<', '(')
405 result = result.replace('>', ')')
406 result = re.sub(r'[\r\n]+', '', result)
407
408 #print(result)
409 docString = docString + '. OCIO Transforms: ' + result
410 nd.setDocString(docString)
411
412 ng = graphDoc.addNodeGraph('NG_' + xformName)
413 ng.setNodeDefString(nd.getName())
414 convertNode = ng.addNode('convert', 'asVec', 'vector3')
415 converInput = convertNode.addInput('in', 'color3')
416 converInput.setInterfaceName('in')
417
418 #print(f'Transform from: {sourceColorSpace} to {targetColorSpace}')
419 if not groupTransform:
420 #print(f'No group transform found for the color space transform: {sourceColorSpace} to {targetColorSpace}')
421 return None
422 #print(f'Number of transforms: {groupTransform.__len__()}')
423 previousNode = None
424
425 # Iterate and create appropriate nodes and connections
426 for i in range(groupTransform.__len__()):
427 transform = groupTransform.__getitem__(i)
428 # Get type of transform
429 transformType = transform.getTransformType()
430 if transformType in invalidTransforms:
431 print(f'- WARNING: Transform[{i}]: {transformType} contains an unsupported transform type')
432 continue
433
434 #print(f'- Transform[{i}]: {transformType}')
435 if transformType == OCIO.TransformType.TRANSFORM_TYPE_MATRIX:
436 matrixNode = ng.addNode('transform', ng.createValidChildName(f'matrixTransform'), 'vector3')
437
438 # Route output from previous node as input of current node
439 inInput = matrixNode.addInput('in', 'vector3')
440 if previousNode:
441 inInput.setConnectedNode(previousNode)
442 else:
443 #if i==0:
444 inInput.setConnectedNode(convertNode)
445 #else:
446 # inInput.setValue([0.0, 0.0, 0.0], 'vector3')
447
448 # Set matrix value
449 matInput = matrixNode.addInput('mat', 'matrix33')
450 matrixValue = transform.getMatrix()
451 # Extract 3x3 matrix from 4x4 matrix
452 matrixValue = matrixValue[0:3] + matrixValue[4:7] + matrixValue[8:11]
453 matrixValue = ', '.join([str(x) for x in matrixValue])
454 #print(' - Matrix:', matrixValue)
455 matInput.setAttribute('value', matrixValue)
456
457 # Add offset value - TODO
458 offsetValue = transform.getOffset()
459 offsetValue = ', '.join([str(x) for x in offsetValue])
460 #print(' - Offset:', offsetValue)
461 # Add a add vector3 to graph
462
463 previousNode = matrixNode
464
465 # TODO: Handle other transform types
466 elif transformType == OCIO.TransformType.TRANSFORM_TYPE_EXPONENT or transformType == OCIO.TransformType.TRANSFORM_TYPE_EXPONENT_WITH_LINEAR:
467
468 hasOffset = (transformType == OCIO.TransformType.TRANSFORM_TYPE_EXPONENT_WITH_LINEAR)
469
470 #print(f'- Transform[{i}]: {transformType} support has not been implemented yet')
471 exponentNode = ng.addNode('power', ng.createValidChildName(f'exponent'), 'vector3')
472 exponentInput = exponentNode.addInput('in1', 'vector3')
473 if previousNode:
474 exponentInput.setConnectedNode(previousNode)
475 else:
476 if i==0:
477 exponentInput.setConnectedNode(convertNode)
478 else:
479 exponentInput.setValue([0.0, 0.0, 0.0], 'vector3')
480
481 exponentInput2 = exponentNode.addInput('in2', 'vector3')
482 exponentInput2Value = None
483 if not hasOffset:
484 exponentInput2Value = transform.getValue()
485 else:
486 exponentInput2Value = transform.getGamma()
487 # Only want the first 3 values in the array
488 exponentInput2Value = exponentInput2Value[0:3]
489 exponentInput2.setValue(exponentInput2Value, 'float')
490
491 previousNode = exponentNode
492
493 if hasOffset:
494 # Add offset
495 offsetNode = ng.addNode('add', ng.createValidChildName(f'offset'), 'vector3')
496 offsetInput2 = offsetNode.addInput('in2', 'vector3')
497 offsetInput2.setConnectedNode(exponentNode)
498 offsetInput = offsetNode.addInput('in1', 'vector3')
499 offsetValue = transform.getOffset()
500 # Only want the first 3 values in the array
501 offsetValue = offsetValue[0:3]
502 offsetInput.setValue(offsetValue, 'vector3')
503
504 previousNode = offsetNode
505
506 # Remap range
507 elif transformType == OCIO.TransformType.TRANSFORM_TYPE_RANGE:
508 # Set old min/max and new min/max
509 inMin = transform.getMinInValue()
510 inMax = transform.getMaxInValue()
511 outMin = transform.getMinOutValue()
512 if not outMin:
513 outMin = inMin
514 outMax = transform.getMaxOutValue()
515 if not outMax:
516 outMax = inMax
517 #print(f' - Range: inMin={inMin}, inMax={inMax}, outMin={outMin}, outMax={outMax}',
518 # transform)
519
520 clamp_min = False
521 clamp_max = False
522 if inMin and not inMax and not outMax:
523 #print(f' ->>>>>>>> Clamp max: inMin={inMin}, inMax={inMax}, outMin={outMin}, outMax={outMax}')
524 clamp_max = True
525 elif inMax and not inMin and not outMin:
526 #print(f' ->>>>>>>>> Clamp min: inMin={inMin}, inMax={inMax}, outMin={outMin}, outMax={outMax}')
527 clamp_min = True
528
529 # If not clamp then it's a range remap
530 if not clamp_min and not clamp_max:
531 rangeNode = ng.addNode('range', ng.createValidChildName(f'range'), 'vector3')
532 rangeInput = rangeNode.addInput('in', 'vector3')
533 if previousNode:
534 rangeInput.setConnectedNode(previousNode)
535 else:
536 if i==0:
537 rangeInput.setConnectedNode(convertNode)
538 else:
539 rangeInput.setValue([0.0, 0.0, 0.0], 'vector3')
540
541 inMinInput = rangeNode.addInput('inlow', 'vector3')
542 inMinInput.setValue([inMin, inMin, inMin], 'vector3')
543 inMaxInput = rangeNode.addInput('inhigh', 'vector3')
544 inMaxInput.setValue([inMax, inMax, inMax], 'vector3')
545 outMinInput = rangeNode.addInput('outlow', 'vector3')
546 outMinInput.setValue([outMin, outMin, outMin], 'vector3')
547 outMaxInput = rangeNode.addInput('outhigh', 'vector3')
548 outMaxInput.setValue([outMax, outMax, outMax], 'vector3')
549
550 #print("add range node:", mx.prettyPrint(rangeNode))
551
552 previousNode = rangeNode
553
554 elif clamp_max:
555 clampNode = ng.addNode('min', ng.createValidChildName(f'clamp_max'), 'vector3')
556 clampInput = clampNode.addInput('in1', 'vector3')
557 if previousNode:
558 clampInput.setConnectedNode(previousNode)
559 else:
560 if i==0:
561 clampInput.setConnectedNode(convertNode)
562 else:
563 clampInput.setValue([0.0, 0.0, 0.0], 'vector3')
564 minInput = clampNode.addInput('in2', 'vector3')
565 minInput.setValue([inMax, inMax, inMax], 'vector3')
566
567 #print('add clamp max node:', mx.prettyPrint(clampNode))
568 previousNode = clampNode
569
570 elif clamp_min:
571 clampNode = ng.addNode('max', ng.createValidChildName(f'clamp_min'), 'vector3')
572 clampInput = clampNode.addInput('in1', 'vector3')
573 if previousNode:
574 clampInput.setConnectedNode(previousNode)
575 else:
576 if i==0:
577 clampInput.setConnectedNode(convertNode)
578 else:
579 clampInput.setValue([0.0, 0.0, 0.0], 'vector3')
580 maxInput = clampNode.addInput('in2', 'vector3')
581 maxInput.setValue([inMin, inMin, inMin], 'vector3')
582
583 #print('add clamp min node:', mx.prettyPrint(clampNode))
584 previousNode = clampNode
585
586
587 elif transformType == OCIO.TransformType.TRANSFORM_TYPE_LOG_CAMERA:
588 print(f'- WARNING. Transform[{i}]: {transformType} support has not been implemented yet')
589
590 else:
591 print(f'- WARNING. Transform[{i}]: {transformType} support has not been implemented yet')
592 continue
593
594
595 # Create an output for the last node if any
596 convertNode2 = ng.addNode('convert', 'asColor', 'color3')
597 converInput2 = convertNode2.addInput('in', 'vector3')
598 if previousNode:
599 converInput2.setConnectedNode(previousNode)
600 else:
601 # Pass-through
602 #print('No transforms applied. Transform is a pass-through.')
603 converInput2.setConnectedNode(convertNode)
604 out = ng.addOutput(ng.createValidChildName('out'), 'color3')
605 out.setConnectedNode(convertNode2)
606
607 return graphDoc
608
609 def createColor3Variant(self, definition, definitionDoc, IN_PIXEL_STRING = 'in'):
610 '''
611 Create a color3 variant of a color4 definition.
612 @param definition: The color4 definition.
613 @param definitionDoc: The MaterialX document.
614 @param IN_PIXEL_STRING: The input pixel string.
615 '''
616 color4Name = definition.getName()
617 color3Name = color4Name.replace('color4', 'color3')
618 color3Def = definitionDoc.addNodeDef(color3Name)
619 color3Def.copyContentFrom(definition)
620 c3input = color3Def.getInput(IN_PIXEL_STRING)
621 c3input.setType('color3')
622 c3input.setValue([0.0, 0.0, 0.0], 'color3')
623
624 ngName = color3Def.getName().replace('ND_', 'NG_')
625 ng = definitionDoc.addNodeGraph(ngName)
626 c4instance = ng.addNodeInstance(definition)
627 c4instance.addInputsFromNodeDef()
628 c4instanceIn = c4instance.getInput(IN_PIXEL_STRING)
629 c3to4 = ng.addNode('convert', 'c3to4', 'color4')
630 c3to4Input = c3to4.addInput('in', 'color3')
631 c4to3 = ng.addNode('convert', 'c4to3', 'color3')
632 c4to3Input = c4to3.addInput('in', 'color4')
633 ngout = ng.addOutput('out', 'color3')
634 #ngin = ng.addInput('in', 'color3')
635 ng.setNodeDef(color3Def)
636
637 c4instanceIn.setConnectedNode(c3to4)
638 c4to3Input.setConnectedNode(c4instance)
639 ngout.setConnectedNode(c4to3)
640 c3to4Input.setInterfaceName(IN_PIXEL_STRING)
A class to generate MaterialX color transform definitions using OCIO.
Definition core.py:13
createMaterialXImplementation(self, sourceColorSpace, targetColorSpace, doc, definition, transformName, extension, target)
Create a new implementation in a document for a given definition.
Definition core.py:295
generateOCIO(self, config, definitionDoc, implDoc, sourceColorSpace='acescg', targetColorSpace='lin_rec709', type='color4', IN_PIXEL_STRING='in')
Generate a MaterialX definition and implementation for a given color space transform.
Definition core.py:328
generateOCIOGraph(self, config, sourceColorSpace='acescg', targetColorSpace='lin_rec709', type='color3')
Generate a MaterialX nodegraph for a given color space transform.
Definition core.py:377
printConfigs(self, configs)
Print the OCIO built in configurations as a markdown table.
Definition core.py:52
str createValidName(self, str name)
Create a valid name MaterialX name.
Definition core.py:71
generateTransformGraph(self, config, sourceColorSpace, destColorSpace)
Generate the group of transforms required to go from a source color space to a destination color spac...
Definition core.py:156
generateShaderCode(self, config, sourceColorSpace, destColorSpace, language)
Generate shader for a transform from a source color space to a destination color space for a given co...
Definition core.py:105
OSL(self, config, sourceColorSpace, targetColorSpace)
Generate OSL shader code for a transform from a source color space to a destination color space for a...
Definition core.py:228
getBuiltinConfigs(self)
Get the OCIO built in configurations.
Definition core.py:18
setShaderDescriptionParameters(self, shaderDesc, sourceSpace, targetSpace, typeName)
Set parameters on a shader description for a given source and target color space and type name.
Definition core.py:93
MSL(self, config, sourceColorSpace, targetColorSpace)
Generate MSL shader code for a transform from a source color space to a destination color space for a...
Definition core.py:213
createColor3Variant(self, definition, definitionDoc, IN_PIXEL_STRING='in')
Create a color3 variant of a color4 definition.
Definition core.py:609
generateMaterialXDefinition(self, doc, sourceColorSpace, targetColorSpace, inputName, type)
Create a new definition in a document for a given color space transform.
Definition core.py:249
createTransformName(self, sourceSpace, targetSpace, typeName, prefix='mx_')
Create a transform name from a source and target color space and a type name.
Definition core.py:82
writeShaderCode(self, outputPath, code, transformName, extension, target)
Write the shader code to a file.
Definition core.py:279
hasTextureResources(self, configs, targetColorSpace, language)
Scan through all the color spaces on the configs to check for texture resource usage.
Definition core.py:183