def get_3x4_RT_matrix_from_blender(cam):

    from mathutils import Matrix  #Todo: additional dependency! not listed in readme
    # bcam stands for blender camera
    R_bcam2cv = Matrix(((1, 0, 0), (0, -1, 0), (0, 0, -1)))

    # Transpose since the rotation is object rotation,
    # and we want coordinate rotation
    # R_world2bcam = cam.rotation_euler.to_matrix().transposed()
    # T_world2bcam = -1*R_world2bcam * location
    #
    # Use matrix_world instead to account for all constraints
    cam = Matrix(cam)
    location, rotation = cam.decompose()[0:2]
    R_world2bcam = rotation.to_matrix().transposed()

    # Convert camera location to translation vector used in coordinate changes
    # T_world2bcam = -1*R_world2bcam*cam.location
    # Use location from matrix_world to account for constraints:
    T_world2bcam = -1 * np.dot(R_world2bcam, location)

    # Build the coordinate transform matrix from world to computer vision camera
    R_world2cv = np.dot(R_bcam2cv, R_world2bcam)
    T_world2cv = np.dot(R_bcam2cv, T_world2bcam)

    # put into 3x4 matrix
    RT = np.concatenate(
        (np.array(R_world2cv), np.array(T_world2cv).reshape(3, 1)), axis=1)

    return RT
    def matrix(mat_input):
        mat_input =  Matrix([mat_input[0:4], mat_input[4:8], mat_input[8:12], mat_input[12:16]])
        mat_input.transpose()

        # Use decompose() here since to_quaternion() for some reasons return a different result for rotation in the tricky case of a negative scale
        location, rotation, scale = mat_input.decompose()
        return Conversion.matrix_from_trs(Conversion.location(location), Conversion.matrix_quaternion(rotation), Conversion.scale(scale))
Beispiel #3
0
    def load_world_node(self, node):
        content_manager = ContentManager()
        node_path = node['m_worldNodePrefix'] + '.vwnod_c'
        full_node_path = content_manager.find_file(node_path)
        world_node_file = ValveCompiledFile(full_node_path)
        world_node_file.read_block_info()
        world_node_file.check_external_resources()
        world_data: DataBlock = world_node_file.get_data_block(
            block_name="DATA")[0]
        collection = get_or_create_collection(
            f"static_props_{Path(node_path).stem}", self.master_collection)
        for n, static_object in enumerate(world_data.data['m_sceneObjects']):
            model_path = static_object['m_renderableModel']
            proper_path = world_node_file.available_resources.get(model_path)
            self.logger.info(
                f"Loading ({n}/{len(world_data.data['m_sceneObjects'])}){model_path} mesh"
            )
            mat_rows: List = static_object['m_vTransform']
            transform_mat = Matrix(
                [mat_rows[0], mat_rows[1], mat_rows[2], [0, 0, 0, 1]])
            loc, rot, sca = transform_mat.decompose()
            custom_data = {
                'prop_path': str(proper_path),
                'type': 'static_prop',
                'scale': self.scale,
                'entity': static_object,
                'skin': static_object.get('skin', 'default') or 'default'
            }

            self.create_empty(proper_path.stem,
                              loc,
                              rot.to_euler(),
                              sca,
                              parent_collection=collection,
                              custom_data=custom_data)
Beispiel #4
0
def get_keyframes(armature):
    '''Get each bone location and rotation for each frame.'''
    location_list = []
    rotation_list = []

    for frame in range(bpy.context.scene.frame_start,
                       bpy.context.scene.frame_end + 1):
        bpy.context.scene.frame_set(frame)

        locations = {}
        rotations = {}

        for bone in armature.pose.bones:
            bone_matrix = transform_animation_matrix(bone.matrix)
            if bone.parent and bone.parent.parent:
                parent_matrix = transform_animation_matrix(bone.parent.matrix)
                bone_matrix = parent_matrix.inverted() * bone_matrix
            elif not bone.parent:
                bone_matrix = Matrix()

            loc, rot, scl = bone_matrix.decompose()

            locations[bone.name] = loc
            rotations[bone.name] = rot.to_euler()

        location_list.append(locations.copy())
        rotation_list.append(rotations.copy())

        del locations
        del rotations

    bcPrint("Keyframes have been appended to lists.")

    return location_list, rotation_list
Beispiel #5
0
    def draw_decomposed_matrix(self, label: str, matrix: Matrix) -> None:
        (trans, rot, scale) = matrix.decompose()

        col = self.layout.column(align=False)
        col.label(text=label)

        def nicenum(num: float) -> str:
            if abs(num) < 1e-3:
                return "-"
            return f"{num:.3f}"

        def nicescale(num: float) -> str:
            if abs(1.0 - num) < 1e-3:
                return "-"
            return f"{num:.3f}"

        grid = col.grid_flow(row_major=True, columns=4, align=True)
        grid.label(text="T")
        grid.label(text=nicenum(trans.x))
        grid.label(text=nicenum(trans.y))
        grid.label(text=nicenum(trans.z))
        grid.label(text="R")
        grid.label(text=nicenum(rot.x))
        grid.label(text=nicenum(rot.y))
        grid.label(text=nicenum(rot.z))
        grid.label(text="S")
        grid.label(text=nicescale(scale.x))
        grid.label(text=nicescale(scale.y))
        grid.label(text=nicescale(scale.z))
Beispiel #6
0
def swap_coordinate_system(matrix_world: mathutils.Matrix,
                           mesh: Union[bpy.types.Mesh, bmesh.types.BMesh],
                           is_swap: bool) -> None:
    swap_mat = mathutils.Matrix.Identity(4)

    if is_swap:
        swap_mat[0][0], swap_mat[0][1], swap_mat[0][2], swap_mat[0][
            3] = 1, 0, 0, 0
        swap_mat[1][0], swap_mat[1][1], swap_mat[1][2], swap_mat[1][
            3] = 0, 0, 1, 0
        swap_mat[2][0], swap_mat[2][1], swap_mat[2][2], swap_mat[2][
            3] = 0, 1, 0, 0
        swap_mat[3][0], swap_mat[3][1], swap_mat[3][2], swap_mat[3][
            3] = 0, 0, 0, 1

    trans, rot, scale = matrix_world.decompose()

    if type(mesh) is bpy.types.Mesh:
        for vertex in mesh.vertices:
            vertex.co = swap_mat * matrix_world * vertex.co
            vertex.normal = (
                swap_mat * matrix_world).to_3x3().normalized() * vertex.normal

        if is_swap:
            mesh.flip_normals()

    if type(mesh) is bmesh.types.BMesh:
        for vertex in mesh.verts:
            vertex.co = swap_mat * matrix_world * vertex.co
            vertex.normal = (
                swap_mat * matrix_world).to_3x3().normalized() * vertex.normal

        if is_swap:
            for face in mesh.faces:
                face.normal_flip()
Beispiel #7
0
def baby_from_blender(mat: Matrix) -> Matrix:
    t, qr, s = mat.decompose()
    out = (
        Matrix.Translation(swizzle_yup_location(t) * Vector([-1, 1, 1])) @  #
        swizzle_yup_rotation(qr).to_matrix().to_4x4() @  #
        any_scale(swizzle_yup_scale(s)))
    out.transpose()
    return out
Beispiel #8
0
def getTranslationOrientation(ob, file):
	if isinstance(ob, bpy.types.Bone):
		
		ob_matrix_local = ob.matrix_local.copy()
		ob_matrix_local.transpose()
		t = ob_matrix_local
		ob_matrix_local = Matrix([[-t[2][0], -t[2][1], -t[2][2], -t[2][3]],
								[t[1][0], t[1][1], t[1][2], t[1][3]],
								[t[0][0], t[0][1], t[0][2], t[0][3]],
								[t[3][0], t[3][1], t[3][2], t[3][3]]])
								
		rotMatrix_z90_4x4 = Matrix.Rotation(math.radians(90.0), 4, 'Z')
		rotMatrix_z90_4x4.transpose()
		
		file.write('Name:%s\n' % ob.name)

		t = rotMatrix_z90_4x4 * ob_matrix_local
		matrix = Matrix([[t[0][0], t[0][1], t[0][2], t[0][3]],
								[t[1][0], t[1][1], t[1][2], t[1][3]],
								[t[2][0], t[2][1], t[2][2], t[2][3]],
								[t[3][0], t[3][1], t[3][2], t[3][3]]])
								
		parent = ob.parent
		if parent:
			parent_matrix_local = parent.matrix_local.copy()
			parent_matrix_local.transpose()
			t = parent_matrix_local
			parent_matrix_local = Matrix([[-t[2][0], -t[2][1], -t[2][2], -t[2][3]],
									[t[1][0], t[1][1], t[1][2], t[1][3]],
									[t[0][0], t[0][1], t[0][2], t[0][3]],
									[t[3][0], t[3][1], t[3][2], t[3][3]]])
			par_matrix = rotMatrix_z90_4x4 * parent_matrix_local
			par_matrix_cpy = par_matrix.copy()
			par_matrix_cpy.invert()
			matrix = matrix * par_matrix_cpy

		matrix.transpose()
		loc, rot, sca = matrix.decompose()
	else:
		matrix = ob.matrix_world
		if matrix:
			loc, rot, sca = matrix.decompose()
		else:
			raise "error: this should never happen!"
	return loc, rot
Beispiel #9
0
def getTranslationOrientation(ob):
    if isinstance(ob, bpy.types.Bone):

        ob_matrix_local = ob.matrix_local.copy()
        ob_matrix_local.transpose()
        t = ob_matrix_local
        ob_matrix_local = Matrix([[-t[2][0], -t[2][1], -t[2][2], -t[2][3]],
                                  [t[1][0], t[1][1], t[1][2], t[1][3]],
                                  [t[0][0], t[0][1], t[0][2], t[0][3]],
                                  [t[3][0], t[3][1], t[3][2], t[3][3]]])

        rotMatrix_z90_4x4 = Matrix.Rotation(math.radians(90.0), 4, 'Z')
        rotMatrix_z90_4x4.transpose()

        t = rotMatrix_z90_4x4 * ob_matrix_local
        matrix = Matrix([[t[0][0], t[0][1], t[0][2], t[0][3]],
                         [t[1][0], t[1][1], t[1][2], t[1][3]],
                         [t[2][0], t[2][1], t[2][2], t[2][3]],
                         [t[3][0], t[3][1], t[3][2], t[3][3]]])

        parent = ob.parent
        if parent:
            parent_matrix_local = parent.matrix_local.copy()
            parent_matrix_local.transpose()
            t = parent_matrix_local
            parent_matrix_local = Matrix(
                [[-t[2][0], -t[2][1], -t[2][2], -t[2][3]],
                 [t[1][0], t[1][1], t[1][2], t[1][3]],
                 [t[0][0], t[0][1], t[0][2], t[0][3]],
                 [t[3][0], t[3][1], t[3][2], t[3][3]]])
            par_matrix = rotMatrix_z90_4x4 * parent_matrix_local
            par_matrix_cpy = par_matrix.copy()
            par_matrix_cpy.invert()
            matrix = matrix * par_matrix_cpy

        matrix.transpose()
        loc, rot, sca = matrix.decompose()
    else:
        matrix = ob.matrix_world
        if matrix:
            loc, rot, sca = matrix.decompose()
        else:
            raise "error: this should never happen!"
    return loc, rot
Beispiel #10
0
def get_trs(node):
    if 'matrix' in node:
        m = node['matrix']
        # column-major to row-major
        m = Matrix([m[0:4], m[4:8], m[8:12], m[12:16]])
        m.transpose()
        (loc, rot, sca) = m.decompose()
    else:
        sca = node.get('scale', [1.0, 1.0, 1.0])
        rot = node.get('rotation', [0.0, 0.0, 0.0, 1.0])
        rot = [rot[3], rot[0], rot[1], rot[2]]  # xyzw -> wxyz
        loc = node.get('translation', [0.0, 0.0, 0.0])

    # Switch glTF coordinates to Blender coordinates
    sca = [sca[0], sca[2], sca[1]]
    rot = [rot[0], rot[1], -rot[3], rot[2]]
    loc = [loc[0], -loc[2], loc[1]]

    return (Vector(loc), Quaternion(rot), Vector(sca))
    def draw_decomposed_matrix(self, label: str, matrix: Matrix) -> None:
        (trans, rot, scale) = matrix.decompose()

        col = self.layout.column(align=False)
        col.label(text=label)

        grid = col.grid_flow(row_major=True, columns=4, align=True)
        grid.label(text="T")
        grid.label(text=self.nicenum(trans.x))
        grid.label(text=self.nicenum(trans.y))
        grid.label(text=self.nicenum(trans.z))
        grid.label(text="R")
        grid.label(text=self.nicenum(rot.x))
        grid.label(text=self.nicenum(rot.y))
        grid.label(text=self.nicenum(rot.z))
        grid.label(text="S")
        grid.label(text=self.nicescale(scale.x))
        grid.label(text=self.nicescale(scale.y))
        grid.label(text=self.nicescale(scale.z))
    def assignFrame(self, armature, frameNum, excludeFingers):
        # this is REQUIRED to get something to actually get recorded other than just before assignment
        bpy.context.scene.update()
        
        for name in KINECT_BONES:
            if excludeFingers and self.isFinger(name): continue
            if name not in armature.data.bones: continue

            bone = armature.pose.bones[name]

            objectSpace = bone.matrix
            localSpace = Matrix(armature.convert_space(bone, objectSpace, 'POSE', 'LOCAL'))
            loc, rot, scale = localSpace.decompose()

            if name == ROOT_BONE:
                bone.location = self.relativeRootLoc(frameNum)
                bone.keyframe_insert('location', frame = frameNum, group = name)

            bone.rotation_quaternion = rot
            bone.keyframe_insert('rotation_quaternion', frame = frameNum, group = name)
Beispiel #13
0
def get_node_trs(op, node):
    """Gets the TRS proerties from a glTF node JSON object."""
    if 'matrix' in node:
        m = node['matrix']
        # column-major to row-major
        m = Matrix([m[0:4], m[4:8], m[8:12], m[12:16]])
        m.transpose()
        loc, rot, sca = m.decompose()
        # wxyz -> xyzw
        # convert_rotation will switch back
        rot = [rot[1], rot[2], rot[3], rot[0]]

    else:
        sca = node.get('scale', [1.0, 1.0, 1.0])
        rot = node.get('rotation', [0.0, 0.0, 0.0, 1.0])
        loc = node.get('translation', [0.0, 0.0, 0.0])

    # Switch glTF coordinates to Blender coordinates
    sca = op.convert_scale(sca)
    rot = op.convert_rotation(rot)
    loc = op.convert_translation(loc)

    return [Vector(loc), Quaternion(rot), Vector(sca)]
Beispiel #14
0
    def assignFrame(self, armature, frameNum, excludeFingers):
        # this is REQUIRED to get something to actually get recorded other than just before assignment
        bpy.context.scene.update()

        for name in KINECT_BONES:
            if excludeFingers and self.isFinger(name): continue
            if name not in armature.data.bones: continue

            bone = armature.pose.bones[name]

            objectSpace = bone.matrix
            localSpace = Matrix(
                armature.convert_space(bone, objectSpace, 'POSE', 'LOCAL'))
            loc, rot, scale = localSpace.decompose()

            if name == ROOT_BONE:
                bone.location = self.relativeRootLoc(frameNum)
                bone.keyframe_insert('location', frame=frameNum, group=name)

            bone.rotation_quaternion = rot
            bone.keyframe_insert('rotation_quaternion',
                                 frame=frameNum,
                                 group=name)
Beispiel #15
0
def se3_get_skeleton_from_file(operator, context):
    filepath = operator.filepath

    current_bone = ""

    bone_data = OrderedDict()

    is_in_limits = False
    is_in_pose = False

    with open(filepath, "r") as file:
        for line in file:
            if "SE_SKELETON" in line or "BONES" in line:
                continue

            if "NAME" in line:
                name = line
                name = name.replace('NAME ', "")
                name = name.replace('"', "")
                current_bone = sanitize_name(name)
                bone_data[current_bone] = {
                    "name": current_bone,
                    "parent": "",
                    "root_bone": False,
                    "matrix": [],
                    "length": 0.0
                }

            if "PARENT" in line:
                parent = line
                parent = parent.replace('PARENT ', "")
                parent = parent.replace('"', "")
                parent = sanitize_name(parent)
                if parent is "":
                    bone_data[current_bone]["root_bone"] = True
                    continue
                else:
                    bone_data[current_bone]["parent"] = parent

            if "LENGTH" in line:
                length = line
                length = length.replace("LENGTH ", "")
                length = length.replace('"', "")
                length = sanitize_name(length)
                bone_data[current_bone]["length"] = float(length)

            if "LIMITS" in line:
                is_in_limits = True
                continue

            if is_in_limits and "DEFAULT_POSE" not in line:
                continue

            if "DEFAULT_POSE" in line:
                is_in_limits = False
                is_in_pose = True
                continue

            if is_in_pose and "}" not in line:
                matrix = line
                bone_data[current_bone]["matrix"] = gen_matrix(matrix)

            if is_in_pose and "}" in line:
                is_in_pose = False
                continue

    armature_da = bpy.data.armatures.new("Armature")
    armature_ob = bpy.data.objects.new("Armature", armature_da)
    armature_ob.show_x_ray = True

    bpy.context.scene.objects.link(armature_ob)

    bpy.context.scene.objects.active = armature_ob
    bpy.ops.object.mode_set(mode='EDIT')

    ob = bpy.context.object

    for name, bone in bone_data.items():
        print(name)
        if bone["root_bone"]:
            m = Matrix()
            constraints = bone["matrix"]
            m[0][0:2] = -constraints[0], constraints[2], -constraints[1]
            m[1][0:2] = constraints[8], -constraints[10], constraints[9]
            m[2][0:2] = constraints[4], -constraints[6], constraints[5]

            v = Vector((-constraints[3], constraints[11], constraints[7]))
        else:
            m = Matrix()
            constraints = bone["matrix"]
            m[0][0:2] = constraints[0], -constraints[2], constraints[1]
            m[1][0:2] = -constraints[8], constraints[10], -constraints[9]
            m[2][0:2] = constraints[4], -constraints[6], constraints[5]

            v = Vector(
                (constraints[3],
                 -(constraints[11] - bone_data[bone["parent"]]["length"]),
                 constraints[7]))

        edit_bone = armature_ob.data.edit_bones.new(bone["name"])
        edit_bone.matrix = m

        print(m.decompose())
        print(v)
        print("-------------------")

        edit_bone.head = v
        edit_bone.length = bone["length"]

        if not bone["root_bone"]:
            edit_bone.parent = armature_ob.data.edit_bones[bone["parent"]]

    return {"FINISHED"}
Beispiel #16
0
def read_chan(context, filepath, z_up, rot_ord, sensor_width, sensor_height):

    # get the active object
    scene = context.scene
    obj = context.active_object
    camera = obj.data if obj.type == 'CAMERA' else None

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

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

    # iterate through the files lines
    for line in filehandle:
        # reset the target objects matrix
        # (the one from which 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 camera and len(data) > 7:
                camera.sensor_fit = 'HORIZONTAL'
                camera.sensor_width = sensor_width
                camera.sensor_height = sensor_height
                camera.angle_y = radians(float(data[7]))
                camera.keyframe_insert("lens")
    filehandle.close()

    return {'FINISHED'}
    def add_neutral_bones(self):
        for n in [
                n for n in self.nodes.values()
                if n.armature is not None and n.blender_type == VExportNode.
                OBJECT and hasattr(self.nodes[n.armature], "need_neutral_bone")
        ]:  #all skin meshes objects where neutral bone is needed
            # First add a new node

            axis_basis_change = Matrix.Identity(4)
            if self.export_settings[gltf2_blender_export_keys.YUP]:
                axis_basis_change = Matrix(
                    ((1.0, 0.0, 0.0, 0.0), (0.0, 0.0, 1.0, 0.0),
                     (0.0, -1.0, 0.0, 0.0), (0.0, 0.0, 0.0, 1.0)))

            trans, rot, sca = axis_basis_change.decompose()
            translation, rotation, scale = (None, None, None)
            if trans[0] != 0.0 or trans[1] != 0.0 or trans[2] != 0.0:
                translation = [trans[0], trans[1], trans[2]]
            if rot[0] != 1.0 or rot[1] != 0.0 or rot[2] != 0.0 or rot[3] != 0.0:
                rotation = [rot[1], rot[2], rot[3], rot[0]]
            if sca[0] != 1.0 or sca[1] != 1.0 or sca[2] != 1.0:
                scale = [sca[0], sca[1], sca[2]]
            neutral_bone = gltf2_io.Node(camera=None,
                                         children=None,
                                         extensions=None,
                                         extras=None,
                                         matrix=None,
                                         mesh=None,
                                         name='neutral_bone',
                                         rotation=rotation,
                                         scale=scale,
                                         skin=None,
                                         translation=translation,
                                         weights=None)
            # Add it to child list of armature
            self.nodes[n.armature].node.children.append(neutral_bone)
            # Add it to joint list
            n.node.skin.joints.append(neutral_bone)

            # Need to add an InverseBindMatrix
            array = BinaryData.decode_accessor_internal(
                n.node.skin.inverse_bind_matrices)

            axis_basis_change = Matrix.Identity(4)
            if self.export_settings[gltf2_blender_export_keys.YUP]:
                axis_basis_change = Matrix(
                    ((1.0, 0.0, 0.0, 0.0), (0.0, 0.0, 1.0, 0.0),
                     (0.0, -1.0, 0.0, 0.0), (0.0, 0.0, 0.0, 1.0)))

            inverse_bind_matrix = (axis_basis_change @ self.nodes[
                n.armature].matrix_world_armature).inverted_safe()

            matrix = []
            for column in range(0, 4):
                for row in range(0, 4):
                    matrix.append(inverse_bind_matrix[row][column])

            array = np.append(array, np.array([matrix]), axis=0)
            binary_data = gltf2_io_binary_data.BinaryData.from_list(
                array.flatten(), gltf2_io_constants.ComponentType.Float)
            n.node.skin.inverse_bind_matrices = gltf2_blender_gather_accessors.gather_accessor(
                binary_data, gltf2_io_constants.ComponentType.Float,
                len(array.flatten()) //
                gltf2_io_constants.DataType.num_elements(
                    gltf2_io_constants.DataType.Mat4), None, None,
                gltf2_io_constants.DataType.Mat4, self.export_settings)
def create_skeleton(PDX_bone_list):
    # keep track of bones as we create them
    bone_list = [None for _ in range(0, len(PDX_bone_list))]

    # check this skeleton is not already built in the scene
    matching_rigs = [
        get_rig_from_bone_name(clean_imported_name(bone.name))
        for bone in PDX_bone_list
    ]
    matching_rigs = list(set(rig for rig in matching_rigs if rig))
    if len(matching_rigs) == 1:
        return matching_rigs[0]

    # temporary name used during creation
    tmp_rig_name = 'io_pdx_rig'

    # create the armature datablock
    armt = bpy.data.armatures.new('armature')
    armt.name = 'imported_armature'
    armt.draw_type = 'STICK'

    # create the object and link to the scene
    new_rig = bpy.data.objects.new(tmp_rig_name, armt)
    bpy.context.scene.objects.link(new_rig)
    bpy.context.scene.objects.active = new_rig
    new_rig.show_x_ray = True
    new_rig.select = True

    bpy.ops.object.mode_set(mode='EDIT')
    for bone in PDX_bone_list:
        index = bone.ix[0]
        transform = bone.tx
        parent = getattr(bone, 'pa', None)

        # determine unique bone name
        # Maya allows non-unique transform names (on leaf nodes) and handles it internally by using | separators
        unique_name = clean_imported_name(bone.name)

        # create joint
        new_bone = armt.edit_bones.new(name=unique_name)
        new_bone.select = True
        bone_list[index] = new_bone

        # connect to parent
        if parent is not None:
            parent_bone = bone_list[parent[0]]
            new_bone.parent = parent_bone
            new_bone.use_connect = False

        # determine bone head transform
        mat = Matrix(
            ((transform[0], transform[3], transform[6], transform[9]),
             (transform[1], transform[4], transform[7],
              transform[10]), (transform[2], transform[5], transform[8],
                               transform[11]), (0.0, 0.0, 0.0, 1.0)))
        # rescale or recompose matrix so we always import bones at 1.0 scale
        loc, rot, scale = mat.decompose()
        try:
            safemat = Matrix.Scale(1.0 / scale[0], 4) * mat
        except ZeroDivisionError:  # guard against zero scale bones...
            safemat = Matrix.Translation(
                loc) * rot.to_matrix().to_4x4() * Matrix.Scale(1.0, 4)

        # determine avg distance to any children
        bone_children = [
            b for b in PDX_bone_list if getattr(b, 'pa', [None]) == bone.ix
        ]
        bone_dists = []
        for child in bone_children:
            child_transform = child.tx
            c_mat = Matrix(
                ((child_transform[0], child_transform[3], child_transform[6],
                  child_transform[9]),
                 (child_transform[1], child_transform[4], child_transform[7],
                  child_transform[10]),
                 (child_transform[2], child_transform[5], child_transform[8],
                  child_transform[11]), (0.0, 0.0, 0.0, 1.0)))
            c_dist = c_mat.to_translation() - safemat.to_translation()
            bone_dists.append(
                math.sqrt(c_dist.x**2 + c_dist.y**2 + c_dist.z**2))

        avg_dist = 5.0
        if bone_children:
            avg_dist = sum(bone_dists) / len(bone_dists)
        avg_dist = min(max(1.0, avg_dist), 10.0)

        # set bone tail offset first
        new_bone.tail = Vector((0.0, 0.0, 0.1 * avg_dist))
        # set matrix directly as this includes bone roll/rotation
        new_bone.matrix = swap_coord_space(
            safemat.inverted_safe())  # convert to Blender space

    # set or correct some bone settings based on hierarchy
    for bone in bone_list:
        # Blender culls zero length bones, nudge the tail to ensure we don't create any
        if bone.length == 0:
            # FIXME: is this safe? this would affect bone rotation
            bone.tail += Vector((0, 0, 0.1))

    bpy.ops.object.mode_set(mode='OBJECT')
    bpy.context.scene.update()

    return new_rig
Beispiel #19
0
def iterate_object(export_context: ExportContext, export_dir, out_objects, object: bpy.types.Object, transform: mathutils.Matrix):
    transform = transform @ object.matrix_basis

    t, r, s = transform.decompose()
    transform_attributes = {
        "position": [t.x, t.y, t.z],
        "rotation": [r.x, r.y, r.z, r.w],
        "scale": [s.x, s.y, s.z]
    }

    object_attributes = {
        "transform": transform_attributes,
    }

    light_kind_names = {
        "POINT": "Point",
        "SUN": "Directional",
        "SPOT": "Spot",
    }
    
    if object.type == 'LIGHT':
        print("LIGHT")
        print(object.data)
        light = object.data
        kind = light_kind_names.get(light.type)
        if not kind:
            #unsupported
            print("unsupported light type " + light.type)
        else:
            c = light.color
            object_attributes["light"] = {
                "color": [c.r, c.g, c.b],
                "kind": light_kind_names[light.type],
                "intensity": light.energy,
                "cutoff_distance": light.cutoff_distance if light.use_custom_distance else -1.0,
            }

            if light.type == "SPOT":
                outer_angle = light.spot_size * 0.5
                inner_angle = outer_angle - outer_angle * light.spot_blend
                object_attributes["light"]["spot"] = {
                    "outer_angle": outer_angle,
                    "inner_angle": inner_angle
                }

    
    if object.instance_collection:
        library = object.instance_collection.library
        if not library:
            raise rafx_errors.RafxPrefabSceneUnsupportedObject("Collection instance {} must be linked from external file".format(object.instance_collection))

        # HACK HACK HACK: Assume that the blender file only contains one model, and its scene name matches the filename.
        # The alternative is linking the blend file, iterating over all scenes and trying to find the one that contains
        # the given collection. do_export_external_model does this
        library_export_path = rafx_blender_paths.find_base_export_path_for_data_block(export_context.project_settings, object.instance_collection)
        library_path = bpy.path.abspath(library.filepath)
        library_name = os.path.basename(library_path)
        model_name, ext = os.path.splitext(library_name)
        model_name = "{}.blender_model".format(model_name)
        f = os.path.join(library_export_path, model_name)
        collection_export_path = rafx_blender_paths.make_cross_platform_relative_path(f, export_dir)        
        object_attributes["model"] = {
            "model": collection_export_path
        }
    
    if object.type == 'MESH':
        if export_context.export_properties.enable_mesh_export:
            export_mesh.export(export_context, object)
        if export_context.export_properties.enable_model_export:
            export_model.export_model_for_mesh_object(export_context, object)
        model_path = rafx_blender_paths.find_export_path_for_blender_data_block_with_extension(export_context.project_settings, object, "blender_model")
        model_path = rafx_blender_paths.make_cross_platform_relative_path(model_path, export_dir)
        object_attributes["model"] = {
            "model": model_path
        }

    out_objects.append(object_attributes)
def transform_matrix_blender_to_gmd(matrix: Matrix) -> Matrix:
    pos, rot, scale = matrix.decompose()
    pos, rot, scale = transform_blender_to_gmd(pos, rot, scale)
    return transform_to_matrix(pos, rot, scale)
def read_chan(context, filepath, z_up, rot_ord, sensor_width, sensor_height):

    # get the active object
    scene = context.scene
    obj = context.active_object
    camera = obj.data if obj.type == 'CAMERA' else None

    # 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 camera and len(data) > 7:
                camera.sensor_fit = 'HORIZONTAL'
                camera.sensor_width = sensor_width
                camera.sensor_height = sensor_height
                camera.angle_y = radians(float(data[7]))
                camera.keyframe_insert("lens")
    filehandle.close()

    return {'FINISHED'}