diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2018-01-31 23:17:27 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2018-02-01 20:09:17 +0300 |
commit | 253b412acefc6abe9c221a4886e153739c4f50f4 (patch) | |
tree | 1b6c307dc634d55b5337e3ae0b370d295d1ac844 /source/blender/draw | |
parent | a57063a432a3908b0b750b889478ba87dfed60e2 (diff) |
Eevee: Render: Add Subsurface Pass support.
Diffstat (limited to 'source/blender/draw')
6 files changed, 174 insertions, 12 deletions
diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index 84627e03137..8c0ba921419 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -1056,9 +1056,16 @@ static void material_opaque( DRW_shgroup_uniform_texture(*shgrp, "sssTexProfile", sss_tex_profile); } - DRW_shgroup_stencil_mask(*shgrp, e_data.sss_count + 1); - EEVEE_subsurface_add_pass(sldata, vedata, e_data.sss_count + 1, sss_profile); - e_data.sss_count++; + /* Limit of 8 bit stencil buffer. ID 255 is refraction. */ + if (e_data.sss_count < 254) { + DRW_shgroup_stencil_mask(*shgrp, e_data.sss_count + 1); + EEVEE_subsurface_add_pass(sldata, vedata, e_data.sss_count + 1, sss_profile); + e_data.sss_count++; + } + else { + /* TODO : display message. */ + printf("Error: Too many different Subsurface shader in the scene.\n"); + } } } } diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index 17d41cabe66..1c35d5e7262 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -178,6 +178,7 @@ typedef struct EEVEE_PassList { struct DRWPass *ssr_resolve; struct DRWPass *sss_blur_ps; struct DRWPass *sss_resolve_ps; + struct DRWPass *sss_accum_ps; struct DRWPass *color_downsample_ps; struct DRWPass *color_downsample_cube_ps; struct DRWPass *taa_resolve; @@ -220,6 +221,7 @@ typedef struct EEVEE_FramebufferList { struct GPUFrameBuffer *bloom_accum_fb[MAX_BLOOM_STEP - 1]; struct GPUFrameBuffer *sss_blur_fb; struct GPUFrameBuffer *sss_clear_fb; + struct GPUFrameBuffer *sss_accum_fb; struct GPUFrameBuffer *dof_down_fb; struct GPUFrameBuffer *dof_scatter_far_fb; struct GPUFrameBuffer *dof_scatter_near_fb; @@ -249,6 +251,8 @@ typedef struct EEVEE_TextureList { struct GPUTexture *bloom_blit; /* R16_G16_B16 */ struct GPUTexture *bloom_downsample[MAX_BLOOM_STEP]; /* R16_G16_B16 */ struct GPUTexture *bloom_upsample[MAX_BLOOM_STEP - 1]; /* R16_G16_B16 */ + struct GPUTexture *sss_dir_accum; + struct GPUTexture *sss_col_accum; struct GPUTexture *ssr_normal_input; struct GPUTexture *ssr_specrough_input; struct GPUTexture *ssr_hit_output; @@ -820,10 +824,12 @@ void EEVEE_screen_raytrace_free(void); /* eevee_subsurface.c */ int EEVEE_subsurface_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_subsurface_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); +void EEVEE_subsurface_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_subsurface_add_pass( EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, unsigned int sss_id, struct GPUUniformBuffer *sss_profile); void EEVEE_subsurface_data_render(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_subsurface_compute(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); +void EEVEE_subsurface_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_subsurface_free(void); /* eevee_motion_blur.c */ diff --git a/source/blender/draw/engines/eevee/eevee_render.c b/source/blender/draw/engines/eevee/eevee_render.c index f7ebded2408..e3d6d182053 100644 --- a/source/blender/draw/engines/eevee/eevee_render.c +++ b/source/blender/draw/engines/eevee/eevee_render.c @@ -160,6 +160,51 @@ static void eevee_render_result_combined( DRW_framebuffer_read_data(rr->xof, rr->yof, rr->rectx, rr->recty, 4, 0, rp->rect); } +static void eevee_render_result_subsurface( + RenderResult *rr, const char *viewname, + EEVEE_Data *vedata, EEVEE_ViewLayerData *UNUSED(sldata)) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + ViewLayer *view_layer = draw_ctx->view_layer; + + if ((view_layer->passflag & SCE_PASS_SUBSURFACE_COLOR) != 0) { + RenderLayer *rl = rr->layers.first; + RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_SUBSURFACE_COLOR, viewname); + + IDProperty *props = BKE_view_layer_engine_evaluated_get(view_layer, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_EEVEE); + float render_samples = (float)BKE_collection_engine_property_value_get_int(props, "taa_render_samples"); + + DRW_framebuffer_bind(vedata->fbl->sss_accum_fb); + DRW_framebuffer_read_data(rr->xof, rr->yof, rr->rectx, rr->recty, 3, 1, rp->rect); + + /* This is the accumulated color. Divide by the number of samples. */ + for (int i = 0; i < rr->rectx * rr->recty * 3; i++) { + rp->rect[i] /= render_samples; + } + } + + if ((view_layer->passflag & SCE_PASS_SUBSURFACE_DIRECT) != 0) { + RenderLayer *rl = rr->layers.first; + RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_SUBSURFACE_DIRECT, viewname); + + IDProperty *props = BKE_view_layer_engine_evaluated_get(view_layer, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_EEVEE); + float render_samples = (float)BKE_collection_engine_property_value_get_int(props, "taa_render_samples"); + + DRW_framebuffer_bind(vedata->fbl->sss_accum_fb); + DRW_framebuffer_read_data(rr->xof, rr->yof, rr->rectx, rr->recty, 3, 0, rp->rect); + + /* This is the accumulated color. Divide by the number of samples. */ + for (int i = 0; i < rr->rectx * rr->recty * 3; i++) { + rp->rect[i] /= render_samples; + } + } + + if ((view_layer->passflag & SCE_PASS_SUBSURFACE_INDIRECT) != 0) { + /* Do nothing as all the lighting is in the direct pass. + * TODO : Separate Direct from indirect lighting. */ + } +} + static void eevee_render_result_normal( RenderResult *rr, const char *viewname, EEVEE_Data *vedata, EEVEE_ViewLayerData *UNUSED(sldata)) @@ -253,6 +298,13 @@ void EEVEE_render_draw(EEVEE_Data *vedata, struct RenderEngine *engine, struct D EEVEE_lights_cache_finish(sldata); EEVEE_lightprobes_cache_finish(sldata, vedata); + if ((view_layer->passflag & (SCE_PASS_SUBSURFACE_COLOR | + SCE_PASS_SUBSURFACE_DIRECT | + SCE_PASS_SUBSURFACE_INDIRECT)) != 0) + { + EEVEE_subsurface_output_init(sldata, vedata); + } + /* Init render result. */ const char *viewname = NULL; const float *render_size = DRW_viewport_size_get(); @@ -304,13 +356,12 @@ void EEVEE_render_draw(EEVEE_Data *vedata, struct RenderEngine *engine, struct D /* Effects pre-transparency */ EEVEE_subsurface_compute(sldata, vedata); EEVEE_reflection_compute(sldata, vedata); - EEVEE_occlusion_draw_debug(sldata, vedata); - DRW_draw_pass(psl->probe_display); EEVEE_refraction_compute(sldata, vedata); /* Opaque refraction */ DRW_draw_pass(psl->refract_depth_pass); DRW_draw_pass(psl->refract_depth_pass_cull); DRW_draw_pass(psl->refract_pass); + EEVEE_subsurface_output_accumulate(sldata, vedata); /* Result NORMAL */ eevee_render_result_normal(rr, viewname, vedata, sldata); /* Volumetrics Resolve Opaque */ @@ -324,8 +375,8 @@ void EEVEE_render_draw(EEVEE_Data *vedata, struct RenderEngine *engine, struct D EEVEE_draw_effects(sldata, vedata); } - /* Result Combined */ eevee_render_result_combined(rr, viewname, vedata, sldata); + eevee_render_result_subsurface(rr, viewname, vedata, sldata); RE_engine_end_result(engine, rr, false, false, false); } diff --git a/source/blender/draw/engines/eevee/eevee_subsurface.c b/source/blender/draw/engines/eevee/eevee_subsurface.c index e93e9574acd..4ca1f0f42a1 100644 --- a/source/blender/draw/engines/eevee/eevee_subsurface.c +++ b/source/blender/draw/engines/eevee/eevee_subsurface.c @@ -33,7 +33,7 @@ #include "GPU_texture.h" static struct { - struct GPUShader *sss_sh[3]; + struct GPUShader *sss_sh[4]; } e_data = {NULL}; /* Engine data */ extern char datatoc_common_uniforms_lib_glsl[]; @@ -49,6 +49,9 @@ static void eevee_create_shader_subsurface(void) e_data.sss_sh[1] = DRW_shader_create_fullscreen(frag_str, "#define SECOND_PASS\n"); e_data.sss_sh[2] = DRW_shader_create_fullscreen(frag_str, "#define SECOND_PASS\n" "#define USE_SEP_ALBEDO\n"); + e_data.sss_sh[3] = DRW_shader_create_fullscreen(frag_str, "#define SECOND_PASS\n" + "#define USE_SEP_ALBEDO\n" + "#define RESULT_ACCUM\n"); MEM_freeN(frag_str); } @@ -71,6 +74,11 @@ int EEVEE_subsurface_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) effects->sss_separate_albedo = BKE_collection_engine_property_value_get_bool(props, "sss_separate_albedo"); common_data->sss_jitter_threshold = BKE_collection_engine_property_value_get_float(props, "sss_jitter_threshold"); + /* Force separate albedo for final render */ + if (DRW_state_is_image_render()) { + effects->sss_separate_albedo = true; + } + /* Shaders */ if (!e_data.sss_sh[0]) { eevee_create_shader_subsurface(); @@ -109,6 +117,47 @@ int EEVEE_subsurface_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) return 0; } +static void set_shgrp_stencil(void *UNUSED(userData), DRWShadingGroup *shgrp) +{ + DRW_shgroup_stencil_mask(shgrp, 255); +} + +void EEVEE_subsurface_output_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) +{ + EEVEE_FramebufferList *fbl = vedata->fbl; + EEVEE_TextureList *txl = vedata->txl; + const float *viewport_size = DRW_viewport_size_get(); + + const DRWContextState *draw_ctx = DRW_context_state_get(); + ViewLayer *view_layer = draw_ctx->view_layer; + IDProperty *props = BKE_view_layer_engine_evaluated_get(view_layer, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_EEVEE); + + if (BKE_collection_engine_property_value_get_bool(props, "sss_enable")) { + float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + + DRWFboTexture tex_data[2] = {{&txl->sss_dir_accum, DRW_TEX_RGBA_16, 0}, + {&txl->sss_col_accum, DRW_TEX_RGBA_16, 0}}; + DRW_framebuffer_init(&fbl->sss_accum_fb, &draw_engine_eevee_type, (int)viewport_size[0], (int)viewport_size[1], + tex_data, 2); + + /* Clear texture. */ + DRW_framebuffer_bind(fbl->sss_accum_fb); + DRW_framebuffer_clear(true, false, false, clear, 0.0f); + + /* Make the opaque refraction pass mask the sss. */ + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_CLIP_PLANES | + DRW_STATE_WIRE | DRW_STATE_WRITE_STENCIL; + DRW_pass_state_set(vedata->psl->refract_pass, state); + DRW_pass_foreach_shgroup(vedata->psl->refract_pass, &set_shgrp_stencil, NULL); + } + else { + /* Cleanup to release memory */ + DRW_TEXTURE_FREE_SAFE(txl->sss_dir_accum); + DRW_TEXTURE_FREE_SAFE(txl->sss_col_accum); + DRW_FRAMEBUFFER_FREE_SAFE(fbl->sss_accum_fb); + } +} + void EEVEE_subsurface_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) { EEVEE_PassList *psl = vedata->psl; @@ -121,7 +170,9 @@ void EEVEE_subsurface_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data */ psl->sss_blur_ps = DRW_pass_create("Blur Horiz", DRW_STATE_WRITE_COLOR | DRW_STATE_STENCIL_EQUAL); - psl->sss_resolve_ps = DRW_pass_create("Blur Vert", DRW_STATE_WRITE_COLOR | DRW_STATE_ADDITIVE | DRW_STATE_STENCIL_EQUAL); + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_ADDITIVE | DRW_STATE_STENCIL_EQUAL; + psl->sss_resolve_ps = DRW_pass_create("Blur Vert", state); + psl->sss_accum_ps = DRW_pass_create("Resolve Accum", state); } } @@ -157,6 +208,18 @@ void EEVEE_subsurface_add_pass( if (effects->sss_separate_albedo) { DRW_shgroup_uniform_buffer(grp, "sssAlbedo", &txl->sss_albedo); } + + if (DRW_state_is_image_render()) { + grp = DRW_shgroup_create(e_data.sss_sh[3], psl->sss_accum_ps); + DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); + DRW_shgroup_uniform_buffer(grp, "depthBuffer", &dtxl->depth); + DRW_shgroup_uniform_buffer(grp, "sssData", &txl->sss_blur); + DRW_shgroup_uniform_buffer(grp, "sssAlbedo", &txl->sss_albedo); + DRW_shgroup_uniform_block(grp, "sssProfile", sss_profile); + DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); + DRW_shgroup_stencil_mask(grp, sss_id); + DRW_shgroup_call_add(grp, quad, NULL); + } } void EEVEE_subsurface_data_render(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) @@ -271,9 +334,35 @@ void EEVEE_subsurface_compute(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *v } } +void EEVEE_subsurface_output_accumulate(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) +{ + EEVEE_PassList *psl = vedata->psl; + EEVEE_FramebufferList *fbl = vedata->fbl; + EEVEE_TextureList *txl = vedata->txl; + EEVEE_StorageList *stl = vedata->stl; + EEVEE_EffectsInfo *effects = stl->effects; + + if (((effects->enabled_effects & EFFECT_SSS) != 0) && (fbl->sss_accum_fb != NULL)) { + /* Copy stencil channel, could be avoided (see EEVEE_subsurface_init) */ + DRW_framebuffer_blit(fbl->main, fbl->sss_blur_fb, false, true); + + /* Only do vertical pass + Resolve */ + DRW_framebuffer_texture_detach(txl->sss_stencil); + DRW_framebuffer_texture_attach(fbl->sss_accum_fb, txl->sss_stencil, 0, 0); + DRW_framebuffer_bind(fbl->sss_accum_fb); + DRW_draw_pass(psl->sss_accum_ps); + + /* Restore */ + DRW_framebuffer_texture_detach(txl->sss_stencil); + DRW_framebuffer_texture_attach(fbl->sss_blur_fb, txl->sss_stencil, 0, 0); + DRW_framebuffer_bind(fbl->main); + } +} + void EEVEE_subsurface_free(void) { DRW_SHADER_FREE_SAFE(e_data.sss_sh[0]); DRW_SHADER_FREE_SAFE(e_data.sss_sh[1]); DRW_SHADER_FREE_SAFE(e_data.sss_sh[2]); + DRW_SHADER_FREE_SAFE(e_data.sss_sh[3]); } diff --git a/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl index 184eac54c26..d9e12bcc4bd 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl @@ -18,7 +18,10 @@ uniform sampler2DArray utilTex; #define texelfetch_noise_tex(coord) texelFetch(utilTex, ivec3(ivec2(coord) % LUT_SIZE, 2.0), 0) #endif /* UTIL_TEX */ -out vec4 FragColor; +layout(location = 0) out vec4 FragColor; +#ifdef RESULT_ACCUM +layout(location = 1) out vec4 sssColor; +#endif uniform mat4 ProjectionMatrix; @@ -84,10 +87,15 @@ void main(void) #ifdef FIRST_PASS FragColor = vec4(accum, sss_data.a); #else /* SECOND_PASS */ - #ifdef USE_SEP_ALBEDO +# ifdef USE_SEP_ALBEDO +# ifdef RESULT_ACCUM + FragColor = vec4(accum, 1.0); + sssColor = texture(sssAlbedo, uvs); +# else FragColor = vec4(accum * texture(sssAlbedo, uvs).rgb, 1.0); - #else +# endif +# else FragColor = vec4(accum, 1.0); - #endif +# endif #endif } diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index b9873ff3926..0e8861b48bb 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -1105,6 +1105,7 @@ void DRW_shgroup_state_disable(DRWShadingGroup *shgroup, DRWState state) void DRW_shgroup_stencil_mask(DRWShadingGroup *shgroup, unsigned int mask) { + BLI_assert(mask <= 255); shgroup->stencil_mask = mask; } |