Eevee: Render: Add Subsurface Pass support.
This commit is contained in:
parent
a57063a432
commit
253b412ace
|
@ -469,6 +469,12 @@ class VIEWLAYER_PT_eevee_layer_passes(ViewLayerButtonsPanel, Panel):
|
|||
col.prop(view_layer, "use_pass_z")
|
||||
col.prop(view_layer, "use_pass_normal")
|
||||
|
||||
col = split.column()
|
||||
col.label(text="Subsurface:")
|
||||
row = col.row(align=True)
|
||||
row.prop(view_layer, "use_pass_subsurface_direct", text="Direct", toggle=True)
|
||||
row.prop(view_layer, "use_pass_subsurface_color", text="Color", toggle=True)
|
||||
|
||||
|
||||
classes = (
|
||||
VIEWLAYER_UL_viewlayers,
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
FragColor = vec4(accum * texture(sssAlbedo, uvs).rgb, 1.0);
|
||||
#else
|
||||
# ifdef USE_SEP_ALBEDO
|
||||
# ifdef RESULT_ACCUM
|
||||
FragColor = vec4(accum, 1.0);
|
||||
#endif
|
||||
sssColor = texture(sssAlbedo, uvs);
|
||||
# else
|
||||
FragColor = vec4(accum * texture(sssAlbedo, uvs).rgb, 1.0);
|
||||
# endif
|
||||
# else
|
||||
FragColor = vec4(accum, 1.0);
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue