def read_config(self, text=True):
        self.ini_file = self.Config_LE.text()
        if not os.path.exists(self.ini_file):
            toast(u"配置路径不存在")
            self.Config_LE.setText("")
            return

        # print(self.ini_file)

        self.config = ConfigParser() if six.PY2 else ConfigParser(strict=False)
        self.config.read(self.ini_file)

        section = "MovieSceneCaptureUIInstance AutomatedLevelSequenceCapture"
        option = "Settings"
        try:
            capture_settings = self.config.get(section, option)
        except:
            return
        capture_settings_dict = self.json_config[section][option]
        capture_settings = capture_settings[1:-1]
        pattern = re.compile("\((.+?)\)")
        value_list = []
        for i, match in enumerate(pattern.findall(capture_settings)):
            capture_settings = capture_settings.replace(match, "$$%s$$" % i)
            value_list.append(match)

        # NOTE 设置
        for pair in capture_settings.split(","):
            k, v = pair.split("=")
            v = value_list[int(v[3])] if v.startswith("($$") else v
            k = capture_settings_dict.get(k)
            if not k:
                continue
            elif k == "output_directory":
                self.Output_LE.setText(v[6:-1].replace("\\\\", "\\")) if text else None
            elif text and k == "output_format":
                self.FileName_LE.setText(v[1:-1]) if text else None
            elif k == "game_mode_override":
                if v == "None":
                    continue
                v = v.split('"')[1]
                v = unreal.load_class(None, v)
                self.capture_settings.set_editor_property(k, v)
            elif k == "custom_frame_rate":
                numerator, denominator = v.split(",")
                numerator = numerator.split("=")[1]
                denominator = denominator.split("=")[1]
                v = unreal.FrameRate(int(numerator), int(denominator))
                self.capture_settings.set_editor_property(k, v)
            elif k == "resolution":
                x, y = v.split(",")
                x = x.split("=")[1]
                y = y.split("=")[1]
                v = unreal.CaptureResolution(int(x), int(y))
                self.capture_settings.set_editor_property(k, v)
            else:
                v = ast.literal_eval(v)
                self.capture_settings.set_editor_property(k, v)
Example #2
0
    def get_or_create(self,
                      asset_path='',
                      asset_class=None,
                      unique_name=True,
                      asset_factory=None):
        if isinstance(asset_class, str):
            asset_class = unreal.load_class(None, asset_class)

        asset_factory = asset_factory if asset_factory else self.get_factory(
            asset_class)
        if not asset_factory:
            raise Exception('No factory registered for asset_class: %s' %
                            asset_class.get_name())

        return self._get_or_create(asset_path, asset_class, unique_name,
                                   asset_factory)
    def spawn_actors_recursive(self, prim, parent_info):

        info = None

        # Spawn an actor for each xformable usd object
        if prim.IsA(UsdGeom.Xformable):

            # Setup container to hold import state for one node
            info = USDImportNode()
            info.usd_path = str(prim.GetPath())
            info.usd_node = prim
            info.parent = parent_info

            #print("spawn: " + str(prim.GetPath()))

            # Set label displayed in world outliner, not the internal object name
            info.label = prim.GetName()

            # Check for custom attributes in the usd scene
            info.unreal_asset = None
            info.unreal_asset_path = self.get_usd_attribute_value(
                prim, usd_unreal.attributes.asset_path_variable_name)
            if info.unreal_asset_path != None:
                info.unreal_asset = unreal.load_asset(info.unreal_asset_path)

            info.unreal_class = None
            info.unreal_class_path_name = self.get_usd_attribute_value(
                prim, usd_unreal.attributes.actor_class_variable_name)
            if info.unreal_class_path_name != None:
                info.unreal_class = unreal.load_class(
                    None, info.unreal_class_path_name)

            # Fallback try to find asset that was auto imported (without custom unreal property)
            if info.unreal_asset_path == None and info.unreal_asset == None:
                if prim.IsA(UsdGeom.Mesh):
                    possible_asset_path = self.generate_asset_path(
                        str(prim.GetPath()))
                    if self.allow_asset_import:
                        unreal_asset = unreal.load_asset(possible_asset_path)
                        if unreal_asset != None:
                            info.unreal_asset = unreal_asset
                            info.unreal_class = unreal.StaticMeshActor.static_class(
                            )

            # Support for generic USD object types (Meshes, Cameras, Lights, ...)
            #if prim.IsA(UsdGeom.Mesh):
            #	if info.unreal_class == None:
            #		info.unreal_class = unreal.StaticMeshActor.static_class()
            #	if info.unreal_asset_path == None:
            #		info.unreal_asset_path = self.generated_asset_base_path + self.usd_path_to_asset_path(str(prim.GetPath()))

            if prim.IsA(UsdGeom.Camera):
                if info.unreal_class == None:
                    info.unreal_class = unreal.CineCameraActor.static_class()
            else:
                if info.unreal_class == None:
                    unreal_light_class = usd_unreal.attributes.LightAttributes.get_unreal_light_class_from_usd_prim(
                        prim)
                    if unreal_light_class != None:
                        info.unreal_class = unreal_light_class.static_class()

            # Spawn actor
            actor = None
            for handler in self.actor_import_handlers:
                actor = handler(info)
                if actor != None:
                    break

        for child in prim.GetChildren():
            self.spawn_actors_recursive(child, info)
Example #4
0
def render_sequence_to_movie(sequencer_asset_path,
                             level_name,
                             level_path,
                             output_file_name,
                             resolution=(1280, 720),
                             game_mode_override='None',
                             warm_up_frame_count=0,
                             delay_before_warm_up=0.0,
                             delay_before_shot_warm_up=0.0,
                             delay_every_frame=0.0,
                             use_burn_in=False,
                             encorder_format='422'):
    # 1) Create an instance of our UAutomatedLevelSequenceCapture and override all of the settings on it. This class is currently
    # set as a config class so settings will leak between the Unreal Sequencer Render-to-Movie UI and this object. To work around
    # this, we set every setting via the script so that no changes the user has made via the UI will affect the script version.
    # The users UI settings will be reset as an unfortunate side effect of this.
    capture_settings = unreal.AutomatedLevelSequenceCapture()

    # Set all POD settings on the UMovieSceneCapture
    output_dir = unreal.SystemLibrary.get_project_directory(
    ) + "Saved/VideoCaptures/"
    capture_settings.settings.output_directory = unreal.DirectoryPath(
        output_dir)
    if not os.path.exists(output_dir):
        os.mkdir(output_dir)

    #capture_settings.settings.movie_extension = '.avi'

    # If you game mode is implemented in Blueprint, load_asset(...) is going to return you the C++ type ('Blueprint') and not what the BP says it inherits from.
    # Instead, because game_mode_override is a TSubclassOf<AGameModeBase> we can use unreal.load_class to get the UClass which is implicitly convertable.
    # ie: capture_settings.settings.game_mode_override = unreal.load_class(None, "/Game/AI/TestingSupport/AITestingGameMode.AITestingGameMode_C")

    editor_world_settings = unreal.EditorLevelLibrary.get_editor_world(
    ).get_world_settings()
    ''' game_mode_override is not working
		so change game_mode in world setting temporatily '''
    print "# World Setting - Game Mode Input = " + game_mode_override
    print "# World Setting - Game Mode = " + str(
        editor_world_settings.default_game_mode) + " - type = " + str(
            type(editor_world_settings.default_game_mode))
    if game_mode_override == 'None':
        unreal.EditorLevelLibrary.get_editor_world().get_world_settings(
        ).set_editor_property('default_game_mode', None)
    elif game_mode_override == 'BP_CameraGameMode':
        unreal.EditorLevelLibrary.get_editor_world().get_world_settings(
        ).set_editor_property(
            'default_game_mode',
            unreal.load_class(
                None,
                '/VirtualCamera/Custom/BP_CameraGameMode.BP_CameraGameMode_C'))
    else:
        pass

    print "# World Setting - Game Mode Override = " + str(
        editor_world_settings.default_game_mode) + " - type = " + str(
            type(editor_world_settings.default_game_mode))

    capture_settings.settings.game_mode_override = None
    #if game_mode_override=='BP_CameraGameMode':
    #	capture_settings.settings.game_mode_override = None
    capture_settings.settings.output_format = output_file_name
    capture_settings.settings.overwrite_existing = False
    capture_settings.settings.use_relative_frame_numbers = False
    capture_settings.settings.handle_frames = 0
    capture_settings.settings.zero_pad_frame_numbers = 4
    # If you wish to override the output framerate you can use these two lines, otherwise the framerate will be derived from the sequence being rendered
    capture_settings.settings.use_custom_frame_rate = True
    capture_settings.settings.custom_frame_rate = unreal.FrameRate(24, 1)
    capture_settings.settings.resolution.res_x = resolution[0]
    capture_settings.settings.resolution.res_y = resolution[1]
    capture_settings.settings.enable_texture_streaming = False
    capture_settings.settings.cinematic_engine_scalability = True
    capture_settings.settings.cinematic_mode = True
    capture_settings.settings.allow_movement = False  # Requires cinematic_mode = True
    capture_settings.settings.allow_turning = False  # Requires cinematic_mode = True
    capture_settings.settings.show_player = False  # Requires cinematic_mode = True
    capture_settings.settings.show_hud = False  # Requires cinematic_mode = True
    capture_settings.use_separate_process = False
    capture_settings.close_editor_when_capture_starts = False  # Requires use_separate_process = True
    capture_settings.additional_command_line_arguments = "-NOSCREENMESSAGES"  # Requires use_separate_process = True
    capture_settings.inherited_command_line_arguments = ""  # Requires use_separate_process = True

    # Set all the POD settings on UAutomatedLevelSequenceCapture
    capture_settings.use_custom_start_frame = False  # If False, the system will automatically calculate the start based on sequence content
    capture_settings.use_custom_end_frame = False  # If False, the system will automatically calculate the end based on sequence content
    capture_settings.custom_start_frame = unreal.FrameNumber(
        0)  # Requires use_custom_start_frame = True
    capture_settings.custom_end_frame = unreal.FrameNumber(
        0)  # Requires use_custom_end_frame = True
    capture_settings.warm_up_frame_count = warm_up_frame_count
    capture_settings.delay_before_warm_up = delay_before_warm_up
    capture_settings.delay_before_shot_warm_up = delay_before_shot_warm_up
    capture_settings.delay_every_frame = delay_every_frame

    capture_settings.write_edit_decision_list = True

    # Tell the capture settings which level sequence to render with these settings. The asset does not need to be loaded,
    # as we're only capturing the path to it and when the PIE instance is created it will load the specified asset.
    # If you only had a reference to the level sequence, you could use "unreal.SoftObjectPath(mysequence.get_path_name())"
    capture_settings.level_sequence_asset = unreal.SoftObjectPath(
        sequencer_asset_path)

    # To configure the video output we need to tell the capture settings which capture protocol to use. The various supported
    # capture protocols can be found by setting the Unreal Content Browser to "Engine C++ Classes" and filtering for "Protocol"
    # ie: CompositionGraphCaptureProtocol, ImageSequenceProtocol_PNG, etc. Do note that some of the listed protocols are not intended
    # to be used directly.
    # Right click on a Protocol and use "Copy Reference" and then remove the extra formatting around it. ie:
    # Class'/Script/MovieSceneCapture.ImageSequenceProtocol_PNG' gets transformed into "/Script/MovieSceneCapture.ImageSequenceProtocol_PNG"

    #capture_settings.set_image_capture_protocol_type(unreal.load_class(None, "/Script/MovieSceneCapture.VideoCaptureProtocol"))
    capture_settings.set_image_capture_protocol_type(
        unreal.load_class(
            None, "/Script/AppleProResMedia.AppleProResEncoderProtocol"))
    # After we have set the capture protocol to a soft class path we can start editing the settings for the instance of the protocol that is internallyc reated.
    #capture_settings.get_image_capture_protocol().compression_quality = 100

    # The other complex settings is the burn-in. Create an instance of the LevelSequenceBurnInOptions which is used to
    # specify if we should use a burn in, and then which settings.
    burn_in_options = unreal.LevelSequenceBurnInOptions()
    #unreal.log('use_burn_in =' + str(use_burn_in))
    burn_in_options.use_burn_in = use_burn_in
    #unreal.log('burn_in_options.use_burn_in =' + str(burn_in_options.use_burn_in))

    # You have to specify a path to a class to use for the burn in (if use_burn_in = True), and this class specifies a UClass to define the
    # settings object type. We've created a convinence function which takes the class path, loads the class at that path and assigns it to
    # the Settings object.
    #burn_in_options.set_burn_in(unreal.SoftClassPath("/Engine/Sequencer/DefaultBurnIn.DefaultBurnIn_C"))
    burn_in_options.set_burn_in(
        unreal.SoftClassPath("/MofacRenderMovie/CustomBurnIn.CustomBurnIn_C"))

    # The default burn in is implemented entirely in Blueprint which means that the method we've been using to set properties will not
    # work for it. The python bindings that turn bSomeVariableName into "some_variable_name" only work for C++ classes with
    # UPROPERTY(BlueprintReadWrite) marked fields. Python doesn't know about the existence of Blueprint classes and their fields, so we
    # have to use an alternative method.
    burn_in_options.settings.set_editor_property(
        'TopLeftText', "{FocalLength}mm,{Aperture},{FocusDistance}")
    burn_in_options.settings.set_editor_property(
        'TopCenterText',
        "{MasterName} - {Date} - {EngineVersion} - " + proj_names)
    burn_in_options.settings.set_editor_property('TopRightText', artist_names)

    burn_in_options.settings.set_editor_property(
        'BottomLeftText',
        "Level: " + level_name + "\nPath: " + level_path + "\n{ShotName}")
    burn_in_options.settings.set_editor_property(
        'BottomCenterText', "{hh}:{mm}:{ss}:{ff} ({MasterFrame})")
    burn_in_options.settings.set_editor_property(
        'BottomRightText',
        "{shh}:{smm}:{sss}:{sff} {SourceTimecode} {ShotFrame}")

    # Load a Texture2D asset and assign it to the UTexture2D reference that Watermark is.
    # burn_in_settings.set_editor_property('Watermark', None)
    # Note that this example creates a really obvious watermark (a big blurry green smiley face) just so that you know it's working!
    #burn_in_options.settings.set_editor_property('Watermark', unreal.load_asset("/Engine/EngineResources/AICON-Green"))
    #burn_in_options.settings.set_editor_property('WatermarkTint', unreal.LinearColor(1.0, 0.5, 0.5, 0.5)) # Create a FLinearColor to tint our Watermark

    # Assign our created instances to our original capture_settings object.
    capture_settings.burn_in_options = burn_in_options

    # Finally invoke Sequencer's Render to Movie functionality. This will examine the specified settings object and either construct a new PIE instance to render in,
    # or create and launch a new process (optionally shutting down your editor).

    #unreal.log(capture_settings.get_image_capture_protocol().get_editor_property('EncodingFormat'))
    '''
	enum class EAppleProResEncoderFormats : uint8
	{
		F_422HQ UMETA(DisplayName = "422 HQ"),
		F_422 UMETA(DisplayName = "422"),
		F_422LT UMETA(DisplayName = "422 LT"),
		F_422Proxy UMETA(DisplayName = "422 Proxy"),
		F_4444 UMETA(DisplayName = "4444"),
		F_4444XQ UMETA(DisplayName = "4444 XQ"),
	};
	'''
    TargetEncoderFormat = unreal.AppleProResEncoderFormats.F_422
    #print type(TargetEncoderFormat)
    #print TargetEncoderFormat
    #print dir(type(TargetEncoderFormat))
    if encorder_format == '422 HQ':
        TargetEncoderFormat = unreal.AppleProResEncoderFormats.F_422HQ
    elif encorder_format == '422':
        pass
    elif encorder_format == '422 LT':
        TargetEncoderFormat = unreal.AppleProResEncoderFormats.F_422LT
    elif encorder_format == '422 Proxy':
        TargetEncoderFormat = unreal.AppleProResEncoderFormats.F_422_PROXY
    elif encorder_format == '4444':
        TargetEncoderFormat = unreal.AppleProResEncoderFormats.F_4444
    elif encorder_format == '4444 XQ':
        TargetEncoderFormat = unreal.AppleProResEncoderFormats.F_4444XQ

    capture_settings.get_image_capture_protocol().set_editor_property(
        'EncodingFormat', TargetEncoderFormat)

    if args.use_audio_capture:
        capture_settings.set_audio_capture_protocol_type(
            unreal.load_class(
                None,
                "/Script/MovieSceneCapture.MasterAudioSubmixCaptureProtocol"))
        capture_settings.get_audio_capture_protocol().set_editor_property(
            'FileName', output_file_name)
    #unreal.log(capture_settings.get_image_capture_protocol().get_editor_property('EncodingFormat'))
    #unreal.log(type(capture_settings.get_image_capture_protocol().get_editor_property('EncodingFormat')))

    unreal.SequencerTools.render_movie(capture_settings, on_finished_callback)
Example #5
0
    def render_sequence_to_movie(sequence_path, sequence_name):
        def on_render_movie_finished(success):
            print(
                "Movie has finished rendering. Python can now invoke another movie render if needed. Sucess: "
                + str(success))

        on_finished_callback = unreal.OnRenderMovieStopped()
        on_finished_callback.bind_callable(on_render_movie_finished)

        file_path = sequence_path + "/" + sequence_name

        capture_settings = unreal.AutomatedLevelSequenceCapture()

        # out put path
        capture_settings.settings.output_directory = unreal.DirectoryPath(
            "../../../Game/Saved/VideoCaptures/")

        capture_settings.settings.game_mode_override = None

        # out put name
        capture_settings.settings.output_format = sequence_name

        capture_settings.settings.overwrite_existing = False
        capture_settings.settings.use_relative_frame_numbers = False
        capture_settings.settings.handle_frames = 0
        capture_settings.settings.zero_pad_frame_numbers = 4

        capture_settings.settings.use_custom_frame_rate = True

        capture_settings.settings.custom_frame_rate = unreal.FrameRate(24, 1)
        capture_settings.settings.resolution.res_x = 1280
        capture_settings.settings.resolution.res_y = 720

        capture_settings.settings.enable_texture_streaming = False
        capture_settings.settings.cinematic_engine_scalability = True
        capture_settings.settings.cinematic_mode = True
        capture_settings.settings.allow_movement = False
        capture_settings.settings.allow_turning = False
        capture_settings.settings.show_player = False
        capture_settings.settings.show_hud = False
        capture_settings.use_separate_process = False
        capture_settings.close_editor_when_capture_starts = False
        capture_settings.additional_command_line_arguments = "-NOSCREENMESSAGES"
        capture_settings.inherited_command_line_arguments = ""

        capture_settings.use_custom_start_frame = False
        capture_settings.use_custom_end_frame = False
        capture_settings.custom_start_frame = unreal.FrameNumber(0)
        capture_settings.custom_end_frame = unreal.FrameNumber(0)
        capture_settings.warm_up_frame_count = 0.0
        capture_settings.delay_before_warm_up = 0
        capture_settings.delay_before_shot_warm_up = 0.0
        capture_settings.write_edit_decision_list = True

        # Change format
        capture_settings.set_image_capture_protocol_type(
            unreal.load_class(
                None, "/Script/MovieSceneCapture.ImageSequenceProtocol_JPG"))
        capture_settings.get_image_capture_protocol().compression_quality = 100

        capture_settings.level_sequence_asset = unreal.SoftObjectPath(
            file_path)
        unreal.SequencerTools.render_movie(capture_settings,
                                           on_finished_callback)
Example #6
0
def render_sequence_to_movie(sequencer_asset_path):
    # 1) Create an instance of our UAutomatedLevelSequenceCapture and override all of the settings on it. This class is currently
    # set as a config class so settings will leak between the Unreal Sequencer Render-to-Movie UI and this object. To work around
    # this, we set every setting via the script so that no changes the user has made via the UI will affect the script version.
    # The users UI settings will be reset as an unfortunate side effect of this.
    capture_settings = unreal.AutomatedLevelSequenceCapture()

    # Set all POD settings on the UMovieSceneCapture
    capture_settings.settings.output_directory = unreal.DirectoryPath(
        "../../../QAGame/Saved/VideoCaptures/")

    # If you game mode is implemented in Blueprint, load_asset(...) is going to return you the C++ type ('Blueprint') and not what the BP says it inherits from.
    # Instead, because game_mode_override is a TSubclassOf<AGameModeBase> we can use unreal.load_class to get the UClass which is implicitly convertable.
    # ie: capture_settings.settings.game_mode_override = unreal.load_class(None, "/Game/AI/TestingSupport/AITestingGameMode.AITestingGameMode_C")
    capture_settings.settings.game_mode_override = None
    capture_settings.settings.output_format = "{world}"
    capture_settings.settings.overwrite_existing = True
    capture_settings.settings.use_relative_frame_numbers = False
    capture_settings.settings.handle_frames = 0
    capture_settings.settings.zero_pad_frame_numbers = 4
    # If you wish to override the output framerate you can use these two lines, otherwise the framerate will be derived from the sequence being rendered
    capture_settings.settings.use_custom_frame_rate = True
    capture_settings.settings.custom_frame_rate = unreal.FrameRate(24, 1)
    capture_settings.settings.resolution.res_x = 1280
    capture_settings.settings.resolution.res_y = 720
    capture_settings.settings.enable_texture_streaming = False
    capture_settings.settings.cinematic_engine_scalability = True
    capture_settings.settings.cinematic_mode = True
    capture_settings.settings.allow_movement = False  # Requires cinematic_mode = True
    capture_settings.settings.allow_turning = False  # Requires cinematic_mode = True
    capture_settings.settings.show_player = False  # Requires cinematic_mode = True
    capture_settings.settings.show_hud = False  # Requires cinematic_mode = True
    capture_settings.use_separate_process = False
    capture_settings.close_editor_when_capture_starts = False  # Requires use_separate_process = True
    capture_settings.additional_command_line_arguments = "-NOSCREENMESSAGES"  # Requires use_separate_process = True
    capture_settings.inherited_command_line_arguments = ""  # Requires use_separate_process = True

    # Set all the POD settings on UAutomatedLevelSequenceCapture
    capture_settings.use_custom_start_frame = False  # If False, the system will automatically calculate the start based on sequence content
    capture_settings.use_custom_end_frame = False  # If False, the system will automatically calculate the end based on sequence content
    capture_settings.custom_start_frame = unreal.FrameNumber(
        0)  # Requires use_custom_start_frame = True
    capture_settings.custom_end_frame = unreal.FrameNumber(
        0)  # Requires use_custom_end_frame = True
    capture_settings.warm_up_frame_count = 0.0
    capture_settings.delay_before_warm_up = 0
    capture_settings.delay_before_shot_warm_up = 0.0
    capture_settings.write_edit_decision_list = True

    # Tell the capture settings which level sequence to render with these settings. The asset does not need to be loaded,
    # as we're only capturing the path to it and when the PIE instance is created it will load the specified asset.
    # If you only had a reference to the level sequence, you could use "unreal.SoftObjectPath(mysequence.get_path_name())"
    capture_settings.level_sequence_asset = unreal.SoftObjectPath(
        sequencer_asset_path)

    # To configure the video output we need to tell the capture settings which capture protocol to use. The various supported
    # capture protocols can be found by setting the Unreal Content Browser to "Engine C++ Classes" and filtering for "Protocol"
    # ie: CompositionGraphCaptureProtocol, ImageSequenceProtocol_PNG, etc. Do note that some of the listed protocols are not intended
    # to be used directly.
    # Right click on a Protocol and use "Copy Reference" and then remove the extra formatting around it. ie:
    # Class'/Script/MovieSceneCapture.ImageSequenceProtocol_PNG' gets transformed into "/Script/MovieSceneCapture.ImageSequenceProtocol_PNG"
    capture_settings.set_image_capture_protocol_type(
        unreal.load_class(
            None, "/Script/MovieSceneCapture.ImageSequenceProtocol_PNG"))

    # After we have set the capture protocol to a soft class path we can start editing the settings for the instance of the protocol that is internallyc reated.
    capture_settings.get_image_capture_protocol().compression_quality = 100

    # The other complex settings is the burn-in. Create an instance of the LevelSequenceBurnInOptions which is used to
    # specify if we should use a burn in, and then which settings.
    burn_in_options = unreal.LevelSequenceBurnInOptions()
    burn_in_options.use_burn_in = True

    # You have to specify a path to a class to use for the burn in (if use_burn_in = True), and this class specifies a UClass to define the
    # settings object type. We've created a convinence function which takes the class path, loads the class at that path and assigns it to
    # the Settings object.
    burn_in_options.set_burn_in(
        unreal.SoftClassPath(
            "/Engine/Sequencer/DefaultBurnIn.DefaultBurnIn_C"))

    # The default burn in is implemented entirely in Blueprint which means that the method we've been using to set properties will not
    # work for it. The python bindings that turn bSomeVariableName into "some_variable_name" only work for C++ classes with
    # UPROPERTY(BlueprintReadWrite) marked fields. Python doesn't know about the existence of Blueprint classes and their fields, so we
    # have to use an alternative method.
    burn_in_options.settings.set_editor_property(
        'TopLeftText', "{FocalLength}mm,{Aperture},{FocusDistance}")
    burn_in_options.settings.set_editor_property(
        'TopCenterText', "{MasterName} - {Date} - {EngineVersion}")
    burn_in_options.settings.set_editor_property(
        'TopRightText',
        "{TranslationX} {TranslationY} {TranslationZ}, {RotationX} {RotationY} {RotationZ}"
    )

    burn_in_options.settings.set_editor_property('BottomLeftText',
                                                 "{ShotName}")
    burn_in_options.settings.set_editor_property(
        'BottomCenterText', "{hh}:{mm}:{ss}:{ff} ({MasterFrame})")
    burn_in_options.settings.set_editor_property('BottomRightText',
                                                 "{ShotFrame}")

    # Load a Texture2D asset and assign it to the UTexture2D reference that Watermark is.
    # burn_in_settings.set_editor_property('Watermark', None)
    # Note that this example creates a really obvious watermark (a big blurry green smiley face) just so that you know it's working!
    burn_in_options.settings.set_editor_property(
        'Watermark', unreal.load_asset("/Engine/EngineResources/AICON-Green"))
    burn_in_options.settings.set_editor_property(
        'WatermarkTint',
        unreal.LinearColor(1.0, 0.5, 0.5,
                           0.5))  # Create a FLinearColor to tint our Watermark

    # Assign our created instances to our original capture_settings object.
    capture_settings.burn_in_options = burn_in_options

    # Finally invoke Sequencer's Render to Movie functionality. This will examine the specified settings object and either construct a new PIE instance to render in,
    # or create and launch a new process (optionally shutting down your editor).
    unreal.SequencerTools.render_movie(capture_settings, on_finished_callback)