diff options
author | Jeroen Bakker <j.bakker@atmind.nl> | 2018-05-22 15:12:47 +0300 |
---|---|---|
committer | Jeroen Bakker <j.bakker@atmind.nl> | 2018-05-22 15:55:50 +0300 |
commit | dfe088c5d9c819e7266e8e88fb31e92ac2ee8592 (patch) | |
tree | 893d823c1957624257c3ef128422c3fa132e9049 /source | |
parent | ff19b527e85ec5144efbd663bf9b4c338e179358 (diff) |
Workbench: SeeThrough draw option
Option to see through all meshes (transparency)
Works for OB_SOLID and OB_TEXTURED. Does not work for
V3D_SHADING_SHADOW.
TODO: Fresnel effect
Diffstat (limited to 'source')
24 files changed, 1518 insertions, 717 deletions
diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c index 63fe9642ee7..be0ae64faa4 100644 --- a/source/blender/blenloader/intern/versioning_280.c +++ b/source/blender/blenloader/intern/versioning_280.c @@ -1479,6 +1479,19 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main) } } + if (!DNA_struct_elem_find(fd->filesdna, "View3DShading", "float", "see_through_transparency")) { + for (bScreen *screen = main->screen.first; screen; screen = screen->id.next) { + for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { + for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) { + if (sl->spacetype == SPACE_VIEW3D) { + View3D *v3d = (View3D *)sl; + v3d->shading.see_through_transparency = 0.3f; + } + } + } + } + } + for (Scene *scene = main->scene.first; scene; scene = scene->id.next) { switch (scene->toolsettings->snap_mode) { case 0: scene->toolsettings->snap_mode = SCE_SNAP_MODE_INCREMENT; break; diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 9478d41f6db..71bdcc7496c 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -105,10 +105,14 @@ set(SRC engines/eevee/eevee_subsurface.c engines/eevee/eevee_temporal_sampling.c engines/eevee/eevee_volumes.c + engines/workbench/workbench_data.c engines/workbench/workbench_engine.c + engines/workbench/workbench_deferred.c + engines/workbench/workbench_forward.c engines/workbench/workbench_materials.c engines/workbench/workbench_studiolight.c engines/workbench/solid_mode.c + engines/workbench/transparent_mode.c engines/external/external_engine.c DRW_engine.h @@ -208,17 +212,20 @@ data_to_c_simple(engines/eevee/shaders/volumetric_resolve_frag.glsl SRC) 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_background_lib.glsl SRC) +data_to_c_simple(engines/workbench/shaders/workbench_common_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_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_object_outline_lib.glsl SRC) data_to_c_simple(engines/workbench/shaders/workbench_prepass_vert.glsl SRC) data_to_c_simple(engines/workbench/shaders/workbench_prepass_frag.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_composite_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_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_background_lib.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_common_lib.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_data_lib.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_object_overlap_lib.glsl SRC) data_to_c_simple(engines/workbench/shaders/workbench_world_light_lib.glsl SRC) data_to_c_simple(modes/shaders/common_globals_lib.glsl SRC) 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 a698a5afeaa..e72ee1c2eac 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl @@ -7,4 +7,6 @@ struct WorldData { vec4 diffuse_light_z_neg; vec4 background_color_low; vec4 background_color_high; + vec4 object_outline_color; + float see_through_transparency; }; diff --git a/source/blender/draw/engines/workbench/shaders/workbench_composite_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_deferred_composite_frag.glsl index 17477e56b40..35867a566f1 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_composite_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_deferred_composite_frag.glsl @@ -5,7 +5,6 @@ uniform sampler2D colorBuffer; uniform sampler2D normalBuffer; /* normalBuffer contains viewport normals */ uniform vec2 invertedViewportSize; -uniform vec3 objectOverlapColor = vec3(0.0); uniform float shadowMultiplier; uniform float lightMultiplier; uniform float shadowShift = 0.1; @@ -29,15 +28,15 @@ void main() return; } #else /* !V3D_SHADING_OBJECT_OUTLINE */ - float object_overlap = calculate_object_overlap(objectId, texel, object_id); + float object_outline = calculate_object_outline(objectId, texel, object_id); if (object_id == NO_OBJECT_ID) { vec3 background = background_color(world_data, uv_viewport.y); - if (object_overlap == 0.0) { + if (object_outline == 0.0) { fragColor = vec4(background, 0.0); } else { - fragColor = vec4(mix(objectOverlapColor, background, object_overlap), 1.0-object_overlap); + fragColor = vec4(mix(world_data.object_outline_color.rgb, background, object_outline), 1.0-object_outline); } return; } @@ -84,7 +83,7 @@ void main() shaded_color *= light_multiplier; #ifdef V3D_SHADING_OBJECT_OUTLINE - shaded_color = mix(objectOverlapColor, shaded_color, object_overlap); + shaded_color = mix(world_data.object_outline_color.rgb, shaded_color, object_outline); #endif /* V3D_SHADING_OBJECT_OUTLINE */ fragColor = vec4(shaded_color, 1.0); } 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 new file mode 100644 index 00000000000..054e8d308cb --- /dev/null +++ b/source/blender/draw/engines/workbench/shaders/workbench_forward_composite_frag.glsl @@ -0,0 +1,34 @@ +out vec4 fragColor; + +uniform usampler2D objectId; +uniform sampler2D transparentAccum; +uniform sampler2D transparentRevealage; +uniform vec2 invertedViewportSize; + +layout(std140) uniform world_block { + WorldData world_data; +}; + +void main() +{ + ivec2 texel = ivec2(gl_FragCoord.xy); + vec2 uv_viewport = gl_FragCoord.xy * invertedViewportSize; + uint object_id = texelFetch(objectId, texel, 0).r; + vec4 transparent_accum = texelFetch(transparentAccum, texel, 0); + float revealage = texelFetch(transparentRevealage, texel, 0).r; + vec4 color; + +#ifdef V3D_SHADING_OBJECT_OUTLINE + float outline = calculate_object_outline(objectId, texel, object_id); +#else /* V3D_SHADING_OBJECT_OUTLINE */ + float outline = 1.0; +#endif /* V3D_SHADING_OBJECT_OUTLINE */ + + if (object_id == NO_OBJECT_ID) { + color = vec4(background_color(world_data, uv_viewport.y), 0.0); + } else { + color = transparent_accum; + } + + fragColor = vec4(mix(world_data.object_outline_color.rgb, color.xyz, outline), 1.0); +} 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 new file mode 100644 index 00000000000..450cb3e680b --- /dev/null +++ b/source/blender/draw/engines/workbench/shaders/workbench_forward_depth_frag.glsl @@ -0,0 +1,8 @@ +uniform int object_id = 0; +layout(location=0) out uint objectId; + +void main() +{ + objectId = uint(object_id); +} + 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 new file mode 100644 index 00000000000..7eb5336e303 --- /dev/null +++ b/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl @@ -0,0 +1,54 @@ +uniform vec4 color = vec4(0.0, 0.0, 1.0, 1.0); +#ifdef OB_TEXTURE +uniform sampler2D image; +#endif +uniform mat3 normalWorldMatrix; + +#ifdef NORMAL_VIEWPORT_PASS_ENABLED +in vec3 normal_viewport; +#endif /* NORMAL_VIEWPORT_PASS_ENABLED */ +#ifdef OB_TEXTURE +in vec2 uv_interp; +#endif + +layout(std140) uniform world_block { + WorldData world_data; +}; + +layout(location=0) out vec4 transparentAccum; + +vec4 calculate_transparent_accum(vec4 premultiplied) { + float a = min(1.0, premultiplied.a) * 8.0 + 0.01; + float b = -gl_FragCoord.z * 0.95 + 1.0; + float w = clamp(a * a * a * 1e8 * b * b * b, 1e-2, 3e2); + return vec4(premultiplied.rgb, premultiplied.a); +} +void main() +{ + vec4 diffuse_color; +#ifdef OB_SOLID + diffuse_color = color; +#endif /* OB_SOLID */ +#ifdef OB_TEXTURE + diffuse_color = texture(image, uv_interp); +#endif /* OB_TEXTURE */ + +#ifdef V3D_LIGHTING_STUDIO +#ifdef STUDIOLIGHT_ORIENTATION_CAMERA + vec3 diffuse_light = get_camera_diffuse_light(world_data, normal_viewport); +#endif +#ifdef STUDIOLIGHT_ORIENTATION_WORLD + vec3 normal_world = normalWorldMatrix * normal_viewport; + vec3 diffuse_light = get_world_diffuse_light(world_data, normal_world); +#endif + vec3 shaded_color = diffuse_light * diffuse_color.rgb; + +#else /* V3D_LIGHTING_STUDIO */ + vec3 shaded_color = diffuse_color.rgb; +#endif /* V3D_LIGHTING_STUDIO */ + + float alpha = world_data.see_through_transparency; + vec4 premultiplied = vec4(shaded_color.rgb * alpha, alpha); + transparentAccum = calculate_transparent_accum(premultiplied); +} + 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 new file mode 100644 index 00000000000..3e925ba023f --- /dev/null +++ b/source/blender/draw/engines/workbench/shaders/workbench_object_outline_lib.glsl @@ -0,0 +1,12 @@ +#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_object_overlap_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_object_overlap_lib.glsl deleted file mode 100644 index e1ae9b93144..00000000000 --- a/source/blender/draw/engines/workbench/shaders/workbench_object_overlap_lib.glsl +++ /dev/null @@ -1,12 +0,0 @@ -#define OBJECT_OVERLAP_OFFSET 1 - -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(0.25)); -} diff --git a/source/blender/draw/engines/workbench/solid_mode.c b/source/blender/draw/engines/workbench/solid_mode.c index e2db345d8b0..1e49d1ae573 100644 --- a/source/blender/draw/engines/workbench/solid_mode.c +++ b/source/blender/draw/engines/workbench/solid_mode.c @@ -37,43 +37,43 @@ static void workbench_solid_engine_init(void *vedata) { WORKBENCH_Data *data = vedata; - workbench_materials_engine_init(data); + workbench_deferred_engine_init(data); } static void workbench_solid_cache_init(void *vedata) { WORKBENCH_Data *data = vedata; - workbench_materials_cache_init(data); + workbench_deferred_cache_init(data); } static void workbench_solid_cache_populate(void *vedata, Object *ob) { WORKBENCH_Data *data = vedata; - workbench_materials_solid_cache_populate(data, ob); + workbench_deferred_solid_cache_populate(data, ob); } static void workbench_solid_cache_finish(void *vedata) { WORKBENCH_Data *data = vedata; - workbench_materials_cache_finish(data); + workbench_deferred_cache_finish(data); } static void workbench_solid_draw_background(void *vedata) { WORKBENCH_Data *data = vedata; - workbench_materials_draw_background(data); + workbench_deferred_draw_background(data); } static void workbench_solid_draw_scene(void *vedata) { WORKBENCH_Data *data = vedata; - workbench_materials_draw_scene(data); + workbench_deferred_draw_scene(data); } static void workbench_solid_engine_free(void) { - workbench_materials_engine_free(); + workbench_deferred_engine_free(); } static const DrawEngineDataSize workbench_data_size = DRW_VIEWPORT_DATA_SIZE(WORKBENCH_Data); diff --git a/source/blender/draw/engines/workbench/transparent_mode.c b/source/blender/draw/engines/workbench/transparent_mode.c new file mode 100644 index 00000000000..c5d3db4b390 --- /dev/null +++ b/source/blender/draw/engines/workbench/transparent_mode.c @@ -0,0 +1,96 @@ +/* + * 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 transparent_mode.c + * \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_background(void *vedata) +{ + WORKBENCH_Data *data = vedata; + workbench_forward_draw_background(data); +} + +static void workbench_transparent_draw_scene(void *vedata) +{ + WORKBENCH_Data *data = vedata; + workbench_forward_draw_scene(data); +} + +static void workbench_transparent_engine_free(void) +{ + workbench_forward_engine_free(); +} + +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_background, + &workbench_transparent_draw_scene, + NULL, + NULL, + NULL, +}; + diff --git a/source/blender/draw/engines/workbench/workbench_data.c b/source/blender/draw/engines/workbench/workbench_data.c new file mode 100644 index 00000000000..c3671fa37b1 --- /dev/null +++ b/source/blender/draw/engines/workbench/workbench_data.c @@ -0,0 +1,49 @@ +#include "workbench_private.h" + +#include "UI_resources.h" + +void workbench_private_data_init(WORKBENCH_PrivateData *wpd) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + wpd->material_hash = BLI_ghash_ptr_new(__func__); + + View3D *v3d = draw_ctx->v3d; + if (v3d) { + wpd->shading = v3d->shading; + wpd->drawtype = v3d->drawtype; + wpd->studio_light = BKE_studiolight_find(wpd->shading.studio_light); + } + else { + memset(&wpd->shading, 0, sizeof(wpd->shading)); + wpd->shading.light = V3D_LIGHTING_STUDIO; + wpd->shading.shadow_intensity = 0.5; + copy_v3_fl(wpd->shading.single_color, 0.8f); + wpd->drawtype = OB_SOLID; + wpd->studio_light = BKE_studiolight_findindex(0); + wpd->shading.see_through_transparency = 0.3f; + } + wpd->shadow_multiplier = 1.0 - wpd->shading.shadow_intensity; + + WORKBENCH_UBO_World *wd = &wpd->world_data; + 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); + + /* XXX: Really quick conversion to avoid washed out background. + * Needs to be adressed properly (color managed using ocio). */ + srgb_to_linearrgb_v3_v3(wd->background_color_high, wd->background_color_high); + srgb_to_linearrgb_v3_v3(wd->background_color_low, wd->background_color_low); + + studiolight_update_world(wpd->studio_light, wd); + + wd->see_through_transparency = wpd->shading.see_through_transparency; + copy_v3_v3(wd->object_outline_color, wpd->shading.object_outline_color); + wd->object_outline_color[3] = 1.0f; + + wpd->world_ubo = DRW_uniformbuffer_create(sizeof(WORKBENCH_UBO_World), &wpd->world_data); +} + +void workbench_private_data_free(WORKBENCH_PrivateData *wpd) +{ + 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_deferred.c b/source/blender/draw/engines/workbench/workbench_deferred.c new file mode 100644 index 00000000000..70de6f71ae8 --- /dev/null +++ b/source/blender/draw/engines/workbench/workbench_deferred.c @@ -0,0 +1,585 @@ +/* + * 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 workbench_deferred.c + * \ingroup draw_engine + */ + +#include "workbench_private.h" + +#include "BIF_gl.h" + +#include "BLI_alloca.h" +#include "BLI_dynstr.h" +#include "BLI_utildefines.h" + +#include "BKE_node.h" +#include "BKE_particle.h" + +#include "DNA_image_types.h" +#include "DNA_mesh_types.h" +#include "DNA_modifier_types.h" +#include "DNA_node_types.h" + +#include "ED_uvedit.h" + +#include "GPU_shader.h" +#include "GPU_texture.h" + + +/* *********** STATIC *********** */ + +// #define DEBUG_SHADOW_VOLUME + +static struct { + struct GPUShader *prepass_sh_cache[MAX_SHADERS]; + struct GPUShader *composite_sh_cache[MAX_SHADERS]; + struct GPUShader *shadow_fail_sh; + struct GPUShader *shadow_pass_sh; + struct GPUShader *shadow_caps_sh; + + struct GPUTexture *object_id_tx; /* ref only, not alloced */ + struct GPUTexture *color_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 */ + float light_direction_vs[3]; + int next_object_id; + float normal_world_matrix[3][3]; +} e_data = {NULL}; + +/* Shaders */ +extern char datatoc_workbench_prepass_vert_glsl[]; +extern char datatoc_workbench_prepass_frag_glsl[]; +extern char datatoc_workbench_deferred_composite_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_background_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_world_light_lib_glsl[]; + + + +static char *workbench_build_composite_frag(WORKBENCH_PrivateData *wpd) +{ + char *str = NULL; + + 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_background_lib_glsl); + + if (wpd->shading.light & V3D_LIGHTING_STUDIO) { + BLI_dynstr_append(ds, datatoc_workbench_world_light_lib_glsl); + } + if (wpd->shading.flag & V3D_SHADING_OBJECT_OUTLINE) { + BLI_dynstr_append(ds, datatoc_workbench_object_outline_lib_glsl); + } + + BLI_dynstr_append(ds, datatoc_workbench_deferred_composite_frag_glsl); + + str = BLI_dynstr_get_cstring(ds); + BLI_dynstr_free(ds); + return str; +} + +static char *workbench_build_prepass_frag(void) +{ + char *str = NULL; + + DynStr *ds = BLI_dynstr_new(); + + BLI_dynstr_append(ds, datatoc_workbench_common_lib_glsl); + BLI_dynstr_append(ds, datatoc_workbench_prepass_frag_glsl); + + str = BLI_dynstr_get_cstring(ds); + BLI_dynstr_free(ds); + return str; +} + + + +static void ensure_deferred_shaders(WORKBENCH_PrivateData *wpd, int index, int drawtype) +{ + if (e_data.prepass_sh_cache[index] == NULL) { + char *defines = workbench_material_build_defines(wpd, drawtype); + char *composite_frag = workbench_build_composite_frag(wpd); + char *prepass_frag = workbench_build_prepass_frag(); + e_data.prepass_sh_cache[index] = DRW_shader_create(datatoc_workbench_prepass_vert_glsl, NULL, prepass_frag, defines); + if (drawtype == OB_SOLID) { + e_data.composite_sh_cache[index] = DRW_shader_create_fullscreen(composite_frag, defines); + } + MEM_freeN(prepass_frag); + MEM_freeN(composite_frag); + MEM_freeN(defines); + } +} + +static void select_deferred_shaders(WORKBENCH_PrivateData *wpd) +{ + int index_solid = workbench_material_get_shader_index(wpd, OB_SOLID); + int index_texture = workbench_material_get_shader_index(wpd, OB_TEXTURE); + + ensure_deferred_shaders(wpd, index_solid, OB_SOLID); + ensure_deferred_shaders(wpd, index_texture, OB_TEXTURE); + + wpd->prepass_solid_sh = e_data.prepass_sh_cache[index_solid]; + wpd->prepass_texture_sh = e_data.prepass_sh_cache[index_texture]; + wpd->composite_sh = e_data.composite_sh_cache[index_solid]; +} + +/* Functions */ + + +static void workbench_init_object_data(ObjectEngineData *engine_data) +{ + WORKBENCH_ObjectData *data = (WORKBENCH_ObjectData *)engine_data; + data->object_id = e_data.next_object_id++; +} + +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(); + + 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; + #ifdef DEBUG_SHADOW_VOLUME + const char *shadow_frag = datatoc_workbench_shadow_debug_frag_glsl; + #else + const char *shadow_frag = NULL; + #endif + e_data.shadow_pass_sh = DRW_shader_create( + datatoc_workbench_shadow_vert_glsl, + datatoc_workbench_shadow_geom_glsl, + shadow_frag, + "#define SHADOW_PASS\n"); + e_data.shadow_fail_sh = DRW_shader_create( + datatoc_workbench_shadow_vert_glsl, + datatoc_workbench_shadow_geom_glsl, + shadow_frag, + "#define SHADOW_FAIL\n"); + e_data.shadow_caps_sh = DRW_shader_create( + datatoc_workbench_shadow_vert_glsl, + datatoc_workbench_shadow_caps_geom_glsl, + shadow_frag, + NULL); + } + + if (!stl->g_data) { + /* Alloc transient pointers */ + stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__); + } + + workbench_private_data_init(stl->g_data); + + { + 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], GPU_R32UI, &draw_engine_workbench_solid); + e_data.color_buffer_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_RGBA8, &draw_engine_workbench_solid); + e_data.composite_buffer_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_RGBA16F, &draw_engine_workbench_solid); + + if (NORMAL_ENCODING_ENABLED()) { + e_data.normal_buffer_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_RG16, &draw_engine_workbench_solid); + } else { + e_data.normal_buffer_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_RGBA32F, &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.color_buffer_tx), + GPU_ATTACHMENT_TEXTURE(e_data.normal_buffer_tx), + }); + GPU_framebuffer_ensure_config(&fbl->composite_fb, { + GPU_ATTACHMENT_TEXTURE(dtxl->depth), + GPU_ATTACHMENT_TEXTURE(e_data.composite_buffer_tx), + }); + } + + /* Prepass */ + { + int state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL; + psl->prepass_pass = DRW_pass_create("Prepass", state); + } +} + +void workbench_deferred_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]); + } + DRW_SHADER_FREE_SAFE(e_data.shadow_pass_sh); + DRW_SHADER_FREE_SAFE(e_data.shadow_fail_sh); + DRW_SHADER_FREE_SAFE(e_data.shadow_caps_sh); +} + +static void workbench_composite_uniforms(WORKBENCH_PrivateData *wpd, DRWShadingGroup *grp) +{ + DRW_shgroup_uniform_texture_ref(grp, "colorBuffer", &e_data.color_buffer_tx); + DRW_shgroup_uniform_texture_ref(grp, "objectId", &e_data.object_id_tx); + if (NORMAL_VIEWPORT_PASS_ENABLED(wpd)) { + DRW_shgroup_uniform_texture_ref(grp, "normalBuffer", &e_data.normal_buffer_tx); + } + DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo); + DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1); + + workbench_material_set_normal_world_matrix(grp, wpd, e_data.normal_world_matrix); +} + +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(); + static float light_multiplier = 1.0f; + + + Scene *scene = draw_ctx->scene; + + select_deferred_shaders(wpd); + /* Deferred Mix Pass */ + { + copy_v3_v3(e_data.display.light_direction, scene->display.light_direction); + negate_v3(e_data.display.light_direction); +#if 0 + if (STUDIOLIGHT_ORIENTATION_WORLD_ENABLED(wpd)) { + BKE_studiolight_ensure_flag(wpd->studio_light, STUDIOLIGHT_LIGHT_DIRECTION_CALCULATED); + float rot_matrix[3][3]; + // float dir[3] = {0.57, 0.57, -0.57}; + axis_angle_to_mat3_single(rot_matrix, 'Z', wpd->shading.studiolight_rot_z); + mul_v3_m3v3(e_data.display.light_direction, rot_matrix, wpd->studio_light->light_direction); + } +#endif + float view_matrix[4][4]; + DRW_viewport_matrix_get(view_matrix, DRW_MAT_VIEW); + mul_v3_mat3_m4v3(e_data.light_direction_vs, view_matrix, e_data.display.light_direction); + + e_data.display.shadow_shift = scene->display.shadow_shift; + + if (SHADOW_ENABLED(wpd)) { + psl->composite_pass = DRW_pass_create("Composite", DRW_STATE_WRITE_COLOR | DRW_STATE_STENCIL_EQUAL); + grp = DRW_shgroup_create(wpd->composite_sh, psl->composite_pass); + workbench_composite_uniforms(wpd, grp); + DRW_shgroup_stencil_mask(grp, 0x00); + DRW_shgroup_uniform_vec3(grp, "lightDirection", e_data.light_direction_vs, 1); + DRW_shgroup_uniform_float(grp, "lightMultiplier", &light_multiplier, 1); + DRW_shgroup_uniform_float(grp, "shadowMultiplier", &wpd->shadow_multiplier, 1); + DRW_shgroup_uniform_float(grp, "shadowShift", &scene->display.shadow_shift, 1); + DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); + +#ifdef DEBUG_SHADOW_VOLUME + psl->shadow_depth_pass_pass = DRW_pass_create("Shadow Debug Pass", DRW_STATE_DEPTH_LESS | DRW_STATE_WRITE_COLOR | DRW_STATE_ADDITIVE); + grp = DRW_shgroup_create(e_data.shadow_pass_sh, psl->shadow_depth_pass_pass); + psl->shadow_depth_fail_pass = DRW_pass_create("Shadow Debug Fail", DRW_STATE_DEPTH_GREATER_EQUAL | DRW_STATE_WRITE_COLOR | DRW_STATE_ADDITIVE); + grp = DRW_shgroup_create(e_data.shadow_fail_sh, psl->shadow_depth_fail_pass); + psl->shadow_depth_fail_caps_pass = DRW_pass_create("Shadow Depth Fail Caps", DRW_STATE_DEPTH_GREATER_EQUAL | DRW_STATE_WRITE_COLOR | DRW_STATE_ADDITIVE); + grp = DRW_shgroup_create(e_data.shadow_caps_sh, psl->shadow_depth_fail_caps_pass); +#else + psl->shadow_depth_pass_pass = DRW_pass_create("Shadow Depth Pass", DRW_STATE_DEPTH_LESS | DRW_STATE_WRITE_STENCIL_SHADOW_PASS); + grp = DRW_shgroup_create(e_data.shadow_pass_sh, psl->shadow_depth_pass_pass); + DRW_shgroup_stencil_mask(grp, 0xFF); + psl->shadow_depth_fail_pass = DRW_pass_create("Shadow Depth Fail", DRW_STATE_DEPTH_LESS | DRW_STATE_WRITE_STENCIL_SHADOW_FAIL); + grp = DRW_shgroup_create(e_data.shadow_fail_sh, psl->shadow_depth_fail_pass); + DRW_shgroup_stencil_mask(grp, 0xFF); + psl->shadow_depth_fail_caps_pass = DRW_pass_create("Shadow Depth Fail Caps", DRW_STATE_DEPTH_LESS | DRW_STATE_WRITE_STENCIL_SHADOW_FAIL); + grp = DRW_shgroup_create(e_data.shadow_caps_sh, psl->shadow_depth_fail_caps_pass); + DRW_shgroup_stencil_mask(grp, 0xFF); + + psl->composite_shadow_pass = DRW_pass_create("Composite Shadow", DRW_STATE_WRITE_COLOR | DRW_STATE_STENCIL_NEQUAL); + 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_vec3(grp, "lightDirection", e_data.light_direction_vs, 1); + DRW_shgroup_uniform_float(grp, "lightMultiplier", &wpd->shadow_multiplier, 1); + DRW_shgroup_uniform_float(grp, "shadowMultiplier", &wpd->shadow_multiplier, 1); + DRW_shgroup_uniform_float(grp, "shadowShift", &scene->display.shadow_shift, 1); + DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); +#endif + } + else { + psl->composite_pass = DRW_pass_create("Composite", DRW_STATE_WRITE_COLOR); + grp = DRW_shgroup_create(wpd->composite_sh, psl->composite_pass); + workbench_composite_uniforms(wpd, grp); + DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); + } + } +} +static WORKBENCH_MaterialData *get_or_create_material_data(WORKBENCH_Data *vedata, Object *ob, Material *mat, Image *ima, int drawtype) +{ + WORKBENCH_StorageList *stl = vedata->stl; + WORKBENCH_PassList *psl = vedata->psl; + WORKBENCH_PrivateData *wpd = stl->g_data; + WORKBENCH_MaterialData *material; + 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; + + /* Solid */ + workbench_material_get_solid_color(wpd, ob, mat, material_template.color); + material_template.object_id = engine_object_data->object_id; + material_template.drawtype = drawtype; + material_template.ima = ima; + uint hash = workbench_material_get_hash(&material_template); + + material = BLI_ghash_lookup(wpd->material_hash, SET_UINT_IN_POINTER(hash)); + if (material == NULL) { + material = MEM_mallocN(sizeof(WORKBENCH_MaterialData), __func__); + material->shgrp = DRW_shgroup_create(drawtype == OB_SOLID ? wpd->prepass_solid_sh : wpd->prepass_texture_sh, psl->prepass_pass); + DRW_shgroup_stencil_mask(material->shgrp, 0xFF); + material->object_id = engine_object_data->object_id; + copy_v4_v4(material->color, material_template.color); + switch (drawtype) { + case OB_SOLID: + DRW_shgroup_uniform_vec3(material->shgrp, "object_color", material->color, 1); + break; + + case OB_TEXTURE: + { + GPUTexture *tex = GPU_texture_from_blender(ima, NULL, GL_TEXTURE_2D, false, false, false); + DRW_shgroup_uniform_texture(material->shgrp, "image", tex); + break; + } + } + DRW_shgroup_uniform_int(material->shgrp, "object_id", &material->object_id, 1); + BLI_ghash_insert(wpd->material_hash, SET_UINT_IN_POINTER(hash), material); + } + return material; +} + +static void workbench_cache_populate_particles(WORKBENCH_Data *vedata, Object *ob) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + if (ob == draw_ctx->object_edit) { + return; + } + for (ParticleSystem *psys = ob->particlesystem.first; psys != NULL; psys = psys->next) { + if (!psys_check_enabled(ob, psys, false)) { + continue; + } + if (!DRW_check_psys_visible_within_active_context(ob, psys)) { + return; + } + ParticleSettings *part = psys->part; + const int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as; + + static float mat[4][4]; + unit_m4(mat); + + if (draw_as == PART_DRAW_PATH) { + struct Gwn_Batch *geom = DRW_cache_particles_get_hair(ob, psys, NULL); + WORKBENCH_MaterialData *material = get_or_create_material_data(vedata, ob, NULL, NULL, OB_SOLID); + DRW_shgroup_call_add(material->shgrp, geom, mat); + } + } +} + +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; + + if (!DRW_object_is_renderable(ob)) + return; + + if (ob->type == OB_MESH) { + workbench_cache_populate_particles(vedata, ob); + } + + WORKBENCH_MaterialData *material; + if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT)) { + const DRWContextState *draw_ctx = DRW_context_state_get(); + const bool is_active = (ob == draw_ctx->obact); + const bool is_sculpt_mode = is_active && (draw_ctx->object_mode & OB_MODE_SCULPT) != 0; + bool is_drawn = false; + if (!is_sculpt_mode && wpd->drawtype == OB_TEXTURE && ob->type == OB_MESH) { + const Mesh *me = ob->data; + if (me->mloopuv) { + const int materials_len = MAX2(1, (is_sculpt_mode ? 1 : ob->totcol)); + struct GPUMaterial **gpumat_array = BLI_array_alloca(gpumat_array, materials_len); + struct Gwn_Batch **geom_array = me->totcol ? DRW_cache_mesh_surface_texpaint_get(ob) : NULL; + if (materials_len > 0 && geom_array) { + for (int i = 0; i < materials_len; i++) { + Material *mat = give_current_material(ob, i + 1); + Image *image; + ED_object_get_active_image(ob, i + 1, &image, NULL, NULL, NULL); + /* use OB_SOLID when no texture could be determined */ + int mat_drawtype = OB_SOLID; + if (image) { + mat_drawtype = OB_TEXTURE; + } + material = get_or_create_material_data(vedata, ob, mat, image, mat_drawtype); + DRW_shgroup_call_object_add(material->shgrp, geom_array[i], ob); + } + is_drawn = true; + } + } + } + + /* Fallback from not drawn OB_TEXTURE mode or just OB_SOLID mode */ + if (!is_drawn) { + if ((wpd->shading.color_type != V3D_SHADING_MATERIAL_COLOR) || is_sculpt_mode) { + /* No material split needed */ + struct Gwn_Batch *geom = DRW_cache_object_surface_get(ob); + if (geom) { + material = get_or_create_material_data(vedata, ob, NULL, NULL, OB_SOLID); + if (is_sculpt_mode) { + DRW_shgroup_call_sculpt_add(material->shgrp, ob, ob->obmat); + } + else { + DRW_shgroup_call_object_add(material->shgrp, geom, ob); + } + } + } + else { /* MATERIAL colors */ + const int materials_len = MAX2(1, (is_sculpt_mode ? 1 : ob->totcol)); + struct GPUMaterial **gpumat_array = BLI_array_alloca(gpumat_array, materials_len); + for (int i = 0; i < materials_len; i++) { + gpumat_array[i] = NULL; + } + + struct Gwn_Batch **mat_geom = DRW_cache_object_surface_material_get(ob, gpumat_array, materials_len, NULL, NULL, NULL); + if (mat_geom) { + for (int i = 0; i < materials_len; ++i) { + Material *mat = give_current_material(ob, i + 1); + material = get_or_create_material_data(vedata, ob, mat, NULL, OB_SOLID); + DRW_shgroup_call_object_add(material->shgrp, mat_geom[i], ob); + } + } + } + } + + if (SHADOW_ENABLED(wpd) && (ob->display.flag & OB_SHOW_SHADOW) > 0) { + struct Gwn_Batch *geom_shadow = DRW_cache_object_edge_detection_get(ob); + if (geom_shadow) { + if (is_sculpt_mode) { + /* 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 + * sculped meshes are heavy to begin with. */ + // DRW_shgroup_call_sculpt_add(wpd->shadow_shgrp, ob, ob->obmat); + } + else { + 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); + + invert_m4_m4(ob->imat, ob->obmat); + mul_v3_mat3_m4v3(engine_object_data->shadow_dir, ob->imat, e_data.display.light_direction); + + DRWShadingGroup *grp; + if (true) { + 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_call_object_add(grp, geom_shadow, ob); + } + else { + struct Gwn_Batch *geom_caps = DRW_cache_object_surface_get(ob); + if (geom_caps) { + 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_call_object_add(grp, geom_caps, ob); + } + + 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_call_object_add(grp, geom_shadow, ob); + } + } + } + } + } +} + +void workbench_deferred_cache_finish(WORKBENCH_Data *UNUSED(vedata)) +{ +} + +void workbench_deferred_draw_background(WORKBENCH_Data *vedata) +{ + WORKBENCH_StorageList *stl = vedata->stl; + WORKBENCH_FramebufferList *fbl = vedata->fbl; + WORKBENCH_PrivateData *wpd = stl->g_data; + const float clear_depth = 1.0f; + const float clear_color[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + uint clear_stencil = 0xFF; + + DRW_stats_group_start("Clear Background"); + GPU_framebuffer_bind(fbl->prepass_fb); + int clear_bits = GPU_DEPTH_BIT | GPU_COLOR_BIT; + SET_FLAG_FROM_TEST(clear_bits, SHADOW_ENABLED(wpd), GPU_STENCIL_BIT); + GPU_framebuffer_clear(fbl->prepass_fb, clear_bits, clear_color, clear_depth, clear_stencil); + DRW_stats_group_end(); +} + +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(); + + /* clear in background */ + GPU_framebuffer_bind(fbl->prepass_fb); + DRW_draw_pass(psl->prepass_pass); + if (SHADOW_ENABLED(wpd)) { +#ifdef DEBUG_SHADOW_VOLUME + GPU_framebuffer_bind(fbl->composite_fb); + DRW_draw_pass(psl->composite_pass); + DRW_draw_pass(psl->shadow_depth_pass_pass); + DRW_draw_pass(psl->shadow_depth_fail_pass); + DRW_draw_pass(psl->shadow_depth_fail_caps_pass); +#else + GPU_framebuffer_bind(dfbl->depth_only_fb); + DRW_draw_pass(psl->shadow_depth_pass_pass); + DRW_draw_pass(psl->shadow_depth_fail_pass); + DRW_draw_pass(psl->shadow_depth_fail_caps_pass); + 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); + } + + GPU_framebuffer_bind(dfbl->color_only_fb); + DRW_transform_to_display(e_data.composite_buffer_tx); + + workbench_private_data_free(wpd); +} diff --git a/source/blender/draw/engines/workbench/workbench_engine.h b/source/blender/draw/engines/workbench/workbench_engine.h index 0cbbe8df4af..a7f168db093 100644 --- a/source/blender/draw/engines/workbench/workbench_engine.h +++ b/source/blender/draw/engines/workbench/workbench_engine.h @@ -27,6 +27,7 @@ #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 new file mode 100644 index 00000000000..02d2e3bde38 --- /dev/null +++ b/source/blender/draw/engines/workbench/workbench_forward.c @@ -0,0 +1,456 @@ +/* + * 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 workbench_forward.c + * \ingroup draw_engine + */ + +#include "workbench_private.h" + +#include "BIF_gl.h" + +#include "BLI_alloca.h" +#include "BLI_dynstr.h" +#include "BLI_utildefines.h" + +#include "BKE_node.h" +#include "BKE_particle.h" + +#include "DNA_image_types.h" +#include "DNA_mesh_types.h" +#include "DNA_modifier_types.h" +#include "DNA_node_types.h" + +#include "ED_uvedit.h" + +#include "GPU_shader.h" +#include "GPU_texture.h" + +#include "UI_resources.h" + +/* *********** STATIC *********** */ +static struct { + struct GPUShader *composite_sh_cache[MAX_SHADERS]; + struct GPUShader *transparent_accum_sh_cache[MAX_SHADERS]; + struct GPUShader *depth_sh; + + struct GPUTexture *object_id_tx; /* ref only, not alloced */ + struct GPUTexture *transparent_accum_tx; /* ref only, not alloced */ + struct GPUTexture *composite_buffer_tx; /* ref only, not alloced */ + int next_object_id; + float normal_world_matrix[3][3]; +} e_data = {NULL}; + +/* Shaders */ +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_background_lib_glsl[]; +extern char datatoc_workbench_object_outline_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_depth_frag(void) +{ + char *str = NULL; + + DynStr *ds = BLI_dynstr_new(); + + BLI_dynstr_append(ds, datatoc_workbench_common_lib_glsl); + BLI_dynstr_append(ds, datatoc_workbench_forward_depth_frag_glsl); + + str = BLI_dynstr_get_cstring(ds); + BLI_dynstr_free(ds); + return str; +} + +static char *workbench_build_forward_transparent_accum_frag(void) +{ + char *str = NULL; + + 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_world_light_lib_glsl); + BLI_dynstr_append(ds, datatoc_workbench_forward_transparent_accum_frag_glsl); + + str = BLI_dynstr_get_cstring(ds); + BLI_dynstr_free(ds); + return str; +} + +static char *workbench_build_forward_composite_frag(void) +{ + char *str = NULL; + + 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_background_lib_glsl); + BLI_dynstr_append(ds, datatoc_workbench_object_outline_lib_glsl); + BLI_dynstr_append(ds, datatoc_workbench_forward_composite_frag_glsl); + + str = BLI_dynstr_get_cstring(ds); + BLI_dynstr_free(ds); + return str; +} + +static void workbench_init_object_data(ObjectEngineData *engine_data) +{ + WORKBENCH_ObjectData *data = (WORKBENCH_ObjectData *)engine_data; + data->object_id = e_data.next_object_id++; +} + +static WORKBENCH_MaterialData *get_or_create_material_data(WORKBENCH_Data *vedata, Object *ob, Material *mat, Image *ima, int drawtype) +{ + WORKBENCH_StorageList *stl = vedata->stl; + WORKBENCH_PassList *psl = vedata->psl; + WORKBENCH_PrivateData *wpd = stl->g_data; + WORKBENCH_MaterialData *material; + 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; + DRWShadingGroup *grp; + + /* Solid */ + workbench_material_get_solid_color(wpd, ob, mat, material_template.color); + material_template.object_id = engine_object_data->object_id; + material_template.drawtype = drawtype; + material_template.ima = ima; + uint hash = workbench_material_get_hash(&material_template); + + material = BLI_ghash_lookup(wpd->material_hash, SET_UINT_IN_POINTER(hash)); + if (material == NULL) { + material = MEM_mallocN(sizeof(WORKBENCH_MaterialData), __func__); + + /* transparent accum */ + grp = DRW_shgroup_create(drawtype == OB_SOLID ? wpd->transparent_accum_sh : wpd->transparent_accum_texture_sh, psl->transparent_accum_pass); + DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo); + workbench_material_set_normal_world_matrix(grp, wpd, e_data.normal_world_matrix); + copy_v4_v4(material->color, material_template.color); + switch (drawtype) { + case OB_SOLID: + DRW_shgroup_uniform_vec4(grp, "color", material->color, 1); + break; + + case OB_TEXTURE: + { + GPUTexture *tex = GPU_texture_from_blender(ima, NULL, GL_TEXTURE_2D, false, false, false); + DRW_shgroup_uniform_texture(grp, "image", tex); + break; + } + } + material->shgrp = grp; + + /* Depth */ + material->shgrp_depth = DRW_shgroup_create(e_data.depth_sh, psl->depth_pass); + material->object_id = engine_object_data->object_id; + DRW_shgroup_uniform_int(material->shgrp_depth, "object_id", &material->object_id, 1); + BLI_ghash_insert(wpd->material_hash, SET_UINT_IN_POINTER(hash), material); + } + return material; +} + +static void ensure_forward_shaders(WORKBENCH_PrivateData *wpd, int index, int drawtype) +{ + if (e_data.composite_sh_cache[index] == NULL) { + char *defines = workbench_material_build_defines(wpd, drawtype); + char *composite_frag = workbench_build_forward_composite_frag(); + if (drawtype == OB_SOLID) { + e_data.composite_sh_cache[index] = DRW_shader_create_fullscreen(composite_frag, defines); + } + MEM_freeN(composite_frag); + MEM_freeN(defines); + } + + if (e_data.transparent_accum_sh_cache[index] == NULL) { + char *defines = workbench_material_build_defines(wpd, drawtype); + char *transparent_accum_frag = workbench_build_forward_transparent_accum_frag(); + e_data.transparent_accum_sh_cache[index] = DRW_shader_create(datatoc_workbench_prepass_vert_glsl, NULL, transparent_accum_frag, defines); + MEM_freeN(transparent_accum_frag); + + MEM_freeN(defines); + } +} + +static void select_forward_shaders(WORKBENCH_PrivateData *wpd) +{ + int index_solid = workbench_material_get_shader_index(wpd, OB_SOLID); + int index_texture = workbench_material_get_shader_index(wpd, OB_TEXTURE); + + ensure_forward_shaders(wpd, index_solid, OB_SOLID); + ensure_forward_shaders(wpd, index_texture, OB_TEXTURE); + + wpd->composite_sh = e_data.composite_sh_cache[index_solid]; + wpd->transparent_accum_sh = e_data.transparent_accum_sh_cache[index_solid]; + wpd->transparent_accum_texture_sh = e_data.transparent_accum_sh_cache[index_texture]; +} + +/* 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(); + DRWShadingGroup *grp; + + if (!stl->g_data) { + /* Alloc transient pointers */ + stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__); + } + WORKBENCH_PrivateData *wpd = stl->g_data; + workbench_private_data_init(wpd); + + if (!e_data.next_object_id) { + e_data.next_object_id = 1; + memset(e_data.composite_sh_cache, 0x00, sizeof(struct GPUShader *) * MAX_SHADERS); + memset(e_data.transparent_accum_sh_cache, 0x00, sizeof(struct GPUShader *) * MAX_SHADERS); + + /* XXX: forward depth does not use any defines ATM. */ + char *defines = workbench_material_build_defines(wpd, OB_SOLID); + char *forward_depth_frag = workbench_build_forward_depth_frag(); + e_data.depth_sh = DRW_shader_create(datatoc_workbench_prepass_vert_glsl, NULL, forward_depth_frag, defines); + MEM_freeN(forward_depth_frag); + MEM_freeN(defines); + } + select_forward_shaders(wpd); + + 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], 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.composite_buffer_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_RGBA16F, &draw_engine_workbench_transparent); + GPU_framebuffer_ensure_config(&fbl->depth_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_framebuffer_ensure_config(&fbl->composite_fb, { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(e_data.composite_buffer_tx), + }); + const float clear_color[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + DRW_stats_group_start("Clear Buffers"); + GPU_framebuffer_bind(fbl->transparent_accum_fb); + GPU_framebuffer_clear_color(fbl->transparent_accum_fb, clear_color); + GPU_framebuffer_bind(fbl->depth_fb); + GPU_framebuffer_clear_color(fbl->depth_fb, clear_color); + DRW_stats_group_end(); + + + /* Treansparecy Accum */ + { + int state = DRW_STATE_WRITE_COLOR | DRW_STATE_ADDITIVE;// | DRW_STATE_CULL_BACK; + 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; + psl->depth_pass = DRW_pass_create("Depth", state); + } + /* Composite */ + { + int state = DRW_STATE_WRITE_COLOR; + psl->composite_pass = DRW_pass_create("Composite", state); + + grp = DRW_shgroup_create(wpd->composite_sh, psl->composite_pass); + 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_block(grp, "world_block", wpd->world_ubo); + 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_forward_engine_free() +{ + for (int index = 0; index < MAX_SHADERS; index++) { + DRW_SHADER_FREE_SAFE(e_data.composite_sh_cache[index]); + DRW_SHADER_FREE_SAFE(e_data.transparent_accum_sh_cache[index]); + } + DRW_SHADER_FREE_SAFE(e_data.depth_sh); +} + +void workbench_forward_cache_init(WORKBENCH_Data *UNUSED(vedata)) +{ +} + +static void workbench_forward_cache_populate_particles(WORKBENCH_Data *vedata, Object *ob) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + if (ob == draw_ctx->object_edit) { + return; + } + for (ParticleSystem *psys = ob->particlesystem.first; psys != NULL; psys = psys->next) { + if (!psys_check_enabled(ob, psys, false)) { + continue; + } + if (!DRW_check_psys_visible_within_active_context(ob, psys)) { + return; + } + ParticleSettings *part = psys->part; + const int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as; + + static float mat[4][4]; + unit_m4(mat); + + if (draw_as == PART_DRAW_PATH) { + struct Gwn_Batch *geom = DRW_cache_particles_get_hair(ob, psys, NULL); + WORKBENCH_MaterialData *material = get_or_create_material_data(vedata, ob, NULL, NULL, OB_SOLID); + DRW_shgroup_call_add(material->shgrp, geom, mat); + } + } +} + +void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob) +{ + WORKBENCH_StorageList *stl = vedata->stl; + WORKBENCH_PrivateData *wpd = stl->g_data; + + if (!DRW_object_is_renderable(ob)) + return; + + if (ob->type == OB_MESH) { + workbench_forward_cache_populate_particles(vedata, ob); + } + if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT)) { + const DRWContextState *draw_ctx = DRW_context_state_get(); + const bool is_active = (ob == draw_ctx->obact); + const bool is_sculpt_mode = is_active && (draw_ctx->object_mode & OB_MODE_SCULPT) != 0; + bool is_drawn = false; + + WORKBENCH_MaterialData *material = get_or_create_material_data(vedata, ob, NULL, NULL, OB_SOLID); + if (!is_sculpt_mode && wpd->drawtype == OB_TEXTURE && ob->type == OB_MESH) { + const Mesh *me = ob->data; + if (me->mloopuv) { + const int materials_len = MAX2(1, (is_sculpt_mode ? 1 : ob->totcol)); + struct GPUMaterial **gpumat_array = BLI_array_alloca(gpumat_array, materials_len); + struct Gwn_Batch **geom_array = me->totcol ? DRW_cache_mesh_surface_texpaint_get(ob) : NULL; + if (materials_len > 0 && geom_array) { + for (int i = 0; i < materials_len; i++) { + Material *mat = give_current_material(ob, i + 1); + Image *image; + ED_object_get_active_image(ob, i + 1, &image, NULL, NULL, NULL); + /* use OB_SOLID when no texture could be determined */ + int mat_drawtype = OB_SOLID; + if (image) { + mat_drawtype = OB_TEXTURE; + } + material = get_or_create_material_data(vedata, ob, mat, image, mat_drawtype); + DRW_shgroup_call_object_add(material->shgrp_depth, geom_array[i], ob); + DRW_shgroup_call_object_add(material->shgrp, geom_array[i], ob); + } + is_drawn = true; + } + } + } + + /* Fallback from not drawn OB_TEXTURE mode or just OB_SOLID mode */ + if (!is_drawn) { + if ((wpd->shading.color_type != V3D_SHADING_MATERIAL_COLOR) || is_sculpt_mode) { + /* No material split needed */ + struct Gwn_Batch *geom = DRW_cache_object_surface_get(ob); + if (geom) { + if (is_sculpt_mode) { + DRW_shgroup_call_sculpt_add(material->shgrp_depth, ob, ob->obmat); + DRW_shgroup_call_sculpt_add(material->shgrp, ob, ob->obmat); + } + else { + DRW_shgroup_call_object_add(material->shgrp_depth, geom, ob); + DRW_shgroup_call_object_add(material->shgrp, geom, ob); + } + } + } + else { + const int materials_len = MAX2(1, (is_sculpt_mode ? 1 : ob->totcol)); + struct GPUMaterial **gpumat_array = BLI_array_alloca(gpumat_array, materials_len); + for (int i = 0; i < materials_len; i++) { + gpumat_array[i] = NULL; + } + + struct Gwn_Batch **mat_geom = DRW_cache_object_surface_material_get(ob, gpumat_array, materials_len, NULL, NULL, NULL); + if (mat_geom) { + for (int i = 0; i < materials_len; ++i) { + Material *mat = give_current_material(ob, i + 1); + material = get_or_create_material_data(vedata, ob, mat, NULL, OB_SOLID); + DRW_shgroup_call_object_add(material->shgrp_depth, mat_geom[i], ob); + DRW_shgroup_call_object_add(material->shgrp, mat_geom[i], ob); + } + } + } + } + } +} + +void workbench_forward_cache_finish(WORKBENCH_Data *UNUSED(vedata)) +{ +} + +void workbench_forward_draw_background(WORKBENCH_Data *UNUSED(vedata)) +{ + const float clear_depth = 1.0f; + uint clear_stencil = 0xFF; + + const float clear_color[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); + DRW_stats_group_start("Clear Background"); + GPU_framebuffer_bind(dfbl->default_fb); + int clear_bits = GPU_DEPTH_BIT | GPU_COLOR_BIT; + GPU_framebuffer_clear(dfbl->default_fb, clear_bits, clear_color, clear_depth, clear_stencil); + DRW_stats_group_end(); +} + +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(); + + /* Write Depth + Object ID */ + GPU_framebuffer_bind(fbl->depth_fb); + DRW_draw_pass(psl->depth_pass); + + /* Shade */ + GPU_framebuffer_bind(fbl->transparent_accum_fb); + DRW_draw_pass(psl->transparent_accum_pass); + + /* Composite */ + GPU_framebuffer_bind(fbl->composite_fb); + DRW_draw_pass(psl->composite_pass); + + /* Color correct */ + GPU_framebuffer_bind(dfbl->color_only_fb); + DRW_transform_to_display(e_data.composite_buffer_tx); + + workbench_private_data_free(wpd); +} diff --git a/source/blender/draw/engines/workbench/workbench_materials.c b/source/blender/draw/engines/workbench/workbench_materials.c index 116bf809f1f..9b364d8ff09 100644 --- a/source/blender/draw/engines/workbench/workbench_materials.c +++ b/source/blender/draw/engines/workbench/workbench_materials.c @@ -1,100 +1,46 @@ -/* - * 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 workbench_materials.c - * \ingroup draw_engine - */ #include "workbench_private.h" -#include "BIF_gl.h" - -#include "BLI_alloca.h" #include "BLI_dynstr.h" -#include "BLI_utildefines.h" - -#include "BKE_node.h" -#include "BKE_particle.h" - -#include "DNA_image_types.h" -#include "DNA_mesh_types.h" -#include "DNA_modifier_types.h" -#include "DNA_node_types.h" - -#include "ED_uvedit.h" - -#include "GPU_shader.h" -#include "GPU_texture.h" - -#include "UI_resources.h" - -/* *********** STATIC *********** */ - -// #define DEBUG_SHADOW_VOLUME -#define MAX_SHADERS 255 -static struct { - struct GPUShader *prepass_sh_cache[MAX_SHADERS]; - struct GPUShader *composite_sh_cache[MAX_SHADERS]; - struct GPUShader *shadow_fail_sh; - struct GPUShader *shadow_pass_sh; - struct GPUShader *shadow_caps_sh; +#define HSV_SATURATION 0.5 +#define HSV_VALUE 0.9 - struct GPUTexture *object_id_tx; /* ref only, not alloced */ - struct GPUTexture *color_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 */ - float light_direction_vs[3]; - int next_object_id; - float normal_world_matrix[3][3]; -} e_data = {{NULL}}; - -/* Shaders */ -extern char datatoc_workbench_prepass_vert_glsl[]; -extern char datatoc_workbench_prepass_frag_glsl[]; -extern char datatoc_workbench_composite_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_background_lib_glsl[]; -extern char datatoc_workbench_common_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->shading.flag & V3D_SHADING_OBJECT_OUTLINE) -#define SHADOW_ENABLED(wpd) (wpd->shading.flag & V3D_SHADING_SHADOW) -#define NORMAL_VIEWPORT_PASS_ENABLED(wpd) (wpd->shading.light & V3D_LIGHTING_STUDIO || SHADOW_ENABLED(wpd)) -#define NORMAL_ENCODING_ENABLED() (true) -#define STUDIOLIGHT_ORIENTATION_WORLD_ENABLED(wpd) (wpd->studio_light->flag & STUDIOLIGHT_ORIENTATION_WORLD) +void workbench_material_get_solid_color(WORKBENCH_PrivateData *wpd, Object *ob, Material *mat, float *color) +{ + /* When in OB_TEXTURE always uyse V3D_SHADING_MATERIAL_COLOR as fallback when no texture could be determined */ + int color_type = wpd->drawtype == OB_SOLID ? wpd->shading.color_type : V3D_SHADING_MATERIAL_COLOR; + static float default_color[] = {0.8f, 0.8f, 0.8f, 1.0f}; + color[3] = 1.0f; + if (DRW_object_is_paint_mode(ob) || color_type == V3D_SHADING_SINGLE_COLOR) { + copy_v3_v3(color, wpd->shading.single_color); + } + 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 offset = fmodf((hash / 100000.0) * M_GOLDEN_RATION_CONJUGATE, 1.0); + float hsv[3] = {offset, HSV_SATURATION, HSV_VALUE}; + hsv_to_rgb_v(hsv, color); + } + else if (color_type == V3D_SHADING_OBJECT_COLOR) { + copy_v3_v3(color, ob->col); + } + else { + /* V3D_SHADING_MATERIAL_COLOR */ + if (mat) { + copy_v3_v3(color, &mat->r); + } + else { + copy_v3_v3(color, default_color); + } + } +} -static char *workbench_build_defines(WORKBENCH_PrivateData *wpd, int drawtype) +char *workbench_material_build_defines(WORKBENCH_PrivateData *wpd, int drawtype) { char *str = NULL; @@ -136,91 +82,7 @@ static char *workbench_build_defines(WORKBENCH_PrivateData *wpd, int drawtype) return str; } -static char *workbench_build_composite_frag(WORKBENCH_PrivateData *wpd) -{ - char *str = NULL; - - 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_background_lib_glsl); - - if (wpd->shading.light & V3D_LIGHTING_STUDIO) { - BLI_dynstr_append(ds, datatoc_workbench_world_light_lib_glsl); - } - if (wpd->shading.flag & V3D_SHADING_OBJECT_OUTLINE) { - 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 char *workbench_build_prepass_frag(void) -{ - char *str = NULL; - - DynStr *ds = BLI_dynstr_new(); - - BLI_dynstr_append(ds, datatoc_workbench_common_lib_glsl); - BLI_dynstr_append(ds, datatoc_workbench_prepass_frag_glsl); - - str = BLI_dynstr_get_cstring(ds); - BLI_dynstr_free(ds); - return str; -} - -static int get_shader_index(WORKBENCH_PrivateData *wpd, int drawtype) -{ - const int DRAWOPTIONS_MASK = V3D_SHADING_OBJECT_OUTLINE | V3D_SHADING_SHADOW; - int index = (wpd->shading.flag & DRAWOPTIONS_MASK); - index = (index << 2) + wpd->shading.light; - index = (index << 2); - /* set the drawtype flag - 0 = OB_SOLID, - 1 = OB_TEXTURE - 2 = STUDIOLIGHT_ORIENTATION_WORLD - */ - SET_FLAG_FROM_TEST(index, wpd->studio_light->flag & STUDIOLIGHT_ORIENTATION_WORLD, 2); - SET_FLAG_FROM_TEST(index, drawtype == OB_TEXTURE, 1); - return index; -} - -static void ensure_deferred_shaders(WORKBENCH_PrivateData *wpd, int index, int drawtype) -{ - if (e_data.prepass_sh_cache[index] == NULL) { - char *defines = workbench_build_defines(wpd, drawtype); - char *composite_frag = workbench_build_composite_frag(wpd); - char *prepass_frag = workbench_build_prepass_frag(); - e_data.prepass_sh_cache[index] = DRW_shader_create(datatoc_workbench_prepass_vert_glsl, NULL, prepass_frag, defines); - if (drawtype == OB_SOLID) { - e_data.composite_sh_cache[index] = DRW_shader_create_fullscreen(composite_frag, defines); - } - MEM_freeN(prepass_frag); - MEM_freeN(composite_frag); - MEM_freeN(defines); - } -} - -static void select_deferred_shaders(WORKBENCH_PrivateData *wpd) -{ - int index_solid = get_shader_index(wpd, OB_SOLID); - int index_texture = get_shader_index(wpd, OB_TEXTURE); - - ensure_deferred_shaders(wpd, index_solid, OB_SOLID); - ensure_deferred_shaders(wpd, index_texture, OB_TEXTURE); - - wpd->prepass_solid_sh = e_data.prepass_sh_cache[index_solid]; - wpd->prepass_texture_sh = e_data.prepass_sh_cache[index_texture]; - wpd->composite_sh = e_data.composite_sh_cache[index_solid]; -} - -/* Functions */ -static uint get_material_hash(WORKBENCH_MaterialData *material_template) +uint workbench_material_get_hash(WORKBENCH_MaterialData *material_template) { /* TODO: make a C-string with settings and hash the string */ uint input[4]; @@ -239,172 +101,24 @@ static uint get_material_hash(WORKBENCH_MaterialData *material_template) return result; } -static void workbench_init_object_data(ObjectEngineData *engine_data) -{ - WORKBENCH_ObjectData *data = (WORKBENCH_ObjectData *)engine_data; - data->object_id = e_data.next_object_id++; -} - -static void get_material_solid_color(WORKBENCH_PrivateData *wpd, Object *ob, Material *mat, float *color, float hsv_saturation, float hsv_value) -{ - /* When in OB_TEXTURE always uyse V3D_SHADING_MATERIAL_COLOR as fallback when no texture could be determined */ - int color_type = wpd->drawtype == OB_SOLID ? wpd->shading.color_type : V3D_SHADING_MATERIAL_COLOR; - static float default_color[] = {0.8f, 0.8f, 0.8f}; - if (DRW_object_is_paint_mode(ob) || color_type == V3D_SHADING_SINGLE_COLOR) { - copy_v3_v3(color, wpd->shading.single_color); - } - 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 offset = fmodf((hash / 100000.0) * M_GOLDEN_RATION_CONJUGATE, 1.0); - - float hsv[3] = {offset, hsv_saturation, hsv_value}; - hsv_to_rgb_v(hsv, color); - } - else if (color_type == V3D_SHADING_OBJECT_COLOR) { - copy_v3_v3(color, ob->col); - } - else { - /* V3D_SHADING_MATERIAL_COLOR */ - if (mat) { - copy_v3_v3(color, &mat->r); - } - else { - copy_v3_v3(color, default_color); - } - } -} -static void workbench_private_data_init(WORKBENCH_Data *vedata) -{ - WORKBENCH_StorageList *stl = vedata->stl; - WORKBENCH_PrivateData *wpd = stl->g_data; - const DRWContextState *draw_ctx = DRW_context_state_get(); - - View3D *v3d = draw_ctx->v3d; - if (v3d) { - wpd->shading = v3d->shading; - wpd->drawtype = v3d->drawtype; - wpd->studio_light = BKE_studiolight_find(wpd->shading.studio_light); - } - else { - /* XXX: We should get the default shading from the view layer, after we implemented the render callback */ - memset(&wpd->shading, 0, sizeof(wpd->shading)); - wpd->shading.light = V3D_LIGHTING_STUDIO; - wpd->shading.shadow_intensity = 0.5; - copy_v3_fl(wpd->shading.single_color, 0.8f); - wpd->drawtype = OB_SOLID; - wpd->studio_light = BKE_studiolight_findindex(0); - } - wpd->shadow_multiplier = 1.0 - wpd->shading.shadow_intensity; - - WORKBENCH_UBO_World *wd = &wpd->world_data; - 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); - - /* XXX: Really quick conversion to avoid washed out background. - * Needs to be adressed properly (color managed using ocio). */ - srgb_to_linearrgb_v3_v3(wd->background_color_high, wd->background_color_high); - srgb_to_linearrgb_v3_v3(wd->background_color_low, wd->background_color_low); - - studiolight_update_world(wpd->studio_light, wd); - -} -void workbench_materials_engine_init(WORKBENCH_Data *vedata) +int workbench_material_get_shader_index(WORKBENCH_PrivateData *wpd, int drawtype) { - WORKBENCH_FramebufferList *fbl = vedata->fbl; - WORKBENCH_StorageList *stl = vedata->stl; - WORKBENCH_PassList *psl = vedata->psl; - DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); - - 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; -#ifdef DEBUG_SHADOW_VOLUME - const char *shadow_frag = datatoc_workbench_shadow_debug_frag_glsl; -#else - const char *shadow_frag = NULL; -#endif - e_data.shadow_pass_sh = DRW_shader_create( - datatoc_workbench_shadow_vert_glsl, - datatoc_workbench_shadow_geom_glsl, - shadow_frag, - "#define SHADOW_PASS\n"); - e_data.shadow_fail_sh = DRW_shader_create( - datatoc_workbench_shadow_vert_glsl, - datatoc_workbench_shadow_geom_glsl, - shadow_frag, - "#define SHADOW_FAIL\n"); - e_data.shadow_caps_sh = DRW_shader_create( - datatoc_workbench_shadow_vert_glsl, - datatoc_workbench_shadow_caps_geom_glsl, - shadow_frag, - NULL); - } - - if (!stl->g_data) { - /* Alloc transient pointers */ - stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__); - } - - workbench_private_data_init(vedata); - - { - 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], GPU_R32UI, &draw_engine_workbench_solid); - e_data.color_buffer_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_RGBA8, &draw_engine_workbench_solid); - e_data.composite_buffer_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_RGBA16F, &draw_engine_workbench_solid); - - if (NORMAL_ENCODING_ENABLED()) { - e_data.normal_buffer_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_RG16, &draw_engine_workbench_solid); - } - else { - e_data.normal_buffer_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_RGBA32F, &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.color_buffer_tx), - GPU_ATTACHMENT_TEXTURE(e_data.normal_buffer_tx), - }); - GPU_framebuffer_ensure_config(&fbl->composite_fb, { - GPU_ATTACHMENT_TEXTURE(dtxl->depth), - GPU_ATTACHMENT_TEXTURE(e_data.composite_buffer_tx), - }); - } - - /* Prepass */ - { - int state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL; - 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]); - } - DRW_SHADER_FREE_SAFE(e_data.shadow_pass_sh); - DRW_SHADER_FREE_SAFE(e_data.shadow_fail_sh); - DRW_SHADER_FREE_SAFE(e_data.shadow_caps_sh); + const int DRAWOPTIONS_MASK = V3D_SHADING_OBJECT_OUTLINE | V3D_SHADING_SHADOW; + int index = (wpd->shading.flag & DRAWOPTIONS_MASK); + index = (index << 2) + wpd->shading.light; + index = (index << 2); + /* set the drawtype flag + 0 = OB_SOLID, + 1 = OB_TEXTURE + 2 = STUDIOLIGHT_ORIENTATION_WORLD + */ + SET_FLAG_FROM_TEST(index, wpd->studio_light->flag & STUDIOLIGHT_ORIENTATION_WORLD, 2); + SET_FLAG_FROM_TEST(index, drawtype == OB_TEXTURE, 1); + return index; } -static void workbench_composite_uniforms(WORKBENCH_PrivateData *wpd, DRWShadingGroup *grp) +void workbench_material_set_normal_world_matrix(DRWShadingGroup *grp, WORKBENCH_PrivateData *wpd, float persistent_matrix[3][3]) { - DRW_shgroup_uniform_texture_ref(grp, "colorBuffer", &e_data.color_buffer_tx); - DRW_shgroup_uniform_texture_ref(grp, "objectId", &e_data.object_id_tx); - if (NORMAL_VIEWPORT_PASS_ENABLED(wpd)) { - DRW_shgroup_uniform_texture_ref(grp, "normalBuffer", &e_data.normal_buffer_tx); - } - DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo); - DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1); - if (STUDIOLIGHT_ORIENTATION_WORLD_ENABLED(wpd)) { float view_matrix_inverse[4][4]; float rot_matrix[4][4]; @@ -412,340 +126,7 @@ static void workbench_composite_uniforms(WORKBENCH_PrivateData *wpd, DRWShadingG axis_angle_to_mat4_single(rot_matrix, 'Z', -wpd->shading.studiolight_rot_z); DRW_viewport_matrix_get(view_matrix_inverse, DRW_MAT_VIEWINV); mul_m4_m4m4(matrix, rot_matrix, view_matrix_inverse); - copy_m3_m4(e_data.normal_world_matrix, matrix); - DRW_shgroup_uniform_mat3(grp, "normalWorldMatrix", e_data.normal_world_matrix); - } -} - -void workbench_materials_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(); - static float light_multiplier = 1.0f; - - wpd->material_hash = BLI_ghash_ptr_new(__func__); - - Scene *scene = draw_ctx->scene; - - select_deferred_shaders(wpd); - /* Deferred Mix Pass */ - { - wpd->world_ubo = DRW_uniformbuffer_create(sizeof(WORKBENCH_UBO_World), NULL); - DRW_uniformbuffer_update(wpd->world_ubo, &wpd->world_data); - - copy_v3_v3(e_data.display.light_direction, scene->display.light_direction); - negate_v3(e_data.display.light_direction); -#if 0 - if (STUDIOLIGHT_ORIENTATION_WORLD_ENABLED(wpd)) { - BKE_studiolight_ensure_flag(wpd->studio_light, STUDIOLIGHT_LIGHT_DIRECTION_CALCULATED); - float rot_matrix[3][3]; - // float dir[3] = {0.57, 0.57, -0.57}; - axis_angle_to_mat3_single(rot_matrix, 'Z', wpd->shading.studiolight_rot_z); - mul_v3_m3v3(e_data.display.light_direction, rot_matrix, wpd->studio_light->light_direction); + copy_m3_m4(persistent_matrix, matrix); + DRW_shgroup_uniform_mat3(grp, "normalWorldMatrix", persistent_matrix); } -#endif - float view_matrix[4][4]; - DRW_viewport_matrix_get(view_matrix, DRW_MAT_VIEW); - mul_v3_mat3_m4v3(e_data.light_direction_vs, view_matrix, e_data.display.light_direction); - - e_data.display.shadow_shift = scene->display.shadow_shift; - - if (SHADOW_ENABLED(wpd)) { - psl->composite_pass = DRW_pass_create("Composite", DRW_STATE_WRITE_COLOR | DRW_STATE_STENCIL_EQUAL); - grp = DRW_shgroup_create(wpd->composite_sh, psl->composite_pass); - workbench_composite_uniforms(wpd, grp); - DRW_shgroup_stencil_mask(grp, 0x00); - DRW_shgroup_uniform_vec3(grp, "lightDirection", e_data.light_direction_vs, 1); - DRW_shgroup_uniform_float(grp, "lightMultiplier", &light_multiplier, 1); - DRW_shgroup_uniform_float(grp, "shadowMultiplier", &wpd->shadow_multiplier, 1); - DRW_shgroup_uniform_float(grp, "shadowShift", &scene->display.shadow_shift, 1); - DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); - -#ifdef DEBUG_SHADOW_VOLUME - psl->shadow_depth_pass_pass = DRW_pass_create("Shadow Debug Pass", DRW_STATE_DEPTH_LESS | DRW_STATE_WRITE_COLOR | DRW_STATE_ADDITIVE); - grp = DRW_shgroup_create(e_data.shadow_pass_sh, psl->shadow_depth_pass_pass); - psl->shadow_depth_fail_pass = DRW_pass_create("Shadow Debug Fail", DRW_STATE_DEPTH_GREATER_EQUAL | DRW_STATE_WRITE_COLOR | DRW_STATE_ADDITIVE); - grp = DRW_shgroup_create(e_data.shadow_fail_sh, psl->shadow_depth_fail_pass); - psl->shadow_depth_fail_caps_pass = DRW_pass_create("Shadow Depth Fail Caps", DRW_STATE_DEPTH_GREATER_EQUAL | DRW_STATE_WRITE_COLOR | DRW_STATE_ADDITIVE); - grp = DRW_shgroup_create(e_data.shadow_caps_sh, psl->shadow_depth_fail_caps_pass); -#else - psl->shadow_depth_pass_pass = DRW_pass_create("Shadow Depth Pass", DRW_STATE_DEPTH_LESS | DRW_STATE_WRITE_STENCIL_SHADOW_PASS); - grp = DRW_shgroup_create(e_data.shadow_pass_sh, psl->shadow_depth_pass_pass); - DRW_shgroup_stencil_mask(grp, 0xFF); - psl->shadow_depth_fail_pass = DRW_pass_create("Shadow Depth Fail", DRW_STATE_DEPTH_LESS | DRW_STATE_WRITE_STENCIL_SHADOW_FAIL); - grp = DRW_shgroup_create(e_data.shadow_fail_sh, psl->shadow_depth_fail_pass); - DRW_shgroup_stencil_mask(grp, 0xFF); - psl->shadow_depth_fail_caps_pass = DRW_pass_create("Shadow Depth Fail Caps", DRW_STATE_DEPTH_LESS | DRW_STATE_WRITE_STENCIL_SHADOW_FAIL); - grp = DRW_shgroup_create(e_data.shadow_caps_sh, psl->shadow_depth_fail_caps_pass); - DRW_shgroup_stencil_mask(grp, 0xFF); - - psl->composite_shadow_pass = DRW_pass_create("Composite Shadow", DRW_STATE_WRITE_COLOR | DRW_STATE_STENCIL_NEQUAL); - 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_vec3(grp, "lightDirection", e_data.light_direction_vs, 1); - DRW_shgroup_uniform_float(grp, "lightMultiplier", &wpd->shadow_multiplier, 1); - DRW_shgroup_uniform_float(grp, "shadowMultiplier", &wpd->shadow_multiplier, 1); - DRW_shgroup_uniform_float(grp, "shadowShift", &scene->display.shadow_shift, 1); - DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); -#endif - } - else { - psl->composite_pass = DRW_pass_create("Composite", DRW_STATE_WRITE_COLOR); - grp = DRW_shgroup_create(wpd->composite_sh, psl->composite_pass); - workbench_composite_uniforms(wpd, grp); - DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); - } - } -} -static WORKBENCH_MaterialData *get_or_create_material_data(WORKBENCH_Data *vedata, Object *ob, Material *mat, Image *ima, int drawtype) -{ - WORKBENCH_StorageList *stl = vedata->stl; - WORKBENCH_PassList *psl = vedata->psl; - WORKBENCH_PrivateData *wpd = stl->g_data; - WORKBENCH_MaterialData *material; - 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; - const float hsv_saturation = 0.5; - const float hsv_value = 0.9; - - /* Solid */ - get_material_solid_color(wpd, ob, mat, material_template.color, hsv_saturation, hsv_value); - material_template.object_id = engine_object_data->object_id; - material_template.drawtype = drawtype; - material_template.ima = ima; - uint hash = get_material_hash(&material_template); - - material = BLI_ghash_lookup(wpd->material_hash, SET_UINT_IN_POINTER(hash)); - if (material == NULL) { - material = MEM_mallocN(sizeof(WORKBENCH_MaterialData), __func__); - material->shgrp = DRW_shgroup_create(drawtype == OB_SOLID ? wpd->prepass_solid_sh : wpd->prepass_texture_sh, psl->prepass_pass); - DRW_shgroup_stencil_mask(material->shgrp, 0xFF); - material->object_id = engine_object_data->object_id; - copy_v3_v3(material->color, material_template.color); - switch (drawtype) { - case OB_SOLID: - DRW_shgroup_uniform_vec3(material->shgrp, "object_color", material->color, 1); - break; - - case OB_TEXTURE: - { - GPUTexture *tex = GPU_texture_from_blender(ima, NULL, GL_TEXTURE_2D, false, false, false); - DRW_shgroup_uniform_texture(material->shgrp, "image", tex); - break; - } - } - DRW_shgroup_uniform_int(material->shgrp, "object_id", &material->object_id, 1); - BLI_ghash_insert(wpd->material_hash, SET_UINT_IN_POINTER(hash), material); - } - return material; -} - -static void workbench_cache_populate_particles(WORKBENCH_Data *vedata, Object *ob) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - if (ob == draw_ctx->object_edit) { - return; - } - for (ParticleSystem *psys = ob->particlesystem.first; psys != NULL; psys = psys->next) { - if (!psys_check_enabled(ob, psys, false)) { - continue; - } - if (!DRW_check_psys_visible_within_active_context(ob, psys)) { - return; - } - ParticleSettings *part = psys->part; - const int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as; - - static float mat[4][4]; - unit_m4(mat); - - if (draw_as == PART_DRAW_PATH) { - struct Gwn_Batch *geom = DRW_cache_particles_get_hair(ob, psys, NULL); - WORKBENCH_MaterialData *material = get_or_create_material_data(vedata, ob, NULL, NULL, OB_SOLID); - DRW_shgroup_call_add(material->shgrp, geom, mat); - } - } -} - -void workbench_materials_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob) -{ - WORKBENCH_PassList *psl = vedata->psl; - WORKBENCH_StorageList *stl = vedata->stl; - WORKBENCH_PrivateData *wpd = stl->g_data; - - if (!DRW_object_is_renderable(ob)) - return; - - if (ob->type == OB_MESH) { - workbench_cache_populate_particles(vedata, ob); - } - - WORKBENCH_MaterialData *material; - if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT)) { - const DRWContextState *draw_ctx = DRW_context_state_get(); - const bool is_active = (ob == draw_ctx->obact); - const bool is_sculpt_mode = is_active && (draw_ctx->object_mode & OB_MODE_SCULPT) != 0; - bool is_drawn = false; - if (!is_sculpt_mode && wpd->drawtype == OB_TEXTURE && ob->type == OB_MESH) { - const Mesh *me = ob->data; - if (me->mloopuv) { - const int materials_len = MAX2(1, (is_sculpt_mode ? 1 : ob->totcol)); - struct GPUMaterial **gpumat_array = BLI_array_alloca(gpumat_array, materials_len); - struct Gwn_Batch **geom_array = me->totcol ? DRW_cache_mesh_surface_texpaint_get(ob) : NULL; - if (materials_len > 0 && geom_array) { - for (int i = 0; i < materials_len; i++) { - Material *mat = give_current_material(ob, i + 1); - Image *image; - ED_object_get_active_image(ob, i + 1, &image, NULL, NULL, NULL); - /* use OB_SOLID when no texture could be determined */ - int mat_drawtype = OB_SOLID; - if (image) { - mat_drawtype = OB_TEXTURE; - } - material = get_or_create_material_data(vedata, ob, mat, image, mat_drawtype); - DRW_shgroup_call_object_add(material->shgrp, geom_array[i], ob); - } - is_drawn = true; - } - } - } - - /* Fallback from not drawn OB_TEXTURE mode or just OB_SOLID mode */ - if (!is_drawn) { - if ((wpd->shading.color_type != V3D_SHADING_MATERIAL_COLOR) || is_sculpt_mode) { - /* No material split needed */ - struct Gwn_Batch *geom = DRW_cache_object_surface_get(ob); - if (geom) { - material = get_or_create_material_data(vedata, ob, NULL, NULL, OB_SOLID); - if (is_sculpt_mode) { - DRW_shgroup_call_sculpt_add(material->shgrp, ob, ob->obmat); - } - else { - DRW_shgroup_call_object_add(material->shgrp, geom, ob); - } - } - } - else { /* MATERIAL colors */ - const int materials_len = MAX2(1, (is_sculpt_mode ? 1 : ob->totcol)); - struct GPUMaterial **gpumat_array = BLI_array_alloca(gpumat_array, materials_len); - for (int i = 0; i < materials_len; i++) { - gpumat_array[i] = NULL; - } - - struct Gwn_Batch **mat_geom = DRW_cache_object_surface_material_get(ob, gpumat_array, materials_len, NULL, NULL, NULL); - if (mat_geom) { - for (int i = 0; i < materials_len; ++i) { - Material *mat = give_current_material(ob, i + 1); - material = get_or_create_material_data(vedata, ob, mat, NULL, OB_SOLID); - DRW_shgroup_call_object_add(material->shgrp, mat_geom[i], ob); - } - } - } - } - - if (SHADOW_ENABLED(wpd) && (ob->display.flag & OB_SHOW_SHADOW) > 0) { - struct Gwn_Batch *geom_shadow = DRW_cache_object_edge_detection_get(ob); - if (geom_shadow) { - if (is_sculpt_mode) { - /* 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 - * sculped meshes are heavy to begin with. */ - // DRW_shgroup_call_sculpt_add(wpd->shadow_shgrp, ob, ob->obmat); - } - else { - 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); - - invert_m4_m4(ob->imat, ob->obmat); - mul_v3_mat3_m4v3(engine_object_data->shadow_dir, ob->imat, e_data.display.light_direction); - - DRWShadingGroup *grp; - if (true) { - 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_call_object_add(grp, geom_shadow, ob); - } - else { - struct Gwn_Batch *geom_caps = DRW_cache_object_surface_get(ob); - if (geom_caps) { - 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_call_object_add(grp, geom_caps, ob); - } - - 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_call_object_add(grp, geom_shadow, ob); - } - } - } - } - } -} - -void workbench_materials_cache_finish(WORKBENCH_Data *UNUSED(vedata)) -{ -} - -void workbench_materials_draw_background(WORKBENCH_Data *vedata) -{ - WORKBENCH_StorageList *stl = vedata->stl; - WORKBENCH_FramebufferList *fbl = vedata->fbl; - WORKBENCH_PrivateData *wpd = stl->g_data; - const float clear_depth = 1.0f; - const float clear_color[4] = {0.0f, 0.0f, 0.0f, 0.0f}; - uint clear_stencil = 0xFF; - - DRW_stats_group_start("Clear Background"); - GPU_framebuffer_bind(fbl->prepass_fb); - int clear_bits = GPU_DEPTH_BIT | GPU_COLOR_BIT; - SET_FLAG_FROM_TEST(clear_bits, SHADOW_ENABLED(wpd), GPU_STENCIL_BIT); - GPU_framebuffer_clear(fbl->prepass_fb, clear_bits, clear_color, clear_depth, clear_stencil); - DRW_stats_group_end(); -} - -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(); - - /* clear in background */ - GPU_framebuffer_bind(fbl->prepass_fb); - DRW_draw_pass(psl->prepass_pass); - if (SHADOW_ENABLED(wpd)) { -#ifdef DEBUG_SHADOW_VOLUME - GPU_framebuffer_bind(fbl->composite_fb); - DRW_draw_pass(psl->composite_pass); - DRW_draw_pass(psl->shadow_depth_pass_pass); - DRW_draw_pass(psl->shadow_depth_fail_pass); - DRW_draw_pass(psl->shadow_depth_fail_caps_pass); -#else - GPU_framebuffer_bind(dfbl->depth_only_fb); - DRW_draw_pass(psl->shadow_depth_pass_pass); - DRW_draw_pass(psl->shadow_depth_fail_pass); - DRW_draw_pass(psl->shadow_depth_fail_caps_pass); - 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); - } - - GPU_framebuffer_bind(dfbl->color_only_fb); - DRW_transform_to_display(e_data.composite_buffer_tx); - - 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 5c3db3e0d57..714314a3d09 100644 --- a/source/blender/draw/engines/workbench/workbench_private.h +++ b/source/blender/draw/engines/workbench/workbench_private.h @@ -37,11 +37,24 @@ #define WORKBENCH_ENGINE "BLENDER_WORKBENCH" #define M_GOLDEN_RATION_CONJUGATE 0.618033988749895 +#define MAX_SHADERS 255 + + +#define OBJECT_ID_PASS_ENABLED(wpd) (wpd->shading.flag & V3D_SHADING_OBJECT_OUTLINE) +#define SHADOW_ENABLED(wpd) (wpd->shading.flag & V3D_SHADING_SHADOW) +#define NORMAL_VIEWPORT_PASS_ENABLED(wpd) (wpd->shading.light & V3D_LIGHTING_STUDIO || SHADOW_ENABLED(wpd)) +#define NORMAL_ENCODING_ENABLED() (true) +#define STUDIOLIGHT_ORIENTATION_WORLD_ENABLED(wpd) (wpd->studio_light->flag & STUDIOLIGHT_ORIENTATION_WORLD) typedef struct WORKBENCH_FramebufferList { + /* Deferred render buffers */ struct GPUFrameBuffer *prepass_fb; struct GPUFrameBuffer *composite_fb; + + /* Forward render buffers */ + struct GPUFrameBuffer *depth_fb; + struct GPUFrameBuffer *transparent_accum_fb; } WORKBENCH_FramebufferList; typedef struct WORKBENCH_StorageList { @@ -49,13 +62,17 @@ typedef struct WORKBENCH_StorageList { } WORKBENCH_StorageList; typedef struct WORKBENCH_PassList { + /* deferred rendering */ struct DRWPass *prepass_pass; struct DRWPass *shadow_depth_pass_pass; struct DRWPass *shadow_depth_fail_pass; struct DRWPass *shadow_depth_fail_caps_pass; struct DRWPass *composite_pass; struct DRWPass *composite_shadow_pass; - struct DRWPass *composite_light_pass; + + /* forward rendering */ + struct DRWPass *transparent_accum_pass; + struct DRWPass *depth_pass; } WORKBENCH_PassList; typedef struct WORKBENCH_Data { @@ -75,6 +92,9 @@ typedef struct WORKBENCH_UBO_World { float diffuse_light_z_neg[4]; float background_color_low[4]; float background_color_high[4]; + float object_outline_color[4]; + float see_through_transparency; + float pad[3]; } WORKBENCH_UBO_World; BLI_STATIC_ASSERT_ALIGN(WORKBENCH_UBO_World, 16) @@ -83,6 +103,8 @@ typedef struct WORKBENCH_PrivateData { struct GPUShader *prepass_solid_sh; struct GPUShader *prepass_texture_sh; struct GPUShader *composite_sh; + struct GPUShader *transparent_accum_sh; + struct GPUShader *transparent_accum_texture_sh; View3DShading shading; StudioLight *studio_light; int drawtype; @@ -94,13 +116,15 @@ typedef struct WORKBENCH_PrivateData { typedef struct WORKBENCH_MaterialData { /* Solid color */ - float color[3]; + float color[4]; int object_id; int drawtype; Image *ima; /* Linked shgroup for drawing */ DRWShadingGroup *shgrp; + /* forward rendering */ + DRWShadingGroup *shgrp_depth; } WORKBENCH_MaterialData; typedef struct WORKBENCH_ObjectData { @@ -124,16 +148,39 @@ void workbench_solid_materials_cache_finish(WORKBENCH_Data *vedata); void workbench_solid_materials_draw_scene(WORKBENCH_Data *vedata); void workbench_solid_materials_free(void); +/* workbench_deferred.c */ +void workbench_deferred_engine_init(WORKBENCH_Data *vedata); +void workbench_deferred_engine_free(void); +void workbench_deferred_draw_background(WORKBENCH_Data *vedata); +void workbench_deferred_draw_scene(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_background(WORKBENCH_Data *vedata); +void workbench_forward_draw_scene(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); + /* workbench_materials.c */ -void workbench_materials_engine_init(WORKBENCH_Data *vedata); -void workbench_materials_engine_free(void); -void workbench_materials_draw_background(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); +char *workbench_material_build_defines(WORKBENCH_PrivateData *wpd, int drawtype); +void workbench_material_get_solid_color(WORKBENCH_PrivateData *wpd, Object *ob, Material *mat, float *color); +uint workbench_material_get_hash(WORKBENCH_MaterialData *material_template); +int workbench_material_get_shader_index(WORKBENCH_PrivateData *wpd, int drawtype); +void workbench_material_set_normal_world_matrix(DRWShadingGroup *grp, WORKBENCH_PrivateData *wpd, float persistent_matrix[3][3]); /* workbench_studiolight.c */ void studiolight_update_world(StudioLight *sl, WORKBENCH_UBO_World *wd); +/* workbench_data.c */ +void workbench_private_data_init(WORKBENCH_PrivateData *wpd); +void workbench_private_data_free(WORKBENCH_PrivateData *wpd); + +extern DrawEngineType draw_engine_workbench_solid; +extern DrawEngineType draw_engine_workbench_transparent; + #endif diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 95256a2b1c8..c91c4536fa4 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -1015,7 +1015,7 @@ static void drw_engines_enable_external(void) /* 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, int drawtype) +static void drw_engines_enable_from_engine(RenderEngineType *engine_type, int drawtype, int shading_flags) { switch (drawtype) { case OB_WIRE: @@ -1023,7 +1023,12 @@ static void drw_engines_enable_from_engine(RenderEngineType *engine_type, int dr case OB_SOLID: case OB_TEXTURE: - use_drw_engine(&draw_engine_workbench_solid); + if (shading_flags & V3D_SHADING_SEE_THROUGH) { + use_drw_engine(&draw_engine_workbench_transparent); + } + else { + use_drw_engine(&draw_engine_workbench_solid); + } break; case OB_MATERIAL: @@ -1118,7 +1123,7 @@ static void drw_engines_enable(ViewLayer *view_layer, RenderEngineType *engine_t View3D * v3d = DST.draw_ctx.v3d; const int drawtype = v3d->drawtype; - drw_engines_enable_from_engine(engine_type, drawtype); + drw_engines_enable_from_engine(engine_type, drawtype, v3d->shading.flag); if (DRW_state_draw_support()) { drw_engines_enable_from_overlays(v3d->overlay.flag); diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index f26da3ad07e..d52ff1259cf 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -324,6 +324,7 @@ static SpaceLink *view3d_new(const ScrArea *UNUSED(sa), const Scene *scene) v3d->drawtype = OB_SOLID; v3d->shading.light = V3D_LIGHTING_STUDIO; v3d->shading.shadow_intensity = 0.5; + v3d->shading.see_through_transparency = 0.3f; copy_v3_fl(v3d->shading.single_color, 0.8f); v3d->gridflag = V3D_SHOW_X | V3D_SHOW_Y | V3D_SHOW_FLOOR; diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c index e7f6cf36476..0ee9adfc396 100644 --- a/source/blender/editors/space_view3d/view3d_header.c +++ b/source/blender/editors/space_view3d/view3d_header.c @@ -221,6 +221,45 @@ void VIEW3D_OT_layers(wmOperatorType *ot) RNA_def_boolean(ot->srna, "toggle", 1, "Toggle", "Toggle the layer"); } +/* -------------------------------------------------------------------- */ +/** \name Toggle Bone selection Overlay Operator + * \{ */ + +static int toggle_show_see_through(bContext *C, wmOperator *UNUSED(op)) +{ + View3D *v3d = CTX_wm_view3d(C); + v3d->shading.flag ^= V3D_SHADING_SEE_THROUGH; + ED_view3d_shade_update(CTX_data_main(C), v3d, CTX_wm_area(C)); + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d); + return OPERATOR_FINISHED; +} + +static int toggle_show_see_through_poll(bContext *C) +{ + bool result = (ED_operator_view3d_active(C) && !ED_operator_posemode(C)); + if (result) { + // Additional test for SOLID or TEXTURE mode + View3D *v3d = CTX_wm_view3d(C); + result = (v3d->drawtype & (OB_SOLID | OB_TEXTURE)) > 0; + } + return result; +} + +void VIEW3D_OT_toggle_see_through_draw_option(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Toggle Show See Though"; + ot->description = "Toggle show see through"; + ot->idname = "VIEW3D_OT_toggle_see_through_draw_option"; + + /* api callbacks */ + ot->exec = toggle_show_see_through; + ot->poll = toggle_show_see_through_poll; +} + +/** \} */ + + static void do_view3d_header_buttons(bContext *C, void *UNUSED(arg), int event) { wmWindow *win = CTX_wm_window(C); diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h index 1c86e5ab30b..794ca0dcad9 100644 --- a/source/blender/editors/space_view3d/view3d_intern.h +++ b/source/blender/editors/space_view3d/view3d_intern.h @@ -65,6 +65,7 @@ enum { /* view3d_header.c */ void VIEW3D_OT_layers(struct wmOperatorType *ot); +void VIEW3D_OT_toggle_see_through_draw_option(struct wmOperatorType *ot); /* view3d_ops.c */ void view3d_operatortypes(void); diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c index 43ff8af42fb..dd168c26f07 100644 --- a/source/blender/editors/space_view3d/view3d_ops.c +++ b/source/blender/editors/space_view3d/view3d_ops.c @@ -222,6 +222,7 @@ void view3d_operatortypes(void) WM_operatortype_append(VIEW3D_OT_snap_cursor_to_active); WM_operatortype_append(VIEW3D_OT_toggle_render); + WM_operatortype_append(VIEW3D_OT_toggle_see_through_draw_option); WM_operatortype_append(VIEW3D_OT_ruler_add); @@ -402,18 +403,13 @@ void view3d_keymap(wmKeyConfig *keyconf) RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_layers", ZEROKEY, KM_PRESS, KM_ANY, 0)->ptr, "nr", 10); /* drawtype */ - - kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle_enum", ZKEY, KM_PRESS, 0, 0); - RNA_string_set(kmi->ptr, "data_path", "space_data.shading.type"); - RNA_string_set(kmi->ptr, "value_1", "SOLID"); - RNA_string_set(kmi->ptr, "value_2", "WIREFRAME"); - kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle_enum", ZKEY, KM_PRESS, KM_ALT, 0); RNA_string_set(kmi->ptr, "data_path", "space_data.shading.type"); RNA_string_set(kmi->ptr, "value_1", "SOLID"); RNA_string_set(kmi->ptr, "value_2", "TEXTURED"); WM_keymap_add_item(keymap, "VIEW3D_OT_toggle_render", ZKEY, KM_PRESS, KM_SHIFT, 0); + WM_keymap_add_item(keymap, "VIEW3D_OT_toggle_see_through_draw_option", ZKEY, KM_PRESS, 0, 0); kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", ZKEY, KM_PRESS, 0, 0); RNA_string_set(kmi->ptr, "data_path", "space_data.use_occlude_geometry"); diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h index 0df741df031..fd0f78dda2a 100644 --- a/source/blender/makesdna/DNA_view3d_types.h +++ b/source/blender/makesdna/DNA_view3d_types.h @@ -145,6 +145,9 @@ typedef struct View3DShading { float single_color[3]; float studiolight_rot_z; + float see_through_transparency; + + float object_outline_color[3]; float pad2; } View3DShading; @@ -335,6 +338,7 @@ enum { /* View3DShading->flag */ enum { V3D_SHADING_OBJECT_OUTLINE = (1 << 0), + V3D_SHADING_SEE_THROUGH = (1 << 1), V3D_SHADING_SHADOW = (1 << 2), }; diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 3b9adad4957..d90dbd2ad7a 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -2293,6 +2293,7 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna) RNA_def_property_float_sdna(prop, NULL, "shading.single_color"); RNA_def_property_array(prop, 3); RNA_def_property_ui_text(prop, "Color", "Color for single color mode"); + RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); prop = RNA_def_property(srna, "show_shadows", PROP_BOOLEAN, PROP_NONE); @@ -2301,6 +2302,28 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Shadow", "Show Shadow"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); + prop = RNA_def_property(srna, "show_see_through", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "shading.flag", V3D_SHADING_SEE_THROUGH); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_ui_text(prop, "See Through", "Show whole scene transparent"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); + + prop = RNA_def_property(srna, "see_through_transparency", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "shading.see_through_transparency"); + RNA_def_property_float_default(prop, 0.3f); + RNA_def_property_ui_text(prop, "Transparency", "See through transparency"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_range(prop, 0.1f, 0.5f, 1, 3); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); + + prop = RNA_def_property(srna, "object_outline_color", PROP_FLOAT, PROP_COLOR); + RNA_def_property_float_sdna(prop, NULL, "shading.object_outline_color"); + RNA_def_property_array(prop, 3); + RNA_def_property_ui_text(prop, "Outline Color", "Color for object outline"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); + prop = RNA_def_property(srna, "shadow_intensity", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "shading.shadow_intensity"); RNA_def_property_float_default(prop, 0.5); |