Changeset View
Changeset View
Standalone View
Standalone View
source/blender/draw/engines/gpencil/gpencil_antialiasing.c
| Show All 16 Lines | |||||
| */ | */ | ||||
| /** \file | /** \file | ||||
| * \ingroup draw | * \ingroup draw | ||||
| */ | */ | ||||
| #include "DRW_render.h" | #include "DRW_render.h" | ||||
| #include "BLI_jitter_2d.h" | |||||
| #include "gpencil_engine.h" | #include "gpencil_engine.h" | ||||
| #include "smaa_textures.h" | #include "smaa_textures.h" | ||||
| void GPENCIL_antialiasing_init(struct GPENCIL_Data *vedata) | #define NUM_JITTER_SAMPLES 11 | ||||
| static struct { | |||||
| bool init; | |||||
| float jitter_5[5][2]; | |||||
| float jitter_8[8][2]; | |||||
| float jitter_11[11][2]; | |||||
| float jitter_16[16][2]; | |||||
| } e_data = {false}; | |||||
| static void gpencil_taa_jitter_init_order(float (*table)[2], int num) | |||||
| { | |||||
| BLI_jitter_init(table, num); | |||||
| /* find closest element to center */ | |||||
| int closest_index = 0; | |||||
| float closest_squared_distance = 1.0f; | |||||
| for (int index = 0; index < num; index++) { | |||||
| const float squared_dist = square_f(table[index][0]) + square_f(table[index][1]); | |||||
| if (squared_dist < closest_squared_distance) { | |||||
| closest_squared_distance = squared_dist; | |||||
| closest_index = index; | |||||
| } | |||||
| } | |||||
| /* move jitter table so that closest sample is in center */ | |||||
| for (int index = 0; index < num; index++) { | |||||
| sub_v2_v2(table[index], table[closest_index]); | |||||
| mul_v2_fl(table[index], 2.0f); | |||||
| } | |||||
| /* swap center sample to the start of the table */ | |||||
| if (closest_index != 0) { | |||||
| swap_v2_v2(table[0], table[closest_index]); | |||||
| } | |||||
| /* Sort list based on farthest distance with previous. */ | |||||
| for (int i = 0; i < num - 2; i++) { | |||||
| float f_squared_dist = 0.0; | |||||
| int f_index = i; | |||||
| for (int j = i + 1; j < num; j++) { | |||||
| const float squared_dist = square_f(table[i][0] - table[j][0]) + | |||||
| square_f(table[i][1] - table[j][1]); | |||||
| if (squared_dist > f_squared_dist) { | |||||
| f_squared_dist = squared_dist; | |||||
| f_index = j; | |||||
| } | |||||
| } | |||||
| swap_v2_v2(table[i + 1], table[f_index]); | |||||
| } | |||||
| } | |||||
| static void gpencil_taa_jitter_init(void) | |||||
| { | |||||
| if (e_data.init == false) { | |||||
| e_data.init = true; | |||||
| gpencil_taa_jitter_init_order(e_data.jitter_5, 5); | |||||
| gpencil_taa_jitter_init_order(e_data.jitter_8, 8); | |||||
| gpencil_taa_jitter_init_order(e_data.jitter_11, 11); | |||||
| gpencil_taa_jitter_init_order(e_data.jitter_16, 16); | |||||
| } | |||||
| } | |||||
| int GPENCIL_antialiasing_sample_count_get(GPENCIL_PrivateData *pd) | |||||
| { | |||||
| if (pd->anti_aliasing_mode == GPENCIL_AA_MODE_TAA) { | |||||
| // TODO(jbakker): Make user setting in Render/Grease pencil panel. | |||||
| return NUM_JITTER_SAMPLES; | |||||
| } | |||||
| /* Only draw using SMAA. */ | |||||
| return 1; | |||||
| } | |||||
| static void gpencil_antialiasing_init_simplified(struct GPENCIL_Data *vedata) | |||||
| { | { | ||||
| GPENCIL_PrivateData *pd = vedata->stl->pd; | GPENCIL_PrivateData *pd = vedata->stl->pd; | ||||
| GPENCIL_FramebufferList *fbl = vedata->fbl; | |||||
| GPENCIL_TextureList *txl = vedata->txl; | |||||
| GPENCIL_PassList *psl = vedata->psl; | GPENCIL_PassList *psl = vedata->psl; | ||||
| DRWShadingGroup *grp; | DRWShadingGroup *grp; | ||||
| const float *size = DRW_viewport_size_get(); | const float *size = DRW_viewport_size_get(); | ||||
| const float *sizeinv = DRW_viewport_invert_size_get(); | const float *sizeinv = DRW_viewport_invert_size_get(); | ||||
| const float metrics[4] = {sizeinv[0], sizeinv[1], size[0], size[1]}; | const float metrics[4] = {sizeinv[0], sizeinv[1], size[0], size[1]}; | ||||
| if (pd->simplify_antialias) { | |||||
| /* No AA fallback. */ | /* No AA fallback. */ | ||||
| DRW_PASS_CREATE(psl->smaa_resolve_ps, DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM); | DRW_PASS_CREATE(psl->smaa_resolve_ps, DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM); | ||||
| GPUShader *sh = GPENCIL_shader_antialiasing(2); | GPUShader *sh = GPENCIL_shader_antialiasing(2); | ||||
| grp = DRW_shgroup_create(sh, psl->smaa_resolve_ps); | grp = DRW_shgroup_create(sh, psl->smaa_resolve_ps); | ||||
| DRW_shgroup_uniform_texture(grp, "blendTex", pd->color_tx); | DRW_shgroup_uniform_texture(grp, "blendTex", pd->color_tx); | ||||
| DRW_shgroup_uniform_texture(grp, "colorTex", pd->color_tx); | DRW_shgroup_uniform_texture(grp, "colorTex", pd->color_tx); | ||||
| DRW_shgroup_uniform_texture(grp, "revealTex", pd->reveal_tx); | DRW_shgroup_uniform_texture(grp, "revealTex", pd->reveal_tx); | ||||
| DRW_shgroup_uniform_bool_copy(grp, "doAntiAliasing", false); | DRW_shgroup_uniform_bool_copy(grp, "doAntiAliasing", false); | ||||
| DRW_shgroup_uniform_bool_copy(grp, "onlyAlpha", pd->draw_wireframe); | DRW_shgroup_uniform_bool_copy(grp, "onlyAlpha", pd->draw_wireframe); | ||||
| DRW_shgroup_uniform_vec4_copy(grp, "viewportMetrics", metrics); | DRW_shgroup_uniform_vec4_copy(grp, "viewportMetrics", metrics); | ||||
| DRW_shgroup_call_procedural_triangles(grp, NULL, 1); | DRW_shgroup_call_procedural_triangles(grp, NULL, 1); | ||||
| return; | |||||
| } | } | ||||
| static void gpencil_antialiasing_init_smaa(struct GPENCIL_Data *vedata) | |||||
| { | |||||
| GPENCIL_PrivateData *pd = vedata->stl->pd; | |||||
| GPENCIL_FramebufferList *fbl = vedata->fbl; | |||||
| GPENCIL_TextureList *txl = vedata->txl; | |||||
| GPENCIL_PassList *psl = vedata->psl; | |||||
| DRWShadingGroup *grp; | |||||
| const float *size = DRW_viewport_size_get(); | |||||
| const float *sizeinv = DRW_viewport_invert_size_get(); | |||||
| const float metrics[4] = {sizeinv[0], sizeinv[1], size[0], size[1]}; | |||||
| if (txl->smaa_search_tx == NULL) { | if (txl->smaa_search_tx == NULL) { | ||||
| txl->smaa_search_tx = GPU_texture_create_2d( | txl->smaa_search_tx = GPU_texture_create_2d( | ||||
| "smaa_search", SEARCHTEX_WIDTH, SEARCHTEX_HEIGHT, 1, GPU_R8, NULL); | "smaa_search", SEARCHTEX_WIDTH, SEARCHTEX_HEIGHT, 1, GPU_R8, NULL); | ||||
| GPU_texture_update(txl->smaa_search_tx, GPU_DATA_UBYTE, searchTexBytes); | GPU_texture_update(txl->smaa_search_tx, GPU_DATA_UBYTE, searchTexBytes); | ||||
| txl->smaa_area_tx = GPU_texture_create_2d( | txl->smaa_area_tx = GPU_texture_create_2d( | ||||
| "smaa_area", AREATEX_WIDTH, AREATEX_HEIGHT, 1, GPU_RG8, NULL); | "smaa_area", AREATEX_WIDTH, AREATEX_HEIGHT, 1, GPU_RG8, NULL); | ||||
| GPU_texture_update(txl->smaa_area_tx, GPU_DATA_UBYTE, areaTexBytes); | GPU_texture_update(txl->smaa_area_tx, GPU_DATA_UBYTE, areaTexBytes); | ||||
| ▲ Show 20 Lines • Show All 62 Lines • ▼ Show 20 Lines | if (txl->smaa_search_tx == NULL) { | ||||
| DRW_shgroup_uniform_bool_copy(grp, "doAntiAliasing", true); | DRW_shgroup_uniform_bool_copy(grp, "doAntiAliasing", true); | ||||
| DRW_shgroup_uniform_bool_copy(grp, "onlyAlpha", pd->draw_wireframe); | DRW_shgroup_uniform_bool_copy(grp, "onlyAlpha", pd->draw_wireframe); | ||||
| DRW_shgroup_uniform_vec4_copy(grp, "viewportMetrics", metrics); | DRW_shgroup_uniform_vec4_copy(grp, "viewportMetrics", metrics); | ||||
| DRW_shgroup_call_procedural_triangles(grp, NULL, 1); | DRW_shgroup_call_procedural_triangles(grp, NULL, 1); | ||||
| } | } | ||||
| } | } | ||||
| static float filter_blackman_harris(float x, const float width) | |||||
| { | |||||
| if (x > width * 0.5f) { | |||||
| return 0.0f; | |||||
| } | |||||
| x = 2.0f * M_PI * clamp_f((x / width + 0.5f), 0.0f, 1.0f); | |||||
| return 0.35875f - 0.48829f * cosf(x) + 0.14128f * cosf(2.0f * x) - 0.01168f * cosf(3.0f * x); | |||||
| } | |||||
| /* Compute weights for the 3x3 neighborhood using a 1.5px filter. */ | |||||
| static void gpencil_antialiasing_weights_get(const float offset[2], | |||||
| float r_weights[9], | |||||
| float *r_weight_sum) | |||||
| { | |||||
| /* NOTE: If filter width is bigger than 2.0f, then we need to sample more neighborhood. */ | |||||
| const float filter_width = 2.0f; | |||||
| *r_weight_sum = 0.0f; | |||||
| int i = 0; | |||||
| for (int x = -1; x <= 1; x++) { | |||||
| for (int y = -1; y <= 1; y++, i++) { | |||||
| float sample_co[2] = {x, y}; | |||||
| add_v2_v2(sample_co, offset); | |||||
| float r = len_v2(sample_co); | |||||
| /* fclem: is radial distance ok here? */ | |||||
| float weight = filter_blackman_harris(r, filter_width); | |||||
| *r_weight_sum += weight; | |||||
| r_weights[i] = weight; | |||||
| } | |||||
| } | |||||
| } | |||||
| static void gpencil_antialiasing_init_taa(struct GPENCIL_Data *vedata) | |||||
| { | |||||
| GPENCIL_PrivateData *pd = vedata->stl->pd; | |||||
| GPENCIL_TextureList *txl = vedata->txl; | |||||
| GPENCIL_PassList *psl = vedata->psl; | |||||
| GPENCIL_FramebufferList *fbl = vedata->fbl; | |||||
| DRWShadingGroup *grp; | |||||
| gpencil_taa_jitter_init(); | |||||
| DRW_texture_ensure_fullscreen_2d(&txl->history_buffer_tx, GPU_RGBA16F, 0); | |||||
| DRW_texture_ensure_fullscreen_2d(&txl->depth_buffer_tx, GPU_DEPTH24_STENCIL8, 0); | |||||
| DRW_texture_ensure_fullscreen_2d(&txl->final_depth_buffer_tx, GPU_DEPTH24_STENCIL8, 0); | |||||
| GPU_framebuffer_ensure_config(&fbl->antialiasing_fb, | |||||
| { | |||||
| GPU_ATTACHMENT_NONE, | |||||
| GPU_ATTACHMENT_TEXTURE(txl->history_buffer_tx), | |||||
| }); | |||||
| // Create taa resolve shader. | |||||
| { | |||||
| DRW_PASS_CREATE(psl->taa_accum_ps, DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ADD_FULL); | |||||
| DRW_PASS_INSTANCE_CREATE(psl->taa_accum_replace_ps, psl->taa_accum_ps, DRW_STATE_WRITE_COLOR); | |||||
| GPUShader *shader = GPENCIL_shader_antialiasing_accumulation_get(); | |||||
| grp = DRW_shgroup_create(shader, psl->taa_accum_ps); | |||||
| DRW_shgroup_uniform_texture_ex(grp, "colorBuffer", pd->color_tx, GPU_SAMPLER_DEFAULT); | |||||
| DRW_shgroup_uniform_float(grp, "samplesWeights", pd->taa_weights, 9); | |||||
| DRW_shgroup_call_procedural_triangles(grp, NULL, 1); | |||||
| } | |||||
| { | |||||
| DRW_PASS_CREATE(psl->taa_resolve_ps, DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA); | |||||
| GPUShader *sh = GPENCIL_shader_antialiasing_resolve_get(); | |||||
| grp = DRW_shgroup_create(sh, psl->taa_resolve_ps); | |||||
| DRW_shgroup_uniform_texture(grp, "colorBuffer", txl->history_buffer_tx); | |||||
| DRW_shgroup_uniform_texture(grp, "revealTex", pd->reveal_tx); | |||||
| DRW_shgroup_uniform_float(grp, "taaAccumulatedWeight", &pd->taa_weight_accum, 1); | |||||
| DRW_shgroup_call_procedural_triangles(grp, NULL, 1); | |||||
| } | |||||
| } | |||||
| void GPENCIL_antialiasing_init(struct GPENCIL_Data *vedata) | |||||
| { | |||||
| const GPENCIL_PrivateData *pd = vedata->stl->pd; | |||||
| switch (pd->anti_aliasing_mode) { | |||||
| case GPENCIL_AA_MODE_SIMPLIFIED: | |||||
| gpencil_antialiasing_init_simplified(vedata); | |||||
| break; | |||||
| case GPENCIL_AA_MODE_SMAA: | |||||
| gpencil_antialiasing_init_smaa(vedata); | |||||
| break; | |||||
| case GPENCIL_AA_MODE_TAA: | |||||
| gpencil_antialiasing_init_taa(vedata); | |||||
| break; | |||||
| } | |||||
| } | |||||
| void GPENCIL_antialiasing_setup(GPENCIL_Data *vedata) | |||||
| { | |||||
| GPENCIL_PrivateData *pd = vedata->stl->pd; | |||||
| GPENCIL_TextureList *txl = vedata->txl; | |||||
| const float *viewport_size = DRW_viewport_size_get(); | |||||
| const DRWView *default_view = DRW_view_default_get(); | |||||
| float *transform_offset; | |||||
| switch (pd->taa_sample_len) { | |||||
| default: | |||||
| case 5: | |||||
| transform_offset = e_data.jitter_5[min_ii(pd->taa_sample, 5)]; | |||||
| break; | |||||
| case 8: | |||||
| transform_offset = e_data.jitter_8[min_ii(pd->taa_sample, 8)]; | |||||
| break; | |||||
| case 11: | |||||
| transform_offset = e_data.jitter_11[min_ii(pd->taa_sample, 11)]; | |||||
| break; | |||||
| case 16: | |||||
| transform_offset = e_data.jitter_16[min_ii(pd->taa_sample, 16)]; | |||||
| break; | |||||
| } | |||||
| gpencil_antialiasing_weights_get(transform_offset, pd->taa_weights, &pd->taa_weights_sum); | |||||
| /* construct new matrices from transform delta */ | |||||
| float winmat[4][4], viewmat[4][4], persmat[4][4]; | |||||
| DRW_view_winmat_get(default_view, winmat, false); | |||||
| DRW_view_viewmat_get(default_view, viewmat, false); | |||||
| DRW_view_persmat_get(default_view, persmat, false); | |||||
| window_translate_m4(winmat, | |||||
| persmat, | |||||
| transform_offset[0] / viewport_size[0], | |||||
| transform_offset[1] / viewport_size[1]); | |||||
| if (pd->view) { | |||||
| /* When rendering just update the view. This avoids recomputing the culling. */ | |||||
| DRW_view_update_sub(pd->view, viewmat, winmat); | |||||
| } | |||||
| else { | |||||
| /* TAA is not making a big change to the matrices. | |||||
| * Reuse the main view culling by creating a sub-view. */ | |||||
| pd->view = DRW_view_create_sub(default_view, viewmat, winmat); | |||||
| } | |||||
| DRW_view_set_active(pd->view); | |||||
| const bool is_first_sample = pd->taa_sample == 0; | |||||
| const bool is_second_sample = pd->taa_sample == 1; | |||||
| if (is_first_sample) { | |||||
| GPU_texture_copy(txl->depth_buffer_tx, pd->depth_tx); | |||||
| } | |||||
| else { | |||||
| if (is_second_sample) { | |||||
| GPU_texture_copy(txl->final_depth_buffer_tx, pd->depth_tx); | |||||
| } | |||||
| GPU_texture_copy(pd->depth_tx, txl->depth_buffer_tx); | |||||
| } | |||||
| } | |||||
| void GPENCIL_antialiasing_draw(struct GPENCIL_Data *vedata) | void GPENCIL_antialiasing_draw(struct GPENCIL_Data *vedata) | ||||
| { | { | ||||
| GPENCIL_FramebufferList *fbl = vedata->fbl; | GPENCIL_FramebufferList *fbl = vedata->fbl; | ||||
| GPENCIL_PrivateData *pd = vedata->stl->pd; | GPENCIL_PrivateData *pd = vedata->stl->pd; | ||||
| GPENCIL_TextureList *txl = vedata->txl; | |||||
| GPENCIL_PassList *psl = vedata->psl; | GPENCIL_PassList *psl = vedata->psl; | ||||
| if (!pd->simplify_antialias) { | switch (pd->anti_aliasing_mode) { | ||||
| case GPENCIL_AA_MODE_SIMPLIFIED: | |||||
| GPU_framebuffer_bind(pd->scene_fb); | |||||
| DRW_draw_pass(psl->smaa_resolve_ps); | |||||
| break; | |||||
| case GPENCIL_AA_MODE_SMAA: | |||||
| GPU_framebuffer_bind(fbl->smaa_edge_fb); | GPU_framebuffer_bind(fbl->smaa_edge_fb); | ||||
| DRW_draw_pass(psl->smaa_edge_ps); | DRW_draw_pass(psl->smaa_edge_ps); | ||||
| GPU_framebuffer_bind(fbl->smaa_weight_fb); | GPU_framebuffer_bind(fbl->smaa_weight_fb); | ||||
| DRW_draw_pass(psl->smaa_weight_ps); | DRW_draw_pass(psl->smaa_weight_ps); | ||||
| } | |||||
| GPU_framebuffer_bind(pd->scene_fb); | GPU_framebuffer_bind(pd->scene_fb); | ||||
| DRW_draw_pass(psl->smaa_resolve_ps); | DRW_draw_pass(psl->smaa_resolve_ps); | ||||
| break; | |||||
| case GPENCIL_AA_MODE_TAA: { | |||||
| /* TODO(jbakker): TAA resolve. */ | |||||
| const bool is_first_taa_sample = pd->taa_sample == 0; | |||||
| const bool is_last_taa_sample = pd->taa_sample == pd->taa_sample_len - 1; | |||||
| GPU_framebuffer_bind(fbl->antialiasing_fb); | |||||
| if (is_first_taa_sample) { | |||||
| pd->taa_weight_accum = pd->taa_weights_sum; | |||||
| DRW_draw_pass(psl->taa_accum_replace_ps); | |||||
| } | |||||
| else { | |||||
| DRW_draw_pass(psl->taa_accum_ps); | |||||
| pd->taa_weight_accum += pd->taa_weights_sum; | |||||
| } | |||||
| if (is_last_taa_sample) { | |||||
| // if current sample is last sample, resolve to scene_fb | |||||
| GPU_framebuffer_bind(pd->scene_fb); | |||||
| DRW_draw_pass(psl->taa_resolve_ps); | |||||
| GPU_texture_copy(pd->depth_tx, txl->final_depth_buffer_tx); | |||||
| } | |||||
| break; | |||||
| } | |||||
| } | |||||
| } | } | ||||