tips,tricks & geekie stuff

Build a camera from EXR metadata

tl;dr: Leveraging the power of the EXR metadata to create an animated Camera Node in Nuke.

When it comes to designing a comp template intended to be used along an entire show as a base-comp (a comp from where to start working on different shots later on), being able to make it the most streamlined possible is of paramount importance. Here is where metadata comes into place.
Like you may already know, an EXR file can store metadata values that can be accessed and used in Nuke to dynamically drive the parameters of virtually any node. Hence, streamlining a so called base-comp implies automatizating certain tasks and ultimately saving time (and money), avoiding human errors.
This being said, here I share with you an example of such a thing: a Python script which is able to create a Camera Node from the Arnold Render specific metadata stored in a EXR file, thus making it unnecesary to export alembic or fbx caches and then saving us one step in the pipeline.

important: for making this work, import the script and call theĀ create_cam() function.

snippet
# local application/library specific imports
import nukescripts
import nuke


def bake_arnold_exr_cam(name, eye):

    try:
        node = nuke.selectedNode()
    except ValueError:
        nuke.message("select a node")
        return

    if node.Class() != "Read":
        nuke.message("you should select an EXR file containing metadata")
        return
    else:
        cam = nuke.createNode('Camera2')
        cam['useMatrix'].setValue(False)
        cam['rot_order'].setValue('XYZ')
        # cam.setName("EXR_right_camera_" + node.name())
        cam.setName("EXR_" + name + "_camera_" + node.name())

        for k in ('focal', 'haperture', 'vaperture', 'translate', 'rotate'):
            cam[k].setAnimated()

        for frame in range(node.firstFrame(), (node.lastFrame()) + 1):
            haperture = node.metadata('exr/g' + eye + '_cameraApertureMmH', frame)
            vaperture = node.metadata('exr/g' + eye + '_cameraApertureMmV', frame)
            focal = node.metadata('exr/g' + eye + '_focalLength', frame)

            transX = node.metadata('exr/g' + eye + '_cameraTranslationX', frame)
            transY = node.metadata('exr/g' + eye + '_cameraTranslationY', frame)
            transZ = node.metadata('exr/g' + eye + '_cameraTranslationZ', frame)

            rotX = node.metadata('exr/g' + eye + '_cameraRotationX', frame)
            rotY = node.metadata('exr/g' + eye + '_cameraRotationY', frame)
            rotZ = node.metadata('exr/g' + eye + '_cameraRotationZ', frame)

            cam['focal'].setValueAt(float(focal), frame)
            cam['haperture'].setValueAt(float(haperture), frame)
            cam['vaperture'].setValueAt(float(vaperture), frame)

            cam['translate'].setValueAt(float(transX), frame, 0)
            cam['translate'].setValueAt(float(transY), frame, 1)
            cam['translate'].setValueAt(float(transZ), frame, 2)
            cam['rotate'].setValueAt(float(rotX), frame, 0)
            cam['rotate'].setValueAt(float(rotY), frame, 1)
            cam['rotate'].setValueAt(float(rotZ), frame, 2)

        return nuke.message( name + " " + "camera" + " " + "created")



class ModalPanel(nukescripts.PythonPanel):
    def __init__(self):
        nukescripts.PythonPanel.__init__(self, title="BAKE YOUR CAM")
        self.menu = nuke.Enumeration_Knob('eye', 'eye:', ['left', 'right'])
        self.addKnob(self.menu)

    def getValue(self):
        return self.menu.getValue()

    def getName(self, n):
        return self.menu.value()


def create_cam():
    panel_instance = ModalPanel()
    if panel_instance.showModalDialog():

        value = int(panel_instance.getValue())
        cam_created = panel_instance.getName(value)

        if value == 0:
            bake_arnold_exr_cam("left", "_L")
            # ok_panel = nuke.message(cam_created + " " + 'camera' + " " + "created")
        elif value == 1:
            bake_arnold_exr_cam("right", "_R")
            # ok_panel = nuke.message(cam_created + " " + 'camera' + " " + "created")   #ok_panel.show()
    else:
        pass
        print("next time")


		
if __name__ == '__main__':
    create_cam()