def sync_collection_instances(self, depsgraph, object_keys_to_export,
                                  material_override):
        """ Export collections instances """
        res = False
        frame_current = depsgraph.scene.frame_current

        for inst in self.depsgraph_instances(depsgraph):
            instance_key = instance.key(inst)
            if instance_key not in object_keys_to_export:
                continue

            inst_obj = self.rpr_context.objects.get(instance_key, None)
            if not inst_obj:
                indirect_only = inst.parent.original.indirect_only_get(
                    view_layer=depsgraph.view_layer)
                instance.sync(self.rpr_context,
                              inst,
                              indirect_only=indirect_only,
                              material_override=material_override,
                              frame_current=frame_current)
            else:
                assign_materials(self.rpr_context,
                                 inst_obj,
                                 inst.object,
                                 material_override=material_override)

            res = True

        return res
    def sync_collection_instances(self, depsgraph, object_keys_to_export,
                                  material_override):
        """ Export collections instances """
        res = False

        for inst in self.depsgraph_instances(depsgraph):
            instance_key = instance.key(inst)
            if instance_key not in object_keys_to_export:
                continue

            if not material_override:
                inst_obj = self.rpr_context.objects.get(instance_key, None)
                if inst_obj:
                    if len(inst.object.material_slots) == 0:
                        # remove override from instance without assigned materials
                        inst_obj.set_material(None)
                    assign_materials(self.rpr_context, inst_obj, inst.object)
                    res = True
            else:
                indirect_only = inst.parent.original.indirect_only_get(
                    view_layer=depsgraph.view_layer)
                instance.sync(self.rpr_context,
                              inst,
                              indirect_only=indirect_only,
                              material_override=material_override)
                res = True
        return res
    def sync_objects_collection(self, depsgraph):
        """
        Removes objects which are not present in depsgraph anymore.
        Adds objects which are not present in rpr_context but existed in depsgraph
        """
        res = False
        view_layer_data = ViewLayerSettings(depsgraph.view_layer)
        material_override = view_layer_data.material_override

        # set of depsgraph object keys
        depsgraph_keys = set.union(
            set(object.key(obj) for obj in self.depsgraph_objects(depsgraph)),
            set(
                instance.key(obj)
                for obj in self.depsgraph_instances(depsgraph)))

        # set of visible rpr object keys
        rpr_object_keys = set(
            key for key, obj in self.rpr_context.objects.items()
            if not isinstance(obj, pyrpr.Shape) or obj.is_visible)

        # sets of objects keys to remove from rpr
        object_keys_to_remove = rpr_object_keys - depsgraph_keys

        # sets of objects keys to export into rpr
        object_keys_to_export = depsgraph_keys - rpr_object_keys

        if object_keys_to_remove:
            log("Object keys to remove", object_keys_to_remove)
            for obj_key in object_keys_to_remove:
                if obj_key in self.rpr_context.objects:
                    self.rpr_context.remove_object(obj_key)
                    res = True

        if object_keys_to_export:
            log("Object keys to add", object_keys_to_export)

            res |= self.sync_collection_objects(depsgraph,
                                                object_keys_to_export,
                                                material_override)

            res |= self.sync_collection_instances(depsgraph,
                                                  object_keys_to_export,
                                                  material_override)

        # update/remove material override on rest of scene object
        if view_layer_data != self.view_layer_data:
            # update/remove material override on all other objects
            self.view_layer_data = view_layer_data
            res = True

            rpr_mesh_keys = set(
                key for key, obj in self.rpr_context.objects.items()
                if isinstance(obj, pyrpr.Mesh) and obj.is_visible)
            unchanged_meshes_keys = tuple(e for e in depsgraph_keys
                                          if e in rpr_mesh_keys)
            log("Object keys to update material override",
                unchanged_meshes_keys)
            self.sync_collection_objects(depsgraph, unchanged_meshes_keys,
                                         material_override)

            rpr_instance_keys = set(
                key for key, obj in self.rpr_context.objects.items()
                if isinstance(obj, pyrpr.Instance) and obj.is_visible)
            unchanged_instances_keys = tuple(e for e in depsgraph_keys
                                             if e in rpr_instance_keys)
            log("Instance keys to update material override",
                unchanged_instances_keys)
            self.sync_collection_instances(depsgraph, unchanged_instances_keys,
                                           material_override)

        return res
    def sync_motion_blur(self, depsgraph: bpy.types.Depsgraph):
        def set_motion_blur(rpr_object, prev_matrix, cur_matrix):
            if hasattr(rpr_object, 'set_motion_transform'):
                rpr_object.set_motion_transform(
                    np.array(prev_matrix, dtype=np.float32).reshape(4, 4))
            else:
                velocity = (prev_matrix - cur_matrix).to_translation()
                rpr_object.set_linear_motion(*velocity)

                mul_diff = prev_matrix @ cur_matrix.inverted()

                quaternion = mul_diff.to_quaternion()
                if quaternion.axis.length > 0.5:
                    rpr_object.set_angular_motion(*quaternion.axis,
                                                  quaternion.angle)
                else:
                    rpr_object.set_angular_motion(1.0, 0.0, 0.0, 0.0)

                if not isinstance(rpr_object, pyrpr.Camera):
                    scale_motion = mul_diff.to_scale() - mathutils.Vector(
                        (1, 1, 1))
                    rpr_object.set_scale_motion(*scale_motion)

        cur_matrices = {}

        # getting current frame matrices
        for obj in self.depsgraph_objects(depsgraph, with_camera=True):
            if not obj.rpr.motion_blur:
                continue

            key = object.key(obj)
            rpr_object = self.rpr_context.objects.get(key, None)
            if not rpr_object or not isinstance(
                    rpr_object, (pyrpr.Shape, pyrpr.AreaLight, pyrpr.Camera)):
                continue

            cur_matrices[key] = obj.matrix_world.copy()

        for inst in self.depsgraph_instances(depsgraph):
            if not inst.parent.rpr.motion_blur:
                continue

            key = instance.key(inst)
            rpr_object = self.rpr_context.objects.get(key, None)
            if not rpr_object or not isinstance(
                    rpr_object, (pyrpr.Shape, pyrpr.AreaLight)):
                continue

            cur_matrices[key] = inst.matrix_world.copy()

        if not cur_matrices:
            return

        cur_frame = depsgraph.scene.frame_current
        prev_frame = cur_frame - 1

        # set to previous frame and calculate motion blur data
        self._set_scene_frame(depsgraph.scene, prev_frame, 0.0)
        try:
            for obj in self.depsgraph_objects(depsgraph, with_camera=True):
                key = object.key(obj)
                cur_matrix = cur_matrices.get(key, None)
                if cur_matrix is None:
                    continue

                set_motion_blur(self.rpr_context.objects[key],
                                obj.matrix_world, cur_matrix)

            for inst in self.depsgraph_instances(depsgraph):
                key = instance.key(inst)
                cur_matrix = cur_matrices.get(key, None)
                if cur_matrix is None:
                    continue

                set_motion_blur(self.rpr_context.objects[key],
                                inst.matrix_world, cur_matrix)

        finally:
            # restore current frame
            self._set_scene_frame(depsgraph.scene, cur_frame, 0.0)