Grease Pencil: Add separate render pass
This PR adds a separate "Grease Pencil" render pass. Once the "Grease Pencil" option is checked in the passes list, the Grease Pencil engine will render to a new render pass for various composition uses. Notes: - Occluded Grease Pencil geometry is not rendered. - In most cases, using an "Alpha Over" with the rest will result in the same render as the "Combined" output. The exception is when there are Grease Pencil layers that use a blending mode that changes the chromaticity of the alpha channel. Pull Request: https://projects.blender.org/blender/blender/pulls/137638
This commit is contained in:
@@ -1028,6 +1028,7 @@ class CYCLES_RENDER_PT_passes_data(CyclesButtonsPanel, Panel):
|
||||
sub.active = not rd.use_motion_blur
|
||||
sub.prop(view_layer, "use_pass_vector")
|
||||
col.prop(view_layer, "use_pass_uv")
|
||||
col.prop(view_layer, "use_pass_grease_pencil", text="Grease Pencil")
|
||||
|
||||
col.prop(cycles_view_layer, "denoising_store_passes", text="Denoising Data")
|
||||
|
||||
|
||||
@@ -84,6 +84,7 @@ class VIEWLAYER_PT_eevee_next_layer_passes_data(ViewLayerButtonsPanel, Panel):
|
||||
sub = col.column()
|
||||
sub.active = not scene.render.use_motion_blur
|
||||
sub.prop(view_layer, "use_pass_vector")
|
||||
col.prop(view_layer, "use_pass_grease_pencil", text="Grease Pencil")
|
||||
|
||||
|
||||
class VIEWLAYER_PT_workbench_layer_passes_data(ViewLayerButtonsPanel, Panel):
|
||||
@@ -102,6 +103,7 @@ class VIEWLAYER_PT_workbench_layer_passes_data(ViewLayerButtonsPanel, Panel):
|
||||
col = layout.column()
|
||||
col.prop(view_layer, "use_pass_combined")
|
||||
col.prop(view_layer, "use_pass_z")
|
||||
col.prop(view_layer, "use_pass_grease_pencil", text="Grease Pencil")
|
||||
|
||||
|
||||
class VIEWLAYER_PT_eevee_next_layer_passes_light(ViewLayerButtonsPanel, Panel):
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
#include "RE_engine.h"
|
||||
#include "RE_pipeline.h"
|
||||
#include "render_types.h"
|
||||
|
||||
#include "IMB_imbuf_types.hh"
|
||||
|
||||
@@ -65,7 +66,8 @@ static void render_init_buffers(const DRWContext *draw_ctx,
|
||||
Instance &inst,
|
||||
RenderEngine *engine,
|
||||
RenderLayer *render_layer,
|
||||
const rcti *rect)
|
||||
const rcti *rect,
|
||||
const bool use_separated_pass)
|
||||
{
|
||||
const int2 size = int2(draw_ctx->viewport_size_get());
|
||||
View &view = View::default_get();
|
||||
@@ -89,10 +91,11 @@ static void render_init_buffers(const DRWContext *draw_ctx,
|
||||
remap_depth(view, {pix_z, rpass_z_src->rectx * rpass_z_src->recty});
|
||||
}
|
||||
|
||||
const bool do_region = !(rect->xmin == 0 && rect->ymin == 0 && rect->xmax == size.x &&
|
||||
rect->ymax == size.y);
|
||||
const bool do_region = (!use_separated_pass) &&
|
||||
(!(rect->xmin == 0 && rect->ymin == 0 && rect->xmax == size.x &&
|
||||
rect->ymax == size.y));
|
||||
const bool do_clear_z = !pix_z || do_region;
|
||||
const bool do_clear_col = !pix_col || do_region;
|
||||
const bool do_clear_col = use_separated_pass || (!pix_col) || do_region;
|
||||
|
||||
/* FIXME(fclem): we have a precision loss in the depth buffer because of this re-upload.
|
||||
* Find where it comes from! */
|
||||
@@ -225,6 +228,51 @@ static void render_result_combined(RenderLayer *rl,
|
||||
rp->ibuf->float_buffer.data);
|
||||
}
|
||||
|
||||
static void render_result_separated_pass(float *data, Instance &instance, const rcti *rect)
|
||||
{
|
||||
Framebuffer read_fb;
|
||||
read_fb.ensure(GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(instance.accumulation_tx));
|
||||
GPU_framebuffer_bind(read_fb);
|
||||
GPU_framebuffer_read_color(read_fb,
|
||||
rect->xmin,
|
||||
rect->ymin,
|
||||
BLI_rcti_size_x(rect),
|
||||
BLI_rcti_size_y(rect),
|
||||
4,
|
||||
0,
|
||||
GPU_DATA_FLOAT,
|
||||
data);
|
||||
}
|
||||
|
||||
static void render_frame(RenderEngine *engine,
|
||||
Depsgraph *depsgraph,
|
||||
const DRWContext *draw_ctx,
|
||||
RenderLayer *render_layer,
|
||||
const rcti rect,
|
||||
gpencil::Instance &inst,
|
||||
Manager &manager,
|
||||
const bool separated_pass)
|
||||
{
|
||||
const float aa_radius = clamp_f(draw_ctx->scene->r.gauss, 0.0f, 100.0f);
|
||||
const int sample_count = draw_ctx->scene->grease_pencil_settings.aa_samples;
|
||||
for (const int sample_i : IndexRange(sample_count)) {
|
||||
const float2 aa_sample = Instance::antialiasing_sample_get(sample_i, sample_count) * aa_radius;
|
||||
const float2 aa_offset = 2.0f * aa_sample / float2(inst.render_color_tx.size());
|
||||
render_set_view(engine, depsgraph, aa_offset);
|
||||
render_init_buffers(draw_ctx, inst, engine, render_layer, &rect, separated_pass);
|
||||
|
||||
/* Render the gpencil object and merge the result to the underlying render. */
|
||||
inst.draw(manager);
|
||||
|
||||
/* Weight of this render SSAA sample. The sum of previous samples is weighted by `1 - weight`.
|
||||
* This diminishes after each new sample as we want all samples to be equally weighted inside
|
||||
* the final result (inside the combined buffer). This weighting scheme allows to always store
|
||||
* the resolved result making it ready for in-progress display or read-back. */
|
||||
const float weight = 1.0f / (1.0f + sample_i);
|
||||
inst.antialiasing_accumulate(manager, weight);
|
||||
}
|
||||
}
|
||||
|
||||
void Engine::render_to_image(RenderEngine *engine, RenderLayer *render_layer, const rcti rect)
|
||||
{
|
||||
const char *viewname = RE_GetActiveRenderView(engine->re);
|
||||
@@ -232,12 +280,18 @@ void Engine::render_to_image(RenderEngine *engine, RenderLayer *render_layer, co
|
||||
const DRWContext *draw_ctx = DRW_context_get();
|
||||
Depsgraph *depsgraph = draw_ctx->depsgraph;
|
||||
|
||||
if (draw_ctx->view_layer->grease_pencil_flags & GREASE_PENCIL_AS_SEPARATE_PASS) {
|
||||
Render *re = engine->re;
|
||||
RE_create_render_pass(
|
||||
re->result, RE_PASSNAME_GREASE_PENCIL, 4, "RGBA", render_layer->name, viewname, true);
|
||||
}
|
||||
|
||||
gpencil::Instance inst;
|
||||
|
||||
Manager &manager = *DRW_manager_get();
|
||||
|
||||
render_set_view(engine, depsgraph);
|
||||
render_init_buffers(draw_ctx, inst, engine, render_layer, &rect);
|
||||
render_init_buffers(draw_ctx, inst, engine, render_layer, &rect, false);
|
||||
inst.init();
|
||||
|
||||
inst.camera = DEG_get_evaluated_object(depsgraph, RE_GetCamera(engine->re));
|
||||
@@ -259,26 +313,17 @@ void Engine::render_to_image(RenderEngine *engine, RenderLayer *render_layer, co
|
||||
|
||||
manager.end_sync();
|
||||
|
||||
const float aa_radius = clamp_f(draw_ctx->scene->r.gauss, 0.0f, 100.0f);
|
||||
const int sample_count = draw_ctx->scene->grease_pencil_settings.aa_samples;
|
||||
for (const int sample_i : IndexRange(sample_count)) {
|
||||
const float2 aa_sample = Instance::antialiasing_sample_get(sample_i, sample_count) * aa_radius;
|
||||
const float2 aa_offset = 2.0f * aa_sample / float2(inst.render_color_tx.size());
|
||||
render_set_view(engine, depsgraph, aa_offset);
|
||||
render_init_buffers(draw_ctx, inst, engine, render_layer, &rect);
|
||||
render_frame(engine, depsgraph, draw_ctx, render_layer, rect, inst, manager, false);
|
||||
render_result_combined(render_layer, viewname, inst, &rect);
|
||||
|
||||
/* Render the gpencil object and merge the result to the underlying render. */
|
||||
inst.draw(manager);
|
||||
|
||||
/* Weight of this render SSAA sample. The sum of previous samples is weighted by `1 - weight`.
|
||||
* This diminishes after each new sample as we want all samples to be equally weighted inside
|
||||
* the final result (inside the combined buffer). This weighting scheme allows to always store
|
||||
* the resolved result making it ready for in-progress display or read-back. */
|
||||
const float weight = 1.0f / (1.0f + sample_i);
|
||||
inst.antialiasing_accumulate(manager, weight);
|
||||
float *pass_data = RE_RenderLayerGetPass(render_layer, RE_PASSNAME_GREASE_PENCIL, viewname);
|
||||
if (pass_data) {
|
||||
render_frame(engine, depsgraph, draw_ctx, render_layer, rect, inst, manager, true);
|
||||
render_result_separated_pass(pass_data, inst, &rect);
|
||||
}
|
||||
|
||||
render_result_combined(render_layer, viewname, inst, &rect);
|
||||
/* Transfer depth in the last step, because if we need to render separate pass, we need original
|
||||
* untouched depth buffer. */
|
||||
render_result_z(draw_ctx, render_layer, viewname, inst, &rect);
|
||||
}
|
||||
|
||||
|
||||
@@ -50,6 +50,11 @@ typedef enum eViewLayerEEVEEPassType {
|
||||
#define EEVEE_RENDER_PASS_MAX_BIT 21
|
||||
ENUM_OPERATORS(eViewLayerEEVEEPassType, 1 << EEVEE_RENDER_PASS_MAX_BIT)
|
||||
|
||||
/* #ViewLayer::grease_pencil_flags */
|
||||
typedef enum eViewLayerGreasePencilFlags {
|
||||
GREASE_PENCIL_AS_SEPARATE_PASS = (1 << 0),
|
||||
} eViewLayerGreasePencilFlags;
|
||||
|
||||
/* #ViewLayerAOV.type */
|
||||
typedef enum eViewLayerAOVType {
|
||||
AOV_TYPE_VALUE = 0,
|
||||
@@ -166,7 +171,7 @@ typedef struct ViewLayer {
|
||||
float pass_alpha_threshold;
|
||||
short cryptomatte_flag;
|
||||
short cryptomatte_levels;
|
||||
char _pad1[4];
|
||||
int grease_pencil_flags;
|
||||
|
||||
int samples;
|
||||
|
||||
|
||||
@@ -304,6 +304,8 @@ typedef enum eScenePassType {
|
||||
#define RE_PASSNAME_CRYPTOMATTE_ASSET "CryptoAsset"
|
||||
#define RE_PASSNAME_CRYPTOMATTE_MATERIAL "CryptoMaterial"
|
||||
|
||||
#define RE_PASSNAME_GREASE_PENCIL "GreasePencil"
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
@@ -682,6 +682,14 @@ void RNA_def_view_layer(BlenderRNA *brna)
|
||||
RNA_def_property_struct_type(prop, "FreestyleSettings");
|
||||
RNA_def_property_ui_text(prop, "Freestyle Settings", "");
|
||||
|
||||
/* Grease Pencil */
|
||||
prop = RNA_def_property(srna, "use_pass_grease_pencil", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(
|
||||
prop, nullptr, "grease_pencil_flags", GREASE_PENCIL_AS_SEPARATE_PASS);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Grease Pencil", "Deliver Grease Pencil render result in a separate pass");
|
||||
RNA_def_property_update(prop, NC_SCENE | ND_LAYER, nullptr);
|
||||
|
||||
/* debug update routine */
|
||||
func = RNA_def_function(srna, "update", "rna_ViewLayer_update_tagged");
|
||||
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_REPORTS);
|
||||
|
||||
@@ -329,6 +329,11 @@ static void cmp_node_rlayer_create_outputs(bNodeTree *ntree,
|
||||
ntree, node, scene, view_layer, RE_PASSNAME_FREESTYLE, SOCK_RGBA);
|
||||
}
|
||||
|
||||
if (view_layer->grease_pencil_flags & GREASE_PENCIL_AS_SEPARATE_PASS) {
|
||||
node_cmp_rlayers_register_pass(
|
||||
ntree, node, scene, view_layer, RE_PASSNAME_GREASE_PENCIL, SOCK_RGBA);
|
||||
}
|
||||
|
||||
MEM_freeN(data);
|
||||
node->storage = nullptr;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user