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:
@@ -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__)
|
||||
|
@@ -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);
|
||||
|
@@ -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);
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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)
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
|
@@ -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}
|
||||
};
|
||||
|
||||
|
Reference in New Issue
Block a user