96 Generate shader for a transform from a source color space to a destination color space
97 for a given config and shader language.
99 @param config: The OCIO configuration.
100 @param sourceColorSpace: The source color space.
101 @param destColorSpace: The destination color space.
102 @param language: The OCIO GPU language.
103 @return: A tuple containing the shader code and the number of texture resources required.
105 Returns the shader code and the number of texture resources required.
110 return shaderCode, textureCount
115 processor = config.getProcessor(sourceColorSpace, destColorSpace)
117 print(
'Failed to generated code for transform: %s -> %s' % (sourceColorSpace, destColorSpace))
118 return shaderCode, textureCount
121 gpuProcessor = processor.getDefaultGPUProcessor()
123 shaderDesc = OCIO.GpuShaderDesc.CreateShaderDesc()
126 shaderDesc.setLanguage(language)
127 if shaderDesc.getLanguage() == language:
129 gpuProcessor.extractGpuShaderInfo(shaderDesc)
130 shaderCode = shaderDesc.getShaderText()
132 for t
in shaderDesc.getTextures():
136 shaderCode = shaderCode.replace(
137 "// Declaration of the OCIO shader function\n",
138 "// " + sourceColorSpace +
" to " + destColorSpace +
" function. Texture count: %d\n" % textureCount)
140 except OCIO.Exception
as err:
143 return shaderCode, textureCount
174 Scan through all the color spaces on the configs to check for texture resource usage.
175 Returns a set of color spaces that require texture resources.
177 @param configs: The OCIO configurations.
178 @param targetColorSpace: The target color space.
179 @param language: The OCIO GPU language.
180 @return: A set of color spaces that require texture resources.
182 testedSources = set()
183 textureSources = set()
185 config = OCIO.Config.CreateFromBuiltinConfig(c)
186 colorSpaces = config.getColorSpaces()
187 for colorSpace
in colorSpaces:
188 colorSpaceName = colorSpace.getName()
190 if colorSpaceName
in testedSources:
192 testedSources.add(colorSpaceName)
195 code, textureCount = self.
generateShaderCode(config, colorSpace.getName(), targetColorSpace, language)
197 print(
'- Transform "%s" to "%s" requires %d texture resources' % (colorSpace.getName(), targetColorSpace, textureCount))
198 textureSources.add(colorSpaceName)
200 return textureSources
217 def OSL(self, config, sourceColorSpace, targetColorSpace):
219 Generate OSL shader code for a transform from a source color space to a destination color space
221 @param config: The OCIO configuration.
222 @param sourceColorSpace: The source color space.
223 @param targetColorSpace: The destination color space.
224 @return: The shader code.
226 if OCIO.GpuLanguage.LANGUAGE_OSL_1:
227 language = OCIO.GpuLanguage.LANGUAGE_OSL_1
228 code, textureCount = self.
generateShaderCode(config, sourceColorSpace, targetColorSpace, language)
232 code = code.replace(
'OSL_' + transformName,
'__temp_name__')
233 code = code.replace(transformName, transformName +
'_impl')
234 code = code.replace(
'__temp_name__', transformName)
235 code = code.replace(
"// Declaration of the OCIO shader function\n",
"// " + sourceColorSpace +
" to " + targetColorSpace +
" function\n")
236 code =
'```c++\n' + code +
'\n```\n'
240 Create a new definition in a document for a given color space transform.
241 Returns the definition.
245 nodeName = transformName.replace(
'mx_',
'ND_')
247 comment = doc.addChildOfCategory(
'comment')
248 docString =
' Color space %s to %s transform. Generated via OCIO. ' % (sourceColorSpace, targetColorSpace)
249 comment.setDocString(docString)
251 definition = doc.addNodeDef(nodeName,
'color4')
252 category = sourceColorSpace +
'_to_' + targetColorSpace
253 definition.setNodeString(category)
254 definition.setNodeGroup(
'colortransform')
255 definition.setDocString(docString)
256 definition.setVersionString(
'1.0')
258 defaultValueString =
'0.0 0.0 0.0 1.0'
259 defaultValue = mx.createValueFromStrings(defaultValueString,
'color4')
260 input = definition.addInput(inputName, type)
261 input.setValue(defaultValue)
262 output = definition.getOutput(
'out')
263 output.setAttribute(
'default',
'in')
285 Create a new implementation in a document for a given definition.
286 @param sourceColorSpace: The source color space.
287 @param targetColorSpace: The target color space.
288 @param doc: The MaterialX document.
289 @param definition: The MaterialX definition.
290 @param transformName: The transform name.
291 @param extension: The file extension.
292 @param target: The target language.
294 implName = transformName +
'_' + target
295 filename = transformName +
'.' + extension
296 implName = implName.replace(
'mx_',
'IM_')
299 impl = doc.getImplementation(implName)
301 print(
'Implementation already exists: %s' % implName)
304 comment = doc.addChildOfCategory(
'comment')
305 comment.setDocString(
' Color space %s to %s transform. Generated via OCIO for target: %s'
306 % (sourceColorSpace, targetColorSpace, target))
307 impl = doc.addImplementation(implName)
308 impl.setFile(filename)
309 impl.setFunction(transformName)
310 impl.setTarget(target)
311 impl.setNodeDef(definition)
315 def generateOCIO(self, config, definitionDoc, implDoc, sourceColorSpace = 'acescg', targetColorSpace = 'lin_rec709',
316 type='color4', IN_PIXEL_STRING = 'in'):
318 Generate a MaterialX definition and implementation for a given color space transform.
319 Returns the definition, implementation, source code, extension and target.
320 @param config: The OCIO configuration.
321 @param definitionDoc: The MaterialX document to add the definition to.
322 @param implDoc: The MaterialX document to add the implementation to.
323 @param sourceColorSpace: The source color space.
324 @param targetColorSpace: The destination color space.
325 @param type: The type of the transform.
326 @param IN_PIXEL_STRING: The input pixel string.
327 @return: A tuple containing the definition, transform name, source code, extension
332 [
'genglsl',
'glsl', OCIO.GpuLanguage.GPU_LANGUAGE_GLSL_4_0]
338 for gen
in generationList:
343 code, textureCount = self.
generateShaderCode(config, sourceColorSpace, targetColorSpace, language)
347 print(
'- Skip generation for transform: "%s" to "%s" which requires %d texture resources' % (sourceColorSpace, targetColorSpace, textureCount))
355 IN_PIXEL_STRING, type)
362 return definition, transformName, code, extension, target
364 def generateOCIOGraph(self, config, sourceColorSpace = 'acescg', targetColorSpace = 'lin_rec709',
367 Generate a MaterialX nodegraph for a given color space transform.
368 @param config: The OCIO configuration.
369 @param sourceColorSpace: The source color space.
370 @param targetColorSpace: The destination color space.
371 @param type: The type of the transform.
372 Returns a MaterialX document containing a functional nodegraph and nodedef pair.
377 invalidTransforms = [ OCIO.TransformType.TRANSFORM_TYPE_LUT3D, OCIO.TransformType.TRANSFORM_TYPE_LUT1D,
378 OCIO.TransformType.TRANSFORM_TYPE_GRADING_PRIMARY ]
381 graphDoc = mx.createDocument()
382 outputType =
'color3'
383 xformName = sourceColorSpace +
'_to_' + targetColorSpace +
'_' + outputType
385 nd = graphDoc.addNodeDef(
'ND_' + xformName )
386 nd.setAttribute(
'node', xformName)
387 ndInput = nd.addInput(
'in',
'color3')
388 ndInput.setValue([0.0, 0.0, 0.0],
'color3')
389 docString = f
'Generated color space {sourceColorSpace} to {targetColorSpace} transform.'
390 result = f
'{groupTransform}'
392 result = result.replace(
'<',
'(')
393 result = result.replace(
'>',
')')
394 result = re.sub(
r'[\r\n]+',
'', result)
397 docString = docString +
'. OCIO Transforms: ' + result
398 nd.setDocString(docString)
400 ng = graphDoc.addNodeGraph(
'NG_' + xformName)
401 ng.setAttribute(
'nodedef', nd.getName())
402 convertNode = ng.addNode(
'convert',
'asVec',
'vector3')
403 converInput = convertNode.addInput(
'in',
'color3')
404 converInput.setInterfaceName(
'in')
407 if not groupTransform:
414 for i
in range(groupTransform.__len__()):
415 transform = groupTransform.__getitem__(i)
417 transformType = transform.getTransformType()
418 if transformType
in invalidTransforms:
419 print(f
'- Transform[{i}]: {transformType} contains an unsupported transform type')
423 if transformType == OCIO.TransformType.TRANSFORM_TYPE_MATRIX:
424 matrixNode = ng.addNode(
'transform', ng.createValidChildName(f
'matrixTransform'),
'vector3')
427 inInput = matrixNode.addInput(
'in',
'vector3')
429 inInput.setAttribute(
'nodename', previousNode)
432 inInput.setAttribute(
'nodename',
'asVec')
437 matInput = matrixNode.addInput(
'mat',
'matrix33')
438 matrixValue = transform.getMatrix()
440 matrixValue = matrixValue[0:3] + matrixValue[4:7] + matrixValue[8:11]
441 matrixValue =
', '.join([str(x)
for x
in matrixValue])
443 matInput.setAttribute(
'value', matrixValue)
446 offsetValue = transform.getOffset()
447 offsetValue =
', '.join([str(x)
for x
in offsetValue])
451 previousNode = matrixNode.getName()
454 elif transformType == OCIO.TransformType.TRANSFORM_TYPE_EXPONENT
or transformType == OCIO.TransformType.TRANSFORM_TYPE_EXPONENT_WITH_LINEAR:
456 hasOffset = (transformType == OCIO.TransformType.TRANSFORM_TYPE_EXPONENT_WITH_LINEAR)
459 exponentNode = ng.addNode(
'power', ng.createValidChildName(f
'exponent'),
'vector3')
460 exponentInput = exponentNode.addInput(
'in1',
'vector3')
462 exponentInput.setAttribute(
'nodename', previousNode)
465 exponentInput.setAttribute(
'nodename',
'asVec')
467 exponentInput.setValue([0.0, 0.0, 0.0],
'vector3')
469 exponentInput2 = exponentNode.addInput(
'in2',
'vector3')
470 exponentInput2Value =
None
472 exponentInput2Value = transform.getValue()
474 exponentInput2Value = transform.getGamma()
476 exponentInput2Value = exponentInput2Value[0:3]
477 exponentInput2.setValue(exponentInput2Value,
'float')
479 previousNode = exponentNode.getName()
483 offsetNode = ng.addNode(
'add', ng.createValidChildName(f
'offset'),
'vector3')
484 offsetInput2 = offsetNode.addInput(
'in2',
'vector3')
485 offsetInput2.setNodeName(exponentNode.getName())
486 offsetInput = offsetNode.addInput(
'in1',
'vector3')
487 offsetValue = transform.getOffset()
489 offsetValue = offsetValue[0:3]
490 offsetInput.setValue(offsetValue,
'vector3')
492 previousNode = offsetNode.getName()
495 print(f
'- Transform[{i}]: {transformType} support has not been implemented yet')
500 convertNode2 = ng.addNode(
'convert',
'asColor',
'color3')
501 converInput2 = convertNode2.addInput(
'in',
'vector3')
503 converInput2.setAttribute(
'nodename', previousNode)
507 converInput2.setAttribute(
'nodename',
'asVec')
509 out = ng.addOutput(ng.createValidChildName(
'out'),
'color3')
510 out.setAttribute(
'nodename',
'asColor')
516 Create a color3 variant of a color4 definition.
517 @param definition: The color4 definition.
518 @param definitionDoc: The MaterialX document.
519 @param IN_PIXEL_STRING: The input pixel string.
521 color4Name = definition.getName()
522 color3Name = color4Name.replace(
'color4',
'color3')
523 color3Def = definitionDoc.addNodeDef(color3Name)
524 color3Def.copyContentFrom(definition)
525 c3input = color3Def.getInput(IN_PIXEL_STRING)
526 c3input.setType(
'color3')
527 c3input.setValue([0.0, 0.0, 0.0],
'color3')
529 ngName = color3Def.getName().replace(
'ND_',
'NG_')
530 ng = definitionDoc.addNodeGraph(ngName)
531 c4instance = ng.addNodeInstance(definition)
532 c4instance.addInputsFromNodeDef()
533 c4instanceIn = c4instance.getInput(IN_PIXEL_STRING)
534 c3to4 = ng.addNode(
'convert',
'c3to4',
'color4')
535 c3to4Input = c3to4.addInput(
'in',
'color3')
536 c4to3 = ng.addNode(
'convert',
'c4to3',
'color3')
537 c4to3Input = c4to3.addInput(
'in',
'color4')
538 ngout = ng.addOutput(
'out',
'color3')
540 ng.setNodeDef(color3Def)
542 c4instanceIn.setNodeName(c3to4.getName())
543 c4to3Input.setNodeName(c4instance.getName())
544 ngout.setNodeName(c4to3.getName())
545 c3to4Input.setInterfaceName(IN_PIXEL_STRING)