Samiam’s Scribble Pad

December 3, 2015

MtoA OpenEXR Meta Data via Python Scripting Arnold and Maya EXR

Filed under: Uncategorized — admin @ 1:04 pm

snap-clockworkorange-latest

 

Basically this post is a call for help, and once I have it solved it will become a reference for anybody else trying to do the same thing in the future.

In the Maya Arnold Render Globals there are some fields to Add MetaData with a “Name”, “Type” and “Value” field available.

Which is cool if you are clicking, but if you want to push these buttons with code, what are the attributes called or the methods are to set them

so basically the answer is usually documented in the source

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
class EXRDriverTranslatorUI(templates.AttributeTemplate):
    def changeAttrName(self, nodeName, attrNameText, index):
        # Get the attribute name, type and value
        attrName = nodeName+'['+str(index)+']'
        metadata = cmds.getAttr(attrName)
        result = metadata.split(' ', 2 )
        result += [""] * (3-len(result))
 
        # Get the new name
        name = cmds.textField(attrNameText, query=True, text=True)
 
        # Update the name in all the templates
        templatesNames[:] = [tup for tup in templatesNames if cmds.columnLayout(tup, exists=True)]
        for templateName in templatesNames:
            cmds.textField(templateName+"|mtoa_exrMetadataRow_"+str(index)+"|MtoA_exrMAttributeName", edit=True, text=name.replace(" ", ""))
 
        # Update the metadata value
        metadata = result[0]+" "+name.replace(" ", "")+" "+result[2]
        cmds.setAttr(attrName, metadata, type="string")
 
    def changeAttrType(self, nodeName, menu, index):
        # Get the attribute name, type and value
        attrName = nodeName+'['+str(index)+']'
        metadata = cmds.getAttr(attrName)
        result = metadata.split(' ', 2 )
        result += [""] * (3-len(result))
 
        # Get the new type
        typeNumber = cmds.optionMenu(menu, query=True, select=True)
        type = cmds.optionMenu(menu, query=True, value=True)
 
        # Update the type in all the templates
        templatesNames[:] = [tup for tup in templatesNames if cmds.columnLayout(tup, exists=True)]
        for templateName in templatesNames:
            cmds.optionMenu(templateName+"|mtoa_exrMetadataRow_"+str(index)+"|MtoA_exrMAttributeType", edit=True, select=typeNumber)
 
        # Update the metadata value
        metadata = type+" "+result[1]+" "+result[2]
        cmds.setAttr(attrName, metadata, type="string")
 
    def changeAttrValue(self, nodeName, attrValueText, index):
        # Get the attribute name, type and value
        attrName = nodeName+'['+str(index)+']'
        metadata = cmds.getAttr(attrName)
        result = metadata.split(' ', 2 )
        result += [""] * (3-len(result))
 
        # Get the new value
        value = cmds.textField(attrValueText, query=True, text=True)
 
        # Update the value in all the templates
        templatesNames[:] = [tup for tup in templatesNames if cmds.columnLayout(tup, exists=True)]
        for templateName in templatesNames:
            cmds.textField(templateName+"|mtoa_exrMetadataRow_"+str(index)+"|MtoA_exrMAttributeValue", edit=True, text=value)
 
        # Update the metadata value
        metadata = result[0]+" "+result[1]+" "+value
        cmds.setAttr(attrName, metadata, type="string")
 
    def removeAttribute(self, nodeName, index):
        cmds.removeMultiInstance(nodeName+'['+str(index)+']')
        self.updatedMetadata(nodeName)
 
    def addAttribute(self, nodeName):
        next = 0
        if cmds.getAttr(nodeName, multiIndices=True):
            next = cmds.getAttr(nodeName, multiIndices=True)[-1] + 1
        cmds.setAttr(nodeName+'['+str(next)+']', "INT", type="string")
        self.updatedMetadata(nodeName)
 
    def updateLine(self, nodeName, metadata, index):
        # Attribute controls will be created with the current metadata content
        result = metadata.split(' ', 2 )
        result += [""] * (3-len(result))
 
        # Attribute Name
        attrNameText = cmds.textField("MtoA_exrMAttributeName", text=result[1])
        cmds.textField(attrNameText, edit=True, changeCommand=pm.Callback(self.changeAttrName, nodeName, attrNameText, index))
 
        # Attribute Type
        menu = cmds.optionMenu("MtoA_exrMAttributeType")
        cmds.menuItem( label='INT', data=0)
        cmds.menuItem( label='FLOAT', data=1)
        cmds.menuItem( label='POINT2', data=2)
        cmds.menuItem( label='MATRIX', data=3)
        cmds.menuItem( label='STRING', data=4)
        if result[0] == 'INT':
            cmds.optionMenu(menu, edit=True, select=1)
        elif result[0] == 'FLOAT':
            cmds.optionMenu(menu, edit=True, select=2)
        elif result[0] == 'POINT2':
            cmds.optionMenu(menu, edit=True, select=3)
        elif result[0] == 'MATRIX':
            cmds.optionMenu(menu, edit=True, select=4)
        elif result[0] == 'STRING':
            cmds.optionMenu(menu, edit=True, select=5)
        cmds.optionMenu(menu, edit=True, changeCommand=pm.Callback(self.changeAttrType, nodeName, menu, index))
 
        # Attribute Value
        attrValueText = cmds.textField("MtoA_exrMAttributeValue", text=result[2])
        cmds.textField(attrValueText, edit=True, changeCommand=pm.Callback(self.changeAttrValue, nodeName, attrValueText, index))
 
        # Remove button
        cmds.symbolButton(image="SP_TrashIcon.png", command=pm.Callback(self.removeAttribute, nodeName, index))
 
    def updatedMetadata(self, nodeName):
        templatesNames[:] = [tup for tup in templatesNames if cmds.columnLayout(tup, exists=True)]
        for templateName in templatesNames:
            cmds.setParent(templateName)
            #Remove all attributes controls and rebuild them again with the metadata updated content
            for child in cmds.columnLayout(templateName, query=True, childArray=True) or []:
                cmds.deleteUI(child)
            for index in cmds.getAttr(nodeName, multiIndices=True) or []:
                attrName = nodeName+'['+str(index)+']'
                metadata = cmds.getAttr(attrName)
                if metadata:
                    cmds.rowLayout('mtoa_exrMetadataRow_'+str(index),nc=4, cw4=(120,80,120,20), cl4=('center', 'center', 'center', 'right'))
                    self.updateLine(nodeName, metadata, index)
                    cmds.setParent('..')
 
    def metadataNew(self, nodeName):
        cmds.rowLayout(nc=2, cw2=(200,140), cl2=('center', 'center'))
        cmds.button( label='Add New Attribute', command=pm.Callback(self.addAttribute, 'defaultArnoldDriver.custom_attributes'))
        cmds.setParent( '..' )
        layout = cmds.columnLayout(rowSpacing=5, columnWidth=340)
        # This template could be created more than once in different panels
        templatesNames.append(layout)
        self.updatedMetadata('defaultArnoldDriver.custom_attributes')
        cmds.setParent( '..' )
 
    def metadataReplace(self, nodeName):
        pass
 
    def setup(self):
        self.addControl('exrCompression', label='Compression')
        self.addControl('halfPrecision', label='Half Precision')
        self.addControl('preserveLayerName', label='Preserve Layer Name')
        self.addControl('tiled', label='Tiled')
        self.addControl('autocrop', label='Autocrop')
        self.addControl('append', label='Append')
        self.beginLayout("Metadata (name, type, value)", collapse=True)
        self.addCustom('custom_attributes', self.metadataNew, self.metadataReplace)
        self.endLayout()

So after that it isn’t rocket surgery

There is a compound attribute with strings in it called “custom attributes” as seen in the screen shot below

snap-clockworkorange-20151203-120441

So if you want to bang another another value into that custom attribute you can

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#Print attributes
for i in maya.cmds.getAttr("defaultArnoldDriver.customAttributes",mi=True):
    print maya.cmds.getAttr("defaultArnoldDriver.customAttributes[%d]" % i)
 
 
 
def addAttribute(nodeName, value):
    """
    \add an attribute
    """
    next = 0
    if cmds.getAttr(nodeName, multiIndices=True):
        next = cmds.getAttr(nodeName, multiIndices=True)[-1] + 1
    cmds.setAttr(nodeName+'['+str(next)+']', "%s %s %s" % (value["type"],value["name"],value["value"]), type="string")
 
#Call function above
example = {"type":"FLOAT","name":"example","value":2.0}        
nodeName = "defaultArnoldDriver.customAttributes"
addAttribute(nodeName,example)    
 
#Print attributes again after adding
for i in maya.cmds.getAttr("defaultArnoldDriver.customAttributes",mi=True):
    print maya.cmds.getAttr("defaultArnoldDriver.customAttributes[%d]" % i)
 
#This updates the GUI    
from mtoa.ui.ae import customShapeAttributes
 
c = customShapeAttributes.EXRDriverTranslatorUI('aiAOVDriver')
 
c.updatedMetadata(nodeName)

But that doesn’t update the GUI, but may make an EXR with meta data.

So I think I need to do it with a little more care.

But in reality it is there in the data structure, the gui will be updated if you just add and then delete an element, because it will call updatedMetadata method in the class above.

So I guess I could just call that by myself.

If I knew how to get to the method of a callback on an AE template installed by a Python Class.

Basically that is the start of the reverse engineering.

Will update once it is properly solved.

Also it doesn’t enable me to set these values with an expression per frame, but that shouldn’t be too tricky to do.

3 Comments »

  1. Hey Sam.

    I do have a solution how the GUI is updated correctely if you are adding attribues:

    c= customShapeAttributes.EXRDriverTranslatorUI(‘aiAOVDriver’)
    c._setActiveNodeAttr(nodeName)
    c.updatedMetadata(nodeName)

    Whithout c._setActiveNodeAttr(nodeName) the self.nodeName variable is not set and because of that the GUI update doesn´t work.

    Hope you still have a use for that. :)

    Comment by Sophia Zauner — July 7, 2017 @ 8:45 pm

  2. Hello Sam,
    That’s an interesting post, thanks for sharing!
    Did you find out more information since the article was written?

    I’m looking for a way to write custom metadatas to my EXR renders, through an expression.
    (the ‘.verticalFilmOffset’, ‘.horizontalFilmOffset’ and ‘.preScale’ attributs of the rendering camera)

    And I need to do it in script, as the scene if fully built in script.
    So I guess that falls right into your case, doesn’t it? :)

    I don’t find much information out there on the subject. I’d be grateful for any help on the subject.

    Thanks a lot,
    Adrien

    Comment by Adrien — August 4, 2017 @ 4:09 am

  3. Hi
    thanks for this .. this saved me a bit of work figuring our how to the metadata.
    Did you find in the meantime a way to update the UI?

    Comment by Tino Nettling — November 9, 2017 @ 8:31 pm

RSS feed for comments on this post. TrackBack URL

Leave a comment

Powered by WordPress