Render API/Image Editor: Add postprocessing operator that calls the render engine when executed

This commit adds a general operator for postprocessing render results in the Image editor.
To do so, the render API is extended by two functions:
 - can_postprocess checks whether the current render result can be postprocessed by the engine.
   For the denoiser, this will check whether the required passes have been rendered.
 - postprocess is executed when the user runs the operator. For the denoiser, this will do the actual denoising.
This commit is contained in:
2016-06-21 19:23:25 +02:00
parent 51c1c3636a
commit c167e5d723
10 changed files with 173 additions and 3 deletions

View File

@@ -1202,6 +1202,26 @@ class IMAGE_PT_tools_grease_pencil_edit(GreasePencilStrokeEditPanel, Panel):
class IMAGE_PT_tools_grease_pencil_sculpt(GreasePencilStrokeSculptPanel, Panel):
bl_space_type = 'IMAGE_EDITOR'
class IMAGE_PT_tools_post_process(Panel):
bl_space_type = 'IMAGE_EDITOR'
bl_region_type = 'UI'
bl_label = "Post-processing"
@classmethod
def poll(cls, context):
rd = context.scene.render
sima = context.space_data
return sima.show_render and rd.use_result_postprocess
def draw(self, context):
layout = self.layout
sima = context.space_data
ima = sima.image
layout.operator("image.postprocess");
if __name__ == "__main__": # only for live edit.
bpy.utils.register_module(__name__)

View File

@@ -136,6 +136,7 @@ float get_render_aosss_error(const struct RenderData *r, float error);
bool BKE_scene_use_new_shading_nodes(const struct Scene *scene);
bool BKE_scene_use_shading_nodes_custom(struct Scene *scene);
bool BKE_scene_use_spherical_stereo(struct Scene *scene);
bool BKE_scene_use_result_postprocess(struct Scene *scene);
bool BKE_scene_uses_blender_internal(const struct Scene *scene);
bool BKE_scene_uses_blender_game(const struct Scene *scene);

View File

@@ -2203,6 +2203,12 @@ bool BKE_scene_use_spherical_stereo(Scene *scene)
return (type && type->flag & RE_USE_SPHERICAL_STEREO);
}
bool BKE_scene_use_result_postprocess(Scene *scene)
{
RenderEngineType *type = RE_engines_find(scene->r.engine);
return (type && type->flag & RE_USE_RESULT_POSTPROCESS);
}
bool BKE_scene_uses_blender_internal(const Scene *scene)
{
return STREQ(scene->r.engine, RE_engine_id_BLENDER_RENDER);

View File

@@ -92,6 +92,8 @@ void IMAGE_OT_read_renderlayers(struct wmOperatorType *ot);
void IMAGE_OT_render_border(struct wmOperatorType *ot);
void IMAGE_OT_clear_render_border(struct wmOperatorType *ot);
void IMAGE_OT_postprocess(struct wmOperatorType *ot);
/* image_panels.c */
struct ImageUser *ntree_get_active_iuser(struct bNodeTree *ntree);
void image_buttons_register(struct ARegionType *art);

View File

@@ -3662,3 +3662,63 @@ void IMAGE_OT_clear_render_border(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
static int postprocess_poll(bContext *C)
{
Scene *scene = CTX_data_scene(C);
Image *ima = CTX_data_edit_image(C);
RenderResult *rr = BKE_image_acquire_renderresult(scene, ima);
RenderEngineType *type = RE_engines_find(scene->r.engine);
RenderEngine *engine;
int can_postprocess;
if (!(ima && ima->type == IMA_TYPE_R_RESULT && rr &&
BKE_scene_use_result_postprocess(scene) &&
type->can_postprocess && type->postprocess)) {
if (rr) {
BKE_image_release_renderresult(scene, ima);
}
return 0;
}
/* this is probably a bit slow, but how else to check for passes etc. in a flexible way? */
engine = RE_engine_create(type);
can_postprocess = type->can_postprocess(engine, rr);
BKE_image_release_renderresult(scene, ima);
RE_engine_free(engine);
return can_postprocess;
}
static int postprocess_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
Image *ima = CTX_data_edit_image(C);
RenderResult *rr = BKE_image_acquire_renderresult(scene, ima);
RenderEngineType *type = RE_engines_find(scene->r.engine);
RenderEngine *engine = RE_engine_create(type);
type->postprocess(engine, scene, rr);
BKE_image_release_renderresult(scene, ima);
RE_engine_free(engine);
return OPERATOR_FINISHED;
}
void IMAGE_OT_postprocess(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Postprocess Render Result";
ot->description = "Call the render engine to post-process the render result";
ot->idname = "IMAGE_OT_postprocess";
/* api callbacks */
ot->exec = postprocess_exec;
ot->poll = postprocess_poll;
/* flags */
ot->flag = OPTYPE_REGISTER;
}

View File

@@ -262,6 +262,8 @@ static void image_operatortypes(void)
WM_operatortype_append(IMAGE_OT_read_renderlayers);
WM_operatortype_append(IMAGE_OT_render_border);
WM_operatortype_append(IMAGE_OT_clear_render_border);
WM_operatortype_append(IMAGE_OT_postprocess);
}
static void image_keymap(struct wmKeyConfig *keyconf)

View File

@@ -256,6 +256,47 @@ static void engine_update_script_node(RenderEngine *engine, struct bNodeTree *nt
RNA_parameter_list_free(&list);
}
static int engine_can_postprocess(RenderEngine *engine, struct RenderResult *result)
{
extern FunctionRNA rna_RenderEngine_can_postprocess_func;
PointerRNA ptr;
ParameterList list;
FunctionRNA *func;
void *ret;
int can_postprocess;
RNA_pointer_create(NULL, engine->type->ext.srna, engine, &ptr);
func = &rna_RenderEngine_can_postprocess_func;
RNA_parameter_list_create(&list, &ptr, func);
RNA_parameter_set_lookup(&list, "result", &result);
engine->type->ext.call(NULL, &ptr, func, &list);
RNA_parameter_get_lookup(&list, "can_postprocess", &ret);
can_postprocess = *(int *)ret;
RNA_parameter_list_free(&list);
return can_postprocess;
}
static void engine_postprocess(RenderEngine *engine, struct Scene *scene, struct RenderResult *result)
{
extern FunctionRNA rna_RenderEngine_postprocess_func;
PointerRNA ptr;
ParameterList list;
FunctionRNA *func;
RNA_pointer_create(NULL, engine->type->ext.srna, engine, &ptr);
func = &rna_RenderEngine_postprocess_func;
RNA_parameter_list_create(&list, &ptr, func);
RNA_parameter_set_lookup(&list, "scene", &scene);
RNA_parameter_set_lookup(&list, "result", &result);
engine->type->ext.call(NULL, &ptr, func, &list);
RNA_parameter_list_free(&list);
}
/* RenderEngine registration */
static void rna_RenderEngine_unregister(Main *UNUSED(bmain), StructRNA *type)
@@ -276,7 +317,7 @@ static StructRNA *rna_RenderEngine_register(Main *bmain, ReportList *reports, vo
RenderEngineType *et, dummyet = {NULL};
RenderEngine dummyengine = {NULL};
PointerRNA dummyptr;
int have_function[6];
int have_function[8];
/* setup dummy engine & engine type to store static properties in */
dummyengine.type = &dummyet;
@@ -318,6 +359,8 @@ static StructRNA *rna_RenderEngine_register(Main *bmain, ReportList *reports, vo
et->view_update = (have_function[3]) ? engine_view_update : NULL;
et->view_draw = (have_function[4]) ? engine_view_draw : NULL;
et->update_script_node = (have_function[5]) ? engine_update_script_node : NULL;
et->can_postprocess = (have_function[6]) ? engine_can_postprocess : NULL;
et->postprocess = (have_function[7]) ? engine_postprocess : NULL;
BLI_addtail(&R_engines, et);
@@ -488,6 +531,23 @@ static void rna_def_render_engine(BlenderRNA *brna)
prop = RNA_def_pointer(func, "node", "Node", "", "");
RNA_def_property_flag(prop, PROP_RNAPTR);
/* result postprocessing callbacks */
func = RNA_def_function(srna, "can_postprocess", NULL);
RNA_def_function_ui_description(func, "Pool whether a render result can be postprocessed");
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE);
prop = RNA_def_pointer(func, "result", "RenderResult", "Result", "");
RNA_def_property_flag(prop, PROP_REQUIRED);
prop = RNA_def_boolean(func, "can_postprocess", 0, "Can post-process", "Whether the render result can be postprocessed or not");
RNA_def_function_return(func, prop);
func = RNA_def_function(srna, "postprocess", NULL);
RNA_def_function_ui_description(func, "Postprocess the given render result");
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE);
prop = RNA_def_pointer(func, "scene", "Scene", "Scene", "");
RNA_def_property_flag(prop, PROP_REQUIRED);
prop = RNA_def_pointer(func, "result", "RenderResult", "Result", "");
RNA_def_property_flag(prop, PROP_REQUIRED);
/* tag for redraw */
func = RNA_def_function(srna, "tag_redraw", "engine_tag_redraw");
RNA_def_function_ui_description(func, "Request redraw for viewport rendering");
@@ -698,6 +758,10 @@ static void rna_def_render_engine(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "type->flag", RE_USE_SPHERICAL_STEREO);
RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
prop = RNA_def_property(srna, "bl_use_result_postprocess", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "type->flag", RE_USE_RESULT_POSTPROCESS);
RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
RNA_define_verify_sdna(1);
}

View File

@@ -1476,6 +1476,12 @@ static int rna_RenderSettings_use_spherical_stereo_get(PointerRNA *ptr)
return BKE_scene_use_spherical_stereo(scene);
}
static int rna_RenderSettings_use_result_postprocess_get(PointerRNA *ptr)
{
Scene *scene = (Scene *)ptr->id.data;
return BKE_scene_use_result_postprocess(scene);
}
static int rna_RenderSettings_use_game_engine_get(PointerRNA *ptr)
{
RenderData *rd = (RenderData *)ptr->data;
@@ -6144,6 +6150,11 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Use Spherical Stereo", "Active render engine supports spherical stereo rendering");
prop = RNA_def_property(srna, "use_result_postprocess", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_funcs(prop, "rna_RenderSettings_use_result_postprocess_get", NULL);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Use Result Postprocess", "Active render engine supports result post-processing");
prop = RNA_def_property(srna, "use_game_engine", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_funcs(prop, "rna_RenderSettings_use_game_engine_get", NULL);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);

View File

@@ -63,6 +63,7 @@ struct BakePixel;
#define RE_USE_TEXTURE_PREVIEW 128
#define RE_USE_SHADING_NODES_CUSTOM 256
#define RE_USE_SPHERICAL_STEREO 512
#define RE_USE_RESULT_POSTPROCESS 1024
/* RenderEngine.flag */
#define RE_ENGINE_ANIMATION 1
@@ -97,6 +98,9 @@ typedef struct RenderEngineType {
void (*update_script_node)(struct RenderEngine *engine, struct bNodeTree *ntree, struct bNode *node);
int (*can_postprocess)(struct RenderEngine *engine, struct RenderResult *result);
void (*postprocess)(struct RenderEngine *engine, struct Scene *scene, struct RenderResult *result);
/* RNA integration */
ExtensionRNA ext;
} RenderEngineType;

View File

@@ -68,7 +68,7 @@
static RenderEngineType internal_render_type = {
NULL, NULL,
"BLENDER_RENDER", N_("Blender Render"), RE_INTERNAL,
NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
{NULL, NULL, NULL}
};
@@ -77,7 +77,7 @@ static RenderEngineType internal_render_type = {
static RenderEngineType internal_game_type = {
NULL, NULL,
"BLENDER_GAME", N_("Blender Game"), RE_INTERNAL | RE_GAME,
NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
{NULL, NULL, NULL}
};