diff options
author | Jeroen Bakker <j.bakker@atmind.nl> | 2018-04-25 11:59:48 +0300 |
---|---|---|
committer | Jeroen Bakker <j.bakker@atmind.nl> | 2018-04-25 12:09:49 +0300 |
commit | 35220ccde0cf77ee11f01ebd2c3d7b3f60d72903 (patch) | |
tree | af5ace5652995b3b355286639a5b67e784859f33 /source/blender/draw/engines/workbench | |
parent | fc8d9030000aa77dc26b8ff4c442672894e28ffc (diff) |
Silhouette Overlap Overlay
Added Object Overlap Overlay
- Added R32UI support to GPU_framebuffer
- Added R32U support to draw manager
- The overlay mode has a object data pass that will render 'needed' data to specific buffers so we can mix them together via a deferred rendering. In future will also add UV's and other data
- Overlap is implemented as an overlay so it could be used on top of the Scene lighted Solid mode (that will be rendered by Eevee.
Reviewers: fclem, brecht
Reviewed By: fclem
Subscribers: sergey
Tags: #code_quest
Maniphest Tasks: T54726
Differential Revision: https://developer.blender.org/D3174
Diffstat (limited to 'source/blender/draw/engines/workbench')
17 files changed, 414 insertions, 289 deletions
diff --git a/source/blender/draw/engines/workbench/shaders/solid_flat_frag.glsl b/source/blender/draw/engines/workbench/shaders/solid_flat_frag.glsl deleted file mode 100644 index 3a6700bdadc..00000000000 --- a/source/blender/draw/engines/workbench/shaders/solid_flat_frag.glsl +++ /dev/null @@ -1,8 +0,0 @@ -uniform vec3 color; - -out vec4 fragColor; - -void main() -{ - fragColor = vec4(color, 1.0); -} diff --git a/source/blender/draw/engines/workbench/shaders/solid_studio_frag.glsl b/source/blender/draw/engines/workbench/shaders/solid_studio_frag.glsl deleted file mode 100644 index 96e65e2919e..00000000000 --- a/source/blender/draw/engines/workbench/shaders/solid_studio_frag.glsl +++ /dev/null @@ -1,29 +0,0 @@ -uniform vec3 color; -uniform vec3 light_direction = vec3(0.0, 0.0, 1.0); - -uniform vec3 world_diffuse_light_xp = vec3(0.5, 0.5, 0.6); -uniform vec3 world_diffuse_light_xn = vec3(0.5, 0.5, 0.6); -uniform vec3 world_diffuse_light_yp = vec3(0.5, 0.5, 0.6); -uniform vec3 world_diffuse_light_yn = vec3(0.5, 0.5, 0.6); -uniform vec3 world_diffuse_light_zp = vec3(0.8, 0.8, 0.8); -uniform vec3 world_diffuse_light_zn = vec3(0.0, 0.0, 0.0); - -in vec3 normal_viewport; -out vec4 fragColor; -#define USE_WORLD_DIFFUSE -#define AMBIENT_COLOR vec3(0.2, 0.2, 0.2) - -void main() -{ - -#ifdef USE_WORLD_DIFFUSE - vec3 diffuse_light_color = get_world_diffuse_light(normal_viewport, world_diffuse_light_xp, world_diffuse_light_xn, world_diffuse_light_yp, world_diffuse_light_yn, world_diffuse_light_zp, world_diffuse_light_zn); - vec3 shaded_color = (AMBIENT_COLOR + diffuse_light_color) * color; - -#else - float intensity = lambert_diffuse(light_direction, normal_viewport); - vec3 shaded_color = color * intensity; - -#endif - fragColor = vec4(shaded_color, 1.0); -} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_background_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_background_lib.glsl new file mode 100644 index 00000000000..fb8c8fb95e4 --- /dev/null +++ b/source/blender/draw/engines/workbench/shaders/workbench_background_lib.glsl @@ -0,0 +1,3 @@ +vec3 background_color(WorldData world_data, float y) { + return mix(world_data.background_color_low, world_data.background_color_high, y).xyz; +} 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..ccb94f56db8 --- /dev/null +++ b/source/blender/draw/engines/workbench/shaders/workbench_composite_frag.glsl @@ -0,0 +1,59 @@ +out vec4 fragColor; + +uniform usampler2D objectId; +uniform sampler2D depth; +uniform sampler2D diffuseColor; +uniform sampler2D normalViewport; +uniform vec2 invertedViewportSize; + +uniform vec3 objectOverlapColor = vec3(0.0); + +layout(std140) uniform world_block { + WorldData world_data; +}; + + +void main() +{ + ivec2 texel = ivec2(gl_FragCoord.xy); + vec2 uvViewport = gl_FragCoord.xy * invertedViewportSize; + float depth = texelFetch(depth, texel, 0).r; + +#ifndef V3D_DRAWOPTION_OBJECT_OVERLAP + if (depth == 1.0) { + fragColor = vec4(background_color(world_data, uvViewport.y), 0.0); + return; + } +#else /* !V3D_DRAWOPTION_OBJECT_OVERLAP */ + uint object_id = depth == 1.0? NO_OBJECT_ID: texelFetch(objectId, texel, 0).r; + float object_overlap = calculate_object_overlap(objectId, texel, object_id); + + if (object_id == NO_OBJECT_ID) { + vec3 background = background_color(world_data, uvViewport.y); + if (object_overlap == 0.0) { + fragColor = vec4(background, 0.0); + } else { + fragColor = vec4(mix(objectOverlapColor, background, object_overlap), 1.0-object_overlap); + } + return; + } +#endif /* !V3D_DRAWOPTION_OBJECT_OVERLAP */ + + vec3 diffuse_color = texelFetch(diffuseColor, texel, 0).rgb; + +#ifdef V3D_LIGHTING_STUDIO + vec3 normal_viewport = texelFetch(normalViewport, texel, 0).rgb; + vec3 diffuse_light = get_world_diffuse_light(world_data, normal_viewport); + vec3 shaded_color = diffuse_light * diffuse_color; + +#else /* V3D_LIGHTING_STUDIO */ + vec3 shaded_color = diffuse_color; +#endif /* V3D_LIGHTING_STUDIO */ + + +#ifdef V3D_DRAWOPTION_OBJECT_OVERLAP + shaded_color = mix(objectOverlapColor, shaded_color, object_overlap); +#endif /* V3D_DRAWOPTION_OBJECT_OVERLAP */ + + fragColor = vec4(shaded_color, 1.0); +} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl new file mode 100644 index 00000000000..11497778fa4 --- /dev/null +++ b/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl @@ -0,0 +1,10 @@ +struct WorldData { + vec4 diffuse_light_xp; + vec4 diffuse_light_xn; + vec4 diffuse_light_yp; + vec4 diffuse_light_yn; + vec4 diffuse_light_zp; + vec4 diffuse_light_zn; + vec4 background_color_low; + vec4 background_color_high; +}; diff --git a/source/blender/draw/engines/workbench/shaders/workbench_diffuse_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_diffuse_lib.glsl deleted file mode 100644 index ab060745060..00000000000 --- a/source/blender/draw/engines/workbench/shaders/workbench_diffuse_lib.glsl +++ /dev/null @@ -1,21 +0,0 @@ -float normalized_dot(vec3 v1, vec3 v2) -{ - return max(0.0, dot(v1, v2)); -} - -float lambert_diffuse(vec3 light_direction, vec3 surface_normal) -{ - return normalized_dot(light_direction, surface_normal); -} - -vec3 get_world_diffuse_light(vec3 N, vec3 xp, vec3 xn, vec3 yp, vec3 yn, vec3 zp, vec3 zn) -{ - vec3 result = vec3(0.0, 0.0, 0.0); - result = mix(result, xp, normalized_dot(vec3( 1.0, 0.0, 0.0), N)); - result = mix(result, xn, normalized_dot(vec3(-1.0, 0.0, 0.0), N)); - result = mix(result, yp, normalized_dot(vec3( 0.0, 1.0, 0.0), N)); - result = mix(result, yn, normalized_dot(vec3( 0.0, -1.0, 0.0), N)); - result = mix(result, zp, normalized_dot(vec3( 0.0, 0.0, 1.0), N)); - result = mix(result, zn, normalized_dot(vec3( 0.0, 0.0, -1.0), N)); - return result; -} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_object_overlap_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_object_overlap_lib.glsl new file mode 100644 index 00000000000..f4c7c896d17 --- /dev/null +++ b/source/blender/draw/engines/workbench/shaders/workbench_object_overlap_lib.glsl @@ -0,0 +1,13 @@ +#define OBJECT_OVERLAP_OFFSET 1 +#define NO_OBJECT_ID uint(0) + +float calculate_object_overlap(usampler2D objectId, ivec2 texel, uint object_id) +{ + uvec4 oid_offset = uvec4( + texelFetchOffset(objectId, texel, 0, ivec2(0, OBJECT_OVERLAP_OFFSET)).r, + texelFetchOffset(objectId, texel, 0, ivec2(0, -OBJECT_OVERLAP_OFFSET)).r, + texelFetchOffset(objectId, texel, 0, ivec2(-OBJECT_OVERLAP_OFFSET, 0)).r, + texelFetchOffset(objectId, texel, 0, ivec2( OBJECT_OVERLAP_OFFSET, 0)).r); + + return dot(vec4(equal(uvec4(object_id), oid_offset)), vec4(1.0/4.0)); +}
\ No newline at end of file diff --git a/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl new file mode 100644 index 00000000000..208c684f722 --- /dev/null +++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl @@ -0,0 +1,15 @@ +uniform int object_id = 0; +uniform vec3 object_color = vec3(1.0, 0.0, 1.0); + +in vec3 normal_viewport; + +out uint objectId; +out vec3 diffuseColor; +out vec3 normalViewport; + +void main() +{ + objectId = uint(object_id); + diffuseColor = object_color; + normalViewport = normal_viewport; +} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_studio_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl index 2da5deabfc2..2da5deabfc2 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_studio_vert.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl diff --git a/source/blender/draw/engines/workbench/shaders/workbench_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_vert.glsl deleted file mode 100644 index 97639f03734..00000000000 --- a/source/blender/draw/engines/workbench/shaders/workbench_vert.glsl +++ /dev/null @@ -1,8 +0,0 @@ -uniform mat4 ModelViewProjectionMatrix; - -in vec3 pos; - -void main() -{ - gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); -} 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 new file mode 100644 index 00000000000..9257cae3e1d --- /dev/null +++ b/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl @@ -0,0 +1,9 @@ +vec3 get_world_diffuse_light(WorldData world_data, vec3 N) +{ + vec4 result = world_data.diffuse_light_xp * clamp(N.x, 0.0, 1.0); + result = mix(result, world_data.diffuse_light_xn, clamp(-N.x, 0.0, 1.0)); + result = mix(result, world_data.diffuse_light_yp, clamp( N.y, 0.0, 1.0)); + result = mix(result, world_data.diffuse_light_yn, clamp(-N.y, 0.0, 1.0)); + result = mix(result, world_data.diffuse_light_zp, clamp( N.z, 0.0, 1.0)); + return mix(result, world_data.diffuse_light_zn, clamp(-N.z, 0.0, 1.0)).xyz; +} diff --git a/source/blender/draw/engines/workbench/solid_flat_mode.c b/source/blender/draw/engines/workbench/solid_flat_mode.c deleted file mode 100644 index 7b096ad7a25..00000000000 --- a/source/blender/draw/engines/workbench/solid_flat_mode.c +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright 2016, Blender Foundation. - * - * 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. - * - * Contributor(s): Blender Institute - * - */ - -/** \file solid_flat_mode.c - * \ingroup draw_engine - * - * Simple engine for drawing color and/or depth. - * When we only need simple flat shaders. - */ - -#include "DRW_render.h" - -#include "GPU_shader.h" - -#include "workbench_private.h" -/* Functions */ - -static void workbench_solid_flat_engine_init(void *UNUSED(vedata)) -{ - workbench_materials_engine_init(); -} - -static void workbench_solid_flat_cache_init(void *vedata) -{ - WORKBENCH_Data * data = (WORKBENCH_Data *)vedata; - WORKBENCH_PassList *psl = data->psl; - WORKBENCH_StorageList *stl = data->stl; - - if (!stl->g_data) { - /* Alloc transient pointers */ - stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__); - } - - /* Depth Pass */ - { - int state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS; - psl->depth_pass = DRW_pass_create("Depth Pass", state); - } - - /* Solid Pass */ - { - int state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL; - psl->solid_pass = DRW_pass_create("Solid Pass", state); - } - - workbench_materials_cache_init(data); -} - - -static void workbench_solid_flat_cache_populate(void *vedata, Object *ob) -{ - WORKBENCH_Data * data = (WORKBENCH_Data *)vedata; - workbench_materials_solid_cache_populate(data, ob); -} - -static void workbench_solid_flat_cache_finish(void *UNUSED(vedata)) -{ -} - -static void workbench_solid_flat_draw_scene(void *vedata) -{ - WORKBENCH_Data *data = (WORKBENCH_Data *)vedata; - WORKBENCH_PassList *psl = data->psl; - - DRW_draw_pass(psl->depth_pass); - DRW_draw_pass(psl->solid_pass); - - workbench_materials_draw_scene_finish(data); -} - -static void workbench_solid_flat_engine_free(void) -{ - workbench_materials_engine_free(); -} - -static const DrawEngineDataSize workbench_data_size = DRW_VIEWPORT_DATA_SIZE(WORKBENCH_Data); - -DrawEngineType draw_engine_workbench_solid_flat = { - NULL, NULL, - N_("Workbench"), - &workbench_data_size, - &workbench_solid_flat_engine_init, - &workbench_solid_flat_engine_free, - &workbench_solid_flat_cache_init, - &workbench_solid_flat_cache_populate, - &workbench_solid_flat_cache_finish, - NULL, - &workbench_solid_flat_draw_scene, - NULL, - NULL, - NULL, -}; diff --git a/source/blender/draw/engines/workbench/solid_studio_mode.c b/source/blender/draw/engines/workbench/solid_mode.c index 046ad38fa91..7b5900cab39 100644 --- a/source/blender/draw/engines/workbench/solid_studio_mode.c +++ b/source/blender/draw/engines/workbench/solid_mode.c @@ -34,76 +34,59 @@ /* Functions */ -static void workbench_solid_studio_engine_init(void *UNUSED(vedata)) +static void workbench_solid_engine_init(void *vedata) { - workbench_materials_engine_init(); + WORKBENCH_Data * data = (WORKBENCH_Data *)vedata; + workbench_materials_engine_init(data); } -static void workbench_solid_studio_cache_init(void *vedata) +static void workbench_solid_cache_init(void *vedata) { WORKBENCH_Data * data = (WORKBENCH_Data *)vedata; - WORKBENCH_PassList *psl = data->psl; - WORKBENCH_StorageList *stl = data->stl; - - if (!stl->g_data) { - /* Alloc transient pointers */ - stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__); - } - - /* Depth Pass */ - { - int state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS; - psl->depth_pass = DRW_pass_create("Depth Pass", state); - } - - /* Solid Pass */ - { - int state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL; - psl->solid_pass = DRW_pass_create("Solid Pass", state); - } workbench_materials_cache_init(data); } -static void workbench_solid_studio_cache_populate(void *vedata, Object *ob) +static void workbench_solid_cache_populate(void *vedata, Object *ob) { WORKBENCH_Data * data = (WORKBENCH_Data *)vedata; workbench_materials_solid_cache_populate(data, ob); } -static void workbench_solid_studio_cache_finish(void *UNUSED(vedata)) +static void workbench_solid_cache_finish(void *vedata) { + WORKBENCH_Data * data = (WORKBENCH_Data *)vedata; + workbench_materials_cache_finish(data); } -static void workbench_solid_studio_draw_scene(void *vedata) +static void workbench_solid_draw_background(void *UNUSED(vedata)) { - WORKBENCH_Data * data = (WORKBENCH_Data *)vedata; - WORKBENCH_PassList *psl = data->psl; - - DRW_draw_pass(psl->depth_pass); - DRW_draw_pass(psl->solid_pass); +} - workbench_materials_draw_scene_finish(data); +static void workbench_solid_draw_scene(void *vedata) +{ + WORKBENCH_Data * data = (WORKBENCH_Data *)vedata; + workbench_materials_draw_scene(data); } -static void workbench_solid_studio_engine_free(void) +static void workbench_solid_engine_free(void) { workbench_materials_engine_free(); } static const DrawEngineDataSize workbench_data_size = DRW_VIEWPORT_DATA_SIZE(WORKBENCH_Data); -DrawEngineType draw_engine_workbench_solid_studio = { +DrawEngineType draw_engine_workbench_solid = { NULL, NULL, N_("Workbench"), &workbench_data_size, - &workbench_solid_studio_engine_init, - &workbench_solid_studio_engine_free, - &workbench_solid_studio_cache_init, - &workbench_solid_studio_cache_populate, - &workbench_solid_studio_cache_finish, - NULL, - &workbench_solid_studio_draw_scene, + &workbench_solid_engine_init, + &workbench_solid_engine_free, + &workbench_solid_cache_init, + &workbench_solid_cache_populate, + &workbench_solid_cache_finish, + &workbench_solid_draw_background, + &workbench_solid_draw_scene, NULL, NULL, NULL, diff --git a/source/blender/draw/engines/workbench/workbench_engine.c b/source/blender/draw/engines/workbench/workbench_engine.c index c93ff5cb2e9..689bdd4111b 100644 --- a/source/blender/draw/engines/workbench/workbench_engine.c +++ b/source/blender/draw/engines/workbench/workbench_engine.c @@ -48,6 +48,9 @@ static void workbench_layer_collection_settings_create(RenderEngine *UNUSED(engi BLI_assert(props && props->type == IDP_GROUP && props->subtype == IDP_GROUP_SUB_ENGINE_RENDER); + + BKE_collection_engine_property_add_float(props, "random_object_color_saturation", 0.5f); + BKE_collection_engine_property_add_float(props, "random_object_color_value", 0.9f); } /* Note: currently unused, we may want to register so we can see this when debugging the view. */ @@ -56,7 +59,7 @@ RenderEngineType DRW_engine_viewport_workbench_type = { NULL, NULL, WORKBENCH_ENGINE, N_("Workbench"), RE_INTERNAL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &workbench_layer_collection_settings_create, NULL, - &draw_engine_workbench_solid_flat, + &draw_engine_workbench_solid, {NULL, NULL, NULL} }; diff --git a/source/blender/draw/engines/workbench/workbench_engine.h b/source/blender/draw/engines/workbench/workbench_engine.h index 306579880ca..0cbbe8df4af 100644 --- a/source/blender/draw/engines/workbench/workbench_engine.h +++ b/source/blender/draw/engines/workbench/workbench_engine.h @@ -26,8 +26,7 @@ #ifndef __WORKBENCH_ENGINE_H__ #define __WORKBENCH_ENGINE_H__ -extern DrawEngineType draw_engine_workbench_solid_flat; -extern DrawEngineType draw_engine_workbench_solid_studio; +extern DrawEngineType draw_engine_workbench_solid; extern RenderEngineType DRW_engine_viewport_workbench_type; #endif /* __WORKBENCH_ENGINE_H__ */ diff --git a/source/blender/draw/engines/workbench/workbench_materials.c b/source/blender/draw/engines/workbench/workbench_materials.c index 97d370795bc..388720ba8ec 100644 --- a/source/blender/draw/engines/workbench/workbench_materials.c +++ b/source/blender/draw/engines/workbench/workbench_materials.c @@ -24,107 +24,240 @@ */ #include "workbench_private.h" + +#include "BLI_dynstr.h" +#include "UI_resources.h" #include "GPU_shader.h" /* *********** STATIC *********** */ +#define MAX_SHADERS 255 static struct { - struct GPUShader *depth_sh; - - /* Solid flat mode */ - struct GPUShader *solid_flat_sh; + struct GPUShader *prepass_sh_cache[MAX_SHADERS]; + struct GPUShader *composite_sh_cache[MAX_SHADERS]; - /* Solid studio mode */ - struct GPUShader *solid_studio_sh; + struct GPUTexture *object_id_tx; /* ref only, not alloced */ + struct GPUTexture *diffuse_color_tx; /* ref only, not alloced */ + struct GPUTexture *normal_viewport_tx; /* ref only, not alloced */ + int next_object_id; } e_data = {NULL}; /* Shaders */ -extern char datatoc_solid_flat_frag_glsl[]; -extern char datatoc_solid_studio_frag_glsl[]; -extern char datatoc_workbench_vert_glsl[]; -extern char datatoc_workbench_studio_vert_glsl[]; -extern char datatoc_workbench_diffuse_lib_glsl[]; +extern char datatoc_workbench_prepass_vert_glsl[]; +extern char datatoc_workbench_prepass_frag_glsl[]; +extern char datatoc_workbench_composite_frag_glsl[]; -/* Functions */ -static uint get_material_hash(const float color[3]) +extern char datatoc_workbench_background_lib_glsl[]; +extern char datatoc_workbench_data_lib_glsl[]; +extern char datatoc_workbench_object_overlap_lib_glsl[]; +extern char datatoc_workbench_world_light_lib_glsl[]; + +extern DrawEngineType draw_engine_workbench_solid; + +#define OBJECT_ID_PASS_ENABLED(wpd) (wpd->drawtype_options & V3D_DRAWOPTION_OBJECT_OVERLAP) +#define NORMAL_VIEWPORT_PASS_ENABLED(wpd) (wpd->drawtype_lighting & V3D_LIGHTING_STUDIO) + +static char *workbench_build_defines(WORKBENCH_PrivateData *wpd) { - uint r = (uint)(color[0] * 512); - uint g = (uint)(color[1] * 512); - uint b = (uint)(color[2] * 512); + char *str = NULL; - return r + g * 4096 + b * 4096 * 4096; + DynStr *ds = BLI_dynstr_new(); + + if (wpd->drawtype_options & V3D_DRAWOPTION_OBJECT_OVERLAP) { + BLI_dynstr_appendf(ds, "#define V3D_DRAWOPTION_OBJECT_OVERLAP\n"); + } + if (wpd->drawtype_lighting & V3D_LIGHTING_STUDIO) { + BLI_dynstr_appendf(ds, "#define V3D_LIGHTING_STUDIO\n"); + } + + str = BLI_dynstr_get_cstring(ds); + BLI_dynstr_free(ds); + return str; } -static void get_material_solid_color(WORKBENCH_PrivateData *wpd, Object *ob, float *color) +static char *workbench_build_composite_frag(WORKBENCH_PrivateData *wpd) { - if (wpd->drawtype_options & V3D_DRAWOPTION_RANDOMIZE) { - unsigned int obhash = BLI_ghashutil_strhash(ob->id.name); - cpack_to_rgb(obhash, &color[0], &color[1], &color[2]); + char *str = NULL; + DynStr *ds = BLI_dynstr_new(); + + BLI_dynstr_append(ds, datatoc_workbench_data_lib_glsl); + BLI_dynstr_append(ds, datatoc_workbench_background_lib_glsl); + + if (wpd->drawtype_lighting & V3D_LIGHTING_STUDIO) { + BLI_dynstr_append(ds, datatoc_workbench_world_light_lib_glsl); } - else { - copy_v3_v3(color, ob->col); + if (wpd->drawtype_options & V3D_DRAWOPTION_OBJECT_OVERLAP) { + BLI_dynstr_append(ds, datatoc_workbench_object_overlap_lib_glsl); + } + + BLI_dynstr_append(ds, datatoc_workbench_composite_frag_glsl); + + str = BLI_dynstr_get_cstring(ds); + BLI_dynstr_free(ds); + return str; +} + +static int get_shader_index(WORKBENCH_PrivateData *wpd) +{ + return (wpd->drawtype_options << 2) + wpd->drawtype_lighting; +} + +static void select_deferred_shaders(WORKBENCH_PrivateData *wpd) +{ + int index = get_shader_index(wpd); + + if (e_data.prepass_sh_cache[index] == NULL) { + char *defines = workbench_build_defines(wpd); + char *composite_frag = workbench_build_composite_frag(wpd); + e_data.prepass_sh_cache[index] = DRW_shader_create(datatoc_workbench_prepass_vert_glsl, NULL, datatoc_workbench_prepass_frag_glsl, defines); + e_data.composite_sh_cache[index] = DRW_shader_create_fullscreen(composite_frag, defines); + MEM_freeN(defines); + MEM_freeN(composite_frag); } + + wpd->prepass_sh = e_data.prepass_sh_cache[index]; + wpd->composite_sh = e_data.composite_sh_cache[index]; } -void workbench_materials_engine_init(void) +/* Functions */ +static uint get_material_hash(WORKBENCH_PrivateData *wpd, WORKBENCH_MaterialData *material_template) { - if (!e_data.depth_sh) { - /* Depth pass */ - e_data.depth_sh = DRW_shader_create_3D_depth_only(); + uint input[4]; + float *color = material_template->color; + input[0] = (uint)(color[0] * 512); + input[1] = (uint)(color[1] * 512); + input[2] = (uint)(color[2] * 512); - /* Solid flat */ - e_data.solid_flat_sh = DRW_shader_create(datatoc_workbench_vert_glsl, NULL, datatoc_solid_flat_frag_glsl, "\n"); - e_data.solid_studio_sh = DRW_shader_create(datatoc_workbench_studio_vert_glsl, NULL, datatoc_solid_studio_frag_glsl, datatoc_workbench_diffuse_lib_glsl); + /* Only hash object id when needed */ + input[3] = (uint)0; + if (OBJECT_ID_PASS_ENABLED(wpd)) { + input[3] = material_template->object_id; } + + return BLI_ghashutil_uinthash_v4_murmur(input); } -void workbench_materials_engine_free() +static void workbench_init_object_data(ObjectEngineData *engine_data) { - DRW_SHADER_FREE_SAFE(e_data.solid_flat_sh); - DRW_SHADER_FREE_SAFE(e_data.solid_studio_sh); + WORKBENCH_ObjectData *data = (WORKBENCH_ObjectData*)engine_data; + data->object_id = e_data.next_object_id++; +} +static void get_material_solid_color(WORKBENCH_PrivateData *wpd, WORKBENCH_ObjectData *engine_object_data, Object *ob, float *color, float hsv_saturation, float hsv_value) +{ + if (wpd->drawtype_options & V3D_DRAWOPTION_RANDOMIZE) { + float offset = fmodf(engine_object_data->object_id * M_GOLDEN_RATION_CONJUGATE, 1.0); + float hsv[3] = {offset, hsv_saturation, hsv_value}; + hsv_to_rgb_v(hsv, color); + } + else { + copy_v3_v3(color, ob->col); + } } -void workbench_materials_draw_scene_finish(WORKBENCH_Data *vedata) +void workbench_materials_engine_init(WORKBENCH_Data *vedata) { + WORKBENCH_FramebufferList *fbl = vedata->fbl; WORKBENCH_StorageList *stl = vedata->stl; - WORKBENCH_PrivateData *wpd = stl->g_data; + WORKBENCH_PassList *psl = vedata->psl; + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); - BLI_ghash_free(wpd->material_hash, NULL, MEM_freeN); + if (!e_data.next_object_id) { + memset(e_data.prepass_sh_cache, 0x00, sizeof(struct GPUShader *) * MAX_SHADERS); + memset(e_data.composite_sh_cache, 0x00, sizeof(struct GPUShader *) * MAX_SHADERS); + e_data.next_object_id = 1; + } + + if (!stl->g_data) { + /* Alloc transient pointers */ + stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__); + } + + { + const float *viewport_size = DRW_viewport_size_get(); + const int size[2] = {(int)viewport_size[0], (int)viewport_size[1]}; + e_data.object_id_tx = DRW_texture_pool_query_2D(size[0], size[1], DRW_TEX_R_32U, &draw_engine_workbench_solid); + e_data.diffuse_color_tx = DRW_texture_pool_query_2D(size[0], size[1], DRW_TEX_RGBA_32, &draw_engine_workbench_solid); + e_data.normal_viewport_tx = DRW_texture_pool_query_2D(size[0], size[1], DRW_TEX_RGBA_32, &draw_engine_workbench_solid); + + GPU_framebuffer_ensure_config(&fbl->prepass_fb, { + GPU_ATTACHMENT_TEXTURE(dtxl->depth), + GPU_ATTACHMENT_TEXTURE(e_data.object_id_tx), + GPU_ATTACHMENT_TEXTURE(e_data.diffuse_color_tx), + GPU_ATTACHMENT_TEXTURE(e_data.normal_viewport_tx), + }); + } + + /* Prepass */ + { + int state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS; + psl->prepass_pass = DRW_pass_create("Prepass", state); + } } +void workbench_materials_engine_free() +{ + for (int index = 0; index < MAX_SHADERS; index ++) { + DRW_SHADER_FREE_SAFE(e_data.prepass_sh_cache[index]); + DRW_SHADER_FREE_SAFE(e_data.composite_sh_cache[index]); + } +} void workbench_materials_cache_init(WORKBENCH_Data *vedata) { WORKBENCH_StorageList *stl = vedata->stl; WORKBENCH_PassList *psl = vedata->psl; WORKBENCH_PrivateData *wpd = stl->g_data; + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + DRWShadingGroup *grp; const DRWContextState *DCS = DRW_context_state_get(); - wpd->depth_shgrp = DRW_shgroup_create(e_data.depth_sh, psl->depth_pass); - wpd->material_hash = BLI_ghash_ptr_new("Workbench material_hash"); + wpd->material_hash = BLI_ghash_ptr_new(__func__); View3D *v3d = DCS->v3d; if (v3d) { -#if 0 - /* TODO: switch implementation when OB_TEXTURE is implemented */ - switch (v3d->drawtype) { - default: - case OB_SOLID: - wpd->drawtype_lighting = v3d->drawtype_lighting; - break; - } -#else wpd->drawtype_lighting = v3d->drawtype_lighting; wpd->drawtype_options = v3d->drawtype_options; -#endif } else { wpd->drawtype_lighting = V3D_LIGHTING_STUDIO; wpd->drawtype_options = 0; } + + select_deferred_shaders(wpd); + /* Deferred Mix Pass */ + { + WORKBENCH_UBO_World *wd = &wpd->world_data; + wd->diffuse_light_xp[0] = 0.8; wd->diffuse_light_xp[1] = 0.8; wd->diffuse_light_xp[2] = 1.0; + wd->diffuse_light_xn[0] = 0.8; wd->diffuse_light_xn[1] = 0.8; wd->diffuse_light_xn[2] = 1.0; + wd->diffuse_light_yp[0] = 0.8; wd->diffuse_light_yp[1] = 0.8; wd->diffuse_light_yp[2] = 1.0; + wd->diffuse_light_yn[0] = 0.8; wd->diffuse_light_yn[1] = 0.8; wd->diffuse_light_yn[2] = 1.0; + wd->diffuse_light_zp[0] = 1.0; wd->diffuse_light_zp[1] = 1.0; wd->diffuse_light_zp[2] = 1.0; + wd->diffuse_light_zn[0] = 0.0; wd->diffuse_light_zn[1] = 0.0; wd->diffuse_light_zn[2] = 0.0; + UI_GetThemeColor3fv(UI_GetThemeValue(TH_SHOW_BACK_GRAD)?TH_LOW_GRAD:TH_HIGH_GRAD, wd->background_color_low); + UI_GetThemeColor3fv(TH_HIGH_GRAD, wd->background_color_high); + + psl->composite_pass = DRW_pass_create("Composite", DRW_STATE_WRITE_COLOR); + grp = DRW_shgroup_create(wpd->composite_sh, psl->composite_pass); + DRW_shgroup_uniform_texture_ref(grp, "depth", &dtxl->depth); + DRW_shgroup_uniform_texture_ref(grp, "diffuseColor", &e_data.diffuse_color_tx); + if (OBJECT_ID_PASS_ENABLED(wpd)) { + DRW_shgroup_uniform_texture_ref(grp, "objectId", &e_data.object_id_tx); + } + if (NORMAL_VIEWPORT_PASS_ENABLED(wpd)) { + DRW_shgroup_uniform_texture_ref(grp, "normalViewport", &e_data.normal_viewport_tx); + } + wpd->world_ubo = DRW_uniformbuffer_create(sizeof(WORKBENCH_UBO_World), NULL); + DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo); + DRW_uniformbuffer_update(wpd->world_ubo, &wpd->world_data); + DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1); + + DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); + } + + } void workbench_materials_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob) @@ -136,29 +269,75 @@ void workbench_materials_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob if (!DRW_object_is_renderable(ob)) return; + struct Gwn_Batch *geom = DRW_cache_object_surface_get(ob); + IDProperty *props = BKE_layer_collection_engine_evaluated_get(ob, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_WORKBENCH); + WORKBENCH_MaterialData *material; if (geom) { - /* Depth */ - DRW_shgroup_call_add(stl->g_data->depth_shgrp, geom, ob->obmat); + const DRWContextState *draw_ctx = DRW_context_state_get(); + const bool is_active = (ob == draw_ctx->obact); + WORKBENCH_ObjectData *engine_object_data = (WORKBENCH_ObjectData*)DRW_object_engine_data_ensure(ob, &draw_engine_workbench_solid, sizeof(WORKBENCH_ObjectData), &workbench_init_object_data, NULL); + WORKBENCH_MaterialData material_template; + float color[3]; + const float hsv_saturation = BKE_collection_engine_property_value_get_float(props, "random_object_color_saturation"); + const float hsv_value = BKE_collection_engine_property_value_get_float(props, "random_object_color_value"); /* Solid */ - GPUShader *shader = wpd->drawtype_lighting == V3D_LIGHTING_FLAT ? e_data.solid_flat_sh : e_data.solid_studio_sh; - - float color[3]; - get_material_solid_color(wpd, ob, color); - unsigned int hash = get_material_hash(color); + get_material_solid_color(wpd, engine_object_data, ob, color, hsv_saturation, hsv_value); + copy_v3_v3(material_template.color, color); + material_template.object_id = engine_object_data->object_id; + unsigned int hash = get_material_hash(wpd, &material_template); material = BLI_ghash_lookup(wpd->material_hash, SET_UINT_IN_POINTER(hash)); if (material == NULL) { - material = MEM_mallocN(sizeof(WORKBENCH_MaterialData), "WORKBENCH_MaterialData"); - material->shgrp = DRW_shgroup_create(shader, psl->solid_pass); - copy_v3_v3(material->color, color); - DRW_shgroup_uniform_vec3(material->shgrp, "color", material->color, 1); + material = MEM_mallocN(sizeof(WORKBENCH_MaterialData), __func__); + material->shgrp = DRW_shgroup_create(wpd->prepass_sh, psl->prepass_pass); + material->object_id = engine_object_data->object_id; + copy_v3_v3(material->color, material_template.color); + DRW_shgroup_uniform_vec3(material->shgrp, "object_color", material->color, 1); + DRW_shgroup_uniform_int(material->shgrp, "object_id", &material->object_id, 1); BLI_ghash_insert(wpd->material_hash, SET_UINT_IN_POINTER(hash), material); } - DRW_shgroup_call_add(material->shgrp, geom, ob->obmat); + const bool is_sculpt_mode = is_active && (draw_ctx->object_mode & OB_MODE_SCULPT) != 0; + if(is_sculpt_mode) { + DRW_shgroup_call_sculpt_add(material->shgrp, ob, ob->obmat); + } + else { + DRW_shgroup_call_object_add(material->shgrp, geom, ob); + } } +} +void workbench_materials_cache_finish(WORKBENCH_Data *UNUSED(vedata)) +{ } + +void workbench_materials_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(); + const float clear_depth = 1.0f; + + GPU_framebuffer_bind(fbl->prepass_fb); + if (OBJECT_ID_PASS_ENABLED(wpd)) { + const float clear_color[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + GPU_framebuffer_clear_color_depth(fbl->prepass_fb, clear_color, clear_depth); + } + else { + GPU_framebuffer_clear_depth(fbl->prepass_fb, clear_depth); + } + DRW_draw_pass(psl->prepass_pass); + + GPU_framebuffer_bind(dfbl->color_only_fb); + DRW_draw_pass(psl->composite_pass); + + BLI_ghash_free(wpd->material_hash, NULL, MEM_freeN); + DRW_UBO_FREE_SAFE(wpd->world_ubo); + +} + diff --git a/source/blender/draw/engines/workbench/workbench_private.h b/source/blender/draw/engines/workbench/workbench_private.h index 8e61828f063..079a0759731 100644 --- a/source/blender/draw/engines/workbench/workbench_private.h +++ b/source/blender/draw/engines/workbench/workbench_private.h @@ -31,46 +31,73 @@ #include "DNA_view3d_types.h" #define WORKBENCH_ENGINE "BLENDER_WORKBENCH" +#define M_GOLDEN_RATION_CONJUGATE 0.618033988749895 +typedef struct WORKBENCH_FramebufferList { + struct GPUFrameBuffer *prepass_fb; +} WORKBENCH_FramebufferList; typedef struct WORKBENCH_StorageList { struct WORKBENCH_PrivateData *g_data; } WORKBENCH_StorageList; typedef struct WORKBENCH_PassList { - struct DRWPass *depth_pass; - struct DRWPass *solid_pass; + struct DRWPass *prepass_pass; + struct DRWPass *composite_pass; } WORKBENCH_PassList; typedef struct WORKBENCH_Data { void *engine_type; - DRWViewportEmptyList *fbl; + WORKBENCH_FramebufferList *fbl; DRWViewportEmptyList *txl; WORKBENCH_PassList *psl; WORKBENCH_StorageList *stl; } WORKBENCH_Data; -typedef struct WORKBENCH_PrivateData { - DRWShadingGroup *depth_shgrp; - - DRWShadingGroup *shadeless_shgrp; +typedef struct WORKBENCH_UBO_World { + float diffuse_light_xp[4]; + float diffuse_light_xn[4]; + float diffuse_light_yp[4]; + float diffuse_light_yn[4]; + float diffuse_light_zp[4]; + float diffuse_light_zn[4]; + float background_color_low[4]; + float background_color_high[4]; +} WORKBENCH_UBO_World; +BLI_STATIC_ASSERT_ALIGN(WORKBENCH_UBO_World, 16) +typedef struct WORKBENCH_PrivateData { struct GHash *material_hash; + struct GPUShader *prepass_sh; + struct GPUShader *composite_sh; short drawtype_lighting; short drawtype_options; + struct GPUUniformBuffer *world_ubo; + WORKBENCH_UBO_World world_data; } WORKBENCH_PrivateData; /* Transient data */ typedef struct WORKBENCH_MaterialData { /* Solid color */ float color[3]; + int object_id; /* Linked shgroup for drawing */ DRWShadingGroup *shgrp; } WORKBENCH_MaterialData; +typedef struct WORKBENCH_ObjectData { + struct ObjectEngineData *next, *prev; + struct DrawEngineType *engine_type; + /* Only nested data, NOT the engine data itself. */ + ObjectEngineDataFreeCb free; + /* Accumulated recalc flags, which corresponds to ID->recalc flags. */ + int recalc; + + int object_id; +} WORKBENCH_ObjectData; /* workbench_engine.c */ -void workbench_solid_materials_init(void); +void workbench_solid_materials_init(WORKBENCH_Data *vedata); void workbench_solid_materials_cache_init(WORKBENCH_Data *vedata); void workbench_solid_materials_cache_populate(WORKBENCH_Data *vedata, Object *ob); void workbench_solid_materials_cache_finish(WORKBENCH_Data *vedata); @@ -78,10 +105,11 @@ void workbench_solid_materials_draw_scene(WORKBENCH_Data *vedata); void workbench_solid_materials_free(void); /* workbench_materials.c */ -void workbench_materials_engine_init(void); +void workbench_materials_engine_init(WORKBENCH_Data *vedata); void workbench_materials_engine_free(void); -void workbench_materials_draw_scene_finish(WORKBENCH_Data *vedata); +void workbench_materials_draw_scene(WORKBENCH_Data *vedata); void workbench_materials_cache_init(WORKBENCH_Data *vedata); void workbench_materials_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob); +void workbench_materials_cache_finish(WORKBENCH_Data *vedata); #endif |