From 606f1d80b39a978f32aaae5a0cd22e18775dd36a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Sun, 1 Mar 2020 23:50:05 +0100 Subject: Workbench: Refactor: Add Shadow support --- .../shaders/workbench_composite_frag.glsl | 2 + .../workbench/shaders/workbench_data_lib.glsl | 5 + .../shaders/workbench_shadow_debug_frag.glsl | 16 +-- .../shaders/workbench_transparent_accum_frag.glsl | 2 + .../shaders/workbench_world_light_lib.glsl | 10 ++ .../draw/engines/workbench/workbench_data.c | 55 +++++----- .../draw/engines/workbench/workbench_deferred.c | 14 +-- .../draw/engines/workbench/workbench_engine.c | 78 ++++++++++---- .../draw/engines/workbench/workbench_materials.c | 27 +++-- .../draw/engines/workbench/workbench_opaque.c | 25 +++-- .../draw/engines/workbench/workbench_private.h | 49 +++++++-- .../draw/engines/workbench/workbench_shader.c | 50 +++++++++ .../draw/engines/workbench/workbench_shadow.c | 114 ++++++++++++++++++++- .../draw/engines/workbench/workbench_studiolight.c | 9 +- .../draw/engines/workbench/workbench_transparent.c | 1 + source/blender/draw/intern/draw_hair.c | 2 +- 16 files changed, 364 insertions(+), 95 deletions(-) diff --git a/source/blender/draw/engines/workbench/shaders/workbench_composite_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_composite_frag.glsl index 0616043aef0..cdb9823096c 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_composite_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_composite_frag.glsl @@ -38,5 +38,7 @@ void main() fragColor.rgb = base_color; #endif + fragColor.rgb *= get_shadow(N); + fragColor.a = 1.0; } diff --git a/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl index 83ee73b00d8..75fde40bc94 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl @@ -9,6 +9,11 @@ struct WorldData { vec4 viewport_size; vec4 object_outline_color; vec4 shadow_direction_vs; + float shadow_focus; + float shadow_shift; + float shadow_mul; + float shadow_add; + /* - 16 bytes alignment- */ LightData lights[4]; vec4 ambient_color; int matcap_orientation; diff --git a/source/blender/draw/engines/workbench/shaders/workbench_shadow_debug_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_shadow_debug_frag.glsl index 6b0741b6d1b..6fa76510e6e 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_shadow_debug_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_shadow_debug_frag.glsl @@ -1,15 +1,19 @@ out vec4 fragColor; +layout(location = 0) out vec4 materialData; +layout(location = 1) out vec4 normalData; +layout(location = 2) out uint objectId; + void main() { - const float intensity = 0.25; + const float a = 0.25; #ifdef SHADOW_PASS - fragColor = vec4( - (gl_FrontFacing) ? vec3(intensity, -intensity, 0.0) : vec3(-intensity, intensity, 0.0), 1.0); + materialData.rgb = gl_FrontFacing ? vec3(a, -a, 0.0) : vec3(-a, a, 0.0); #else - fragColor = vec4((gl_FrontFacing) ? vec3(intensity, intensity, -intensity) : - vec3(-intensity, -intensity, intensity), - 1.0); + materialData.rgb = gl_FrontFacing ? vec3(a, a, -a) : vec3(-a, -a, a); #endif + materialData.a = 0.0; + normalData = vec4(0.0); + objectId = 0u; } diff --git a/source/blender/draw/engines/workbench/shaders/workbench_transparent_accum_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_transparent_accum_frag.glsl index e1b031e7294..7113b998fa7 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_transparent_accum_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_transparent_accum_frag.glsl @@ -79,6 +79,8 @@ void main() vec3 shaded_color = color; #endif + shaded_color *= get_shadow(N); + /* Listing 4 */ float weight = calculate_transparent_weight() * alpha_interp; transparentAccum = vec4(shaded_color * weight, alpha_interp); diff --git a/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl index e7c94c9b955..1c966a9e47c 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl @@ -121,3 +121,13 @@ vec3 get_world_lighting(vec3 base_color, float roughness, float metallic, vec3 N return diffuse_light + specular_light; } + +uniform bool forceShadowing = false; + +float get_shadow(vec3 N) +{ + float light_factor = -dot(N, world_data.shadow_direction_vs.xyz); + float shadow_mix = smoothstep(world_data.shadow_shift, world_data.shadow_focus, light_factor); + shadow_mix *= forceShadowing ? 0.0 : world_data.shadow_mul; + return shadow_mix + world_data.shadow_add; +} \ No newline at end of file diff --git a/source/blender/draw/engines/workbench/workbench_data.c b/source/blender/draw/engines/workbench/workbench_data.c index ad5eaff2392..937c6a33319 100644 --- a/source/blender/draw/engines/workbench/workbench_data.c +++ b/source/blender/draw/engines/workbench/workbench_data.c @@ -79,17 +79,44 @@ static WORKBENCH_ViewLayerData *workbench_view_layer_data_ensure_ex(struct ViewL return *vldata; } -static void workbench_world_data_update_shadow_direction_vs(WORKBENCH_PrivateData *wpd) +void workbench_private_data_get_light_direction(float r_light_direction[3]) { + const DRWContextState *draw_ctx = DRW_context_state_get(); + Scene *scene = draw_ctx->scene; + + copy_v3_v3(r_light_direction, scene->display.light_direction); + SWAP(float, r_light_direction[2], r_light_direction[1]); + r_light_direction[2] = -r_light_direction[2]; + r_light_direction[0] = -r_light_direction[0]; +} + +static void workbench_shadow_world_data_update(WORKBENCH_PrivateData *wpd) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + const Scene *scene = draw_ctx->scene; + WORKBENCH_UBO_World *wd = &wpd->world_data; - float light_direction[3]; float view_matrix[4][4]; DRW_view_viewmat_get(NULL, view_matrix, false); - workbench_private_data_get_light_direction(light_direction); + workbench_private_data_get_light_direction(wpd->light_direction_ws); /* Shadow direction. */ - mul_v3_mat3_m4v3(wd->shadow_direction_vs, view_matrix, light_direction); + mul_v3_mat3_m4v3(wd->shadow_direction_vs, view_matrix, wpd->light_direction_ws); + + /* Clamp to avoid overshadowing and shading errors. */ + float focus = clamp_f(scene->display.shadow_focus, 0.0001f, 0.99999f); + wd->shadow_shift = scene->display.shadow_shift; + wd->shadow_focus = 1.0f - focus * (1.0f - wd->shadow_shift); + + if (SHADOW_ENABLED(wpd)) { + wd->shadow_mul = wpd->shading.shadow_intensity; + wd->shadow_add = 1.0f - wd->shadow_mul; + } + else { + wd->shadow_mul = 0.0f; + wd->shadow_add = 1.0f; + } } /* \} */ @@ -205,13 +232,6 @@ void workbench_private_data_init(WORKBENCH_PrivateData *wpd) wpd->studio_light = BKE_studiolight_find(wpd->shading.studio_light, STUDIOLIGHT_TYPE_STUDIO); } - float shadow_focus = scene->display.shadow_focus; - /* Clamp to avoid overshadowing and shading errors. */ - CLAMP(shadow_focus, 0.0001f, 0.99999f); - wpd->shadow_shift = scene->display.shadow_shift; - wpd->shadow_focus = 1.0f - shadow_focus * (1.0f - wpd->shadow_shift); - wpd->shadow_multiplier = 1.0 - wpd->shading.shadow_intensity; - WORKBENCH_UBO_World *wd = &wpd->world_data; wd->matcap_orientation = (wpd->shading.flag & V3D_SHADING_MATCAP_FLIP_X) != 0; @@ -227,7 +247,7 @@ void workbench_private_data_init(WORKBENCH_PrivateData *wpd) wd->curvature_ridge = 0.5f / max_ff(SQUARE(wpd->shading.curvature_ridge_factor), 1e-4f); wd->curvature_valley = 0.7f / max_ff(SQUARE(wpd->shading.curvature_valley_factor), 1e-4f); - workbench_world_data_update_shadow_direction_vs(wpd); + workbench_shadow_world_data_update(wpd); workbench_viewvecs_update(wpd->world_data.viewvecs); copy_v2_v2(wpd->world_data.viewport_size, DRW_viewport_size_get()); copy_v2_v2(wpd->world_data.viewport_size_inv, DRW_viewport_invert_size_get()); @@ -296,17 +316,6 @@ void workbench_private_data_init(WORKBENCH_PrivateData *wpd) BLI_listbase_clear(&wpd->smoke_domains); } -void workbench_private_data_get_light_direction(float r_light_direction[3]) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - Scene *scene = draw_ctx->scene; - - copy_v3_v3(r_light_direction, scene->display.light_direction); - SWAP(float, r_light_direction[2], r_light_direction[1]); - r_light_direction[2] = -r_light_direction[2]; - r_light_direction[0] = -r_light_direction[0]; -} - void workbench_update_material_ubos(WORKBENCH_PrivateData *UNUSED(wpd)) { const DRWContextState *draw_ctx = DRW_context_state_get(); diff --git a/source/blender/draw/engines/workbench/workbench_deferred.c b/source/blender/draw/engines/workbench/workbench_deferred.c index f1528c2213c..4bd0e663650 100644 --- a/source/blender/draw/engines/workbench/workbench_deferred.c +++ b/source/blender/draw/engines/workbench/workbench_deferred.c @@ -334,12 +334,6 @@ static struct GPUTexture *create_jitter_texture(int num_samples) } /* Functions */ -static void workbench_init_object_data(DrawData *dd) -{ - WORKBENCH_ObjectData *data = (WORKBENCH_ObjectData *)dd; - data->shadow_bbox_dirty = true; -} - static void workbench_init_oit_framebuffer(WORKBENCH_FramebufferList *fbl, DefaultTextureList *dtxl) { @@ -732,7 +726,7 @@ void workbench_deferred_cache_init(WORKBENCH_Data *vedata) /* Deferred Mix Pass */ { workbench_private_data_get_light_direction(e_data.display.light_direction); - studiolight_update_light(wpd, e_data.display.light_direction); + studiolight_update_light(wpd); if (SHADOW_ENABLED(wpd)) { psl->composite_pass = DRW_pass_create( @@ -1161,11 +1155,7 @@ void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob) } else { WORKBENCH_ObjectData *engine_object_data = (WORKBENCH_ObjectData *)DRW_drawdata_ensure( - &ob->id, - &draw_engine_workbench_solid, - sizeof(WORKBENCH_ObjectData), - &workbench_init_object_data, - NULL); + &ob->id, &draw_engine_workbench_solid, sizeof(WORKBENCH_ObjectData), NULL, NULL); if (studiolight_object_cast_visible_shadow(wpd, ob, engine_object_data)) { diff --git a/source/blender/draw/engines/workbench/workbench_engine.c b/source/blender/draw/engines/workbench/workbench_engine.c index 06a8508c997..ac0a4e6221a 100644 --- a/source/blender/draw/engines/workbench/workbench_engine.c +++ b/source/blender/draw/engines/workbench/workbench_engine.c @@ -82,6 +82,7 @@ static void workbench_cache_init(void *ved) workbench_opaque_cache_init(vedata); workbench_transparent_cache_init(vedata); + workbench_shadow_cache_init(vedata); // workbench_aa_create_pass(vedata); // workbench_dof_create_pass(vedata); @@ -105,14 +106,14 @@ static void workbench_cache_sculpt_populate(WORKBENCH_PrivateData *wpd, Object * BLI_assert(wpd->shading.color_type != V3D_SHADING_TEXTURE_COLOR); if (use_single_drawcall) { - DRWShadingGroup *grp = workbench_material_setup(wpd, ob, 0, color_type, false); + DRWShadingGroup *grp = workbench_material_setup(wpd, ob, 0, color_type, NULL); DRW_shgroup_call_sculpt(grp, ob, false, false, use_vcol); } else { const int materials_len = DRW_cache_object_material_count_get(ob); struct DRWShadingGroup **shgrps = BLI_array_alloca(shgrps, materials_len); for (int i = 0; i < materials_len; i++) { - shgrps[i] = workbench_material_setup(wpd, ob, i + 1, color_type, false); + shgrps[i] = workbench_material_setup(wpd, ob, i + 1, color_type, NULL); } DRW_shgroup_call_sculpt_with_materials(shgrps, ob, false); } @@ -132,7 +133,7 @@ static void workbench_cache_texpaint_populate(WORKBENCH_PrivateData *wpd, Object int interp = (imapaint->interp == IMAGEPAINT_INTERP_LINEAR) ? SHD_INTERP_LINEAR : SHD_INTERP_CLOSEST; - DRWShadingGroup *grp = workbench_image_setup(wpd, ob, 0, ima, NULL, interp, false); + DRWShadingGroup *grp = workbench_image_setup(wpd, ob, 0, ima, NULL, interp); DRW_shgroup_call(grp, geom, ob); } } @@ -141,14 +142,17 @@ static void workbench_cache_texpaint_populate(WORKBENCH_PrivateData *wpd, Object if (geoms) { const int materials_len = DRW_cache_object_material_count_get(ob); for (int i = 0; i < materials_len; i++) { - DRWShadingGroup *grp = workbench_image_setup(wpd, ob, i + 1, NULL, NULL, 0, false); + DRWShadingGroup *grp = workbench_image_setup(wpd, ob, i + 1, NULL, NULL, 0); DRW_shgroup_call(grp, geoms[i], ob); } } } } -static void workbench_cache_common_populate(WORKBENCH_PrivateData *wpd, Object *ob, int color_type) +static void workbench_cache_common_populate(WORKBENCH_PrivateData *wpd, + Object *ob, + int color_type, + bool *r_transp) { const bool use_tex = ELEM(color_type, V3D_SHADING_TEXTURE_COLOR); const bool use_vcol = ELEM(color_type, V3D_SHADING_VERTEX_COLOR); @@ -159,7 +163,7 @@ static void workbench_cache_common_populate(WORKBENCH_PrivateData *wpd, Object * struct GPUBatch *geom = (use_vcol) ? DRW_cache_mesh_surface_vertpaint_get(ob) : DRW_cache_object_surface_get(ob); if (geom) { - DRWShadingGroup *grp = workbench_material_setup(wpd, ob, 0, color_type, false); + DRWShadingGroup *grp = workbench_material_setup(wpd, ob, 0, color_type, r_transp); DRW_shgroup_call(grp, geom, ob); } } @@ -169,7 +173,7 @@ static void workbench_cache_common_populate(WORKBENCH_PrivateData *wpd, Object * if (geoms) { const int materials_len = DRW_cache_object_material_count_get(ob); for (int i = 0; i < materials_len; i++) { - DRWShadingGroup *grp = workbench_material_setup(wpd, ob, i + 1, color_type, false); + DRWShadingGroup *grp = workbench_material_setup(wpd, ob, i + 1, color_type, r_transp); DRW_shgroup_call(grp, geoms[i], ob); } } @@ -192,8 +196,8 @@ static void workbench_cache_hair_populate(WORKBENCH_PrivateData *wpd, int interp = (imapaint && imapaint->interp == IMAGEPAINT_INTERP_LINEAR) ? SHD_INTERP_LINEAR : SHD_INTERP_CLOSEST; DRWShadingGroup *grp = (use_texpaint_mode) ? - workbench_image_setup(wpd, ob, part->omat, ima, NULL, interp, true) : - workbench_material_setup(wpd, ob, part->omat, color_type, true); + workbench_image_hair_setup(wpd, ob, part->omat, ima, NULL, interp) : + workbench_material_hair_setup(wpd, ob, part->omat, color_type); DRW_shgroup_hair_create_sub(ob, psys, md, grp); } @@ -203,7 +207,8 @@ static void workbench_cache_hair_populate(WORKBENCH_PrivateData *wpd, static int workbench_color_type_get(WORKBENCH_PrivateData *wpd, Object *ob, bool *r_sculpt_pbvh, - bool *r_texpaint_mode) + bool *r_texpaint_mode, + bool *r_draw_shadow) { int color_type = wpd->shading.color_type; const Mesh *me = (ob->type == OB_MESH) ? ob->data : NULL; @@ -241,6 +246,20 @@ static int workbench_color_type_get(WORKBENCH_PrivateData *wpd, } } + if (r_draw_shadow) { + *r_draw_shadow = (ob->dtx & OB_DRAW_NO_SHADOW_CAST) == 0 && SHADOW_ENABLED(wpd); + /* Currently unsupported in sculpt mode. We could revert to the slow + * method in this case but I'm not sure if it's a good idea given that + * sculpted meshes are heavy to begin with. */ + if (is_sculpt_pbvh) { + *r_draw_shadow = false; + } + + if (is_active && DRW_object_use_hide_faces(ob)) { + *r_draw_shadow = false; + } + } + return color_type; } @@ -256,9 +275,9 @@ static void workbench_cache_populate(void *ved, Object *ob) if (ob->type == OB_MESH && ob->modifiers.first != NULL) { bool use_sculpt_pbvh, use_texpaint_mode; - int color_type = workbench_color_type_get(wpd, ob, &use_sculpt_pbvh, &use_texpaint_mode); + int color_type = workbench_color_type_get(wpd, ob, &use_sculpt_pbvh, &use_texpaint_mode, NULL); - for (ModifierData *md = ob->modifiers.first; md; md = md->next) { + LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) { if (md->type != eModifierType_ParticleSystem) { continue; } @@ -286,8 +305,9 @@ static void workbench_cache_populate(void *ved, Object *ob) } if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL)) { - bool use_sculpt_pbvh, use_texpaint_mode; - int color_type = workbench_color_type_get(wpd, ob, &use_sculpt_pbvh, &use_texpaint_mode); + bool use_sculpt_pbvh, use_texpaint_mode, draw_shadow, has_transp_mat = false; + int color_type = workbench_color_type_get( + wpd, ob, &use_sculpt_pbvh, &use_texpaint_mode, &draw_shadow); if (use_sculpt_pbvh) { workbench_cache_sculpt_populate(wpd, ob, color_type); @@ -296,7 +316,11 @@ static void workbench_cache_populate(void *ved, Object *ob) workbench_cache_texpaint_populate(wpd, ob); } else { - workbench_cache_common_populate(wpd, ob, color_type); + workbench_cache_common_populate(wpd, ob, color_type, &has_transp_mat); + } + + if (draw_shadow) { + workbench_shadow_cache_populate(vedata, ob, has_transp_mat); } } } @@ -372,10 +396,13 @@ static void workbench_draw_scene(void *ved) { GPU_framebuffer_bind(fbl->opaque_fb); + GPU_framebuffer_clear_stencil(fbl->opaque_fb, 0x00); DRW_draw_pass(psl->opaque_pass); - /* TODO(fclem) shadows */ - // DRW_draw_pass(psl->shadow_pass); + if (psl->shadow_pass[0]) { + DRW_draw_pass(psl->shadow_pass[0]); + DRW_draw_pass(psl->shadow_pass[1]); + } { GPU_framebuffer_bind(fbl->opaque_infront_fb); @@ -388,9 +415,6 @@ static void workbench_draw_scene(void *ved) GPU_framebuffer_bind(dfbl->default_fb); DRW_draw_pass(psl->composite_pass); - /* TODO(fclem) shadows : render shadowed areas */ - // DRW_draw_pass(psl->composite_shadow_pass); - /* TODO(fclem) ambient occlusion */ // GPU_framebuffer_bind(dfbl->color_only_fb); // DRW_draw_pass(psl->ambient_occlusion_pass); @@ -433,6 +457,18 @@ static void workbench_view_update(void *UNUSED(ved)) { } +static void workbench_id_update(void *UNUSED(vedata), struct ID *id) +{ + if (GS(id->name) == ID_OB) { + WORKBENCH_ObjectData *oed = (WORKBENCH_ObjectData *)DRW_drawdata_get( + id, &draw_engine_workbench_solid); + if (oed != NULL && oed->dd.recalc != 0) { + oed->shadow_bbox_dirty = (oed->dd.recalc & ID_RECALC_ALL) != 0; + oed->dd.recalc = 0; + } + } +} + static const DrawEngineDataSize workbench_data_size = DRW_VIEWPORT_DATA_SIZE(WORKBENCH_Data); DrawEngineType draw_engine_workbench = { @@ -447,7 +483,7 @@ DrawEngineType draw_engine_workbench = { &workbench_cache_finish, &workbench_draw_scene, &workbench_view_update, - NULL, + &workbench_id_update, NULL, }; diff --git a/source/blender/draw/engines/workbench/workbench_materials.c b/source/blender/draw/engines/workbench/workbench_materials.c index 2aeaee646e9..60349cd567b 100644 --- a/source/blender/draw/engines/workbench/workbench_materials.c +++ b/source/blender/draw/engines/workbench/workbench_materials.c @@ -466,8 +466,8 @@ static bool workbench_material_chunk_select(WORKBENCH_PrivateData *wpd, uint32_t return resource_changed; } -DRWShadingGroup *workbench_material_setup( - WORKBENCH_PrivateData *wpd, Object *ob, int mat_nr, int color_type, bool hair) +DRWShadingGroup *workbench_material_setup_ex( + WORKBENCH_PrivateData *wpd, Object *ob, int mat_nr, int color_type, bool hair, bool *r_transp) { Image *ima = NULL; ImageUser *iuser = NULL; @@ -484,7 +484,7 @@ DRWShadingGroup *workbench_material_setup( switch (color_type) { case V3D_SHADING_TEXTURE_COLOR: { - return workbench_image_setup(wpd, ob, mat_nr, ima, iuser, interp, hair); + return workbench_image_setup_ex(wpd, ob, mat_nr, ima, iuser, interp, hair); } case V3D_SHADING_MATERIAL_COLOR: { /* For now, we use the same ubo for material and object coloring but with different indices. @@ -497,6 +497,10 @@ DRWShadingGroup *workbench_material_setup( const bool transp = wpd->shading.xray_alpha < 1.0f || ma->a < 1.0f; WORKBENCH_Prepass *prepass = &wpd->prepass[transp][infront][hair]; + if (r_transp && transp) { + *r_transp = true; + } + DRWShadingGroup **grp_mat = NULL; /* A hashmap stores material shgroups to pack all similar drawcalls together. */ if (BLI_ghash_ensure_p(prepass->material_hash, ma, (void ***)&grp_mat)) { @@ -536,19 +540,22 @@ DRWShadingGroup *workbench_material_setup( grp = DRW_shgroup_create_sub(grp); DRW_shgroup_uniform_block(grp, "material_block", wpd->material_ubo_curr); } + if (r_transp && transp) { + *r_transp = true; + } return grp; } } } /* If ima is null, search appropriate image node but will fallback to purple texture otherwise. */ -DRWShadingGroup *workbench_image_setup(WORKBENCH_PrivateData *wpd, - Object *ob, - int mat_nr, - Image *ima, - ImageUser *iuser, - int interp, - bool hair) +DRWShadingGroup *workbench_image_setup_ex(WORKBENCH_PrivateData *wpd, + Object *ob, + int mat_nr, + Image *ima, + ImageUser *iuser, + int interp, + bool hair) { GPUTexture *tex = NULL, *tex_tile_data = NULL; diff --git a/source/blender/draw/engines/workbench/workbench_opaque.c b/source/blender/draw/engines/workbench/workbench_opaque.c index d9c4c5a80a9..b968f257007 100644 --- a/source/blender/draw/engines/workbench/workbench_opaque.c +++ b/source/blender/draw/engines/workbench/workbench_opaque.c @@ -114,17 +114,18 @@ void workbench_opaque_cache_init(WORKBENCH_Data *data) } } { - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_GREATER; + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_GREATER | DRW_STATE_STENCIL_EQUAL; DRW_PASS_CREATE(psl->composite_pass, state); sh = workbench_shader_composite_get(wpd); grp = DRW_shgroup_create(sh, psl->composite_pass); + DRW_shgroup_uniform_block_persistent(grp, "world_block", wpd->world_ubo); + DRW_shgroup_uniform_texture_persistent(grp, "materialBuffer", wpd->material_buffer_tx); + DRW_shgroup_uniform_texture_persistent(grp, "normalBuffer", wpd->normal_buffer_tx); + DRW_shgroup_uniform_bool_copy(grp, "forceShadowing", false); DRW_shgroup_stencil_mask(grp, 0x00); - DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo); - DRW_shgroup_uniform_texture(grp, "materialBuffer", wpd->material_buffer_tx); - DRW_shgroup_uniform_texture(grp, "normalBuffer", wpd->normal_buffer_tx); const bool use_spec = workbench_is_specular_highlight_enabled(wpd); @@ -134,14 +135,24 @@ void workbench_opaque_cache_init(WORKBENCH_Data *data) STUDIOLIGHT_MATCAP_SPECULAR_GPUTEXTURE); struct GPUTexture *diff_tx = wpd->studio_light->matcap_diffuse.gputexture; struct GPUTexture *spec_tx = wpd->studio_light->matcap_specular.gputexture; - DRW_shgroup_uniform_texture(grp, "matcapDiffuseImage", diff_tx); - DRW_shgroup_uniform_texture(grp, "matcapSpecularImage", use_spec ? spec_tx : diff_tx); + spec_tx = use_spec ? spec_tx : diff_tx; + DRW_shgroup_uniform_texture_persistent(grp, "matcapDiffuseImage", diff_tx); + DRW_shgroup_uniform_texture_persistent(grp, "matcapSpecularImage", spec_tx); DRW_shgroup_uniform_bool_copy(grp, "useSpecularMatcap", use_spec); } else if (STUDIOLIGHT_TYPE_STUDIO_ENABLED(wpd)) { DRW_shgroup_uniform_bool_copy(grp, "useSpecularLighting", use_spec); } DRW_shgroup_call_procedural_triangles(grp, NULL, 1); + + if (true) { + grp = DRW_shgroup_create_sub(grp); + DRW_shgroup_uniform_bool_copy(grp, "forceShadowing", true); + DRW_shgroup_state_disable(grp, DRW_STATE_STENCIL_EQUAL); + DRW_shgroup_state_enable(grp, DRW_STATE_STENCIL_NEQUAL); + DRW_shgroup_stencil_mask(grp, 0x00); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); + } } { DRWState state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS | DRW_STATE_WRITE_STENCIL | @@ -152,8 +163,8 @@ void workbench_opaque_cache_init(WORKBENCH_Data *data) sh = workbench_shader_merge_infront_get(wpd); grp = DRW_shgroup_create(sh, psl->merge_infront_pass); - DRW_shgroup_stencil_mask(grp, 0x00); DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth_in_front); + DRW_shgroup_stencil_mask(grp, 0x00); DRW_shgroup_call_procedural_triangles(grp, NULL, 1); } } diff --git a/source/blender/draw/engines/workbench/workbench_private.h b/source/blender/draw/engines/workbench/workbench_private.h index 90c1908100f..155deba8380 100644 --- a/source/blender/draw/engines/workbench/workbench_private.h +++ b/source/blender/draw/engines/workbench/workbench_private.h @@ -34,6 +34,8 @@ #include "workbench_engine.h" +extern struct DrawEngineType draw_engine_workbench; + #define WORKBENCH_ENGINE "BLENDER_WORKBENCH" /* TODO put them in workbench_shader.c */ #define MAX_COMPOSITE_SHADERS 3 @@ -42,6 +44,8 @@ #define MAX_CAVITY_SHADERS (1 << 3) #define MAX_MATERIAL (1 << 12) +#define DEBUG_SHADOW_VOLUME 0 + #define TEXTURE_DRAWING_ENABLED(wpd) (wpd->shading.color_type == V3D_SHADING_TEXTURE_COLOR) #define VERTEX_COLORS_ENABLED(wpd) (wpd->shading.color_type == V3D_SHADING_VERTEX_COLOR) #define MATERIAL_COLORS_ENABLED(wpd) (wpd->shading.color_type == V3D_SHADING_MATERIAL_COLOR) @@ -143,6 +147,7 @@ typedef struct WORKBENCH_PassList { /* deferred rendering */ struct DRWPass *opaque_pass; struct DRWPass *opaque_infront_pass; + struct DRWPass *shadow_pass[2]; struct DRWPass *merge_infront_pass; struct DRWPass *prepass_pass; struct DRWPass *prepass_hair_pass; @@ -207,6 +212,7 @@ typedef struct WORKBENCH_UBO_World { float viewport_size[2], viewport_size_inv[2]; float object_outline_color[4]; float shadow_direction_vs[4]; + float shadow_focus, shadow_shift, shadow_mul, shadow_add; WORKBENCH_UBO_Light lights[4]; float ambient_color[4]; int matcap_orientation; @@ -299,6 +305,12 @@ typedef struct WORKBENCH_PrivateData { int material_chunk_curr; int material_index; + /* Shadow */ + struct DRWShadingGroup *shadow_pass_grp[2]; + struct DRWShadingGroup *shadow_fail_grp[2]; + struct DRWShadingGroup *shadow_fail_caps_grp[2]; + float light_direction_ws[3]; + /* Volumes */ bool volumes_do; ListBase smoke_domains; @@ -493,6 +505,10 @@ void workbench_opaque_cache_init(WORKBENCH_Data *data); void workbench_transparent_engine_init(WORKBENCH_Data *data); void workbench_transparent_cache_init(WORKBENCH_Data *data); +/* workbench_shadow.c */ +void workbench_shadow_cache_init(WORKBENCH_Data *data); +void workbench_shadow_cache_populate(WORKBENCH_Data *data, Object *ob, const bool has_transp_mat); + /* workbench_shader.c */ GPUShader *workbench_shader_opaque_get(WORKBENCH_PrivateData *wpd, bool hair); GPUShader *workbench_shader_opaque_image_get(WORKBENCH_PrivateData *wpd, bool hair, bool tiled); @@ -505,6 +521,9 @@ GPUShader *workbench_shader_transparent_image_get(WORKBENCH_PrivateData *wpd, bool tiled); GPUShader *workbench_shader_transparent_resolve_get(WORKBENCH_PrivateData *wpd); +GPUShader *workbench_shader_shadow_pass_get(bool manifold); +GPUShader *workbench_shader_shadow_fail_get(bool manifold, bool cap); + void workbench_shader_library_ensure(void); void workbench_shader_free(void); @@ -609,21 +628,31 @@ void workbench_material_ubo_data(WORKBENCH_PrivateData *wpd, WORKBENCH_UBO_Material *data, int color_type); -DRWShadingGroup *workbench_material_setup( - WORKBENCH_PrivateData *wpd, Object *ob, int mat_nr, int color_type, bool hair); -DRWShadingGroup *workbench_image_setup(WORKBENCH_PrivateData *wpd, - Object *ob, - int mat_nr, - Image *ima, - ImageUser *iuser, - int interp, - bool hair); +DRWShadingGroup *workbench_material_setup_ex( + WORKBENCH_PrivateData *wpd, Object *ob, int mat_nr, int color_type, bool hair, bool *r_transp); +DRWShadingGroup *workbench_image_setup_ex(WORKBENCH_PrivateData *wpd, + Object *ob, + int mat_nr, + Image *ima, + ImageUser *iuser, + int interp, + bool hair); + +#define workbench_material_setup(wpd, ob, mat_nr, color_type, r_transp) \ + workbench_material_setup_ex(wpd, ob, mat_nr, color_type, false, r_transp) +#define workbench_image_setup(wpd, ob, mat_nr, ima, iuser, interp) \ + workbench_image_setup_ex(wpd, ob, mat_nr, ima, iuser, interp, false) + +#define workbench_material_hair_setup(wpd, ob, mat_nr, color_type) \ + workbench_material_setup_ex(wpd, ob, mat_nr, color_type, true, 0) +#define workbench_image_hair_setup(wpd, ob, mat_nr, ima, iuser, interp) \ + workbench_image_setup_ex(wpd, ob, mat_nr, ima, iuser, interp, true) /* workbench_studiolight.c */ void studiolight_update_world(WORKBENCH_PrivateData *wpd, StudioLight *sl, WORKBENCH_UBO_World *wd); -void studiolight_update_light(WORKBENCH_PrivateData *wpd, const float light_direction[3]); +void studiolight_update_light(WORKBENCH_PrivateData *wpd); bool studiolight_object_cast_visible_shadow(WORKBENCH_PrivateData *wpd, Object *ob, WORKBENCH_ObjectData *oed); diff --git a/source/blender/draw/engines/workbench/workbench_shader.c b/source/blender/draw/engines/workbench/workbench_shader.c index bc769001f8c..3470d42608e 100644 --- a/source/blender/draw/engines/workbench/workbench_shader.c +++ b/source/blender/draw/engines/workbench/workbench_shader.c @@ -33,6 +33,7 @@ extern char datatoc_common_view_lib_glsl[]; extern char datatoc_workbench_prepass_vert_glsl[]; extern char datatoc_workbench_prepass_hair_vert_glsl[]; extern char datatoc_workbench_prepass_frag_glsl[]; + // extern char datatoc_workbench_cavity_frag_glsl[]; // extern char datatoc_workbench_forward_composite_frag_glsl[]; // extern char datatoc_workbench_deferred_composite_frag_glsl[]; @@ -77,6 +78,9 @@ static struct { struct GPUShader *oit_resolve_sh; struct GPUShader *merge_infront_sh; + struct GPUShader *shadow_depth_pass_sh[2]; + struct GPUShader *shadow_depth_fail_sh[2][2]; + struct DRWShaderLibrary *lib; } e_data = {{{{NULL}}}}; @@ -241,6 +245,44 @@ GPUShader *workbench_shader_transparent_resolve_get(WORKBENCH_PrivateData *wpd) return e_data.oit_resolve_sh; } +static GPUShader *workbench_shader_shadow_pass_get_ex(bool depth_pass, bool manifold, bool cap) +{ + struct GPUShader **shader = (depth_pass) ? &e_data.shadow_depth_pass_sh[manifold] : + &e_data.shadow_depth_fail_sh[manifold][cap]; + + if (*shader == NULL) { +#if DEBUG_SHADOW_VOLUME + const char *shadow_frag = datatoc_workbench_shadow_debug_frag_glsl; +#else + const char *shadow_frag = datatoc_gpu_shader_depth_only_frag_glsl; +#endif + + *shader = GPU_shader_create_from_arrays({ + .vert = (const char *[]){datatoc_common_view_lib_glsl, + datatoc_workbench_shadow_vert_glsl, + NULL}, + .geom = (const char *[]){(cap) ? datatoc_workbench_shadow_caps_geom_glsl : + datatoc_workbench_shadow_geom_glsl, + NULL}, + .frag = (const char *[]){shadow_frag, NULL}, + .defs = (const char *[]){(depth_pass) ? "#define SHADOW_PASS\n" : "#define SHADOW_FAIL\n", + (manifold) ? "" : "#define DOUBLE_MANIFOLD\n", + NULL}, + }); + } + return *shader; +} + +GPUShader *workbench_shader_shadow_pass_get(bool manifold) +{ + return workbench_shader_shadow_pass_get_ex(true, manifold, false); +} + +GPUShader *workbench_shader_shadow_fail_get(bool manifold, bool cap) +{ + return workbench_shader_shadow_pass_get_ex(false, manifold, cap); +} + void workbench_shader_free(void) { for (int j = 0; j < sizeof(e_data.opaque_prepass_sh_cache) / sizeof(void *); j++) { @@ -255,6 +297,14 @@ void workbench_shader_free(void) struct GPUShader **sh_array = &e_data.opaque_composite_sh[0]; DRW_SHADER_FREE_SAFE(sh_array[j]); } + for (int j = 0; j < sizeof(e_data.shadow_depth_pass_sh) / sizeof(void *); j++) { + struct GPUShader **sh_array = &e_data.shadow_depth_pass_sh[0]; + DRW_SHADER_FREE_SAFE(sh_array[j]); + } + for (int j = 0; j < sizeof(e_data.shadow_depth_fail_sh) / sizeof(void *); j++) { + struct GPUShader **sh_array = &e_data.shadow_depth_fail_sh[0][0]; + DRW_SHADER_FREE_SAFE(sh_array[j]); + } DRW_SHADER_FREE_SAFE(e_data.oit_resolve_sh); DRW_SHADER_FREE_SAFE(e_data.merge_infront_sh); diff --git a/source/blender/draw/engines/workbench/workbench_shadow.c b/source/blender/draw/engines/workbench/workbench_shadow.c index 5be863e387d..635206cd38f 100644 --- a/source/blender/draw/engines/workbench/workbench_shadow.c +++ b/source/blender/draw/engines/workbench/workbench_shadow.c @@ -22,4 +22,116 @@ #include "DRW_render.h" -#include "workbench_engine.h" \ No newline at end of file +#include "workbench_engine.h" +#include "workbench_private.h" + +void workbench_shadow_cache_init(WORKBENCH_Data *data) +{ + WORKBENCH_PassList *psl = data->psl; + WORKBENCH_PrivateData *wpd = data->stl->wpd; + struct GPUShader *sh; + DRWShadingGroup *grp; + + studiolight_update_light(wpd); + + if (SHADOW_ENABLED(wpd)) { +#if DEBUG_SHADOW_VOLUME + DRWState depth_pass_state = DRW_STATE_DEPTH_LESS; + DRWState depth_fail_state = DRW_STATE_DEPTH_GREATER_EQUAL; + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ADD_FULL; +#else + DRWState depth_pass_state = DRW_STATE_WRITE_STENCIL_SHADOW_PASS; + DRWState depth_fail_state = DRW_STATE_WRITE_STENCIL_SHADOW_FAIL; + DRWState state = DRW_STATE_DEPTH_LESS | DRW_STATE_STENCIL_ALWAYS; +#endif + + /* TODO(fclem) Merge into one pass with subpasses. */ + DRW_PASS_CREATE(psl->shadow_pass[0], state | depth_pass_state); + DRW_PASS_CREATE(psl->shadow_pass[1], state | depth_fail_state); + + /* Stencil Shadow passes. */ + for (int manifold = 0; manifold < 2; manifold++) { + sh = workbench_shader_shadow_pass_get(manifold); + wpd->shadow_pass_grp[manifold] = grp = DRW_shgroup_create(sh, psl->shadow_pass[0]); + DRW_shgroup_stencil_mask(grp, 0xFF); /* Needed once to set the stencil state for the pass. */ + + sh = workbench_shader_shadow_fail_get(manifold, false); + wpd->shadow_fail_grp[manifold] = grp = DRW_shgroup_create(sh, psl->shadow_pass[1]); + DRW_shgroup_stencil_mask(grp, 0xFF); /* Needed once to set the stencil state for the pass. */ + + sh = workbench_shader_shadow_fail_get(manifold, true); + wpd->shadow_fail_caps_grp[manifold] = grp = DRW_shgroup_create(sh, psl->shadow_pass[1]); + } + } + else { + psl->shadow_pass[0] = NULL; + psl->shadow_pass[1] = NULL; + } +} + +static void workbench_init_object_data(DrawData *dd) +{ + WORKBENCH_ObjectData *data = (WORKBENCH_ObjectData *)dd; + data->shadow_bbox_dirty = true; +} + +void workbench_shadow_cache_populate(WORKBENCH_Data *data, Object *ob, const bool has_transp_mat) +{ + WORKBENCH_PrivateData *wpd = data->stl->wpd; + + bool is_manifold; + struct GPUBatch *geom_shadow = DRW_cache_object_edge_detection_get(ob, &is_manifold); + if (geom_shadow == NULL) { + return; + } + + WORKBENCH_ObjectData *engine_object_data = (WORKBENCH_ObjectData *)DRW_drawdata_ensure( + &ob->id, + &draw_engine_workbench, + sizeof(WORKBENCH_ObjectData), + &workbench_init_object_data, + NULL); + + if (studiolight_object_cast_visible_shadow(wpd, ob, engine_object_data)) { + mul_v3_mat3_m4v3(engine_object_data->shadow_dir, ob->imat, wpd->light_direction_ws); + + DRWShadingGroup *grp; + bool use_shadow_pass_technique = !studiolight_camera_in_object_shadow( + wpd, ob, engine_object_data); + + /* Shadow pass technique needs object to be have all its surface opaque. */ + if (has_transp_mat) { + use_shadow_pass_technique = false; + } + + if (use_shadow_pass_technique) { + grp = DRW_shgroup_create_sub(wpd->shadow_pass_grp[is_manifold]); + DRW_shgroup_uniform_vec3(grp, "lightDirection", engine_object_data->shadow_dir, 1); + DRW_shgroup_uniform_float_copy(grp, "lightDistance", 1e5f); + DRW_shgroup_call_no_cull(grp, geom_shadow, ob); +#if DEBUG_SHADOW_VOLUME + DRW_debug_bbox(&engine_object_data->shadow_bbox, (float[4]){1.0f, 0.0f, 0.0f, 1.0f}); +#endif + } + else { + float extrude_distance = studiolight_object_shadow_distance(wpd, ob, engine_object_data); + + /* TODO(fclem): only use caps if they are in the view frustum. */ + const bool need_caps = true; + if (need_caps) { + grp = DRW_shgroup_create_sub(wpd->shadow_fail_caps_grp[is_manifold]); + DRW_shgroup_uniform_vec3(grp, "lightDirection", engine_object_data->shadow_dir, 1); + DRW_shgroup_uniform_float_copy(grp, "lightDistance", extrude_distance); + DRW_shgroup_call_no_cull(grp, DRW_cache_object_surface_get(ob), ob); + } + + grp = DRW_shgroup_create_sub(wpd->shadow_fail_grp[is_manifold]); + DRW_shgroup_uniform_vec3(grp, "lightDirection", engine_object_data->shadow_dir, 1); + DRW_shgroup_uniform_float_copy(grp, "lightDistance", extrude_distance); + DRW_shgroup_call_no_cull(grp, geom_shadow, ob); +#if DEBUG_SHADOW_VOLUME + DRW_debug_bbox(&engine_object_data->shadow_bbox, (float[4]){0.0f, 1.0f, 0.0f, 1.0f}); +#endif + } + } +} \ No newline at end of file diff --git a/source/blender/draw/engines/workbench/workbench_studiolight.c b/source/blender/draw/engines/workbench/workbench_studiolight.c index 4eee0ce3cce..e9dd6c63feb 100644 --- a/source/blender/draw/engines/workbench/workbench_studiolight.c +++ b/source/blender/draw/engines/workbench/workbench_studiolight.c @@ -94,23 +94,24 @@ static void compute_parallel_lines_nor_and_dist(const float v1[2], } } -void studiolight_update_light(WORKBENCH_PrivateData *wpd, const float light_direction[3]) +void studiolight_update_light(WORKBENCH_PrivateData *wpd) { - wpd->shadow_changed = !compare_v3v3(wpd->cached_shadow_direction, light_direction, 1e-5f); + wpd->shadow_changed = !compare_v3v3( + wpd->cached_shadow_direction, wpd->light_direction_ws, 1e-5f); if (wpd->shadow_changed) { float up[3] = {0.0f, 0.0f, 1.0f}; unit_m4(wpd->shadow_mat); /* TODO fix singularity. */ - copy_v3_v3(wpd->shadow_mat[2], light_direction); + copy_v3_v3(wpd->shadow_mat[2], wpd->light_direction_ws); cross_v3_v3v3(wpd->shadow_mat[0], wpd->shadow_mat[2], up); normalize_v3(wpd->shadow_mat[0]); cross_v3_v3v3(wpd->shadow_mat[1], wpd->shadow_mat[2], wpd->shadow_mat[0]); invert_m4_m4(wpd->shadow_inv, wpd->shadow_mat); - copy_v3_v3(wpd->cached_shadow_direction, light_direction); + copy_v3_v3(wpd->cached_shadow_direction, wpd->light_direction_ws); } float planes[6][4]; diff --git a/source/blender/draw/engines/workbench/workbench_transparent.c b/source/blender/draw/engines/workbench/workbench_transparent.c index 297d07c03c6..2efa08683c3 100644 --- a/source/blender/draw/engines/workbench/workbench_transparent.c +++ b/source/blender/draw/engines/workbench/workbench_transparent.c @@ -56,6 +56,7 @@ static void workbench_transparent_lighting_uniforms(WORKBENCH_PrivateData *wpd, { const bool use_spec = workbench_is_specular_highlight_enabled(wpd); DRW_shgroup_uniform_block_persistent(grp, "world_block", wpd->world_ubo); + DRW_shgroup_uniform_bool_copy(grp, "forceShadowing", false); if (STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) { BKE_studiolight_ensure_flag(wpd->studio_light, diff --git a/source/blender/draw/intern/draw_hair.c b/source/blender/draw/intern/draw_hair.c index fa03c28b470..7b0fa3ce1ec 100644 --- a/source/blender/draw/intern/draw_hair.c +++ b/source/blender/draw/intern/draw_hair.c @@ -128,7 +128,7 @@ static DRWShadingGroup *drw_shgroup_create_hair_procedural_ex(Object *object, object, psys, md, &hair_cache, subdiv, thickness_res); DRWShadingGroup *shgrp; - if (shgrp) { + if (shgrp_parent) { shgrp = DRW_shgroup_create_sub(shgrp_parent); } else if (gpu_mat) { -- cgit v1.2.3