Skip to content
Snippets Groups Projects
import_nuke_chan.py 4.84 KiB
Newer Older
# ##### BEGIN GPL LICENSE BLOCK #####
#
#  This program is free software; you can redistribute it and/or
#  modify it under the terms of the GNU General Public License
#  as published by the Free Software Foundation; either version 2
#  of the License, or (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software Foundation,
#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####

""" This script is an importer for the nuke's .chan files"""

from mathutils import Vector, Matrix, Euler
from math import radians, tan


def read_chan(context, filepath, z_up, rot_ord):

    # get the active object
    scene = context.scene
    obj = context.active_object

    # get the resolution (needed to calculate the camera lens)
    res_x = scene.render.resolution_x
    res_y = scene.render.resolution_y
    res_ratio = res_y / res_x

    # prepare the correcting matrix
    rot_mat = Matrix.Rotation(radians(90.0), 4, 'X').to_4x4()

    # read the file
    filehandle = open(filepath, 'r')

    # iterate throug the files lines
    for line in filehandle:
        # reset the target objects matrix
        # (the one from whitch one we'll extract the final transforms)
        m_trans_mat = Matrix()

        # strip the line
        data = line.split()

        # test if the line is not commented out
        if data and not data[0].startswith("#"):

            # set the frame number basing on the chan file
            scene.frame_set(int(data[0]))

            # read the translation values from the first three columns of line
            v_transl = Vector((float(data[1]),
                               float(data[2]),
                               float(data[3])))
            translation_mat = Matrix.Translation(v_transl)
            translation_mat.to_4x4()

            # read the rotations, and set the rotation order basing on the order
            # set during the export (it's not being saved in the chan file
            # you have to keep it noted somewhere
            # the actual objects rotation order doesn't matter since the
            # rotations are being extracted from the matrix afterwards
            e_rot = Euler((radians(float(data[4])),
                           radians(float(data[5])),
                           radians(float(data[6]))))
            e_rot.order = rot_ord
            mrot_mat = e_rot.to_matrix()
            mrot_mat.resize_4x4()

            # merge the rotation and translation
            m_trans_mat = translation_mat * mrot_mat

            # correct the world space
            # (nuke's and blenders scene spaces are different)
            if z_up:
                m_trans_mat = rot_mat * m_trans_mat

            # break the matrix into a set of the coordinates
            trns = m_trans_mat.decompose()

            # set the location and the location's keyframe
            obj.location = trns[0]
            obj.keyframe_insert("location")

            # convert the rotation to euler angles (or not)
            # basing on the objects rotation mode
            if obj.rotation_mode == 'QUATERNION':
                obj.rotation_quaternion = trns[1]
                obj.keyframe_insert("rotation_quaternion")
            elif obj.rotation_mode == 'AXIS_ANGLE':
                tmp_rot = trns[1].to_axis_angle()
                obj.rotation_axis_angle = (tmp_rot[1], ) + tmp_rot[0][:]
                obj.keyframe_insert("rotation_axis_angle")
                del tmp_rot
            else:
                obj.rotation_euler = trns[1].to_euler(obj.rotation_mode)
                obj.keyframe_insert("rotation_euler")


            # check if the object is camera and fov data is present
            if obj.type == 'CAMERA' and len(data) > 7:
                v_fov = float(data[7])
                sensor_x = 0
                sensor_y = 0
                if hasattr(obj.data, "sensor_width"):  # Preserve compatibility
                    if obj.data.sensor_fit == 'VERTICAL':
                        sensor_x = obj.data.sensor_width
                        sensor_y = obj.data.sensor_height
                    else:
                        sensor_x = obj.data.sensor_width
                        sensor_y = sensor_x * res_ratio
                else:
                    sensor_x = 32  # standard blender's sensor size
                    sensor_y = sensor_x * res_ratio
                lenslen = ((sensor_y / 2.0) / tan(radians(v_fov / 2.0)))
                obj.data.lens = lenslen
                obj.data.keyframe_insert("lens")
    filehandle.close()

    return {'FINISHED'}