Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorClément Foucault <foucault.clem@gmail.com>2020-03-11 19:07:43 +0300
committerClément Foucault <foucault.clem@gmail.com>2020-03-11 19:12:16 +0300
commitc476c36e400883d929a7149def8dcb6ad6157a86 (patch)
treec19c43ad1ed82f333c08bee7d2096024fed812dd /source
parentf01bc597a8e6bf5df19f1af0c422918c96b25e41 (diff)
Workbench Simplification Refactor
This patch is (almost) a complete rewrite of workbench engine. The features remain unchanged but the code quality is greatly improved. Hair shading is brighter but also more correct. This also introduce the concept of `DRWShaderLibrary` to make a simple include system inside the GLSL files. Differential Revision: https://developer.blender.org/D7060
Diffstat (limited to 'source')
-rw-r--r--source/blender/blenlib/intern/BLI_memblock.c8
-rw-r--r--source/blender/draw/CMakeLists.txt47
-rw-r--r--source/blender/draw/engines/overlay/overlay_engine.c3
-rw-r--r--source/blender/draw/engines/overlay/overlay_wireframe.c10
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_cavity_frag.glsl81
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl97
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl154
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_composite_frag.glsl44
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_curvature_lib.glsl47
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl34
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_deferred_background_frag.glsl30
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_deferred_composite_frag.glsl103
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_effect_cavity_frag.glsl31
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_effect_fxaa_frag.glsl14
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_effect_outline_frag.glsl24
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_frag.glsl44
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_vert.glsl21
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_effect_taa_frag.glsl11
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_forward_composite_frag.glsl36
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_forward_depth_frag.glsl20
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl118
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_ghost_resolve_frag.glsl13
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_image_lib.glsl83
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_matcap_lib.glsl30
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_material_lib.glsl21
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_merge_infront_frag.glsl18
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_object_outline_lib.glsl12
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl97
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_prepass_hair_vert.glsl94
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl114
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_shader_interface_lib.glsl21
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_shadow_debug_frag.glsl16
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_transparent_accum_frag.glsl89
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_transparent_resolve_frag.glsl26
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl37
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl3
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl88
-rw-r--r--source/blender/draw/engines/workbench/solid_mode.c119
-rw-r--r--source/blender/draw/engines/workbench/transparent_mode.c97
-rw-r--r--source/blender/draw/engines/workbench/workbench_data.c407
-rw-r--r--source/blender/draw/engines/workbench/workbench_deferred.c1415
-rw-r--r--source/blender/draw/engines/workbench/workbench_effect_aa.c101
-rw-r--r--source/blender/draw/engines/workbench/workbench_effect_antialiasing.c421
-rw-r--r--source/blender/draw/engines/workbench/workbench_effect_cavity.c182
-rw-r--r--source/blender/draw/engines/workbench/workbench_effect_dof.c217
-rw-r--r--source/blender/draw/engines/workbench/workbench_effect_fxaa.c59
-rw-r--r--source/blender/draw/engines/workbench/workbench_effect_outline.c55
-rw-r--r--source/blender/draw/engines/workbench/workbench_effect_taa.c305
-rw-r--r--source/blender/draw/engines/workbench/workbench_engine.c547
-rw-r--r--source/blender/draw/engines/workbench/workbench_engine.h2
-rw-r--r--source/blender/draw/engines/workbench/workbench_forward.c817
-rw-r--r--source/blender/draw/engines/workbench/workbench_materials.c529
-rw-r--r--source/blender/draw/engines/workbench/workbench_opaque.c165
-rw-r--r--source/blender/draw/engines/workbench/workbench_private.h670
-rw-r--r--source/blender/draw/engines/workbench/workbench_render.c95
-rw-r--r--source/blender/draw/engines/workbench/workbench_shader.c533
-rw-r--r--source/blender/draw/engines/workbench/workbench_shadow.c367
-rw-r--r--source/blender/draw/engines/workbench/workbench_studiolight.c257
-rw-r--r--source/blender/draw/engines/workbench/workbench_transparent.c180
-rw-r--r--source/blender/draw/engines/workbench/workbench_volume.c117
-rw-r--r--source/blender/draw/intern/DRW_render.h26
-rw-r--r--source/blender/draw/intern/draw_common.h5
-rw-r--r--source/blender/draw/intern/draw_hair.c29
-rw-r--r--source/blender/draw/intern/draw_manager.c38
-rw-r--r--source/blender/draw/intern/draw_manager_data.c20
-rw-r--r--source/blender/draw/intern/draw_manager_shader.c129
-rw-r--r--source/blender/draw/intern/draw_manager_texture.c7
-rw-r--r--source/blender/gpu/shaders/gpu_shader_common_obinfos_lib.glsl11
-rw-r--r--source/blender/makesdna/DNA_view3d_enums.h4
69 files changed, 4382 insertions, 5283 deletions
diff --git a/source/blender/blenlib/intern/BLI_memblock.c b/source/blender/blenlib/intern/BLI_memblock.c
index ee9ea15835b..b532202ebaa 100644
--- a/source/blender/blenlib/intern/BLI_memblock.c
+++ b/source/blender/blenlib/intern/BLI_memblock.c
@@ -191,10 +191,14 @@ void *BLI_memblock_iterstep(BLI_memblock_iter *iter)
return ptr;
}
-/* Direct access. elem is element index inside the chosen chunk. */
+/* Direct access. elem is element index inside the chosen chunk.
+ * Double usage: You can set chunk to 0 and set the absolute elem index.
+ * The correct chunk will be retrieve. */
void *BLI_memblock_elem_get(BLI_memblock *mblk, int chunk, int elem)
{
BLI_assert(chunk < mblk->chunk_len);
- BLI_assert(elem < (mblk->chunk_size / mblk->elem_size));
+ int elem_per_chunk = mblk->chunk_size / mblk->elem_size;
+ chunk += elem / elem_per_chunk;
+ elem = elem % elem_per_chunk;
return (char *)(mblk->chunk_list[chunk]) + mblk->elem_size * elem;
}
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index 1f04739644e..fe03a32fd07 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -97,19 +97,18 @@ set(SRC
engines/eevee/eevee_subsurface.c
engines/eevee/eevee_temporal_sampling.c
engines/eevee/eevee_volumes.c
- engines/workbench/solid_mode.c
- engines/workbench/transparent_mode.c
engines/workbench/workbench_data.c
- engines/workbench/workbench_deferred.c
- engines/workbench/workbench_effect_aa.c
+ engines/workbench/workbench_effect_antialiasing.c
+ engines/workbench/workbench_effect_cavity.c
engines/workbench/workbench_effect_dof.c
- engines/workbench/workbench_effect_fxaa.c
- engines/workbench/workbench_effect_taa.c
+ engines/workbench/workbench_effect_outline.c
engines/workbench/workbench_engine.c
- engines/workbench/workbench_forward.c
engines/workbench/workbench_materials.c
+ engines/workbench/workbench_opaque.c
engines/workbench/workbench_render.c
- engines/workbench/workbench_studiolight.c
+ engines/workbench/workbench_shader.c
+ engines/workbench/workbench_shadow.c
+ engines/workbench/workbench_transparent.c
engines/workbench/workbench_volume.c
engines/external/external_engine.c
engines/gpencil/gpencil_antialiasing.c
@@ -247,28 +246,32 @@ data_to_c_simple(engines/eevee/shaders/volumetric_scatter_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/volumetric_integration_frag.glsl SRC)
data_to_c_simple(engines/workbench/shaders/workbench_cavity_lib.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_cavity_frag.glsl SRC)
data_to_c_simple(engines/workbench/shaders/workbench_common_lib.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_composite_frag.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_curvature_lib.glsl SRC)
data_to_c_simple(engines/workbench/shaders/workbench_data_lib.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_deferred_composite_frag.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_deferred_background_frag.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_effect_cavity_frag.glsl SRC)
data_to_c_simple(engines/workbench/shaders/workbench_effect_dof_frag.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_effect_fxaa_frag.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_effect_outline_frag.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_effect_smaa_frag.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_effect_smaa_vert.glsl SRC)
data_to_c_simple(engines/workbench/shaders/workbench_effect_taa_frag.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_forward_composite_frag.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_forward_depth_frag.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_ghost_resolve_frag.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_object_outline_lib.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_curvature_lib.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_prepass_vert.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_image_lib.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_matcap_lib.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_material_lib.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_merge_infront_frag.glsl SRC)
data_to_c_simple(engines/workbench/shaders/workbench_prepass_frag.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_shadow_vert.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_shadow_geom.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_prepass_hair_vert.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_prepass_vert.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_shader_interface_lib.glsl SRC)
data_to_c_simple(engines/workbench/shaders/workbench_shadow_caps_geom.glsl SRC)
data_to_c_simple(engines/workbench/shaders/workbench_shadow_debug_frag.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_volume_vert.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_shadow_geom.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_shadow_vert.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_transparent_accum_frag.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_transparent_resolve_frag.glsl SRC)
data_to_c_simple(engines/workbench/shaders/workbench_volume_frag.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_volume_vert.glsl SRC)
data_to_c_simple(engines/workbench/shaders/workbench_world_light_lib.glsl SRC)
data_to_c_simple(intern/shaders/common_colormanagement_lib.glsl SRC)
diff --git a/source/blender/draw/engines/overlay/overlay_engine.c b/source/blender/draw/engines/overlay/overlay_engine.c
index cfa0fa9eb1a..740ca42800e 100644
--- a/source/blender/draw/engines/overlay/overlay_engine.c
+++ b/source/blender/draw/engines/overlay/overlay_engine.c
@@ -382,9 +382,6 @@ static void OVERLAY_cache_finish(void *vedata)
DRW_texture_ensure_fullscreen_2d(&dtxl->depth_in_front, GPU_DEPTH24_STENCIL8, 0);
GPU_framebuffer_ensure_config(
- &dfbl->default_fb,
- {GPU_ATTACHMENT_TEXTURE(dtxl->depth), GPU_ATTACHMENT_TEXTURE(dtxl->color)});
- GPU_framebuffer_ensure_config(
&dfbl->in_front_fb,
{GPU_ATTACHMENT_TEXTURE(dtxl->depth_in_front), GPU_ATTACHMENT_TEXTURE(dtxl->color)});
}
diff --git a/source/blender/draw/engines/overlay/overlay_wireframe.c b/source/blender/draw/engines/overlay/overlay_wireframe.c
index 722055c36f0..6b0e5e0b72e 100644
--- a/source/blender/draw/engines/overlay/overlay_wireframe.c
+++ b/source/blender/draw/engines/overlay/overlay_wireframe.c
@@ -68,22 +68,17 @@ void OVERLAY_wireframe_cache_init(OVERLAY_Data *vedata)
OVERLAY_shader_wireframe();
for (int xray = 0; xray < (is_material_shmode ? 1 : 2); xray++) {
- /* Only do stencil test if stencil buffer is written by the render engine. */
- DRWState stencil_state = is_material_shmode ? 0 : DRW_STATE_STENCIL_EQUAL;
DRWState state = DRW_STATE_FIRST_VERTEX_CONVENTION | DRW_STATE_WRITE_COLOR |
DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
DRWPass *pass;
- uint stencil_mask;
if (xray == 0) {
- DRW_PASS_CREATE(psl->wireframe_ps, state | stencil_state | pd->clipping_state);
+ DRW_PASS_CREATE(psl->wireframe_ps, state | pd->clipping_state);
pass = psl->wireframe_ps;
- stencil_mask = 0xFF;
}
else {
DRW_PASS_CREATE(psl->wireframe_xray_ps, state | pd->clipping_state);
pass = psl->wireframe_xray_ps;
- stencil_mask = 0x00;
}
for (int use_coloring = 0; use_coloring < 2; use_coloring++) {
@@ -94,17 +89,14 @@ void OVERLAY_wireframe_cache_init(OVERLAY_Data *vedata)
DRW_shgroup_uniform_bool_copy(grp, "isTransform", (G.moving & G_TRANSFORM_OBJ) != 0);
DRW_shgroup_uniform_bool_copy(grp, "isObjectColor", is_object_color);
DRW_shgroup_uniform_bool_copy(grp, "isRandomColor", is_random_color);
- DRW_shgroup_stencil_mask(grp, stencil_mask);
pd->wires_all_grp[xray][use_coloring] = grp = DRW_shgroup_create(wires_sh, pass);
DRW_shgroup_uniform_float_copy(grp, "wireStepParam", 1.0f);
- DRW_shgroup_stencil_mask(grp, stencil_mask);
}
pd->wires_sculpt_grp[xray] = grp = DRW_shgroup_create(wires_sh, pass);
DRW_shgroup_uniform_float_copy(grp, "wireStepParam", 10.0f);
DRW_shgroup_uniform_bool_copy(grp, "useColoring", false);
- DRW_shgroup_stencil_mask(grp, stencil_mask);
}
if (is_material_shmode) {
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_cavity_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_cavity_frag.glsl
deleted file mode 100644
index a0e04f252e2..00000000000
--- a/source/blender/draw/engines/workbench/shaders/workbench_cavity_frag.glsl
+++ /dev/null
@@ -1,81 +0,0 @@
-out vec4 fragColor;
-
-uniform sampler2D depthBuffer;
-uniform sampler2D colorBuffer;
-uniform sampler2D normalBuffer;
-uniform usampler2D objectId;
-
-uniform vec2 invertedViewportSize;
-uniform mat4 WinMatrix; /* inverse WinMatrix */
-
-uniform vec4 viewvecs[3];
-uniform vec4 ssao_params;
-uniform vec4 ssao_settings;
-uniform vec2 curvature_settings;
-uniform sampler2D ssao_jitter;
-
-layout(std140) uniform samples_block
-{
- vec4 ssao_samples[500];
-};
-
-#define ssao_samples_num ssao_params.x
-#define jitter_tilling ssao_params.yz
-#define ssao_iteration ssao_params.w
-
-#define ssao_distance ssao_settings.x
-#define ssao_factor_cavity ssao_settings.y
-#define ssao_factor_edge ssao_settings.z
-#define ssao_attenuation ssao_settings.w
-
-vec3 get_view_space_from_depth(in vec2 uvcoords, in float depth)
-{
- if (WinMatrix[3][3] == 0.0) {
- /* Perspective */
- float d = 2.0 * depth - 1.0;
-
- float zview = -WinMatrix[3][2] / (d + WinMatrix[2][2]);
-
- return zview * (viewvecs[0].xyz + vec3(uvcoords, 0.0) * viewvecs[1].xyz);
- }
- else {
- /* Orthographic */
- vec3 offset = vec3(uvcoords, depth);
-
- return viewvecs[0].xyz + offset * viewvecs[1].xyz;
- }
-}
-
-/* forward declaration */
-void ssao_factors(in float depth,
- in vec3 normal,
- in vec3 position,
- in vec2 screenco,
- out float cavities,
- out float edges);
-
-void main()
-{
- vec2 screenco = vec2(gl_FragCoord.xy) * invertedViewportSize;
- ivec2 texel = ivec2(gl_FragCoord.xy);
-
- float cavity = 0.0, edges = 0.0, curvature = 0.0;
-
-#ifdef USE_CAVITY
- float depth = texelFetch(depthBuffer, texel, 0).x;
- vec3 position = get_view_space_from_depth(screenco, depth);
- vec3 normal_viewport = workbench_normal_decode(texelFetch(normalBuffer, texel, 0).rg);
-
- ssao_factors(depth, normal_viewport, position, screenco, cavity, edges);
-#endif
-
-#ifdef USE_CURVATURE
- curvature = calculate_curvature(
- objectId, normalBuffer, texel, curvature_settings.x, curvature_settings.y);
-#endif
-
- float final_cavity_factor = clamp((1.0 - cavity) * (1.0 + edges) * (1.0 + curvature), 0.0, 4.0);
-
- /* Using UNORM render target so compress the range. */
- fragColor = vec4(final_cavity_factor / CAVITY_BUFFER_RANGE);
-}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl
index 376b19cdd1b..87d04144cde 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl
@@ -1,77 +1,87 @@
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(workbench_data_lib.glsl)
+#pragma BLENDER_REQUIRE(workbench_common_lib.glsl)
-/* from The Alchemy screen-space ambient obscurance algorithm
+layout(std140) uniform samples_block
+{
+ vec4 samples_coords[512];
+};
+
+uniform sampler2D cavityJitter;
+
+/* From The Alchemy screen-space ambient obscurance algorithm
* http://graphics.cs.williams.edu/papers/AlchemyHPG11/VV11AlchemyAO.pdf */
-void ssao_factors(in float depth,
- in vec3 normal,
- in vec3 position,
- in vec2 screenco,
- out float cavities,
- out float edges)
+void cavity_compute(vec2 screenco,
+ sampler2D depthBuffer,
+ sampler2D normalBuffer,
+ out float cavities,
+ out float edges)
{
cavities = edges = 0.0;
- /* early out if there is no need for SSAO */
- if (ssao_factor_cavity == 0.0 && ssao_factor_edge == 0.0) {
+
+ float depth = texture(depthBuffer, screenco).x;
+
+ /* Early out if background and infront. */
+ if (depth == 1.0 || depth == 0.0) {
return;
}
- /* take the normalized ray direction here */
- vec3 noise = texture(ssao_jitter, screenco.xy * jitter_tilling).rgb;
+ vec3 position = view_position_from_depth(screenco, depth, world_data.viewvecs, ProjectionMatrix);
+ vec3 normal = workbench_normal_decode(texture(normalBuffer, screenco));
+
+ vec2 jitter_co = (screenco * world_data.viewport_size.xy) * world_data.cavity_jitter_scale;
+ vec3 noise = texture(cavityJitter, jitter_co).rgb;
/* find the offset in screen space by multiplying a point
* in camera space at the depth of the point by the projection matrix. */
vec2 offset;
- float homcoord = WinMatrix[2][3] * position.z + WinMatrix[3][3];
- offset.x = WinMatrix[0][0] * ssao_distance / homcoord;
- offset.y = WinMatrix[1][1] * ssao_distance / homcoord;
+ float homcoord = ProjectionMatrix[2][3] * position.z + ProjectionMatrix[3][3];
+ offset.x = ProjectionMatrix[0][0] * world_data.cavity_distance / homcoord;
+ offset.y = ProjectionMatrix[1][1] * world_data.cavity_distance / homcoord;
/* convert from -1.0...1.0 range to 0.0..1.0 for easy use with texture coordinates */
offset *= 0.5;
- int num_samples = int(ssao_samples_num);
-
/* Note. Putting noise usage here to put some ALU after texture fetch. */
vec2 rotX = noise.rg;
vec2 rotY = vec2(-rotX.y, rotX.x);
- for (int x = 0; x < num_samples; x++) {
- int sample_index = x + (int(ssao_iteration) * num_samples);
- if (sample_index > 500) {
- continue;
- }
- /* ssao_samples[x].xy is sample direction (normalized).
- * ssao_samples[x].z is sample distance from disk center. */
-
+ int sample_start = world_data.cavity_sample_start;
+ int sample_end = world_data.cavity_sample_end;
+ for (int i = sample_start; i < sample_end && i < 512; i++) {
+ /* sample_coord.xy is sample direction (normalized).
+ * sample_coord.z is sample distance from disk center. */
+ vec3 sample_coord = samples_coords[i].xyz;
/* Rotate with random direction to get jittered result. */
- vec2 dir_jittered = vec2(dot(ssao_samples[sample_index].xy, rotX),
- dot(ssao_samples[sample_index].xy, rotY));
- dir_jittered.xy *= ssao_samples[sample_index].z + noise.b;
+ vec2 dir_jittered = vec2(dot(sample_coord.xy, rotX), dot(sample_coord.xy, rotY));
+ dir_jittered.xy *= sample_coord.z + noise.b;
- vec2 uvcoords = screenco.xy + dir_jittered * offset;
-
- if (uvcoords.x > 1.0 || uvcoords.x < 0.0 || uvcoords.y > 1.0 || uvcoords.y < 0.0) {
+ vec2 uvcoords = screenco + dir_jittered * offset;
+ /* Out of screen case. */
+ if (any(greaterThan(abs(uvcoords - 0.5), vec2(0.5)))) {
continue;
}
-
- float depth_new = texture(depthBuffer, uvcoords).r;
-
+ /* Sample depth. */
+ float s_depth = texture(depthBuffer, uvcoords).r;
/* Handle Background case */
- bool is_background = (depth_new == 1.0);
-
+ bool is_background = (s_depth == 1.0);
/* This trick provide good edge effect even if no neighbor is found. */
- vec3 pos_new = get_view_space_from_depth(uvcoords, (is_background) ? depth : depth_new);
+ s_depth = (is_background) ? depth : s_depth;
+ vec3 s_pos = view_position_from_depth(
+ uvcoords, s_depth, world_data.viewvecs, ProjectionMatrix);
if (is_background) {
- pos_new.z -= ssao_distance;
+ s_pos.z -= world_data.cavity_distance;
}
- vec3 dir = pos_new - position;
+ vec3 dir = s_pos - position;
float len = length(dir);
float f_cavities = dot(dir, normal);
float f_edge = -f_cavities;
float f_bias = 0.05 * len + 0.0001;
- float attenuation = 1.0 / (len * (1.0 + len * len * ssao_attenuation));
+ float attenuation = 1.0 / (len * (1.0 + len * len * world_data.cavity_attenuation));
/* use minor bias here to avoid self shadowing */
if (f_cavities > -f_bias) {
@@ -82,11 +92,10 @@ void ssao_factors(in float depth,
edges += f_edge * attenuation;
}
}
-
- cavities /= ssao_samples_num;
- edges /= ssao_samples_num;
+ cavities *= world_data.cavity_sample_count_inv;
+ edges *= world_data.cavity_sample_count_inv;
/* don't let cavity wash out the surface appearance */
- cavities = clamp(cavities * ssao_factor_cavity, 0.0, 1.0);
- edges = edges * ssao_factor_edge;
+ cavities = clamp(cavities * world_data.cavity_valley_factor, 0.0, 1.0);
+ edges = edges * world_data.cavity_ridge_factor;
}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl
index c0d7719180b..25eaf003e07 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl
@@ -1,30 +1,16 @@
-#define NO_OBJECT_ID uint(0)
+
#define EPSILON 0.00001
#define M_PI 3.14159265358979323846
#define CAVITY_BUFFER_RANGE 4.0
-/* 4x4 bayer matrix prepared for 8bit UNORM precision error. */
-#define P(x) (((x + 0.5) * (1.0 / 16.0) - 0.5) * (1.0 / 255.0))
-const vec4 dither_mat4x4[4] = vec4[4](vec4(P(0.0), P(8.0), P(2.0), P(10.0)),
- vec4(P(12.0), P(4.0), P(14.0), P(6.0)),
- vec4(P(3.0), P(11.0), P(1.0), P(9.0)),
- vec4(P(15.0), P(7.0), P(13.0), P(5.0)));
-
-float bayer_dither_noise()
-{
- ivec2 tx1 = ivec2(gl_FragCoord.xy) % 4;
- ivec2 tx2 = ivec2(gl_FragCoord.xy) % 2;
- return dither_mat4x4[tx1.x][tx1.y];
-}
-
#ifdef WORKBENCH_ENCODE_NORMALS
# define WB_Normal vec2
/* From http://aras-p.info/texts/CompactNormalStorage.html
* Using Method #4: Spheremap Transform */
-vec3 workbench_normal_decode(WB_Normal enc)
+vec3 workbench_normal_decode(vec4 enc)
{
vec2 fenc = enc.xy * 4.0 - 2.0;
float f = dot(fenc, fenc);
@@ -37,8 +23,9 @@ vec3 workbench_normal_decode(WB_Normal enc)
/* From http://aras-p.info/texts/CompactNormalStorage.html
* Using Method #4: Spheremap Transform */
-WB_Normal workbench_normal_encode(vec3 n)
+WB_Normal workbench_normal_encode(bool front_face, vec3 n)
{
+ n = normalize(front_face ? n : -n);
float p = sqrt(n.z * 8.0 + 8.0);
n.xy = clamp(n.xy / p + 0.5, 0.0, 1.0);
return n.xy;
@@ -47,161 +34,64 @@ WB_Normal workbench_normal_encode(vec3 n)
#else
# define WB_Normal vec3
/* Well just do nothing... */
-# define workbench_normal_encode(a) (a)
-# define workbench_normal_decode(a) (a)
+# define workbench_normal_encode(f, a) (a)
+# define workbench_normal_decode(a) (a.xyz)
#endif /* WORKBENCH_ENCODE_NORMALS */
-/* Encoding into the alpha of a RGBA8 UNORM texture. */
+/* Encoding into the alpha of a RGBA16F texture. (10bit mantissa) */
#define TARGET_BITCOUNT 8u
#define METALLIC_BITS 3u /* Metallic channel is less important. */
#define ROUGHNESS_BITS (TARGET_BITCOUNT - METALLIC_BITS)
-#define TOTAL_BITS (METALLIC_BITS + ROUGHNESS_BITS)
/* Encode 2 float into 1 with the desired precision. */
float workbench_float_pair_encode(float v1, float v2)
{
- // const uint total_mask = ~(0xFFFFFFFFu << TOTAL_BITS);
// const uint v1_mask = ~(0xFFFFFFFFu << ROUGHNESS_BITS);
// const uint v2_mask = ~(0xFFFFFFFFu << METALLIC_BITS);
/* Same as above because some compiler are dumb af. and think we use mediump int. */
- const int total_mask = 0xFF;
const int v1_mask = 0x1F;
const int v2_mask = 0x7;
int iv1 = int(v1 * float(v1_mask));
int iv2 = int(v2 * float(v2_mask)) << int(ROUGHNESS_BITS);
- return float(iv1 | iv2) * (1.0 / float(total_mask));
+ return float(iv1 | iv2);
}
void workbench_float_pair_decode(float data, out float v1, out float v2)
{
- // const uint total_mask = ~(0xFFFFFFFFu << TOTAL_BITS);
// const uint v1_mask = ~(0xFFFFFFFFu << ROUGHNESS_BITS);
// const uint v2_mask = ~(0xFFFFFFFFu << METALLIC_BITS);
/* Same as above because some compiler are dumb af. and think we use mediump int. */
- const int total_mask = 0xFF;
const int v1_mask = 0x1F;
const int v2_mask = 0x7;
- int idata = int(data * float(total_mask));
+ int idata = int(data);
v1 = float(idata & v1_mask) * (1.0 / float(v1_mask));
v2 = float(idata >> int(ROUGHNESS_BITS)) * (1.0 / float(v2_mask));
}
-float calculate_transparent_weight(float z, float alpha)
-{
-#if 0
- /* Eq 10 : Good for surfaces with varying opacity (like particles) */
- float a = min(1.0, alpha * 10.0) + 0.01;
- float b = -gl_FragCoord.z * 0.95 + 1.0;
- float w = a * a * a * 3e2 * b * b * b;
-#else
- /* Eq 7 put more emphasis on surfaces closer to the view. */
- // float w = 10.0 / (1e-5 + pow(abs(z) / 5.0, 2.0) + pow(abs(z) / 200.0, 6.0)); /* Eq 7 */
- // float w = 10.0 / (1e-5 + pow(abs(z) / 10.0, 3.0) + pow(abs(z) / 200.0, 6.0)); /* Eq 8 */
- // float w = 10.0 / (1e-5 + pow(abs(z) / 200.0, 4.0)); /* Eq 9 */
- /* Same as eq 7, but optimized. */
- float a = abs(z) / 5.0;
- float b = abs(z) / 200.0;
- b *= b;
- float w = 10.0 / ((1e-5 + a * a) + b * (b * b)); /* Eq 7 */
-#endif
- return alpha * clamp(w, 1e-2, 3e2);
-}
-
-/* Special function only to be used with calculate_transparent_weight(). */
-float linear_zdepth(float depth, vec4 viewvecs[3], mat4 proj_mat)
+vec3 view_vector_from_screen_uv(vec2 uv, vec4 viewvecs[3], mat4 proj_mat)
{
if (proj_mat[3][3] == 0.0) {
- float d = 2.0 * depth - 1.0;
- return -proj_mat[3][2] / (d + proj_mat[2][2]);
+ return normalize(viewvecs[0].xyz + vec3(uv, 0.0) * viewvecs[1].xyz);
}
else {
- /* Return depth from near plane. */
- return depth * viewvecs[1].z;
- }
-}
-
-vec3 view_vector_from_screen_uv(vec2 uv, vec4 viewvecs[3], mat4 proj_mat)
-{
- return (proj_mat[3][3] == 0.0) ? normalize(viewvecs[0].xyz + vec3(uv, 0.0) * viewvecs[1].xyz) :
- vec3(0.0, 0.0, 1.0);
-}
-
-vec2 matcap_uv_compute(vec3 I, vec3 N, bool flipped)
-{
- /* Quick creation of an orthonormal basis */
- float a = 1.0 / (1.0 + I.z);
- float b = -I.x * I.y * a;
- vec3 b1 = vec3(1.0 - I.x * I.x * a, b, -I.x);
- vec3 b2 = vec3(b, 1.0 - I.y * I.y * a, -I.y);
- vec2 matcap_uv = vec2(dot(b1, N), dot(b2, N));
- if (flipped) {
- matcap_uv.x = -matcap_uv.x;
+ return vec3(0.0, 0.0, 1.0);
}
- return matcap_uv * 0.496 + 0.5;
}
-bool node_tex_tile_lookup(inout vec3 co, sampler2DArray ima, sampler1DArray map)
+vec3 view_position_from_depth(vec2 uvcoords, float depth, vec4 viewvecs[3], mat4 proj_mat)
{
- vec2 tile_pos = floor(co.xy);
-
- if (tile_pos.x < 0 || tile_pos.y < 0 || tile_pos.x >= 10)
- return false;
-
- float tile = 10.0 * tile_pos.y + tile_pos.x;
- if (tile >= textureSize(map, 0).x)
- return false;
-
- /* Fetch tile information. */
- float tile_layer = texelFetch(map, ivec2(tile, 0), 0).x;
- if (tile_layer < 0.0)
- return false;
-
- vec4 tile_info = texelFetch(map, ivec2(tile, 1), 0);
-
- co = vec3(((co.xy - tile_pos) * tile_info.zw) + tile_info.xy, tile_layer);
- return true;
-}
+ if (proj_mat[3][3] == 0.0) {
+ /* Perspective */
+ float d = 2.0 * depth - 1.0;
-vec4 workbench_sample_texture(sampler2D image,
- vec2 coord,
- bool nearest_sampling,
- bool premultiplied)
-{
- vec2 tex_size = vec2(textureSize(image, 0).xy);
- /* TODO(fclem) We could do the same with sampler objects.
- * But this is a quick workaround instead of messing with the GPUTexture itself. */
- vec2 uv = nearest_sampling ? (floor(coord * tex_size) + 0.5) / tex_size : coord;
- vec4 color = texture(image, uv);
+ float zview = -proj_mat[3][2] / (d + proj_mat[2][2]);
- /* Unpremultiply if stored multiplied, since straight alpha is expected by shaders. */
- if (premultiplied && !(color.a == 0.0 || color.a == 1.0)) {
- color.rgb = color.rgb / color.a;
+ return zview * (viewvecs[0].xyz + vec3(uvcoords, 0.0) * viewvecs[1].xyz);
}
+ else {
+ /* Orthographic */
+ vec3 offset = vec3(uvcoords, depth);
- return color;
-}
-
-vec4 workbench_sample_texture_array(sampler2DArray tile_array,
- sampler1DArray tile_data,
- vec2 coord,
- bool nearest_sampling,
- bool premultiplied)
-{
- vec2 tex_size = vec2(textureSize(tile_array, 0).xy);
-
- vec3 uv = vec3(coord, 0);
- if (!node_tex_tile_lookup(uv, tile_array, tile_data))
- return vec4(1.0, 0.0, 1.0, 1.0);
-
- /* TODO(fclem) We could do the same with sampler objects.
- * But this is a quick workaround instead of messing with the GPUTexture itself. */
- uv.xy = nearest_sampling ? (floor(uv.xy * tex_size) + 0.5) / tex_size : uv.xy;
- vec4 color = texture(tile_array, uv);
-
- /* Unpremultiply if stored multiplied, since straight alpha is expected by shaders. */
- if (premultiplied && !(color.a == 0.0 || color.a == 1.0)) {
- color.rgb = color.rgb / color.a;
+ return viewvecs[0].xyz + offset * viewvecs[1].xyz;
}
-
- return color;
}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_composite_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_composite_frag.glsl
new file mode 100644
index 00000000000..cdb9823096c
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/workbench_composite_frag.glsl
@@ -0,0 +1,44 @@
+
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(workbench_common_lib.glsl)
+#pragma BLENDER_REQUIRE(workbench_matcap_lib.glsl)
+#pragma BLENDER_REQUIRE(workbench_world_light_lib.glsl)
+
+uniform sampler2D materialBuffer;
+uniform sampler2D normalBuffer;
+
+in vec4 uvcoordsvar;
+
+out vec4 fragColor;
+
+void main()
+{
+ /* Normal and Incident vector are in viewspace. Lighting is evaluated in viewspace. */
+ vec3 I = view_vector_from_screen_uv(uvcoordsvar.st, world_data.viewvecs, ProjectionMatrix);
+ vec3 N = workbench_normal_decode(texture(normalBuffer, uvcoordsvar.st));
+ vec4 mat_data = texture(materialBuffer, uvcoordsvar.st);
+
+ vec3 base_color = mat_data.rgb;
+
+ float roughness, metallic;
+ workbench_float_pair_decode(mat_data.a, roughness, metallic);
+
+#ifdef V3D_LIGHTING_MATCAP
+ /* When using matcaps, mat_data.a is the backface sign. */
+ N = (mat_data.a > 0.0) ? N : -N;
+
+ fragColor.rgb = get_matcap_lighting(base_color, N, I);
+#endif
+
+#ifdef V3D_LIGHTING_STUDIO
+ fragColor.rgb = get_world_lighting(base_color, roughness, metallic, N, I);
+#endif
+
+#ifdef V3D_LIGHTING_FLAT
+ fragColor.rgb = base_color;
+#endif
+
+ fragColor.rgb *= get_shadow(N);
+
+ fragColor.a = 1.0;
+}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_curvature_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_curvature_lib.glsl
index 22dc906be83..e6bc4c7bbc6 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_curvature_lib.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_curvature_lib.glsl
@@ -1,6 +1,5 @@
-#ifndef CURVATURE_OFFSET
-# define CURVATURE_OFFSET 1
-#endif
+
+#pragma BLENDER_REQUIRE(workbench_data_lib.glsl)
float curvature_soft_clamp(float curvature, float control)
{
@@ -10,33 +9,35 @@ float curvature_soft_clamp(float curvature, float control)
return 0.25 / control;
}
-float calculate_curvature(
- usampler2D objectId, sampler2D normalBuffer, ivec2 texel, float ridge, float valley)
+void curvature_compute(vec2 uv,
+ usampler2D objectIdBuffer,
+ sampler2D normalBuffer,
+ out float curvature)
{
- uint object_up = texelFetchOffset(objectId, texel, 0, ivec2(0, CURVATURE_OFFSET)).r;
- uint object_down = texelFetchOffset(objectId, texel, 0, ivec2(0, -CURVATURE_OFFSET)).r;
- uint object_left = texelFetchOffset(objectId, texel, 0, ivec2(-CURVATURE_OFFSET, 0)).r;
- uint object_right = texelFetchOffset(objectId, texel, 0, ivec2(CURVATURE_OFFSET, 0)).r;
+ curvature = 0.0;
+
+ vec3 offset = vec3(world_data.viewport_size_inv, 0.0) * world_data.ui_scale;
+ uint object_up = texture(objectIdBuffer, uv + offset.zy).r;
+ uint object_down = texture(objectIdBuffer, uv - offset.zy).r;
+ uint object_right = texture(objectIdBuffer, uv + offset.xz).r;
+ uint object_left = texture(objectIdBuffer, uv - offset.xz).r;
+ /* Remove object outlines. */
if ((object_up != object_down) || (object_right != object_left)) {
- return 0.0;
+ return;
}
- vec2 normal_up = texelFetchOffset(normalBuffer, texel, 0, ivec2(0, CURVATURE_OFFSET)).rg;
- vec2 normal_down = texelFetchOffset(normalBuffer, texel, 0, ivec2(0, -CURVATURE_OFFSET)).rg;
- vec2 normal_left = texelFetchOffset(normalBuffer, texel, 0, ivec2(-CURVATURE_OFFSET, 0)).rg;
- vec2 normal_right = texelFetchOffset(normalBuffer, texel, 0, ivec2(CURVATURE_OFFSET, 0)).rg;
-
- normal_up = workbench_normal_decode(normal_up).rg;
- normal_down = workbench_normal_decode(normal_down).rg;
- normal_left = workbench_normal_decode(normal_left).rg;
- normal_right = workbench_normal_decode(normal_right).rg;
+ float normal_up = workbench_normal_decode(texture(normalBuffer, uv + offset.zy)).g;
+ float normal_down = workbench_normal_decode(texture(normalBuffer, uv - offset.zy)).g;
+ float normal_right = workbench_normal_decode(texture(normalBuffer, uv + offset.xz)).r;
+ float normal_left = workbench_normal_decode(texture(normalBuffer, uv - offset.xz)).r;
- float normal_diff = ((normal_up.g - normal_down.g) + (normal_right.r - normal_left.r));
+ float normal_diff = (normal_up - normal_down) + (normal_right - normal_left);
if (normal_diff < 0) {
- return -2.0 * curvature_soft_clamp(-normal_diff, valley);
+ curvature = -2.0 * curvature_soft_clamp(-normal_diff, world_data.curvature_valley);
+ }
+ else {
+ curvature = 2.0 * curvature_soft_clamp(normal_diff, world_data.curvature_ridge);
}
-
- return 2.0 * curvature_soft_clamp(normal_diff, ridge);
}
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 0c984b094d3..5f3283e1643 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl
@@ -5,12 +5,42 @@ struct LightData {
};
struct WorldData {
+ vec4 viewvecs[3];
+ 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 num_lights;
- int matcap_orientation;
+
+ int cavity_sample_start;
+ int cavity_sample_end;
+ float cavity_sample_count_inv;
+ float cavity_jitter_scale;
+
+ float cavity_valley_factor;
+ float cavity_ridge_factor;
+ float cavity_attenuation;
+ float cavity_distance;
+
float curvature_ridge;
float curvature_valley;
+ float ui_scale;
+ float _pad0;
+
+ int matcap_orientation;
+ bool use_specular;
+ int _pad1;
+ int _pad2;
+};
+
+#define viewport_size_inv viewport_size.zw
+
+layout(std140) uniform world_block
+{
+ WorldData world_data;
};
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_deferred_background_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_deferred_background_frag.glsl
deleted file mode 100644
index 22fa2babbbf..00000000000
--- a/source/blender/draw/engines/workbench/shaders/workbench_deferred_background_frag.glsl
+++ /dev/null
@@ -1,30 +0,0 @@
-
-uniform usampler2D objectId;
-
-uniform vec2 invertedViewportSize;
-
-out vec4 fragColor;
-
-layout(std140) uniform world_block
-{
- WorldData world_data;
-};
-
-void main()
-{
- vec2 uv_viewport = gl_FragCoord.xy * invertedViewportSize;
-
-#ifndef V3D_SHADING_OBJECT_OUTLINE
-
- fragColor = vec4(0.0);
-
-#else /* !V3D_SHADING_OBJECT_OUTLINE */
-
- ivec2 texel = ivec2(gl_FragCoord.xy);
- uint object_id = texelFetch(objectId, texel, 0).r;
- float object_outline = calculate_object_outline(objectId, texel, object_id);
-
- fragColor = vec4(world_data.object_outline_color.rgb, 1.0) * (1.0 - object_outline);
-
-#endif /* !V3D_SHADING_OBJECT_OUTLINE */
-}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_deferred_composite_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_deferred_composite_frag.glsl
deleted file mode 100644
index fd4cea4279a..00000000000
--- a/source/blender/draw/engines/workbench/shaders/workbench_deferred_composite_frag.glsl
+++ /dev/null
@@ -1,103 +0,0 @@
-out vec4 fragColor;
-
-uniform usampler2D objectId;
-uniform sampler2D materialBuffer;
-uniform sampler2D normalBuffer;
-/* normalBuffer contains viewport normals */
-uniform sampler2D cavityBuffer;
-uniform sampler2D matcapDiffuseImage;
-uniform sampler2D matcapSpecularImage;
-
-uniform vec2 invertedViewportSize;
-uniform vec4 viewvecs[3];
-uniform float shadowMultiplier;
-uniform float lightMultiplier;
-uniform float shadowShift = 0.1;
-uniform float shadowFocus = 1.0;
-
-uniform vec3 materialSingleColor;
-
-layout(std140) uniform world_block
-{
- WorldData world_data;
-};
-
-void main()
-{
- ivec2 texel = ivec2(gl_FragCoord.xy);
- vec2 uv_viewport = gl_FragCoord.xy * invertedViewportSize;
-
- float roughness, metallic;
- vec3 base_color;
-
-#ifndef MATDATA_PASS_ENABLED
- base_color = materialSingleColor;
- metallic = 0.0;
- roughness = 0.5;
-#else
- vec4 material_data = texelFetch(materialBuffer, texel, 0);
- base_color = material_data.rgb;
- workbench_float_pair_decode(material_data.a, roughness, metallic);
-#endif
-
-/* Do we need normals */
-#ifdef NORMAL_VIEWPORT_PASS_ENABLED
- vec3 normal_viewport = workbench_normal_decode(texelFetch(normalBuffer, texel, 0).rg);
-#endif
-
- vec3 I_vs = view_vector_from_screen_uv(uv_viewport, viewvecs, ProjectionMatrix);
-
- /* -------- SHADING --------- */
-#ifdef V3D_LIGHTING_FLAT
- vec3 shaded_color = base_color;
-
-#elif defined(V3D_LIGHTING_MATCAP)
- /* When using matcaps, the metallic is the backface sign. */
- normal_viewport = (metallic > 0.0) ? normal_viewport : -normal_viewport;
- bool flipped = world_data.matcap_orientation != 0;
- vec2 matcap_uv = matcap_uv_compute(I_vs, normal_viewport, flipped);
- vec3 matcap_diffuse = textureLod(matcapDiffuseImage, matcap_uv, 0.0).rgb;
-
-# ifdef V3D_SHADING_SPECULAR_HIGHLIGHT
- vec3 matcap_specular = textureLod(matcapSpecularImage, matcap_uv, 0.0).rgb;
-# else
- vec3 matcap_specular = vec3(0.0);
-# endif
-
- vec3 shaded_color = matcap_diffuse * base_color + matcap_specular;
-
-#elif defined(V3D_LIGHTING_STUDIO)
-
-# ifdef V3D_SHADING_SPECULAR_HIGHLIGHT
- vec3 specular_color = mix(vec3(0.05), base_color, metallic);
- vec3 diffuse_color = mix(base_color, vec3(0.0), metallic);
-# else
- roughness = 0.0;
- vec3 specular_color = vec3(0.0);
- vec3 diffuse_color = base_color;
-# endif
-
- vec3 shaded_color = get_world_lighting(
- world_data, diffuse_color, specular_color, roughness, normal_viewport, I_vs);
-#endif
-
- /* -------- POST EFFECTS --------- */
-#ifdef WB_CAVITY
- /* Using UNORM texture so decompress the range */
- shaded_color *= texelFetch(cavityBuffer, texel, 0).r * CAVITY_BUFFER_RANGE;
-#endif
-
-#ifdef V3D_SHADING_SHADOW
- float light_factor = -dot(normal_viewport, world_data.shadow_direction_vs.xyz);
- float shadow_mix = smoothstep(shadowFocus, shadowShift, light_factor);
- shaded_color *= mix(lightMultiplier, shadowMultiplier, shadow_mix);
-#endif
-
-#ifdef V3D_SHADING_OBJECT_OUTLINE
- uint object_id = texelFetch(objectId, texel, 0).r;
- float object_outline = calculate_object_outline(objectId, texel, object_id);
- shaded_color = mix(world_data.object_outline_color.rgb, shaded_color, object_outline);
-#endif
-
- fragColor = vec4(shaded_color, 1.0);
-}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_cavity_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_cavity_frag.glsl
new file mode 100644
index 00000000000..328d50e69e0
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_cavity_frag.glsl
@@ -0,0 +1,31 @@
+
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(workbench_common_lib.glsl)
+#pragma BLENDER_REQUIRE(workbench_cavity_lib.glsl)
+#pragma BLENDER_REQUIRE(workbench_curvature_lib.glsl)
+
+uniform sampler2D depthBuffer;
+uniform sampler2D normalBuffer;
+uniform usampler2D objectIdBuffer;
+
+in vec4 uvcoordsvar;
+
+out vec4 fragColor;
+
+void main()
+{
+ float cavity = 0.0, edges = 0.0, curvature = 0.0;
+
+#ifdef USE_CAVITY
+ cavity_compute(uvcoordsvar.st, depthBuffer, normalBuffer, cavity, edges);
+#endif
+
+#ifdef USE_CURVATURE
+ curvature_compute(uvcoordsvar.st, objectIdBuffer, normalBuffer, curvature);
+#endif
+
+ float final_cavity_factor = clamp((1.0 - cavity) * (1.0 + edges) * (1.0 + curvature), 0.0, 4.0);
+
+ fragColor.rgb = vec3(final_cavity_factor);
+ fragColor.a = 1.0;
+}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_fxaa_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_fxaa_frag.glsl
deleted file mode 100644
index 95ca2c0c297..00000000000
--- a/source/blender/draw/engines/workbench/shaders/workbench_effect_fxaa_frag.glsl
+++ /dev/null
@@ -1,14 +0,0 @@
-
-in vec4 uvcoordsvar;
-
-out vec4 FragColor;
-
-uniform sampler2D colorBuffer;
-uniform vec2 invertedViewportSize;
-
-void main()
-{
- ivec2 texel = ivec2(gl_FragCoord.xy);
- FragColor = FxaaPixelShader(
- uvcoordsvar.st, colorBuffer, invertedViewportSize, 1.0, 0.166, 0.0833);
-}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_outline_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_outline_frag.glsl
new file mode 100644
index 00000000000..fb6fdb93462
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_outline_frag.glsl
@@ -0,0 +1,24 @@
+
+#pragma BLENDER_REQUIRE(workbench_data_lib.glsl)
+
+uniform usampler2D objectIdBuffer;
+
+in vec4 uvcoordsvar;
+
+out vec4 fragColor;
+
+void main()
+{
+ vec3 offset = vec3(world_data.viewport_size_inv, 0.0) * world_data.ui_scale;
+ vec2 uv = uvcoordsvar.st;
+
+ uint center_id = texture(objectIdBuffer, uv).r;
+ uvec4 adjacent_ids = uvec4(texture(objectIdBuffer, uv + offset.zy).r,
+ texture(objectIdBuffer, uv - offset.zy).r,
+ texture(objectIdBuffer, uv + offset.xz).r,
+ texture(objectIdBuffer, uv - offset.xz).r);
+
+ float outline_opacity = 1.0 - dot(vec4(equal(uvec4(center_id), adjacent_ids)), vec4(0.25));
+
+ fragColor = world_data.object_outline_color * outline_opacity;
+}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_frag.glsl
new file mode 100644
index 00000000000..2dea2fc4883
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_frag.glsl
@@ -0,0 +1,44 @@
+
+uniform sampler2D edgesTex;
+uniform sampler2D areaTex;
+uniform sampler2D searchTex;
+uniform sampler2D blendTex;
+uniform sampler2D colorTex;
+uniform float mixFactor;
+uniform float taaSampleCountInv;
+
+in vec2 uvs;
+in vec2 pixcoord;
+in vec4 offset[3];
+
+#if SMAA_STAGE == 0
+out vec2 fragColor;
+#else
+out vec4 fragColor;
+#endif
+
+void main()
+{
+#if SMAA_STAGE == 0
+ /* Detect edges in color and revealage buffer. */
+ fragColor = SMAALumaEdgeDetectionPS(uvs, offset, colorTex);
+ /* Discard if there is no edge. */
+ if (dot(fragColor, float2(1.0, 1.0)) == 0.0) {
+ discard;
+ }
+
+#elif SMAA_STAGE == 1
+ fragColor = SMAABlendingWeightCalculationPS(
+ uvs, pixcoord, offset, edgesTex, areaTex, searchTex, vec4(0));
+
+#elif SMAA_STAGE == 2
+ fragColor = vec4(0.0);
+ if (mixFactor > 0.0) {
+ fragColor += SMAANeighborhoodBlendingPS(uvs, offset[0], colorTex, blendTex) * mixFactor;
+ }
+ if (mixFactor < 1.0) {
+ fragColor += texture(colorTex, uvs) * (1.0 - mixFactor);
+ }
+ fragColor *= taaSampleCountInv;
+#endif
+}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_vert.glsl
new file mode 100644
index 00000000000..07734d19972
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_vert.glsl
@@ -0,0 +1,21 @@
+
+out vec2 uvs;
+out vec2 pixcoord;
+out vec4 offset[3];
+
+void main()
+{
+ int v = gl_VertexID % 3;
+ float x = -1.0 + float((v & 1) << 2);
+ float y = -1.0 + float((v & 2) << 1);
+ gl_Position = vec4(x, y, 1.0, 1.0);
+ uvs = (gl_Position.xy + 1.0) * 0.5;
+
+#if SMAA_STAGE == 0
+ SMAAEdgeDetectionVS(uvs, offset);
+#elif SMAA_STAGE == 1
+ SMAABlendingWeightCalculationVS(uvs, pixcoord, offset);
+#elif SMAA_STAGE == 2
+ SMAANeighborhoodBlendingVS(uvs, offset[0]);
+#endif
+}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_taa_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_taa_frag.glsl
index 5795268f794..b877c2c3f76 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_effect_taa_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_taa_frag.glsl
@@ -1,14 +1,11 @@
-uniform sampler2D historyBuffer;
+
uniform sampler2D colorBuffer;
-out vec4 colorOutput;
+in vec4 uvcoordsvar;
-uniform float mixFactor;
+out vec4 fragColor;
void main()
{
- ivec2 texel = ivec2(gl_FragCoord.xy);
- vec4 color_buffer = texelFetch(colorBuffer, texel, 0);
- vec4 history_buffer = texelFetch(historyBuffer, texel, 0);
- colorOutput = mix(history_buffer, color_buffer, mixFactor);
+ fragColor = texture(colorBuffer, uvcoordsvar.st);
}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_forward_composite_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_forward_composite_frag.glsl
deleted file mode 100644
index 0a4d64b37ad..00000000000
--- a/source/blender/draw/engines/workbench/shaders/workbench_forward_composite_frag.glsl
+++ /dev/null
@@ -1,36 +0,0 @@
-out vec4 fragColor;
-
-uniform usampler2D objectId;
-uniform sampler2D transparentAccum;
-uniform sampler2D transparentRevealage;
-uniform vec2 invertedViewportSize;
-
-#ifndef ALPHA_COMPOSITE
-layout(std140) uniform world_block
-{
- WorldData world_data;
-};
-#endif
-
-/* TODO: Bypass the whole shader if there is no xray pass and no outline pass. */
-void main()
-{
- ivec2 texel = ivec2(gl_FragCoord.xy);
- vec2 uv_viewport = gl_FragCoord.xy * invertedViewportSize;
-
- /* Listing 4 */
- vec4 trans_accum = texelFetch(transparentAccum, texel, 0);
- float trans_revealage = trans_accum.a;
- trans_accum.a = texelFetch(transparentRevealage, texel, 0).r;
-
- vec3 trans_color = trans_accum.rgb / clamp(trans_accum.a, 1e-4, 5e4);
-
- fragColor.a = 1.0 - trans_revealage;
- fragColor.rgb = trans_color * fragColor.a;
-
-#ifdef V3D_SHADING_OBJECT_OUTLINE
- uint object_id = texelFetch(objectId, texel, 0).r;
- float outline = calculate_object_outline(objectId, texel, object_id);
- fragColor = mix(vec4(world_data.object_outline_color.rgb, 1.0), fragColor, outline);
-#endif
-}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_forward_depth_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_forward_depth_frag.glsl
deleted file mode 100644
index abd8c1f6579..00000000000
--- a/source/blender/draw/engines/workbench/shaders/workbench_forward_depth_frag.glsl
+++ /dev/null
@@ -1,20 +0,0 @@
-
-layout(location = 0) out uint objectId;
-
-uniform float ImageTransparencyCutoff = 0.1;
-#ifdef V3D_SHADING_TEXTURE_COLOR
-uniform sampler2D image;
-
-in vec2 uv_interp;
-#endif
-
-void main()
-{
-#ifdef V3D_SHADING_TEXTURE_COLOR
- if (texture(image, uv_interp).a < ImageTransparencyCutoff) {
- discard;
- }
-#endif
-
- objectId = uint(resource_id + 1) & 0xFFu;
-}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl
deleted file mode 100644
index 559dc07c107..00000000000
--- a/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl
+++ /dev/null
@@ -1,118 +0,0 @@
-
-uniform float ImageTransparencyCutoff = 0.1;
-#ifdef TEXTURE_IMAGE_ARRAY
-uniform sampler2DArray image_tile_array;
-uniform sampler1DArray image_tile_data;
-#else
-uniform sampler2D image;
-#endif
-uniform bool imageNearest;
-uniform bool imagePremultiplied;
-
-uniform float alpha = 0.5;
-uniform vec2 invertedViewportSize;
-uniform vec4 viewvecs[3];
-
-uniform vec4 materialColorAndMetal;
-uniform float materialRoughness;
-
-uniform float shadowMultiplier = 0.5;
-uniform float lightMultiplier = 1.0;
-uniform float shadowShift = 0.1;
-uniform float shadowFocus = 1.0;
-
-#ifdef NORMAL_VIEWPORT_PASS_ENABLED
-in vec3 normal_viewport;
-#endif /* NORMAL_VIEWPORT_PASS_ENABLED */
-#ifdef V3D_SHADING_TEXTURE_COLOR
-in vec2 uv_interp;
-#endif
-#ifdef V3D_SHADING_VERTEX_COLOR
-in vec3 vertexColor;
-#endif
-#ifdef V3D_LIGHTING_MATCAP
-uniform sampler2D matcapDiffuseImage;
-uniform sampler2D matcapSpecularImage;
-#endif
-
-layout(std140) uniform world_block
-{
- WorldData world_data;
-};
-
-layout(location = 0) out vec4 transparentAccum;
-layout(location = 1) out
- float revealageAccum; /* revealage actually stored in transparentAccum.a */
-
-void main()
-{
- vec4 base_color;
-
-#if defined(V3D_SHADING_TEXTURE_COLOR)
-# ifdef TEXTURE_IMAGE_ARRAY
- base_color = workbench_sample_texture_array(
- image_tile_array, image_tile_data, uv_interp, imageNearest, imagePremultiplied);
-# else
- base_color = workbench_sample_texture(image, uv_interp, imageNearest, imagePremultiplied);
-# endif
- if (base_color.a < ImageTransparencyCutoff) {
- discard;
- }
-#elif defined(V3D_SHADING_VERTEX_COLOR)
- base_color.rgb = vertexColor;
-#else
- base_color.rgb = materialColorAndMetal.rgb;
-#endif /* V3D_SHADING_TEXTURE_COLOR */
-
- vec2 uv_viewport = gl_FragCoord.xy * invertedViewportSize;
- vec3 I_vs = view_vector_from_screen_uv(uv_viewport, viewvecs, ProjectionMatrix);
-
-#ifdef NORMAL_VIEWPORT_PASS_ENABLED
- vec3 nor = normalize(normal_viewport);
-#endif
-
- /* -------- SHADING --------- */
-#ifdef V3D_LIGHTING_FLAT
- vec3 shaded_color = base_color.rgb;
-
-#elif defined(V3D_LIGHTING_MATCAP)
- bool flipped = world_data.matcap_orientation != 0;
- vec2 matcap_uv = matcap_uv_compute(I_vs, nor, flipped);
- vec3 matcap_diffuse = textureLod(matcapDiffuseImage, matcap_uv, 0.0).rgb;
-# ifdef V3D_SHADING_SPECULAR_HIGHLIGHT
- vec3 matcap_specular = textureLod(matcapSpecularImage, matcap_uv, 0.0).rgb;
-# else
- vec3 matcap_specular = vec3(0.0);
-# endif
- vec3 shaded_color = matcap_diffuse * base_color.rgb + matcap_specular;
-
-#elif defined(V3D_LIGHTING_STUDIO)
-# ifdef V3D_SHADING_SPECULAR_HIGHLIGHT
- float metallic = materialColorAndMetal.a;
- vec3 specular_color = mix(vec3(0.05), base_color.rgb, metallic);
- vec3 diffuse_color = mix(base_color.rgb, vec3(0.0), metallic);
-# else
- vec3 specular_color = vec3(0.0);
- vec3 diffuse_color = base_color.rgb;
-# endif
-
- vec3 shaded_color = get_world_lighting(
- world_data, diffuse_color, specular_color, materialRoughness, nor, I_vs);
-#endif
-
-#ifdef V3D_SHADING_SHADOW
- float light_factor = -dot(nor, world_data.shadow_direction_vs.xyz);
- float shadow_mix = smoothstep(shadowFocus, shadowShift, light_factor);
- shaded_color *= mix(lightMultiplier, shadowMultiplier, shadow_mix);
-#endif
-
- /* Based on :
- * McGuire and Bavoil, Weighted Blended Order-Independent Transparency, Journal of
- * Computer Graphics Techniques (JCGT), vol. 2, no. 2, 122–141, 2013
- */
- /* Listing 4 */
- float z = linear_zdepth(gl_FragCoord.z, viewvecs, ProjectionMatrix);
- float weight = calculate_transparent_weight(z, alpha);
- transparentAccum = vec4(shaded_color * weight, alpha);
- revealageAccum = weight;
-}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_ghost_resolve_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_ghost_resolve_frag.glsl
deleted file mode 100644
index d223a7650c5..00000000000
--- a/source/blender/draw/engines/workbench/shaders/workbench_ghost_resolve_frag.glsl
+++ /dev/null
@@ -1,13 +0,0 @@
-uniform sampler2D depthBuffer;
-
-void main(void)
-{
- float depth = texelFetch(depthBuffer, ivec2(gl_FragCoord.xy), 0).r;
-
- /* background, discard */
- if (depth >= 1.0) {
- discard;
- }
-
- gl_FragDepth = depth;
-}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_image_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_image_lib.glsl
new file mode 100644
index 00000000000..6f99739f259
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/workbench_image_lib.glsl
@@ -0,0 +1,83 @@
+
+/* TODO(fclem) deduplicate code. */
+bool node_tex_tile_lookup(inout vec3 co, sampler2DArray ima, sampler1DArray map)
+{
+ vec2 tile_pos = floor(co.xy);
+
+ if (tile_pos.x < 0 || tile_pos.y < 0 || tile_pos.x >= 10)
+ return false;
+
+ float tile = 10.0 * tile_pos.y + tile_pos.x;
+ if (tile >= textureSize(map, 0).x)
+ return false;
+
+ /* Fetch tile information. */
+ float tile_layer = texelFetch(map, ivec2(tile, 0), 0).x;
+ if (tile_layer < 0.0)
+ return false;
+
+ vec4 tile_info = texelFetch(map, ivec2(tile, 1), 0);
+
+ co = vec3(((co.xy - tile_pos) * tile_info.zw) + tile_info.xy, tile_layer);
+ return true;
+}
+
+vec4 workbench_sample_texture(sampler2D image, vec2 coord, bool nearest_sampling)
+{
+ vec2 tex_size = vec2(textureSize(image, 0).xy);
+ /* TODO(fclem) We could do the same with sampler objects.
+ * But this is a quick workaround instead of messing with the GPUTexture itself. */
+ vec2 uv = nearest_sampling ? (floor(coord * tex_size) + 0.5) / tex_size : coord;
+ return texture(image, uv);
+}
+
+vec4 workbench_sample_texture_array(sampler2DArray tile_array,
+ sampler1DArray tile_data,
+ vec2 coord,
+ bool nearest_sampling)
+{
+ vec2 tex_size = vec2(textureSize(tile_array, 0).xy);
+
+ vec3 uv = vec3(coord, 0);
+ if (!node_tex_tile_lookup(uv, tile_array, tile_data))
+ return vec4(1.0, 0.0, 1.0, 1.0);
+
+ /* TODO(fclem) We could do the same with sampler objects.
+ * But this is a quick workaround instead of messing with the GPUTexture itself. */
+ uv.xy = nearest_sampling ? (floor(uv.xy * tex_size) + 0.5) / tex_size : uv.xy;
+ return texture(tile_array, uv);
+}
+
+uniform sampler2DArray imageTileArray;
+uniform sampler1DArray imageTileData;
+uniform sampler2D imageTexture;
+
+uniform float imageTransparencyCutoff = 0.1;
+uniform bool imageNearest;
+uniform bool imagePremult;
+
+vec3 workbench_image_color(vec2 uvs)
+{
+#ifdef V3D_SHADING_TEXTURE_COLOR
+# ifdef TEXTURE_IMAGE_ARRAY
+ vec4 color = workbench_sample_texture_array(imageTileArray, imageTileData, uvs, imageNearest);
+# else
+ vec4 color = workbench_sample_texture(imageTexture, uvs, imageNearest);
+# endif
+
+ /* Unpremultiply if stored multiplied, since straight alpha is expected by shaders. */
+ if (imagePremult && !(color.a == 0.0 || color.a == 1.0)) {
+ color.rgb /= color.a;
+ }
+
+# ifdef GPU_FRAGMENT_SHADER
+ if (color.a < imageTransparencyCutoff) {
+ discard;
+ }
+# endif
+
+ return color.rgb;
+#else
+ return vec3(1.0);
+#endif
+}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_matcap_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_matcap_lib.glsl
new file mode 100644
index 00000000000..2d18cc1b014
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/workbench_matcap_lib.glsl
@@ -0,0 +1,30 @@
+
+#pragma BLENDER_REQUIRE(workbench_data_lib.glsl)
+
+vec2 matcap_uv_compute(vec3 I, vec3 N, bool flipped)
+{
+ /* Quick creation of an orthonormal basis */
+ float a = 1.0 / (1.0 + I.z);
+ float b = -I.x * I.y * a;
+ vec3 b1 = vec3(1.0 - I.x * I.x * a, b, -I.x);
+ vec3 b2 = vec3(b, 1.0 - I.y * I.y * a, -I.y);
+ vec2 matcap_uv = vec2(dot(b1, N), dot(b2, N));
+ if (flipped) {
+ matcap_uv.x = -matcap_uv.x;
+ }
+ return matcap_uv * 0.496 + 0.5;
+}
+
+uniform sampler2D matcapDiffuseImage;
+uniform sampler2D matcapSpecularImage;
+
+vec3 get_matcap_lighting(vec3 base_color, vec3 N, vec3 I)
+{
+ bool flipped = world_data.matcap_orientation != 0;
+ vec2 uv = matcap_uv_compute(I, N, flipped);
+
+ vec3 diffuse = textureLod(matcapDiffuseImage, uv, 0.0).rgb;
+ vec3 specular = textureLod(matcapSpecularImage, uv, 0.0).rgb;
+
+ return diffuse * base_color + specular * float(world_data.use_specular);
+}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_material_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_material_lib.glsl
new file mode 100644
index 00000000000..1d8950e34b3
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/workbench_material_lib.glsl
@@ -0,0 +1,21 @@
+
+layout(std140) uniform material_block
+{
+ vec4 mat_data[4096];
+};
+
+/* If set to -1, the resource handle is used instead. */
+uniform int materialIndex;
+
+void workbench_material_data_get(
+ int handle, out vec3 color, out float alpha, out float roughness, out float metallic)
+{
+ handle = (materialIndex != -1) ? materialIndex : handle;
+ vec4 data = mat_data[uint(handle) & 0xFFFu];
+ color = data.rgb;
+
+ uint encoded_data = floatBitsToUint(data.w);
+ alpha = float((encoded_data >> 16u) & 0xFFu) * (1.0 / 255.0);
+ roughness = float((encoded_data >> 8u) & 0xFFu) * (1.0 / 255.0);
+ metallic = float(encoded_data & 0xFFu) * (1.0 / 255.0);
+}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_merge_infront_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_merge_infront_frag.glsl
new file mode 100644
index 00000000000..58becb03290
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/workbench_merge_infront_frag.glsl
@@ -0,0 +1,18 @@
+
+uniform sampler2D depthBuffer;
+
+in vec4 uvcoordsvar;
+
+out vec4 fragColor;
+
+void main()
+{
+ float depth = texture(depthBuffer, uvcoordsvar.st).r;
+ /* Discard background pixels. */
+ if (depth == 1.0) {
+ discard;
+ }
+ /* Make this fragment occlude any fragment that will try to
+ * render over it in the normal passes. */
+ gl_FragDepth = 0.0;
+} \ No newline at end of file
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_object_outline_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_object_outline_lib.glsl
deleted file mode 100644
index a4a5d9c31a3..00000000000
--- a/source/blender/draw/engines/workbench/shaders/workbench_object_outline_lib.glsl
+++ /dev/null
@@ -1,12 +0,0 @@
-#define OBJECT_OUTLINE_OFFSET 1
-
-float calculate_object_outline(usampler2D objectId, ivec2 texel, uint object_id)
-{
- uvec4 oid_offset = uvec4(
- texelFetchOffset(objectId, texel, 0, ivec2(0, OBJECT_OUTLINE_OFFSET)).r,
- texelFetchOffset(objectId, texel, 0, ivec2(0, -OBJECT_OUTLINE_OFFSET)).r,
- texelFetchOffset(objectId, texel, 0, ivec2(-OBJECT_OUTLINE_OFFSET, 0)).r,
- texelFetchOffset(objectId, texel, 0, ivec2(OBJECT_OUTLINE_OFFSET, 0)).r);
-
- return dot(vec4(equal(uvec4(object_id), oid_offset)), vec4(0.25));
-}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl
index 94e41b4bcd4..6d24b001d4d 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl
@@ -1,92 +1,29 @@
-uniform vec4 materialColorAndMetal;
-uniform float materialRoughness;
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(workbench_shader_interface_lib.glsl)
+#pragma BLENDER_REQUIRE(workbench_common_lib.glsl)
+#pragma BLENDER_REQUIRE(workbench_image_lib.glsl)
-#ifdef TEXTURE_IMAGE_ARRAY
-uniform sampler2DArray image_tile_array;
-uniform sampler1DArray image_tile_data;
-#else
-uniform sampler2D image;
-#endif
-uniform float ImageTransparencyCutoff = 0.1;
-uniform bool imageNearest;
-uniform bool imagePremultiplied;
-
-#ifdef NORMAL_VIEWPORT_PASS_ENABLED
-in vec3 normal_viewport;
-#endif
-
-#ifdef V3D_SHADING_TEXTURE_COLOR
-in vec2 uv_interp;
-#endif
-#ifdef V3D_SHADING_VERTEX_COLOR
-in vec3 vertexColor;
-#endif
-
-#ifdef HAIR_SHADER
-flat in float hair_rand;
-#endif
-
-#ifdef MATDATA_PASS_ENABLED
layout(location = 0) out vec4 materialData;
-#endif
-#ifdef OBJECT_ID_PASS_ENABLED
-layout(location = 1) out uint objectId;
-#endif
-#ifdef NORMAL_VIEWPORT_PASS_ENABLED
-layout(location = 2) out WB_Normal normalViewport;
-#endif
+layout(location = 1) out WB_Normal normalData;
+layout(location = 2) out uint objectId;
+
+uniform bool useMatcap = false;
void main()
{
-#ifdef MATDATA_PASS_ENABLED
- float metallic, roughness;
- vec4 color;
-
-# if defined(V3D_SHADING_TEXTURE_COLOR)
-# ifdef TEXTURE_IMAGE_ARRAY
- color = workbench_sample_texture_array(
- image_tile_array, image_tile_data, uv_interp, imageNearest, imagePremultiplied);
-# else
- color = workbench_sample_texture(image, uv_interp, imageNearest, imagePremultiplied);
-# endif
- if (color.a < ImageTransparencyCutoff) {
- discard;
- }
-# elif defined(V3D_SHADING_VERTEX_COLOR)
- color.rgb = vertexColor;
-# else
- color.rgb = materialColorAndMetal.rgb;
-# endif
-
-# ifdef V3D_LIGHTING_MATCAP
- /* Encode front facing in metallic channel. */
- metallic = float(gl_FrontFacing);
- roughness = 0.0;
-# else
- metallic = materialColorAndMetal.a;
- roughness = materialRoughness;
-# endif
+ normalData = workbench_normal_encode(gl_FrontFacing, normal_interp);
-# ifdef HAIR_SHADER
- /* Add some variation to the hairs to avoid uniform look. */
- float hair_variation = hair_rand * 0.1;
- color = clamp(color - hair_variation, 0.0, 1.0);
- metallic = clamp(materialColorAndMetal.a - hair_variation, 0.0, 1.0);
- roughness = clamp(materialRoughness - hair_variation, 0.0, 1.0);
-# endif
+ materialData = vec4(color_interp, packed_rough_metal);
- materialData.rgb = color.rgb;
- materialData.a = workbench_float_pair_encode(roughness, metallic);
-#endif /* MATDATA_PASS_ENABLED */
+ objectId = uint(object_id);
-#ifdef OBJECT_ID_PASS_ENABLED
- objectId = uint(resource_id + 1) & 0xFFu;
-#endif
+ if (useMatcap) {
+ /* For matcaps, save front facing in alpha channel. */
+ materialData.a = float(gl_FrontFacing);
+ }
-#ifdef NORMAL_VIEWPORT_PASS_ENABLED
- vec3 n = (gl_FrontFacing) ? normal_viewport : -normal_viewport;
- n = normalize(n);
- normalViewport = workbench_normal_encode(n);
+#ifdef V3D_SHADING_TEXTURE_COLOR
+ materialData.rgb = workbench_image_color(uv_interp);
#endif
}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_prepass_hair_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_prepass_hair_vert.glsl
new file mode 100644
index 00000000000..6a7bc185fe9
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_hair_vert.glsl
@@ -0,0 +1,94 @@
+#pragma BLENDER_REQUIRE(common_hair_lib.glsl)
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(workbench_shader_interface_lib.glsl)
+#pragma BLENDER_REQUIRE(workbench_common_lib.glsl)
+#pragma BLENDER_REQUIRE(workbench_material_lib.glsl)
+#pragma BLENDER_REQUIRE(workbench_image_lib.glsl)
+
+uniform samplerBuffer ac; /* active color layer */
+uniform samplerBuffer au; /* active texture layer */
+
+/* From http://libnoise.sourceforge.net/noisegen/index.html */
+float integer_noise(int n)
+{
+ n = (n >> 13) ^ n;
+ int nn = (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff;
+ return (float(nn) / 1073741824.0);
+}
+
+vec3 workbench_hair_random_normal(vec3 tan, vec3 binor, float rand)
+{
+ /* To "simulate" anisotropic shading, randomize hair normal per strand. */
+ vec3 nor = cross(tan, binor);
+ nor = normalize(mix(nor, -tan, rand * 0.1));
+ float cos_theta = (rand * 2.0 - 1.0) * 0.2;
+ float sin_theta = sqrt(max(0.0, 1.0 - cos_theta * cos_theta));
+ nor = nor * sin_theta + binor * cos_theta;
+ return nor;
+}
+
+void workbench_hair_random_material(float rand,
+ inout vec3 color,
+ inout float roughness,
+ inout float metallic)
+{
+ /* Center noise around 0. */
+ rand -= 0.5;
+ rand *= 0.1;
+ /* Add some variation to the hairs to avoid uniform look. */
+ metallic = clamp(metallic + rand, 0.0, 1.0);
+ roughness = clamp(roughness + rand, 0.0, 1.0);
+ /* Modulate by color intensity to reduce very high contrast when color is dark. */
+ color = clamp(color + rand * (color + 0.05), 0.0, 1.0);
+}
+
+void main()
+{
+ bool is_persp = (ProjectionMatrix[3][3] == 0.0);
+ float time, thick_time, thickness;
+ vec3 world_pos, tan, binor;
+ hair_get_pos_tan_binor_time(is_persp,
+ ModelMatrixInverse,
+ ViewMatrixInverse[3].xyz,
+ ViewMatrixInverse[2].xyz,
+ world_pos,
+ tan,
+ binor,
+ time,
+ thickness,
+ thick_time);
+
+ gl_Position = point_world_to_ndc(world_pos);
+
+ float hair_rand = integer_noise(hair_get_strand_id());
+ vec3 nor = workbench_hair_random_normal(tan, binor, hair_rand);
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(world_pos);
+#endif
+
+ uv_interp = hair_get_customdata_vec2(au);
+
+ normal_interp = normalize(normal_world_to_view(nor));
+
+#ifdef OPAQUE_MATERIAL
+ float metallic, roughness;
+#endif
+ workbench_material_data_get(resource_handle, color_interp, alpha_interp, roughness, metallic);
+
+ if (materialIndex == 0) {
+ color_interp = hair_get_customdata_vec3(ac);
+ }
+
+ /* Hairs have lots of layer and can rapidly become the most prominent surface.
+ * So we lower their alpha artificially. */
+ alpha_interp *= 0.3;
+
+ workbench_hair_random_material(hair_rand, color_interp, roughness, metallic);
+
+#ifdef OPAQUE_MATERIAL
+ packed_rough_metal = workbench_float_pair_encode(roughness, metallic);
+#endif
+
+ object_id = int((uint(resource_id) + 1u) & 0xFFu);
+}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl
index 0a3252f0b9b..31e298d1540 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl
@@ -1,110 +1,40 @@
-#ifndef HAIR_SHADER
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(workbench_shader_interface_lib.glsl)
+#pragma BLENDER_REQUIRE(workbench_common_lib.glsl)
+#pragma BLENDER_REQUIRE(workbench_material_lib.glsl)
+#pragma BLENDER_REQUIRE(workbench_image_lib.glsl)
+
in vec3 pos;
in vec3 nor;
-in vec2 au; /* active texture layer */
-# ifdef V3D_SHADING_VERTEX_COLOR
in vec4 ac; /* active color */
-# endif
-# define uv au
-#else /* HAIR_SHADER */
-
-# ifdef V3D_SHADING_TEXTURE_COLOR
-uniform samplerBuffer au; /* active texture layer */
-# endif
-# ifdef V3D_SHADING_VERTEX_COLOR
-uniform samplerBuffer ac; /* active color layer */
-# endif
-
-flat out float hair_rand;
-#endif /* HAIR_SHADER */
-
-#ifdef NORMAL_VIEWPORT_PASS_ENABLED
-out vec3 normal_viewport;
-#endif
-
-#ifdef V3D_SHADING_TEXTURE_COLOR
-out vec2 uv_interp;
-#endif
-#ifdef V3D_SHADING_VERTEX_COLOR
-out vec3 vertexColor;
-#endif
-
-#ifdef OBJECT_ID_PASS_ENABLED
-RESOURCE_ID_VARYING
-#endif
-
-/* From http://libnoise.sourceforge.net/noisegen/index.html */
-float integer_noise(int n)
-{
- n = (n >> 13) ^ n;
- int nn = (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff;
- return (float(nn) / 1073741824.0);
-}
-
-vec3 workbench_hair_hair_normal(vec3 tan, vec3 binor, float rand)
-{
- /* To "simulate" anisotropic shading, randomize hair normal per strand. */
- vec3 nor = cross(tan, binor);
- nor = normalize(mix(nor, -tan, rand * 0.1));
- float cos_theta = (rand * 2.0 - 1.0) * 0.2;
- float sin_theta = sqrt(max(0.0, 1.0 - cos_theta * cos_theta));
- nor = nor * sin_theta + binor * cos_theta;
- return nor;
-}
+in vec2 au; /* active texture layer */
void main()
{
-#ifdef HAIR_SHADER
-# ifdef V3D_SHADING_TEXTURE_COLOR
- vec2 uv = hair_get_customdata_vec2(au);
-# endif
- float time, thick_time, thickness;
- vec3 world_pos, tan, binor;
- hair_get_pos_tan_binor_time((ProjectionMatrix[3][3] == 0.0),
- ModelMatrixInverse,
- ViewMatrixInverse[3].xyz,
- ViewMatrixInverse[2].xyz,
- world_pos,
- tan,
- binor,
- time,
- thickness,
- thick_time);
-
- hair_rand = integer_noise(hair_get_strand_id());
- vec3 nor = workbench_hair_hair_normal(tan, binor, hair_rand);
-#else
vec3 world_pos = point_object_to_world(pos);
-#endif
gl_Position = point_world_to_ndc(world_pos);
-#ifdef V3D_SHADING_TEXTURE_COLOR
- uv_interp = uv;
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(world_pos);
#endif
-#ifdef V3D_SHADING_VERTEX_COLOR
-# ifndef HAIR_SHADER
- vertexColor = ac.rgb;
-# else
- vertexColor = hair_get_customdata_vec4(ac).rgb;
-# endif
-#endif
+ uv_interp = au;
-#ifdef NORMAL_VIEWPORT_PASS_ENABLED
-# ifndef HAIR_SHADER
- normal_viewport = normal_object_to_view(nor);
- normal_viewport = normalize(normal_viewport);
-# else
- normal_viewport = normal_world_to_view(nor);
-# endif
-#endif
+ normal_interp = normalize(normal_object_to_view(nor));
-#ifdef OBJECT_ID_PASS_ENABLED
- PASS_RESOURCE_ID
+#ifdef OPAQUE_MATERIAL
+ float metallic, roughness;
#endif
+ workbench_material_data_get(resource_handle, color_interp, alpha_interp, roughness, metallic);
-#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_calc_clip_distance(world_pos);
+ if (materialIndex == 0) {
+ color_interp = ac.rgb;
+ }
+
+#ifdef OPAQUE_MATERIAL
+ packed_rough_metal = workbench_float_pair_encode(roughness, metallic);
#endif
+
+ object_id = int((uint(resource_id) + 1u) & 0xFFu);
}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_shader_interface_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_shader_interface_lib.glsl
new file mode 100644
index 00000000000..8e2f7ba4735
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/workbench_shader_interface_lib.glsl
@@ -0,0 +1,21 @@
+
+#ifdef GPU_VERTEX_SHADER
+# define IN_OUT out
+#else
+# define IN_OUT in
+#endif
+
+IN_OUT ShaderStageInterface
+{
+ vec3 normal_interp;
+ vec3 color_interp;
+ float alpha_interp;
+ vec2 uv_interp;
+#ifdef TRANSPARENT_MATERIAL
+ flat float roughness;
+ flat float metallic;
+#else
+ flat float packed_rough_metal;
+#endif
+ flat int object_id;
+};
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
new file mode 100644
index 00000000000..3c2d1a9c0c7
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/workbench_transparent_accum_frag.glsl
@@ -0,0 +1,89 @@
+
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(workbench_shader_interface_lib.glsl)
+#pragma BLENDER_REQUIRE(workbench_common_lib.glsl)
+#pragma BLENDER_REQUIRE(workbench_image_lib.glsl)
+#pragma BLENDER_REQUIRE(workbench_matcap_lib.glsl)
+#pragma BLENDER_REQUIRE(workbench_world_light_lib.glsl)
+
+/* Revealage is actually stored in transparentAccum alpha channel.
+ * This is a workaround to older hardware not having separate blend equation per render target. */
+layout(location = 0) out vec4 transparentAccum;
+layout(location = 1) out vec4 revealageAccum;
+
+/* Note: Blending will be skipped on objectId because output is a non-normalized integer buffer. */
+layout(location = 2) out uint objectId;
+
+/* Special function only to be used with calculate_transparent_weight(). */
+float linear_zdepth(float depth, vec4 viewvecs[3], mat4 proj_mat)
+{
+ if (proj_mat[3][3] == 0.0) {
+ float d = 2.0 * depth - 1.0;
+ return -proj_mat[3][2] / (d + proj_mat[2][2]);
+ }
+ else {
+ /* Return depth from near plane. */
+ return depth * viewvecs[1].z;
+ }
+}
+
+/* Based on :
+ * McGuire and Bavoil, Weighted Blended Order-Independent Transparency, Journal of
+ * Computer Graphics Techniques (JCGT), vol. 2, no. 2, 122–141, 2013
+ */
+float calculate_transparent_weight(void)
+{
+ float z = linear_zdepth(gl_FragCoord.z, world_data.viewvecs, ProjectionMatrix);
+#if 0
+ /* Eq 10 : Good for surfaces with varying opacity (like particles) */
+ float a = min(1.0, alpha * 10.0) + 0.01;
+ float b = -gl_FragCoord.z * 0.95 + 1.0;
+ float w = a * a * a * 3e2 * b * b * b;
+#else
+ /* Eq 7 put more emphasis on surfaces closer to the view. */
+ // float w = 10.0 / (1e-5 + pow(abs(z) / 5.0, 2.0) + pow(abs(z) / 200.0, 6.0)); /* Eq 7 */
+ // float w = 10.0 / (1e-5 + pow(abs(z) / 10.0, 3.0) + pow(abs(z) / 200.0, 6.0)); /* Eq 8 */
+ // float w = 10.0 / (1e-5 + pow(abs(z) / 200.0, 4.0)); /* Eq 9 */
+ /* Same as eq 7, but optimized. */
+ float a = abs(z) / 5.0;
+ float b = abs(z) / 200.0;
+ b *= b;
+ float w = 10.0 / ((1e-5 + a * a) + b * (b * b)); /* Eq 7 */
+#endif
+ return clamp(w, 1e-2, 3e2);
+}
+
+void main()
+{
+ /* Normal and Incident vector are in viewspace. Lighting is evaluated in viewspace. */
+ vec2 uv_viewport = gl_FragCoord.xy * world_data.viewport_size_inv;
+ vec3 I = view_vector_from_screen_uv(uv_viewport, world_data.viewvecs, ProjectionMatrix);
+ vec3 N = normalize(normal_interp);
+
+ vec3 color = color_interp;
+
+#ifdef V3D_SHADING_TEXTURE_COLOR
+ color = workbench_image_color(uv_interp);
+#endif
+
+#ifdef V3D_LIGHTING_MATCAP
+ vec3 shaded_color = get_matcap_lighting(color, N, I);
+#endif
+
+#ifdef V3D_LIGHTING_STUDIO
+ vec3 shaded_color = get_world_lighting(color, roughness, metallic, N, I);
+#endif
+
+#ifdef V3D_LIGHTING_FLAT
+ 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);
+ revealageAccum = vec4(weight);
+
+ objectId = uint(object_id);
+}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_transparent_resolve_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_transparent_resolve_frag.glsl
new file mode 100644
index 00000000000..d985737a35b
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/workbench_transparent_resolve_frag.glsl
@@ -0,0 +1,26 @@
+
+uniform sampler2D transparentAccum;
+uniform sampler2D transparentRevealage;
+
+in vec4 uvcoordsvar;
+
+out vec4 fragColor;
+
+/* Based on :
+ * McGuire and Bavoil, Weighted Blended Order-Independent Transparency, Journal of
+ * Computer Graphics Techniques (JCGT), vol. 2, no. 2, 122–141, 2013
+ */
+
+void main()
+{
+ /* Revealage is actually stored in transparentAccum alpha channel.
+ * This is a workaround to older hardware not having separate blend equation per render target.
+ */
+ vec4 trans_accum = texture(transparentAccum, uvcoordsvar.st);
+ float trans_weight = texture(transparentRevealage, uvcoordsvar.st).r;
+ float trans_reveal = trans_accum.a;
+
+ /* Listing 4 */
+ fragColor.rgb = trans_accum.rgb / clamp(trans_weight, 1e-4, 5e4);
+ fragColor.a = 1.0 - trans_reveal;
+}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl
index 585e48ae7ec..e957f8bbe9c 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl
@@ -1,4 +1,9 @@
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_common_obinfos_lib.glsl)
+#pragma BLENDER_REQUIRE(workbench_data_lib.glsl)
+#pragma BLENDER_REQUIRE(workbench_common_lib.glsl)
+
uniform sampler2D depthBuffer;
uniform sampler3D densityTexture;
@@ -8,10 +13,9 @@ uniform sampler1D flameColorTexture;
uniform sampler1D transferTexture;
uniform int samplesLen = 256;
-uniform float noiseOfs = 0.0f;
+uniform float noiseOfs = 0.0;
uniform float stepLength; /* Step length in local space. */
uniform float densityScale; /* Simple Opacity multiplicator. */
-uniform vec4 viewvecs[3];
uniform vec3 activeColor;
uniform float slicePosition;
@@ -23,34 +27,11 @@ in vec3 localPos;
out vec4 fragColor;
-#define M_PI 3.1415926535897932 /* pi */
-
float phase_function_isotropic()
{
return 1.0 / (4.0 * M_PI);
}
-float get_view_z_from_depth(float depth)
-{
- if (ProjectionMatrix[3][3] == 0.0) {
- float d = 2.0 * depth - 1.0;
- return -ProjectionMatrix[3][2] / (d + ProjectionMatrix[2][2]);
- }
- else {
- return viewvecs[0].z + depth * viewvecs[1].z;
- }
-}
-
-vec3 get_view_space_from_depth(vec2 uvcoords, float depth)
-{
- if (ProjectionMatrix[3][3] == 0.0) {
- return vec3(viewvecs[0].xy + uvcoords * viewvecs[1].xy, 1.0) * get_view_z_from_depth(depth);
- }
- else {
- return viewvecs[0].xyz + vec3(uvcoords, depth) * viewvecs[1].xyz;
- }
-}
-
float max_v3(vec3 v)
{
return max(v.x, max(v.y, v.z));
@@ -209,8 +190,10 @@ void main()
float depth = texelFetch(depthBuffer, ivec2(gl_FragCoord.xy), 0).r;
float depth_end = min(depth, gl_FragCoord.z);
- vec3 vs_ray_end = get_view_space_from_depth(screen_uv, depth_end);
- vec3 vs_ray_ori = get_view_space_from_depth(screen_uv, 0.0);
+ vec3 vs_ray_end = view_position_from_depth(
+ screen_uv, depth_end, world_data.viewvecs, ProjectionMatrix);
+ vec3 vs_ray_ori = view_position_from_depth(
+ screen_uv, 0.0, world_data.viewvecs, ProjectionMatrix);
vec3 vs_ray_dir = (is_persp) ? (vs_ray_end - vs_ray_ori) : vec3(0.0, 0.0, -1.0);
vs_ray_dir /= abs(vs_ray_dir.z);
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl
index 3542a1a91fc..1a32a202290 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl
@@ -1,4 +1,7 @@
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_common_obinfos_lib.glsl)
+
uniform float slicePosition;
uniform int sliceAxis; /* -1 is no slice, 0 is X, 1 is Y, 2 is Z. */
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 690ce5d527f..81f6e651be0 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
@@ -1,4 +1,6 @@
+#pragma BLENDER_REQUIRE(workbench_data_lib.glsl)
+
/* [Drobot2014a] Low Level Optimizations for GCN */
vec4 fast_rcp(vec4 v)
{
@@ -41,9 +43,19 @@ vec4 wrapped_lighting(vec4 NL, vec4 w)
return clamp((NL + w) * denom, 0.0, 1.0);
}
-vec3 get_world_lighting(
- WorldData world_data, vec3 diffuse_color, vec3 specular_color, float roughness, vec3 N, vec3 I)
+vec3 get_world_lighting(vec3 base_color, float roughness, float metallic, vec3 N, vec3 I)
{
+ vec3 specular_color, diffuse_color;
+
+ if (world_data.use_specular) {
+ diffuse_color = mix(base_color, vec3(0.0), metallic);
+ specular_color = mix(vec3(0.05), base_color, metallic);
+ }
+ else {
+ diffuse_color = base_color;
+ specular_color = vec3(0.0);
+ }
+
vec3 specular_light = world_data.ambient_color.rgb;
vec3 diffuse_light = world_data.ambient_color.rgb;
vec4 wrap = vec4(world_data.lights[0].diffuse_color_wrap.a,
@@ -51,37 +63,37 @@ vec3 get_world_lighting(
world_data.lights[2].diffuse_color_wrap.a,
world_data.lights[3].diffuse_color_wrap.a);
-#ifdef V3D_SHADING_SPECULAR_HIGHLIGHT
- /* Prepare Specular computation. Eval 4 lights at once. */
- vec3 R = -reflect(I, N);
- vec4 spec_angle, spec_NL, wrap_NL;
- prep_specular(world_data.lights[0].direction.xyz, I, N, R, spec_NL.x, wrap_NL.x, spec_angle.x);
- prep_specular(world_data.lights[1].direction.xyz, I, N, R, spec_NL.y, wrap_NL.y, spec_angle.y);
- prep_specular(world_data.lights[2].direction.xyz, I, N, R, spec_NL.z, wrap_NL.z, spec_angle.z);
- prep_specular(world_data.lights[3].direction.xyz, I, N, R, spec_NL.w, wrap_NL.w, spec_angle.w);
-
- vec4 gloss = vec4(1.0 - roughness);
- /* Reduce gloss for smooth light. (simulate bigger light) */
- gloss *= 1.0 - wrap;
- vec4 shininess = exp2(10.0 * gloss + 1.0);
-
- vec4 spec_light = blinn_specular(shininess, spec_angle, spec_NL);
-
- /* Simulate Env. light. */
- vec4 w = mix(wrap, vec4(1.0), roughness);
- vec4 spec_env = wrapped_lighting(wrap_NL, w);
-
- spec_light = mix(spec_light, spec_env, wrap * wrap);
-
- /* Multiply result by lights specular colors. */
- specular_light += spec_light.x * world_data.lights[0].specular_color.rgb;
- specular_light += spec_light.y * world_data.lights[1].specular_color.rgb;
- specular_light += spec_light.z * world_data.lights[2].specular_color.rgb;
- specular_light += spec_light.w * world_data.lights[3].specular_color.rgb;
-
- float NV = clamp(dot(N, I), 0.0, 1.0);
- specular_color = brdf_approx(specular_color, roughness, NV);
-#endif
+ if (world_data.use_specular) {
+ /* Prepare Specular computation. Eval 4 lights at once. */
+ vec3 R = -reflect(I, N);
+ vec4 spec_angle, spec_NL, wrap_NL;
+ prep_specular(world_data.lights[0].direction.xyz, I, N, R, spec_NL.x, wrap_NL.x, spec_angle.x);
+ prep_specular(world_data.lights[1].direction.xyz, I, N, R, spec_NL.y, wrap_NL.y, spec_angle.y);
+ prep_specular(world_data.lights[2].direction.xyz, I, N, R, spec_NL.z, wrap_NL.z, spec_angle.z);
+ prep_specular(world_data.lights[3].direction.xyz, I, N, R, spec_NL.w, wrap_NL.w, spec_angle.w);
+
+ vec4 gloss = vec4(1.0 - roughness);
+ /* Reduce gloss for smooth light. (simulate bigger light) */
+ gloss *= 1.0 - wrap;
+ vec4 shininess = exp2(10.0 * gloss + 1.0);
+
+ vec4 spec_light = blinn_specular(shininess, spec_angle, spec_NL);
+
+ /* Simulate Env. light. */
+ vec4 w = mix(wrap, vec4(1.0), roughness);
+ vec4 spec_env = wrapped_lighting(wrap_NL, w);
+
+ spec_light = mix(spec_light, spec_env, wrap * wrap);
+
+ /* Multiply result by lights specular colors. */
+ specular_light += spec_light.x * world_data.lights[0].specular_color.rgb;
+ specular_light += spec_light.y * world_data.lights[1].specular_color.rgb;
+ specular_light += spec_light.z * world_data.lights[2].specular_color.rgb;
+ specular_light += spec_light.w * world_data.lights[3].specular_color.rgb;
+
+ float NV = clamp(dot(N, I), 0.0, 1.0);
+ specular_color = brdf_approx(specular_color, roughness, NV);
+ }
specular_light *= specular_color;
/* Prepare diffuse computation. Eval 4 lights at once. */
@@ -107,3 +119,13 @@ vec3 get_world_lighting(
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/solid_mode.c b/source/blender/draw/engines/workbench/solid_mode.c
deleted file mode 100644
index fed7e230a86..00000000000
--- a/source/blender/draw/engines/workbench/solid_mode.c
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Copyright 2016, Blender Foundation.
- */
-
-/** \file
- * \ingroup draw_engine
- *
- * Simple engine for drawing color and/or depth.
- * When we only need simple studio shaders.
- */
-
-#include "DRW_render.h"
-
-#include "GPU_shader.h"
-
-#include "RE_pipeline.h"
-
-#include "workbench_private.h"
-
-/* Functions */
-
-static void workbench_solid_engine_init(void *vedata)
-{
- WORKBENCH_Data *data = vedata;
- workbench_deferred_engine_init(data);
-}
-
-static void workbench_solid_cache_init(void *vedata)
-{
-
- WORKBENCH_Data *data = vedata;
- workbench_deferred_cache_init(data);
-}
-
-static void workbench_solid_cache_populate(void *vedata, Object *ob)
-{
- WORKBENCH_Data *data = vedata;
- workbench_deferred_solid_cache_populate(data, ob);
-}
-
-static void workbench_solid_cache_finish(void *vedata)
-{
- WORKBENCH_Data *data = vedata;
- workbench_deferred_cache_finish(data);
-}
-
-static void workbench_solid_draw_scene(void *vedata)
-{
- WORKBENCH_Data *data = vedata;
- const int num_samples = workbench_num_viewport_rendering_iterations(data);
-
- for (int sample = 0; sample < num_samples; sample++) {
- workbench_deferred_draw_scene(data);
- }
- workbench_deferred_draw_finish(data);
-}
-
-static void workbench_solid_engine_free(void)
-{
- workbench_deferred_engine_free();
-}
-
-static void workbench_solid_view_update(void *vedata)
-{
- WORKBENCH_Data *data = vedata;
- workbench_taa_view_updated(data);
-}
-
-static void workbench_solid_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 void workbench_render_to_image(void *vedata,
- RenderEngine *engine,
- RenderLayer *render_layer,
- const rcti *rect)
-{
- workbench_render(vedata, engine, render_layer, rect);
-}
-
-static const DrawEngineDataSize workbench_data_size = DRW_VIEWPORT_DATA_SIZE(WORKBENCH_Data);
-
-DrawEngineType draw_engine_workbench_solid = {
- NULL,
- NULL,
- N_("Workbench"),
- &workbench_data_size,
- &workbench_solid_engine_init,
- &workbench_solid_engine_free,
- &workbench_solid_cache_init,
- &workbench_solid_cache_populate,
- &workbench_solid_cache_finish,
- &workbench_solid_draw_scene,
- &workbench_solid_view_update,
- &workbench_solid_id_update,
- &workbench_render_to_image,
-};
diff --git a/source/blender/draw/engines/workbench/transparent_mode.c b/source/blender/draw/engines/workbench/transparent_mode.c
deleted file mode 100644
index fef1ffded8d..00000000000
--- a/source/blender/draw/engines/workbench/transparent_mode.c
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Copyright 2016, Blender Foundation.
- */
-
-/** \file
- * \ingroup draw_engine
- *
- * Simple engine for drawing color and/or depth.
- * When we only need simple studio shaders.
- */
-
-#include "DRW_render.h"
-
-#include "GPU_shader.h"
-
-#include "workbench_private.h"
-
-/* Functions */
-
-static void workbench_transparent_engine_init(void *vedata)
-{
- WORKBENCH_Data *data = vedata;
- workbench_forward_engine_init(data);
-}
-
-static void workbench_transparent_cache_init(void *vedata)
-{
-
- WORKBENCH_Data *data = vedata;
- workbench_forward_cache_init(data);
-}
-
-static void workbench_transparent_cache_populate(void *vedata, Object *ob)
-{
- WORKBENCH_Data *data = vedata;
- workbench_forward_cache_populate(data, ob);
-}
-
-static void workbench_transparent_cache_finish(void *vedata)
-{
- WORKBENCH_Data *data = vedata;
- workbench_forward_cache_finish(data);
-}
-
-static void workbench_transparent_draw_scene(void *vedata)
-{
- WORKBENCH_Data *data = vedata;
- const int num_samples = workbench_num_viewport_rendering_iterations(data);
-
- for (int sample = 0; sample < num_samples; sample++) {
- workbench_forward_draw_scene(data);
- }
- workbench_forward_draw_finish(data);
-}
-
-static void workbench_transparent_engine_free(void)
-{
- workbench_forward_engine_free();
-}
-
-static void workbench_transparent_view_update(void *vedata)
-{
- WORKBENCH_Data *data = vedata;
- workbench_taa_view_updated(data);
-}
-
-static const DrawEngineDataSize workbench_data_size = DRW_VIEWPORT_DATA_SIZE(WORKBENCH_Data);
-
-DrawEngineType draw_engine_workbench_transparent = {
- NULL,
- NULL,
- N_("Workbench"),
- &workbench_data_size,
- &workbench_transparent_engine_init,
- &workbench_transparent_engine_free,
- &workbench_transparent_cache_init,
- &workbench_transparent_cache_populate,
- &workbench_transparent_cache_finish,
- &workbench_transparent_draw_scene,
- &workbench_transparent_view_update,
- NULL,
- NULL,
-};
diff --git a/source/blender/draw/engines/workbench/workbench_data.c b/source/blender/draw/engines/workbench/workbench_data.c
index 623a3c0cb15..0ab67d620ee 100644
--- a/source/blender/draw/engines/workbench/workbench_data.c
+++ b/source/blender/draw/engines/workbench/workbench_data.c
@@ -22,133 +22,231 @@
#include "workbench_private.h"
+#include "BLI_memblock.h"
+
#include "DNA_userdef_types.h"
#include "ED_view3d.h"
+#include "ED_screen.h"
#include "UI_resources.h"
-#include "GPU_batch.h"
+#include "GPU_uniformbuffer.h"
/* -------------------------------------------------------------------- */
/** \name World Data
* \{ */
-static void workbench_world_data_free(DrawData *dd)
+GPUUniformBuffer *workbench_material_ubo_alloc(WORKBENCH_PrivateData *wpd)
{
- WORKBENCH_WorldData *data = (WORKBENCH_WorldData *)dd;
- DRW_UBO_FREE_SAFE(data->world_ubo);
+ struct GPUUniformBuffer **ubo = BLI_memblock_alloc(wpd->material_ubo);
+ if (*ubo == NULL) {
+ *ubo = GPU_uniformbuffer_create(sizeof(WORKBENCH_UBO_Material) * MAX_MATERIAL, NULL, NULL);
+ }
+ return *ubo;
}
-/* Ensure the availability of the world_ubo in the given WORKBENCH_PrivateData
- *
- * See T70167: Some platforms create threads to upload ubo's.
- *
- * Reuses the last previous created `world_ubo`. Due to limitations of
- * DrawData it will only be reused when there is a world attached to the Scene.
- * Future development: The best location would be to store it in the View3D.
- *
- * We don't cache the data itself as there was no indication that that lead to
- * an improvement.
- *
- * This functions also sets the `WORKBENCH_PrivateData.is_world_ubo_owner` that must
- * be respected.
- */
-static void workbench_world_data_ubo_ensure(const Scene *scene, WORKBENCH_PrivateData *wpd)
+static void workbench_ubo_free(void *elem)
{
- World *world = scene->world;
- if (world) {
- WORKBENCH_WorldData *engine_world_data = (WORKBENCH_WorldData *)DRW_drawdata_ensure(
- &world->id,
- &draw_engine_workbench_solid,
- sizeof(WORKBENCH_WorldData),
- NULL,
- &workbench_world_data_free);
-
- if (engine_world_data->world_ubo == NULL) {
- engine_world_data->world_ubo = DRW_uniformbuffer_create(sizeof(WORKBENCH_UBO_World),
- &wpd->world_data);
- }
- else {
- DRW_uniformbuffer_update(engine_world_data->world_ubo, &wpd->world_data);
- }
-
- /* Borrow world data ubo */
- wpd->is_world_ubo_owner = false;
- wpd->world_ubo = engine_world_data->world_ubo;
- }
- else {
- /* there is no world so we cannot cache the UBO. */
- BLI_assert(!wpd->world_ubo || wpd->is_world_ubo_owner);
- if (!wpd->world_ubo) {
- wpd->is_world_ubo_owner = true;
- wpd->world_ubo = DRW_uniformbuffer_create(sizeof(WORKBENCH_UBO_World), &wpd->world_data);
- }
- }
+ GPUUniformBuffer **ubo = elem;
+ DRW_UBO_FREE_SAFE(*ubo);
}
-static void workbench_world_data_update_shadow_direction_vs(WORKBENCH_PrivateData *wpd)
+static void workbench_view_layer_data_free(void *storage)
{
- 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_ViewLayerData *vldata = (WORKBENCH_ViewLayerData *)storage;
+
+ DRW_UBO_FREE_SAFE(vldata->dof_sample_ubo);
+ DRW_UBO_FREE_SAFE(vldata->world_ubo);
+ DRW_UBO_FREE_SAFE(vldata->cavity_sample_ubo);
+ DRW_TEXTURE_FREE_SAFE(vldata->cavity_jitter_tx);
+
+ BLI_memblock_destroy(vldata->material_ubo_data, NULL);
+ BLI_memblock_destroy(vldata->material_ubo, workbench_ubo_free);
+}
- workbench_private_data_get_light_direction(light_direction);
+static WORKBENCH_ViewLayerData *workbench_view_layer_data_ensure_ex(struct ViewLayer *view_layer)
+{
+ WORKBENCH_ViewLayerData **vldata = (WORKBENCH_ViewLayerData **)
+ DRW_view_layer_engine_data_ensure_ex(view_layer,
+ (DrawEngineType *)&workbench_view_layer_data_ensure_ex,
+ &workbench_view_layer_data_free);
+
+ if (*vldata == NULL) {
+ *vldata = MEM_callocN(sizeof(**vldata), "WORKBENCH_ViewLayerData");
+ size_t matbuf_size = sizeof(WORKBENCH_UBO_Material) * MAX_MATERIAL;
+ (*vldata)->material_ubo_data = BLI_memblock_create_ex(matbuf_size, matbuf_size * 2);
+ (*vldata)->material_ubo = BLI_memblock_create_ex(sizeof(void *), sizeof(void *) * 8);
+ (*vldata)->world_ubo = DRW_uniformbuffer_create(sizeof(WORKBENCH_UBO_World), NULL);
+ }
- /* Shadow direction. */
- mul_v3_mat3_m4v3(wd->shadow_direction_vs, view_matrix, light_direction);
+ return *vldata;
}
/* \} */
-void workbench_clear_color_get(float color[4])
+static void workbench_viewvecs_update(float r_viewvecs[3][4])
{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- const Scene *scene = draw_ctx->scene;
+ float invproj[4][4];
+ const bool is_persp = DRW_view_is_persp_get(NULL);
+ DRW_view_winmat_get(NULL, invproj, true);
+
+ /* view vectors for the corners of the view frustum.
+ * Can be used to recreate the world space position easily */
+ copy_v4_fl4(r_viewvecs[0], -1.0f, -1.0f, -1.0f, 1.0f);
+ copy_v4_fl4(r_viewvecs[1], 1.0f, -1.0f, -1.0f, 1.0f);
+ copy_v4_fl4(r_viewvecs[2], -1.0f, 1.0f, -1.0f, 1.0f);
+
+ /* convert the view vectors to view space */
+ for (int i = 0; i < 3; i++) {
+ mul_m4_v4(invproj, r_viewvecs[i]);
+ /* normalized trick see:
+ * http://www.derschmale.com/2014/01/26/reconstructing-positions-from-the-depth-buffer */
+ mul_v3_fl(r_viewvecs[i], 1.0f / r_viewvecs[i][3]);
+ if (is_persp) {
+ mul_v3_fl(r_viewvecs[i], 1.0f / r_viewvecs[i][2]);
+ }
+ r_viewvecs[i][3] = 1.0;
+ }
+
+ /* we need to store the differences */
+ r_viewvecs[1][0] -= r_viewvecs[0][0];
+ r_viewvecs[1][1] = r_viewvecs[2][1] - r_viewvecs[0][1];
- if (!DRW_state_is_scene_render() || !DRW_state_draw_background()) {
- zero_v4(color);
+ /* calculate a depth offset as well */
+ if (!is_persp) {
+ float vec_far[] = {-1.0f, -1.0f, 1.0f, 1.0f};
+ mul_m4_v4(invproj, vec_far);
+ mul_v3_fl(vec_far, 1.0f / vec_far[3]);
+ r_viewvecs[1][2] = vec_far[2] - r_viewvecs[0][2];
}
- else if (scene->world) {
- copy_v3_v3(color, &scene->world->horr);
- color[3] = 1.0f;
+}
+
+static void workbench_studiolight_data_update(WORKBENCH_PrivateData *wpd, WORKBENCH_UBO_World *wd)
+{
+ StudioLight *studiolight = wpd->studio_light;
+ float view_matrix[4][4], rot_matrix[4][4];
+ DRW_view_viewmat_get(NULL, view_matrix, false);
+
+ if (USE_WORLD_ORIENTATION(wpd)) {
+ axis_angle_to_mat4_single(rot_matrix, 'Z', -wpd->shading.studiolight_rot_z);
+ mul_m4_m4m4(rot_matrix, view_matrix, rot_matrix);
+ swap_v3_v3(rot_matrix[2], rot_matrix[1]);
+ negate_v3(rot_matrix[2]);
}
else {
- zero_v3(color);
- color[3] = 1.0f;
+ unit_m4(rot_matrix);
}
-}
-void workbench_effect_info_init(WORKBENCH_EffectInfo *effect_info)
-{
- effect_info->jitter_index = 0;
- effect_info->view_updated = true;
+ if (U.edit_studio_light) {
+ studiolight = BKE_studiolight_studio_edit_get();
+ }
+
+ /* Studio Lights. */
+ for (int i = 0; i < 4; i++) {
+ WORKBENCH_UBO_Light *light = &wd->lights[i];
+
+ SolidLight *sl = (studiolight) ? &studiolight->light[i] : NULL;
+ if (sl && sl->flag) {
+ copy_v3_v3(light->light_direction, sl->vec);
+ mul_mat3_m4_v3(rot_matrix, light->light_direction);
+ /* We should predivide the power by PI but that makes the lights really dim. */
+ copy_v3_v3(light->specular_color, sl->spec);
+ copy_v3_v3(light->diffuse_color, sl->col);
+ light->wrapped = sl->smooth;
+ }
+ else {
+ copy_v3_fl3(light->light_direction, 1.0f, 0.0f, 0.0f);
+ copy_v3_fl(light->specular_color, 0.0f);
+ copy_v3_fl(light->diffuse_color, 0.0f);
+ }
+ }
+
+ if (studiolight) {
+ copy_v3_v3(wd->ambient_color, studiolight->light_ambient);
+ }
+ else {
+ copy_v3_fl(wd->ambient_color, 1.0f);
+ }
+
+ wd->use_specular = workbench_is_specular_highlight_enabled(wpd);
}
void workbench_private_data_init(WORKBENCH_PrivateData *wpd)
{
const DRWContextState *draw_ctx = DRW_context_state_get();
- const Scene *scene = draw_ctx->scene;
- wpd->material_hash = BLI_ghash_ptr_new(__func__);
- wpd->material_transp_hash = BLI_ghash_ptr_new(__func__);
+ RegionView3D *rv3d = draw_ctx->rv3d;
+ View3D *v3d = draw_ctx->v3d;
+ Scene *scene = draw_ctx->scene;
+ WORKBENCH_ViewLayerData *vldata = workbench_view_layer_data_ensure_ex(draw_ctx->view_layer);
+
+ wpd->is_playback = DRW_state_is_playback();
+ wpd->is_navigating = rv3d && (rv3d->rflag & (RV3D_NAVIGATING | RV3D_PAINTING));
+
+ wpd->ctx_mode = CTX_data_mode_enum_ex(
+ draw_ctx->object_edit, draw_ctx->obact, draw_ctx->object_mode);
+
wpd->preferences = &U;
+ wpd->scene = scene;
+ wpd->sh_cfg = draw_ctx->sh_cfg;
+ wpd->clip_state = RV3D_CLIPPING_ENABLED(v3d, rv3d) ? DRW_STATE_CLIP_PLANES : 0;
+ wpd->cull_state = CULL_BACKFACE_ENABLED(wpd) ? DRW_STATE_CULL_BACK : 0;
+ wpd->vldata = vldata;
+ wpd->world_ubo = vldata->world_ubo;
- View3D *v3d = draw_ctx->v3d;
- RegionView3D *rv3d = draw_ctx->rv3d;
+ wpd->taa_sample_len = workbench_antialiasing_sample_count_get(wpd);
+
+ wpd->volumes_do = false;
+ BLI_listbase_clear(&wpd->smoke_domains);
if (!v3d || (v3d->shading.type == OB_RENDER && BKE_scene_uses_blender_workbench(scene))) {
+ /* FIXME: This reproduce old behavior when workbench was separated in 2 engines.
+ * But this is a workaround for a missing update tagging from operators. */
+ if (scene->display.shading.type != wpd->shading.type ||
+ XRAY_ENABLED(v3d) != XRAY_ENABLED((&scene->display))) {
+ wpd->view_updated = true;
+ }
+
wpd->shading = scene->display.shading;
- wpd->shading.xray_alpha = XRAY_ALPHA((&scene->display));
- wpd->use_color_render_settings = true;
+ if (XRAY_FLAG_ENABLED((&scene->display))) {
+ wpd->shading.xray_alpha = XRAY_ALPHA((&scene->display));
+ }
+ else {
+ wpd->shading.xray_alpha = 1.0f;
+ }
+
+ if (scene->r.alphamode == R_ALPHAPREMUL) {
+ copy_v4_fl(wpd->background_color, 0.0f);
+ }
+ else if (scene->world) {
+ World *wo = scene->world;
+ copy_v4_fl4(wpd->background_color, wo->horr, wo->horg, wo->horb, 1.0f);
+ }
+ else {
+ copy_v4_fl4(wpd->background_color, 0.0f, 0.0f, 0.0f, 1.0f);
+ }
}
else {
+ /* FIXME: This reproduce old behavior when workbench was separated in 2 engines.
+ * But this is a workaround for a missing update tagging from operators. */
+ if (v3d->shading.type != wpd->shading.type || XRAY_ENABLED(v3d) != XRAY_ENABLED(wpd)) {
+ wpd->view_updated = true;
+ }
+
wpd->shading = v3d->shading;
- wpd->shading.xray_alpha = XRAY_ALPHA(v3d);
- wpd->use_color_render_settings = false;
- }
+ if (wpd->shading.type < OB_SOLID) {
+ wpd->shading.xray_alpha = 0.0f;
+ }
+ else if (XRAY_ENABLED(v3d)) {
+ wpd->shading.xray_alpha = XRAY_ALPHA(v3d);
+ }
+ else {
+ wpd->shading.xray_alpha = 1.0f;
+ }
- wpd->use_color_management = BKE_scene_check_color_management_enabled(scene);
+ /* No background. The overlays will draw the correct one. */
+ copy_v4_fl(wpd->background_color, 0.0f);
+ }
if (wpd->shading.light == V3D_LIGHTING_MATCAP) {
wpd->studio_light = BKE_studiolight_find(wpd->shading.matcap, STUDIOLIGHT_TYPE_MATCAP);
@@ -162,119 +260,56 @@ 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;
-
- studiolight_update_world(wpd, wpd->studio_light, wd);
-
- copy_v3_v3(wd->object_outline_color, wpd->shading.object_outline_color);
- wd->object_outline_color[3] = 1.0f;
-
- wd->curvature_ridge = 0.5f / max_ff(square_f(wpd->shading.curvature_ridge_factor), 1e-4f);
- wd->curvature_valley = 0.7f / max_ff(square_f(wpd->shading.curvature_valley_factor), 1e-4f);
-
- /* Will be NULL when rendering. */
- if (RV3D_CLIPPING_ENABLED(v3d, rv3d)) {
- wpd->world_clip_planes = rv3d->clip;
- }
- else {
- wpd->world_clip_planes = NULL;
- }
-
- workbench_world_data_update_shadow_direction_vs(wpd);
- workbench_world_data_ubo_ensure(scene, wpd);
-
- /* Cavity settings */
{
- const int ssao_samples = scene->display.matcap_ssao_samples;
-
- float invproj[4][4];
- const bool is_persp = DRW_view_is_persp_get(NULL);
- /* view vectors for the corners of the view frustum.
- * Can be used to recreate the world space position easily */
- float viewvecs[3][4] = {
- {-1.0f, -1.0f, -1.0f, 1.0f},
- {1.0f, -1.0f, -1.0f, 1.0f},
- {-1.0f, 1.0f, -1.0f, 1.0f},
- };
- int i;
- const float *size = DRW_viewport_size_get();
-
- wpd->ssao_params[0] = ssao_samples;
- wpd->ssao_params[1] = size[0] / 64.0;
- wpd->ssao_params[2] = size[1] / 64.0;
- wpd->ssao_params[3] = 0;
-
- /* distance, factor, factor, attenuation */
- copy_v4_fl4(wpd->ssao_settings,
- scene->display.matcap_ssao_distance,
- wpd->shading.cavity_valley_factor,
- wpd->shading.cavity_ridge_factor,
- scene->display.matcap_ssao_attenuation);
-
- DRW_view_winmat_get(NULL, wpd->winmat, false);
- DRW_view_winmat_get(NULL, invproj, true);
-
- /* convert the view vectors to view space */
- for (i = 0; i < 3; i++) {
- mul_m4_v4(invproj, viewvecs[i]);
- /* normalized trick see:
- * http://www.derschmale.com/2014/01/26/reconstructing-positions-from-the-depth-buffer */
- mul_v3_fl(viewvecs[i], 1.0f / viewvecs[i][3]);
- if (is_persp) {
- mul_v3_fl(viewvecs[i], 1.0f / viewvecs[i][2]);
- }
- viewvecs[i][3] = 1.0;
-
- copy_v4_v4(wpd->viewvecs[i], viewvecs[i]);
- }
-
- /* we need to store the differences */
- wpd->viewvecs[1][0] -= wpd->viewvecs[0][0];
- wpd->viewvecs[1][1] = wpd->viewvecs[2][1] - wpd->viewvecs[0][1];
-
- /* calculate a depth offset as well */
- if (!is_persp) {
- float vec_far[] = {-1.0f, -1.0f, 1.0f, 1.0f};
- mul_m4_v4(invproj, vec_far);
- mul_v3_fl(vec_far, 1.0f / vec_far[3]);
- wpd->viewvecs[1][2] = vec_far[2] - wpd->viewvecs[0][2];
- }
+ /* Material UBOs. */
+ wpd->material_ubo_data = vldata->material_ubo_data;
+ wpd->material_ubo = vldata->material_ubo;
+ wpd->material_chunk_count = 1;
+ wpd->material_chunk_curr = 0;
+ wpd->material_index = 1;
+ /* Create default material ubo. */
+ wpd->material_ubo_data_curr = BLI_memblock_alloc(wpd->material_ubo_data);
+ wpd->material_ubo_curr = workbench_material_ubo_alloc(wpd);
+ /* Init default material used by vertex color & texture. */
+ workbench_material_ubo_data(
+ wpd, NULL, NULL, &wpd->material_ubo_data_curr[0], V3D_SHADING_MATERIAL_COLOR);
}
-
- wpd->volumes_do = false;
- BLI_listbase_clear(&wpd->smoke_domains);
}
-void workbench_private_data_get_light_direction(float r_light_direction[3])
+void workbench_update_world_ubo(WORKBENCH_PrivateData *wpd)
{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- Scene *scene = draw_ctx->scene;
+ WORKBENCH_UBO_World wd;
- 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];
+ copy_v2_v2(wd.viewport_size, DRW_viewport_size_get());
+ copy_v2_v2(wd.viewport_size_inv, DRW_viewport_invert_size_get());
+ copy_v3_v3(wd.object_outline_color, wpd->shading.object_outline_color);
+ wd.object_outline_color[3] = 1.0f;
+ wd.ui_scale = G_draw.block.sizePixel;
+ wd.matcap_orientation = (wpd->shading.flag & V3D_SHADING_MATCAP_FLIP_X) != 0;
+
+ workbench_studiolight_data_update(wpd, &wd);
+ workbench_shadow_data_update(wpd, &wd);
+ workbench_cavity_data_update(wpd, &wd);
+ workbench_viewvecs_update(wd.viewvecs);
+
+ DRW_uniformbuffer_update(wpd->world_ubo, &wd);
}
-void workbench_private_data_free(WORKBENCH_PrivateData *wpd)
+void workbench_update_material_ubos(WORKBENCH_PrivateData *UNUSED(wpd))
{
- BLI_ghash_free(wpd->material_hash, NULL, MEM_freeN);
- BLI_ghash_free(wpd->material_transp_hash, NULL, MEM_freeN);
-
- if (wpd->is_world_ubo_owner) {
- DRW_UBO_FREE_SAFE(wpd->world_ubo);
- }
- else {
- wpd->world_ubo = NULL;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ WORKBENCH_ViewLayerData *vldata = workbench_view_layer_data_ensure_ex(draw_ctx->view_layer);
+
+ BLI_memblock_iter iter, iter_data;
+ BLI_memblock_iternew(vldata->material_ubo, &iter);
+ BLI_memblock_iternew(vldata->material_ubo_data, &iter_data);
+ WORKBENCH_UBO_Material *matchunk;
+ while ((matchunk = BLI_memblock_iterstep(&iter_data))) {
+ GPUUniformBuffer **ubo = BLI_memblock_iterstep(&iter);
+ BLI_assert(*ubo != NULL);
+ GPU_uniformbuffer_update(*ubo, matchunk);
}
- DRW_UBO_FREE_SAFE(wpd->dof_ubo);
+ BLI_memblock_clear(vldata->material_ubo, workbench_ubo_free);
+ BLI_memblock_clear(vldata->material_ubo_data, NULL);
}
diff --git a/source/blender/draw/engines/workbench/workbench_deferred.c b/source/blender/draw/engines/workbench/workbench_deferred.c
deleted file mode 100644
index df9a597faf9..00000000000
--- a/source/blender/draw/engines/workbench/workbench_deferred.c
+++ /dev/null
@@ -1,1415 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Copyright 2016, Blender Foundation.
- */
-
-/** \file
- * \ingroup draw_engine
- */
-
-#include "workbench_private.h"
-
-#include "BLI_alloca.h"
-#include "BLI_dynstr.h"
-#include "BLI_utildefines.h"
-#include "BLI_rand.h"
-#include "BLI_string_utils.h"
-
-#include "BKE_modifier.h"
-#include "BKE_object.h"
-#include "BKE_paint.h"
-#include "BKE_particle.h"
-
-#include "DNA_image_types.h"
-#include "DNA_fluid_types.h"
-#include "DNA_mesh_types.h"
-#include "DNA_modifier_types.h"
-#include "DNA_node_types.h"
-
-#include "GPU_shader.h"
-#include "GPU_texture.h"
-#include "GPU_extensions.h"
-
-#include "../eevee/eevee_lut.h" /* TODO find somewhere to share blue noise Table */
-
-/* *********** STATIC *********** */
-
-/* #define DEBUG_SHADOW_VOLUME */
-
-#ifdef DEBUG_SHADOW_VOLUME
-# include "draw_debug.h"
-#endif
-
-typedef struct WORKBENCH_DEFERRED_Shaders {
- struct GPUShader *prepass_sh_cache[MAX_PREPASS_SHADERS];
-} WORKBENCH_DEFERRED_Shaders;
-
-static struct {
- WORKBENCH_DEFERRED_Shaders sh_data[GPU_SHADER_CFG_LEN];
-
- struct GPUShader *composite_sh_cache[MAX_COMPOSITE_SHADERS];
- struct GPUShader *cavity_sh[MAX_CAVITY_SHADERS];
- struct GPUShader *background_sh[2];
- struct GPUShader *ghost_resolve_sh;
- struct GPUShader *shadow_fail_sh;
- struct GPUShader *shadow_fail_manifold_sh;
- struct GPUShader *shadow_pass_sh;
- struct GPUShader *shadow_pass_manifold_sh;
- struct GPUShader *shadow_caps_sh;
- struct GPUShader *shadow_caps_manifold_sh;
- struct GPUShader *oit_resolve_sh;
-
- /* TODO(fclem) move everything below to wpd and custom viewlayer data. */
- struct GPUTexture *oit_accum_tx; /* ref only, not alloced */
- struct GPUTexture *oit_revealage_tx; /* ref only, not alloced */
- struct GPUTexture *object_id_tx; /* ref only, not alloced */
- struct GPUTexture *color_buffer_tx; /* ref only, not alloced */
- struct GPUTexture *cavity_buffer_tx; /* ref only, not alloced */
- struct GPUTexture *normal_buffer_tx; /* ref only, not alloced */
- struct GPUTexture *composite_buffer_tx; /* ref only, not alloced */
-
- SceneDisplay display; /* world light direction for shadows */
-
- struct GPUUniformBuffer *sampling_ubo;
- struct GPUTexture *jitter_tx;
- int cached_sample_num;
-} e_data = {{{{NULL}}}};
-
-/* Shaders */
-extern char datatoc_common_hair_lib_glsl[];
-extern char datatoc_common_view_lib_glsl[];
-
-extern char datatoc_workbench_prepass_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[];
-extern char datatoc_workbench_deferred_background_frag_glsl[];
-extern char datatoc_workbench_ghost_resolve_frag_glsl[];
-
-extern char datatoc_workbench_shadow_vert_glsl[];
-extern char datatoc_workbench_shadow_geom_glsl[];
-extern char datatoc_workbench_shadow_caps_geom_glsl[];
-extern char datatoc_workbench_shadow_debug_frag_glsl[];
-
-extern char datatoc_workbench_cavity_lib_glsl[];
-extern char datatoc_workbench_common_lib_glsl[];
-extern char datatoc_workbench_data_lib_glsl[];
-extern char datatoc_workbench_object_outline_lib_glsl[];
-extern char datatoc_workbench_curvature_lib_glsl[];
-extern char datatoc_workbench_world_light_lib_glsl[];
-
-extern char datatoc_gpu_shader_depth_only_frag_glsl[];
-
-static char *workbench_build_composite_frag(WORKBENCH_PrivateData *wpd)
-{
- DynStr *ds = BLI_dynstr_new();
-
- BLI_dynstr_append(ds, datatoc_common_view_lib_glsl);
- BLI_dynstr_append(ds, datatoc_workbench_data_lib_glsl);
- BLI_dynstr_append(ds, datatoc_workbench_common_lib_glsl);
-
- if (!FLAT_ENABLED(wpd)) {
- BLI_dynstr_append(ds, datatoc_workbench_world_light_lib_glsl);
- }
- if (OBJECT_OUTLINE_ENABLED(wpd)) {
- BLI_dynstr_append(ds, datatoc_workbench_object_outline_lib_glsl);
- }
- if (CURVATURE_ENABLED(wpd)) {
- BLI_dynstr_append(ds, datatoc_workbench_curvature_lib_glsl);
- }
-
- BLI_dynstr_append(ds, datatoc_workbench_deferred_composite_frag_glsl);
-
- char *str = BLI_dynstr_get_cstring(ds);
- BLI_dynstr_free(ds);
- return str;
-}
-
-static char *workbench_build_prepass_frag(void)
-{
- DynStr *ds = BLI_dynstr_new();
-
- BLI_dynstr_append(ds, datatoc_common_view_lib_glsl);
- BLI_dynstr_append(ds, datatoc_workbench_data_lib_glsl);
- BLI_dynstr_append(ds, datatoc_workbench_common_lib_glsl);
- BLI_dynstr_append(ds, datatoc_workbench_prepass_frag_glsl);
-
- char *str = BLI_dynstr_get_cstring(ds);
- BLI_dynstr_free(ds);
- return str;
-}
-
-static char *workbench_build_prepass_vert(bool is_hair)
-{
- DynStr *ds = BLI_dynstr_new();
- if (is_hair) {
- BLI_dynstr_append(ds, datatoc_common_hair_lib_glsl);
- }
- BLI_dynstr_append(ds, datatoc_common_view_lib_glsl);
- BLI_dynstr_append(ds, datatoc_workbench_prepass_vert_glsl);
- char *str = BLI_dynstr_get_cstring(ds);
- BLI_dynstr_free(ds);
- return str;
-}
-
-static char *workbench_build_cavity_frag(bool cavity, bool curvature, bool high_dpi)
-{
- DynStr *ds = BLI_dynstr_new();
-
- if (cavity) {
- BLI_dynstr_append(ds, "#define USE_CAVITY\n");
- }
- if (curvature) {
- BLI_dynstr_append(ds, "#define USE_CURVATURE\n");
- }
- if (high_dpi) {
- BLI_dynstr_append(ds, "#define CURVATURE_OFFSET 2\n");
- }
- if (NORMAL_ENCODING_ENABLED()) {
- BLI_dynstr_append(ds, "#define WORKBENCH_ENCODE_NORMALS\n");
- }
- BLI_dynstr_append(ds, datatoc_workbench_common_lib_glsl);
- BLI_dynstr_append(ds, datatoc_workbench_curvature_lib_glsl);
- BLI_dynstr_append(ds, datatoc_workbench_cavity_frag_glsl);
- BLI_dynstr_append(ds, datatoc_workbench_cavity_lib_glsl);
-
- char *str = BLI_dynstr_get_cstring(ds);
- BLI_dynstr_free(ds);
- return str;
-}
-
-static GPUShader *workbench_cavity_shader_get(bool cavity, bool curvature)
-{
- const bool high_dpi = (U.pixelsize > 1.5f);
- int index = 0;
- SET_FLAG_FROM_TEST(index, cavity, 1 << 0);
- SET_FLAG_FROM_TEST(index, curvature, 1 << 1);
- SET_FLAG_FROM_TEST(index, high_dpi, 1 << 2);
-
- GPUShader **sh = &e_data.cavity_sh[index];
- if (*sh == NULL) {
- char *cavity_frag = workbench_build_cavity_frag(cavity, curvature, high_dpi);
- *sh = DRW_shader_create_fullscreen(cavity_frag, NULL);
- MEM_freeN(cavity_frag);
- }
- return *sh;
-}
-
-static GPUShader *ensure_deferred_prepass_shader(WORKBENCH_PrivateData *wpd,
- bool is_uniform_color,
- bool is_hair,
- bool is_tiled,
- const WORKBENCH_ColorOverride color_override,
- eGPUShaderConfig sh_cfg)
-{
- WORKBENCH_DEFERRED_Shaders *sh_data = &e_data.sh_data[sh_cfg];
- int index = workbench_material_get_prepass_shader_index(
- wpd, is_uniform_color, is_hair, is_tiled, color_override);
- if (sh_data->prepass_sh_cache[index] == NULL) {
- const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[sh_cfg];
- char *defines = workbench_material_build_defines(
- wpd, is_uniform_color, is_hair, is_tiled, color_override);
- char *prepass_vert = workbench_build_prepass_vert(is_hair);
- char *prepass_frag = workbench_build_prepass_frag();
- sh_data->prepass_sh_cache[index] = GPU_shader_create_from_arrays({
- .vert = (const char *[]){sh_cfg_data->lib, prepass_vert, NULL},
- .frag = (const char *[]){prepass_frag, NULL},
- .defs = (const char *[]){sh_cfg_data->def, defines, NULL},
- });
- MEM_freeN(prepass_vert);
- MEM_freeN(prepass_frag);
- MEM_freeN(defines);
- }
- return sh_data->prepass_sh_cache[index];
-}
-
-static GPUShader *ensure_deferred_composite_shader(WORKBENCH_PrivateData *wpd)
-{
- int index = workbench_material_get_composite_shader_index(wpd);
- if (e_data.composite_sh_cache[index] == NULL) {
- char *defines = workbench_material_build_defines(
- wpd, false, false, false, WORKBENCH_COLOR_OVERRIDE_OFF);
- char *composite_frag = workbench_build_composite_frag(wpd);
- e_data.composite_sh_cache[index] = DRW_shader_create_fullscreen(composite_frag, defines);
- MEM_freeN(composite_frag);
- MEM_freeN(defines);
- }
- return e_data.composite_sh_cache[index];
-}
-
-static GPUShader *ensure_background_shader(WORKBENCH_PrivateData *wpd)
-{
- const int index = OBJECT_OUTLINE_ENABLED(wpd) ? 1 : 0;
- if (e_data.background_sh[index] == NULL) {
- const char *defines = (index) ? "#define V3D_SHADING_OBJECT_OUTLINE\n" : NULL;
- char *frag = BLI_string_joinN(datatoc_workbench_data_lib_glsl,
- datatoc_workbench_common_lib_glsl,
- datatoc_workbench_object_outline_lib_glsl,
- datatoc_workbench_deferred_background_frag_glsl);
- e_data.background_sh[index] = DRW_shader_create_fullscreen(frag, defines);
- MEM_freeN(frag);
- }
- return e_data.background_sh[index];
-}
-
-static void select_deferred_shaders(WORKBENCH_PrivateData *wpd, eGPUShaderConfig sh_cfg)
-{
- wpd->prepass_sh = ensure_deferred_prepass_shader(
- wpd, false, false, false, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg);
- wpd->prepass_hair_sh = ensure_deferred_prepass_shader(
- wpd, false, true, false, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg);
- wpd->prepass_uniform_sh = ensure_deferred_prepass_shader(
- wpd, true, false, false, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg);
- wpd->prepass_uniform_hair_sh = ensure_deferred_prepass_shader(
- wpd, true, true, false, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg);
- wpd->prepass_textured_sh = ensure_deferred_prepass_shader(
- wpd, false, false, false, WORKBENCH_COLOR_OVERRIDE_TEXTURE, sh_cfg);
- wpd->prepass_textured_array_sh = ensure_deferred_prepass_shader(
- wpd, false, false, true, WORKBENCH_COLOR_OVERRIDE_TEXTURE, sh_cfg);
- wpd->prepass_vertex_sh = ensure_deferred_prepass_shader(
- wpd, false, false, false, WORKBENCH_COLOR_OVERRIDE_VERTEX, sh_cfg);
- wpd->composite_sh = ensure_deferred_composite_shader(wpd);
- wpd->background_sh = ensure_background_shader(wpd);
-}
-
-/* Using Hammersley distribution */
-static float *create_disk_samples(int num_samples, int num_iterations)
-{
- /* vec4 to ensure memory alignment. */
- const int total_samples = num_samples * num_iterations;
- float(*texels)[4] = MEM_mallocN(sizeof(float[4]) * total_samples, __func__);
- const float num_samples_inv = 1.0f / num_samples;
-
- for (int i = 0; i < total_samples; i++) {
- float it_add = (i / num_samples) * 0.499f;
- float r = fmodf((i + 0.5f + it_add) * num_samples_inv, 1.0f);
- double dphi;
- BLI_hammersley_1d(i, &dphi);
-
- float phi = (float)dphi * 2.0f * M_PI + it_add;
- texels[i][0] = cosf(phi);
- texels[i][1] = sinf(phi);
- /* This deliberately distribute more samples
- * at the center of the disk (and thus the shadow). */
- texels[i][2] = r;
- }
-
- return (float *)texels;
-}
-
-static struct GPUTexture *create_jitter_texture(int num_samples)
-{
- float jitter[64 * 64][4];
- const float num_samples_inv = 1.0f / num_samples;
-
- for (int i = 0; i < 64 * 64; i++) {
- float phi = blue_noise[i][0] * 2.0f * M_PI;
- /* This rotate the sample per pixels */
- jitter[i][0] = cosf(phi);
- jitter[i][1] = sinf(phi);
- /* This offset the sample along it's direction axis (reduce banding) */
- float bn = blue_noise[i][1] - 0.5f;
- CLAMP(bn, -0.499f, 0.499f); /* fix fireflies */
- jitter[i][2] = bn * num_samples_inv;
- jitter[i][3] = blue_noise[i][1];
- }
-
- UNUSED_VARS(bsdf_split_sum_ggx, btdf_split_sum_ggx, ltc_mag_ggx, ltc_mat_ggx, ltc_disk_integral);
-
- return DRW_texture_create_2d(64, 64, GPU_RGBA16F, DRW_TEX_FILTER | DRW_TEX_WRAP, &jitter[0][0]);
-}
-/* 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)
-{
- const float *size = DRW_viewport_size_get();
- e_data.oit_accum_tx = DRW_texture_pool_query_2d(
- size[0], size[1], GPU_RGBA16F, &draw_engine_workbench_solid);
- e_data.oit_revealage_tx = DRW_texture_pool_query_2d(
- size[0], size[1], GPU_R16F, &draw_engine_workbench_solid);
-
- GPU_framebuffer_ensure_config(&fbl->transparent_accum_fb,
- {
- GPU_ATTACHMENT_TEXTURE(dtxl->depth),
- GPU_ATTACHMENT_TEXTURE(e_data.oit_accum_tx),
- GPU_ATTACHMENT_TEXTURE(e_data.oit_revealage_tx),
- });
-}
-
-void workbench_deferred_engine_init(WORKBENCH_Data *vedata)
-{
- WORKBENCH_FramebufferList *fbl = vedata->fbl;
- WORKBENCH_StorageList *stl = vedata->stl;
- WORKBENCH_PassList *psl = vedata->psl;
- DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
- const DRWContextState *draw_ctx = DRW_context_state_get();
- RegionView3D *rv3d = draw_ctx->rv3d;
- View3D *v3d = draw_ctx->v3d;
- Scene *scene = draw_ctx->scene;
- Object *camera;
-
- if (v3d && rv3d) {
- camera = (rv3d->persp == RV3D_CAMOB) ? v3d->camera : NULL;
- }
- else {
- camera = scene->camera;
- }
-
- if (!stl->g_data) {
- /* Alloc transient pointers */
- stl->g_data = MEM_callocN(sizeof(*stl->g_data), __func__);
- }
- if (!stl->effects) {
- stl->effects = MEM_callocN(sizeof(*stl->effects), __func__);
- workbench_effect_info_init(stl->effects);
- }
-
- if (!e_data.shadow_pass_sh) {
- WORKBENCH_DEFERRED_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
- memset(sh_data->prepass_sh_cache, 0, sizeof(sh_data->prepass_sh_cache));
- memset(e_data.composite_sh_cache, 0, sizeof(e_data.composite_sh_cache));
-#ifdef 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
- /* TODO only compile on demand */
- e_data.shadow_pass_sh = GPU_shader_create_from_arrays({
- .vert = (const char *[]){datatoc_common_view_lib_glsl,
- datatoc_workbench_shadow_vert_glsl,
- NULL},
- .geom = (const char *[]){datatoc_workbench_shadow_geom_glsl, NULL},
- .frag = (const char *[]){shadow_frag, NULL},
- .defs = (const char *[]){"#define SHADOW_PASS\n"
- "#define DOUBLE_MANIFOLD\n",
- NULL},
- });
- e_data.shadow_pass_manifold_sh = GPU_shader_create_from_arrays({
- .vert = (const char *[]){datatoc_common_view_lib_glsl,
- datatoc_workbench_shadow_vert_glsl,
- NULL},
- .geom = (const char *[]){datatoc_workbench_shadow_geom_glsl, NULL},
- .frag = (const char *[]){shadow_frag, NULL},
- .defs = (const char *[]){"#define SHADOW_PASS\n", NULL},
- });
- e_data.shadow_fail_sh = GPU_shader_create_from_arrays({
- .vert = (const char *[]){datatoc_common_view_lib_glsl,
- datatoc_workbench_shadow_vert_glsl,
- NULL},
- .geom = (const char *[]){datatoc_workbench_shadow_geom_glsl, NULL},
- .frag = (const char *[]){shadow_frag, NULL},
- .defs = (const char *[]){"#define SHADOW_FAIL\n"
- "#define DOUBLE_MANIFOLD\n",
- NULL},
- });
- e_data.shadow_fail_manifold_sh = GPU_shader_create_from_arrays({
- .vert = (const char *[]){datatoc_common_view_lib_glsl,
- datatoc_workbench_shadow_vert_glsl,
- NULL},
- .geom = (const char *[]){datatoc_workbench_shadow_geom_glsl, NULL},
- .frag = (const char *[]){shadow_frag, NULL},
- .defs = (const char *[]){"#define SHADOW_FAIL\n", NULL},
- });
- e_data.shadow_caps_sh = GPU_shader_create_from_arrays({
- .vert = (const char *[]){datatoc_common_view_lib_glsl,
- datatoc_workbench_shadow_vert_glsl,
- NULL},
- .geom = (const char *[]){datatoc_workbench_shadow_caps_geom_glsl, NULL},
- .frag = (const char *[]){shadow_frag, NULL},
- .defs = (const char *[]){"#define SHADOW_FAIL\n"
- "#define DOUBLE_MANIFOLD\n",
- NULL},
- });
- e_data.shadow_caps_manifold_sh = GPU_shader_create_from_arrays({
- .vert = (const char *[]){datatoc_common_view_lib_glsl,
- datatoc_workbench_shadow_vert_glsl,
- NULL},
- .geom = (const char *[]){datatoc_workbench_shadow_caps_geom_glsl, NULL},
- .frag = (const char *[]){shadow_frag, NULL},
- .defs = (const char *[]){"#define SHADOW_FAIL\n", NULL},
- });
-
- e_data.ghost_resolve_sh = DRW_shader_create_fullscreen(
- datatoc_workbench_ghost_resolve_frag_glsl, NULL);
- }
- workbench_volume_engine_init();
- workbench_fxaa_engine_init();
- workbench_taa_engine_init(vedata);
-
- WORKBENCH_PrivateData *wpd = stl->g_data;
- workbench_private_data_init(wpd);
-
- wpd->shading.xray_alpha = 1.0f;
-
- workbench_dof_engine_init(vedata, camera);
-
- if (OIT_ENABLED(wpd)) {
- if (e_data.oit_resolve_sh == NULL) {
- e_data.oit_resolve_sh = DRW_shader_create_fullscreen(
- datatoc_workbench_forward_composite_frag_glsl, "#define ALPHA_COMPOSITE\n");
- }
-
- workbench_forward_choose_shaders(wpd, draw_ctx->sh_cfg);
- workbench_forward_outline_shaders_ensure(wpd, draw_ctx->sh_cfg);
- }
-
- {
- const float *viewport_size = DRW_viewport_size_get();
- const int size[2] = {(int)viewport_size[0], (int)viewport_size[1]};
- const eGPUTextureFormat nor_tex_format = NORMAL_ENCODING_ENABLED() ? GPU_RG16 : GPU_RGBA32F;
- const eGPUTextureFormat comp_tex_format = GPU_RGBA16F;
- const eGPUTextureFormat col_tex_format = workbench_color_texture_format(wpd);
- const eGPUTextureFormat id_tex_format = OBJECT_ID_PASS_ENABLED(wpd) ? GPU_R32UI : GPU_R8;
-
- e_data.object_id_tx = NULL;
- e_data.color_buffer_tx = NULL;
- e_data.composite_buffer_tx = NULL;
- e_data.normal_buffer_tx = NULL;
- e_data.cavity_buffer_tx = NULL;
-
- e_data.composite_buffer_tx = DRW_texture_pool_query_2d(
- size[0], size[1], comp_tex_format, &draw_engine_workbench_solid);
-
- if (workbench_is_matdata_pass_enabled(wpd) || GPU_unused_fb_slot_workaround()) {
- e_data.color_buffer_tx = DRW_texture_pool_query_2d(
- size[0], size[1], col_tex_format, &draw_engine_workbench_solid);
- }
- if (OBJECT_ID_PASS_ENABLED(wpd) || GPU_unused_fb_slot_workaround()) {
- e_data.object_id_tx = DRW_texture_pool_query_2d(
- size[0], size[1], id_tex_format, &draw_engine_workbench_solid);
- }
- if (NORMAL_VIEWPORT_PASS_ENABLED(wpd)) {
- e_data.normal_buffer_tx = DRW_texture_pool_query_2d(
- size[0], size[1], nor_tex_format, &draw_engine_workbench_solid);
- }
- if (CAVITY_ENABLED(wpd)) {
- e_data.cavity_buffer_tx = DRW_texture_pool_query_2d(
- size[0], size[1], GPU_R16, &draw_engine_workbench_solid);
- }
-
- GPU_framebuffer_ensure_config(&fbl->prepass_fb,
- {
- GPU_ATTACHMENT_TEXTURE(dtxl->depth),
- GPU_ATTACHMENT_TEXTURE(e_data.color_buffer_tx),
- GPU_ATTACHMENT_TEXTURE(e_data.object_id_tx),
- GPU_ATTACHMENT_TEXTURE(e_data.normal_buffer_tx),
- });
- GPU_framebuffer_ensure_config(&fbl->cavity_fb,
- {
- GPU_ATTACHMENT_NONE,
- GPU_ATTACHMENT_TEXTURE(e_data.cavity_buffer_tx),
- });
- GPU_framebuffer_ensure_config(&fbl->composite_fb,
- {
- GPU_ATTACHMENT_TEXTURE(dtxl->depth),
- GPU_ATTACHMENT_TEXTURE(e_data.composite_buffer_tx),
- });
- GPU_framebuffer_ensure_config(&fbl->color_only_fb,
- {
- GPU_ATTACHMENT_NONE,
- GPU_ATTACHMENT_TEXTURE(e_data.composite_buffer_tx),
- });
-
- if (!workbench_is_matdata_pass_enabled(wpd) && !GPU_unused_fb_slot_workaround()) {
- e_data.color_buffer_tx = DRW_texture_pool_query_2d(
- size[0], size[1], col_tex_format, &draw_engine_workbench_solid);
- }
-
- GPU_framebuffer_ensure_config(&fbl->effect_fb,
- {
- GPU_ATTACHMENT_NONE,
- GPU_ATTACHMENT_TEXTURE(e_data.color_buffer_tx),
- });
-
- if (OBJECT_ID_PASS_ENABLED(wpd)) {
- GPU_framebuffer_ensure_config(&fbl->id_clear_fb,
- {
- GPU_ATTACHMENT_NONE,
- GPU_ATTACHMENT_TEXTURE(e_data.object_id_tx),
- });
- }
- }
-
- {
- /* AO Samples Tex */
- int num_iterations = workbench_taa_calculate_num_iterations(vedata);
-
- const int ssao_samples_single_iteration = scene->display.matcap_ssao_samples;
- const int ssao_samples = MIN2(num_iterations * ssao_samples_single_iteration, 500);
-
- if (e_data.sampling_ubo && (e_data.cached_sample_num != ssao_samples)) {
- DRW_UBO_FREE_SAFE(e_data.sampling_ubo);
- DRW_TEXTURE_FREE_SAFE(e_data.jitter_tx);
- }
-
- if (e_data.sampling_ubo == NULL) {
- float *samples = create_disk_samples(ssao_samples_single_iteration, num_iterations);
- e_data.jitter_tx = create_jitter_texture(ssao_samples);
- e_data.sampling_ubo = DRW_uniformbuffer_create(sizeof(float[4]) * ssao_samples, samples);
- e_data.cached_sample_num = ssao_samples;
- MEM_freeN(samples);
- }
- }
-
- /* Prepass */
- {
- DRWShadingGroup *grp;
- DRWState clip_state = WORLD_CLIPPING_ENABLED(wpd) ? DRW_STATE_CLIP_PLANES : 0;
- DRWState cull_state = CULL_BACKFACE_ENABLED(wpd) ? DRW_STATE_CULL_BACK : 0;
- DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
-
- psl->prepass_pass = DRW_pass_create("Prepass", state | cull_state | clip_state);
- psl->prepass_hair_pass = DRW_pass_create("Prepass", state | clip_state);
-
- psl->ghost_prepass_pass = DRW_pass_create("Prepass Ghost", state | cull_state | clip_state);
- psl->ghost_prepass_hair_pass = DRW_pass_create("Prepass Ghost", state | clip_state);
-
- psl->ghost_resolve_pass = DRW_pass_create("Resolve Ghost Depth",
- DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS);
- grp = DRW_shgroup_create(e_data.ghost_resolve_sh, psl->ghost_resolve_pass);
- DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth_in_front);
- DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL);
- }
-
- {
- workbench_aa_create_pass(vedata, &e_data.color_buffer_tx);
- }
-
- {
- workbench_dof_create_pass(vedata, &e_data.composite_buffer_tx, e_data.jitter_tx);
- }
-
- if (CAVITY_ENABLED(wpd)) {
- int state = DRW_STATE_WRITE_COLOR;
- GPUShader *shader = workbench_cavity_shader_get(SSAO_ENABLED(wpd), CURVATURE_ENABLED(wpd));
- psl->cavity_pass = DRW_pass_create("Cavity", state);
- DRWShadingGroup *grp = DRW_shgroup_create(shader, psl->cavity_pass);
- DRW_shgroup_uniform_texture_ref(grp, "normalBuffer", &e_data.normal_buffer_tx);
- DRW_shgroup_uniform_block(grp, "samples_block", e_data.sampling_ubo);
-
- if (SSAO_ENABLED(wpd)) {
- DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth);
- DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1);
- DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)wpd->viewvecs, 3);
- DRW_shgroup_uniform_vec4(grp, "ssao_params", wpd->ssao_params, 1);
- DRW_shgroup_uniform_vec4(grp, "ssao_settings", wpd->ssao_settings, 1);
- DRW_shgroup_uniform_mat4(grp, "WinMatrix", wpd->winmat);
- DRW_shgroup_uniform_texture(grp, "ssao_jitter", e_data.jitter_tx);
- }
-
- if (CURVATURE_ENABLED(wpd)) {
- DRW_shgroup_uniform_texture_ref(grp, "objectId", &e_data.object_id_tx);
- DRW_shgroup_uniform_vec2(grp, "curvature_settings", &wpd->world_data.curvature_ridge, 1);
- }
-
- DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL);
- }
-}
-
-void workbench_deferred_engine_free(void)
-{
- for (int sh_data_index = 0; sh_data_index < ARRAY_SIZE(e_data.sh_data); sh_data_index++) {
- WORKBENCH_DEFERRED_Shaders *sh_data = &e_data.sh_data[sh_data_index];
- for (int index = 0; index < MAX_PREPASS_SHADERS; index++) {
- DRW_SHADER_FREE_SAFE(sh_data->prepass_sh_cache[index]);
- }
- }
- for (int index = 0; index < MAX_COMPOSITE_SHADERS; index++) {
- DRW_SHADER_FREE_SAFE(e_data.composite_sh_cache[index]);
- }
- for (int index = 0; index < MAX_CAVITY_SHADERS; index++) {
- DRW_SHADER_FREE_SAFE(e_data.cavity_sh[index]);
- }
- DRW_SHADER_FREE_SAFE(e_data.ghost_resolve_sh);
- DRW_UBO_FREE_SAFE(e_data.sampling_ubo);
- DRW_TEXTURE_FREE_SAFE(e_data.jitter_tx);
- DRW_SHADER_FREE_SAFE(e_data.background_sh[0]);
- DRW_SHADER_FREE_SAFE(e_data.background_sh[1]);
-
- DRW_SHADER_FREE_SAFE(e_data.oit_resolve_sh);
-
- DRW_SHADER_FREE_SAFE(e_data.shadow_pass_sh);
- DRW_SHADER_FREE_SAFE(e_data.shadow_pass_manifold_sh);
- DRW_SHADER_FREE_SAFE(e_data.shadow_fail_sh);
- DRW_SHADER_FREE_SAFE(e_data.shadow_fail_manifold_sh);
- DRW_SHADER_FREE_SAFE(e_data.shadow_caps_sh);
- DRW_SHADER_FREE_SAFE(e_data.shadow_caps_manifold_sh);
-
- workbench_volume_engine_free();
- workbench_fxaa_engine_free();
- workbench_taa_engine_free();
- workbench_dof_engine_free();
-}
-
-static void workbench_composite_uniforms(WORKBENCH_PrivateData *wpd, DRWShadingGroup *grp)
-{
- DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo);
- if (workbench_is_matdata_pass_enabled(wpd)) {
- DRW_shgroup_uniform_texture_ref(grp, "materialBuffer", &e_data.color_buffer_tx);
- }
- else {
- DRW_shgroup_uniform_vec3(grp, "materialSingleColor", wpd->shading.single_color, 1);
- }
- if (OBJECT_OUTLINE_ENABLED(wpd)) {
- DRW_shgroup_uniform_texture_ref(grp, "objectId", &e_data.object_id_tx);
- }
- if (NORMAL_VIEWPORT_COMP_PASS_ENABLED(wpd)) {
- DRW_shgroup_uniform_texture_ref(grp, "normalBuffer", &e_data.normal_buffer_tx);
- }
- if (CAVITY_ENABLED(wpd)) {
- DRW_shgroup_uniform_texture_ref(grp, "cavityBuffer", &e_data.cavity_buffer_tx);
- }
- if (workbench_is_specular_highlight_enabled(wpd) || STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) {
- DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)wpd->viewvecs, 3);
- }
- if (workbench_is_specular_highlight_enabled(wpd) || STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) {
- DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1);
- }
- if (STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) {
- BKE_studiolight_ensure_flag(wpd->studio_light,
- STUDIOLIGHT_MATCAP_DIFFUSE_GPUTEXTURE |
- STUDIOLIGHT_MATCAP_SPECULAR_GPUTEXTURE);
- DRW_shgroup_uniform_texture(
- grp, "matcapDiffuseImage", wpd->studio_light->matcap_diffuse.gputexture);
- if (workbench_is_specular_highlight_enabled(wpd)) {
- DRW_shgroup_uniform_texture(
- grp, "matcapSpecularImage", wpd->studio_light->matcap_specular.gputexture);
- }
- }
-}
-
-void workbench_deferred_cache_init(WORKBENCH_Data *vedata)
-{
- WORKBENCH_StorageList *stl = vedata->stl;
- WORKBENCH_PassList *psl = vedata->psl;
- WORKBENCH_PrivateData *wpd = stl->g_data;
- DRWShadingGroup *grp;
- const DRWContextState *draw_ctx = DRW_context_state_get();
-
- Scene *scene = draw_ctx->scene;
-
- workbench_volume_cache_init(vedata);
- select_deferred_shaders(wpd, draw_ctx->sh_cfg);
-
- /* Background Pass */
- {
- DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL;
- if (DRW_state_is_scene_render()) {
- /* Composite the scene over cleared background. */
- state |= DRW_STATE_BLEND_ALPHA_PREMUL;
- }
- psl->background_pass = DRW_pass_create("Background", state);
- grp = DRW_shgroup_create(wpd->background_sh, psl->background_pass);
- DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo);
- DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1);
- if (OBJECT_OUTLINE_ENABLED(wpd)) {
- DRW_shgroup_uniform_texture_ref(grp, "objectId", &e_data.object_id_tx);
- }
- DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL);
- }
-
- /* Deferred Mix Pass */
- {
- workbench_private_data_get_light_direction(e_data.display.light_direction);
- studiolight_update_light(wpd, e_data.display.light_direction);
-
- if (SHADOW_ENABLED(wpd)) {
- psl->composite_pass = DRW_pass_create(
- "Composite", DRW_STATE_WRITE_COLOR | DRW_STATE_STENCIL_EQUAL | DRW_STATE_DEPTH_GREATER);
- grp = DRW_shgroup_create(wpd->composite_sh, psl->composite_pass);
- workbench_composite_uniforms(wpd, grp);
- DRW_shgroup_stencil_mask(grp, 0x00);
- DRW_shgroup_uniform_float_copy(grp, "lightMultiplier", 1.0f);
- DRW_shgroup_uniform_float(grp, "shadowMultiplier", &wpd->shadow_multiplier, 1);
- DRW_shgroup_uniform_float_copy(grp, "shadowShift", scene->display.shadow_shift);
- DRW_shgroup_uniform_float_copy(grp, "shadowFocus", wpd->shadow_focus);
- DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL);
-
- /* Stencil Shadow passes. */
-#ifdef DEBUG_SHADOW_VOLUME
- DRWState depth_pass_state = DRW_STATE_DEPTH_LESS | DRW_STATE_WRITE_COLOR |
- DRW_STATE_BLEND_ADD;
- DRWState depth_fail_state = DRW_STATE_DEPTH_GREATER_EQUAL | DRW_STATE_WRITE_COLOR |
- DRW_STATE_BLEND_ADD;
-#else
- DRWState depth_pass_state = DRW_STATE_DEPTH_LESS | DRW_STATE_WRITE_STENCIL_SHADOW_PASS |
- DRW_STATE_STENCIL_ALWAYS;
- DRWState depth_fail_state = DRW_STATE_DEPTH_LESS | DRW_STATE_WRITE_STENCIL_SHADOW_FAIL |
- DRW_STATE_STENCIL_ALWAYS;
-#endif
- psl->shadow_depth_pass_pass = DRW_pass_create("Shadow Pass", depth_pass_state);
- psl->shadow_depth_pass_mani_pass = DRW_pass_create("Shadow Pass Mani", depth_pass_state);
- psl->shadow_depth_fail_pass = DRW_pass_create("Shadow Fail", depth_fail_state);
- psl->shadow_depth_fail_mani_pass = DRW_pass_create("Shadow Fail Mani", depth_fail_state);
- psl->shadow_depth_fail_caps_pass = DRW_pass_create("Shadow Fail Caps", depth_fail_state);
- psl->shadow_depth_fail_caps_mani_pass = DRW_pass_create("Shadow Fail Caps Mani",
- depth_fail_state);
-
-#ifndef DEBUG_SHADOW_VOLUME
- grp = DRW_shgroup_create(e_data.shadow_pass_sh, psl->shadow_depth_pass_pass);
- DRW_shgroup_stencil_mask(grp, 0xFF);
- grp = DRW_shgroup_create(e_data.shadow_pass_manifold_sh, psl->shadow_depth_pass_mani_pass);
- DRW_shgroup_stencil_mask(grp, 0xFF);
- grp = DRW_shgroup_create(e_data.shadow_fail_sh, psl->shadow_depth_fail_pass);
- DRW_shgroup_stencil_mask(grp, 0xFF);
- grp = DRW_shgroup_create(e_data.shadow_fail_manifold_sh, psl->shadow_depth_fail_mani_pass);
- DRW_shgroup_stencil_mask(grp, 0xFF);
- grp = DRW_shgroup_create(e_data.shadow_caps_sh, psl->shadow_depth_fail_caps_pass);
- DRW_shgroup_stencil_mask(grp, 0xFF);
- grp = DRW_shgroup_create(e_data.shadow_caps_manifold_sh,
- psl->shadow_depth_fail_caps_mani_pass);
- DRW_shgroup_stencil_mask(grp, 0xFF);
-
- psl->composite_shadow_pass = DRW_pass_create(
- "Composite Shadow",
- DRW_STATE_WRITE_COLOR | DRW_STATE_STENCIL_NEQUAL | DRW_STATE_DEPTH_GREATER);
- grp = DRW_shgroup_create(wpd->composite_sh, psl->composite_shadow_pass);
- DRW_shgroup_stencil_mask(grp, 0x00);
- workbench_composite_uniforms(wpd, grp);
- DRW_shgroup_uniform_float(grp, "lightMultiplier", &wpd->shadow_multiplier, 1);
- DRW_shgroup_uniform_float(grp, "shadowMultiplier", &wpd->shadow_multiplier, 1);
- DRW_shgroup_uniform_float_copy(grp, "shadowShift", scene->display.shadow_shift);
- DRW_shgroup_uniform_float_copy(grp, "shadowFocus", wpd->shadow_focus);
- DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL);
-#endif
- }
- else {
- psl->composite_pass = DRW_pass_create("Composite",
- DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_GREATER);
- grp = DRW_shgroup_create(wpd->composite_sh, psl->composite_pass);
- workbench_composite_uniforms(wpd, grp);
- DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL);
- }
- }
-
- /**
- * Order Independent Transparency.
- * Similar to workbench forward. Duplicated code to avoid
- * spaghetti with workbench forward. It would be great if we unify
- * this in a clean way.
- */
- if (OIT_ENABLED(wpd)) {
- DRWState clip_state = WORLD_CLIPPING_ENABLED(wpd) ? DRW_STATE_CLIP_PLANES : 0;
- DRWState cull_state = CULL_BACKFACE_ENABLED(wpd) ? DRW_STATE_CULL_BACK : 0;
- /* Transparency Accum */
- {
- /* Same as forward but here we use depth test to
- * not bleed through other solid objects. */
- int state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS | DRW_STATE_BLEND_OIT | cull_state |
- clip_state;
- psl->transparent_accum_pass = DRW_pass_create("Transparent Accum", state);
- }
- /* Depth */
- {
- int state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | cull_state | clip_state;
- psl->object_outline_pass = DRW_pass_create("Transparent Depth", state);
- }
- /* OIT Composite */
- {
- int state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL;
- psl->oit_composite_pass = DRW_pass_create("OIT Composite", state);
-
- grp = DRW_shgroup_create(e_data.oit_resolve_sh, psl->oit_composite_pass);
- DRW_shgroup_uniform_texture_ref(grp, "transparentAccum", &e_data.oit_accum_tx);
- DRW_shgroup_uniform_texture_ref(grp, "transparentRevealage", &e_data.oit_revealage_tx);
- DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1);
- DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL);
- }
- }
-}
-
-static WORKBENCH_MaterialData *get_or_create_material_data(WORKBENCH_Data *vedata,
- Object *ob,
- Material *mat,
- Image *ima,
- ImageUser *iuser,
- eV3DShadingColorType color_type,
- int interp)
-{
- WORKBENCH_StorageList *stl = vedata->stl;
- WORKBENCH_PassList *psl = vedata->psl;
- WORKBENCH_PrivateData *wpd = stl->g_data;
- WORKBENCH_MaterialData *material;
- WORKBENCH_MaterialData material_template;
- const bool is_ghost = (ob->dtx & OB_DRAWXRAY);
-
- /* Solid */
- workbench_material_update_data(wpd, ob, mat, &material_template, color_type);
- material_template.color_type = color_type;
- material_template.ima = ima;
- material_template.iuser = iuser;
- material_template.interp = interp;
- uint hash = workbench_material_get_hash(&material_template, is_ghost);
-
- material = BLI_ghash_lookup(wpd->material_hash, POINTER_FROM_UINT(hash));
- if (material == NULL) {
- material = MEM_mallocN(sizeof(WORKBENCH_MaterialData), __func__);
- /* select the correct prepass shader */
- GPUShader *shader = (wpd->shading.color_type == color_type) ? wpd->prepass_sh :
- wpd->prepass_uniform_sh;
- const bool is_tiled = (ima && ima->source == IMA_SRC_TILED);
- if (color_type == V3D_SHADING_TEXTURE_COLOR) {
- shader = is_tiled ? wpd->prepass_textured_array_sh : wpd->prepass_textured_sh;
- }
- if (color_type == V3D_SHADING_VERTEX_COLOR) {
- shader = wpd->prepass_vertex_sh;
- }
- material->shgrp = DRW_shgroup_create(
- shader, (ob->dtx & OB_DRAWXRAY) ? psl->ghost_prepass_pass : psl->prepass_pass);
- workbench_material_copy(material, &material_template);
- DRW_shgroup_stencil_mask(material->shgrp, (ob->dtx & OB_DRAWXRAY) ? 0x00 : 0xFF);
- workbench_material_shgroup_uniform(wpd, material->shgrp, material, ob, true, is_tiled, interp);
- BLI_ghash_insert(wpd->material_hash, POINTER_FROM_UINT(hash), material);
- }
- return material;
-}
-
-static void workbench_cache_populate_particles(WORKBENCH_Data *vedata, Object *ob)
-{
- WORKBENCH_StorageList *stl = vedata->stl;
- WORKBENCH_PassList *psl = vedata->psl;
- WORKBENCH_PrivateData *wpd = stl->g_data;
-
- for (ModifierData *md = ob->modifiers.first; md; md = md->next) {
- if (md->type != eModifierType_ParticleSystem) {
- continue;
- }
- ParticleSystem *psys = ((ParticleSystemModifierData *)md)->psys;
- if (!DRW_object_is_visible_psys_in_active_context(ob, psys)) {
- continue;
- }
- ParticleSettings *part = psys->part;
- const int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as;
-
- if (draw_as == PART_DRAW_PATH) {
- Material *mat;
- Image *image;
- ImageUser *iuser;
- int interp;
- workbench_material_get_image_and_mat(ob, part->omat, &image, &iuser, &interp, &mat);
- eV3DShadingColorType color_type = workbench_material_determine_color_type(
- wpd, image, ob, false);
- WORKBENCH_MaterialData *material = get_or_create_material_data(
- vedata, ob, mat, image, iuser, color_type, interp);
-
- struct GPUShader *shader = (wpd->shading.color_type == color_type) ?
- wpd->prepass_hair_sh :
- wpd->prepass_uniform_hair_sh;
- DRWShadingGroup *shgrp = DRW_shgroup_hair_create(
- ob,
- psys,
- md,
- (ob->dtx & OB_DRAWXRAY) ? psl->ghost_prepass_hair_pass : psl->prepass_hair_pass,
- shader);
- DRW_shgroup_stencil_mask(shgrp, (ob->dtx & OB_DRAWXRAY) ? 0x00 : 0xFF);
- workbench_material_shgroup_uniform(wpd, shgrp, material, ob, true, false, interp);
- }
- }
-}
-
-static void workbench_cache_populate_texture_paint_mode(WORKBENCH_Data *vedata, Object *ob)
-{
- WORKBENCH_StorageList *stl = vedata->stl;
- WORKBENCH_PrivateData *wpd = stl->g_data;
- const DRWContextState *draw_ctx = DRW_context_state_get();
-
- Scene *scene = draw_ctx->scene;
- const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) &&
- !DRW_state_is_image_render();
- WORKBENCH_MaterialData *material;
-
- /* Force workbench to render active object textured when in texture paint mode */
- const ImagePaintSettings *imapaint = &scene->toolsettings->imapaint;
-
- /* Single Image mode */
- if (imapaint->mode == IMAGEPAINT_MODE_IMAGE) {
- Image *image = imapaint->canvas;
- int interp = (imapaint->interp == IMAGEPAINT_INTERP_LINEAR) ? SHD_INTERP_LINEAR :
- SHD_INTERP_CLOSEST;
- eV3DShadingColorType color_type = workbench_material_determine_color_type(
- wpd, image, ob, use_sculpt_pbvh);
- struct GPUBatch *geom = DRW_cache_mesh_surface_texpaint_single_get(ob);
- material = get_or_create_material_data(vedata, ob, NULL, image, NULL, color_type, interp);
-
- DRW_shgroup_call(material->shgrp, geom, ob);
- }
- else {
- /* IMAGEPAINT_MODE_MATERIAL */
- const int materials_len = DRW_cache_object_material_count_get(ob);
- struct GPUBatch **geom_array = DRW_cache_mesh_surface_texpaint_get(ob);
- for (int i = 0; i < materials_len; i++) {
- if (geom_array != NULL && geom_array[i] != NULL) {
- Material *mat;
- Image *image;
- ImageUser *iuser;
- int interp;
- workbench_material_get_image_and_mat(ob, i + 1, &image, &iuser, &interp, &mat);
- eV3DShadingColorType color_type = workbench_material_determine_color_type(
- wpd, image, ob, use_sculpt_pbvh);
- material = get_or_create_material_data(vedata, ob, mat, image, iuser, color_type, interp);
- DRW_shgroup_call(material->shgrp, geom_array[i], ob);
- }
- }
- }
-}
-
-static void workbench_cache_populate_vertex_paint_mode(WORKBENCH_Data *vedata, Object *ob)
-{
- WORKBENCH_StorageList *stl = vedata->stl;
- WORKBENCH_PrivateData *wpd = stl->g_data;
- const DRWContextState *draw_ctx = DRW_context_state_get();
-
- const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) &&
- !DRW_state_is_image_render();
- WORKBENCH_MaterialData *material;
-
- eV3DShadingColorType color_type = workbench_material_determine_color_type(
- wpd, NULL, ob, use_sculpt_pbvh);
- struct GPUBatch *geom = DRW_cache_mesh_surface_vertpaint_get(ob);
- material = get_or_create_material_data(vedata, ob, NULL, NULL, NULL, color_type, false);
- DRW_shgroup_call(material->shgrp, geom, ob);
-}
-
-void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob)
-{
- WORKBENCH_StorageList *stl = vedata->stl;
- WORKBENCH_PassList *psl = vedata->psl;
- WORKBENCH_PrivateData *wpd = stl->g_data;
- const DRWContextState *draw_ctx = DRW_context_state_get();
- Scene *scene = draw_ctx->scene;
-
- if (!DRW_object_is_renderable(ob)) {
- return;
- }
-
- if (ob->type == OB_MESH) {
- workbench_cache_populate_particles(vedata, ob);
- }
-
- ModifierData *md;
- if (((ob->base_flag & BASE_FROM_DUPLI) == 0) &&
- (md = modifiers_findByType(ob, eModifierType_Fluid)) &&
- (modifier_isEnabled(scene, md, eModifierMode_Realtime)) &&
- (((FluidModifierData *)md)->domain != NULL) &&
- (((FluidModifierData *)md)->domain->type == FLUID_DOMAIN_TYPE_GAS)) {
- workbench_volume_cache_populate(vedata, scene, ob, md);
- return; /* Do not draw solid in this case. */
- }
-
- if (!(DRW_object_visibility_in_active_context(ob) & OB_VISIBLE_SELF)) {
- return;
- }
- if ((ob->dt < OB_SOLID) && !DRW_state_is_scene_render()) {
- return;
- }
-
- WORKBENCH_MaterialData *material;
- if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL)) {
- const bool is_active = (ob == draw_ctx->obact);
- const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) &&
- !DRW_state_is_image_render();
- const bool use_hide = is_active && DRW_object_use_hide_faces(ob);
- const int materials_len = DRW_cache_object_material_count_get(ob);
- const Mesh *me = (ob->type == OB_MESH) ? ob->data : NULL;
- bool has_transp_mat = false;
- const WORKBENCH_ColorOverride color_override = workbench_object_color_override_get(ob);
- const bool use_texture_paint_drawing = !(DRW_state_is_image_render() &&
- draw_ctx->v3d == NULL) &&
- (color_override == WORKBENCH_COLOR_OVERRIDE_TEXTURE) &&
- me && me->mloopuv;
- const bool use_vertex_paint_drawing = !(DRW_state_is_image_render() &&
- draw_ctx->v3d == NULL) &&
- (color_override == WORKBENCH_COLOR_OVERRIDE_VERTEX) &&
- me && me->mloopcol;
-
- if (use_texture_paint_drawing) {
- workbench_cache_populate_texture_paint_mode(vedata, ob);
- }
- else if (use_vertex_paint_drawing) {
- workbench_cache_populate_vertex_paint_mode(vedata, ob);
- }
- else if (!use_sculpt_pbvh && TEXTURE_DRAWING_ENABLED(wpd) && me && me->mloopuv) {
- /* Draw textured */
- struct GPUBatch **geom_array = DRW_cache_mesh_surface_texpaint_get(ob);
- for (int i = 0; i < materials_len; i++) {
- if (geom_array != NULL && geom_array[i] != NULL) {
- Material *mat;
- Image *image;
- ImageUser *iuser;
- int interp;
- workbench_material_get_image_and_mat(ob, i + 1, &image, &iuser, &interp, &mat);
- eV3DShadingColorType color_type = workbench_material_determine_color_type(
- wpd, image, ob, use_sculpt_pbvh);
- if (color_type == V3D_SHADING_MATERIAL_COLOR && mat && mat->a < 1.0) {
- material = workbench_forward_get_or_create_material_data(
- vedata, ob, mat, image, iuser, color_type, 0);
- has_transp_mat = true;
- }
- else {
- material = get_or_create_material_data(
- vedata, ob, mat, image, iuser, color_type, interp);
- }
- DRW_shgroup_call(material->shgrp, geom_array[i], ob);
- }
- }
- }
- else if (ELEM(wpd->shading.color_type,
- V3D_SHADING_SINGLE_COLOR,
- V3D_SHADING_OBJECT_COLOR,
- V3D_SHADING_RANDOM_COLOR,
- V3D_SHADING_VERTEX_COLOR)) {
- eV3DShadingColorType color_type = workbench_material_determine_color_type(
- wpd, NULL, ob, use_sculpt_pbvh);
-
- if ((ob->color[3] < 1.0f) && (color_type == V3D_SHADING_OBJECT_COLOR)) {
- material = workbench_forward_get_or_create_material_data(
- vedata, ob, NULL, NULL, NULL, color_type, 0);
- has_transp_mat = true;
- }
- else {
- /* Draw solid color */
- material = get_or_create_material_data(vedata, ob, NULL, NULL, NULL, color_type, 0);
- }
-
- if (use_sculpt_pbvh) {
- bool use_vcol = (color_type == V3D_SHADING_VERTEX_COLOR);
- DRW_shgroup_call_sculpt(material->shgrp, ob, false, false, use_vcol);
- }
- else {
- struct GPUBatch *geom;
- if (color_type == V3D_SHADING_VERTEX_COLOR) {
- geom = DRW_cache_mesh_surface_vertpaint_get(ob);
- }
- else {
- geom = DRW_cache_object_surface_get(ob);
- }
-
- if (geom) {
- DRW_shgroup_call(material->shgrp, geom, ob);
- }
- }
- }
- else {
- /* Draw material color */
- if (use_sculpt_pbvh) {
- struct DRWShadingGroup **shgrps = BLI_array_alloca(shgrps, materials_len);
-
- for (int i = 0; i < materials_len; i++) {
- struct Material *mat = BKE_object_material_get(ob, i + 1);
- if (mat != NULL && mat->a < 1.0f) {
- material = workbench_forward_get_or_create_material_data(
- vedata, ob, mat, NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0);
- has_transp_mat = true;
- }
- else {
- material = get_or_create_material_data(
- vedata, ob, mat, NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0);
- }
- shgrps[i] = material->shgrp;
- }
- DRW_shgroup_call_sculpt_with_materials(shgrps, ob, false);
- }
- else {
- struct GPUBatch **geoms;
- struct GPUMaterial **gpumat_array = BLI_array_alloca(gpumat_array, materials_len);
- memset(gpumat_array, 0, sizeof(*gpumat_array) * materials_len);
-
- geoms = DRW_cache_object_surface_material_get(ob, gpumat_array, materials_len);
- for (int i = 0; i < materials_len; i++) {
- if (geoms != NULL && geoms[i] != NULL) {
- Material *mat = BKE_object_material_get(ob, i + 1);
- if (mat != NULL && mat->a < 1.0f) {
- material = workbench_forward_get_or_create_material_data(
- vedata, ob, mat, NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0);
- has_transp_mat = true;
- }
- else {
- material = get_or_create_material_data(
- vedata, ob, mat, NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0);
- }
- DRW_shgroup_call(material->shgrp, geoms[i], ob);
- }
- }
- }
- }
-
- if (SHADOW_ENABLED(wpd) && !(ob->dtx & OB_DRAW_NO_SHADOW_CAST)) {
- bool is_manifold;
- struct GPUBatch *geom_shadow = DRW_cache_object_edge_detection_get(ob, &is_manifold);
- if (geom_shadow) {
- if (use_sculpt_pbvh || use_hide) {
- /* 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. */
- // DRW_shgroup_call_sculpt(wpd->shadow_shgrp, ob, ob->obmat);
- }
- 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);
-
- if (studiolight_object_cast_visible_shadow(wpd, ob, engine_object_data)) {
-
- mul_v3_mat3_m4v3(
- engine_object_data->shadow_dir, ob->imat, e_data.display.light_direction);
-
- DRWShadingGroup *grp;
- bool use_shadow_pass_technique = !studiolight_camera_in_object_shadow(
- wpd, ob, engine_object_data);
-
- if (use_shadow_pass_technique && !has_transp_mat) {
- if (is_manifold) {
- grp = DRW_shgroup_create(e_data.shadow_pass_manifold_sh,
- psl->shadow_depth_pass_mani_pass);
- }
- else {
- grp = DRW_shgroup_create(e_data.shadow_pass_sh, psl->shadow_depth_pass_pass);
- }
- 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);
-#ifdef 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) {
- if (is_manifold) {
- grp = DRW_shgroup_create(e_data.shadow_caps_manifold_sh,
- psl->shadow_depth_fail_caps_mani_pass);
- }
- else {
- grp = DRW_shgroup_create(e_data.shadow_caps_sh,
- psl->shadow_depth_fail_caps_pass);
- }
- 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);
- }
-
- if (is_manifold) {
- grp = DRW_shgroup_create(e_data.shadow_fail_manifold_sh,
- psl->shadow_depth_fail_mani_pass);
- }
- else {
- grp = DRW_shgroup_create(e_data.shadow_fail_sh, psl->shadow_depth_fail_pass);
- }
- 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);
-#ifdef DEBUG_SHADOW_VOLUME
- DRW_debug_bbox(&engine_object_data->shadow_bbox, (float[4]){0.0f, 1.0f, 0.0f, 1.0f});
-#endif
- }
- }
- }
- }
- }
- }
-}
-
-void workbench_deferred_cache_finish(WORKBENCH_Data *vedata)
-{
- WORKBENCH_PassList *psl = vedata->psl;
- WORKBENCH_FramebufferList *fbl = vedata->fbl;
-
- if (GHOST_ENABLED(psl)) {
- /* HACK we allocate the infront depth here to avoid the overhead when if is not needed. */
- DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
- DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
-
- DRW_texture_ensure_fullscreen_2d(&dtxl->depth_in_front, GPU_DEPTH24_STENCIL8, 0);
-
- GPU_framebuffer_ensure_config(
- &dfbl->default_fb,
- {GPU_ATTACHMENT_TEXTURE(dtxl->depth), GPU_ATTACHMENT_TEXTURE(dtxl->color)});
- GPU_framebuffer_ensure_config(
- &dfbl->in_front_fb,
- {GPU_ATTACHMENT_TEXTURE(dtxl->depth_in_front), GPU_ATTACHMENT_TEXTURE(dtxl->color)});
-
- GPU_framebuffer_ensure_config(&fbl->ghost_prepass_fb,
- {
- GPU_ATTACHMENT_TEXTURE(dtxl->depth_in_front),
- GPU_ATTACHMENT_TEXTURE(e_data.color_buffer_tx),
- GPU_ATTACHMENT_TEXTURE(e_data.object_id_tx),
- GPU_ATTACHMENT_TEXTURE(e_data.normal_buffer_tx),
- });
- }
-}
-
-void workbench_deferred_draw_scene(WORKBENCH_Data *vedata)
-{
- WORKBENCH_PassList *psl = vedata->psl;
- WORKBENCH_StorageList *stl = vedata->stl;
- WORKBENCH_FramebufferList *fbl = vedata->fbl;
- WORKBENCH_PrivateData *wpd = stl->g_data;
- DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
- DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
-
- if (workbench_is_taa_enabled(wpd)) {
- workbench_taa_draw_scene_start(vedata);
- }
-
- const float clear_depth = 1.0f;
- const float clear_col[4] = {0.0f, 0.0f, 0.0f, 0.0f};
- uint clear_stencil = 0x00;
- int clear_bits = GPU_DEPTH_BIT;
- SET_FLAG_FROM_TEST(clear_bits, SHADOW_ENABLED(wpd), GPU_STENCIL_BIT);
-
- if (OBJECT_ID_PASS_ENABLED(wpd)) {
- /* From all the color buffers, only object id needs to be cleared. */
- GPU_framebuffer_bind(fbl->id_clear_fb);
- GPU_framebuffer_clear_color(fbl->id_clear_fb, clear_col);
- }
-
- GPU_framebuffer_bind(fbl->prepass_fb);
- GPU_framebuffer_clear(fbl->prepass_fb, clear_bits, clear_col, clear_depth, clear_stencil);
-
- DRW_draw_pass(psl->prepass_pass);
- DRW_draw_pass(psl->prepass_hair_pass);
-
- if (fbl->ghost_prepass_fb) {
- GPU_framebuffer_bind(fbl->ghost_prepass_fb);
- GPU_framebuffer_clear_depth(fbl->ghost_prepass_fb, 1.0f);
- }
- else if (dtxl->depth_in_front) {
- /* TODO(fclem) This clear should be done in a global place. */
- GPU_framebuffer_bind(dfbl->in_front_fb);
- GPU_framebuffer_clear_depth(dfbl->in_front_fb, 1.0f);
- }
-
- if (GHOST_ENABLED(psl)) {
- DRW_draw_pass(psl->ghost_prepass_pass);
- DRW_draw_pass(psl->ghost_prepass_hair_pass);
-
- GPU_framebuffer_bind(dfbl->depth_only_fb);
- DRW_draw_pass(psl->ghost_resolve_pass);
- }
-
- if (CAVITY_ENABLED(wpd)) {
- GPU_framebuffer_bind(fbl->cavity_fb);
- DRW_draw_pass(psl->cavity_pass);
- }
-
- if (DRW_state_is_scene_render()) {
- float clear_color[4];
- workbench_clear_color_get(clear_color);
- GPU_framebuffer_bind(fbl->composite_fb);
- GPU_framebuffer_clear_color(fbl->composite_fb, clear_color);
- }
-
- if (SHADOW_ENABLED(wpd)) {
-#ifdef DEBUG_SHADOW_VOLUME
- GPU_framebuffer_bind(fbl->composite_fb);
- DRW_draw_pass(psl->composite_pass);
-#else
- GPU_framebuffer_bind(dfbl->depth_only_fb);
-#endif
- DRW_draw_pass(psl->shadow_depth_pass_pass);
- DRW_draw_pass(psl->shadow_depth_pass_mani_pass);
- DRW_draw_pass(psl->shadow_depth_fail_pass);
- DRW_draw_pass(psl->shadow_depth_fail_mani_pass);
- DRW_draw_pass(psl->shadow_depth_fail_caps_pass);
- DRW_draw_pass(psl->shadow_depth_fail_caps_mani_pass);
-
- if (GHOST_ENABLED(psl)) {
- /* We need to set the stencil buffer to 0 where Ghost objects are
- * else they will get shadow and even badly shadowed. */
- DRWState state = DRW_STATE_DEPTH_EQUAL | DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_ALWAYS;
- DRW_pass_state_set(psl->ghost_prepass_pass, state);
- DRW_pass_state_set(psl->ghost_prepass_hair_pass, state);
-
- DRW_draw_pass(psl->ghost_prepass_pass);
- DRW_draw_pass(psl->ghost_prepass_hair_pass);
- }
-#ifndef DEBUG_SHADOW_VOLUME
- GPU_framebuffer_bind(fbl->composite_fb);
- DRW_draw_pass(psl->composite_pass);
- DRW_draw_pass(psl->composite_shadow_pass);
-#endif
- }
- else {
- GPU_framebuffer_bind(fbl->composite_fb);
- DRW_draw_pass(psl->composite_pass);
- }
-
- /* In order to not draw on top of ghost objects, we clear the stencil
- * to 0xFF and the ghost object to 0x00 and only draw overlays on top if
- * stencil is not 0. */
- /* TODO(fclem) Remove this hack. */
- GPU_framebuffer_bind(dfbl->depth_only_fb);
- GPU_framebuffer_clear_stencil(dfbl->depth_only_fb, 0xFF);
-
- /* TODO(fclem): only enable when needed (when there is overlays). */
- if (GHOST_ENABLED(psl)) {
- DRWState state = DRW_STATE_DEPTH_EQUAL | DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_ALWAYS;
- DRW_pass_state_set(psl->ghost_prepass_pass, state);
- DRW_pass_state_set(psl->ghost_prepass_hair_pass, state);
-
- DRW_draw_pass(psl->ghost_prepass_pass);
- DRW_draw_pass(psl->ghost_prepass_hair_pass);
- }
-
- GPU_framebuffer_bind(fbl->composite_fb);
- DRW_draw_pass(psl->background_pass);
-
- if (OIT_ENABLED(wpd) && !DRW_pass_is_empty(psl->transparent_accum_pass)) {
- /* meh, late init to not request buffers we won't use. */
- workbench_init_oit_framebuffer(fbl, dtxl);
-
- const float clear_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
- GPU_framebuffer_bind(fbl->transparent_accum_fb);
- GPU_framebuffer_clear_color(fbl->transparent_accum_fb, clear_color);
- DRW_draw_pass(psl->transparent_accum_pass);
-
- GPU_framebuffer_bind(fbl->composite_fb);
- DRW_draw_pass(psl->oit_composite_pass);
- }
-
- if (wpd->volumes_do) {
- GPU_framebuffer_bind(fbl->color_only_fb);
- DRW_draw_pass(psl->volume_pass);
- }
-
- workbench_dof_draw_pass(vedata);
- workbench_aa_draw_pass(vedata, e_data.composite_buffer_tx);
-}
-
-void workbench_deferred_draw_finish(WORKBENCH_Data *vedata)
-{
- WORKBENCH_StorageList *stl = vedata->stl;
- WORKBENCH_PrivateData *wpd = stl->g_data;
-
- /* XXX TODO(fclem) do not discard UBOS after drawing! Store them per viewport. */
- workbench_private_data_free(wpd);
- workbench_volume_smoke_textures_free(wpd);
-}
diff --git a/source/blender/draw/engines/workbench/workbench_effect_aa.c b/source/blender/draw/engines/workbench/workbench_effect_aa.c
deleted file mode 100644
index c03fe5cd5c8..00000000000
--- a/source/blender/draw/engines/workbench/workbench_effect_aa.c
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Copyright 2016, Blender Foundation.
- */
-
-/** \file
- * \ingroup draw_engine
- */
-
-#include "ED_screen.h"
-
-#include "draw_color_management.h"
-
-#include "workbench_private.h"
-
-void workbench_aa_create_pass(WORKBENCH_Data *vedata, GPUTexture **tx)
-{
- WORKBENCH_StorageList *stl = vedata->stl;
- WORKBENCH_PrivateData *wpd = stl->g_data;
- WORKBENCH_PassList *psl = vedata->psl;
- WORKBENCH_EffectInfo *effect_info = stl->effects;
- const DRWContextState *draw_ctx = DRW_context_state_get();
-
- if (draw_ctx->evil_C != NULL) {
- struct wmWindowManager *wm = CTX_wm_manager(draw_ctx->evil_C);
- wpd->is_playback = ED_screen_animation_playing(wm) != NULL;
- }
- else {
- wpd->is_playback = false;
- }
-
- if (workbench_is_taa_enabled(wpd)) {
- psl->effect_aa_pass = workbench_taa_create_pass(vedata, tx);
- }
- else if (workbench_is_fxaa_enabled(wpd)) {
- psl->effect_aa_pass = workbench_fxaa_create_pass(tx);
- effect_info->jitter_index = 0;
- }
- else {
- psl->effect_aa_pass = NULL;
- effect_info->jitter_index = 0;
- }
-}
-
-static void workspace_aa_draw_transform(GPUTexture *tx, WORKBENCH_PrivateData *UNUSED(wpd))
-{
- DRW_transform_none(tx);
-}
-
-void workbench_aa_draw_pass(WORKBENCH_Data *vedata, GPUTexture *tx)
-{
- WORKBENCH_StorageList *stl = vedata->stl;
- WORKBENCH_PrivateData *wpd = stl->g_data;
- WORKBENCH_FramebufferList *fbl = vedata->fbl;
- WORKBENCH_PassList *psl = vedata->psl;
- WORKBENCH_EffectInfo *effect_info = stl->effects;
-
- DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
- if (workbench_is_fxaa_enabled(wpd)) {
- GPU_framebuffer_bind(fbl->effect_fb);
- workspace_aa_draw_transform(tx, wpd);
- GPU_framebuffer_bind(dfbl->color_only_fb);
- DRW_draw_pass(psl->effect_aa_pass);
- }
- else if (workbench_is_taa_enabled(wpd)) {
- /*
- * when drawing the first TAA frame, we transform directly to the
- * color_only_fb as the TAA shader is just performing a direct copy.
- * the workbench_taa_draw_screen_end will fill the history buffer
- * for the other iterations.
- */
- if (effect_info->jitter_index == 1) {
- GPU_framebuffer_bind(dfbl->color_only_fb);
- workspace_aa_draw_transform(tx, wpd);
- }
- else {
- GPU_framebuffer_bind(fbl->effect_fb);
- workspace_aa_draw_transform(tx, wpd);
- GPU_framebuffer_bind(dfbl->color_only_fb);
- DRW_draw_pass(psl->effect_aa_pass);
- }
- workbench_taa_draw_scene_end(vedata);
- }
- else {
- GPU_framebuffer_bind(dfbl->color_only_fb);
- workspace_aa_draw_transform(tx, wpd);
- }
-}
diff --git a/source/blender/draw/engines/workbench/workbench_effect_antialiasing.c b/source/blender/draw/engines/workbench/workbench_effect_antialiasing.c
new file mode 100644
index 00000000000..6a8f77699bc
--- /dev/null
+++ b/source/blender/draw/engines/workbench/workbench_effect_antialiasing.c
@@ -0,0 +1,421 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2020, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ *
+ * Anti-aliasing:
+ *
+ * We use SMAA (Smart Morphological Anti-Aliasing) as a fast antialiasing solution.
+ *
+ * If the viewport stays static, the engine ask for multiple redraw and will progressively
+ * converge to a much more accurate image without aliasing.
+ * We call this one TAA (Temporal Anti-Aliasing).
+ *
+ * This is done using an accumulation buffer and a final pass that will output the final color
+ * to the scene buffer. We softly blend between SMAA and TAA to avoid really harsh transitions.
+ */
+
+#include "ED_screen.h"
+
+#include "BLI_jitter_2d.h"
+
+#include "smaa_textures.h"
+
+#include "workbench_private.h"
+
+static struct {
+ bool init;
+ float jitter_5[5][2];
+ float jitter_8[8][2];
+ float jitter_11[11][2];
+ float jitter_16[16][2];
+ float jitter_32[32][2];
+} e_data = {false};
+
+static void workbench_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 furtest 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 workbench_taa_jitter_init(void)
+{
+ if (e_data.init == false) {
+ e_data.init = true;
+ workbench_taa_jitter_init_order(e_data.jitter_5, 5);
+ workbench_taa_jitter_init_order(e_data.jitter_8, 8);
+ workbench_taa_jitter_init_order(e_data.jitter_11, 11);
+ workbench_taa_jitter_init_order(e_data.jitter_16, 16);
+ workbench_taa_jitter_init_order(e_data.jitter_32, 32);
+ }
+}
+
+int workbench_antialiasing_sample_count_get(WORKBENCH_PrivateData *wpd)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const Scene *scene = draw_ctx->scene;
+
+ if (wpd->is_navigating || wpd->is_playback) {
+ /* Only draw using SMAA or no AA when navigating. */
+ return min_ii(wpd->preferences->viewport_aa, 1);
+ }
+ else if (DRW_state_is_image_render()) {
+ if (draw_ctx->v3d) {
+ return scene->display.viewport_aa;
+ }
+ else {
+ return scene->display.render_aa;
+ }
+ }
+ else {
+ return wpd->preferences->viewport_aa;
+ }
+}
+
+void workbench_antialiasing_view_updated(WORKBENCH_Data *vedata)
+{
+ WORKBENCH_StorageList *stl = vedata->stl;
+ if (stl && stl->wpd) {
+ stl->wpd->view_updated = true;
+ }
+}
+
+void workbench_antialiasing_engine_init(WORKBENCH_Data *vedata)
+{
+ WORKBENCH_FramebufferList *fbl = vedata->fbl;
+ WORKBENCH_TextureList *txl = vedata->txl;
+ WORKBENCH_PrivateData *wpd = vedata->stl->wpd;
+ DrawEngineType *owner = (DrawEngineType *)&workbench_antialiasing_engine_init;
+
+ wpd->view = NULL;
+
+ /* reset complete drawing when navigating. */
+ if (wpd->taa_sample != 0) {
+ if (wpd->is_navigating) {
+ wpd->taa_sample = 0;
+ }
+ }
+
+ if (wpd->view_updated) {
+ wpd->taa_sample = 0;
+ wpd->view_updated = false;
+ }
+
+ {
+ float persmat[4][4];
+ DRW_view_persmat_get(NULL, persmat, false);
+ if (!equals_m4m4(persmat, wpd->last_mat)) {
+ copy_m4_m4(wpd->last_mat, persmat);
+ wpd->taa_sample = 0;
+ }
+ }
+
+ if (wpd->taa_sample_len > 0) {
+ workbench_taa_jitter_init();
+
+ DRW_texture_ensure_fullscreen_2d(&txl->history_buffer_tx, GPU_RGBA16F, DRW_TEX_FILTER);
+ DRW_texture_ensure_fullscreen_2d(&txl->depth_buffer_tx, GPU_DEPTH24_STENCIL8, 0);
+
+ wpd->smaa_edge_tx = DRW_texture_pool_query_fullscreen(GPU_RG8, owner);
+ wpd->smaa_weight_tx = DRW_texture_pool_query_fullscreen(GPU_RGBA8, owner);
+
+ GPU_framebuffer_ensure_config(&fbl->antialiasing_fb,
+ {
+ GPU_ATTACHMENT_TEXTURE(txl->depth_buffer_tx),
+ GPU_ATTACHMENT_TEXTURE(txl->history_buffer_tx),
+ });
+
+ GPU_framebuffer_ensure_config(&fbl->smaa_edge_fb,
+ {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(wpd->smaa_edge_tx),
+ });
+
+ GPU_framebuffer_ensure_config(&fbl->smaa_weight_fb,
+ {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(wpd->smaa_weight_tx),
+ });
+
+ /* TODO could be shared for all viewports. */
+ if (txl->smaa_search_tx == NULL) {
+ txl->smaa_search_tx = GPU_texture_create_nD(SEARCHTEX_WIDTH,
+ SEARCHTEX_HEIGHT,
+ 0,
+ 2,
+ searchTexBytes,
+ GPU_R8,
+ GPU_DATA_UNSIGNED_BYTE,
+ 0,
+ false,
+ NULL);
+
+ txl->smaa_area_tx = GPU_texture_create_nD(AREATEX_WIDTH,
+ AREATEX_HEIGHT,
+ 0,
+ 2,
+ areaTexBytes,
+ GPU_RG8,
+ GPU_DATA_UNSIGNED_BYTE,
+ 0,
+ false,
+ NULL);
+
+ GPU_texture_bind(txl->smaa_search_tx, 0);
+ GPU_texture_filter_mode(txl->smaa_search_tx, true);
+ GPU_texture_unbind(txl->smaa_search_tx);
+
+ GPU_texture_bind(txl->smaa_area_tx, 0);
+ GPU_texture_filter_mode(txl->smaa_area_tx, true);
+ GPU_texture_unbind(txl->smaa_area_tx);
+ }
+ }
+ else {
+ /* Cleanup */
+ DRW_TEXTURE_FREE_SAFE(txl->history_buffer_tx);
+ DRW_TEXTURE_FREE_SAFE(txl->depth_buffer_tx);
+ DRW_TEXTURE_FREE_SAFE(txl->smaa_search_tx);
+ DRW_TEXTURE_FREE_SAFE(txl->smaa_area_tx);
+ }
+}
+
+void workbench_antialiasing_cache_init(WORKBENCH_Data *vedata)
+{
+ WORKBENCH_TextureList *txl = vedata->txl;
+ WORKBENCH_PrivateData *wpd = vedata->stl->wpd;
+ WORKBENCH_PassList *psl = vedata->psl;
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+ DRWShadingGroup *grp = NULL;
+
+ if (wpd->taa_sample_len == 0) {
+ return;
+ }
+
+ {
+ DRW_PASS_CREATE(psl->aa_accum_ps, DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ADD_FULL);
+
+ GPUShader *shader = workbench_shader_antialiasing_accumulation_get();
+ grp = DRW_shgroup_create(shader, psl->aa_accum_ps);
+ DRW_shgroup_uniform_texture(grp, "colorBuffer", dtxl->color);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+ }
+
+ const float *size = DRW_viewport_size_get();
+ const float *sizeinv = DRW_viewport_invert_size_get();
+ float metrics[4] = {sizeinv[0], sizeinv[1], size[0], size[1]};
+
+ {
+ /* Stage 1: Edge detection. */
+ DRW_PASS_CREATE(psl->aa_edge_ps, DRW_STATE_WRITE_COLOR);
+
+ GPUShader *sh = workbench_shader_antialiasing_get(0);
+ grp = DRW_shgroup_create(sh, psl->aa_edge_ps);
+ DRW_shgroup_uniform_texture(grp, "colorTex", txl->history_buffer_tx);
+ DRW_shgroup_uniform_vec4_copy(grp, "viewportMetrics", metrics);
+
+ DRW_shgroup_clear_framebuffer(grp, GPU_COLOR_BIT, 0, 0, 0, 0, 0.0f, 0x0);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+ }
+ {
+ /* Stage 2: Blend Weight/Coord. */
+ DRW_PASS_CREATE(psl->aa_weight_ps, DRW_STATE_WRITE_COLOR);
+
+ GPUShader *sh = workbench_shader_antialiasing_get(1);
+ grp = DRW_shgroup_create(sh, psl->aa_weight_ps);
+ DRW_shgroup_uniform_texture(grp, "edgesTex", wpd->smaa_edge_tx);
+ DRW_shgroup_uniform_texture(grp, "areaTex", txl->smaa_area_tx);
+ DRW_shgroup_uniform_texture(grp, "searchTex", txl->smaa_search_tx);
+ DRW_shgroup_uniform_vec4_copy(grp, "viewportMetrics", metrics);
+
+ DRW_shgroup_clear_framebuffer(grp, GPU_COLOR_BIT, 0, 0, 0, 0, 0.0f, 0x0);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+ }
+ {
+ /* Stage 3: Resolve. */
+ DRW_PASS_CREATE(psl->aa_resolve_ps, DRW_STATE_WRITE_COLOR);
+
+ GPUShader *sh = workbench_shader_antialiasing_get(2);
+ grp = DRW_shgroup_create(sh, psl->aa_resolve_ps);
+ DRW_shgroup_uniform_texture(grp, "blendTex", wpd->smaa_weight_tx);
+ DRW_shgroup_uniform_texture(grp, "colorTex", txl->history_buffer_tx);
+ DRW_shgroup_uniform_vec4_copy(grp, "viewportMetrics", metrics);
+ DRW_shgroup_uniform_float(grp, "mixFactor", &wpd->smaa_mix_factor, 1);
+ DRW_shgroup_uniform_float(grp, "taaSampleCountInv", &wpd->taa_sample_inv, 1);
+
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+ }
+}
+
+/* Return true if render is not cached. */
+bool workbench_antialiasing_setup(WORKBENCH_Data *vedata)
+{
+ WORKBENCH_PrivateData *wpd = vedata->stl->wpd;
+
+ if (wpd->taa_sample_len == 0) {
+ /* AA disabled. */
+ return true;
+ }
+
+ if (wpd->taa_sample >= wpd->taa_sample_len) {
+ /* TAA accumulation has finish. Just copy the result back */
+ return false;
+ }
+ else {
+ const float *viewport_size = DRW_viewport_size_get();
+ const DRWView *default_view = DRW_view_default_get();
+ float *transform_offset;
+
+ switch (wpd->taa_sample_len) {
+ default:
+ case 5:
+ transform_offset = e_data.jitter_5[min_ii(wpd->taa_sample, 5)];
+ break;
+ case 8:
+ transform_offset = e_data.jitter_8[min_ii(wpd->taa_sample, 8)];
+ break;
+ case 11:
+ transform_offset = e_data.jitter_11[min_ii(wpd->taa_sample, 11)];
+ break;
+ case 16:
+ transform_offset = e_data.jitter_16[min_ii(wpd->taa_sample, 16)];
+ break;
+ case 32:
+ transform_offset = e_data.jitter_32[min_ii(wpd->taa_sample, 32)];
+ break;
+ }
+
+ /* 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 (wpd->view) {
+ /* When rendering just update the view. This avoids recomputing the culling. */
+ DRW_view_update_sub(wpd->view, viewmat, winmat);
+ }
+ else {
+ /* TAA is not making a big change to the matrices.
+ * Reuse the main view culling by creating a subview. */
+ wpd->view = DRW_view_create_sub(default_view, viewmat, winmat);
+ }
+ DRW_view_set_active(wpd->view);
+ return true;
+ }
+}
+
+void workbench_antialiasing_draw_pass(WORKBENCH_Data *vedata)
+{
+ WORKBENCH_PrivateData *wpd = vedata->stl->wpd;
+ WORKBENCH_FramebufferList *fbl = vedata->fbl;
+ WORKBENCH_PassList *psl = vedata->psl;
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+
+ if (wpd->taa_sample_len == 0) {
+ /* AA disabled. */
+ /* Just set sample to 1 to avoid rendering indefinitely. */
+ wpd->taa_sample = 1;
+ return;
+ }
+
+ /**
+ * We always do SMAA on top of TAA accumulation, unless the number of samples of TAA is already
+ * high. This ensure a smoother transition.
+ * If TAA accumulation is finished, we only blit the result.
+ */
+
+ if (wpd->taa_sample == 0) {
+ /* In playback mode, we are sure the next redraw will not use the same viewmatrix.
+ * In this case no need to save the depth buffer. */
+ eGPUFrameBufferBits bits = GPU_COLOR_BIT | (!wpd->is_playback ? GPU_DEPTH_BIT : 0);
+ GPU_framebuffer_blit(dfbl->default_fb, 0, fbl->antialiasing_fb, 0, bits);
+ }
+ else {
+ /* Accumulate result to the TAA buffer. */
+ GPU_framebuffer_bind(fbl->antialiasing_fb);
+ DRW_draw_pass(psl->aa_accum_ps);
+ /* Copy back the saved depth buffer for correct overlays. */
+ GPU_framebuffer_blit(fbl->antialiasing_fb, 0, dfbl->default_fb, 0, GPU_DEPTH_BIT);
+ }
+
+ if (!DRW_state_is_image_render() || wpd->taa_sample + 1 == wpd->taa_sample_len) {
+ /* After a certain point SMAA is no longer necessary. */
+ wpd->smaa_mix_factor = 1.0f - clamp_f(wpd->taa_sample / 4.0f, 0.0f, 1.0f);
+ wpd->taa_sample_inv = 1.0f / (wpd->taa_sample + 1);
+
+ if (wpd->smaa_mix_factor > 0.0f) {
+ GPU_framebuffer_bind(fbl->smaa_edge_fb);
+ DRW_draw_pass(psl->aa_edge_ps);
+
+ GPU_framebuffer_bind(fbl->smaa_weight_fb);
+ DRW_draw_pass(psl->aa_weight_ps);
+ }
+
+ GPU_framebuffer_bind(dfbl->default_fb);
+ DRW_draw_pass(psl->aa_resolve_ps);
+ }
+
+ wpd->taa_sample++;
+
+ if (!DRW_state_is_image_render() && wpd->taa_sample < wpd->taa_sample_len) {
+ DRW_viewport_request_redraw();
+ }
+}
diff --git a/source/blender/draw/engines/workbench/workbench_effect_cavity.c b/source/blender/draw/engines/workbench/workbench_effect_cavity.c
new file mode 100644
index 00000000000..cdf8a93fc57
--- /dev/null
+++ b/source/blender/draw/engines/workbench/workbench_effect_cavity.c
@@ -0,0 +1,182 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2020, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ *
+ * Cavity Effect:
+ *
+ * We use Screen Space Ambient Occlusion (SSAO) to enhance geometric details of the surfaces.
+ * We also use a Curvature effect computed only using the surface normals.
+ *
+ * This is done after the opaque pass. It only affects the opaque surfaces.
+ */
+
+#include "DRW_render.h"
+
+#include "BLI_rand.h"
+
+#include "../eevee/eevee_lut.h" /* TODO find somewhere to share blue noise Table */
+
+#include "workbench_engine.h"
+#include "workbench_private.h"
+
+#define JITTER_TEX_SIZE 64
+#define CAVITY_MAX_SAMPLES 512
+
+/* Using Hammersley distribution */
+static float *create_disk_samples(int num_samples, int num_iterations)
+{
+ const int total_samples = num_samples * num_iterations;
+ const float num_samples_inv = 1.0f / num_samples;
+ /* vec4 to ensure memory alignment. */
+ float(*texels)[4] = MEM_callocN(sizeof(float[4]) * CAVITY_MAX_SAMPLES, __func__);
+
+ for (int i = 0; i < total_samples; i++) {
+ float it_add = (i / num_samples) * 0.499f;
+ float r = fmodf((i + 0.5f + it_add) * num_samples_inv, 1.0f);
+ double dphi;
+ BLI_hammersley_1d(i, &dphi);
+
+ float phi = (float)dphi * 2.0f * M_PI + it_add;
+ texels[i][0] = cosf(phi);
+ texels[i][1] = sinf(phi);
+ /* This deliberately distribute more samples
+ * at the center of the disk (and thus the shadow). */
+ texels[i][2] = r;
+ }
+
+ return (float *)texels;
+}
+
+static struct GPUTexture *create_jitter_texture(int num_samples)
+{
+ float jitter[64 * 64][4];
+ const float num_samples_inv = 1.0f / num_samples;
+
+ for (int i = 0; i < 64 * 64; i++) {
+ float phi = blue_noise[i][0] * 2.0f * M_PI;
+ /* This rotate the sample per pixels */
+ jitter[i][0] = cosf(phi);
+ jitter[i][1] = sinf(phi);
+ /* This offset the sample along it's direction axis (reduce banding) */
+ float bn = blue_noise[i][1] - 0.5f;
+ CLAMP(bn, -0.499f, 0.499f); /* fix fireflies */
+ jitter[i][2] = bn * num_samples_inv;
+ jitter[i][3] = blue_noise[i][1];
+ }
+
+ UNUSED_VARS(bsdf_split_sum_ggx, btdf_split_sum_ggx, ltc_mag_ggx, ltc_mat_ggx, ltc_disk_integral);
+
+ return DRW_texture_create_2d(64, 64, GPU_RGBA16F, DRW_TEX_WRAP, &jitter[0][0]);
+}
+
+BLI_INLINE int workbench_cavity_total_sample_count(const WORKBENCH_PrivateData *wpd,
+ const Scene *scene)
+{
+ return min_ii(max_ii(1, wpd->taa_sample_len) * scene->display.matcap_ssao_samples,
+ CAVITY_MAX_SAMPLES);
+}
+
+void workbench_cavity_data_update(WORKBENCH_PrivateData *wpd, WORKBENCH_UBO_World *wd)
+{
+ View3DShading *shading = &wpd->shading;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Scene *scene = draw_ctx->scene;
+
+ if (CAVITY_ENABLED(wpd)) {
+ int cavity_sample_count_single_iteration = scene->display.matcap_ssao_samples;
+ int cavity_sample_count_total = workbench_cavity_total_sample_count(wpd, scene);
+ int max_iter_count = cavity_sample_count_total / cavity_sample_count_single_iteration;
+
+ int sample = wpd->taa_sample % max_iter_count;
+ wd->cavity_sample_start = cavity_sample_count_single_iteration * sample;
+ wd->cavity_sample_end = cavity_sample_count_single_iteration * (sample + 1);
+
+ wd->cavity_sample_count_inv = 1.0f / (wd->cavity_sample_end - wd->cavity_sample_start);
+ wd->cavity_jitter_scale = 1.0f / 64.0f;
+
+ wd->cavity_valley_factor = shading->cavity_valley_factor;
+ wd->cavity_ridge_factor = shading->cavity_ridge_factor;
+ wd->cavity_attenuation = scene->display.matcap_ssao_attenuation;
+ wd->cavity_distance = scene->display.matcap_ssao_distance;
+
+ wd->curvature_ridge = 0.5f / max_ff(square_f(shading->curvature_ridge_factor), 1e-4f);
+ wd->curvature_valley = 0.7f / max_ff(square_f(shading->curvature_valley_factor), 1e-4f);
+ }
+}
+
+void workbench_cavity_samples_ubo_ensure(WORKBENCH_PrivateData *wpd)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Scene *scene = draw_ctx->scene;
+
+ int cavity_sample_count_single_iteration = scene->display.matcap_ssao_samples;
+ int cavity_sample_count = workbench_cavity_total_sample_count(wpd, scene);
+
+ if (wpd->vldata->cavity_sample_count != cavity_sample_count) {
+ DRW_UBO_FREE_SAFE(wpd->vldata->cavity_sample_ubo);
+ DRW_TEXTURE_FREE_SAFE(wpd->vldata->cavity_jitter_tx);
+ }
+
+ if (wpd->vldata->cavity_sample_ubo == NULL) {
+ float *samples = create_disk_samples(cavity_sample_count_single_iteration,
+ max_ii(1, wpd->taa_sample_len));
+ wpd->vldata->cavity_jitter_tx = create_jitter_texture(cavity_sample_count);
+ /* NOTE: Uniform buffer needs to always be filled to be valid. */
+ wpd->vldata->cavity_sample_ubo = DRW_uniformbuffer_create(
+ sizeof(float[4]) * CAVITY_MAX_SAMPLES, samples);
+ wpd->vldata->cavity_sample_count = cavity_sample_count;
+ MEM_freeN(samples);
+ }
+}
+
+void workbench_cavity_cache_init(WORKBENCH_Data *data)
+{
+ WORKBENCH_PassList *psl = data->psl;
+ WORKBENCH_PrivateData *wpd = data->stl->wpd;
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+ struct GPUShader *sh;
+ DRWShadingGroup *grp;
+
+ if (CAVITY_ENABLED(wpd)) {
+ workbench_cavity_samples_ubo_ensure(wpd);
+
+ int state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_MUL;
+ DRW_PASS_CREATE(psl->cavity_ps, state);
+
+ sh = workbench_shader_cavity_get(SSAO_ENABLED(wpd), CURVATURE_ENABLED(wpd));
+
+ grp = DRW_shgroup_create(sh, psl->cavity_ps);
+ DRW_shgroup_uniform_texture(grp, "normalBuffer", wpd->normal_buffer_tx);
+ DRW_shgroup_uniform_block(grp, "samples_block", wpd->vldata->cavity_sample_ubo);
+ DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo);
+
+ if (SSAO_ENABLED(wpd)) {
+ DRW_shgroup_uniform_texture(grp, "depthBuffer", dtxl->depth);
+ DRW_shgroup_uniform_texture(grp, "cavityJitter", wpd->vldata->cavity_jitter_tx);
+ }
+ if (CURVATURE_ENABLED(wpd)) {
+ DRW_shgroup_uniform_texture(grp, "objectIdBuffer", wpd->object_id_tx);
+ }
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+ }
+ else {
+ psl->cavity_ps = NULL;
+ }
+}
diff --git a/source/blender/draw/engines/workbench/workbench_effect_dof.c b/source/blender/draw/engines/workbench/workbench_effect_dof.c
index ae3e2218463..8aa37c6b9fc 100644
--- a/source/blender/draw/engines/workbench/workbench_effect_dof.c
+++ b/source/blender/draw/engines/workbench/workbench_effect_dof.c
@@ -18,6 +18,17 @@
/** \file
* \ingroup draw_engine
+ *
+ * Depth of Field Effect:
+ *
+ * We use a gather approach by sampling a lowres version of the color buffer.
+ * The process can be summarized like this:
+ * - downsample the color buffer using a COC (Circle of Confusion) aware downsample algo.
+ * - do a gather pass using the COC computed in the previous pass.
+ * - do a median filter to reduce noise amount.
+ * - composite on top of main color buffer.
+ *
+ * This is done after all passes and affects every surfaces.
*/
#include "workbench_private.h"
@@ -27,24 +38,6 @@
#include "DNA_camera_types.h"
-/* *********** STATIC *********** */
-static struct {
- struct GPUShader *effect_dof_prepare_sh;
- struct GPUShader *effect_dof_downsample_sh;
- struct GPUShader *effect_dof_flatten_v_sh;
- struct GPUShader *effect_dof_flatten_h_sh;
- struct GPUShader *effect_dof_dilate_v_sh;
- struct GPUShader *effect_dof_dilate_h_sh;
- struct GPUShader *effect_dof_blur1_sh;
- struct GPUShader *effect_dof_blur2_sh;
- struct GPUShader *effect_dof_resolve_sh;
-} e_data = {NULL};
-
-/* Shaders */
-extern char datatoc_workbench_effect_dof_frag_glsl[];
-
-/* *********** Functions *********** */
-
/**
* Transform [-1..1] square to unit circle.
*/
@@ -130,52 +123,40 @@ static void workbench_dof_setup_samples(struct GPUUniformBuffer **ubo,
DRW_uniformbuffer_update(*ubo, *data);
}
-void workbench_dof_engine_init(WORKBENCH_Data *vedata, Object *camera)
+void workbench_dof_engine_init(WORKBENCH_Data *vedata)
{
WORKBENCH_TextureList *txl = vedata->txl;
WORKBENCH_StorageList *stl = vedata->stl;
- WORKBENCH_PrivateData *wpd = stl->g_data;
+ WORKBENCH_PrivateData *wpd = stl->wpd;
WORKBENCH_FramebufferList *fbl = vedata->fbl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ RegionView3D *rv3d = draw_ctx->rv3d;
+ View3D *v3d = draw_ctx->v3d;
+ Scene *scene = draw_ctx->scene;
+ Object *camera;
+
+ if (v3d && rv3d) {
+ camera = (rv3d->persp == RV3D_CAMOB) ? v3d->camera : NULL;
+ }
+ else {
+ camera = scene->camera;
+ }
+
Camera *cam = camera != NULL ? camera->data : NULL;
if ((wpd->shading.flag & V3D_SHADING_DEPTH_OF_FIELD) == 0 || (cam == NULL) ||
((cam->dof.flag & CAM_DOF_ENABLED) == 0)) {
wpd->dof_enabled = false;
- return;
- }
-
- if (e_data.effect_dof_prepare_sh == NULL) {
- e_data.effect_dof_prepare_sh = DRW_shader_create_fullscreen(
- datatoc_workbench_effect_dof_frag_glsl, "#define PREPARE\n");
-
- e_data.effect_dof_downsample_sh = DRW_shader_create_fullscreen(
- datatoc_workbench_effect_dof_frag_glsl, "#define DOWNSAMPLE\n");
-
- e_data.effect_dof_flatten_v_sh = DRW_shader_create_fullscreen(
- datatoc_workbench_effect_dof_frag_glsl, "#define FLATTEN_VERTICAL\n");
-
- e_data.effect_dof_flatten_h_sh = DRW_shader_create_fullscreen(
- datatoc_workbench_effect_dof_frag_glsl, "#define FLATTEN_HORIZONTAL\n");
-
- e_data.effect_dof_dilate_v_sh = DRW_shader_create_fullscreen(
- datatoc_workbench_effect_dof_frag_glsl, "#define DILATE_VERTICAL\n");
-
- e_data.effect_dof_dilate_h_sh = DRW_shader_create_fullscreen(
- datatoc_workbench_effect_dof_frag_glsl, "#define DILATE_HORIZONTAL\n");
- e_data.effect_dof_blur1_sh = DRW_shader_create_fullscreen(
- datatoc_workbench_effect_dof_frag_glsl, "#define BLUR1\n");
-
- e_data.effect_dof_blur2_sh = DRW_shader_create_fullscreen(
- datatoc_workbench_effect_dof_frag_glsl, "#define BLUR2\n");
-
- e_data.effect_dof_resolve_sh = DRW_shader_create_fullscreen(
- datatoc_workbench_effect_dof_frag_glsl, "#define RESOLVE\n");
+ /* Cleanup. */
+ DRW_TEXTURE_FREE_SAFE(txl->dof_source_tx);
+ DRW_TEXTURE_FREE_SAFE(txl->coc_halfres_tx);
+ return;
}
const float *full_size = DRW_viewport_size_get();
int size[2] = {max_ii(1, (int)full_size[0] / 2), max_ii(1, (int)full_size[1] / 2)};
-#if 0
+#if 0 /* TODO(fclem) finish COC min_max optimisation */
/* NOTE: We Ceil here in order to not miss any edge texel if using a NPO2 texture. */
int shrink_h_size[2] = {ceilf(size[0] / 8.0f), size[1]};
int shrink_w_size[2] = {shrink_h_size[0], ceilf(size[1] / 8.0f)};
@@ -186,14 +167,14 @@ void workbench_dof_engine_init(WORKBENCH_Data *vedata, Object *camera)
DRW_texture_ensure_2d(
&txl->coc_halfres_tx, size[0], size[1], GPU_RG8, DRW_TEX_FILTER | DRW_TEX_MIPMAP);
wpd->dof_blur_tx = DRW_texture_pool_query_2d(
- size[0], size[1], GPU_RGBA16F, &draw_engine_workbench_solid);
-#if 0
+ size[0], size[1], GPU_RGBA16F, &draw_engine_workbench);
+#if 0 /* TODO(fclem) finish COC min_max optimisation */
wpd->coc_temp_tx = DRW_texture_pool_query_2d(
- shrink_h_size[0], shrink_h_size[1], GPU_RG8, &draw_engine_workbench_solid);
+ shrink_h_size[0], shrink_h_size[1], GPU_RG8, &draw_engine_workbench);
wpd->coc_tiles_tx[0] = DRW_texture_pool_query_2d(
- shrink_w_size[0], shrink_w_size[1], GPU_RG8, &draw_engine_workbench_solid);
+ shrink_w_size[0], shrink_w_size[1], GPU_RG8, &draw_engine_workbench);
wpd->coc_tiles_tx[1] = DRW_texture_pool_query_2d(
- shrink_w_size[0], shrink_w_size[1], GPU_RG8, &draw_engine_workbench_solid);
+ shrink_w_size[0], shrink_w_size[1], GPU_RG8, &draw_engine_workbench);
#endif
GPU_framebuffer_ensure_config(&fbl->dof_downsample_fb,
@@ -202,7 +183,7 @@ void workbench_dof_engine_init(WORKBENCH_Data *vedata, Object *camera)
GPU_ATTACHMENT_TEXTURE(txl->dof_source_tx),
GPU_ATTACHMENT_TEXTURE(txl->coc_halfres_tx),
});
-#if 0
+#if 0 /* TODO(fclem) finish COC min_max optimisation */
GPU_framebuffer_ensure_config(&fbl->dof_coc_tile_h_fb,
{
GPU_ATTACHMENT_NONE,
@@ -231,11 +212,7 @@ void workbench_dof_engine_init(WORKBENCH_Data *vedata, Object *camera)
});
{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- RegionView3D *rv3d = draw_ctx->rv3d;
-
/* Parameters */
- /* TODO UI Options */
float fstop = cam->dof.aperture_fstop;
float sensor = BKE_camera_sensor_size(cam->sensor_fit, cam->sensor_x, cam->sensor_y);
float focus_dist = BKE_camera_object_dof_distance(camera);
@@ -263,128 +240,125 @@ void workbench_dof_engine_init(WORKBENCH_Data *vedata, Object *camera)
float rotation = cam->dof.aperture_rotation;
float ratio = 1.0f / cam->dof.aperture_ratio;
- if (wpd->dof_ubo == NULL || blades != wpd->dof_blades || rotation != wpd->dof_rotation ||
- ratio != wpd->dof_ratio) {
+ if (wpd->vldata->dof_sample_ubo == NULL || blades != wpd->dof_blades ||
+ rotation != wpd->dof_rotation || ratio != wpd->dof_ratio) {
wpd->dof_blades = blades;
wpd->dof_rotation = rotation;
wpd->dof_ratio = ratio;
- workbench_dof_setup_samples(&wpd->dof_ubo, &stl->dof_ubo_data, blades, rotation, ratio);
+ workbench_dof_setup_samples(
+ &wpd->vldata->dof_sample_ubo, &stl->dof_ubo_data, blades, rotation, ratio);
}
}
wpd->dof_enabled = true;
}
-void workbench_dof_create_pass(WORKBENCH_Data *vedata,
- GPUTexture **dof_input,
- GPUTexture *noise_tex)
+void workbench_dof_cache_init(WORKBENCH_Data *vedata)
{
WORKBENCH_PassList *psl = vedata->psl;
WORKBENCH_TextureList *txl = vedata->txl;
WORKBENCH_StorageList *stl = vedata->stl;
- WORKBENCH_PrivateData *wpd = stl->g_data;
- struct GPUBatch *quad = DRW_cache_fullscreen_quad_get();
+ WORKBENCH_PrivateData *wpd = stl->wpd;
if (!wpd->dof_enabled) {
return;
}
- DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+ GPUShader *prepare_sh, *downsample_sh, *blur1_sh, *blur2_sh, *resolve_sh;
+ workbench_shader_depth_of_field_get(
+ &prepare_sh, &downsample_sh, &blur1_sh, &blur2_sh, &resolve_sh);
- psl->dof_down_ps = DRW_pass_create("DoF DownSample", DRW_STATE_WRITE_COLOR);
- psl->dof_down2_ps = DRW_pass_create("DoF DownSample", DRW_STATE_WRITE_COLOR);
- psl->dof_flatten_h_ps = DRW_pass_create("DoF Flatten Coc H", DRW_STATE_WRITE_COLOR);
- psl->dof_flatten_v_ps = DRW_pass_create("DoF Flatten Coc V", DRW_STATE_WRITE_COLOR);
- psl->dof_dilate_h_ps = DRW_pass_create("DoF Dilate Coc H", DRW_STATE_WRITE_COLOR);
- psl->dof_dilate_v_ps = DRW_pass_create("DoF Dilate Coc V", DRW_STATE_WRITE_COLOR);
- psl->dof_blur1_ps = DRW_pass_create("DoF Blur 1", DRW_STATE_WRITE_COLOR);
- psl->dof_blur2_ps = DRW_pass_create("DoF Blur 2", DRW_STATE_WRITE_COLOR);
- psl->dof_resolve_ps = DRW_pass_create("DoF Resolve",
- DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM);
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
{
- DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_prepare_sh, psl->dof_down_ps);
- DRW_shgroup_uniform_texture_ref(grp, "sceneColorTex", dof_input);
+ psl->dof_down_ps = DRW_pass_create("DoF DownSample", DRW_STATE_WRITE_COLOR);
+
+ DRWShadingGroup *grp = DRW_shgroup_create(prepare_sh, psl->dof_down_ps);
+ DRW_shgroup_uniform_texture(grp, "sceneColorTex", dtxl->color);
DRW_shgroup_uniform_texture(grp, "sceneDepthTex", dtxl->depth);
DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1);
DRW_shgroup_uniform_vec3(grp, "dofParams", &wpd->dof_aperturesize, 1);
DRW_shgroup_uniform_vec2(grp, "nearFar", wpd->dof_near_far, 1);
- DRW_shgroup_call(grp, quad, NULL);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
}
{
- DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_downsample_sh, psl->dof_down2_ps);
+ psl->dof_down2_ps = DRW_pass_create("DoF DownSample", DRW_STATE_WRITE_COLOR);
+
+ DRWShadingGroup *grp = DRW_shgroup_create(downsample_sh, psl->dof_down2_ps);
DRW_shgroup_uniform_texture(grp, "sceneColorTex", txl->dof_source_tx);
DRW_shgroup_uniform_texture(grp, "inputCocTex", txl->coc_halfres_tx);
- DRW_shgroup_call(grp, quad, NULL);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
}
-#if 0
+#if 0 /* TODO(fclem) finish COC min_max optimization */
{
- DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_flatten_h_sh,
- psl->dof_flatten_h_ps);
+ psl->dof_flatten_h_ps = DRW_pass_create("DoF Flatten Coc H", DRW_STATE_WRITE_COLOR);
+
+ DRWShadingGroup *grp = DRW_shgroup_create(flatten_h_sh, psl->dof_flatten_h_ps);
DRW_shgroup_uniform_texture(grp, "inputCocTex", txl->coc_halfres_tx);
- DRW_shgroup_call(grp, quad, NULL);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
}
{
- DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_flatten_v_sh,
- psl->dof_flatten_v_ps);
+ psl->dof_flatten_v_ps = DRW_pass_create("DoF Flatten Coc V", DRW_STATE_WRITE_COLOR);
+
+ DRWShadingGroup *grp = DRW_shgroup_create(flatten_v_sh, psl->dof_flatten_v_ps);
DRW_shgroup_uniform_texture(grp, "inputCocTex", wpd->coc_temp_tx);
- DRW_shgroup_call(grp, quad, NULL);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
}
{
- DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_dilate_v_sh, psl->dof_dilate_v_ps);
+ psl->dof_dilate_h_ps = DRW_pass_create("DoF Dilate Coc H", DRW_STATE_WRITE_COLOR);
+
+ DRWShadingGroup *grp = DRW_shgroup_create(dilate_v_sh, psl->dof_dilate_v_ps);
DRW_shgroup_uniform_texture(grp, "inputCocTex", wpd->coc_tiles_tx[0]);
- DRW_shgroup_call(grp, quad, NULL);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
}
{
- DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_dilate_h_sh, psl->dof_dilate_h_ps);
+ psl->dof_dilate_v_ps = DRW_pass_create("DoF Dilate Coc V", DRW_STATE_WRITE_COLOR);
+
+ DRWShadingGroup *grp = DRW_shgroup_create(dilate_h_sh, psl->dof_dilate_h_ps);
DRW_shgroup_uniform_texture(grp, "inputCocTex", wpd->coc_tiles_tx[1]);
- DRW_shgroup_call(grp, quad, NULL);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
}
#endif
{
- float offset = stl->effects->jitter_index /
- (float)workbench_taa_calculate_num_iterations(vedata);
- DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_blur1_sh, psl->dof_blur1_ps);
- DRW_shgroup_uniform_block(grp, "dofSamplesBlock", wpd->dof_ubo);
- DRW_shgroup_uniform_texture(grp, "noiseTex", noise_tex);
+ psl->dof_blur1_ps = DRW_pass_create("DoF Blur 1", DRW_STATE_WRITE_COLOR);
+
+ /* We reuse the same noise texture. Ensure it is up to date. */
+ workbench_cavity_samples_ubo_ensure(wpd);
+
+ float offset = wpd->taa_sample / wpd->taa_sample_len;
+ DRWShadingGroup *grp = DRW_shgroup_create(blur1_sh, psl->dof_blur1_ps);
+ DRW_shgroup_uniform_block(grp, "dofSamplesBlock", wpd->vldata->dof_sample_ubo);
+ DRW_shgroup_uniform_texture(grp, "noiseTex", wpd->vldata->cavity_jitter_tx);
DRW_shgroup_uniform_texture(grp, "inputCocTex", txl->coc_halfres_tx);
DRW_shgroup_uniform_texture(grp, "halfResColorTex", txl->dof_source_tx);
DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1);
DRW_shgroup_uniform_float_copy(grp, "noiseOffset", offset);
- DRW_shgroup_call(grp, quad, NULL);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
}
{
- DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_blur2_sh, psl->dof_blur2_ps);
+ psl->dof_blur2_ps = DRW_pass_create("DoF Blur 2", DRW_STATE_WRITE_COLOR);
+
+ DRWShadingGroup *grp = DRW_shgroup_create(blur2_sh, psl->dof_blur2_ps);
DRW_shgroup_uniform_texture(grp, "inputCocTex", txl->coc_halfres_tx);
DRW_shgroup_uniform_texture(grp, "blurTex", wpd->dof_blur_tx);
DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1);
- DRW_shgroup_call(grp, quad, NULL);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
}
{
- DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_resolve_sh, psl->dof_resolve_ps);
+ psl->dof_resolve_ps = DRW_pass_create("DoF Resolve",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM);
+
+ DRWShadingGroup *grp = DRW_shgroup_create(resolve_sh, psl->dof_resolve_ps);
DRW_shgroup_uniform_texture(grp, "halfResColorTex", txl->dof_source_tx);
DRW_shgroup_uniform_texture(grp, "sceneDepthTex", dtxl->depth);
DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1);
DRW_shgroup_uniform_vec3(grp, "dofParams", &wpd->dof_aperturesize, 1);
DRW_shgroup_uniform_vec2(grp, "nearFar", wpd->dof_near_far, 1);
- DRW_shgroup_call(grp, quad, NULL);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
}
}
-void workbench_dof_engine_free(void)
-{
- DRW_SHADER_FREE_SAFE(e_data.effect_dof_prepare_sh);
- DRW_SHADER_FREE_SAFE(e_data.effect_dof_downsample_sh);
- DRW_SHADER_FREE_SAFE(e_data.effect_dof_flatten_v_sh);
- DRW_SHADER_FREE_SAFE(e_data.effect_dof_flatten_h_sh);
- DRW_SHADER_FREE_SAFE(e_data.effect_dof_dilate_v_sh);
- DRW_SHADER_FREE_SAFE(e_data.effect_dof_dilate_h_sh);
- DRW_SHADER_FREE_SAFE(e_data.effect_dof_blur1_sh);
- DRW_SHADER_FREE_SAFE(e_data.effect_dof_blur2_sh);
- DRW_SHADER_FREE_SAFE(e_data.effect_dof_resolve_sh);
-}
-
static void workbench_dof_downsample_level(void *userData, int UNUSED(level))
{
WORKBENCH_PassList *psl = (WORKBENCH_PassList *)userData;
@@ -396,7 +370,8 @@ void workbench_dof_draw_pass(WORKBENCH_Data *vedata)
WORKBENCH_FramebufferList *fbl = vedata->fbl;
WORKBENCH_StorageList *stl = vedata->stl;
WORKBENCH_PassList *psl = vedata->psl;
- WORKBENCH_PrivateData *wpd = stl->g_data;
+ WORKBENCH_PrivateData *wpd = stl->wpd;
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
if (!wpd->dof_enabled) {
return;
@@ -410,7 +385,7 @@ void workbench_dof_draw_pass(WORKBENCH_Data *vedata)
GPU_framebuffer_recursive_downsample(
fbl->dof_downsample_fb, 2, workbench_dof_downsample_level, psl);
-#if 0
+#if 0 /* TODO(fclem) finish COC min_max optimization */
GPU_framebuffer_bind(fbl->dof_coc_tile_h_fb);
DRW_draw_pass(psl->dof_flatten_h_ps);
@@ -430,7 +405,7 @@ void workbench_dof_draw_pass(WORKBENCH_Data *vedata)
GPU_framebuffer_bind(fbl->dof_blur2_fb);
DRW_draw_pass(psl->dof_blur2_ps);
- GPU_framebuffer_bind(fbl->color_only_fb);
+ GPU_framebuffer_bind(dfbl->color_only_fb);
DRW_draw_pass(psl->dof_resolve_ps);
DRW_stats_group_end();
diff --git a/source/blender/draw/engines/workbench/workbench_effect_fxaa.c b/source/blender/draw/engines/workbench/workbench_effect_fxaa.c
deleted file mode 100644
index 6e3bf1658ab..00000000000
--- a/source/blender/draw/engines/workbench/workbench_effect_fxaa.c
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Copyright 2016, Blender Foundation.
- */
-
-/** \file
- * \ingroup draw_engine
- */
-#include "workbench_private.h"
-
-/* *********** STATIC *********** */
-static struct {
- struct GPUShader *effect_fxaa_sh;
-} e_data = {NULL};
-
-/* Shaders */
-extern char datatoc_common_fxaa_lib_glsl[];
-extern char datatoc_common_fullscreen_vert_glsl[];
-extern char datatoc_workbench_effect_fxaa_frag_glsl[];
-
-/* *********** Functions *********** */
-void workbench_fxaa_engine_init(void)
-{
- if (e_data.effect_fxaa_sh == NULL) {
- e_data.effect_fxaa_sh = DRW_shader_create_with_lib(datatoc_common_fullscreen_vert_glsl,
- NULL,
- datatoc_workbench_effect_fxaa_frag_glsl,
- datatoc_common_fxaa_lib_glsl,
- NULL);
- }
-}
-
-DRWPass *workbench_fxaa_create_pass(GPUTexture **color_buffer_tx)
-{
- DRWPass *pass = DRW_pass_create("Effect FXAA", DRW_STATE_WRITE_COLOR);
- DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_fxaa_sh, pass);
- DRW_shgroup_uniform_texture_ref(grp, "colorBuffer", color_buffer_tx);
- DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1);
- DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL);
- return pass;
-}
-
-void workbench_fxaa_engine_free(void)
-{
- DRW_SHADER_FREE_SAFE(e_data.effect_fxaa_sh);
-}
diff --git a/source/blender/draw/engines/workbench/workbench_effect_outline.c b/source/blender/draw/engines/workbench/workbench_effect_outline.c
new file mode 100644
index 00000000000..d1bc6b6c435
--- /dev/null
+++ b/source/blender/draw/engines/workbench/workbench_effect_outline.c
@@ -0,0 +1,55 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2020, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ *
+ * Outline Effect:
+ *
+ * Simple effect that just samples an object id buffer to detect objects outlines.
+ */
+
+#include "DRW_render.h"
+
+#include "workbench_engine.h"
+#include "workbench_private.h"
+
+void workbench_outline_cache_init(WORKBENCH_Data *data)
+{
+ WORKBENCH_PassList *psl = data->psl;
+ WORKBENCH_PrivateData *wpd = data->stl->wpd;
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+ struct GPUShader *sh;
+ DRWShadingGroup *grp;
+
+ if (OBJECT_OUTLINE_ENABLED(wpd)) {
+ int state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL;
+ DRW_PASS_CREATE(psl->outline_ps, state);
+
+ sh = workbench_shader_outline_get();
+
+ grp = DRW_shgroup_create(sh, psl->outline_ps);
+ DRW_shgroup_uniform_texture(grp, "objectIdBuffer", wpd->object_id_tx);
+ DRW_shgroup_uniform_texture(grp, "depthBuffer", dtxl->depth);
+ DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+ }
+ else {
+ psl->outline_ps = NULL;
+ }
+}
diff --git a/source/blender/draw/engines/workbench/workbench_effect_taa.c b/source/blender/draw/engines/workbench/workbench_effect_taa.c
deleted file mode 100644
index e2864f8c832..00000000000
--- a/source/blender/draw/engines/workbench/workbench_effect_taa.c
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Copyright 2016, Blender Foundation.
- */
-
-/** \file
- * \ingroup draw_engine
- */
-
-#include "workbench_private.h"
-#include "BLI_jitter_2d.h"
-
-static struct {
- struct GPUShader *effect_taa_sh;
- float jitter_5[5][2];
- float jitter_8[8][2];
- float jitter_11[11][2];
- float jitter_16[16][2];
- float jitter_32[32][2];
-} e_data = {NULL};
-
-extern char datatoc_workbench_effect_taa_frag_glsl[];
-
-static void workbench_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 furtest 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 workbench_taa_jitter_init(void)
-{
- workbench_taa_jitter_init_order(e_data.jitter_5, 5);
- workbench_taa_jitter_init_order(e_data.jitter_8, 8);
- workbench_taa_jitter_init_order(e_data.jitter_11, 11);
- workbench_taa_jitter_init_order(e_data.jitter_16, 16);
- workbench_taa_jitter_init_order(e_data.jitter_32, 32);
-}
-
-int workbench_taa_calculate_num_iterations(WORKBENCH_Data *vedata)
-{
- WORKBENCH_StorageList *stl = vedata->stl;
- WORKBENCH_PrivateData *wpd = stl->g_data;
- const Scene *scene = DRW_context_state_get()->scene;
- int result;
- if (workbench_is_taa_enabled(wpd)) {
- if (DRW_state_is_image_render()) {
- const DRWContextState *draw_ctx = DRW_context_state_get();
- if (draw_ctx->v3d) {
- result = scene->display.viewport_aa;
- }
- else {
- result = scene->display.render_aa;
- }
- }
- else {
- result = wpd->preferences->viewport_aa;
- }
- }
- else {
- /* when no TAA is disabled return 1 to render a single sample
- * see `workbench_render.c` */
- result = 1;
- }
- return result;
-}
-
-int workbench_num_viewport_rendering_iterations(WORKBENCH_Data *UNUSED(vedata))
-{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- const Scene *scene = draw_ctx->scene;
- int result = DRW_state_is_image_render() ? scene->display.viewport_aa : 1;
- result = MAX2(result, 1);
- return result;
-}
-
-void workbench_taa_engine_init(WORKBENCH_Data *vedata)
-{
- WORKBENCH_EffectInfo *effect_info = vedata->stl->effects;
- const DRWContextState *draw_ctx = DRW_context_state_get();
- RegionView3D *rv3d = draw_ctx->rv3d;
-
- if (e_data.effect_taa_sh == NULL) {
- e_data.effect_taa_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_taa_frag_glsl,
- NULL);
- workbench_taa_jitter_init();
- }
-
- effect_info->view = NULL;
-
- /* reset complete drawing when navigating. */
- if (effect_info->jitter_index != 0) {
- if (rv3d && rv3d->rflag & (RV3D_NAVIGATING | RV3D_PAINTING)) {
- effect_info->jitter_index = 0;
- }
- }
-
- if (effect_info->view_updated) {
- effect_info->jitter_index = 0;
- effect_info->view_updated = false;
- }
-
- {
- float persmat[4][4];
- DRW_view_persmat_get(NULL, persmat, false);
- if (!equals_m4m4(persmat, effect_info->last_mat)) {
- copy_m4_m4(effect_info->last_mat, persmat);
- effect_info->jitter_index = 0;
- }
- }
-}
-
-void workbench_taa_engine_free(void)
-{
- DRW_SHADER_FREE_SAFE(e_data.effect_taa_sh);
-}
-
-DRWPass *workbench_taa_create_pass(WORKBENCH_Data *vedata, GPUTexture **color_buffer_tx)
-{
- WORKBENCH_StorageList *stl = vedata->stl;
- WORKBENCH_TextureList *txl = vedata->txl;
- WORKBENCH_EffectInfo *effect_info = stl->effects;
- WORKBENCH_FramebufferList *fbl = vedata->fbl;
- const WORKBENCH_PrivateData *wpd = stl->g_data;
-
- {
- const eGPUTextureFormat hist_buffer_format = workbench_color_texture_format(wpd);
- DRW_texture_ensure_fullscreen_2d(&txl->history_buffer_tx, hist_buffer_format, 0);
- DRW_texture_ensure_fullscreen_2d(&txl->depth_buffer_tx, GPU_DEPTH24_STENCIL8, 0);
- }
-
- {
- GPU_framebuffer_ensure_config(&fbl->effect_taa_fb,
- {
- GPU_ATTACHMENT_NONE,
- GPU_ATTACHMENT_TEXTURE(txl->history_buffer_tx),
- });
- GPU_framebuffer_ensure_config(&fbl->depth_buffer_fb,
- {
- GPU_ATTACHMENT_TEXTURE(txl->depth_buffer_tx),
- });
- }
-
- DRWPass *pass = DRW_pass_create("Effect TAA", DRW_STATE_WRITE_COLOR);
- DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_taa_sh, pass);
- DRW_shgroup_uniform_texture_ref(grp, "colorBuffer", color_buffer_tx);
- DRW_shgroup_uniform_texture_ref(grp, "historyBuffer", &txl->history_buffer_tx);
- DRW_shgroup_uniform_float(grp, "mixFactor", &effect_info->taa_mix_factor, 1);
- DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL);
-
- return pass;
-}
-
-void workbench_taa_draw_scene_start(WORKBENCH_Data *vedata)
-{
- WORKBENCH_StorageList *stl = vedata->stl;
- WORKBENCH_EffectInfo *effect_info = stl->effects;
- WORKBENCH_PrivateData *wpd = stl->g_data;
-
- const float *viewport_size = DRW_viewport_size_get();
- const DRWView *default_view = DRW_view_default_get();
- int num_samples = 8;
- float(*samples)[2];
-
- num_samples = workbench_taa_calculate_num_iterations(vedata);
- switch (num_samples) {
- default:
- case 5:
- samples = e_data.jitter_5;
- break;
- case 8:
- samples = e_data.jitter_8;
- break;
- case 11:
- samples = e_data.jitter_11;
- break;
- case 16:
- samples = e_data.jitter_16;
- break;
- case 32:
- samples = e_data.jitter_32;
- break;
- }
-
- const int jitter_index = effect_info->jitter_index;
- const float *transform_offset = samples[jitter_index];
- effect_info->taa_mix_factor = 1.0f / (jitter_index + 1);
- effect_info->jitter_index = (jitter_index + 1) % num_samples;
- /* Copy jitter index to Cavity iteration */
- wpd->ssao_params[3] = effect_info->jitter_index;
-
- /* 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 (effect_info->view) {
- /* When rendering just update the view. This avoids recomputing the culling. */
- DRW_view_update_sub(effect_info->view, viewmat, winmat);
- }
- else {
- /* TAA is not making a big change to the matrices.
- * Reuse the main view culling by creating a subview. */
- effect_info->view = DRW_view_create_sub(default_view, viewmat, winmat);
- }
- DRW_view_set_active(effect_info->view);
-}
-
-void workbench_taa_draw_scene_end(WORKBENCH_Data *vedata)
-{
- /*
- * If first frame then the offset is 0.0 and its depth is the depth buffer to use
- * for the rest of the draw engines. We store it in a persistent buffer.
- *
- * If it is not the first frame we copy the persistent buffer back to the
- * default depth buffer
- */
- const WORKBENCH_StorageList *stl = vedata->stl;
- const WORKBENCH_FramebufferList *fbl = vedata->fbl;
- const DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
- WORKBENCH_EffectInfo *effect_info = stl->effects;
-
- if (effect_info->jitter_index == 1) {
- GPU_framebuffer_blit(dfbl->depth_only_fb, 0, fbl->depth_buffer_fb, 0, GPU_DEPTH_BIT);
- }
- else {
- GPU_framebuffer_blit(fbl->depth_buffer_fb, 0, dfbl->depth_only_fb, 0, GPU_DEPTH_BIT);
- }
-
- GPU_framebuffer_blit(dfbl->color_only_fb, 0, fbl->effect_taa_fb, 0, GPU_COLOR_BIT);
-
- if (!DRW_state_is_image_render()) {
- DRW_view_set_active(NULL);
- }
-
- if (effect_info->jitter_index != 0 && !DRW_state_is_image_render()) {
- DRW_viewport_request_redraw();
- }
-}
-
-void workbench_taa_view_updated(WORKBENCH_Data *vedata)
-{
- WORKBENCH_StorageList *stl = vedata->stl;
- if (stl) {
- WORKBENCH_EffectInfo *effect_info = stl->effects;
- if (effect_info) {
- effect_info->view_updated = true;
- }
- }
-}
diff --git a/source/blender/draw/engines/workbench/workbench_engine.c b/source/blender/draw/engines/workbench/workbench_engine.c
index 62a192bbb25..b91ca7cf070 100644
--- a/source/blender/draw/engines/workbench/workbench_engine.c
+++ b/source/blender/draw/engines/workbench/workbench_engine.c
@@ -19,18 +19,557 @@
/** \file
* \ingroup draw_engine
*
- * Simple engine for drawing color and/or depth.
- * When we only need simple flat shaders.
+ * Workbench Engine:
+ *
+ * Optimized engine to draw the working viewport with solid and transparent geometry.
*/
#include "DRW_render.h"
+#include "BLI_alloca.h"
+
+#include "BKE_modifier.h"
+#include "BKE_object.h"
+#include "BKE_paint.h"
+#include "BKE_particle.h"
+
+#include "DNA_image_types.h"
+#include "DNA_fluid_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_node_types.h"
+
#include "workbench_engine.h"
#include "workbench_private.h"
#define WORKBENCH_ENGINE "BLENDER_WORKBENCH"
-/* Note: currently unused, we may want to register so we can see this when debugging the view. */
+void workbench_engine_init(void *ved)
+{
+ WORKBENCH_Data *vedata = ved;
+ WORKBENCH_StorageList *stl = vedata->stl;
+ WORKBENCH_TextureList *txl = vedata->txl;
+
+ workbench_shader_library_ensure();
+
+ if (!stl->wpd) {
+ stl->wpd = MEM_callocN(sizeof(*stl->wpd), __func__);
+ stl->wpd->view_updated = true;
+ }
+
+ WORKBENCH_PrivateData *wpd = stl->wpd;
+ workbench_private_data_init(wpd);
+ workbench_update_world_ubo(wpd);
+
+ if (txl->dummy_image_tx == NULL) {
+ float fpixel[4] = {1.0f, 0.0f, 1.0f, 1.0f};
+ txl->dummy_image_tx = DRW_texture_create_2d(1, 1, GPU_RGBA8, 0, fpixel);
+ }
+ wpd->dummy_image_tx = txl->dummy_image_tx;
+
+ if (OBJECT_ID_PASS_ENABLED(wpd)) {
+ wpd->object_id_tx = DRW_texture_pool_query_fullscreen(GPU_R16UI, &draw_engine_workbench);
+ }
+ else {
+ /* Dont free because it's a pool texture. */
+ wpd->object_id_tx = NULL;
+ }
+
+ workbench_opaque_engine_init(vedata);
+ workbench_transparent_engine_init(vedata);
+ workbench_dof_engine_init(vedata);
+ workbench_antialiasing_engine_init(vedata);
+ workbench_volume_engine_init(vedata);
+}
+
+void workbench_cache_init(void *ved)
+{
+ WORKBENCH_Data *vedata = ved;
+
+ workbench_opaque_cache_init(vedata);
+ workbench_transparent_cache_init(vedata);
+ workbench_shadow_cache_init(vedata);
+ workbench_cavity_cache_init(vedata);
+ workbench_outline_cache_init(vedata);
+ workbench_dof_cache_init(vedata);
+ workbench_antialiasing_cache_init(vedata);
+ workbench_volume_cache_init(vedata);
+}
+
+/* TODO(fclem) DRW_cache_object_surface_material_get needs a refactor to allow passing NULL
+ * instead of gpumat_array. Avoiding all this boilerplate code. */
+static struct GPUBatch **workbench_object_surface_material_get(Object *ob)
+{
+ const int materials_len = DRW_cache_object_material_count_get(ob);
+ struct GPUMaterial **gpumat_array = BLI_array_alloca(gpumat_array, materials_len);
+ memset(gpumat_array, 0, sizeof(*gpumat_array) * materials_len);
+
+ return DRW_cache_object_surface_material_get(ob, gpumat_array, materials_len);
+}
+
+static void workbench_cache_sculpt_populate(WORKBENCH_PrivateData *wpd,
+ Object *ob,
+ eV3DShadingColorType color_type)
+{
+ const bool use_vcol = ELEM(color_type, V3D_SHADING_VERTEX_COLOR);
+ const bool use_single_drawcall = !ELEM(color_type, V3D_SHADING_MATERIAL_COLOR);
+ BLI_assert(wpd->shading.color_type != V3D_SHADING_TEXTURE_COLOR);
+
+ if (use_single_drawcall) {
+ 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, NULL);
+ }
+ DRW_shgroup_call_sculpt_with_materials(shgrps, ob, false);
+ }
+}
+
+static void workbench_cache_texpaint_populate(WORKBENCH_PrivateData *wpd, Object *ob)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const Scene *scene = draw_ctx->scene;
+ const ImagePaintSettings *imapaint = &scene->toolsettings->imapaint;
+ const bool use_single_drawcall = imapaint->mode == IMAGEPAINT_MODE_IMAGE;
+
+ if (use_single_drawcall) {
+ struct GPUBatch *geom = DRW_cache_mesh_surface_texpaint_single_get(ob);
+ if (geom) {
+ Image *ima = imapaint->canvas;
+ int interp = (imapaint->interp == IMAGEPAINT_INTERP_LINEAR) ? SHD_INTERP_LINEAR :
+ SHD_INTERP_CLOSEST;
+
+ DRWShadingGroup *grp = workbench_image_setup(wpd, ob, 0, ima, NULL, interp);
+ DRW_shgroup_call(grp, geom, ob);
+ }
+ }
+ else {
+ struct GPUBatch **geoms = DRW_cache_mesh_surface_texpaint_get(ob);
+ 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);
+ DRW_shgroup_call(grp, geoms[i], ob);
+ }
+ }
+ }
+}
+
+static void workbench_cache_common_populate(WORKBENCH_PrivateData *wpd,
+ Object *ob,
+ eV3DShadingColorType 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);
+ const bool use_single_drawcall = !ELEM(
+ color_type, V3D_SHADING_MATERIAL_COLOR, V3D_SHADING_TEXTURE_COLOR);
+
+ if (use_single_drawcall) {
+ 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, r_transp);
+ DRW_shgroup_call(grp, geom, ob);
+ }
+ }
+ else {
+ struct GPUBatch **geoms = (use_tex) ? DRW_cache_mesh_surface_texpaint_get(ob) :
+ workbench_object_surface_material_get(ob);
+ 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, r_transp);
+ DRW_shgroup_call(grp, geoms[i], ob);
+ }
+ }
+ }
+}
+
+static void workbench_cache_hair_populate(WORKBENCH_PrivateData *wpd,
+ Object *ob,
+ ModifierData *md,
+ eV3DShadingColorType color_type,
+ bool use_texpaint_mode)
+{
+ ParticleSystem *psys = ((ParticleSystemModifierData *)md)->psys;
+ ParticleSettings *part = psys->part;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const Scene *scene = draw_ctx->scene;
+
+ const ImagePaintSettings *imapaint = use_texpaint_mode ? &scene->toolsettings->imapaint : NULL;
+ Image *ima = (imapaint && imapaint->mode == IMAGEPAINT_MODE_IMAGE) ? imapaint->canvas : NULL;
+ int interp = (imapaint && imapaint->interp == IMAGEPAINT_INTERP_LINEAR) ? SHD_INTERP_LINEAR :
+ SHD_INTERP_CLOSEST;
+ DRWShadingGroup *grp = (use_texpaint_mode) ?
+ 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);
+}
+
+/* Decide what colortype to draw the object with.
+ * In some cases it can be overwritten by workbench_material_setup(). */
+static eV3DShadingColorType workbench_color_type_get(WORKBENCH_PrivateData *wpd,
+ Object *ob,
+ bool *r_sculpt_pbvh,
+ bool *r_texpaint_mode,
+ bool *r_draw_shadow)
+{
+ eV3DShadingColorType color_type = wpd->shading.color_type;
+ const Mesh *me = (ob->type == OB_MESH) ? ob->data : NULL;
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const bool is_active = (ob == draw_ctx->obact);
+ const bool is_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) &&
+ !DRW_state_is_image_render();
+ const bool is_render = DRW_state_is_image_render() && (draw_ctx->v3d == NULL);
+ const bool is_texpaint_mode = is_active && (wpd->ctx_mode == CTX_MODE_PAINT_TEXTURE);
+ const bool is_vertpaint_mode = is_active && (wpd->ctx_mode == CTX_MODE_PAINT_VERTEX);
+
+ if ((color_type == V3D_SHADING_TEXTURE_COLOR) && (ob->dt < OB_TEXTURE)) {
+ color_type = V3D_SHADING_MATERIAL_COLOR;
+ }
+ /* Disable color mode if data layer is unavailable. */
+ if ((color_type == V3D_SHADING_TEXTURE_COLOR) && (me == NULL || me->mloopuv == NULL)) {
+ color_type = V3D_SHADING_MATERIAL_COLOR;
+ }
+ if ((color_type == V3D_SHADING_VERTEX_COLOR) && (me == NULL || me->mloopcol == NULL)) {
+ color_type = V3D_SHADING_OBJECT_COLOR;
+ }
+
+ *r_sculpt_pbvh = is_sculpt_pbvh;
+ *r_texpaint_mode = false;
+
+ if (!is_sculpt_pbvh && !is_render) {
+ /* Force texture or vertex mode if object is in paint mode. */
+ if (is_texpaint_mode && me && me->mloopuv) {
+ color_type = V3D_SHADING_TEXTURE_COLOR;
+ *r_texpaint_mode = true;
+ }
+ else if (is_vertpaint_mode && me && me->mloopcol) {
+ color_type = V3D_SHADING_VERTEX_COLOR;
+ }
+ }
+
+ 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;
+}
+
+void workbench_cache_populate(void *ved, Object *ob)
+{
+ WORKBENCH_Data *vedata = ved;
+ WORKBENCH_StorageList *stl = vedata->stl;
+ WORKBENCH_PrivateData *wpd = stl->wpd;
+
+ if (!DRW_object_is_renderable(ob)) {
+ return;
+ }
+
+ 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, NULL);
+
+ LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
+ if (md->type != eModifierType_ParticleSystem) {
+ continue;
+ }
+ ParticleSystem *psys = ((ParticleSystemModifierData *)md)->psys;
+ if (!DRW_object_is_visible_psys_in_active_context(ob, psys)) {
+ continue;
+ }
+ ParticleSettings *part = psys->part;
+ const int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as;
+
+ if (draw_as == PART_DRAW_PATH) {
+ workbench_cache_hair_populate(wpd, ob, md, color_type, use_texpaint_mode);
+ }
+ }
+ }
+
+ if (!(ob->base_flag & BASE_FROM_DUPLI)) {
+ ModifierData *md = modifiers_findByType(ob, eModifierType_Fluid);
+ if (md && modifier_isEnabled(wpd->scene, md, eModifierMode_Realtime)) {
+ FluidModifierData *fmd = (FluidModifierData *)md;
+ if (fmd->domain && fmd->domain->type == FLUID_DOMAIN_TYPE_GAS) {
+ workbench_volume_cache_populate(vedata, wpd->scene, ob, md);
+ return; /* Do not draw solid in this case. */
+ }
+ }
+ }
+
+ if (!(DRW_object_visibility_in_active_context(ob) & OB_VISIBLE_SELF)) {
+ return;
+ }
+
+ if ((ob->dt < OB_SOLID) && !DRW_state_is_scene_render()) {
+ return;
+ }
+
+ if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL)) {
+ bool use_sculpt_pbvh, use_texpaint_mode, draw_shadow, has_transp_mat = false;
+ eV3DShadingColorType 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);
+ }
+ else if (use_texpaint_mode) {
+ workbench_cache_texpaint_populate(wpd, ob);
+ }
+ else {
+ workbench_cache_common_populate(wpd, ob, color_type, &has_transp_mat);
+ }
+
+ if (draw_shadow) {
+ workbench_shadow_cache_populate(vedata, ob, has_transp_mat);
+ }
+ }
+}
+
+void workbench_cache_finish(void *ved)
+{
+ WORKBENCH_Data *vedata = ved;
+ WORKBENCH_StorageList *stl = vedata->stl;
+ WORKBENCH_FramebufferList *fbl = vedata->fbl;
+ WORKBENCH_PrivateData *wpd = stl->wpd;
+
+ /* TODO(fclem) Only do this when really needed. */
+ {
+ /* HACK we allocate the infront depth here to avoid the overhead when if is not needed. */
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+
+ DRW_texture_ensure_fullscreen_2d(&dtxl->depth_in_front, GPU_DEPTH24_STENCIL8, 0);
+
+ GPU_framebuffer_ensure_config(&dfbl->in_front_fb,
+ {
+ GPU_ATTACHMENT_TEXTURE(dtxl->depth_in_front),
+ GPU_ATTACHMENT_TEXTURE(dtxl->color),
+ });
+
+ GPU_framebuffer_ensure_config(&fbl->opaque_infront_fb,
+ {
+ GPU_ATTACHMENT_TEXTURE(dtxl->depth_in_front),
+ GPU_ATTACHMENT_TEXTURE(wpd->material_buffer_tx),
+ GPU_ATTACHMENT_TEXTURE(wpd->normal_buffer_tx),
+ GPU_ATTACHMENT_TEXTURE(wpd->object_id_tx),
+ });
+
+ GPU_framebuffer_ensure_config(&fbl->transp_accum_infront_fb,
+ {
+ GPU_ATTACHMENT_TEXTURE(dtxl->depth_in_front),
+ GPU_ATTACHMENT_TEXTURE(wpd->accum_buffer_tx),
+ GPU_ATTACHMENT_TEXTURE(wpd->reveal_buffer_tx),
+ });
+ }
+
+ if (wpd->object_id_tx) {
+ GPU_framebuffer_ensure_config(&fbl->id_clear_fb,
+ {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(wpd->object_id_tx),
+ });
+ }
+ else {
+ GPU_FRAMEBUFFER_FREE_SAFE(fbl->id_clear_fb);
+ }
+
+ workbench_update_material_ubos(wpd);
+
+ /* TODO don't free reuse next redraw. */
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < 2; j++) {
+ for (int k = 0; k < 2; k++) {
+ if (wpd->prepass[i][j][k].material_hash) {
+ BLI_ghash_free(wpd->prepass[i][j][k].material_hash, NULL, NULL);
+ wpd->prepass[i][j][k].material_hash = NULL;
+ }
+ }
+ }
+ }
+}
+
+/* Used by viewport rendering & final rendering.
+ * Do one render loop iteration (i.e: One TAA sample). */
+void workbench_draw_sample(void *ved)
+{
+ WORKBENCH_Data *vedata = ved;
+ WORKBENCH_FramebufferList *fbl = vedata->fbl;
+ WORKBENCH_PrivateData *wpd = vedata->stl->wpd;
+ WORKBENCH_PassList *psl = vedata->psl;
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+ float clear_col[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ float clear_col_with_alpha[4] = {0.0f, 0.0f, 0.0f, 1.0f};
+
+ const bool do_render = workbench_antialiasing_setup(vedata);
+ const bool xray_is_visible = wpd->shading.xray_alpha > 0.0f;
+ const bool do_transparent_infront_pass = !DRW_pass_is_empty(psl->transp_accum_infront_ps);
+ const bool do_transparent_pass = !DRW_pass_is_empty(psl->transp_accum_ps);
+ const bool do_opaque_infront_pass = !DRW_pass_is_empty(psl->opaque_infront_ps);
+ const bool do_opaque_pass = !DRW_pass_is_empty(psl->opaque_ps) || do_opaque_infront_pass;
+
+ if (dfbl->in_front_fb) {
+ GPU_framebuffer_bind(dfbl->in_front_fb);
+ GPU_framebuffer_clear_depth(dfbl->in_front_fb, 1.0f);
+ }
+
+ if (do_render) {
+ GPU_framebuffer_bind(dfbl->default_fb);
+ GPU_framebuffer_clear_color_depth_stencil(dfbl->default_fb, wpd->background_color, 1.0f, 0x00);
+
+ if (fbl->id_clear_fb) {
+ GPU_framebuffer_bind(fbl->id_clear_fb);
+ GPU_framebuffer_clear_color(fbl->id_clear_fb, clear_col);
+ }
+
+ if (do_opaque_pass) {
+ GPU_framebuffer_bind(fbl->opaque_fb);
+ DRW_draw_pass(psl->opaque_ps);
+
+ if (psl->shadow_ps[0]) {
+ DRW_draw_pass(psl->shadow_ps[0]);
+ DRW_draw_pass(psl->shadow_ps[1]);
+ }
+
+ if (do_opaque_infront_pass) {
+ GPU_framebuffer_bind(fbl->opaque_infront_fb);
+ DRW_draw_pass(psl->opaque_infront_ps);
+
+ GPU_framebuffer_bind(fbl->opaque_fb);
+ DRW_draw_pass(psl->merge_infront_ps);
+ }
+
+ GPU_framebuffer_bind(dfbl->default_fb);
+ DRW_draw_pass(psl->composite_ps);
+
+ if (psl->cavity_ps) {
+ GPU_framebuffer_bind(dfbl->color_only_fb);
+ DRW_draw_pass(psl->cavity_ps);
+ }
+ }
+
+ workbench_volume_draw_pass(vedata);
+
+ if (xray_is_visible) {
+ if (do_transparent_pass) {
+ GPU_framebuffer_bind(fbl->transp_accum_fb);
+ GPU_framebuffer_clear_color(fbl->transp_accum_fb, clear_col_with_alpha);
+
+ DRW_draw_pass(psl->transp_accum_ps);
+
+ GPU_framebuffer_bind(dfbl->color_only_fb);
+ DRW_draw_pass(psl->transp_resolve_ps);
+ }
+
+ if (do_transparent_infront_pass) {
+ GPU_framebuffer_bind(fbl->transp_accum_infront_fb);
+ GPU_framebuffer_clear_color(fbl->transp_accum_infront_fb, clear_col_with_alpha);
+
+ DRW_draw_pass(psl->transp_accum_infront_ps);
+
+ GPU_framebuffer_bind(dfbl->color_only_fb);
+ DRW_draw_pass(psl->transp_resolve_ps);
+ }
+ }
+
+ workbench_transparent_draw_depth_pass(vedata);
+
+ if (psl->outline_ps) {
+ GPU_framebuffer_bind(dfbl->color_only_fb);
+ DRW_draw_pass(psl->outline_ps);
+ }
+
+ workbench_dof_draw_pass(vedata);
+ }
+
+ workbench_antialiasing_draw_pass(vedata);
+}
+
+/* Viewport rendering. */
+static void workbench_draw_scene(void *ved)
+{
+ WORKBENCH_Data *vedata = ved;
+ WORKBENCH_PrivateData *wpd = vedata->stl->wpd;
+
+ if (DRW_state_is_opengl_render()) {
+ while (wpd->taa_sample < max_ii(1, wpd->taa_sample_len)) {
+ workbench_update_world_ubo(wpd);
+
+ workbench_draw_sample(vedata);
+ }
+ }
+ else {
+ workbench_draw_sample(vedata);
+ }
+
+ workbench_draw_finish(vedata);
+}
+
+void workbench_draw_finish(void *ved)
+{
+ WORKBENCH_Data *vedata = ved;
+ workbench_volume_draw_finish(vedata);
+}
+
+static void workbench_engine_free(void)
+{
+ workbench_shader_free();
+}
+
+static void workbench_view_update(void *vedata)
+{
+ WORKBENCH_Data *data = vedata;
+ workbench_antialiasing_view_updated(data);
+}
+
+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);
+ 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 = {
+ NULL,
+ NULL,
+ N_("Workbench"),
+ &workbench_data_size,
+ &workbench_engine_init,
+ &workbench_engine_free,
+ &workbench_cache_init,
+ &workbench_cache_populate,
+ &workbench_cache_finish,
+ &workbench_draw_scene,
+ &workbench_view_update,
+ &workbench_id_update,
+ &workbench_render,
+};
+
RenderEngineType DRW_engine_viewport_workbench_type = {
NULL,
NULL,
@@ -44,7 +583,7 @@ RenderEngineType DRW_engine_viewport_workbench_type = {
NULL,
NULL,
&workbench_render_update_passes,
- &draw_engine_workbench_solid,
+ &draw_engine_workbench,
{NULL, NULL, NULL},
};
diff --git a/source/blender/draw/engines/workbench/workbench_engine.h b/source/blender/draw/engines/workbench/workbench_engine.h
index 78f70abdaab..eee53fcde07 100644
--- a/source/blender/draw/engines/workbench/workbench_engine.h
+++ b/source/blender/draw/engines/workbench/workbench_engine.h
@@ -23,8 +23,6 @@
#ifndef __WORKBENCH_ENGINE_H__
#define __WORKBENCH_ENGINE_H__
-extern DrawEngineType draw_engine_workbench_solid;
-extern DrawEngineType draw_engine_workbench_transparent;
extern RenderEngineType DRW_engine_viewport_workbench_type;
#endif /* __WORKBENCH_ENGINE_H__ */
diff --git a/source/blender/draw/engines/workbench/workbench_forward.c b/source/blender/draw/engines/workbench/workbench_forward.c
deleted file mode 100644
index 7e09016cf61..00000000000
--- a/source/blender/draw/engines/workbench/workbench_forward.c
+++ /dev/null
@@ -1,817 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Copyright 2016, Blender Foundation.
- */
-
-/** \file
- * \ingroup draw_engine
- */
-
-#include "workbench_private.h"
-
-#include "BLI_alloca.h"
-#include "BLI_dynstr.h"
-#include "BLI_string_utils.h"
-#include "BLI_utildefines.h"
-
-#include "BKE_modifier.h"
-#include "BKE_object.h"
-#include "BKE_paint.h"
-#include "BKE_particle.h"
-
-#include "DNA_image_types.h"
-#include "DNA_fluid_types.h"
-#include "DNA_mesh_types.h"
-#include "DNA_modifier_types.h"
-#include "DNA_node_types.h"
-
-#include "ED_view3d.h"
-
-#include "GPU_shader.h"
-#include "GPU_texture.h"
-
-/* *********** STATIC *********** */
-
-typedef struct WORKBENCH_FORWARD_Shaders {
- struct GPUShader *transparent_accum_sh_cache[MAX_ACCUM_SHADERS];
- struct GPUShader *object_outline_sh;
- struct GPUShader *object_outline_texture_sh;
- struct GPUShader *object_outline_hair_sh;
-} WORKBENCH_FORWARD_Shaders;
-
-static struct {
- WORKBENCH_FORWARD_Shaders sh_data[GPU_SHADER_CFG_LEN];
-
- struct GPUShader *composite_sh_cache[2];
-
- struct GPUTexture *object_id_tx; /* ref only, not alloced */
- struct GPUTexture *transparent_accum_tx; /* ref only, not alloced */
- struct GPUTexture *transparent_revealage_tx; /* ref only, not alloced */
- struct GPUTexture *composite_buffer_tx; /* ref only, not alloced */
-} e_data = {{{{NULL}}}};
-
-/* Shaders */
-extern char datatoc_common_hair_lib_glsl[];
-extern char datatoc_common_view_lib_glsl[];
-
-extern char datatoc_workbench_forward_composite_frag_glsl[];
-extern char datatoc_workbench_forward_depth_frag_glsl[];
-extern char datatoc_workbench_forward_transparent_accum_frag_glsl[];
-extern char datatoc_workbench_data_lib_glsl[];
-extern char datatoc_workbench_object_outline_lib_glsl[];
-extern char datatoc_workbench_curvature_lib_glsl[];
-extern char datatoc_workbench_prepass_vert_glsl[];
-extern char datatoc_workbench_common_lib_glsl[];
-extern char datatoc_workbench_world_light_lib_glsl[];
-
-/* static functions */
-static char *workbench_build_forward_vert(bool is_hair)
-{
- DynStr *ds = BLI_dynstr_new();
- if (is_hair) {
- BLI_dynstr_append(ds, datatoc_common_hair_lib_glsl);
- }
- BLI_dynstr_append(ds, datatoc_common_view_lib_glsl);
- BLI_dynstr_append(ds, datatoc_workbench_prepass_vert_glsl);
-
- char *str = BLI_dynstr_get_cstring(ds);
- BLI_dynstr_free(ds);
- return str;
-}
-
-static char *workbench_build_forward_outline_frag(void)
-{
- DynStr *ds = BLI_dynstr_new();
-
- BLI_dynstr_append(ds, datatoc_common_view_lib_glsl);
- BLI_dynstr_append(ds, datatoc_workbench_forward_depth_frag_glsl);
-
- char *str = BLI_dynstr_get_cstring(ds);
- BLI_dynstr_free(ds);
- return str;
-}
-
-static char *workbench_build_forward_transparent_accum_frag(void)
-{
- DynStr *ds = BLI_dynstr_new();
-
- BLI_dynstr_append(ds, datatoc_common_view_lib_glsl);
- BLI_dynstr_append(ds, datatoc_workbench_data_lib_glsl);
- BLI_dynstr_append(ds, datatoc_workbench_common_lib_glsl);
- BLI_dynstr_append(ds, datatoc_workbench_world_light_lib_glsl);
- BLI_dynstr_append(ds, datatoc_workbench_forward_transparent_accum_frag_glsl);
-
- char *str = BLI_dynstr_get_cstring(ds);
- BLI_dynstr_free(ds);
- return str;
-}
-
-static char *workbench_build_forward_composite_frag(void)
-{
- DynStr *ds = BLI_dynstr_new();
-
- BLI_dynstr_append(ds, datatoc_workbench_data_lib_glsl);
- BLI_dynstr_append(ds, datatoc_workbench_common_lib_glsl);
- BLI_dynstr_append(ds, datatoc_workbench_object_outline_lib_glsl);
- BLI_dynstr_append(ds, datatoc_workbench_curvature_lib_glsl);
- BLI_dynstr_append(ds, datatoc_workbench_forward_composite_frag_glsl);
-
- char *str = BLI_dynstr_get_cstring(ds);
- BLI_dynstr_free(ds);
- return str;
-}
-
-WORKBENCH_MaterialData *workbench_forward_get_or_create_material_data(
- WORKBENCH_Data *vedata,
- Object *ob,
- Material *mat,
- Image *ima,
- ImageUser *iuser,
- eV3DShadingColorType color_type,
- int interp)
-{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- WORKBENCH_FORWARD_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
- WORKBENCH_StorageList *stl = vedata->stl;
- WORKBENCH_PassList *psl = vedata->psl;
- WORKBENCH_PrivateData *wpd = stl->g_data;
- WORKBENCH_MaterialData *material;
- WORKBENCH_MaterialData material_template;
- DRWShadingGroup *grp;
-
- /* Solid */
- workbench_material_update_data(wpd, ob, mat, &material_template, color_type);
- material_template.color_type = color_type;
- material_template.ima = ima;
- material_template.iuser = iuser;
- material_template.interp = interp;
- uint hash = workbench_material_get_hash(&material_template, false);
-
- material = BLI_ghash_lookup(wpd->material_transp_hash, POINTER_FROM_UINT(hash));
- if (material == NULL) {
- material = MEM_mallocN(sizeof(WORKBENCH_MaterialData), __func__);
-
- /* transparent accum */
- /* select the correct transparent accum shader */
- GPUShader *shader = (wpd->shading.color_type == color_type) ?
- wpd->transparent_accum_sh :
- wpd->transparent_accum_uniform_sh;
- const bool is_tiled = (ima && ima->source == IMA_SRC_TILED);
- if (color_type == V3D_SHADING_TEXTURE_COLOR) {
- shader = is_tiled ? wpd->transparent_accum_textured_array_sh :
- wpd->transparent_accum_textured_sh;
- }
-
- grp = DRW_shgroup_create(shader, psl->transparent_accum_pass);
- DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo);
- DRW_shgroup_uniform_float_copy(grp, "alpha", material_template.alpha);
- DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)wpd->viewvecs, 3);
- workbench_material_copy(material, &material_template);
- if (STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) {
- BKE_studiolight_ensure_flag(wpd->studio_light,
- STUDIOLIGHT_MATCAP_DIFFUSE_GPUTEXTURE |
- STUDIOLIGHT_MATCAP_SPECULAR_GPUTEXTURE);
- DRW_shgroup_uniform_texture(
- grp, "matcapDiffuseImage", wpd->studio_light->matcap_diffuse.gputexture);
- if (workbench_is_specular_highlight_enabled(wpd)) {
- DRW_shgroup_uniform_texture(
- grp, "matcapSpecularImage", wpd->studio_light->matcap_specular.gputexture);
- }
- }
- if (workbench_is_specular_highlight_enabled(wpd) || MATCAP_ENABLED(wpd)) {
- DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1);
- }
- if (SHADOW_ENABLED(wpd)) {
- DRW_shgroup_uniform_float_copy(grp, "shadowMultiplier", wpd->shadow_multiplier);
- DRW_shgroup_uniform_float_copy(grp, "shadowShift", wpd->shadow_shift);
- DRW_shgroup_uniform_float_copy(grp, "shadowFocus", wpd->shadow_focus);
- }
-
- workbench_material_shgroup_uniform(wpd, grp, material, ob, false, is_tiled, interp);
- material->shgrp = grp;
-
- /* Depth */
- if (color_type == V3D_SHADING_TEXTURE_COLOR) {
- material->shgrp_object_outline = DRW_shgroup_create(sh_data->object_outline_texture_sh,
- psl->object_outline_pass);
- GPUTexture *tex = GPU_texture_from_blender(
- material->ima, material->iuser, NULL, GL_TEXTURE_2D);
- DRW_shgroup_uniform_texture(material->shgrp_object_outline, "image", tex);
- }
- else {
- material->shgrp_object_outline = DRW_shgroup_create(sh_data->object_outline_sh,
- psl->object_outline_pass);
- }
- if (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) {
- DRW_shgroup_state_enable(material->shgrp_object_outline, DRW_STATE_CLIP_PLANES);
- }
- BLI_ghash_insert(wpd->material_transp_hash, POINTER_FROM_UINT(hash), material);
- }
- return material;
-}
-
-static GPUShader *ensure_forward_accum_shaders(WORKBENCH_PrivateData *wpd,
- bool is_uniform_color,
- bool is_hair,
- bool is_tiled,
- const WORKBENCH_ColorOverride color_override,
- eGPUShaderConfig sh_cfg)
-{
- WORKBENCH_FORWARD_Shaders *sh_data = &e_data.sh_data[sh_cfg];
- int index = workbench_material_get_accum_shader_index(
- wpd, is_uniform_color, is_hair, is_tiled, color_override);
- if (sh_data->transparent_accum_sh_cache[index] == NULL) {
- const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[sh_cfg];
- char *defines = workbench_material_build_defines(
- wpd, is_uniform_color, is_hair, is_tiled, color_override);
- char *transparent_accum_vert = workbench_build_forward_vert(is_hair);
- char *transparent_accum_frag = workbench_build_forward_transparent_accum_frag();
- sh_data->transparent_accum_sh_cache[index] = GPU_shader_create_from_arrays({
- .vert = (const char *[]){sh_cfg_data->lib, transparent_accum_vert, NULL},
- .frag = (const char *[]){transparent_accum_frag, NULL},
- .defs = (const char *[]){sh_cfg_data->def, defines, NULL},
- });
- MEM_freeN(transparent_accum_vert);
- MEM_freeN(transparent_accum_frag);
- MEM_freeN(defines);
- }
- return sh_data->transparent_accum_sh_cache[index];
-}
-
-static GPUShader *ensure_forward_composite_shaders(WORKBENCH_PrivateData *wpd)
-{
- int index = OBJECT_OUTLINE_ENABLED(wpd) ? 1 : 0;
- if (e_data.composite_sh_cache[index] == NULL) {
- char *defines = workbench_material_build_defines(
- wpd, false, false, false, WORKBENCH_COLOR_OVERRIDE_OFF);
- char *composite_frag = workbench_build_forward_composite_frag();
- e_data.composite_sh_cache[index] = DRW_shader_create_fullscreen(composite_frag, defines);
- MEM_freeN(composite_frag);
- MEM_freeN(defines);
- }
- return e_data.composite_sh_cache[index];
-}
-
-void workbench_forward_choose_shaders(WORKBENCH_PrivateData *wpd, eGPUShaderConfig sh_cfg)
-{
- wpd->composite_sh = ensure_forward_composite_shaders(wpd);
- wpd->transparent_accum_sh = ensure_forward_accum_shaders(
- wpd, false, false, false, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg);
- wpd->transparent_accum_hair_sh = ensure_forward_accum_shaders(
- wpd, false, true, false, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg);
- wpd->transparent_accum_uniform_sh = ensure_forward_accum_shaders(
- wpd, true, false, false, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg);
- wpd->transparent_accum_uniform_hair_sh = ensure_forward_accum_shaders(
- wpd, true, true, false, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg);
- wpd->transparent_accum_textured_sh = ensure_forward_accum_shaders(
- wpd, false, false, false, WORKBENCH_COLOR_OVERRIDE_TEXTURE, sh_cfg);
- wpd->transparent_accum_textured_array_sh = ensure_forward_accum_shaders(
- wpd, false, false, true, WORKBENCH_COLOR_OVERRIDE_TEXTURE, sh_cfg);
- wpd->transparent_accum_vertex_sh = ensure_forward_accum_shaders(
- wpd, false, false, false, WORKBENCH_COLOR_OVERRIDE_VERTEX, sh_cfg);
-}
-
-void workbench_forward_outline_shaders_ensure(WORKBENCH_PrivateData *wpd, eGPUShaderConfig sh_cfg)
-{
- WORKBENCH_FORWARD_Shaders *sh_data = &e_data.sh_data[sh_cfg];
-
- if (sh_data->object_outline_sh == NULL) {
- const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[sh_cfg];
- char *defines = workbench_material_build_defines(
- wpd, false, false, false, WORKBENCH_COLOR_OVERRIDE_OFF);
- char *defines_texture = workbench_material_build_defines(
- wpd, true, false, false, WORKBENCH_COLOR_OVERRIDE_OFF);
- char *defines_hair = workbench_material_build_defines(
- wpd, false, true, false, WORKBENCH_COLOR_OVERRIDE_OFF);
- char *forward_vert = workbench_build_forward_vert(false);
- char *forward_frag = workbench_build_forward_outline_frag();
- char *forward_hair_vert = workbench_build_forward_vert(true);
-
- const char *define_id_pass = "#define OBJECT_ID_PASS_ENABLED\n";
-
- sh_data->object_outline_sh = GPU_shader_create_from_arrays({
- .vert = (const char *[]){sh_cfg_data->lib, forward_vert, NULL},
- .frag = (const char *[]){forward_frag, NULL},
- .defs = (const char *[]){sh_cfg_data->def, defines, define_id_pass, NULL},
- });
- sh_data->object_outline_texture_sh = GPU_shader_create_from_arrays({
- .vert = (const char *[]){sh_cfg_data->lib, forward_vert, NULL},
- .frag = (const char *[]){forward_frag, NULL},
- .defs = (const char *[]){sh_cfg_data->def, defines_texture, define_id_pass, NULL},
- });
- sh_data->object_outline_hair_sh = GPU_shader_create_from_arrays({
- .vert = (const char *[]){sh_cfg_data->lib, forward_hair_vert, NULL},
- .frag = (const char *[]){forward_frag, NULL},
- .defs = (const char *[]){sh_cfg_data->def, defines_hair, define_id_pass, NULL},
- });
-
- MEM_freeN(forward_hair_vert);
- MEM_freeN(forward_vert);
- MEM_freeN(forward_frag);
- MEM_freeN(defines);
- MEM_freeN(defines_texture);
- MEM_freeN(defines_hair);
- }
-}
-
-/* public functions */
-void workbench_forward_engine_init(WORKBENCH_Data *vedata)
-{
- WORKBENCH_FramebufferList *fbl = vedata->fbl;
- WORKBENCH_PassList *psl = vedata->psl;
- WORKBENCH_StorageList *stl = vedata->stl;
- DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
- const DRWContextState *draw_ctx = DRW_context_state_get();
- DRWShadingGroup *grp;
-
- if (!stl->g_data) {
- /* Alloc transient pointers */
- stl->g_data = MEM_callocN(sizeof(*stl->g_data), __func__);
- }
- if (!stl->effects) {
- stl->effects = MEM_callocN(sizeof(*stl->effects), __func__);
- workbench_effect_info_init(stl->effects);
- }
- WORKBENCH_PrivateData *wpd = stl->g_data;
- workbench_private_data_init(wpd);
-
- workbench_forward_outline_shaders_ensure(wpd, draw_ctx->sh_cfg);
-
- workbench_volume_engine_init();
- workbench_fxaa_engine_init();
- workbench_taa_engine_init(vedata);
-
- workbench_forward_outline_shaders_ensure(wpd, draw_ctx->sh_cfg);
- workbench_forward_choose_shaders(wpd, draw_ctx->sh_cfg);
-
- const float *viewport_size = DRW_viewport_size_get();
- const int size[2] = {(int)viewport_size[0], (int)viewport_size[1]};
- const eGPUTextureFormat comp_tex_format = GPU_RGBA16F;
-
- e_data.object_id_tx = DRW_texture_pool_query_2d(
- size[0], size[1], GPU_R32UI, &draw_engine_workbench_transparent);
- e_data.transparent_accum_tx = DRW_texture_pool_query_2d(
- size[0], size[1], GPU_RGBA16F, &draw_engine_workbench_transparent);
- e_data.transparent_revealage_tx = DRW_texture_pool_query_2d(
- size[0], size[1], GPU_R16F, &draw_engine_workbench_transparent);
- e_data.composite_buffer_tx = DRW_texture_pool_query_2d(
- size[0], size[1], comp_tex_format, &draw_engine_workbench_transparent);
-
- GPU_framebuffer_ensure_config(&fbl->object_outline_fb,
- {
- GPU_ATTACHMENT_TEXTURE(dtxl->depth),
- GPU_ATTACHMENT_TEXTURE(e_data.object_id_tx),
- });
- GPU_framebuffer_ensure_config(&fbl->transparent_accum_fb,
- {
- GPU_ATTACHMENT_NONE,
- GPU_ATTACHMENT_TEXTURE(e_data.transparent_accum_tx),
- GPU_ATTACHMENT_TEXTURE(e_data.transparent_revealage_tx),
- });
- GPU_framebuffer_ensure_config(&fbl->composite_fb,
- {
- GPU_ATTACHMENT_NONE,
- GPU_ATTACHMENT_TEXTURE(e_data.composite_buffer_tx),
- });
- GPU_framebuffer_ensure_config(&fbl->effect_fb,
- {
- GPU_ATTACHMENT_NONE,
- GPU_ATTACHMENT_TEXTURE(e_data.transparent_accum_tx),
- });
-
- workbench_volume_cache_init(vedata);
-
- DRWState clip_state = WORLD_CLIPPING_ENABLED(wpd) ? DRW_STATE_CLIP_PLANES : 0;
- DRWState cull_state = CULL_BACKFACE_ENABLED(wpd) ? DRW_STATE_CULL_BACK : 0;
-
- /* Transparency Accum */
- {
- int state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_OIT | cull_state | clip_state;
- psl->transparent_accum_pass = DRW_pass_create("Transparent Accum", state);
- }
- /* Depth */
- {
- int state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | cull_state |
- clip_state;
- psl->object_outline_pass = DRW_pass_create("Object Outline Pass", state);
- }
- /* Composite */
- {
- int state = DRW_STATE_WRITE_COLOR;
- if (DRW_state_is_scene_render()) {
- /* Composite the scene over cleared background. */
- state |= DRW_STATE_BLEND_ALPHA_PREMUL;
- }
- psl->composite_pass = DRW_pass_create("Composite", state);
-
- grp = DRW_shgroup_create(wpd->composite_sh, psl->composite_pass);
- if (OBJECT_ID_PASS_ENABLED(wpd)) {
- DRW_shgroup_uniform_texture_ref(grp, "objectId", &e_data.object_id_tx);
- }
- DRW_shgroup_uniform_texture_ref(grp, "transparentAccum", &e_data.transparent_accum_tx);
- DRW_shgroup_uniform_texture_ref(grp, "transparentRevealage", &e_data.transparent_revealage_tx);
- DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo);
- DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1);
- DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL);
- }
-
- {
- workbench_aa_create_pass(vedata, &e_data.transparent_accum_tx);
- }
-
- if (wpd->shading.type == OB_WIRE) {
- wpd->shading.xray_alpha = 0.0f;
- wpd->shading.xray_alpha_wire = 0.0f;
- }
-}
-
-void workbench_forward_engine_free()
-{
- for (int sh_data_index = 0; sh_data_index < ARRAY_SIZE(e_data.sh_data); sh_data_index++) {
- WORKBENCH_FORWARD_Shaders *sh_data = &e_data.sh_data[sh_data_index];
- for (int index = 0; index < MAX_ACCUM_SHADERS; index++) {
- DRW_SHADER_FREE_SAFE(sh_data->transparent_accum_sh_cache[index]);
- }
- DRW_SHADER_FREE_SAFE(sh_data->object_outline_sh);
- DRW_SHADER_FREE_SAFE(sh_data->object_outline_texture_sh);
- DRW_SHADER_FREE_SAFE(sh_data->object_outline_hair_sh);
- }
-
- for (int index = 0; index < 2; index++) {
- DRW_SHADER_FREE_SAFE(e_data.composite_sh_cache[index]);
- }
-
- workbench_volume_engine_free();
- workbench_fxaa_engine_free();
- workbench_taa_engine_free();
- workbench_dof_engine_free();
-}
-
-void workbench_forward_cache_init(WORKBENCH_Data *UNUSED(vedata))
-{
-}
-
-static void workbench_forward_cache_populate_particles(WORKBENCH_Data *vedata, Object *ob)
-{
- WORKBENCH_StorageList *stl = vedata->stl;
- WORKBENCH_PassList *psl = vedata->psl;
- WORKBENCH_PrivateData *wpd = stl->g_data;
-
- for (ModifierData *md = ob->modifiers.first; md; md = md->next) {
- if (md->type != eModifierType_ParticleSystem) {
- continue;
- }
- ParticleSystem *psys = ((ParticleSystemModifierData *)md)->psys;
- if (!DRW_object_is_visible_psys_in_active_context(ob, psys)) {
- continue;
- }
- ParticleSettings *part = psys->part;
- const int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as;
-
- if (draw_as == PART_DRAW_PATH) {
- const DRWContextState *draw_ctx = DRW_context_state_get();
- Material *mat;
- Image *image;
- ImageUser *iuser;
- int interp;
- workbench_material_get_image_and_mat(ob, part->omat, &image, &iuser, &interp, &mat);
- eV3DShadingColorType color_type = workbench_material_determine_color_type(
- wpd, image, ob, false);
- WORKBENCH_MaterialData *material = workbench_forward_get_or_create_material_data(
- vedata, ob, mat, image, iuser, color_type, interp);
-
- struct GPUShader *shader = (wpd->shading.color_type == color_type) ?
- wpd->transparent_accum_hair_sh :
- wpd->transparent_accum_uniform_hair_sh;
- DRWShadingGroup *shgrp = DRW_shgroup_hair_create(
- ob, psys, md, psl->transparent_accum_pass, shader);
- DRW_shgroup_uniform_block(shgrp, "world_block", wpd->world_ubo);
- workbench_material_shgroup_uniform(wpd, shgrp, material, ob, false, false, interp);
- DRW_shgroup_uniform_vec4(shgrp, "viewvecs[0]", (float *)wpd->viewvecs, 3);
- /* Hairs have lots of layer and can rapidly become the most prominent surface.
- * So lower their alpha artificially. */
- float hair_alpha = XRAY_ALPHA(wpd) * 0.33f;
- DRW_shgroup_uniform_float_copy(shgrp, "alpha", hair_alpha);
- if (STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) {
- BKE_studiolight_ensure_flag(wpd->studio_light,
- STUDIOLIGHT_MATCAP_DIFFUSE_GPUTEXTURE |
- STUDIOLIGHT_MATCAP_SPECULAR_GPUTEXTURE);
- DRW_shgroup_uniform_texture(
- shgrp, "matcapDiffuseImage", wpd->studio_light->matcap_diffuse.gputexture);
- if (workbench_is_specular_highlight_enabled(wpd)) {
- DRW_shgroup_uniform_texture(
- shgrp, "matcapSpecularImage", wpd->studio_light->matcap_specular.gputexture);
- }
- }
- if (workbench_is_specular_highlight_enabled(wpd) || MATCAP_ENABLED(wpd)) {
- DRW_shgroup_uniform_vec2(shgrp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1);
- }
-
- WORKBENCH_FORWARD_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
- shgrp = DRW_shgroup_hair_create(
- ob, psys, md, vedata->psl->object_outline_pass, sh_data->object_outline_hair_sh);
- }
- }
-}
-static void workbench_forward_cache_populate_texture_paint_mode(WORKBENCH_Data *vedata, Object *ob)
-{
- WORKBENCH_StorageList *stl = vedata->stl;
- WORKBENCH_PrivateData *wpd = stl->g_data;
- const DRWContextState *draw_ctx = DRW_context_state_get();
-
- Scene *scene = draw_ctx->scene;
- const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) &&
- !DRW_state_is_image_render();
- WORKBENCH_MaterialData *material;
-
- /* Force workbench to render active object textured when in texture paint mode */
- const ImagePaintSettings *imapaint = &scene->toolsettings->imapaint;
-
- /* Single Image mode */
- if (imapaint->mode == IMAGEPAINT_MODE_IMAGE) {
- Image *image = imapaint->canvas;
- int interp = (imapaint->interp == IMAGEPAINT_INTERP_LINEAR) ? SHD_INTERP_LINEAR :
- SHD_INTERP_CLOSEST;
- eV3DShadingColorType color_type = workbench_material_determine_color_type(
- wpd, image, ob, use_sculpt_pbvh);
- struct GPUBatch *geom = DRW_cache_mesh_surface_texpaint_single_get(ob);
- material = workbench_forward_get_or_create_material_data(
- vedata, ob, NULL, image, NULL, color_type, interp);
-
- DRW_shgroup_call(material->shgrp, geom, ob);
- DRW_shgroup_call(material->shgrp_object_outline, geom, ob);
- }
- else {
- /* IMAGEPAINT_MODE_MATERIAL */
- const int materials_len = DRW_cache_object_material_count_get(ob);
- struct GPUBatch **geom_array = DRW_cache_mesh_surface_texpaint_get(ob);
- for (int i = 0; i < materials_len; i++) {
- if (geom_array != NULL && geom_array[i] != NULL) {
- Material *mat;
- Image *image;
- ImageUser *iuser;
- int interp;
- workbench_material_get_image_and_mat(ob, i + 1, &image, &iuser, &interp, &mat);
- eV3DShadingColorType color_type = workbench_material_determine_color_type(
- wpd, image, ob, use_sculpt_pbvh);
- material = workbench_forward_get_or_create_material_data(
- vedata, ob, mat, image, iuser, color_type, interp);
-
- DRW_shgroup_call(material->shgrp, geom_array[i], ob);
- DRW_shgroup_call(material->shgrp_object_outline, geom_array[i], ob);
- }
- }
- }
-}
-static void workbench_forward_cache_populate_vertex_paint_mode(WORKBENCH_Data *vedata, Object *ob)
-{
- WORKBENCH_StorageList *stl = vedata->stl;
- WORKBENCH_PrivateData *wpd = stl->g_data;
- const DRWContextState *draw_ctx = DRW_context_state_get();
-
- const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) &&
- !DRW_state_is_image_render();
- WORKBENCH_MaterialData *material;
-
- eV3DShadingColorType color_type = workbench_material_determine_color_type(
- wpd, NULL, ob, use_sculpt_pbvh);
- struct GPUBatch *geom = DRW_cache_mesh_surface_vertpaint_get(ob);
- material = workbench_forward_get_or_create_material_data(
- vedata, ob, NULL, NULL, NULL, color_type, false);
- DRW_shgroup_call(material->shgrp, geom, ob);
- DRW_shgroup_call(material->shgrp_object_outline, geom, ob);
-}
-
-void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob)
-{
- WORKBENCH_StorageList *stl = vedata->stl;
- WORKBENCH_PrivateData *wpd = stl->g_data;
- const DRWContextState *draw_ctx = DRW_context_state_get();
- Scene *scene = draw_ctx->scene;
- const bool is_wire = (ob->dt == OB_WIRE);
-
- if (!DRW_object_is_renderable(ob)) {
- return;
- }
-
- if (ob->type == OB_MESH) {
- workbench_forward_cache_populate_particles(vedata, ob);
- }
-
- ModifierData *md;
- if (((ob->base_flag & BASE_FROM_DUPLI) == 0) &&
- (md = modifiers_findByType(ob, eModifierType_Fluid)) &&
- (modifier_isEnabled(scene, md, eModifierMode_Realtime)) &&
- (((FluidModifierData *)md)->domain != NULL) &&
- (((FluidModifierData *)md)->domain->type == FLUID_DOMAIN_TYPE_GAS)) {
- workbench_volume_cache_populate(vedata, scene, ob, md);
- return; /* Do not draw solid in this case. */
- }
-
- if (!(DRW_object_visibility_in_active_context(ob) & OB_VISIBLE_SELF)) {
- return;
- }
- if (ob->dt < OB_WIRE) {
- return;
- }
-
- WORKBENCH_MaterialData *material = NULL;
- if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL)) {
- const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) &&
- !DRW_state_is_image_render();
- const int materials_len = DRW_cache_object_material_count_get(ob);
- const Mesh *me = (ob->type == OB_MESH) ? ob->data : NULL;
- const WORKBENCH_ColorOverride color_override = workbench_object_color_override_get(ob);
- const bool use_texture_paint_drawing = !(DRW_state_is_image_render() &&
- draw_ctx->v3d == NULL) &&
- (color_override == WORKBENCH_COLOR_OVERRIDE_TEXTURE) &&
- me && me->mloopuv;
- const bool use_vertex_paint_drawing = !(DRW_state_is_image_render() &&
- draw_ctx->v3d == NULL) &&
- (color_override == WORKBENCH_COLOR_OVERRIDE_VERTEX) &&
- me && me->mloopcol;
-
- if (use_texture_paint_drawing) {
- workbench_forward_cache_populate_texture_paint_mode(vedata, ob);
- }
- else if (use_vertex_paint_drawing) {
- workbench_forward_cache_populate_vertex_paint_mode(vedata, ob);
- }
- else if (!use_sculpt_pbvh && TEXTURE_DRAWING_ENABLED(wpd) && me && me->mloopuv) {
- struct GPUBatch **geom_array = DRW_cache_mesh_surface_texpaint_get(ob);
- for (int i = 0; i < materials_len; i++) {
- Material *mat;
- Image *image;
- ImageUser *iuser;
- int interp;
- workbench_material_get_image_and_mat(ob, i + 1, &image, &iuser, &interp, &mat);
- eV3DShadingColorType color_type = workbench_material_determine_color_type(
- wpd, image, ob, use_sculpt_pbvh);
- material = workbench_forward_get_or_create_material_data(
- vedata, ob, mat, image, iuser, color_type, interp);
- DRW_shgroup_call(material->shgrp_object_outline, geom_array[i], ob);
- DRW_shgroup_call(material->shgrp, geom_array[i], ob);
- }
- }
- else if (ELEM(wpd->shading.color_type,
- V3D_SHADING_SINGLE_COLOR,
- V3D_SHADING_OBJECT_COLOR,
- V3D_SHADING_RANDOM_COLOR,
- V3D_SHADING_VERTEX_COLOR)) {
- /* No material split needed */
- eV3DShadingColorType color_type = workbench_material_determine_color_type(
- wpd, NULL, ob, use_sculpt_pbvh);
-
- if (use_sculpt_pbvh) {
- material = workbench_forward_get_or_create_material_data(
- vedata, ob, NULL, NULL, NULL, color_type, 0);
- bool use_vcol = (color_type == V3D_SHADING_VERTEX_COLOR);
- /* TODO(fclem) make this call optional */
- DRW_shgroup_call_sculpt(material->shgrp_object_outline, ob, false, false, false);
- if (!is_wire) {
- DRW_shgroup_call_sculpt(material->shgrp, ob, false, false, use_vcol);
- }
- }
- else {
- struct GPUBatch *geom = (color_type == V3D_SHADING_VERTEX_COLOR) ?
- DRW_cache_mesh_surface_vertpaint_get(ob) :
- DRW_cache_object_surface_get(ob);
- if (geom) {
- material = workbench_forward_get_or_create_material_data(
- vedata, ob, NULL, NULL, NULL, color_type, 0);
- /* TODO(fclem) make this call optional */
- DRW_shgroup_call(material->shgrp_object_outline, geom, ob);
- if (!is_wire) {
- DRW_shgroup_call(material->shgrp, geom, ob);
- }
- }
- }
- }
- else {
- /* Draw material color */
- if (use_sculpt_pbvh) {
- struct DRWShadingGroup **shgrps = BLI_array_alloca(shgrps, materials_len);
-
- for (int i = 0; i < materials_len; i++) {
- struct Material *mat = BKE_object_material_get(ob, i + 1);
- material = workbench_forward_get_or_create_material_data(
- vedata, ob, mat, NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0);
- shgrps[i] = material->shgrp;
- }
- /* TODO(fclem) make this call optional */
- DRW_shgroup_call_sculpt(material->shgrp_object_outline, ob, false, false, false);
- if (!is_wire) {
- DRW_shgroup_call_sculpt_with_materials(shgrps, ob, false);
- }
- }
- else {
- struct GPUMaterial **gpumat_array = BLI_array_alloca(gpumat_array, materials_len);
- memset(gpumat_array, 0, sizeof(*gpumat_array) * materials_len);
-
- struct GPUBatch **mat_geom = DRW_cache_object_surface_material_get(
- ob, gpumat_array, materials_len);
- if (mat_geom) {
- for (int i = 0; i < materials_len; i++) {
- if (mat_geom[i] == NULL) {
- continue;
- }
-
- Material *mat = BKE_object_material_get(ob, i + 1);
- material = workbench_forward_get_or_create_material_data(
- vedata, ob, mat, NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0);
- /* TODO(fclem) make this call optional */
- DRW_shgroup_call(material->shgrp_object_outline, mat_geom[i], ob);
- if (!is_wire) {
- DRW_shgroup_call(material->shgrp, mat_geom[i], ob);
- }
- }
- }
- }
- }
- }
-}
-
-void workbench_forward_cache_finish(WORKBENCH_Data *UNUSED(vedata))
-{
-}
-
-void workbench_forward_draw_scene(WORKBENCH_Data *vedata)
-{
- WORKBENCH_PassList *psl = vedata->psl;
- WORKBENCH_StorageList *stl = vedata->stl;
- WORKBENCH_FramebufferList *fbl = vedata->fbl;
- WORKBENCH_PrivateData *wpd = stl->g_data;
- DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
-
- if (dfbl->in_front_fb) {
- /* TODO(fclem) This clear should be done in a global place. */
- GPU_framebuffer_bind(dfbl->in_front_fb);
- GPU_framebuffer_clear_depth(dfbl->in_front_fb, 1.0f);
- }
-
- if (workbench_is_taa_enabled(wpd)) {
- workbench_taa_draw_scene_start(vedata);
- }
-
- /* Write Depth + Object ID */
- const float clear_outline[4] = {0.0f};
- GPU_framebuffer_bind(fbl->object_outline_fb);
- GPU_framebuffer_clear_color(fbl->object_outline_fb, clear_outline);
- DRW_draw_pass(psl->object_outline_pass);
-
- if (XRAY_ALPHA(wpd) > 0.0) {
- const float clear_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
- GPU_framebuffer_bind(fbl->transparent_accum_fb);
- GPU_framebuffer_clear_color(fbl->transparent_accum_fb, clear_color);
- DRW_draw_pass(psl->transparent_accum_pass);
- }
- else {
- /* TODO(fclem): this is unnecessary and takes up perf.
- * Better change the composite frag shader to not use the tx. */
- const float clear_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
- GPU_framebuffer_bind(fbl->transparent_accum_fb);
- GPU_framebuffer_clear_color(fbl->transparent_accum_fb, clear_color);
- }
-
- /* Composite */
- GPU_framebuffer_bind(fbl->composite_fb);
-
- if (DRW_state_is_scene_render()) {
- float clear_color[4];
- workbench_clear_color_get(clear_color);
- GPU_framebuffer_clear_color(fbl->composite_fb, clear_color);
- }
-
- DRW_draw_pass(psl->composite_pass);
- DRW_draw_pass(psl->volume_pass);
-
- /* Only when clipping is enabled. */
- if (psl->background_pass) {
- DRW_draw_pass(psl->background_pass);
- }
-
- /* Color correct and Anti aliasing */
- workbench_aa_draw_pass(vedata, e_data.composite_buffer_tx);
-}
-
-void workbench_forward_draw_finish(WORKBENCH_Data *vedata)
-{
- WORKBENCH_StorageList *stl = vedata->stl;
- WORKBENCH_PrivateData *wpd = stl->g_data;
-
- workbench_private_data_free(wpd);
- workbench_volume_smoke_textures_free(wpd);
-}
diff --git a/source/blender/draw/engines/workbench/workbench_materials.c b/source/blender/draw/engines/workbench/workbench_materials.c
index 5f1e3461d9f..246f5f88045 100644
--- a/source/blender/draw/engines/workbench/workbench_materials.c
+++ b/source/blender/draw/engines/workbench/workbench_materials.c
@@ -22,6 +22,8 @@
#include "workbench_private.h"
+#include "BLI_memblock.h"
+
#include "BKE_image.h"
#include "BKE_node.h"
@@ -31,310 +33,78 @@
#include "DNA_node_types.h"
#include "DNA_mesh_types.h"
+#include "GPU_uniformbuffer.h"
+
#include "ED_uvedit.h"
#define HSV_SATURATION 0.5
#define HSV_VALUE 0.8
-void workbench_material_update_data(WORKBENCH_PrivateData *wpd,
- Object *ob,
- Material *mat,
- WORKBENCH_MaterialData *data,
- int color_type)
+void workbench_material_ubo_data(WORKBENCH_PrivateData *wpd,
+ Object *ob,
+ Material *mat,
+ WORKBENCH_UBO_Material *data,
+ eV3DShadingColorType color_type)
{
- data->metallic = 0.0f;
- data->roughness = 0.632455532f; /* sqrtf(0.4f); */
- data->alpha = wpd->shading.xray_alpha;
+ float metallic = 0.0f;
+ float roughness = 0.632455532f; /* sqrtf(0.4f); */
+ float alpha = wpd->shading.xray_alpha;
- if (color_type == V3D_SHADING_SINGLE_COLOR) {
- copy_v3_v3(data->base_color, wpd->shading.single_color);
- }
- else if (color_type == V3D_SHADING_ERROR_COLOR) {
- copy_v3_fl3(data->base_color, 0.8, 0.0, 0.8);
- }
- else if (color_type == V3D_SHADING_RANDOM_COLOR) {
- uint hash = BLI_ghashutil_strhash_p_murmur(ob->id.name);
- if (ob->id.lib) {
- hash = (hash * 13) ^ BLI_ghashutil_strhash_p_murmur(ob->id.lib->name);
- }
-
- float hue = BLI_hash_int_01(hash);
- float hsv[3] = {hue, HSV_SATURATION, HSV_VALUE};
- hsv_to_rgb_v(hsv, data->base_color);
- }
- else if (ELEM(color_type, V3D_SHADING_OBJECT_COLOR, V3D_SHADING_VERTEX_COLOR)) {
- data->alpha *= ob->color[3];
- copy_v3_v3(data->base_color, ob->color);
- }
- else {
- /* V3D_SHADING_MATERIAL_COLOR or V3D_SHADING_TEXTURE_COLOR */
- if (mat) {
- data->alpha *= mat->a;
- copy_v3_v3(data->base_color, &mat->r);
- if (workbench_is_specular_highlight_enabled(wpd)) {
- data->metallic = mat->metallic;
- data->roughness = sqrtf(mat->roughness); /* Remap to disney roughness. */
- }
- }
- else {
- copy_v3_fl(data->base_color, 0.8f);
- }
- }
-}
-
-char *workbench_material_build_defines(WORKBENCH_PrivateData *wpd,
- bool is_uniform_color,
- bool is_hair,
- bool is_tiled,
- const WORKBENCH_ColorOverride color_override)
-{
- char *str = NULL;
- bool use_textures = (wpd->shading.color_type == V3D_SHADING_TEXTURE_COLOR) && !is_uniform_color;
- bool use_vertex_colors = (wpd->shading.color_type == V3D_SHADING_VERTEX_COLOR) &&
- !is_uniform_color;
-
- switch (color_override) {
- case WORKBENCH_COLOR_OVERRIDE_TEXTURE:
- use_textures = true;
- use_vertex_colors = false;
- is_hair = false;
- break;
- case WORKBENCH_COLOR_OVERRIDE_VERTEX:
- use_textures = false;
- use_vertex_colors = true;
- is_hair = false;
- is_tiled = false;
+ switch (color_type) {
+ case V3D_SHADING_SINGLE_COLOR:
+ copy_v3_v3(data->base_color, wpd->shading.single_color);
break;
- case WORKBENCH_COLOR_OVERRIDE_OFF:
- break;
- }
-
- DynStr *ds = BLI_dynstr_new();
-
- if (wpd->shading.flag & V3D_SHADING_OBJECT_OUTLINE) {
- BLI_dynstr_append(ds, "#define V3D_SHADING_OBJECT_OUTLINE\n");
- }
- if (wpd->shading.flag & V3D_SHADING_SHADOW) {
- BLI_dynstr_append(ds, "#define V3D_SHADING_SHADOW\n");
- }
- if (SSAO_ENABLED(wpd) || CURVATURE_ENABLED(wpd)) {
- BLI_dynstr_append(ds, "#define WB_CAVITY\n");
- }
- if (workbench_is_specular_highlight_enabled(wpd)) {
- BLI_dynstr_append(ds, "#define V3D_SHADING_SPECULAR_HIGHLIGHT\n");
- }
- if (STUDIOLIGHT_ENABLED(wpd)) {
- BLI_dynstr_append(ds, "#define V3D_LIGHTING_STUDIO\n");
- }
- if (FLAT_ENABLED(wpd)) {
- BLI_dynstr_append(ds, "#define V3D_LIGHTING_FLAT\n");
- }
- if (MATCAP_ENABLED(wpd)) {
- BLI_dynstr_append(ds, "#define V3D_LIGHTING_MATCAP\n");
- }
- if (OBJECT_ID_PASS_ENABLED(wpd)) {
- BLI_dynstr_append(ds, "#define OBJECT_ID_PASS_ENABLED\n");
- }
- if (workbench_is_matdata_pass_enabled(wpd)) {
- BLI_dynstr_append(ds, "#define MATDATA_PASS_ENABLED\n");
- }
- if (NORMAL_VIEWPORT_PASS_ENABLED(wpd)) {
- BLI_dynstr_append(ds, "#define NORMAL_VIEWPORT_PASS_ENABLED\n");
- }
- if (use_vertex_colors) {
- BLI_dynstr_append(ds, "#define V3D_SHADING_VERTEX_COLOR\n");
- }
- if (use_textures) {
- BLI_dynstr_append(ds, "#define V3D_SHADING_TEXTURE_COLOR\n");
- }
- if (NORMAL_ENCODING_ENABLED()) {
- BLI_dynstr_append(ds, "#define WORKBENCH_ENCODE_NORMALS\n");
- }
- if (is_hair) {
- BLI_dynstr_append(ds, "#define HAIR_SHADER\n");
- }
- if (use_textures && is_tiled) {
- BLI_dynstr_append(ds, "#define TEXTURE_IMAGE_ARRAY\n");
- }
-
- str = BLI_dynstr_get_cstring(ds);
- BLI_dynstr_free(ds);
- return str;
-}
-
-uint workbench_material_get_hash(WORKBENCH_MaterialData *mat, bool is_ghost)
-{
- union {
- struct {
- /* WHATCH: Keep in sync with View3DShading.color_type max value. */
- uchar color_type;
- uchar diff_r;
- uchar diff_g;
- uchar diff_b;
-
- uchar alpha;
- uchar ghost;
- uchar metal;
- uchar roughness;
-
- void *ima;
- };
- /* HACK to ensure input is 4 uint long. */
- uint a[4];
- } input = {.color_type = (uchar)(mat->color_type),
- .diff_r = (uchar)(mat->base_color[0] * 0xFF),
- .diff_g = (uchar)(mat->base_color[1] * 0xFF),
- .diff_b = (uchar)(mat->base_color[2] * 0xFF),
-
- .alpha = (uint)(mat->alpha * 0xFF),
- .ghost = (uchar)is_ghost,
- .metal = (uchar)(mat->metallic * 0xFF),
- .roughness = (uchar)(mat->roughness * 0xFF),
-
- .ima = mat->ima};
-
- BLI_assert(sizeof(input) == sizeof(uint) * 4);
-
- return BLI_ghashutil_uinthash_v4((uint *)&input);
-}
-
-int workbench_material_get_composite_shader_index(WORKBENCH_PrivateData *wpd)
-{
- /* NOTE: change MAX_COMPOSITE_SHADERS accordingly when modifying this function. */
- int index = 0;
- /* 2 bits FLAT/STUDIO/MATCAP + Specular highlight */
- index = wpd->shading.light;
- SET_FLAG_FROM_TEST(index, wpd->shading.flag & V3D_SHADING_SHADOW, 1 << 2);
- SET_FLAG_FROM_TEST(index, wpd->shading.flag & V3D_SHADING_CAVITY, 1 << 3);
- SET_FLAG_FROM_TEST(index, wpd->shading.flag & V3D_SHADING_OBJECT_OUTLINE, 1 << 4);
- SET_FLAG_FROM_TEST(index, workbench_is_matdata_pass_enabled(wpd), 1 << 5);
- SET_FLAG_FROM_TEST(index, workbench_is_specular_highlight_enabled(wpd), 1 << 6);
- BLI_assert(index < MAX_COMPOSITE_SHADERS);
- return index;
-}
-
-int workbench_material_get_prepass_shader_index(WORKBENCH_PrivateData *wpd,
- bool is_uniform_color,
- bool is_hair,
- bool is_tiled,
- const WORKBENCH_ColorOverride color_override)
-{
- bool use_textures = (wpd->shading.color_type == V3D_SHADING_TEXTURE_COLOR) && !is_uniform_color;
- bool use_vertex_colors = (wpd->shading.color_type == V3D_SHADING_VERTEX_COLOR) &&
- !is_uniform_color;
-
- switch (color_override) {
- case WORKBENCH_COLOR_OVERRIDE_TEXTURE:
- use_textures = true;
- use_vertex_colors = false;
- break;
- case WORKBENCH_COLOR_OVERRIDE_VERTEX:
- use_textures = false;
- use_vertex_colors = true;
- is_tiled = false;
- break;
- case WORKBENCH_COLOR_OVERRIDE_OFF:
- break;
- }
-
- /* NOTE: change MAX_PREPASS_SHADERS accordingly when modifying this function. */
- int index = 0;
- SET_FLAG_FROM_TEST(index, is_hair, 1 << 0);
- SET_FLAG_FROM_TEST(index, workbench_is_matdata_pass_enabled(wpd), 1 << 1);
- SET_FLAG_FROM_TEST(index, OBJECT_ID_PASS_ENABLED(wpd), 1 << 2);
- SET_FLAG_FROM_TEST(index, NORMAL_VIEWPORT_PASS_ENABLED(wpd), 1 << 3);
- SET_FLAG_FROM_TEST(index, MATCAP_ENABLED(wpd), 1 << 4);
- SET_FLAG_FROM_TEST(index, use_textures, 1 << 5);
- SET_FLAG_FROM_TEST(index, use_vertex_colors, 1 << 6);
- SET_FLAG_FROM_TEST(index, is_tiled && use_textures, 1 << 7);
- BLI_assert(index < MAX_PREPASS_SHADERS);
- return index;
-}
-
-int workbench_material_get_accum_shader_index(WORKBENCH_PrivateData *wpd,
- bool is_uniform_color,
- bool is_hair,
- bool is_tiled,
- const WORKBENCH_ColorOverride color_override)
-{
- bool use_textures = (wpd->shading.color_type == V3D_SHADING_TEXTURE_COLOR) && !is_uniform_color;
- bool use_vertex_colors = (wpd->shading.color_type == V3D_SHADING_VERTEX_COLOR) &&
- !is_uniform_color;
-
- switch (color_override) {
- case WORKBENCH_COLOR_OVERRIDE_TEXTURE:
- use_textures = true;
- use_vertex_colors = false;
- is_hair = false;
+ case V3D_SHADING_RANDOM_COLOR: {
+ uint hash = BLI_ghashutil_strhash_p_murmur(ob->id.name);
+ if (ob->id.lib) {
+ hash = (hash * 13) ^ BLI_ghashutil_strhash_p_murmur(ob->id.lib->name);
+ }
+ float hue = BLI_hash_int_01(hash);
+ float hsv[3] = {hue, HSV_SATURATION, HSV_VALUE};
+ hsv_to_rgb_v(hsv, data->base_color);
break;
- case WORKBENCH_COLOR_OVERRIDE_VERTEX:
- use_textures = false;
- use_vertex_colors = true;
- is_hair = false;
- is_tiled = false;
+ }
+ case V3D_SHADING_OBJECT_COLOR:
+ case V3D_SHADING_VERTEX_COLOR:
+ alpha *= ob->color[3];
+ copy_v3_v3(data->base_color, ob->color);
break;
- case WORKBENCH_COLOR_OVERRIDE_OFF:
+ case V3D_SHADING_MATERIAL_COLOR:
+ case V3D_SHADING_TEXTURE_COLOR:
+ default:
+ if (mat) {
+ alpha *= mat->a;
+ copy_v3_v3(data->base_color, &mat->r);
+ metallic = mat->metallic;
+ roughness = sqrtf(mat->roughness); /* Remap to disney roughness. */
+ }
+ else {
+ copy_v3_fl(data->base_color, 0.8f);
+ }
break;
}
- /* NOTE: change MAX_ACCUM_SHADERS accordingly when modifying this function. */
- int index = 0;
- /* 2 bits FLAT/STUDIO/MATCAP + Specular highlight */
- index = wpd->shading.light;
- SET_FLAG_FROM_TEST(index, use_textures, 1 << 2);
- SET_FLAG_FROM_TEST(index, use_vertex_colors, 1 << 3);
- SET_FLAG_FROM_TEST(index, is_hair, 1 << 4);
- /* 1 bits SHADOWS (only facing factor) */
- SET_FLAG_FROM_TEST(index, SHADOW_ENABLED(wpd), 1 << 5);
- SET_FLAG_FROM_TEST(index, workbench_is_specular_highlight_enabled(wpd), 1 << 6);
- SET_FLAG_FROM_TEST(index, is_tiled && use_textures, 1 << 7);
- BLI_assert(index < MAX_ACCUM_SHADERS);
- return index;
+ uint32_t packed_metallic = unit_float_to_uchar_clamp(metallic);
+ uint32_t packed_roughness = unit_float_to_uchar_clamp(roughness);
+ uint32_t packed_alpha = unit_float_to_uchar_clamp(alpha);
+ data->packed_data = (packed_alpha << 16u) | (packed_roughness << 8u) | packed_metallic;
}
-eV3DShadingColorType workbench_material_determine_color_type(WORKBENCH_PrivateData *wpd,
- Image *ima,
- Object *ob,
- bool use_sculpt_pbvh)
+/* Return correct material or empty default material if slot is empty. */
+BLI_INLINE Material *workbench_object_material_get(Object *ob, int mat_nr)
{
- eV3DShadingColorType color_type = wpd->shading.color_type;
- const Mesh *me = (ob->type == OB_MESH) ? ob->data : NULL;
-
- if ((color_type == V3D_SHADING_TEXTURE_COLOR) &&
- (ima == NULL || use_sculpt_pbvh || (ob->dt < OB_TEXTURE))) {
- color_type = V3D_SHADING_MATERIAL_COLOR;
+ Material *ma = BKE_object_material_get(ob, mat_nr);
+ if (ma == NULL) {
+ ma = BKE_material_default_empty();
}
- if (color_type == V3D_SHADING_VERTEX_COLOR && (me == NULL || me->mloopcol == NULL)) {
- color_type = V3D_SHADING_OBJECT_COLOR;
- }
-
- switch (workbench_object_color_override_get(ob)) {
- /* Force V3D_SHADING_TEXTURE_COLOR for active object when in texture painting
- * no matter the shading color that the user has chosen, when there is no
- * texture we will render the object with the error color */
- case WORKBENCH_COLOR_OVERRIDE_TEXTURE:
- color_type = ima ? V3D_SHADING_TEXTURE_COLOR : V3D_SHADING_ERROR_COLOR;
- break;
-
- /* Force V3D_SHADING_VERTEX_COLOR for active object when in vertex painting
- * no matter the shading color that the user has chosen, when there is no
- * vertex color we will render the object with the error color */
- case WORKBENCH_COLOR_OVERRIDE_VERTEX:
- color_type = V3D_SHADING_VERTEX_COLOR;
- break;
-
- case WORKBENCH_COLOR_OVERRIDE_OFF:
- break;
- }
-
- return color_type;
+ return ma;
}
-void workbench_material_get_image_and_mat(
- Object *ob, int mat_nr, Image **r_image, ImageUser **r_iuser, int *r_interp, Material **r_mat)
+BLI_INLINE void workbench_material_get_image(
+ Object *ob, int mat_nr, Image **r_image, ImageUser **r_iuser, int *r_interp)
{
bNode *node;
- *r_mat = BKE_object_material_get(ob, mat_nr);
+
ED_object_get_active_image(ob, mat_nr, r_image, r_iuser, &node, NULL);
if (node && *r_image) {
switch (node->type) {
@@ -358,53 +128,170 @@ void workbench_material_get_image_and_mat(
}
}
-void workbench_material_shgroup_uniform(WORKBENCH_PrivateData *wpd,
- DRWShadingGroup *grp,
- WORKBENCH_MaterialData *material,
- Object *ob,
- const bool deferred,
- const bool is_tiled,
- const int interp)
+/* Return true if the current material ubo has changed and needs to be rebind. */
+BLI_INLINE bool workbench_material_chunk_select(WORKBENCH_PrivateData *wpd,
+ uint32_t id,
+ uint32_t *r_mat_id)
{
- if (deferred && !workbench_is_matdata_pass_enabled(wpd)) {
- return;
+ bool resource_changed = false;
+ /* Divide in chunks of MAX_MATERIAL. */
+ uint32_t chunk = id >> 12u;
+ *r_mat_id = id & 0xFFFu;
+ /* We need to add a new chunk. */
+ while (chunk >= wpd->material_chunk_count) {
+ wpd->material_chunk_count++;
+ wpd->material_ubo_data_curr = BLI_memblock_alloc(wpd->material_ubo_data);
+ wpd->material_ubo_curr = workbench_material_ubo_alloc(wpd);
+ wpd->material_chunk_curr = chunk;
+ resource_changed = true;
+ }
+ /* We need to go back to a previous chunk. */
+ if (wpd->material_chunk_curr != chunk) {
+ wpd->material_ubo_data_curr = BLI_memblock_elem_get(wpd->material_ubo_data, 0, chunk);
+ wpd->material_ubo_curr = BLI_memblock_elem_get(wpd->material_ubo, 0, chunk);
+ wpd->material_chunk_curr = chunk;
+ resource_changed = true;
}
+ return resource_changed;
+}
- const bool use_highlight = workbench_is_specular_highlight_enabled(wpd);
- const bool use_texture = (V3D_SHADING_TEXTURE_COLOR == workbench_material_determine_color_type(
- wpd, material->ima, ob, false));
- if (use_texture) {
- if (is_tiled) {
- GPUTexture *array_tex = GPU_texture_from_blender(
- material->ima, material->iuser, NULL, GL_TEXTURE_2D_ARRAY);
- GPUTexture *data_tex = GPU_texture_from_blender(
- material->ima, material->iuser, NULL, GL_TEXTURE_1D_ARRAY);
- DRW_shgroup_uniform_texture(grp, "image_tile_array", array_tex);
- DRW_shgroup_uniform_texture(grp, "image_tile_data", data_tex);
- }
- else {
- GPUTexture *tex = GPU_texture_from_blender(
- material->ima, material->iuser, NULL, GL_TEXTURE_2D);
- DRW_shgroup_uniform_texture(grp, "image", tex);
+DRWShadingGroup *workbench_material_setup_ex(WORKBENCH_PrivateData *wpd,
+ Object *ob,
+ int mat_nr,
+ eV3DShadingColorType color_type,
+ bool hair,
+ bool *r_transp)
+{
+ Image *ima = NULL;
+ ImageUser *iuser = NULL;
+ int interp;
+ const bool infront = (ob->dtx & OB_DRAWXRAY) != 0;
+
+ if (color_type == V3D_SHADING_TEXTURE_COLOR) {
+ workbench_material_get_image(ob, mat_nr, &ima, &iuser, &interp);
+ if (ima == NULL) {
+ /* Fallback to material color. */
+ color_type = V3D_SHADING_MATERIAL_COLOR;
}
- DRW_shgroup_uniform_bool_copy(
- grp, "imagePremultiplied", (material->ima->alpha_mode == IMA_ALPHA_PREMUL));
- DRW_shgroup_uniform_bool_copy(grp, "imageNearest", (interp == SHD_INTERP_CLOSEST));
}
- DRW_shgroup_uniform_vec4(grp, "materialColorAndMetal", material->base_color, 1);
+ switch (color_type) {
+ case V3D_SHADING_TEXTURE_COLOR: {
+ 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.
+ * This means they are mutually exclusive. */
+ BLI_assert(
+ ELEM(wpd->shading.color_type, V3D_SHADING_MATERIAL_COLOR, V3D_SHADING_TEXTURE_COLOR));
+
+ Material *ma = workbench_object_material_get(ob, mat_nr);
+
+ 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;
+ }
- if (use_highlight) {
- DRW_shgroup_uniform_float(grp, "materialRoughness", &material->roughness, 1);
+ 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)) {
+ return *grp_mat;
+ }
+
+ uint32_t mat_id, id = wpd->material_index++;
+
+ workbench_material_chunk_select(wpd, id, &mat_id);
+ workbench_material_ubo_data(wpd, ob, ma, &wpd->material_ubo_data_curr[mat_id], color_type);
+
+ DRWShadingGroup *grp = prepass->common_shgrp;
+ *grp_mat = grp = DRW_shgroup_create_sub(grp);
+ DRW_shgroup_uniform_block(grp, "material_block", wpd->material_ubo_curr);
+ DRW_shgroup_uniform_int_copy(grp, "materialIndex", mat_id);
+ return grp;
+ }
+ case V3D_SHADING_VERTEX_COLOR: {
+ const bool transp = wpd->shading.xray_alpha < 1.0f;
+ DRWShadingGroup *grp = wpd->prepass[transp][infront][hair].vcol_shgrp;
+ return grp;
+ }
+ default: {
+ /* For now, we use the same ubo for material and object coloring but with different indices.
+ * This means they are mutually exclusive. */
+ BLI_assert(
+ !ELEM(wpd->shading.color_type, V3D_SHADING_MATERIAL_COLOR, V3D_SHADING_TEXTURE_COLOR));
+
+ uint32_t mat_id, id = DRW_object_resource_id_get(ob);
+
+ bool resource_changed = workbench_material_chunk_select(wpd, id, &mat_id);
+ workbench_material_ubo_data(wpd, ob, NULL, &wpd->material_ubo_data_curr[mat_id], color_type);
+
+ const bool transp = wpd->shading.xray_alpha < 1.0f || ob->color[3] < 1.0f;
+ DRWShadingGroup *grp = wpd->prepass[transp][infront][hair].common_shgrp;
+ if (resource_changed) {
+ 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;
+ }
}
}
-void workbench_material_copy(WORKBENCH_MaterialData *dest_material,
- const WORKBENCH_MaterialData *source_material)
+/* If ima is null, search appropriate image node but will fallback to purple texture otherwise. */
+DRWShadingGroup *workbench_image_setup_ex(WORKBENCH_PrivateData *wpd,
+ Object *ob,
+ int mat_nr,
+ Image *ima,
+ ImageUser *iuser,
+ int interp,
+ bool hair)
{
- copy_v3_v3(dest_material->base_color, source_material->base_color);
- dest_material->metallic = source_material->metallic;
- dest_material->roughness = source_material->roughness;
- dest_material->ima = source_material->ima;
- dest_material->iuser = source_material->iuser;
+ GPUTexture *tex = NULL, *tex_tile_data = NULL;
+
+ if (ima == NULL) {
+ workbench_material_get_image(ob, mat_nr, &ima, &iuser, &interp);
+ }
+
+ if (ima) {
+ if (ima->source == IMA_SRC_TILED) {
+ tex = GPU_texture_from_blender(ima, iuser, NULL, GL_TEXTURE_2D_ARRAY);
+ tex_tile_data = GPU_texture_from_blender(ima, iuser, NULL, GL_TEXTURE_1D_ARRAY);
+ }
+ else {
+ tex = GPU_texture_from_blender(ima, iuser, NULL, GL_TEXTURE_2D);
+ }
+ }
+
+ if (tex == NULL) {
+ printf("Image not foudn\n");
+ tex = wpd->dummy_image_tx;
+ }
+
+ const bool infront = (ob->dtx & OB_DRAWXRAY) != 0;
+ const bool transp = wpd->shading.xray_alpha < 1.0f;
+ WORKBENCH_Prepass *prepass = &wpd->prepass[transp][infront][hair];
+
+ DRWShadingGroup **grp_tex = NULL;
+ /* A hashmap stores image shgroups to pack all similar drawcalls together. */
+ if (BLI_ghash_ensure_p(prepass->material_hash, tex, (void ***)&grp_tex)) {
+ return *grp_tex;
+ }
+
+ DRWShadingGroup *grp = (tex_tile_data) ? prepass->image_tiled_shgrp : prepass->image_shgrp;
+
+ *grp_tex = grp = DRW_shgroup_create_sub(grp);
+ if (tex_tile_data) {
+ DRW_shgroup_uniform_texture_persistent(grp, "imageTileArray", tex);
+ DRW_shgroup_uniform_texture_persistent(grp, "imageTileData", tex_tile_data);
+ }
+ else {
+ DRW_shgroup_uniform_texture_persistent(grp, "imageTexture", tex);
+ }
+ DRW_shgroup_uniform_bool_copy(grp, "imagePremult", (ima && ima->alpha_mode == IMA_ALPHA_PREMUL));
+ DRW_shgroup_uniform_bool_copy(grp, "imageNearest", (interp == SHD_INTERP_CLOSEST));
+ return grp;
}
diff --git a/source/blender/draw/engines/workbench/workbench_opaque.c b/source/blender/draw/engines/workbench/workbench_opaque.c
new file mode 100644
index 00000000000..abb76550b96
--- /dev/null
+++ b/source/blender/draw/engines/workbench/workbench_opaque.c
@@ -0,0 +1,165 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2020, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ *
+ * Opaque Pieline:
+ *
+ * Use deferred shading to render opaque surfaces.
+ * This decouple the shading cost from scene complexity.
+ *
+ * The rendering is broken down in two passes:
+ * - the pre-pass where we render all the surfaces and output material data.
+ * - the composite pass where we compute the final aspect of the pixels.
+ */
+
+#include "DRW_render.h"
+
+#include "GPU_extensions.h"
+
+#include "workbench_engine.h"
+#include "workbench_private.h"
+
+void workbench_opaque_engine_init(WORKBENCH_Data *data)
+{
+ WORKBENCH_FramebufferList *fbl = data->fbl;
+ WORKBENCH_PrivateData *wpd = data->stl->wpd;
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+ DrawEngineType *owner = (DrawEngineType *)&workbench_opaque_engine_init;
+
+ /* Reused the same textures format for transparent pipeline to share the textures. */
+ const eGPUTextureFormat col_tex_format = GPU_RGBA16F;
+ const eGPUTextureFormat nor_tex_format = NORMAL_ENCODING_ENABLED() ? GPU_RG16F : GPU_RGBA16F;
+
+ wpd->material_buffer_tx = DRW_texture_pool_query_fullscreen(col_tex_format, owner);
+ wpd->normal_buffer_tx = DRW_texture_pool_query_fullscreen(nor_tex_format, owner);
+
+ GPU_framebuffer_ensure_config(&fbl->opaque_fb,
+ {
+ GPU_ATTACHMENT_TEXTURE(dtxl->depth),
+ GPU_ATTACHMENT_TEXTURE(wpd->material_buffer_tx),
+ GPU_ATTACHMENT_TEXTURE(wpd->normal_buffer_tx),
+ GPU_ATTACHMENT_TEXTURE(wpd->object_id_tx),
+ });
+}
+
+void workbench_opaque_cache_init(WORKBENCH_Data *data)
+{
+ WORKBENCH_PassList *psl = data->psl;
+ WORKBENCH_PrivateData *wpd = data->stl->wpd;
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+ struct GPUShader *sh;
+ DRWShadingGroup *grp;
+
+ const bool use_matcap = (wpd->shading.light == V3D_LIGHTING_MATCAP);
+
+ {
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
+
+ int opaque = 0;
+ for (int infront = 0; infront < 2; infront++) {
+ DRWPass *pass;
+ if (infront) {
+ DRW_PASS_CREATE(psl->opaque_infront_ps, state | wpd->cull_state | wpd->clip_state);
+ pass = psl->opaque_infront_ps;
+ }
+ else {
+ DRW_PASS_CREATE(psl->opaque_ps, state | wpd->cull_state | wpd->clip_state);
+ pass = psl->opaque_ps;
+ }
+
+ for (int hair = 0; hair < 2; hair++) {
+ wpd->prepass[opaque][infront][hair].material_hash = BLI_ghash_ptr_new(__func__);
+
+ sh = workbench_shader_opaque_get(wpd, hair);
+
+ wpd->prepass[opaque][infront][hair].common_shgrp = grp = DRW_shgroup_create(sh, pass);
+ DRW_shgroup_uniform_block(grp, "material_block", wpd->material_ubo_curr);
+ DRW_shgroup_uniform_int_copy(grp, "materialIndex", -1);
+
+ wpd->prepass[opaque][infront][hair].vcol_shgrp = grp = DRW_shgroup_create(sh, pass);
+ DRW_shgroup_uniform_block_persistent(grp, "material_block", wpd->material_ubo_curr);
+ DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. (uses vcol) */
+
+ sh = workbench_shader_opaque_image_get(wpd, hair, false);
+
+ wpd->prepass[opaque][infront][hair].image_shgrp = grp = DRW_shgroup_create(sh, pass);
+ DRW_shgroup_uniform_block_persistent(grp, "material_block", wpd->material_ubo_curr);
+ DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. */
+ DRW_shgroup_uniform_bool_copy(grp, "useMatcap", use_matcap);
+
+ sh = workbench_shader_opaque_image_get(wpd, hair, true);
+
+ wpd->prepass[opaque][infront][hair].image_tiled_shgrp = grp = DRW_shgroup_create(sh, pass);
+ DRW_shgroup_uniform_block_persistent(grp, "material_block", wpd->material_ubo_curr);
+ DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. */
+ DRW_shgroup_uniform_bool_copy(grp, "useMatcap", use_matcap);
+ }
+ }
+ }
+ {
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_GREATER | DRW_STATE_STENCIL_EQUAL;
+
+ DRW_PASS_CREATE(psl->composite_ps, state);
+
+ sh = workbench_shader_composite_get(wpd);
+
+ grp = DRW_shgroup_create(sh, psl->composite_ps);
+ 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);
+
+ if (STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) {
+ BKE_studiolight_ensure_flag(wpd->studio_light,
+ STUDIOLIGHT_MATCAP_DIFFUSE_GPUTEXTURE |
+ STUDIOLIGHT_MATCAP_SPECULAR_GPUTEXTURE);
+ struct GPUTexture *diff_tx = wpd->studio_light->matcap_diffuse.gputexture;
+ struct GPUTexture *spec_tx = wpd->studio_light->matcap_specular.gputexture;
+ const bool use_spec = workbench_is_specular_highlight_enabled(wpd);
+ spec_tx = (use_spec && spec_tx) ? spec_tx : diff_tx;
+ DRW_shgroup_uniform_texture_persistent(grp, "matcapDiffuseImage", diff_tx);
+ DRW_shgroup_uniform_texture_persistent(grp, "matcapSpecularImage", spec_tx);
+ }
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+
+ if (SHADOW_ENABLED(wpd)) {
+ 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 |
+ DRW_STATE_STENCIL_ALWAYS;
+
+ DRW_PASS_CREATE(psl->merge_infront_ps, state);
+
+ sh = workbench_shader_merge_infront_get(wpd);
+
+ grp = DRW_shgroup_create(sh, psl->merge_infront_ps);
+ 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 bb93864966e..a68b66e0f85 100644
--- a/source/blender/draw/engines/workbench/workbench_private.h
+++ b/source/blender/draw/engines/workbench/workbench_private.h
@@ -34,16 +34,14 @@
#include "workbench_engine.h"
+extern struct DrawEngineType draw_engine_workbench;
+
#define WORKBENCH_ENGINE "BLENDER_WORKBENCH"
-#define MAX_COMPOSITE_SHADERS (1 << 7)
-#define MAX_PREPASS_SHADERS (1 << 8)
-#define MAX_ACCUM_SHADERS (1 << 8)
-#define MAX_CAVITY_SHADERS (1 << 3)
-
-#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)
-#define FLAT_ENABLED(wpd) (wpd->shading.light == V3D_LIGHTING_FLAT)
+
+#define MAX_MATERIAL (1 << 12)
+
+#define DEBUG_SHADOW_VOLUME 0
+
#define STUDIOLIGHT_ENABLED(wpd) (wpd->shading.light == V3D_LIGHTING_STUDIO)
#define MATCAP_ENABLED(wpd) (wpd->shading.light == V3D_LIGHTING_MATCAP)
#define USE_WORLD_ORIENTATION(wpd) ((wpd->shading.flag & V3D_SHADING_WORLD_ORIENTATION) != 0)
@@ -63,45 +61,24 @@
(wpd->shading.cavity_type == V3D_SHADING_CAVITY_BOTH)))
#define CAVITY_ENABLED(wpd) (CURVATURE_ENABLED(wpd) || SSAO_ENABLED(wpd))
#define SHADOW_ENABLED(wpd) (wpd->shading.flag & V3D_SHADING_SHADOW)
-#define GHOST_ENABLED(psl) \
- (!DRW_pass_is_empty(psl->ghost_prepass_pass) || !DRW_pass_is_empty(psl->ghost_prepass_hair_pass))
#define CULL_BACKFACE_ENABLED(wpd) ((wpd->shading.flag & V3D_SHADING_BACKFACE_CULLING) != 0)
-#define OIT_ENABLED(wpd) \
- (ELEM(wpd->shading.color_type, \
- V3D_SHADING_MATERIAL_COLOR, \
- V3D_SHADING_OBJECT_COLOR, \
- V3D_SHADING_TEXTURE_COLOR, \
- V3D_SHADING_VERTEX_COLOR))
-
-#define IS_NAVIGATING(wpd) \
- ((DRW_context_state_get()->rv3d) && \
- (DRW_context_state_get()->rv3d->rflag & (RV3D_NAVIGATING | RV3D_PAINTING)))
#define OBJECT_OUTLINE_ENABLED(wpd) (wpd->shading.flag & V3D_SHADING_OBJECT_OUTLINE)
#define OBJECT_ID_PASS_ENABLED(wpd) (OBJECT_OUTLINE_ENABLED(wpd) || CURVATURE_ENABLED(wpd))
-#define NORMAL_VIEWPORT_COMP_PASS_ENABLED(wpd) \
- (MATCAP_ENABLED(wpd) || STUDIOLIGHT_ENABLED(wpd) || SHADOW_ENABLED(wpd))
-#define NORMAL_VIEWPORT_PASS_ENABLED(wpd) \
- (NORMAL_VIEWPORT_COMP_PASS_ENABLED(wpd) || SSAO_ENABLED(wpd) || CURVATURE_ENABLED(wpd))
#define NORMAL_ENCODING_ENABLED() (true)
-#define WORLD_CLIPPING_ENABLED(wpd) (wpd->world_clip_planes != NULL)
struct RenderEngine;
struct RenderLayer;
struct rcti;
typedef struct WORKBENCH_FramebufferList {
- /* Deferred render buffers */
- struct GPUFrameBuffer *prepass_fb;
- struct GPUFrameBuffer *ghost_prepass_fb;
- struct GPUFrameBuffer *cavity_fb;
- struct GPUFrameBuffer *composite_fb;
- struct GPUFrameBuffer *id_clear_fb;
+ struct GPUFrameBuffer *opaque_fb;
+ struct GPUFrameBuffer *opaque_infront_fb;
- struct GPUFrameBuffer *effect_fb;
- struct GPUFrameBuffer *effect_taa_fb;
- struct GPUFrameBuffer *depth_buffer_fb;
- struct GPUFrameBuffer *color_only_fb;
+ struct GPUFrameBuffer *transp_accum_fb;
+ struct GPUFrameBuffer *transp_accum_infront_fb;
+
+ struct GPUFrameBuffer *id_clear_fb;
struct GPUFrameBuffer *dof_downsample_fb;
struct GPUFrameBuffer *dof_coc_tile_h_fb;
@@ -110,10 +87,9 @@ typedef struct WORKBENCH_FramebufferList {
struct GPUFrameBuffer *dof_blur1_fb;
struct GPUFrameBuffer *dof_blur2_fb;
- /* Forward render buffers */
- struct GPUFrameBuffer *object_outline_fb;
- struct GPUFrameBuffer *transparent_accum_fb;
- struct GPUFrameBuffer *transparent_revealage_fb;
+ struct GPUFrameBuffer *antialiasing_fb;
+ struct GPUFrameBuffer *smaa_edge_fb;
+ struct GPUFrameBuffer *smaa_weight_fb;
} WORKBENCH_FramebufferList;
typedef struct WORKBENCH_TextureList {
@@ -121,34 +97,35 @@ typedef struct WORKBENCH_TextureList {
struct GPUTexture *coc_halfres_tx;
struct GPUTexture *history_buffer_tx;
struct GPUTexture *depth_buffer_tx;
+ struct GPUTexture *smaa_search_tx;
+ struct GPUTexture *smaa_area_tx;
+ struct GPUTexture *dummy_image_tx;
+ struct GPUTexture *dummy_volume_tx;
+ struct GPUTexture *dummy_coba_tx;
} WORKBENCH_TextureList;
typedef struct WORKBENCH_StorageList {
- struct WORKBENCH_PrivateData *g_data;
- struct WORKBENCH_EffectInfo *effects;
+ struct WORKBENCH_PrivateData *wpd;
float *dof_ubo_data;
} WORKBENCH_StorageList;
typedef struct WORKBENCH_PassList {
- /* deferred rendering */
- struct DRWPass *prepass_pass;
- struct DRWPass *prepass_hair_pass;
- struct DRWPass *ghost_prepass_pass;
- struct DRWPass *ghost_prepass_hair_pass;
- struct DRWPass *cavity_pass;
- struct DRWPass *shadow_depth_pass_pass;
- struct DRWPass *shadow_depth_pass_mani_pass;
- struct DRWPass *shadow_depth_fail_pass;
- struct DRWPass *shadow_depth_fail_mani_pass;
- struct DRWPass *shadow_depth_fail_caps_pass;
- struct DRWPass *shadow_depth_fail_caps_mani_pass;
- struct DRWPass *composite_pass;
- struct DRWPass *composite_shadow_pass;
- struct DRWPass *oit_composite_pass;
- struct DRWPass *background_pass;
- struct DRWPass *background_pass_clip;
- struct DRWPass *ghost_resolve_pass;
- struct DRWPass *effect_aa_pass;
+ struct DRWPass *opaque_ps;
+ struct DRWPass *opaque_infront_ps;
+
+ struct DRWPass *transp_resolve_ps;
+ struct DRWPass *transp_accum_ps;
+ struct DRWPass *transp_accum_infront_ps;
+
+ struct DRWPass *shadow_ps[2];
+
+ struct DRWPass *merge_infront_ps;
+
+ struct DRWPass *cavity_ps;
+ struct DRWPass *outline_ps;
+
+ struct DRWPass *composite_ps;
+
struct DRWPass *dof_down_ps;
struct DRWPass *dof_down2_ps;
struct DRWPass *dof_flatten_v_ps;
@@ -158,12 +135,13 @@ typedef struct WORKBENCH_PassList {
struct DRWPass *dof_blur1_ps;
struct DRWPass *dof_blur2_ps;
struct DRWPass *dof_resolve_ps;
- struct DRWPass *volume_pass;
- /* forward rendering */
- struct DRWPass *transparent_accum_pass;
- struct DRWPass *object_outline_pass;
- struct DRWPass *depth_pass;
+ struct DRWPass *volume_ps;
+
+ struct DRWPass *aa_accum_ps;
+ struct DRWPass *aa_edge_ps;
+ struct DRWPass *aa_weight_ps;
+ struct DRWPass *aa_resolve_ps;
} WORKBENCH_PassList;
typedef struct WORKBENCH_Data {
@@ -180,84 +158,164 @@ typedef struct WORKBENCH_UBO_Light {
float diffuse_color[3], wrapped;
} WORKBENCH_UBO_Light;
+typedef struct WORKBENCH_UBO_Material {
+ float base_color[3];
+ /* Packed data into a int. Decoded in the shader. */
+ uint32_t packed_data;
+} WORKBENCH_UBO_Material;
+
typedef struct WORKBENCH_UBO_World {
+ float viewvecs[3][4];
+ 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 num_lights;
- int matcap_orientation;
+
+ int cavity_sample_start;
+ int cavity_sample_end;
+ float cavity_sample_count_inv;
+ float cavity_jitter_scale;
+
+ float cavity_valley_factor;
+ float cavity_ridge_factor;
+ float cavity_attenuation;
+ float cavity_distance;
+
float curvature_ridge;
float curvature_valley;
+ float ui_scale;
+ float _pad0;
+
+ int matcap_orientation;
+ int use_specular; /* Bools are 32bit ints in GLSL. */
+ int _pad1;
+ int _pad2;
} WORKBENCH_UBO_World;
+
BLI_STATIC_ASSERT_ALIGN(WORKBENCH_UBO_World, 16)
+BLI_STATIC_ASSERT_ALIGN(WORKBENCH_UBO_Light, 16)
+BLI_STATIC_ASSERT_ALIGN(WORKBENCH_UBO_Material, 16)
-typedef struct WORKBENCH_PrivateData {
+typedef struct WORKBENCH_Prepass {
+ /** Hash storing shading group for each Material or GPUTexture to reduce state changes. */
struct GHash *material_hash;
- struct GHash *material_transp_hash;
- struct GPUShader *prepass_sh;
- struct GPUShader *prepass_hair_sh;
- struct GPUShader *prepass_uniform_sh;
- struct GPUShader *prepass_uniform_hair_sh;
- struct GPUShader *prepass_textured_sh;
- struct GPUShader *prepass_textured_array_sh;
- struct GPUShader *prepass_vertex_sh;
- struct GPUShader *composite_sh;
- struct GPUShader *background_sh;
- struct GPUShader *transparent_accum_sh;
- struct GPUShader *transparent_accum_hair_sh;
- struct GPUShader *transparent_accum_uniform_sh;
- struct GPUShader *transparent_accum_uniform_hair_sh;
- struct GPUShader *transparent_accum_textured_sh;
- struct GPUShader *transparent_accum_textured_array_sh;
- struct GPUShader *transparent_accum_vertex_sh;
+ /** First common (non-vcol and non-image colored) shading group to created subgroups. */
+ struct DRWShadingGroup *common_shgrp;
+ /** First Vertex Color shading group to created subgroups. */
+ struct DRWShadingGroup *vcol_shgrp;
+ /** First Image shading group to created subgroups. */
+ struct DRWShadingGroup *image_shgrp;
+ /** First UDIM (tiled image) shading group to created subgroups. */
+ struct DRWShadingGroup *image_tiled_shgrp;
+} WORKBENCH_Prepass;
+
+typedef struct WORKBENCH_PrivateData {
+ /** ViewLayerData for faster access. */
+ struct WORKBENCH_ViewLayerData *vldata;
+ /** Copy of draw_ctx->sh_cfg for faster access. */
+ eGPUShaderConfig sh_cfg;
+ /** Global clip and cull states. */
+ DRWState clip_state, cull_state;
+ /** Copy of scene->display.shading or v3d->shading for viewport. */
View3DShading shading;
+ /** Chosen studiolight or matcap. */
StudioLight *studio_light;
+ /** Copy of ctx_draw->scene for faster access. */
+ struct Scene *scene;
+ /** Shorthand version of U global for user preferences. */
const UserDef *preferences;
- /* Does this instance owns the `world_ubo` field.
- * Normally the field is borrowed from `WORKBENCH_WorldData`. In case that
- * there is no World attached to the scene the UBO cannot be cached and should
- * be freed after using. */
- bool is_world_ubo_owner;
+ /** Copy of context mode for faster access. */
+ eContextObjectMode ctx_mode;
+ /** Shorthand for wpd->vldata->world_ubo. */
struct GPUUniformBuffer *world_ubo;
- struct DRWShadingGroup *shadow_shgrp;
- struct DRWShadingGroup *depth_shgrp;
- WORKBENCH_UBO_World world_data;
- float shadow_multiplier;
- float shadow_shift;
- float shadow_focus;
- float cached_shadow_direction[3];
+ /** Background color to clear the color buffer with. */
+ float background_color[4];
+
+ /* Shadow */
+ /** Previous shadow direction to test if shadow has changed. */
+ float shadow_cached_direction[3];
+ /** Current shadow direction in world space. */
+ float shadow_direction_ws[3];
+ /** Shadow precomputed matrices. */
float shadow_mat[4][4];
float shadow_inv[4][4];
- /* Far plane of the view frustum. */
+ /** Far plane of the view frustum. Used for shadow volume extrusion. */
float shadow_far_plane[4];
- /* Near plane corners in shadow space. */
- float shadow_near_corners[4][3];
- /* min and max of shadow_near_corners. allow fast test */
+ /** Min and max of shadow_near_corners. Speed up culling test. */
float shadow_near_min[3];
float shadow_near_max[3];
- /* This is a parallelogram, so only 2 normal and distance to the edges. */
+ /** This is a parallelogram, so only 2 normal and distance to the edges. */
float shadow_near_sides[2][4];
+ /* Shadow shading groups. First array elem is for non-manifold geom and second for manifold. */
+ struct DRWShadingGroup *shadow_pass_grp[2];
+ struct DRWShadingGroup *shadow_fail_grp[2];
+ struct DRWShadingGroup *shadow_fail_caps_grp[2];
+ /** If the shadow has changed direction and ob bboxes needs to be updated. */
bool shadow_changed;
- bool is_playback;
- float (*world_clip_planes)[4];
+ /* Temporal Antialiasing */
+ /** Total number of samples to after which TAA stops accumulating samples. */
+ int taa_sample_len;
+ /** Current TAA sample index in [0..taa_sample_len[ range. */
+ int taa_sample;
+ /** Inverse of taa_sample to divide the accumulation buffer. */
+ float taa_sample_inv;
+ /** If the view has been updated and TAA needs to be reset. */
+ bool view_updated;
+ /** View */
+ struct DRWView *view;
+ /** Last projection matrix to see if view is still valid. */
+ float last_mat[4][4];
+
+ /* Smart Morphological Anti-Aliasing */
+ /** Temp buffers to store edges and weights. */
+ struct GPUTexture *smaa_edge_tx;
+ struct GPUTexture *smaa_weight_tx;
+ /** Weight of the smaa pass. */
+ float smaa_mix_factor;
+
+ /** Opaque pipeline buffers. */
+ struct GPUTexture *material_buffer_tx;
+ struct GPUTexture *composite_buffer_tx;
+ struct GPUTexture *normal_buffer_tx;
+ /** Transparent pipeline buffers. */
+ struct GPUTexture *accum_buffer_tx;
+ struct GPUTexture *reveal_buffer_tx;
+ /** Object IDs buffer for curvature & outline. */
+ struct GPUTexture *object_id_tx;
+
+ /** Prepass infos for each draw types [transparent][infront][hair]. */
+ WORKBENCH_Prepass prepass[2][2][2];
+
+ /* Materials */
+ /** Copy of vldata->material_ubo for faster access. */
+ struct BLI_memblock *material_ubo;
+ /** Copy of vldata->material_ubo_data for faster access. */
+ struct BLI_memblock *material_ubo_data;
+ /** Current material chunk being filled by workbench_material_setup_ex(). */
+ WORKBENCH_UBO_Material *material_ubo_data_curr;
+ struct GPUUniformBuffer *material_ubo_curr;
+ /** Copy of txl->dummy_image_tx for faster access. */
+ struct GPUTexture *dummy_image_tx;
+ /** Total number of used material chunk. */
+ int material_chunk_count;
+ /** Index of current material chunk. */
+ int material_chunk_curr;
+ /** Index of current material inside the material chunk. Only for material coloring mode. */
+ int material_index;
/* Volumes */
- bool volumes_do;
+ /** List of smoke domain textures to free after drawing. */
ListBase smoke_domains;
- /* Ssao */
- float winmat[4][4];
- float viewvecs[3][4];
- float ssao_params[4];
- float ssao_settings[4];
-
- /* Dof */
+ /* Depth of Field */
+ /** Depth of field temp buffers. */
struct GPUTexture *dof_blur_tx;
struct GPUTexture *coc_temp_tx;
struct GPUTexture *coc_tiles_tx[2];
- struct GPUUniformBuffer *dof_ubo;
+ /** Depth of field parameters. */
float dof_aperturesize;
float dof_distance;
float dof_invsensorsize;
@@ -265,37 +323,15 @@ typedef struct WORKBENCH_PrivateData {
float dof_blades;
float dof_rotation;
float dof_ratio;
- bool dof_enabled;
- /* Color Management */
- bool use_color_management;
- bool use_color_render_settings;
+ /** True if any volume needs to be rendered. */
+ bool volumes_do;
+ /** Convenience boolean. */
+ bool dof_enabled;
+ bool is_playback;
+ bool is_navigating;
} WORKBENCH_PrivateData; /* Transient data */
-typedef struct WORKBENCH_EffectInfo {
- /** View */
- struct DRWView *view;
- /** Last projection matrix to see if view is still valid. */
- float last_mat[4][4];
- int jitter_index;
- float taa_mix_factor;
- bool view_updated;
-} WORKBENCH_EffectInfo;
-
-typedef struct WORKBENCH_MaterialData {
- float base_color[3], metallic;
- float roughness, alpha;
- eV3DShadingColorType color_type;
- int interp;
- Image *ima;
- ImageUser *iuser;
-
- /* Linked shgroup for drawing */
- DRWShadingGroup *shgrp;
- /* forward rendering */
- DRWShadingGroup *shgrp_object_outline;
-} WORKBENCH_MaterialData;
-
typedef struct WORKBENCH_ObjectData {
DrawData dd;
@@ -307,20 +343,21 @@ typedef struct WORKBENCH_ObjectData {
bool shadow_bbox_dirty;
} WORKBENCH_ObjectData;
-typedef struct WORKBENCH_WorldData {
- DrawData dd;
- /* The cached `GPUUniformBuffer`, that is reused between draw calls. */
+typedef struct WORKBENCH_ViewLayerData {
+ /** Depth of field sample location array.*/
+ struct GPUUniformBuffer *dof_sample_ubo;
+ /** All constant data used for a render loop.*/
struct GPUUniformBuffer *world_ubo;
-} WORKBENCH_WorldData;
-
-/* Enumeration containing override options for base color rendering.
- * This is used to during painting to force the base color to show what you are
- * painting using the selected lighting model. */
-typedef enum WORKBENCH_ColorOverride {
- WORKBENCH_COLOR_OVERRIDE_OFF = 0,
- WORKBENCH_COLOR_OVERRIDE_TEXTURE = CTX_MODE_PAINT_TEXTURE,
- WORKBENCH_COLOR_OVERRIDE_VERTEX = CTX_MODE_PAINT_VERTEX,
-} WORKBENCH_ColorOverride;
+ /** Cavity sample location array.*/
+ struct GPUUniformBuffer *cavity_sample_ubo;
+ /** Blue noise texture used to randomize the sampling of some effects.*/
+ struct GPUTexture *cavity_jitter_tx;
+ /** Materials ubos allocated in a memblock for easy bookeeping. */
+ struct BLI_memblock *material_ubo;
+ struct BLI_memblock *material_ubo_data;
+ /** Number of samples for which cavity_sample_ubo is valid. */
+ int cavity_sample_count;
+} WORKBENCH_ViewLayerData;
/* inline helper functions */
BLI_INLINE bool workbench_is_specular_highlight_enabled(WORKBENCH_PrivateData *wpd)
@@ -333,234 +370,129 @@ BLI_INLINE bool workbench_is_specular_highlight_enabled(WORKBENCH_PrivateData *w
return false;
}
-BLI_INLINE bool workbench_is_taa_enabled(WORKBENCH_PrivateData *wpd)
-{
- if (DRW_state_is_image_render()) {
- const DRWContextState *draw_ctx = DRW_context_state_get();
- if (draw_ctx->v3d) {
- return draw_ctx->scene->display.viewport_aa > SCE_DISPLAY_AA_FXAA;
- }
- else {
- return draw_ctx->scene->display.render_aa > SCE_DISPLAY_AA_FXAA;
- }
- }
- else {
- return !(IS_NAVIGATING(wpd) || wpd->is_playback) &&
- wpd->preferences->viewport_aa > SCE_DISPLAY_AA_FXAA;
- }
-}
-
-BLI_INLINE bool workbench_is_fxaa_enabled(WORKBENCH_PrivateData *wpd)
-{
- if (DRW_state_is_image_render()) {
- const DRWContextState *draw_ctx = DRW_context_state_get();
- if (draw_ctx->v3d) {
- return draw_ctx->scene->display.viewport_aa == SCE_DISPLAY_AA_FXAA;
- }
- else {
- return draw_ctx->scene->display.render_aa == SCE_DISPLAY_AA_FXAA;
- }
- }
- else {
- if (wpd->preferences->viewport_aa == SCE_DISPLAY_AA_FXAA) {
- return true;
- }
-
- /* when navigating or animation playback use FXAA if scene uses TAA. */
- return (IS_NAVIGATING(wpd) || wpd->is_playback) &&
- wpd->preferences->viewport_aa > SCE_DISPLAY_AA_FXAA;
- }
-}
-
-/** Is texture paint mode enabled (globally) */
-BLI_INLINE bool workbench_is_in_texture_paint_mode(void)
-{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- return draw_ctx->object_mode == OB_MODE_TEXTURE_PAINT;
-}
-
-/** Is vertex paint mode enabled (globally) */
-BLI_INLINE bool workbench_is_in_vertex_paint_mode(void)
-{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- return draw_ctx->object_mode == OB_MODE_VERTEX_PAINT;
-}
-
-/* Must the `View3DShading.color_type` be overriden for the given object. */
-BLI_INLINE WORKBENCH_ColorOverride workbench_object_color_override_get(Object *ob)
-{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- if (ob->type == OB_MESH && (draw_ctx->obact == ob)) {
- const enum eContextObjectMode mode = CTX_data_mode_enum_ex(
- draw_ctx->object_edit, draw_ctx->obact, draw_ctx->object_mode);
- if (mode == CTX_MODE_PAINT_TEXTURE) {
- return WORKBENCH_COLOR_OVERRIDE_TEXTURE;
- }
- else if (mode == CTX_MODE_PAINT_VERTEX) {
- return WORKBENCH_COLOR_OVERRIDE_VERTEX;
- }
- }
-
- return WORKBENCH_COLOR_OVERRIDE_OFF;
-}
-
-BLI_INLINE bool workbench_is_matdata_pass_enabled(WORKBENCH_PrivateData *wpd)
-{
- return (wpd->shading.color_type != V3D_SHADING_SINGLE_COLOR || MATCAP_ENABLED(wpd)) ||
- workbench_is_in_texture_paint_mode() || workbench_is_in_vertex_paint_mode();
-}
-
-/**
- * Get the default texture format to be used by the color and history buffers.
- *
- * Use GPU_RGBA16F for final renderings and for drawing textures. This
- * allows displaying HDRI textures. Vertex Colors uses GPU_RGBA16 to resolve
- * color banding issues (T66100). All other modes use GPU_RGBA8 to reduce
- * bandwidth and gpu memory.
- */
-BLI_INLINE eGPUTextureFormat workbench_color_texture_format(const WORKBENCH_PrivateData *wpd)
-{
- eGPUTextureFormat result;
- if (DRW_state_is_image_render() || workbench_is_in_texture_paint_mode() ||
- TEXTURE_DRAWING_ENABLED(wpd)) {
- result = GPU_RGBA16F;
- }
- else {
- result = GPU_RGBA16;
- }
- return result;
-}
-
-/* workbench_deferred.c */
-void workbench_deferred_engine_init(WORKBENCH_Data *vedata);
-void workbench_deferred_engine_free(void);
-void workbench_deferred_draw_scene(WORKBENCH_Data *vedata);
-void workbench_deferred_draw_finish(WORKBENCH_Data *vedata);
-void workbench_deferred_cache_init(WORKBENCH_Data *vedata);
-void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob);
-void workbench_deferred_cache_finish(WORKBENCH_Data *vedata);
-
-/* workbench_forward.c */
-void workbench_forward_engine_init(WORKBENCH_Data *vedata);
-void workbench_forward_engine_free(void);
-void workbench_forward_draw_scene(WORKBENCH_Data *vedata);
-void workbench_forward_draw_finish(WORKBENCH_Data *vedata);
-void workbench_forward_cache_init(WORKBENCH_Data *vedata);
-void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob);
-void workbench_forward_cache_finish(WORKBENCH_Data *vedata);
-
-/* For OIT in deferred */
-void workbench_forward_outline_shaders_ensure(WORKBENCH_PrivateData *wpd, eGPUShaderConfig sh_cfg);
-void workbench_forward_choose_shaders(WORKBENCH_PrivateData *wpd, eGPUShaderConfig sh_cfg);
-WORKBENCH_MaterialData *workbench_forward_get_or_create_material_data(
- WORKBENCH_Data *vedata,
- Object *ob,
- Material *mat,
- Image *ima,
- ImageUser *iuser,
- eV3DShadingColorType color_type,
- int interp);
-
-/* workbench_effect_aa.c */
-void workbench_aa_create_pass(WORKBENCH_Data *vedata, GPUTexture **tx);
-void workbench_aa_draw_pass(WORKBENCH_Data *vedata, GPUTexture *tx);
-
-/* workbench_effect_fxaa.c */
-void workbench_fxaa_engine_init(void);
-void workbench_fxaa_engine_free(void);
-DRWPass *workbench_fxaa_create_pass(GPUTexture **color_buffer_tx);
-
-/* workbench_effect_taa.c */
-void workbench_taa_engine_init(WORKBENCH_Data *vedata);
-void workbench_taa_engine_free(void);
-DRWPass *workbench_taa_create_pass(WORKBENCH_Data *vedata, GPUTexture **color_buffer_tx);
-void workbench_taa_draw_scene_start(WORKBENCH_Data *vedata);
-void workbench_taa_draw_scene_end(WORKBENCH_Data *vedata);
-void workbench_taa_view_updated(WORKBENCH_Data *vedata);
-int workbench_taa_calculate_num_iterations(WORKBENCH_Data *vedata);
-int workbench_num_viewport_rendering_iterations(WORKBENCH_Data *vedata);
-
+/* workbench_opaque.c */
+void workbench_opaque_engine_init(WORKBENCH_Data *data);
+void workbench_opaque_cache_init(WORKBENCH_Data *data);
+
+/* workbench_transparent.c */
+void workbench_transparent_engine_init(WORKBENCH_Data *data);
+void workbench_transparent_cache_init(WORKBENCH_Data *data);
+void workbench_transparent_draw_depth_pass(WORKBENCH_Data *data);
+
+/* workbench_shadow.c */
+void workbench_shadow_data_update(WORKBENCH_PrivateData *wpd, WORKBENCH_UBO_World *wd);
+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);
+GPUShader *workbench_shader_composite_get(WORKBENCH_PrivateData *wpd);
+GPUShader *workbench_shader_merge_infront_get(WORKBENCH_PrivateData *wpd);
+
+GPUShader *workbench_shader_transparent_get(WORKBENCH_PrivateData *wpd, bool hair);
+GPUShader *workbench_shader_transparent_image_get(WORKBENCH_PrivateData *wpd,
+ bool hair,
+ 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);
+
+GPUShader *workbench_shader_cavity_get(bool cavity, bool curvature);
+GPUShader *workbench_shader_outline_get(void);
+
+GPUShader *workbench_shader_antialiasing_accumulation_get(void);
+GPUShader *workbench_shader_antialiasing_get(int stage);
+
+GPUShader *workbench_shader_volume_get(bool slice, bool coba, bool cubic);
+
+void workbench_shader_depth_of_field_get(GPUShader **prepare_sh,
+ GPUShader **downsample_sh,
+ GPUShader **blur1_sh,
+ GPUShader **blur2_sh,
+ GPUShader **resolve_sh);
+
+void workbench_shader_library_ensure(void);
+void workbench_shader_free(void);
+
+/* workbench_effect_antialiasing.c */
+int workbench_antialiasing_sample_count_get(WORKBENCH_PrivateData *wpd);
+void workbench_antialiasing_engine_init(WORKBENCH_Data *vedata);
+void workbench_antialiasing_cache_init(WORKBENCH_Data *vedata);
+void workbench_antialiasing_view_updated(WORKBENCH_Data *vedata);
+bool workbench_antialiasing_setup(WORKBENCH_Data *vedata);
+void workbench_antialiasing_draw_pass(WORKBENCH_Data *vedata);
+
+/* workbench_effect_cavity.c */
+void workbench_cavity_data_update(WORKBENCH_PrivateData *wpd, WORKBENCH_UBO_World *wd);
+void workbench_cavity_samples_ubo_ensure(WORKBENCH_PrivateData *wpd);
+void workbench_cavity_cache_init(WORKBENCH_Data *data);
+
+/* workbench_effect_outline.c */
+void workbench_outline_cache_init(WORKBENCH_Data *data);
/* workbench_effect_dof.c */
-void workbench_dof_engine_init(WORKBENCH_Data *vedata, Object *camera);
-void workbench_dof_engine_free(void);
-void workbench_dof_create_pass(WORKBENCH_Data *vedata,
- GPUTexture **dof_input,
- GPUTexture *noise_tex);
+void workbench_dof_engine_init(WORKBENCH_Data *vedata);
+void workbench_dof_cache_init(WORKBENCH_Data *vedata);
void workbench_dof_draw_pass(WORKBENCH_Data *vedata);
/* workbench_materials.c */
-eV3DShadingColorType workbench_material_determine_color_type(WORKBENCH_PrivateData *wpd,
- Image *ima,
- Object *ob,
- bool use_sculpt_pbvh);
-void workbench_material_get_image_and_mat(
- Object *ob, int mat_nr, Image **r_image, ImageUser **r_iuser, int *r_interp, Material **r_mat);
-char *workbench_material_build_defines(WORKBENCH_PrivateData *wpd,
- bool is_uniform_color,
- bool is_hair,
- bool is_tiled,
- const WORKBENCH_ColorOverride color_override);
-void workbench_material_update_data(WORKBENCH_PrivateData *wpd,
- Object *ob,
- Material *mat,
- WORKBENCH_MaterialData *data,
- int color_type);
-uint workbench_material_get_hash(WORKBENCH_MaterialData *material_template, bool is_ghost);
-int workbench_material_get_composite_shader_index(WORKBENCH_PrivateData *wpd);
-int workbench_material_get_prepass_shader_index(WORKBENCH_PrivateData *wpd,
- bool is_uniform_color,
- bool is_hair,
- bool is_tiled,
- const WORKBENCH_ColorOverride color_override);
-int workbench_material_get_accum_shader_index(WORKBENCH_PrivateData *wpd,
- bool is_uniform_color,
- bool is_hair,
- bool is_tiled,
- const WORKBENCH_ColorOverride color_override);
-void workbench_material_shgroup_uniform(WORKBENCH_PrivateData *wpd,
- DRWShadingGroup *grp,
- WORKBENCH_MaterialData *material,
- Object *ob,
- const bool deferred,
- const bool is_tiled,
- const int interp);
-void workbench_material_copy(WORKBENCH_MaterialData *dest_material,
- const WORKBENCH_MaterialData *source_material);
-
-/* 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]);
-bool studiolight_object_cast_visible_shadow(WORKBENCH_PrivateData *wpd,
- Object *ob,
- WORKBENCH_ObjectData *oed);
-float studiolight_object_shadow_distance(WORKBENCH_PrivateData *wpd,
- Object *ob,
- WORKBENCH_ObjectData *oed);
-bool studiolight_camera_in_object_shadow(WORKBENCH_PrivateData *wpd,
- Object *ob,
- WORKBENCH_ObjectData *oed);
+void workbench_material_ubo_data(WORKBENCH_PrivateData *wpd,
+ Object *ob,
+ Material *mat,
+ WORKBENCH_UBO_Material *data,
+ eV3DShadingColorType color_type);
+
+DRWShadingGroup *workbench_material_setup_ex(WORKBENCH_PrivateData *wpd,
+ Object *ob,
+ int mat_nr,
+ eV3DShadingColorType 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_data.c */
-void workbench_effect_info_init(WORKBENCH_EffectInfo *effect_info);
void workbench_private_data_init(WORKBENCH_PrivateData *wpd);
-void workbench_private_data_free(WORKBENCH_PrivateData *wpd);
-void workbench_private_data_get_light_direction(float r_light_direction[3]);
-void workbench_clear_color_get(float color[4]);
+void workbench_update_world_ubo(WORKBENCH_PrivateData *wpd);
+void workbench_update_material_ubos(WORKBENCH_PrivateData *wpd);
+struct GPUUniformBuffer *workbench_material_ubo_alloc(WORKBENCH_PrivateData *wpd);
/* workbench_volume.c */
-void workbench_volume_engine_init(void);
-void workbench_volume_engine_free(void);
+void workbench_volume_engine_init(WORKBENCH_Data *vedata);
void workbench_volume_cache_init(WORKBENCH_Data *vedata);
void workbench_volume_cache_populate(WORKBENCH_Data *vedata,
- Scene *scene,
- Object *ob,
+ struct Scene *UNUSED(scene),
+ struct Object *ob,
struct ModifierData *md);
-void workbench_volume_smoke_textures_free(WORKBENCH_PrivateData *wpd);
+void workbench_volume_draw_pass(WORKBENCH_Data *vedata);
+void workbench_volume_draw_finish(WORKBENCH_Data *vedata);
+
+/* workbench_engine.c */
+void workbench_engine_init(void *ved);
+void workbench_cache_init(void *ved);
+void workbench_cache_populate(void *ved, Object *ob);
+void workbench_cache_finish(void *ved);
+void workbench_draw_sample(void *ved);
+void workbench_draw_finish(void *ved);
/* workbench_render.c */
-void workbench_render(WORKBENCH_Data *vedata,
+void workbench_render(void *ved,
struct RenderEngine *engine,
struct RenderLayer *render_layer,
const struct rcti *rect);
diff --git a/source/blender/draw/engines/workbench/workbench_render.c b/source/blender/draw/engines/workbench/workbench_render.c
index 6e005e7ccaf..5a315e80a47 100644
--- a/source/blender/draw/engines/workbench/workbench_render.c
+++ b/source/blender/draw/engines/workbench/workbench_render.c
@@ -41,20 +41,12 @@
#include "workbench_private.h"
-static void workbench_render_deferred_cache(void *vedata,
- struct Object *ob,
- struct RenderEngine *UNUSED(engine),
- struct Depsgraph *UNUSED(depsgraph))
+static void workbench_render_cache(void *vedata,
+ struct Object *ob,
+ struct RenderEngine *UNUSED(engine),
+ struct Depsgraph *UNUSED(depsgraph))
{
- workbench_deferred_solid_cache_populate(vedata, ob);
-}
-
-static void workbench_render_forward_cache(void *vedata,
- struct Object *ob,
- struct RenderEngine *UNUSED(engine),
- struct Depsgraph *UNUSED(depsgraph))
-{
- workbench_forward_cache_populate(vedata, ob);
+ workbench_cache_populate(vedata, ob);
}
static void workbench_render_matrices_init(RenderEngine *engine, Depsgraph *depsgraph)
@@ -171,18 +163,11 @@ static void workbench_render_result_z(struct RenderLayer *rl,
}
}
-static void workbench_render_framebuffers_finish(void)
-{
-}
-
-void workbench_render(WORKBENCH_Data *data,
- RenderEngine *engine,
- RenderLayer *render_layer,
- const rcti *rect)
+void workbench_render(void *ved, RenderEngine *engine, RenderLayer *render_layer, const rcti *rect)
{
+ WORKBENCH_Data *data = ved;
DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
const DRWContextState *draw_ctx = DRW_context_state_get();
- const Scene *scene = draw_ctx->scene;
Depsgraph *depsgraph = draw_ctx->depsgraph;
workbench_render_matrices_init(engine, depsgraph);
@@ -191,60 +176,32 @@ void workbench_render(WORKBENCH_Data *data,
return;
}
- const bool deferred = !XRAY_FLAG_ENABLED(&scene->display);
+ workbench_engine_init(data);
- if (deferred) {
- /* Init engine. */
- workbench_deferred_engine_init(data);
+ workbench_cache_init(data);
+ DRW_render_object_iter(data, engine, depsgraph, workbench_render_cache);
+ workbench_cache_finish(data);
- /* Init objects. */
- workbench_deferred_cache_init(data);
- DRW_render_object_iter(data, engine, depsgraph, workbench_render_deferred_cache);
- workbench_deferred_cache_finish(data);
- DRW_render_instance_buffer_finish();
+ DRW_render_instance_buffer_finish();
- /* Also we weed to have a correct fbo bound for DRW_hair_update */
- GPU_framebuffer_bind(dfbl->color_only_fb);
- DRW_hair_update();
-
- /* Draw. */
- int num_samples = workbench_taa_calculate_num_iterations(data);
- for (int sample = 0; sample < num_samples; sample++) {
- if (RE_engine_test_break(engine)) {
- break;
- }
- workbench_deferred_draw_scene(data);
- }
+ /* Also we weed to have a correct fbo bound for DRW_hair_update */
+ GPU_framebuffer_bind(dfbl->default_fb);
+ DRW_hair_update();
- workbench_deferred_draw_finish(data);
- }
- else {
- /* Init engine. */
- workbench_forward_engine_init(data);
-
- /* Init objects. */
- workbench_forward_cache_init(data);
- DRW_render_object_iter(data, engine, depsgraph, workbench_render_forward_cache);
- workbench_forward_cache_finish(data);
- DRW_render_instance_buffer_finish();
-
- /* Also we weed to have a correct fbo bound for DRW_hair_update */
- GPU_framebuffer_bind(dfbl->color_only_fb);
- DRW_hair_update();
-
- /* Draw. */
- int num_samples = workbench_taa_calculate_num_iterations(data);
- for (int sample = 0; sample < num_samples; sample++) {
- if (RE_engine_test_break(engine)) {
- break;
- }
+ GPU_framebuffer_bind(dfbl->default_fb);
+ GPU_framebuffer_clear_depth(dfbl->default_fb, 1.0f);
- workbench_forward_draw_scene(data);
+ WORKBENCH_PrivateData *wpd = data->stl->wpd;
+ while (wpd->taa_sample < max_ii(1, wpd->taa_sample_len)) {
+ if (RE_engine_test_break(engine)) {
+ break;
}
-
- workbench_forward_draw_finish(data);
+ workbench_update_world_ubo(wpd);
+ workbench_draw_sample(data);
}
+ workbench_draw_finish(data);
+
/* Write render output. */
const char *viewname = RE_GetActiveRenderView(engine->re);
RenderPass *rp = RE_pass_find_by_name(render_layer, RE_PASSNAME_COMBINED, viewname);
@@ -260,8 +217,6 @@ void workbench_render(WORKBENCH_Data *data,
rp->rect);
workbench_render_result_z(render_layer, viewname, rect);
-
- workbench_render_framebuffers_finish();
}
void workbench_render_update_passes(RenderEngine *engine, Scene *scene, ViewLayer *view_layer)
diff --git a/source/blender/draw/engines/workbench/workbench_shader.c b/source/blender/draw/engines/workbench/workbench_shader.c
new file mode 100644
index 00000000000..14a980fe628
--- /dev/null
+++ b/source/blender/draw/engines/workbench/workbench_shader.c
@@ -0,0 +1,533 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2020, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "BLI_dynstr.h"
+
+#include "workbench_engine.h"
+#include "workbench_private.h"
+
+extern char datatoc_common_hair_lib_glsl[];
+extern char datatoc_common_view_lib_glsl[];
+extern char datatoc_common_smaa_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_effect_cavity_frag_glsl[];
+extern char datatoc_workbench_effect_outline_frag_glsl[];
+extern char datatoc_workbench_effect_dof_frag_glsl[];
+extern char datatoc_workbench_effect_taa_frag_glsl[];
+extern char datatoc_workbench_effect_smaa_frag_glsl[];
+extern char datatoc_workbench_effect_smaa_vert_glsl[];
+
+extern char datatoc_workbench_composite_frag_glsl[];
+
+extern char datatoc_workbench_transparent_accum_frag_glsl[];
+extern char datatoc_workbench_transparent_resolve_frag_glsl[];
+
+extern char datatoc_workbench_merge_infront_frag_glsl[];
+
+extern char datatoc_workbench_shadow_vert_glsl[];
+extern char datatoc_workbench_shadow_geom_glsl[];
+extern char datatoc_workbench_shadow_caps_geom_glsl[];
+extern char datatoc_workbench_shadow_debug_frag_glsl[];
+
+extern char datatoc_workbench_volume_vert_glsl[];
+extern char datatoc_workbench_volume_frag_glsl[];
+
+extern char datatoc_workbench_cavity_lib_glsl[];
+extern char datatoc_workbench_common_lib_glsl[];
+extern char datatoc_workbench_curvature_lib_glsl[];
+extern char datatoc_workbench_data_lib_glsl[];
+extern char datatoc_workbench_image_lib_glsl[];
+extern char datatoc_workbench_matcap_lib_glsl[];
+extern char datatoc_workbench_material_lib_glsl[];
+extern char datatoc_workbench_shader_interface_lib_glsl[];
+extern char datatoc_workbench_world_light_lib_glsl[];
+
+extern char datatoc_gpu_shader_depth_only_frag_glsl[];
+extern char datatoc_gpu_shader_common_obinfos_lib_glsl[];
+
+/* Maximum number of variations. */
+#define MAX_LIGHTING 3
+#define MAX_COLOR 3
+#define MAX_GEOM 2
+
+enum {
+ VOLUME_SH_SLICE = 0,
+ VOLUME_SH_COBA,
+ VOLUME_SH_CUBIC,
+};
+
+#define VOLUME_SH_MAX (1 << (VOLUME_SH_CUBIC + 1))
+
+static struct {
+ struct GPUShader *opaque_prepass_sh_cache[GPU_SHADER_CFG_LEN][MAX_GEOM][MAX_COLOR];
+ struct GPUShader *transp_prepass_sh_cache[GPU_SHADER_CFG_LEN][MAX_GEOM][MAX_LIGHTING][MAX_COLOR];
+
+ struct GPUShader *opaque_composite_sh[MAX_LIGHTING];
+ struct GPUShader *oit_resolve_sh;
+ struct GPUShader *outline_sh;
+ struct GPUShader *merge_infront_sh;
+
+ struct GPUShader *shadow_depth_pass_sh[2];
+ struct GPUShader *shadow_depth_fail_sh[2][2];
+
+ struct GPUShader *cavity_sh[2][2];
+
+ struct GPUShader *dof_prepare_sh;
+ struct GPUShader *dof_downsample_sh;
+ struct GPUShader *dof_blur1_sh;
+ struct GPUShader *dof_blur2_sh;
+ struct GPUShader *dof_resolve_sh;
+
+ struct GPUShader *aa_accum_sh;
+ struct GPUShader *smaa_sh[3];
+
+ struct GPUShader *volume_sh[2][2][2];
+
+ struct DRWShaderLibrary *lib;
+} e_data = {{{{NULL}}}};
+
+void workbench_shader_library_ensure(void)
+{
+ if (e_data.lib == NULL) {
+ e_data.lib = DRW_shader_library_create();
+ /* NOTE: Theses needs to be ordered by dependencies. */
+ DRW_SHADER_LIB_ADD(e_data.lib, common_hair_lib);
+ DRW_SHADER_LIB_ADD(e_data.lib, common_view_lib);
+ DRW_SHADER_LIB_ADD(e_data.lib, gpu_shader_common_obinfos_lib);
+ DRW_SHADER_LIB_ADD(e_data.lib, workbench_shader_interface_lib);
+ DRW_SHADER_LIB_ADD(e_data.lib, workbench_common_lib);
+ DRW_SHADER_LIB_ADD(e_data.lib, workbench_image_lib);
+ DRW_SHADER_LIB_ADD(e_data.lib, workbench_material_lib);
+ DRW_SHADER_LIB_ADD(e_data.lib, workbench_data_lib);
+ DRW_SHADER_LIB_ADD(e_data.lib, workbench_matcap_lib);
+ DRW_SHADER_LIB_ADD(e_data.lib, workbench_cavity_lib);
+ DRW_SHADER_LIB_ADD(e_data.lib, workbench_curvature_lib);
+ DRW_SHADER_LIB_ADD(e_data.lib, workbench_world_light_lib);
+ }
+}
+
+static char *workbench_build_defines(
+ WORKBENCH_PrivateData *wpd, bool textured, bool tiled, bool cavity, bool curvature)
+{
+ char *str = NULL;
+
+ DynStr *ds = BLI_dynstr_new();
+
+ if (wpd && wpd->shading.light == V3D_LIGHTING_STUDIO) {
+ BLI_dynstr_append(ds, "#define V3D_LIGHTING_STUDIO\n");
+ }
+ else if (wpd && wpd->shading.light == V3D_LIGHTING_MATCAP) {
+ BLI_dynstr_append(ds, "#define V3D_LIGHTING_MATCAP\n");
+ }
+ else {
+ BLI_dynstr_append(ds, "#define V3D_LIGHTING_FLAT\n");
+ }
+
+ if (NORMAL_ENCODING_ENABLED()) {
+ BLI_dynstr_append(ds, "#define WORKBENCH_ENCODE_NORMALS\n");
+ }
+
+ if (textured) {
+ BLI_dynstr_append(ds, "#define V3D_SHADING_TEXTURE_COLOR\n");
+ }
+ if (tiled) {
+ BLI_dynstr_append(ds, "#define TEXTURE_IMAGE_ARRAY\n");
+ }
+ if (cavity) {
+ BLI_dynstr_append(ds, "#define USE_CAVITY\n");
+ }
+ if (curvature) {
+ BLI_dynstr_append(ds, "#define USE_CURVATURE\n");
+ }
+
+ str = BLI_dynstr_get_cstring(ds);
+ BLI_dynstr_free(ds);
+ return str;
+}
+
+static int workbench_color_index(WORKBENCH_PrivateData *UNUSED(wpd), bool textured, bool tiled)
+{
+ BLI_assert(2 < MAX_COLOR);
+ return (textured) ? (tiled ? 2 : 1) : 0;
+}
+
+static GPUShader *workbench_shader_get_ex(
+ WORKBENCH_PrivateData *wpd, bool transp, bool hair, bool textured, bool tiled)
+{
+ int color = workbench_color_index(wpd, textured, tiled);
+ int light = wpd->shading.light;
+ BLI_assert(light < MAX_LIGHTING);
+ struct GPUShader **shader =
+ (transp) ? &e_data.transp_prepass_sh_cache[wpd->sh_cfg][hair][light][color] :
+ &e_data.opaque_prepass_sh_cache[wpd->sh_cfg][hair][color];
+
+ if (*shader == NULL) {
+ char *defines = workbench_build_defines(wpd, textured, tiled, false, false);
+
+ char *frag_file = transp ? datatoc_workbench_transparent_accum_frag_glsl :
+ datatoc_workbench_prepass_frag_glsl;
+ char *frag_src = DRW_shader_library_create_shader_string(e_data.lib, frag_file);
+
+ char *vert_file = hair ? datatoc_workbench_prepass_hair_vert_glsl :
+ datatoc_workbench_prepass_vert_glsl;
+ char *vert_src = DRW_shader_library_create_shader_string(e_data.lib, vert_file);
+
+ const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[wpd->sh_cfg];
+
+ *shader = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg_data->lib, vert_src, NULL},
+ .frag = (const char *[]){frag_src, NULL},
+ .defs = (const char *[]){sh_cfg_data->def,
+ defines,
+ transp ? "#define TRANSPARENT_MATERIAL\n" :
+ "#define OPAQUE_MATERIAL\n",
+ NULL},
+ });
+
+ MEM_freeN(defines);
+ MEM_freeN(frag_src);
+ MEM_freeN(vert_src);
+ }
+ return *shader;
+}
+
+GPUShader *workbench_shader_opaque_get(WORKBENCH_PrivateData *wpd, bool hair)
+{
+ return workbench_shader_get_ex(wpd, false, hair, false, false);
+}
+
+GPUShader *workbench_shader_opaque_image_get(WORKBENCH_PrivateData *wpd, bool hair, bool tiled)
+{
+ return workbench_shader_get_ex(wpd, false, hair, true, tiled);
+}
+
+GPUShader *workbench_shader_transparent_get(WORKBENCH_PrivateData *wpd, bool hair)
+{
+ return workbench_shader_get_ex(wpd, true, hair, false, false);
+}
+
+GPUShader *workbench_shader_transparent_image_get(WORKBENCH_PrivateData *wpd,
+ bool hair,
+ bool tiled)
+{
+ return workbench_shader_get_ex(wpd, true, hair, true, tiled);
+}
+
+GPUShader *workbench_shader_composite_get(WORKBENCH_PrivateData *wpd)
+{
+ int light = wpd->shading.light;
+ struct GPUShader **shader = &e_data.opaque_composite_sh[light];
+ BLI_assert(light < MAX_LIGHTING);
+
+ if (*shader == NULL) {
+ char *defines = workbench_build_defines(wpd, false, false, false, false);
+ char *frag = DRW_shader_library_create_shader_string(e_data.lib,
+ datatoc_workbench_composite_frag_glsl);
+
+ *shader = DRW_shader_create_fullscreen(frag, defines);
+
+ MEM_freeN(defines);
+ MEM_freeN(frag);
+ }
+ return *shader;
+}
+
+GPUShader *workbench_shader_merge_infront_get(WORKBENCH_PrivateData *UNUSED(wpd))
+{
+ if (e_data.merge_infront_sh == NULL) {
+ char *frag = DRW_shader_library_create_shader_string(
+ e_data.lib, datatoc_workbench_merge_infront_frag_glsl);
+
+ e_data.merge_infront_sh = DRW_shader_create_fullscreen(frag, NULL);
+
+ MEM_freeN(frag);
+ }
+ return e_data.merge_infront_sh;
+}
+
+GPUShader *workbench_shader_transparent_resolve_get(WORKBENCH_PrivateData *wpd)
+{
+ if (e_data.oit_resolve_sh == NULL) {
+ char *defines = workbench_build_defines(wpd, false, false, false, false);
+
+ e_data.oit_resolve_sh = DRW_shader_create_fullscreen(
+ datatoc_workbench_transparent_resolve_frag_glsl, defines);
+
+ MEM_freeN(defines);
+ }
+ 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);
+}
+
+GPUShader *workbench_shader_cavity_get(bool cavity, bool curvature)
+{
+ BLI_assert(cavity || curvature);
+ struct GPUShader **shader = &e_data.cavity_sh[cavity][curvature];
+
+ if (*shader == NULL) {
+ char *defines = workbench_build_defines(NULL, false, false, cavity, curvature);
+ char *frag = DRW_shader_library_create_shader_string(
+ e_data.lib, datatoc_workbench_effect_cavity_frag_glsl);
+
+ *shader = DRW_shader_create_fullscreen(frag, defines);
+
+ MEM_freeN(defines);
+ MEM_freeN(frag);
+ }
+ return *shader;
+}
+
+GPUShader *workbench_shader_outline_get(void)
+{
+ if (e_data.outline_sh == NULL) {
+ char *frag = DRW_shader_library_create_shader_string(
+ e_data.lib, datatoc_workbench_effect_outline_frag_glsl);
+
+ e_data.outline_sh = DRW_shader_create_fullscreen(frag, NULL);
+
+ MEM_freeN(frag);
+ }
+ return e_data.outline_sh;
+}
+
+void workbench_shader_depth_of_field_get(GPUShader **prepare_sh,
+ GPUShader **downsample_sh,
+ GPUShader **blur1_sh,
+ GPUShader **blur2_sh,
+ GPUShader **resolve_sh)
+{
+ if (e_data.dof_prepare_sh == NULL) {
+ e_data.dof_prepare_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl,
+ "#define PREPARE\n");
+
+ e_data.dof_downsample_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl,
+ "#define DOWNSAMPLE\n");
+#if 0 /* TODO(fclem) finish COC min_max optimization */
+ e_data.dof_flatten_v_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl,
+ "#define FLATTEN_VERTICAL\n");
+
+ e_data.dof_flatten_h_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl,
+ "#define FLATTEN_HORIZONTAL\n");
+
+ e_data.dof_dilate_v_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl,
+ "#define DILATE_VERTICAL\n");
+
+ e_data.dof_dilate_h_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl,
+ "#define DILATE_HORIZONTAL\n");
+#endif
+ e_data.dof_blur1_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl,
+ "#define BLUR1\n");
+
+ e_data.dof_blur2_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl,
+ "#define BLUR2\n");
+
+ e_data.dof_resolve_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl,
+ "#define RESOLVE\n");
+ }
+
+ *prepare_sh = e_data.dof_prepare_sh;
+ *downsample_sh = e_data.dof_downsample_sh;
+ *blur1_sh = e_data.dof_blur1_sh;
+ *blur2_sh = e_data.dof_blur2_sh;
+ *resolve_sh = e_data.dof_resolve_sh;
+}
+
+GPUShader *workbench_shader_antialiasing_accumulation_get(void)
+{
+ if (e_data.aa_accum_sh == NULL) {
+ char *frag = DRW_shader_library_create_shader_string(e_data.lib,
+ datatoc_workbench_effect_taa_frag_glsl);
+
+ e_data.aa_accum_sh = DRW_shader_create_fullscreen(frag, NULL);
+
+ MEM_freeN(frag);
+ }
+ return e_data.aa_accum_sh;
+}
+
+GPUShader *workbench_shader_antialiasing_get(int stage)
+{
+ BLI_assert(stage < 3);
+ if (!e_data.smaa_sh[stage]) {
+ char stage_define[32];
+ BLI_snprintf(stage_define, sizeof(stage_define), "#define SMAA_STAGE %d\n", stage);
+
+ e_data.smaa_sh[stage] = GPU_shader_create_from_arrays({
+ .vert =
+ (const char *[]){
+ "#define SMAA_INCLUDE_VS 1\n",
+ "#define SMAA_INCLUDE_PS 0\n",
+ "uniform vec4 viewportMetrics;\n",
+ datatoc_common_smaa_lib_glsl,
+ datatoc_workbench_effect_smaa_vert_glsl,
+ NULL,
+ },
+ .frag =
+ (const char *[]){
+ "#define SMAA_INCLUDE_VS 0\n",
+ "#define SMAA_INCLUDE_PS 1\n",
+ "uniform vec4 viewportMetrics;\n",
+ datatoc_common_smaa_lib_glsl,
+ datatoc_workbench_effect_smaa_frag_glsl,
+ NULL,
+ },
+ .defs =
+ (const char *[]){
+ "#define SMAA_GLSL_3\n",
+ "#define SMAA_RT_METRICS viewportMetrics\n",
+ "#define SMAA_PRESET_HIGH\n",
+ "#define SMAA_LUMA_WEIGHT float4(1.0, 1.0, 1.0, 1.0)\n",
+ "#define SMAA_NO_DISCARD\n",
+ stage_define,
+ NULL,
+ },
+ });
+ }
+ return e_data.smaa_sh[stage];
+}
+
+GPUShader *workbench_shader_volume_get(bool slice, bool coba, bool cubic)
+{
+ GPUShader **shader = &e_data.volume_sh[slice][coba][cubic];
+
+ if (*shader == NULL) {
+ DynStr *ds = BLI_dynstr_new();
+
+ if (slice) {
+ BLI_dynstr_append(ds, "#define VOLUME_SLICE\n");
+ }
+ if (coba) {
+ BLI_dynstr_append(ds, "#define USE_COBA\n");
+ }
+ if (cubic) {
+ BLI_dynstr_append(ds, "#define USE_TRICUBIC\n");
+ }
+
+ char *defines = BLI_dynstr_get_cstring(ds);
+ BLI_dynstr_free(ds);
+
+ char *vert = DRW_shader_library_create_shader_string(e_data.lib,
+ datatoc_workbench_volume_vert_glsl);
+ char *frag = DRW_shader_library_create_shader_string(e_data.lib,
+ datatoc_workbench_volume_frag_glsl);
+
+ *shader = DRW_shader_create(vert, NULL, frag, defines);
+
+ MEM_freeN(vert);
+ MEM_freeN(frag);
+ MEM_freeN(defines);
+ }
+ return *shader;
+}
+
+void workbench_shader_free(void)
+{
+ for (int j = 0; j < sizeof(e_data.opaque_prepass_sh_cache) / sizeof(void *); j++) {
+ struct GPUShader **sh_array = &e_data.opaque_prepass_sh_cache[0][0][0];
+ DRW_SHADER_FREE_SAFE(sh_array[j]);
+ }
+ for (int j = 0; j < sizeof(e_data.transp_prepass_sh_cache) / sizeof(void *); j++) {
+ struct GPUShader **sh_array = &e_data.transp_prepass_sh_cache[0][0][0][0];
+ DRW_SHADER_FREE_SAFE(sh_array[j]);
+ }
+ for (int j = 0; j < sizeof(e_data.opaque_composite_sh) / sizeof(void *); j++) {
+ 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]);
+ }
+ for (int j = 0; j < sizeof(e_data.cavity_sh) / sizeof(void *); j++) {
+ struct GPUShader **sh_array = &e_data.cavity_sh[0][0];
+ DRW_SHADER_FREE_SAFE(sh_array[j]);
+ }
+ for (int j = 0; j < sizeof(e_data.smaa_sh) / sizeof(void *); j++) {
+ struct GPUShader **sh_array = &e_data.smaa_sh[0];
+ DRW_SHADER_FREE_SAFE(sh_array[j]);
+ }
+ for (int j = 0; j < sizeof(e_data.volume_sh) / sizeof(void *); j++) {
+ struct GPUShader **sh_array = &e_data.volume_sh[0][0][0];
+ DRW_SHADER_FREE_SAFE(sh_array[j]);
+ }
+
+ DRW_SHADER_FREE_SAFE(e_data.oit_resolve_sh);
+ DRW_SHADER_FREE_SAFE(e_data.outline_sh);
+ DRW_SHADER_FREE_SAFE(e_data.merge_infront_sh);
+
+ DRW_SHADER_FREE_SAFE(e_data.dof_prepare_sh);
+ DRW_SHADER_FREE_SAFE(e_data.dof_downsample_sh);
+ DRW_SHADER_FREE_SAFE(e_data.dof_blur1_sh);
+ DRW_SHADER_FREE_SAFE(e_data.dof_blur2_sh);
+ DRW_SHADER_FREE_SAFE(e_data.dof_resolve_sh);
+
+ DRW_SHADER_FREE_SAFE(e_data.aa_accum_sh);
+
+ DRW_SHADER_LIB_FREE_SAFE(e_data.lib);
+}
diff --git a/source/blender/draw/engines/workbench/workbench_shadow.c b/source/blender/draw/engines/workbench/workbench_shadow.c
new file mode 100644
index 00000000000..8da75942944
--- /dev/null
+++ b/source/blender/draw/engines/workbench/workbench_shadow.c
@@ -0,0 +1,367 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2020, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ *
+ * Shadow:
+ *
+ * Use stencil shadow buffer to cast a sharp shadow over opaque surfaces.
+ *
+ * After the main prepass we render shadow volumes using custom depth & stencil states to
+ * set the stencil of shadowed area to anything but 0.
+ *
+ * Then the shading pass will shade the areas with stencil not equal 0 differently.
+ */
+
+#include "DRW_render.h"
+
+#include "BKE_object.h"
+
+#include "BLI_math.h"
+
+#include "workbench_engine.h"
+#include "workbench_private.h"
+
+static void compute_parallel_lines_nor_and_dist(const float v1[2],
+ const float v2[2],
+ const float v3[2],
+ float r_line[4])
+{
+ sub_v2_v2v2(r_line, v2, v1);
+ /* Find orthogonal vector. */
+ SWAP(float, r_line[0], r_line[1]);
+ r_line[0] = -r_line[0];
+ /* Edge distances. */
+ r_line[2] = dot_v2v2(r_line, v1);
+ r_line[3] = dot_v2v2(r_line, v3);
+ /* Make sure r_line[2] is the minimum. */
+ if (r_line[2] > r_line[3]) {
+ SWAP(float, r_line[2], r_line[3]);
+ }
+}
+
+static void workbench_shadow_update(WORKBENCH_PrivateData *wpd)
+{
+ wpd->shadow_changed = !compare_v3v3(
+ wpd->shadow_cached_direction, wpd->shadow_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], wpd->shadow_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->shadow_cached_direction, wpd->shadow_direction_ws);
+ }
+
+ float planes[6][4];
+ DRW_culling_frustum_planes_get(NULL, planes);
+ /* we only need the far plane. */
+ copy_v4_v4(wpd->shadow_far_plane, planes[2]);
+
+ BoundBox frustum_corners;
+ DRW_culling_frustum_corners_get(NULL, &frustum_corners);
+
+ float shadow_near_corners[4][3];
+ mul_v3_mat3_m4v3(shadow_near_corners[0], wpd->shadow_inv, frustum_corners.vec[0]);
+ mul_v3_mat3_m4v3(shadow_near_corners[1], wpd->shadow_inv, frustum_corners.vec[3]);
+ mul_v3_mat3_m4v3(shadow_near_corners[2], wpd->shadow_inv, frustum_corners.vec[7]);
+ mul_v3_mat3_m4v3(shadow_near_corners[3], wpd->shadow_inv, frustum_corners.vec[4]);
+
+ INIT_MINMAX(wpd->shadow_near_min, wpd->shadow_near_max);
+ for (int i = 0; i < 4; i++) {
+ minmax_v3v3_v3(wpd->shadow_near_min, wpd->shadow_near_max, shadow_near_corners[i]);
+ }
+
+ compute_parallel_lines_nor_and_dist(shadow_near_corners[0],
+ shadow_near_corners[1],
+ shadow_near_corners[2],
+ wpd->shadow_near_sides[0]);
+ compute_parallel_lines_nor_and_dist(shadow_near_corners[1],
+ shadow_near_corners[2],
+ shadow_near_corners[0],
+ wpd->shadow_near_sides[1]);
+}
+
+void workbench_shadow_data_update(WORKBENCH_PrivateData *wpd, WORKBENCH_UBO_World *wd)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const Scene *scene = draw_ctx->scene;
+
+ float view_matrix[4][4];
+ DRW_view_viewmat_get(NULL, view_matrix, false);
+
+ /* Turn the light in a way where it's more user friendly to control. */
+ copy_v3_v3(wpd->shadow_direction_ws, scene->display.light_direction);
+ SWAP(float, wpd->shadow_direction_ws[2], wpd->shadow_direction_ws[1]);
+ wpd->shadow_direction_ws[2] = -wpd->shadow_direction_ws[2];
+ wpd->shadow_direction_ws[0] = -wpd->shadow_direction_ws[0];
+
+ /* Shadow direction. */
+ mul_v3_mat3_m4v3(wd->shadow_direction_vs, view_matrix, wpd->shadow_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;
+ }
+}
+
+void workbench_shadow_cache_init(WORKBENCH_Data *data)
+{
+ WORKBENCH_PassList *psl = data->psl;
+ WORKBENCH_PrivateData *wpd = data->stl->wpd;
+ struct GPUShader *sh;
+ DRWShadingGroup *grp;
+
+ if (SHADOW_ENABLED(wpd)) {
+ workbench_shadow_update(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_ps[0], state | depth_pass_state);
+ DRW_PASS_CREATE(psl->shadow_ps[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_ps[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_ps[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_ps[1]);
+ }
+ }
+ else {
+ psl->shadow_ps[0] = NULL;
+ psl->shadow_ps[1] = NULL;
+ }
+}
+
+static BoundBox *workbench_shadow_object_shadow_bbox_get(WORKBENCH_PrivateData *wpd,
+ Object *ob,
+ WORKBENCH_ObjectData *oed)
+{
+ if (oed->shadow_bbox_dirty || wpd->shadow_changed) {
+ float tmp_mat[4][4];
+ mul_m4_m4m4(tmp_mat, wpd->shadow_inv, ob->obmat);
+
+ /* Get AABB in shadow space. */
+ INIT_MINMAX(oed->shadow_min, oed->shadow_max);
+
+ /* From object space to shadow space */
+ BoundBox *bbox = BKE_object_boundbox_get(ob);
+ for (int i = 0; i < 8; i++) {
+ float corner[3];
+ mul_v3_m4v3(corner, tmp_mat, bbox->vec[i]);
+ minmax_v3v3_v3(oed->shadow_min, oed->shadow_max, corner);
+ }
+ oed->shadow_depth = oed->shadow_max[2] - oed->shadow_min[2];
+ /* Extend towards infinity. */
+ oed->shadow_max[2] += 1e4f;
+
+ /* Get extended AABB in world space. */
+ BKE_boundbox_init_from_minmax(&oed->shadow_bbox, oed->shadow_min, oed->shadow_max);
+ for (int i = 0; i < 8; i++) {
+ mul_m4_v3(wpd->shadow_mat, oed->shadow_bbox.vec[i]);
+ }
+ oed->shadow_bbox_dirty = false;
+ }
+
+ return &oed->shadow_bbox;
+}
+
+static bool workbench_shadow_object_cast_visible_shadow(WORKBENCH_PrivateData *wpd,
+ Object *ob,
+ WORKBENCH_ObjectData *oed)
+{
+ BoundBox *shadow_bbox = workbench_shadow_object_shadow_bbox_get(wpd, ob, oed);
+ const DRWView *default_view = DRW_view_default_get();
+ return DRW_culling_box_test(default_view, shadow_bbox);
+}
+
+static float workbench_shadow_object_shadow_distance(WORKBENCH_PrivateData *wpd,
+ Object *ob,
+ WORKBENCH_ObjectData *oed)
+{
+ BoundBox *shadow_bbox = workbench_shadow_object_shadow_bbox_get(wpd, ob, oed);
+
+ int corners[4] = {0, 3, 4, 7};
+ float dist = 1e4f, dist_isect;
+ for (int i = 0; i < 4; i++) {
+ if (isect_ray_plane_v3(shadow_bbox->vec[corners[i]],
+ wpd->shadow_cached_direction,
+ wpd->shadow_far_plane,
+ &dist_isect,
+ true)) {
+ if (dist_isect < dist) {
+ dist = dist_isect;
+ }
+ }
+ else {
+ /* All rays are parallels. If one fails, the other will too. */
+ break;
+ }
+ }
+ return max_ii(dist - oed->shadow_depth, 0);
+}
+
+static bool workbench_shadow_camera_in_object_shadow(WORKBENCH_PrivateData *wpd,
+ Object *ob,
+ WORKBENCH_ObjectData *oed)
+{
+ /* Just to be sure the min, max are updated. */
+ workbench_shadow_object_shadow_bbox_get(wpd, ob, oed);
+ /* Test if near plane is in front of the shadow. */
+ if (oed->shadow_min[2] > wpd->shadow_near_max[2]) {
+ return false;
+ }
+
+ /* Separation Axis Theorem test */
+
+ /* Test bbox sides first (faster) */
+ if ((oed->shadow_min[0] > wpd->shadow_near_max[0]) ||
+ (oed->shadow_max[0] < wpd->shadow_near_min[0]) ||
+ (oed->shadow_min[1] > wpd->shadow_near_max[1]) ||
+ (oed->shadow_max[1] < wpd->shadow_near_min[1])) {
+ return false;
+ }
+ /* Test projected near rectangle sides */
+ const float pts[4][2] = {
+ {oed->shadow_min[0], oed->shadow_min[1]},
+ {oed->shadow_min[0], oed->shadow_max[1]},
+ {oed->shadow_max[0], oed->shadow_min[1]},
+ {oed->shadow_max[0], oed->shadow_max[1]},
+ };
+
+ for (int i = 0; i < 2; i++) {
+ float min_dst = FLT_MAX, max_dst = -FLT_MAX;
+ for (int j = 0; j < 4; j++) {
+ float dst = dot_v2v2(wpd->shadow_near_sides[i], pts[j]);
+ /* Do min max */
+ if (min_dst > dst) {
+ min_dst = dst;
+ }
+ if (max_dst < dst) {
+ max_dst = dst;
+ }
+ }
+
+ if ((wpd->shadow_near_sides[i][2] > max_dst) || (wpd->shadow_near_sides[i][3] < min_dst)) {
+ return false;
+ }
+ }
+ /* No separation axis found. Both shape intersect. */
+ return true;
+}
+
+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 (workbench_shadow_object_cast_visible_shadow(wpd, ob, engine_object_data)) {
+ mul_v3_mat3_m4v3(engine_object_data->shadow_dir, ob->imat, wpd->shadow_direction_ws);
+
+ DRWShadingGroup *grp;
+ bool use_shadow_pass_technique = !workbench_shadow_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 = workbench_shadow_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
deleted file mode 100644
index 1fb0b394cb1..00000000000
--- a/source/blender/draw/engines/workbench/workbench_studiolight.c
+++ /dev/null
@@ -1,257 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Copyright 2016, Blender Foundation.
- */
-
-/** \file
- * \ingroup draw_engine
- */
-#include "BKE_studiolight.h"
-
-#include "workbench_private.h"
-
-#include "BKE_object.h"
-
-#include "BLI_math.h"
-
-void studiolight_update_world(WORKBENCH_PrivateData *wpd,
- StudioLight *studiolight,
- WORKBENCH_UBO_World *wd)
-{
- float view_matrix[4][4], rot_matrix[4][4];
- DRW_view_viewmat_get(NULL, view_matrix, false);
-
- if (USE_WORLD_ORIENTATION(wpd)) {
- axis_angle_to_mat4_single(rot_matrix, 'Z', -wpd->shading.studiolight_rot_z);
- mul_m4_m4m4(rot_matrix, view_matrix, rot_matrix);
- swap_v3_v3(rot_matrix[2], rot_matrix[1]);
- negate_v3(rot_matrix[2]);
- }
- else {
- unit_m4(rot_matrix);
- }
-
- if (U.edit_studio_light) {
- studiolight = BKE_studiolight_studio_edit_get();
- }
-
- /* Studio Lights. */
- for (int i = 0; i < 4; i++) {
- WORKBENCH_UBO_Light *light = &wd->lights[i];
-
- SolidLight *sl = &studiolight->light[i];
- if (sl->flag) {
- copy_v3_v3(light->light_direction, sl->vec);
- mul_mat3_m4_v3(rot_matrix, light->light_direction);
- /* We should predivide the power by PI but that makes the lights really dim. */
- copy_v3_v3(light->specular_color, sl->spec);
- copy_v3_v3(light->diffuse_color, sl->col);
- light->wrapped = sl->smooth;
- }
- else {
- copy_v3_fl3(light->light_direction, 1.0f, 0.0f, 0.0f);
- copy_v3_fl(light->specular_color, 0.0f);
- copy_v3_fl(light->diffuse_color, 0.0f);
- }
- }
-
- copy_v3_v3(wd->ambient_color, studiolight->light_ambient);
-}
-
-static void compute_parallel_lines_nor_and_dist(const float v1[2],
- const float v2[2],
- const float v3[2],
- float r_line[4])
-{
- sub_v2_v2v2(r_line, v2, v1);
- /* Find orthogonal vector. */
- SWAP(float, r_line[0], r_line[1]);
- r_line[0] = -r_line[0];
- /* Edge distances. */
- r_line[2] = dot_v2v2(r_line, v1);
- r_line[3] = dot_v2v2(r_line, v3);
- /* Make sure r_line[2] is the minimum. */
- if (r_line[2] > r_line[3]) {
- SWAP(float, r_line[2], r_line[3]);
- }
-}
-
-void studiolight_update_light(WORKBENCH_PrivateData *wpd, const float light_direction[3])
-{
- wpd->shadow_changed = !compare_v3v3(wpd->cached_shadow_direction, light_direction, 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);
- 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);
- }
-
- float planes[6][4];
- DRW_culling_frustum_planes_get(NULL, planes);
- /* we only need the far plane. */
- copy_v4_v4(wpd->shadow_far_plane, planes[2]);
-
- BoundBox frustum_corners;
- DRW_culling_frustum_corners_get(NULL, &frustum_corners);
-
- mul_v3_mat3_m4v3(wpd->shadow_near_corners[0], wpd->shadow_inv, frustum_corners.vec[0]);
- mul_v3_mat3_m4v3(wpd->shadow_near_corners[1], wpd->shadow_inv, frustum_corners.vec[3]);
- mul_v3_mat3_m4v3(wpd->shadow_near_corners[2], wpd->shadow_inv, frustum_corners.vec[7]);
- mul_v3_mat3_m4v3(wpd->shadow_near_corners[3], wpd->shadow_inv, frustum_corners.vec[4]);
-
- INIT_MINMAX(wpd->shadow_near_min, wpd->shadow_near_max);
- for (int i = 0; i < 4; i++) {
- minmax_v3v3_v3(wpd->shadow_near_min, wpd->shadow_near_max, wpd->shadow_near_corners[i]);
- }
-
- compute_parallel_lines_nor_and_dist(wpd->shadow_near_corners[0],
- wpd->shadow_near_corners[1],
- wpd->shadow_near_corners[2],
- wpd->shadow_near_sides[0]);
- compute_parallel_lines_nor_and_dist(wpd->shadow_near_corners[1],
- wpd->shadow_near_corners[2],
- wpd->shadow_near_corners[0],
- wpd->shadow_near_sides[1]);
-}
-
-static BoundBox *studiolight_object_shadow_bbox_get(WORKBENCH_PrivateData *wpd,
- Object *ob,
- WORKBENCH_ObjectData *oed)
-{
- if ((oed->shadow_bbox_dirty) || (wpd->shadow_changed)) {
- float tmp_mat[4][4];
- mul_m4_m4m4(tmp_mat, wpd->shadow_inv, ob->obmat);
-
- /* Get AABB in shadow space. */
- INIT_MINMAX(oed->shadow_min, oed->shadow_max);
-
- /* From object space to shadow space */
- BoundBox *bbox = BKE_object_boundbox_get(ob);
- for (int i = 0; i < 8; i++) {
- float corner[3];
- mul_v3_m4v3(corner, tmp_mat, bbox->vec[i]);
- minmax_v3v3_v3(oed->shadow_min, oed->shadow_max, corner);
- }
- oed->shadow_depth = oed->shadow_max[2] - oed->shadow_min[2];
- /* Extend towards infinity. */
- oed->shadow_max[2] += 1e4f;
-
- /* Get extended AABB in world space. */
- BKE_boundbox_init_from_minmax(&oed->shadow_bbox, oed->shadow_min, oed->shadow_max);
- for (int i = 0; i < 8; i++) {
- mul_m4_v3(wpd->shadow_mat, oed->shadow_bbox.vec[i]);
- }
- oed->shadow_bbox_dirty = false;
- }
-
- return &oed->shadow_bbox;
-}
-
-bool studiolight_object_cast_visible_shadow(WORKBENCH_PrivateData *wpd,
- Object *ob,
- WORKBENCH_ObjectData *oed)
-{
- BoundBox *shadow_bbox = studiolight_object_shadow_bbox_get(wpd, ob, oed);
- const DRWView *default_view = DRW_view_default_get();
- return DRW_culling_box_test(default_view, shadow_bbox);
-}
-
-float studiolight_object_shadow_distance(WORKBENCH_PrivateData *wpd,
- Object *ob,
- WORKBENCH_ObjectData *oed)
-{
- BoundBox *shadow_bbox = studiolight_object_shadow_bbox_get(wpd, ob, oed);
-
- int corners[4] = {0, 3, 4, 7};
- float dist = 1e4f, dist_isect;
- for (int i = 0; i < 4; i++) {
- if (isect_ray_plane_v3(shadow_bbox->vec[corners[i]],
- wpd->cached_shadow_direction,
- wpd->shadow_far_plane,
- &dist_isect,
- true)) {
- if (dist_isect < dist) {
- dist = dist_isect;
- }
- }
- else {
- /* All rays are parallels. If one fails, the other will too. */
- break;
- }
- }
- return max_ii(dist - oed->shadow_depth, 0);
-}
-
-bool studiolight_camera_in_object_shadow(WORKBENCH_PrivateData *wpd,
- Object *ob,
- WORKBENCH_ObjectData *oed)
-{
- /* Just to be sure the min, max are updated. */
- studiolight_object_shadow_bbox_get(wpd, ob, oed);
-
- /* Test if near plane is in front of the shadow. */
- if (oed->shadow_min[2] > wpd->shadow_near_max[2]) {
- return false;
- }
-
- /* Separation Axis Theorem test */
-
- /* Test bbox sides first (faster) */
- if ((oed->shadow_min[0] > wpd->shadow_near_max[0]) ||
- (oed->shadow_max[0] < wpd->shadow_near_min[0]) ||
- (oed->shadow_min[1] > wpd->shadow_near_max[1]) ||
- (oed->shadow_max[1] < wpd->shadow_near_min[1])) {
- return false;
- }
-
- /* Test projected near rectangle sides */
- const float pts[4][2] = {
- {oed->shadow_min[0], oed->shadow_min[1]},
- {oed->shadow_min[0], oed->shadow_max[1]},
- {oed->shadow_max[0], oed->shadow_min[1]},
- {oed->shadow_max[0], oed->shadow_max[1]},
- };
-
- for (int i = 0; i < 2; i++) {
- float min_dst = FLT_MAX, max_dst = -FLT_MAX;
- for (int j = 0; j < 4; j++) {
- float dst = dot_v2v2(wpd->shadow_near_sides[i], pts[j]);
- /* Do min max */
- if (min_dst > dst) {
- min_dst = dst;
- }
- if (max_dst < dst) {
- max_dst = dst;
- }
- }
-
- if ((wpd->shadow_near_sides[i][2] > max_dst) || (wpd->shadow_near_sides[i][3] < min_dst)) {
- return false;
- }
- }
-
- /* No separation axis found. Both shape intersect. */
- return true;
-}
diff --git a/source/blender/draw/engines/workbench/workbench_transparent.c b/source/blender/draw/engines/workbench/workbench_transparent.c
new file mode 100644
index 00000000000..1e1b751f80d
--- /dev/null
+++ b/source/blender/draw/engines/workbench/workbench_transparent.c
@@ -0,0 +1,180 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2020, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ *
+ * Transparent Pieline:
+ *
+ * Use Weight Blended Order Independant Transparency to render transparent surfaces.
+ *
+ * The rendering is broken down in two passes:
+ * - the accumulation pass where we render all the surfaces and accumulate all the weights.
+ * - the resolve pass where we divide the accumulated infos by the weights.
+ *
+ * An additional rerender of the transparent surfaces is sometime done in order to have their
+ * correct depth and object ids correctly written.
+ */
+
+#include "DRW_render.h"
+
+#include "ED_view3d.h"
+
+#include "GPU_extensions.h"
+
+#include "workbench_engine.h"
+#include "workbench_private.h"
+
+void workbench_transparent_engine_init(WORKBENCH_Data *data)
+{
+ WORKBENCH_FramebufferList *fbl = data->fbl;
+ WORKBENCH_PrivateData *wpd = data->stl->wpd;
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+ DrawEngineType *owner = (DrawEngineType *)&workbench_transparent_engine_init;
+
+ /* Reuse same format as opaque pipeline to reuse the textures. */
+ /* Note: Floating point texture is required for the reveal_tex as it is used for
+ * the alpha accumulation component (see accumulation shader for more explanation). */
+ const eGPUTextureFormat accum_tex_format = GPU_RGBA16F;
+ const eGPUTextureFormat reveal_tex_format = NORMAL_ENCODING_ENABLED() ? GPU_RG16F : GPU_RGBA32F;
+
+ wpd->accum_buffer_tx = DRW_texture_pool_query_fullscreen(accum_tex_format, owner);
+ wpd->reveal_buffer_tx = DRW_texture_pool_query_fullscreen(reveal_tex_format, owner);
+
+ GPU_framebuffer_ensure_config(&fbl->transp_accum_fb,
+ {
+ GPU_ATTACHMENT_TEXTURE(dtxl->depth),
+ GPU_ATTACHMENT_TEXTURE(wpd->accum_buffer_tx),
+ GPU_ATTACHMENT_TEXTURE(wpd->reveal_buffer_tx),
+ });
+}
+
+static void workbench_transparent_lighting_uniforms(WORKBENCH_PrivateData *wpd,
+ DRWShadingGroup *grp)
+{
+ 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,
+ STUDIOLIGHT_MATCAP_DIFFUSE_GPUTEXTURE |
+ STUDIOLIGHT_MATCAP_SPECULAR_GPUTEXTURE);
+ struct GPUTexture *diff_tx = wpd->studio_light->matcap_diffuse.gputexture;
+ struct GPUTexture *spec_tx = wpd->studio_light->matcap_specular.gputexture;
+ const bool use_spec = workbench_is_specular_highlight_enabled(wpd);
+ spec_tx = (use_spec && spec_tx) ? spec_tx : diff_tx;
+ DRW_shgroup_uniform_texture_persistent(grp, "matcapDiffuseImage", diff_tx);
+ DRW_shgroup_uniform_texture_persistent(grp, "matcapSpecularImage", spec_tx);
+ }
+}
+
+void workbench_transparent_cache_init(WORKBENCH_Data *data)
+{
+ WORKBENCH_PassList *psl = data->psl;
+ WORKBENCH_PrivateData *wpd = data->stl->wpd;
+ struct GPUShader *sh;
+ DRWShadingGroup *grp;
+
+ {
+ int transp = 1;
+ for (int infront = 0; infront < 2; infront++) {
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND_OIT;
+
+ DRWPass *pass;
+ if (infront) {
+ DRW_PASS_CREATE(psl->transp_accum_infront_ps, state | wpd->cull_state | wpd->clip_state);
+ pass = psl->transp_accum_infront_ps;
+ }
+ else {
+ DRW_PASS_CREATE(psl->transp_accum_ps, state | wpd->cull_state | wpd->clip_state);
+ pass = psl->transp_accum_ps;
+ }
+
+ for (int hair = 0; hair < 2; hair++) {
+ wpd->prepass[transp][infront][hair].material_hash = BLI_ghash_ptr_new(__func__);
+
+ sh = workbench_shader_transparent_get(wpd, hair);
+
+ wpd->prepass[transp][infront][hair].common_shgrp = grp = DRW_shgroup_create(sh, pass);
+ DRW_shgroup_uniform_block(grp, "material_block", wpd->material_ubo_curr);
+ DRW_shgroup_uniform_int_copy(grp, "materialIndex", -1);
+ workbench_transparent_lighting_uniforms(wpd, grp);
+
+ wpd->prepass[transp][infront][hair].vcol_shgrp = grp = DRW_shgroup_create(sh, pass);
+ DRW_shgroup_uniform_block_persistent(grp, "material_block", wpd->material_ubo_curr);
+ DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. (uses vcol) */
+
+ sh = workbench_shader_transparent_image_get(wpd, hair, false);
+
+ wpd->prepass[transp][infront][hair].image_shgrp = grp = DRW_shgroup_create(sh, pass);
+ DRW_shgroup_uniform_block_persistent(grp, "material_block", wpd->material_ubo_curr);
+ DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. */
+ workbench_transparent_lighting_uniforms(wpd, grp);
+
+ sh = workbench_shader_transparent_image_get(wpd, hair, true);
+
+ wpd->prepass[transp][infront][hair].image_tiled_shgrp = grp = DRW_shgroup_create(sh, pass);
+ DRW_shgroup_uniform_block_persistent(grp, "material_block", wpd->material_ubo_curr);
+ DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. */
+ workbench_transparent_lighting_uniforms(wpd, grp);
+ }
+ }
+ }
+ {
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA;
+
+ DRW_PASS_CREATE(psl->transp_resolve_ps, state);
+
+ sh = workbench_shader_transparent_resolve_get(wpd);
+
+ grp = DRW_shgroup_create(sh, psl->transp_resolve_ps);
+ DRW_shgroup_uniform_texture(grp, "transparentAccum", wpd->accum_buffer_tx);
+ DRW_shgroup_uniform_texture(grp, "transparentRevealage", wpd->reveal_buffer_tx);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+ }
+}
+
+/* Redraw the transparent passes but with depth test
+ * to output correct outline IDs and depth. */
+void workbench_transparent_draw_depth_pass(WORKBENCH_Data *data)
+{
+ WORKBENCH_PrivateData *wpd = data->stl->wpd;
+ WORKBENCH_FramebufferList *fbl = data->fbl;
+ WORKBENCH_PassList *psl = data->psl;
+
+ const bool do_xray_depth_pass = XRAY_ALPHA(wpd) > 0.0f;
+ const bool do_transparent_depth_pass = psl->outline_ps || wpd->dof_enabled || do_xray_depth_pass;
+
+ if (do_transparent_depth_pass) {
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
+
+ if (!DRW_pass_is_empty(psl->transp_accum_ps)) {
+ GPU_framebuffer_bind(fbl->opaque_fb);
+ /* TODO(fclem) Disable writting to first two buffers. Unecessary waste of bandwidth. */
+ DRW_pass_state_set(psl->transp_accum_ps, state | wpd->cull_state | wpd->clip_state);
+ DRW_draw_pass(psl->transp_accum_ps);
+ }
+
+ if (!DRW_pass_is_empty(psl->transp_accum_infront_ps)) {
+ GPU_framebuffer_bind(fbl->opaque_infront_fb);
+ /* TODO(fclem) Disable writting to first two buffers. Unecessary waste of bandwidth. */
+ DRW_pass_state_set(psl->transp_accum_infront_ps, state | wpd->cull_state | wpd->clip_state);
+ DRW_draw_pass(psl->transp_accum_infront_ps);
+ }
+ }
+} \ No newline at end of file
diff --git a/source/blender/draw/engines/workbench/workbench_volume.c b/source/blender/draw/engines/workbench/workbench_volume.c
index 2c61e894e8c..a3072b834bd 100644
--- a/source/blender/draw/engines/workbench/workbench_volume.c
+++ b/source/blender/draw/engines/workbench/workbench_volume.c
@@ -35,87 +35,23 @@
#include "GPU_draw.h"
-enum {
- VOLUME_SH_SLICE = 0,
- VOLUME_SH_COBA,
- VOLUME_SH_CUBIC,
-};
-
-#define VOLUME_SH_MAX (1 << (VOLUME_SH_CUBIC + 1))
-
-static struct {
- struct GPUShader *volume_sh[VOLUME_SH_MAX];
- struct GPUShader *volume_coba_sh;
- struct GPUTexture *dummy_tex;
- struct GPUTexture *dummy_coba_tex;
-} e_data = {{NULL}};
-
-extern char datatoc_workbench_volume_vert_glsl[];
-extern char datatoc_workbench_volume_frag_glsl[];
-extern char datatoc_common_view_lib_glsl[];
-extern char datatoc_gpu_shader_common_obinfos_lib_glsl[];
-
-static GPUShader *volume_shader_get(bool slice, bool coba, bool cubic)
+void workbench_volume_engine_init(WORKBENCH_Data *vedata)
{
- int id = 0;
- id += (slice) ? (1 << VOLUME_SH_SLICE) : 0;
- id += (coba) ? (1 << VOLUME_SH_COBA) : 0;
- id += (cubic) ? (1 << VOLUME_SH_CUBIC) : 0;
-
- if (!e_data.volume_sh[id]) {
- DynStr *ds = BLI_dynstr_new();
-
- if (slice) {
- BLI_dynstr_append(ds, "#define VOLUME_SLICE\n");
- }
- if (coba) {
- BLI_dynstr_append(ds, "#define USE_COBA\n");
- }
- if (cubic) {
- BLI_dynstr_append(ds, "#define USE_TRICUBIC\n");
- }
-
- char *defines = BLI_dynstr_get_cstring(ds);
- BLI_dynstr_free(ds);
-
- char *libs = BLI_string_joinN(datatoc_common_view_lib_glsl,
- datatoc_gpu_shader_common_obinfos_lib_glsl);
-
- e_data.volume_sh[id] = DRW_shader_create_with_lib(datatoc_workbench_volume_vert_glsl,
- NULL,
- datatoc_workbench_volume_frag_glsl,
- libs,
- defines);
-
- MEM_freeN(libs);
- MEM_freeN(defines);
- }
-
- return e_data.volume_sh[id];
-}
+ WORKBENCH_TextureList *txl = vedata->txl;
-void workbench_volume_engine_init(void)
-{
- if (!e_data.dummy_tex) {
+ if (txl->dummy_volume_tx == NULL) {
float pixel[4] = {0.0f, 0.0f, 0.0f, 0.0f};
- e_data.dummy_tex = GPU_texture_create_3d(1, 1, 1, GPU_RGBA8, pixel, NULL);
- e_data.dummy_coba_tex = GPU_texture_create_1d(1, GPU_RGBA8, pixel, NULL);
+ txl->dummy_volume_tx = GPU_texture_create_3d(1, 1, 1, GPU_RGBA8, pixel, NULL);
+ txl->dummy_coba_tx = GPU_texture_create_1d(1, GPU_RGBA8, pixel, NULL);
}
}
-void workbench_volume_engine_free(void)
-{
- for (int i = 0; i < VOLUME_SH_MAX; i++) {
- DRW_SHADER_FREE_SAFE(e_data.volume_sh[i]);
- }
- DRW_TEXTURE_FREE_SAFE(e_data.dummy_tex);
- DRW_TEXTURE_FREE_SAFE(e_data.dummy_coba_tex);
-}
-
void workbench_volume_cache_init(WORKBENCH_Data *vedata)
{
- vedata->psl->volume_pass = DRW_pass_create(
+ vedata->psl->volume_ps = DRW_pass_create(
"Volumes", DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL | DRW_STATE_CULL_FRONT);
+
+ vedata->stl->wpd->volumes_do = false;
}
void workbench_volume_cache_populate(WORKBENCH_Data *vedata,
@@ -125,8 +61,8 @@ void workbench_volume_cache_populate(WORKBENCH_Data *vedata,
{
FluidModifierData *mmd = (FluidModifierData *)md;
FluidDomainSettings *mds = mmd->domain;
- WORKBENCH_PrivateData *wpd = vedata->stl->g_data;
- WORKBENCH_EffectInfo *effect_info = vedata->stl->effects;
+ WORKBENCH_PrivateData *wpd = vedata->stl->wpd;
+ WORKBENCH_TextureList *txl = vedata->txl;
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
DRWShadingGroup *grp = NULL;
@@ -154,7 +90,8 @@ void workbench_volume_cache_populate(WORKBENCH_Data *vedata,
const bool use_slice = (mds->slice_method == FLUID_DOMAIN_SLICE_AXIS_ALIGNED &&
mds->axis_slice_method == AXIS_SLICE_SINGLE);
const bool cubic_interp = (mds->interp_method == VOLUME_INTERP_CUBIC);
- GPUShader *sh = volume_shader_get(use_slice, mds->use_coba, cubic_interp);
+
+ GPUShader *sh = workbench_shader_volume_get(use_slice, mds->use_coba, cubic_interp);
if (use_slice) {
float invviewmat[4][4];
@@ -168,7 +105,7 @@ void workbench_volume_cache_populate(WORKBENCH_Data *vedata,
/* 0.05f to achieve somewhat the same opacity as the full view. */
float step_length = max_ff(1e-16f, dim[axis] * 0.05f);
- grp = DRW_shgroup_create(sh, vedata->psl->volume_pass);
+ grp = DRW_shgroup_create(sh, vedata->psl->volume_ps);
DRW_shgroup_uniform_float_copy(grp, "slicePosition", mds->slice_depth);
DRW_shgroup_uniform_int_copy(grp, "sliceAxis", axis);
DRW_shgroup_uniform_float_copy(grp, "stepLength", step_length);
@@ -176,7 +113,7 @@ void workbench_volume_cache_populate(WORKBENCH_Data *vedata,
}
else {
double noise_ofs;
- BLI_halton_1d(3, 0.0, effect_info->jitter_index, &noise_ofs);
+ BLI_halton_1d(3, 0.0, wpd->taa_sample, &noise_ofs);
float dim[3], step_length, max_slice;
float slice_ct[3] = {mds->res[0], mds->res[1], mds->res[2]};
mul_v3_fl(slice_ct, max_ff(0.001f, mds->slice_per_voxel));
@@ -186,8 +123,8 @@ void workbench_volume_cache_populate(WORKBENCH_Data *vedata,
mul_v3_v3(dim, slice_ct);
step_length = len_v3(dim);
- grp = DRW_shgroup_create(sh, vedata->psl->volume_pass);
- DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)wpd->viewvecs, 3);
+ grp = DRW_shgroup_create(sh, vedata->psl->volume_ps);
+ DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo);
DRW_shgroup_uniform_int_copy(grp, "samplesLen", max_slice);
DRW_shgroup_uniform_float_copy(grp, "stepLength", step_length);
DRW_shgroup_uniform_float_copy(grp, "noiseOfs", noise_ofs);
@@ -206,9 +143,9 @@ void workbench_volume_cache_populate(WORKBENCH_Data *vedata,
grp, "densityTexture", (mds->tex_color) ? mds->tex_color : mds->tex_density);
DRW_shgroup_uniform_texture(grp, "shadowTexture", mds->tex_shadow);
DRW_shgroup_uniform_texture(
- grp, "flameTexture", (mds->tex_flame) ? mds->tex_flame : e_data.dummy_tex);
+ grp, "flameTexture", (mds->tex_flame) ? mds->tex_flame : txl->dummy_volume_tx);
DRW_shgroup_uniform_texture(
- grp, "flameColorTexture", (mds->tex_flame) ? mds->tex_flame_coba : e_data.dummy_coba_tex);
+ grp, "flameColorTexture", (mds->tex_flame) ? mds->tex_flame_coba : txl->dummy_coba_tx);
DRW_shgroup_uniform_vec3(
grp, "activeColor", (use_constant_color) ? mds->active_color : white, 1);
}
@@ -225,8 +162,22 @@ void workbench_volume_cache_populate(WORKBENCH_Data *vedata,
BLI_addtail(&wpd->smoke_domains, BLI_genericNodeN(mmd));
}
-void workbench_volume_smoke_textures_free(WORKBENCH_PrivateData *wpd)
+void workbench_volume_draw_pass(WORKBENCH_Data *vedata)
+{
+ WORKBENCH_PassList *psl = vedata->psl;
+ WORKBENCH_PrivateData *wpd = vedata->stl->wpd;
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+
+ if (wpd->volumes_do) {
+ GPU_framebuffer_bind(dfbl->color_only_fb);
+ DRW_draw_pass(psl->volume_ps);
+ }
+}
+
+void workbench_volume_draw_finish(WORKBENCH_Data *vedata)
{
+ WORKBENCH_PrivateData *wpd = vedata->stl->wpd;
+
/* Free Smoke Textures after rendering */
/* XXX This is a waste of processing and GPU bandwidth if nothing
* is updated. But the problem is since Textures are stored in the
@@ -238,4 +189,4 @@ void workbench_volume_smoke_textures_free(WORKBENCH_PrivateData *wpd)
GPU_free_smoke(mmd);
}
BLI_freelistN(&wpd->smoke_domains);
-}
+} \ No newline at end of file
diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h
index c3e94fda4fc..5122b1ea1ac 100644
--- a/source/blender/draw/intern/DRW_render.h
+++ b/source/blender/draw/intern/DRW_render.h
@@ -81,6 +81,7 @@ typedef struct DRWPass DRWPass;
typedef struct DRWShadingGroup DRWShadingGroup;
typedef struct DRWUniform DRWUniform;
typedef struct DRWView DRWView;
+typedef struct DRWShaderLibrary DRWShaderLibrary;
/* TODO Put it somewhere else? */
typedef struct BoundSphere {
@@ -148,6 +149,8 @@ struct GPUTexture *DRW_texture_pool_query_2d(int w,
int h,
eGPUTextureFormat format,
DrawEngineType *engine_type);
+struct GPUTexture *DRW_texture_pool_query_fullscreen(eGPUTextureFormat format,
+ DrawEngineType *engine_type);
struct GPUTexture *DRW_texture_create_1d(int w,
eGPUTextureFormat format,
@@ -246,6 +249,24 @@ void DRW_shader_free(struct GPUShader *shader);
} \
} while (0)
+DRWShaderLibrary *DRW_shader_library_create(void);
+
+/* Warning: Each library must be added after all its dependencies. */
+void DRW_shader_library_add_file(DRWShaderLibrary *lib, char *lib_code, const char *lib_name);
+#define DRW_SHADER_LIB_ADD(lib, lib_name) \
+ DRW_shader_library_add_file(lib, datatoc_##lib_name##_glsl, STRINGIFY(lib_name) ".glsl")
+
+char *DRW_shader_library_create_shader_string(DRWShaderLibrary *lib, char *shader_code);
+
+void DRW_shader_library_free(DRWShaderLibrary *lib);
+#define DRW_SHADER_LIB_FREE_SAFE(lib) \
+ do { \
+ if (lib != NULL) { \
+ DRW_shader_library_free(lib); \
+ lib = NULL; \
+ } \
+ } while (0)
+
/* Batches */
typedef enum {
@@ -403,6 +424,9 @@ void DRW_buffer_add_entry_array(DRWCallBuffer *buffer, const void *attr[], uint
DRW_buffer_add_entry_array(buffer, array, (sizeof(array) / sizeof(*array))); \
} while (0)
+/* Can only be called during iter phase. */
+uint32_t DRW_object_resource_id_get(Object *UNUSED(ob));
+
void DRW_shgroup_state_enable(DRWShadingGroup *shgroup, DRWState state);
void DRW_shgroup_state_disable(DRWShadingGroup *shgroup, DRWState state);
@@ -414,7 +438,7 @@ void DRW_shgroup_state_disable(DRWShadingGroup *shgroup, DRWState state);
void DRW_shgroup_stencil_set(DRWShadingGroup *shgroup,
uint write_mask,
uint reference,
- uint comp_mask);
+ uint compare_mask);
/* TODO remove this function. Obsolete version. mask is actually reference value. */
void DRW_shgroup_stencil_mask(DRWShadingGroup *shgroup, uint mask);
diff --git a/source/blender/draw/intern/draw_common.h b/source/blender/draw/intern/draw_common.h
index 24d3b7fa7b6..5818d84a7af 100644
--- a/source/blender/draw/intern/draw_common.h
+++ b/source/blender/draw/intern/draw_common.h
@@ -177,6 +177,11 @@ struct DRWShadingGroup *DRW_shgroup_hair_create(struct Object *object,
struct DRWPass *hair_pass,
struct GPUShader *shader);
+struct DRWShadingGroup *DRW_shgroup_hair_create_sub(struct Object *object,
+ struct ParticleSystem *psys,
+ struct ModifierData *md,
+ struct DRWShadingGroup *shgrp);
+
struct DRWShadingGroup *DRW_shgroup_material_hair_create(struct Object *object,
struct ParticleSystem *psys,
struct ModifierData *md,
diff --git a/source/blender/draw/intern/draw_hair.c b/source/blender/draw/intern/draw_hair.c
index 08256b931ba..847f5e7a224 100644
--- a/source/blender/draw/intern/draw_hair.c
+++ b/source/blender/draw/intern/draw_hair.c
@@ -108,6 +108,7 @@ static DRWShadingGroup *drw_shgroup_create_hair_procedural_ex(Object *object,
ParticleSystem *psys,
ModifierData *md,
DRWPass *hair_pass,
+ DRWShadingGroup *shgrp_parent,
struct GPUMaterial *gpu_mat,
GPUShader *gpu_shader)
{
@@ -127,7 +128,10 @@ static DRWShadingGroup *drw_shgroup_create_hair_procedural_ex(Object *object,
object, psys, md, &hair_cache, subdiv, thickness_res);
DRWShadingGroup *shgrp;
- if (gpu_mat) {
+ if (shgrp_parent) {
+ shgrp = DRW_shgroup_create_sub(shgrp_parent);
+ }
+ else if (gpu_mat) {
shgrp = DRW_shgroup_material_create(gpu_mat, hair_pass);
}
else if (gpu_shader) {
@@ -151,6 +155,17 @@ static DRWShadingGroup *drw_shgroup_create_hair_procedural_ex(Object *object,
}
}
+ /* Fix issue with certain driver not drawing anything if there is no texture bound to
+ * "ac", "au", "u" or "c". */
+ if (hair_cache->num_uv_layers == 0) {
+ DRW_shgroup_uniform_texture(shgrp, "u", hair_cache->final[subdiv].proc_tex);
+ DRW_shgroup_uniform_texture(shgrp, "au", hair_cache->final[subdiv].proc_tex);
+ }
+ if (hair_cache->num_col_layers == 0) {
+ DRW_shgroup_uniform_texture(shgrp, "c", hair_cache->final[subdiv].proc_tex);
+ DRW_shgroup_uniform_texture(shgrp, "ac", hair_cache->final[subdiv].proc_tex);
+ }
+
if ((dupli_parent != NULL) && (dupli_object != NULL)) {
if (dupli_object->type & OB_DUPLICOLLECTION) {
copy_m4_m4(dupli_mat, dupli_parent->obmat);
@@ -220,7 +235,15 @@ static DRWShadingGroup *drw_shgroup_create_hair_procedural_ex(Object *object,
DRWShadingGroup *DRW_shgroup_hair_create(
Object *object, ParticleSystem *psys, ModifierData *md, DRWPass *hair_pass, GPUShader *shader)
{
- return drw_shgroup_create_hair_procedural_ex(object, psys, md, hair_pass, NULL, shader);
+ return drw_shgroup_create_hair_procedural_ex(object, psys, md, hair_pass, NULL, NULL, shader);
+}
+
+DRWShadingGroup *DRW_shgroup_hair_create_sub(Object *object,
+ ParticleSystem *psys,
+ ModifierData *md,
+ DRWShadingGroup *shgrp)
+{
+ return drw_shgroup_create_hair_procedural_ex(object, psys, md, NULL, shgrp, NULL, NULL);
}
DRWShadingGroup *DRW_shgroup_material_hair_create(Object *object,
@@ -229,7 +252,7 @@ DRWShadingGroup *DRW_shgroup_material_hair_create(Object *object,
DRWPass *hair_pass,
struct GPUMaterial *material)
{
- return drw_shgroup_create_hair_procedural_ex(object, psys, md, hair_pass, material, NULL);
+ return drw_shgroup_create_hair_procedural_ex(object, psys, md, hair_pass, NULL, material, NULL);
}
void DRW_hair_update(void)
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c
index 85b071f5c89..9553117c179 100644
--- a/source/blender/draw/intern/draw_manager.c
+++ b/source/blender/draw/intern/draw_manager.c
@@ -1118,45 +1118,23 @@ static void use_drw_engine(DrawEngineType *engine)
BLI_addtail(&DST.enabled_engines, ld);
}
-/**
- * Use for external render engines.
- */
-static void drw_engines_enable_external(void)
-{
- use_drw_engine(DRW_engine_viewport_external_type.draw_engine);
-}
-
-/* TODO revisit this when proper layering is implemented */
/* Gather all draw engines needed and store them in DST.enabled_engines
* That also define the rendering order of engines */
-static void drw_engines_enable_from_engine(RenderEngineType *engine_type,
- eDrawType drawtype,
- bool use_xray)
+static void drw_engines_enable_from_engine(RenderEngineType *engine_type, eDrawType drawtype)
{
switch (drawtype) {
case OB_WIRE:
- use_drw_engine(&draw_engine_workbench_transparent);
- break;
-
case OB_SOLID:
- if (use_xray) {
- use_drw_engine(&draw_engine_workbench_transparent);
- }
- else {
- use_drw_engine(&draw_engine_workbench_solid);
- }
+ use_drw_engine(DRW_engine_viewport_workbench_type.draw_engine);
break;
-
case OB_MATERIAL:
case OB_RENDER:
default:
- /* TODO layers */
if (engine_type->draw_engine != NULL) {
use_drw_engine(engine_type->draw_engine);
}
-
- if ((engine_type->flag & RE_INTERNAL) == 0) {
- drw_engines_enable_external();
+ else if ((engine_type->flag & RE_INTERNAL) == 0) {
+ use_drw_engine(DRW_engine_viewport_external_type.draw_engine);
}
break;
}
@@ -1182,7 +1160,7 @@ static void drw_engines_enable(ViewLayer *UNUSED(view_layer),
const eDrawType drawtype = v3d->shading.type;
const bool use_xray = XRAY_ENABLED(v3d);
- drw_engines_enable_from_engine(engine_type, drawtype, use_xray);
+ drw_engines_enable_from_engine(engine_type, drawtype);
if (gpencil_engine_needed && ((drawtype >= OB_SOLID) || !use_xray)) {
use_drw_engine(&draw_engine_gpencil_type);
}
@@ -1608,6 +1586,9 @@ void DRW_draw_render_loop_offscreen(struct Depsgraph *depsgraph,
GPU_blend(true);
}
+ GPU_matrix_identity_set();
+ GPU_matrix_identity_projection_set();
+
GPU_viewport_unbind_from_offscreen(render_viewport, ofs, do_color_management);
if (draw_background) {
@@ -2646,9 +2627,6 @@ void DRW_engines_register(void)
RE_engines_register(&DRW_engine_viewport_eevee_type);
RE_engines_register(&DRW_engine_viewport_workbench_type);
- DRW_engine_register(&draw_engine_workbench_solid);
- DRW_engine_register(&draw_engine_workbench_transparent);
-
DRW_engine_register(&draw_engine_gpencil_type);
DRW_engine_register(&draw_engine_overlay_type);
diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c
index 83142da051a..be0dd7751ed 100644
--- a/source/blender/draw/intern/draw_manager_data.c
+++ b/source/blender/draw/intern/draw_manager_data.c
@@ -562,6 +562,16 @@ static DRWResourceHandle drw_resource_handle_new(float (*obmat)[4], Object *ob)
return handle;
}
+uint32_t DRW_object_resource_id_get(Object *UNUSED(ob))
+{
+ DRWResourceHandle handle = DST.ob_handle;
+ if (handle == 0) {
+ /* Handle not yet allocated. Return next handle. */
+ handle = DST.resource_handle;
+ }
+ return handle;
+}
+
static DRWResourceHandle drw_resource_handle(DRWShadingGroup *shgroup,
float (*obmat)[4],
Object *ob)
@@ -693,14 +703,14 @@ static void drw_command_set_select_id(DRWShadingGroup *shgroup, GPUVertBuf *buf,
static void drw_command_set_stencil_mask(DRWShadingGroup *shgroup,
uint write_mask,
uint reference,
- uint comp_mask)
+ uint compare_mask)
{
BLI_assert(write_mask <= 0xFF);
BLI_assert(reference <= 0xFF);
- BLI_assert(comp_mask <= 0xFF);
+ BLI_assert(compare_mask <= 0xFF);
DRWCommandSetStencil *cmd = drw_command_create(shgroup, DRW_CMD_STENCIL);
cmd->write_mask = write_mask;
- cmd->comp_mask = comp_mask;
+ cmd->comp_mask = compare_mask;
cmd->ref = reference;
}
@@ -1341,9 +1351,9 @@ void DRW_shgroup_state_disable(DRWShadingGroup *shgroup, DRWState state)
void DRW_shgroup_stencil_set(DRWShadingGroup *shgroup,
uint write_mask,
uint reference,
- uint comp_mask)
+ uint compare_mask)
{
- drw_command_set_stencil_mask(shgroup, write_mask, reference, comp_mask);
+ drw_command_set_stencil_mask(shgroup, write_mask, reference, compare_mask);
}
/* TODO remove this function. */
diff --git a/source/blender/draw/intern/draw_manager_shader.c b/source/blender/draw/intern/draw_manager_shader.c
index ed05fb85dc9..7b08f44921f 100644
--- a/source/blender/draw/intern/draw_manager_shader.c
+++ b/source/blender/draw/intern/draw_manager_shader.c
@@ -24,6 +24,7 @@
#include "DNA_world_types.h"
#include "DNA_material_types.h"
+#include "BLI_dynstr.h"
#include "BLI_listbase.h"
#include "BLI_string_utils.h"
#include "BLI_threads.h"
@@ -282,6 +283,8 @@ void DRW_deferred_shader_remove(GPUMaterial *mat)
/* -------------------------------------------------------------------- */
+/** \{ */
+
GPUShader *DRW_shader_create(const char *vert,
const char *geom,
const char *frag,
@@ -468,3 +471,129 @@ void DRW_shader_free(GPUShader *shader)
{
GPU_shader_free(shader);
}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Shader Library
+ *
+ * Simple include system for glsl files.
+ *
+ * Usage: Create a DRWShaderLibrary and add the library in the right order.
+ * You can have nested dependencies but each new library needs to have all its dependencies already
+ * added to the DRWShaderLibrary.
+ * Finally you can use DRW_shader_library_create_shader_string to get a shader string that also
+ * contains the needed libraries for this shader.
+ * \{ */
+
+/* 32 because we use a 32bit bitmap. */
+#define MAX_LIB 32
+#define MAX_LIB_NAME 64
+#define MAX_LIB_DEPS 8
+
+struct DRWShaderLibrary {
+ char *libs[MAX_LIB];
+ char libs_name[MAX_LIB][MAX_LIB_NAME];
+ uint32_t libs_deps[MAX_LIB];
+};
+
+DRWShaderLibrary *DRW_shader_library_create(void)
+{
+ return MEM_callocN(sizeof(DRWShaderLibrary), "DRWShaderLibrary");
+}
+
+void DRW_shader_library_free(DRWShaderLibrary *lib)
+{
+ MEM_SAFE_FREE(lib);
+}
+
+static int drw_shader_library_search(DRWShaderLibrary *lib, const char *name)
+{
+ for (int i = 0; i < MAX_LIB; i++) {
+ if (lib->libs[i]) {
+ if (!strncmp(lib->libs_name[i], name, strlen(lib->libs_name[i]))) {
+ return i;
+ }
+ }
+ else {
+ break;
+ }
+ }
+ return -1;
+}
+
+/* Return bitmap of dependencies. */
+static uint32_t drw_shader_dependencies_get(DRWShaderLibrary *lib, char *lib_code)
+{
+ /* Search dependencies. */
+ uint32_t deps = 0;
+ char *haystack = lib_code;
+ while ((haystack = strstr(haystack, "BLENDER_REQUIRE("))) {
+ haystack += 16;
+ int dep = drw_shader_library_search(lib, haystack);
+ if (dep == -1) {
+ printf(
+ "Error: Dependency not found.\n"
+ "This might be due to bad lib ordering.\n");
+ BLI_assert(0);
+ }
+ else {
+ deps |= 1u << (uint32_t)dep;
+ }
+ }
+ return deps;
+}
+
+void DRW_shader_library_add_file(DRWShaderLibrary *lib, char *lib_code, const char *lib_name)
+{
+ int index = -1;
+ for (int i = 0; i < MAX_LIB; i++) {
+ if (lib->libs[i] == NULL) {
+ index = i;
+ break;
+ }
+ }
+
+ if (index > -1) {
+ lib->libs[index] = lib_code;
+ BLI_strncpy(lib->libs_name[index], lib_name, MAX_LIB_NAME);
+ }
+ else {
+ printf("Error: Too many libraries. Cannot add %s.\n", lib_name);
+ BLI_assert(0);
+ }
+
+ lib->libs_deps[index] = drw_shader_dependencies_get(lib, lib_code);
+}
+
+/* Return an allocN'ed string containing the shader code with its dependencies prepended.
+ * Caller must free the string with MEM_freeN after use. */
+char *DRW_shader_library_create_shader_string(DRWShaderLibrary *lib, char *shader_code)
+{
+ uint32_t deps = drw_shader_dependencies_get(lib, shader_code);
+
+ DynStr *ds = BLI_dynstr_new();
+ /* Add all dependencies recursively. */
+ for (int i = MAX_LIB - 1; i > -1; i--) {
+ if (lib->libs[i] && (deps & (1u << (uint32_t)i))) {
+ deps |= lib->libs_deps[i];
+ }
+ }
+ /* Concatenate all needed libs into one string. */
+ for (int i = 0; i < MAX_LIB; i++) {
+ if (deps & 1u) {
+ BLI_dynstr_append(ds, lib->libs[i]);
+ }
+ deps = deps >> 1;
+ }
+
+ BLI_dynstr_append(ds, shader_code);
+
+ char *str = BLI_dynstr_get_cstring(ds);
+ BLI_dynstr_free(ds);
+
+ return str;
+}
+
+/** \} */
diff --git a/source/blender/draw/intern/draw_manager_texture.c b/source/blender/draw/intern/draw_manager_texture.c
index 373810b2f7f..c75299158a3 100644
--- a/source/blender/draw/intern/draw_manager_texture.c
+++ b/source/blender/draw/intern/draw_manager_texture.c
@@ -134,6 +134,13 @@ GPUTexture *DRW_texture_pool_query_2d(int w,
return tex;
}
+GPUTexture *DRW_texture_pool_query_fullscreen(eGPUTextureFormat format,
+ DrawEngineType *engine_type)
+{
+ const float *size = DRW_viewport_size_get();
+ return DRW_texture_pool_query_2d((int)size[0], (int)size[1], format, engine_type);
+}
+
void DRW_texture_ensure_fullscreen_2d(GPUTexture **tex,
eGPUTextureFormat format,
DRWTextureFlag flags)
diff --git a/source/blender/gpu/shaders/gpu_shader_common_obinfos_lib.glsl b/source/blender/gpu/shaders/gpu_shader_common_obinfos_lib.glsl
index aa1d437c307..9e1527a9e7f 100644
--- a/source/blender/gpu/shaders/gpu_shader_common_obinfos_lib.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_common_obinfos_lib.glsl
@@ -1,7 +1,8 @@
-/* Need to be included after common_view_lib.glsl for resource_id. */
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+
#ifndef GPU_OBINFOS_UBO
-#define GPU_OBINFOS_UBO
+# define GPU_OBINFOS_UBO
struct ObjectInfos {
vec4 drw_OrcoTexCoFactors[2];
vec4 drw_ObjectColor;
@@ -13,7 +14,7 @@ layout(std140) uniform infoBlock
/* DRW_RESOURCE_CHUNK_LEN = 512 */
ObjectInfos drw_infos[512];
};
-#define OrcoTexCoFactors (drw_infos[resource_id].drw_OrcoTexCoFactors)
-#define ObjectInfo (drw_infos[resource_id].drw_Infos)
-#define ObjectColor (drw_infos[resource_id].drw_ObjectColor)
+# define OrcoTexCoFactors (drw_infos[resource_id].drw_OrcoTexCoFactors)
+# define ObjectInfo (drw_infos[resource_id].drw_Infos)
+# define ObjectColor (drw_infos[resource_id].drw_ObjectColor)
#endif
diff --git a/source/blender/makesdna/DNA_view3d_enums.h b/source/blender/makesdna/DNA_view3d_enums.h
index de186700ed1..85522ea88a2 100644
--- a/source/blender/makesdna/DNA_view3d_enums.h
+++ b/source/blender/makesdna/DNA_view3d_enums.h
@@ -43,10 +43,6 @@ typedef enum eV3DShadingColorType {
V3D_SHADING_TEXTURE_COLOR = 3,
V3D_SHADING_OBJECT_COLOR = 4,
V3D_SHADING_VERTEX_COLOR = 5,
-
- /* Is used to display the object using the error color. For example when in
- * solid texture paint mode without any textures configured */
- V3D_SHADING_ERROR_COLOR = 999,
} eV3DShadingColorType;
/** #View3DShading.background_type */