VSE: Add render options for sequencer scene and active scene
Addresses #146305. Ever since moving to the "sequencer scene" paradigm, attempting to render an image or animation when a sequencer with strips is present often seems to outright ignore the sequencer in most cases. This is because the sequencer scene usually differs from the active scene (which is the true render target), so one must first switch their active scene to the sequencer scene before rendering. This is confusing and seems like a regression in behavior. To improve clarity, this patch does the following: When a sequencer scene with at least one strip (and the sequencer step enabled in the pipeline) exists in the current workspace, new options "Render Sequencer Image" and "Render Sequencer Animation" appear. These options may be invoked by alt-F12 and ctrl-alt-F12, respectively. Additionally, if such a valid sequencer scene is the same as the active scene, then only the regular render options are listed, since in this case they are identical to the sequencer render operators, meaning F12 still works predictably. To switch back and forth between sequencer and main scene render outputs, a new toggle has been added to the image editor to "Show Sequencer Scene" output. This button only appears for the render result if there is a valid sequencer scene that differs from the active scene. Pull Request: https://projects.blender.org/blender/blender/pulls/146934
This commit is contained in:
committed by
John Kiril Swenson
parent
0c18c1cfc2
commit
76c03744a8
@@ -829,6 +829,10 @@ def km_screen(params):
|
||||
{"properties": [("use_viewport", True)]}),
|
||||
("render.render", {"type": 'F12', "value": 'PRESS', "ctrl": True},
|
||||
{"properties": [("animation", True), ("use_viewport", True)]}),
|
||||
("render.render", {"type": 'F12', "value": 'PRESS', "alt": True},
|
||||
{"properties": [("use_sequencer_scene", True), ("use_viewport", True)]}),
|
||||
("render.render", {"type": 'F12', "value": 'PRESS', "ctrl": True, "alt": True},
|
||||
{"properties": [("animation", True), ("use_sequencer_scene", True), ("use_viewport", True)]}),
|
||||
("render.view_cancel", {"type": 'ESC', "value": 'PRESS'}, None),
|
||||
("render.view_show", {"type": 'F11', "value": 'PRESS'}, None),
|
||||
("render.play_rendered_anim", {"type": 'F11', "value": 'PRESS', "ctrl": True}, None),
|
||||
|
||||
@@ -289,6 +289,10 @@ def km_screen_editing(params):
|
||||
{"properties": [("use_viewport", True)]}),
|
||||
("render.render", {"type": 'RET', "value": 'PRESS', "ctrl": True, "alt": True},
|
||||
{"properties": [("animation", True), ("use_viewport", True)]}),
|
||||
("render.render", {"type": 'F12', "value": 'PRESS', "alt": True},
|
||||
{"properties": [("use_sequencer_scene", True), ("use_viewport", True)]}),
|
||||
("render.render", {"type": 'F12', "value": 'PRESS', "ctrl": True, "alt": True},
|
||||
{"properties": [("animation", True), ("use_sequencer_scene", True), ("use_viewport", True)]}),
|
||||
("render.view_cancel", {"type": 'ESC', "value": 'PRESS'}, None),
|
||||
])
|
||||
|
||||
|
||||
@@ -931,6 +931,13 @@ class IMAGE_HT_header(Header):
|
||||
layout.prop_search(mesh.uv_layers, "active", mesh, "uv_layers", text="")
|
||||
|
||||
if ima:
|
||||
seq_scene = context.sequencer_scene
|
||||
scene = context.scene
|
||||
|
||||
if show_render and seq_scene and (seq_scene != scene):
|
||||
row = layout.row()
|
||||
row.prop(sima, "show_sequencer_scene", text="")
|
||||
|
||||
if ima.is_stereo_3d:
|
||||
row = layout.row()
|
||||
row.prop(sima, "show_stereo_3d", text="")
|
||||
|
||||
@@ -467,6 +467,11 @@ class TOPBAR_MT_render(Menu):
|
||||
layout = self.layout
|
||||
|
||||
rd = context.scene.render
|
||||
scene = context.scene
|
||||
seq_scene = context.sequencer_scene
|
||||
strips = getattr(context, "strips", ())
|
||||
|
||||
can_render_seq = seq_scene and seq_scene.render.use_sequencer and strips
|
||||
|
||||
layout.operator("render.render", text="Render Image", icon='RENDER_STILL').use_viewport = True
|
||||
props = layout.operator("render.render", text="Render Animation", icon='RENDER_ANIMATION')
|
||||
@@ -475,6 +480,18 @@ class TOPBAR_MT_render(Menu):
|
||||
|
||||
layout.separator()
|
||||
|
||||
if can_render_seq and (seq_scene != scene):
|
||||
props = layout.operator("render.render", text="Render Sequencer Image", icon='RENDER_STILL')
|
||||
props.use_viewport = True
|
||||
props.use_sequencer_scene = True
|
||||
|
||||
props = layout.operator("render.render", text="Render Sequencer Animation", icon='RENDER_ANIMATION')
|
||||
props.animation = True
|
||||
props.use_viewport = True
|
||||
props.use_sequencer_scene = True
|
||||
|
||||
layout.separator()
|
||||
|
||||
layout.operator("sound.mixdown", text="Render Audio...")
|
||||
|
||||
layout.separator()
|
||||
|
||||
@@ -33,6 +33,7 @@ struct ImageUsage {
|
||||
bool last_tile_drawing;
|
||||
|
||||
const void *last_image = nullptr;
|
||||
const void *last_scene = nullptr;
|
||||
|
||||
ImageUsage() = default;
|
||||
ImageUsage(const ::Image *image, const ::ImageUser *image_user, bool do_tile_drawing)
|
||||
@@ -43,6 +44,7 @@ struct ImageUsage {
|
||||
colorspace_settings = image->colorspace_settings;
|
||||
alpha_mode = image->alpha_mode;
|
||||
last_image = static_cast<const void *>(image);
|
||||
last_scene = image_user ? static_cast<const void *>(image_user->scene) : nullptr;
|
||||
last_tile_drawing = do_tile_drawing;
|
||||
}
|
||||
|
||||
|
||||
@@ -325,16 +325,20 @@ static void get_render_operator_frame_range(wmOperator *render_operator,
|
||||
/* executes blocking render */
|
||||
static wmOperatorStatus screen_render_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
RenderEngineType *re_type = RE_engines_find(scene->r.engine);
|
||||
ViewLayer *active_layer = CTX_data_view_layer(C);
|
||||
ViewLayer *single_layer = nullptr;
|
||||
Render *re;
|
||||
Image *ima;
|
||||
View3D *v3d = CTX_wm_view3d(C);
|
||||
Main *mainp = CTX_data_main(C);
|
||||
|
||||
const bool is_animation = RNA_boolean_get(op->ptr, "animation");
|
||||
const bool is_write_still = RNA_boolean_get(op->ptr, "write_still");
|
||||
const bool use_sequencer_scene = RNA_boolean_get(op->ptr, "use_sequencer_scene");
|
||||
|
||||
Scene *scene = use_sequencer_scene ? CTX_data_sequencer_scene(C) : CTX_data_scene(C);
|
||||
ViewLayer *active_layer = use_sequencer_scene ? BKE_view_layer_default_render(scene) :
|
||||
CTX_data_view_layer(C);
|
||||
RenderEngineType *re_type = RE_engines_find(scene->r.engine);
|
||||
Object *camera_override = v3d ? V3D_CAMERA_LOCAL(v3d) : nullptr;
|
||||
|
||||
/* Cannot do render if there is not this function. */
|
||||
@@ -342,6 +346,11 @@ static wmOperatorStatus screen_render_exec(bContext *C, wmOperator *op)
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
if (use_sequencer_scene && !RE_seq_render_active(scene, &scene->r)) {
|
||||
BKE_report(op->reports, RPT_ERROR, "No sequencer scene with video strips to render");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
if (!is_animation && render_operator_has_custom_frame_range(op)) {
|
||||
BKE_report(op->reports, RPT_ERROR, "Frame start/end specified in a non-animation render");
|
||||
return OPERATOR_CANCELLED;
|
||||
@@ -1000,27 +1009,35 @@ static wmOperatorStatus screen_render_invoke(bContext *C, wmOperator *op, const
|
||||
{
|
||||
/* new render clears all callbacks */
|
||||
Main *bmain = CTX_data_main(C);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
ViewLayer *active_layer = CTX_data_view_layer(C);
|
||||
ViewLayer *single_layer = nullptr;
|
||||
RenderEngineType *re_type = RE_engines_find(scene->r.engine);
|
||||
Render *re;
|
||||
wmJob *wm_job;
|
||||
RenderJob *rj;
|
||||
Image *ima;
|
||||
ScrArea *area;
|
||||
|
||||
const bool is_animation = RNA_boolean_get(op->ptr, "animation");
|
||||
const bool is_write_still = RNA_boolean_get(op->ptr, "write_still");
|
||||
const bool use_viewport = RNA_boolean_get(op->ptr, "use_viewport");
|
||||
const bool use_sequencer_scene = RNA_boolean_get(op->ptr, "use_sequencer_scene");
|
||||
|
||||
View3D *v3d = use_viewport ? CTX_wm_view3d(C) : nullptr;
|
||||
Scene *scene = use_sequencer_scene ? CTX_data_sequencer_scene(C) : CTX_data_scene(C);
|
||||
ViewLayer *active_layer = use_sequencer_scene ? BKE_view_layer_default_render(scene) :
|
||||
CTX_data_view_layer(C);
|
||||
RenderEngineType *re_type = RE_engines_find(scene->r.engine);
|
||||
Object *camera_override = v3d ? V3D_CAMERA_LOCAL(v3d) : nullptr;
|
||||
const char *name;
|
||||
ScrArea *area;
|
||||
|
||||
/* Cannot do render if there is not this function. */
|
||||
if (re_type->render == nullptr) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
if (use_sequencer_scene && !RE_seq_render_active(scene, &scene->r)) {
|
||||
BKE_report(op->reports, RPT_ERROR, "No sequencer scene with video strips to render");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
if (!is_animation && render_operator_has_custom_frame_range(op)) {
|
||||
BKE_report(op->reports, RPT_ERROR, "Frame start/end specified in a non-animation render");
|
||||
return OPERATOR_CANCELLED;
|
||||
@@ -1088,7 +1105,7 @@ static wmOperatorStatus screen_render_invoke(bContext *C, wmOperator *op, const
|
||||
rj->main = bmain;
|
||||
rj->scene = scene;
|
||||
rj->current_scene = rj->scene;
|
||||
rj->view_layer = CTX_data_view_layer(C);
|
||||
rj->view_layer = active_layer;
|
||||
rj->single_layer = single_layer;
|
||||
rj->camera_override = camera_override;
|
||||
rj->anim = is_animation;
|
||||
@@ -1134,6 +1151,7 @@ static wmOperatorStatus screen_render_invoke(bContext *C, wmOperator *op, const
|
||||
}
|
||||
|
||||
/* setup job */
|
||||
const char *name;
|
||||
if (RE_seq_render_active(scene, &scene->r)) {
|
||||
name = RPT_("Rendering sequence...");
|
||||
}
|
||||
@@ -1195,13 +1213,23 @@ static wmOperatorStatus screen_render_invoke(bContext *C, wmOperator *op, const
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
|
||||
static std::string screen_render_get_description(bContext * /*C*/,
|
||||
wmOperatorType * /*ot*/,
|
||||
PointerRNA *ptr)
|
||||
{
|
||||
const bool use_sequencer_scene = RNA_boolean_get(ptr, "use_sequencer_scene");
|
||||
if (use_sequencer_scene) {
|
||||
return TIP_("Render active sequencer scene");
|
||||
}
|
||||
return TIP_("Render active scene");
|
||||
}
|
||||
|
||||
void RENDER_OT_render(wmOperatorType *ot)
|
||||
{
|
||||
PropertyRNA *prop;
|
||||
|
||||
/* identifiers */
|
||||
ot->name = "Render";
|
||||
ot->description = "Render active scene";
|
||||
ot->idname = "RENDER_OT_render";
|
||||
|
||||
/* API callbacks. */
|
||||
@@ -1209,6 +1237,7 @@ void RENDER_OT_render(wmOperatorType *ot)
|
||||
ot->modal = screen_render_modal;
|
||||
ot->cancel = screen_render_cancel;
|
||||
ot->exec = screen_render_exec;
|
||||
ot->get_description = screen_render_get_description;
|
||||
|
||||
/* This isn't needed, causes failure in background mode. */
|
||||
#if 0
|
||||
@@ -1233,6 +1262,12 @@ void RENDER_OT_render(wmOperatorType *ot)
|
||||
"Use 3D Viewport",
|
||||
"When inside a 3D viewport, use layers and camera of the viewport");
|
||||
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
||||
prop = RNA_def_boolean(ot->srna,
|
||||
"use_sequencer_scene",
|
||||
false,
|
||||
"Use Sequencer Scene",
|
||||
"Render the sequencer scene instead of the active scene");
|
||||
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
||||
prop = RNA_def_string(ot->srna,
|
||||
"layer",
|
||||
nullptr,
|
||||
@@ -1273,28 +1308,34 @@ void RENDER_OT_render(wmOperatorType *ot)
|
||||
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
||||
}
|
||||
|
||||
Scene *ED_render_job_get_scene(const bContext *C)
|
||||
static RenderJobBase *render_job_get(const bContext *C)
|
||||
{
|
||||
wmWindowManager *wm = CTX_wm_manager(C);
|
||||
RenderJobBase *rj = (RenderJobBase *)WM_jobs_customdata_from_type(
|
||||
wm, CTX_data_scene(C), WM_JOB_TYPE_RENDER);
|
||||
RenderJobBase *rj;
|
||||
|
||||
if (rj) {
|
||||
return rj->scene;
|
||||
/* Try to find job tied to active scene first. */
|
||||
rj = static_cast<RenderJobBase *>(
|
||||
WM_jobs_customdata_from_type(wm, CTX_data_scene(C), WM_JOB_TYPE_RENDER));
|
||||
|
||||
/* If not found, attempt to find job tied to sequencer scene. */
|
||||
if (rj == nullptr) {
|
||||
return static_cast<RenderJobBase *>(
|
||||
WM_jobs_customdata_from_type(wm, CTX_data_sequencer_scene(C), WM_JOB_TYPE_RENDER));
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
return rj;
|
||||
}
|
||||
|
||||
Scene *ED_render_job_get_scene(const bContext *C)
|
||||
{
|
||||
RenderJobBase *rj = render_job_get(C);
|
||||
return rj ? rj->scene : nullptr;
|
||||
}
|
||||
|
||||
Scene *ED_render_job_get_current_scene(const bContext *C)
|
||||
{
|
||||
wmWindowManager *wm = CTX_wm_manager(C);
|
||||
RenderJobBase *rj = (RenderJobBase *)WM_jobs_customdata_from_type(
|
||||
wm, CTX_data_scene(C), WM_JOB_TYPE_RENDER);
|
||||
if (rj) {
|
||||
return rj->current_scene;
|
||||
}
|
||||
return nullptr;
|
||||
RenderJobBase *rj = render_job_get(C);
|
||||
return rj ? rj->current_scene : nullptr;
|
||||
}
|
||||
|
||||
/* Motion blur curve preset */
|
||||
|
||||
@@ -60,7 +60,7 @@ static void draw_render_info(
|
||||
Render *re = RE_GetSceneRender(scene);
|
||||
Scene *stats_scene = ED_render_job_get_scene(C);
|
||||
if (stats_scene == nullptr) {
|
||||
stats_scene = CTX_data_scene(C);
|
||||
stats_scene = scene;
|
||||
}
|
||||
|
||||
RenderResult *rr = BKE_image_acquire_renderresult(stats_scene, ima);
|
||||
|
||||
@@ -76,13 +76,16 @@ static void image_scopes_tag_refresh(ScrArea *area)
|
||||
static void image_user_refresh_scene(const bContext *C, SpaceImage *sima)
|
||||
{
|
||||
/* Update scene image user for acquiring render results. */
|
||||
sima->iuser.scene = CTX_data_scene(C);
|
||||
sima->iuser.scene = (sima->iuser.flag & IMA_SHOW_SEQUENCER_SCENE) ? CTX_data_sequencer_scene(C) :
|
||||
CTX_data_scene(C);
|
||||
|
||||
if (sima->image && sima->image->type == IMA_TYPE_R_RESULT) {
|
||||
/* While rendering, prefer scene that is being rendered. */
|
||||
Scene *render_scene = ED_render_job_get_current_scene(C);
|
||||
if (render_scene) {
|
||||
sima->iuser.scene = render_scene;
|
||||
SET_FLAG_FROM_TEST(
|
||||
sima->iuser.flag, render_scene == CTX_data_sequencer_scene(C), IMA_SHOW_SEQUENCER_SCENE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -115,7 +115,7 @@ typedef struct ImageTile {
|
||||
/** #ImageUser::flag */
|
||||
enum {
|
||||
IMA_ANIM_ALWAYS = 1 << 0,
|
||||
// IMA_UNUSED_1 = 1 << 1,
|
||||
IMA_SHOW_SEQUENCER_SCENE = 1 << 1,
|
||||
// IMA_UNUSED_2 = 1 << 2,
|
||||
IMA_NEED_FRAME_RECALC = 1 << 3,
|
||||
IMA_SHOW_STEREO = 1 << 4,
|
||||
|
||||
@@ -1819,6 +1819,24 @@ static void rna_SpaceImageEditor_show_stereo_update(Main * /*bmain*/,
|
||||
}
|
||||
}
|
||||
|
||||
static void rna_SpaceImageEditor_show_sequencer_scene_set(PointerRNA *ptr, bool value)
|
||||
{
|
||||
SpaceImage *sima = ptr->data_as<SpaceImage>();
|
||||
|
||||
if (value) {
|
||||
sima->iuser.flag |= IMA_SHOW_SEQUENCER_SCENE;
|
||||
}
|
||||
else {
|
||||
sima->iuser.flag &= ~IMA_SHOW_SEQUENCER_SCENE;
|
||||
}
|
||||
}
|
||||
|
||||
static bool rna_SpaceImageEditor_show_sequencer_scene_get(PointerRNA *ptr)
|
||||
{
|
||||
SpaceImage *sima = ptr->data_as<SpaceImage>();
|
||||
return (sima->iuser.flag & IMA_SHOW_SEQUENCER_SCENE) != 0;
|
||||
}
|
||||
|
||||
static bool rna_SpaceImageEditor_show_render_get(PointerRNA *ptr)
|
||||
{
|
||||
SpaceImage *sima = (SpaceImage *)(ptr->data);
|
||||
@@ -6081,6 +6099,17 @@ static void rna_def_space_image(BlenderRNA *brna)
|
||||
RNA_def_property_update(
|
||||
prop, NC_SPACE | ND_SPACE_IMAGE, "rna_SpaceImageEditor_show_stereo_update");
|
||||
|
||||
prop = RNA_def_property(srna, "show_sequencer_scene", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_funcs(prop,
|
||||
"rna_SpaceImageEditor_show_sequencer_scene_get",
|
||||
"rna_SpaceImageEditor_show_sequencer_scene_set");
|
||||
RNA_def_property_ui_text(
|
||||
prop,
|
||||
"Show Sequencer Scene",
|
||||
"Display the render result for the sequencer scene instead of the active scene");
|
||||
RNA_def_property_ui_icon(prop, ICON_SEQ_SEQUENCER, 0);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, nullptr);
|
||||
|
||||
/* uv */
|
||||
prop = RNA_def_property(srna, "uv_editor", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_flag(prop, PROP_NEVER_NULL);
|
||||
|
||||
Reference in New Issue
Block a user