From 765fd29d6855d098d8fcdd72ba595dfd1e4e4e17 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Fri, 25 May 2018 08:06:36 +0200 Subject: [PATCH] EEvEE: LookDev --- release/scripts/startup/bl_ui/space_view3d.py | 5 + source/blender/blenkernel/BKE_icons.h | 2 +- source/blender/blenkernel/BKE_studiolight.h | 17 +- source/blender/blenkernel/intern/icons.c | 5 +- .../blender/blenkernel/intern/studiolight.c | 229 +++++++++++++----- source/blender/draw/CMakeLists.txt | 1 + .../draw/engines/eevee/eevee_effects.c | 7 + .../blender/draw/engines/eevee/eevee_engine.c | 6 +- .../draw/engines/eevee/eevee_lightprobes.c | 13 +- .../draw/engines/eevee/eevee_lookdev.c | 130 ++++++++++ .../draw/engines/eevee/eevee_materials.c | 82 ++++++- .../draw/engines/eevee/eevee_private.h | 44 ++-- .../engines/eevee/shaders/default_frag.glsl | 4 + .../eevee/shaders/default_world_frag.glsl | 52 +++- .../draw/engines/workbench/workbench_data.c | 2 +- .../editors/interface/interface_icons.c | 2 +- source/blender/makesrna/intern/rna_space.c | 43 +++- 17 files changed, 543 insertions(+), 101 deletions(-) create mode 100644 source/blender/draw/engines/eevee/eevee_lookdev.c diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index e3d8a66ae8c..c9decadf150 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -3545,6 +3545,11 @@ class VIEW3D_PT_shading(Panel): sub.active = shading.show_object_outline sub.prop(shading, "object_outline_color", text="") + elif shading.type in ('MATERIAL'): + col.row().template_icon_view(shading, "studio_light") + if shading.studio_light_orientation == 'WORLD': + col.row().prop(shading, "studiolight_rot_z") + class VIEW3D_PT_overlay(Panel): bl_space_type = 'VIEW_3D' diff --git a/source/blender/blenkernel/BKE_icons.h b/source/blender/blenkernel/BKE_icons.h index e54531bdb0e..22897d2ea80 100644 --- a/source/blender/blenkernel/BKE_icons.h +++ b/source/blender/blenkernel/BKE_icons.h @@ -160,7 +160,7 @@ struct ImBuf *BKE_icon_geom_rasterize( const struct Icon_Geom *geom, const unsigned int size_x, const unsigned int size_y); -int BKE_icon_ensure_studio_light(struct StudioLight *sl); +int BKE_icon_ensure_studio_light(struct StudioLight *sl, int id_type); #define ICON_RENDER_DEFAULT_HEIGHT 32 diff --git a/source/blender/blenkernel/BKE_studiolight.h b/source/blender/blenkernel/BKE_studiolight.h index 2fcf6ab2f19..213de712abd 100644 --- a/source/blender/blenkernel/BKE_studiolight.h +++ b/source/blender/blenkernel/BKE_studiolight.h @@ -51,6 +51,10 @@ #define STUDIOLIGHT_Y_NEG 3 #define STUDIOLIGHT_Z_POS 4 #define STUDIOLIGHT_Z_NEG 5 +#define STUDIOLIGHT_ICON_ID_TYPE_RADIANCE 0 +#define STUDIOLIGHT_ICON_ID_TYPE_IRRADIANCE 1 + +struct GPUTexture; enum StudioLightFlag { STUDIOLIGHT_DIFFUSE_LIGHT_CALCULATED = (1 << 0), @@ -58,7 +62,9 @@ enum StudioLightFlag { STUDIOLIGHT_EXTERNAL_FILE = (1 << 2), STUDIOLIGHT_ORIENTATION_CAMERA = (1 << 3), STUDIOLIGHT_ORIENTATION_WORLD = (1 << 4), - STUDIOLIGHT_RADIANCE_BUFFERS_CALCULATED = (1 << 5), + STUDIOLIGHT_EQUIRECTANGULAR_IMAGE_LOADED = (1 << 5), + STUDIOLIGHT_EQUIRECTANGULAR_GPUTEXTURE = (1 << 6), + STUDIOLIGHT_RADIANCE_BUFFERS_CALCULATED = (1 << 7), } StudioLightFlag; typedef struct StudioLight { @@ -66,18 +72,21 @@ typedef struct StudioLight { int flag; char name[FILE_MAXFILE]; char path[FILE_MAX]; - int icon_id; + int irradiance_icon_id; + int radiance_icon_id; int index; float diffuse_light[6][3]; float light_direction[3]; + ImBuf *equirectangular_buffer; ImBuf *radiance_buffers[6]; + struct GPUTexture *equirectangular_gputexture; } StudioLight; void BKE_studiolight_init(void); void BKE_studiolight_free(void); -struct StudioLight *BKE_studiolight_find(const char *name); +struct StudioLight *BKE_studiolight_find(const char *name, int flag); struct StudioLight *BKE_studiolight_findindex(int index); -unsigned int *BKE_studiolight_preview(StudioLight *sl, int icon_size); +unsigned int *BKE_studiolight_preview(StudioLight *sl, int icon_size, int icon_id_type); const struct ListBase *BKE_studiolight_listbase(void); void BKE_studiolight_ensure_flag(StudioLight *sl, int flag); diff --git a/source/blender/blenkernel/intern/icons.c b/source/blender/blenkernel/intern/icons.c index bfd4e07606f..e409f8c91f0 100644 --- a/source/blender/blenkernel/intern/icons.c +++ b/source/blender/blenkernel/intern/icons.c @@ -806,10 +806,11 @@ struct Icon_Geom *BKE_icon_geom_from_file(const char *filename) /** \name Studio Light Icon * \{ */ -int BKE_icon_ensure_studio_light(struct StudioLight *sl) +int BKE_icon_ensure_studio_light(struct StudioLight *sl, int id_type) { int icon_id = get_next_free_id(); - icon_create(icon_id, ICON_DATA_STUDIOLIGHT, sl); + Icon *icon = icon_create(icon_id, ICON_DATA_STUDIOLIGHT, sl); + icon->id_type = id_type; return icon_id; } /** \} */ diff --git a/source/blender/blenkernel/intern/studiolight.c b/source/blender/blenkernel/intern/studiolight.c index d9ff6e84ac2..f139ea5fbe6 100644 --- a/source/blender/blenkernel/intern/studiolight.c +++ b/source/blender/blenkernel/intern/studiolight.c @@ -48,6 +48,8 @@ #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" +#include "GPU_texture.h" + #include "MEM_guardedalloc.h" @@ -67,6 +69,16 @@ static void studiolight_free(struct StudioLight *sl) IMB_freeImBuf(sl->radiance_buffers[index]); sl->radiance_buffers[index] = NULL; } + + if (sl->equirectangular_gputexture) { + GPU_texture_free(sl->equirectangular_gputexture); + sl->equirectangular_gputexture = NULL; + } + + if (sl->equirectangular_buffer) { + IMB_freeImBuf(sl->equirectangular_buffer); + sl->equirectangular_buffer = NULL; + } } MEM_freeN(sl); } @@ -78,7 +90,8 @@ static struct StudioLight *studiolight_create(void) sl->name[0] = 0x00; sl->flag = 0; sl->index = BLI_listbase_count(&studiolights); - sl->icon_id = BKE_icon_ensure_studio_light(sl); + sl->radiance_icon_id = BKE_icon_ensure_studio_light(sl, STUDIOLIGHT_ICON_ID_TYPE_RADIANCE); + sl->irradiance_icon_id = BKE_icon_ensure_studio_light(sl, STUDIOLIGHT_ICON_ID_TYPE_IRRADIANCE); for (int index = 0 ; index < 6 ; index ++) { sl->radiance_buffers[index] = NULL; @@ -133,13 +146,38 @@ static void studiolight_calculate_radiance_buffer( } } -static void studiolight_calculate_radiance_buffers(StudioLight *sl) +static void studiolight_load_equierectangular_image(StudioLight *sl) { if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) { ImBuf *ibuf = NULL; ibuf = IMB_loadiffname(sl->path, 0, NULL); if (ibuf) { IMB_float_from_rect(ibuf); + sl->equirectangular_buffer = ibuf; + } + } + sl->flag |= STUDIOLIGHT_EQUIRECTANGULAR_IMAGE_LOADED; +} + +static void studiolight_create_equierectangular_gputexture(StudioLight *sl) +{ + if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) { + char error[256]; + BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EQUIRECTANGULAR_IMAGE_LOADED); + ImBuf *ibuf = sl->equirectangular_buffer; + sl->equirectangular_gputexture = GPU_texture_create_2D(ibuf->x, ibuf->y, GPU_RGBA16F, ibuf->rect_float, error); + } + sl->flag |= STUDIOLIGHT_EQUIRECTANGULAR_GPUTEXTURE; +} + + + +static void studiolight_calculate_radiance_buffers(StudioLight *sl) +{ + if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) { + BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EQUIRECTANGULAR_IMAGE_LOADED); + ImBuf* ibuf = sl->equirectangular_buffer; + if (ibuf) { float *colbuf = MEM_mallocN(SQUARE(STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE) * sizeof(float[4]), __func__); const float add = 1.0f / (STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE + 1); const float start = ((1.0f / STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE) * 0.5f) - 0.5f; @@ -183,7 +221,6 @@ static void studiolight_calculate_radiance_buffers(StudioLight *sl) IMB_saveiff(sl->radiance_buffers[STUDIOLIGHT_Z_NEG], "/tmp/studiolight_radiance_top.png", IB_rectfloat); #endif MEM_freeN(colbuf); - IMB_freeImBuf(ibuf); } } sl->flag |= STUDIOLIGHT_RADIANCE_BUFFERS_CALCULATED; @@ -451,70 +488,63 @@ static int studiolight_cmp(const void *a, const void *b) return BLI_strcasecmp(sl1->name, sl2->name); } } -/* API */ -void BKE_studiolight_init(void) + +/* icons */ +static unsigned int* studiolight_radiance_preview(StudioLight *sl, int icon_size) { - StudioLight *sl; - /* go over the preset folder and add a studiolight for every image with its path */ - /* order studio lights by name */ - /* Also reserve icon space for it. */ - /* Add default studio light */ - sl = studiolight_create(); - BLI_strncpy(sl->name, "INTERNAL_01", FILE_MAXFILE); - sl->flag = STUDIOLIGHT_DIFFUSE_LIGHT_CALCULATED | STUDIOLIGHT_ORIENTATION_CAMERA; - copy_v3_fl(sl->diffuse_light[STUDIOLIGHT_X_POS], 0.0f); - copy_v3_fl(sl->diffuse_light[STUDIOLIGHT_X_NEG], 0.0f); - copy_v3_fl(sl->diffuse_light[STUDIOLIGHT_Y_POS], 1.0f); - copy_v3_fl(sl->diffuse_light[STUDIOLIGHT_Y_NEG], 0.0f); - copy_v3_fl(sl->diffuse_light[STUDIOLIGHT_Z_POS], 0.0f); - copy_v3_fl(sl->diffuse_light[STUDIOLIGHT_Z_NEG], 0.0f); - BLI_addtail(&studiolights, sl); + BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EQUIRECTANGULAR_IMAGE_LOADED); - studiolight_add_files_from_datafolder(BLENDER_SYSTEM_DATAFILES, STUDIOLIGHT_CAMERA_FOLDER, STUDIOLIGHT_ORIENTATION_CAMERA); - studiolight_add_files_from_datafolder(BLENDER_USER_DATAFILES, STUDIOLIGHT_CAMERA_FOLDER, STUDIOLIGHT_ORIENTATION_CAMERA); - studiolight_add_files_from_datafolder(BLENDER_SYSTEM_DATAFILES, STUDIOLIGHT_WORLD_FOLDER, STUDIOLIGHT_ORIENTATION_WORLD); - studiolight_add_files_from_datafolder(BLENDER_USER_DATAFILES, STUDIOLIGHT_WORLD_FOLDER, STUDIOLIGHT_ORIENTATION_WORLD); + uint *rect = MEM_mallocN(icon_size * icon_size * sizeof(uint), __func__); + int icon_center = icon_size / 2; + float sphere_radius = icon_center * 0.9; - /* sort studio lights on filename. */ - BLI_listbase_sort(&studiolights, studiolight_cmp); -} + int offset = 0; + for (int y = 0; y < icon_size; y++) { + float dy = y - icon_center; + for (int x = 0; x < icon_size; x++) { + float dx = x - icon_center; + /* calculate aliasing */ + float alias = 0; + const float alias_step = 0.333; + for (float ay = dy - 0.5; ay < dy + 0.5; ay += alias_step) { + for (float ax = dx - 0.5; ax < dx + 0.5; ax += alias_step) { + if (sqrt(ay * ay + ax * ax) < sphere_radius) { + alias += alias_step * alias_step; + } + } + } + uint pixelresult = 0x0; + uint alias_i = clamp_i(alias * 256, 0, 255); + if (alias_i != 0) { + /* calculate normal */ + uint alias_mask = alias_i << 24; + float incoming[3]; + copy_v3_fl3(incoming, 0.0, 1.0, 0.0); -void BKE_studiolight_free(void) -{ - struct StudioLight *sl; - while ((sl = BLI_pophead(&studiolights))) { - studiolight_free(sl); - } -} + float normal[3]; + normal[0] = dx / sphere_radius; + normal[2] = dy / sphere_radius; + normal[1] = -sqrt(-(normal[0] * normal[0]) - (normal[2] * normal[2]) + 1); + normalize_v3(normal); -struct StudioLight *BKE_studiolight_find(const char *name) -{ - LISTBASE_FOREACH(StudioLight *, sl, &studiolights) { - if (STREQLEN(sl->name, name, FILE_MAXFILE)) { - return sl; + float direction[3]; + reflect_v3_v3v3(direction, incoming, normal); + + float color[4]; + studiolight_calculate_radiance(sl->equirectangular_buffer, color, direction); + + pixelresult = rgb_to_cpack( + linearrgb_to_srgb(color[0]), + linearrgb_to_srgb(color[1]), + linearrgb_to_srgb(color[2])) | alias_mask; + } + rect[offset++] = pixelresult; } } - /* When not found, use the default studio light */ - return studiolights.first; + return rect; } -struct StudioLight *BKE_studiolight_findindex(int index) -{ - LISTBASE_FOREACH(StudioLight *, sl, &studiolights) { - if (sl->index == index) { - return sl; - } - } - /* When not found, use the default studio light */ - return studiolights.first; -} - -const struct ListBase *BKE_studiolight_listbase(void) -{ - return &studiolights; -} - -unsigned int *BKE_studiolight_preview(StudioLight *sl, int icon_size) +static unsigned int* studiolight_irradiance_preview(StudioLight *sl, int icon_size) { BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_DIFFUSE_LIGHT_CALCULATED); @@ -566,18 +596,101 @@ unsigned int *BKE_studiolight_preview(StudioLight *sl, int icon_size) return rect; } +/* API */ +void BKE_studiolight_init(void) +{ + StudioLight *sl; + /* go over the preset folder and add a studiolight for every image with its path */ + /* order studio lights by name */ + /* Also reserve icon space for it. */ + /* Add default studio light */ + sl = studiolight_create(); + BLI_strncpy(sl->name, "INTERNAL_01", FILE_MAXFILE); + sl->flag = STUDIOLIGHT_DIFFUSE_LIGHT_CALCULATED | STUDIOLIGHT_ORIENTATION_CAMERA; + copy_v3_fl(sl->diffuse_light[STUDIOLIGHT_X_POS], 0.0f); + copy_v3_fl(sl->diffuse_light[STUDIOLIGHT_X_NEG], 0.0f); + copy_v3_fl(sl->diffuse_light[STUDIOLIGHT_Y_POS], 1.0f); + copy_v3_fl(sl->diffuse_light[STUDIOLIGHT_Y_NEG], 0.0f); + copy_v3_fl(sl->diffuse_light[STUDIOLIGHT_Z_POS], 0.0f); + copy_v3_fl(sl->diffuse_light[STUDIOLIGHT_Z_NEG], 0.0f); + BLI_addtail(&studiolights, sl); + + studiolight_add_files_from_datafolder(BLENDER_SYSTEM_DATAFILES, STUDIOLIGHT_CAMERA_FOLDER, STUDIOLIGHT_ORIENTATION_CAMERA); + studiolight_add_files_from_datafolder(BLENDER_USER_DATAFILES, STUDIOLIGHT_CAMERA_FOLDER, STUDIOLIGHT_ORIENTATION_CAMERA); + studiolight_add_files_from_datafolder(BLENDER_SYSTEM_DATAFILES, STUDIOLIGHT_WORLD_FOLDER, STUDIOLIGHT_ORIENTATION_WORLD); + studiolight_add_files_from_datafolder(BLENDER_USER_DATAFILES, STUDIOLIGHT_WORLD_FOLDER, STUDIOLIGHT_ORIENTATION_WORLD); + + /* sort studio lights on filename. */ + BLI_listbase_sort(&studiolights, studiolight_cmp); +} + +void BKE_studiolight_free(void) +{ + struct StudioLight *sl; + while ((sl = BLI_pophead(&studiolights))) { + studiolight_free(sl); + } +} + +struct StudioLight *BKE_studiolight_find(const char *name, int flag) +{ + LISTBASE_FOREACH(StudioLight *, sl, &studiolights) { + if (STREQLEN(sl->name, name, FILE_MAXFILE)) { + if ((sl->flag & flag) == flag) { + return sl; + } else { + /* flags do not match, so use default */ + return studiolights.first; + } + } + } + /* When not found, use the default studio light */ + return studiolights.first; +} + +struct StudioLight *BKE_studiolight_findindex(int index) +{ + LISTBASE_FOREACH(StudioLight *, sl, &studiolights) { + if (sl->index == index) { + return sl; + } + } + /* When not found, use the default studio light */ + return studiolights.first; +} + +const struct ListBase *BKE_studiolight_listbase(void) +{ + return &studiolights; +} + +unsigned int *BKE_studiolight_preview(StudioLight *sl, int icon_size, int icon_id_type) +{ + if (icon_id_type == STUDIOLIGHT_ICON_ID_TYPE_IRRADIANCE) { + return studiolight_irradiance_preview(sl, icon_size); + } else { + return studiolight_radiance_preview(sl, icon_size); + } +} + void BKE_studiolight_ensure_flag(StudioLight *sl, int flag) { if ((sl->flag & flag) == flag) { return; } + if ((flag & STUDIOLIGHT_EQUIRECTANGULAR_IMAGE_LOADED)) { + studiolight_load_equierectangular_image(sl); + } if ((flag & STUDIOLIGHT_RADIANCE_BUFFERS_CALCULATED)) { studiolight_calculate_radiance_buffers(sl); } if ((flag & STUDIOLIGHT_DIFFUSE_LIGHT_CALCULATED)) { studiolight_calculate_diffuse_light(sl); } + if ((flag & STUDIOLIGHT_EQUIRECTANGULAR_GPUTEXTURE)) { + studiolight_create_equierectangular_gputexture(sl); + } if ((flag & STUDIOLIGHT_LIGHT_DIRECTION_CALCULATED)) { studiolight_calculate_light_direction(sl); } diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index daea87bed54..965faa7ba53 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -97,6 +97,7 @@ set(SRC engines/eevee/eevee_engine.c engines/eevee/eevee_lightprobes.c engines/eevee/eevee_lights.c + engines/eevee/eevee_lookdev.c engines/eevee/eevee_materials.c engines/eevee/eevee_mist.c engines/eevee/eevee_motion_blur.c diff --git a/source/blender/draw/engines/eevee/eevee_effects.c b/source/blender/draw/engines/eevee/eevee_effects.c index 9e262d4f184..211a8abd42c 100644 --- a/source/blender/draw/engines/eevee/eevee_effects.c +++ b/source/blender/draw/engines/eevee/eevee_effects.c @@ -511,6 +511,13 @@ void EEVEE_draw_effects(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) /* Save the final texture and framebuffer for final transformation or read. */ effects->final_tx = effects->source_buffer; effects->final_fb = (effects->target_buffer != fbl->main_color_fb) ? fbl->main_fb : fbl->effect_fb; + if ((effects->enabled_effects & EFFECT_TAA) && (effects->enabled_effects & (EFFECT_BLOOM | EFFECT_DOF | EFFECT_MOTION_BLUR)) == 0) { + if (!effects->swap_double_buffer) { + effects->final_fb = fbl->double_buffer_fb; + } else { + effects->final_fb = fbl->main_fb; + } + } /* If no post processes is enabled, buffers are still not swapped, do it now. */ SWAP_DOUBLE_BUFFERS(); diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c index 8448393aa97..f6776d43665 100644 --- a/source/blender/draw/engines/eevee/eevee_engine.c +++ b/source/blender/draw/engines/eevee/eevee_engine.c @@ -187,7 +187,6 @@ static void eevee_draw_background(void *vedata) /* Default framebuffer and texture */ DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); - /* Sort transparents before the loop. */ DRW_pass_sort_shgroup_z(psl->transparent_pass); @@ -310,6 +309,11 @@ static void eevee_draw_background(void *vedata) } } + /* LookDev */ + EEVEE_lookdev_draw_background(vedata); + /* END */ + + /* Tonemapping and transfer result to default framebuffer. */ GPU_framebuffer_bind(dfbl->default_fb); DRW_transform_to_display(stl->effects->final_tx); diff --git a/source/blender/draw/engines/eevee/eevee_lightprobes.c b/source/blender/draw/engines/eevee/eevee_lightprobes.c index d2faeb6ed39..c7a2951a670 100644 --- a/source/blender/draw/engines/eevee/eevee_lightprobes.c +++ b/source/blender/draw/engines/eevee/eevee_lightprobes.c @@ -71,6 +71,7 @@ static struct { struct GPUShader *probe_default_sh; + struct GPUShader *probe_default_studiolight_sh; struct GPUShader *probe_filter_glossy_sh; struct GPUShader *probe_filter_diffuse_sh; struct GPUShader *probe_filter_visibility_sh; @@ -214,6 +215,9 @@ static void lightprobe_shaders_init(void) e_data.probe_default_sh = DRW_shader_create( datatoc_background_vert_glsl, NULL, datatoc_default_world_frag_glsl, NULL); + e_data.probe_default_studiolight_sh = DRW_shader_create( + datatoc_background_vert_glsl, NULL, datatoc_default_world_frag_glsl, "#define LOOKDEV\n"); + MEM_freeN(shader_str); shader_str = BLI_string_joinN( @@ -411,7 +415,11 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat World *wo = scene->world; float *col = ts.colorBackground; - if (wo) { + + /* LookDev */ + EEVEE_lookdev_cache_init(vedata, &grp, e_data.probe_default_studiolight_sh, psl->probe_background, pinfo); + /* END */ + if (!grp && wo) { col = &wo->horr; bool wo_sh_compiled = true; @@ -445,6 +453,7 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat if (wo->update_flag != 0 || pinfo->prev_world != wo || pinfo->prev_wo_sh_compiled != wo_sh_compiled) { pinfo->update_world |= PROBE_UPDATE_ALL; + pinfo->studiolight_index = 0; pinfo->prev_wo_sh_compiled = wo_sh_compiled; pinfo->prev_world = wo; } @@ -452,6 +461,7 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat } else if (pinfo->prev_world) { pinfo->update_world |= PROBE_UPDATE_ALL; + pinfo->studiolight_index = 0; pinfo->prev_wo_sh_compiled = false; pinfo->prev_world = NULL; } @@ -1830,6 +1840,7 @@ void EEVEE_lightprobes_free(void) MEM_SAFE_FREE(e_data.format_probe_display_cube); MEM_SAFE_FREE(e_data.format_probe_display_planar); DRW_SHADER_FREE_SAFE(e_data.probe_default_sh); + DRW_SHADER_FREE_SAFE(e_data.probe_default_studiolight_sh); DRW_SHADER_FREE_SAFE(e_data.probe_filter_glossy_sh); DRW_SHADER_FREE_SAFE(e_data.probe_filter_diffuse_sh); DRW_SHADER_FREE_SAFE(e_data.probe_filter_visibility_sh); diff --git a/source/blender/draw/engines/eevee/eevee_lookdev.c b/source/blender/draw/engines/eevee/eevee_lookdev.c new file mode 100644 index 00000000000..4abe60242d6 --- /dev/null +++ b/source/blender/draw/engines/eevee/eevee_lookdev.c @@ -0,0 +1,130 @@ +/* + * 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 eevee_lookdev.c + * \ingroup draw_engine + */ +#include "DRW_render.h" + +#include "BKE_camera.h" +#include "BKE_studiolight.h" + +#include "DNA_screen_types.h" + +#include "eevee_private.h" + +void EEVEE_lookdev_cache_init(EEVEE_Data *vedata, DRWShadingGroup **grp, GPUShader *shader, DRWPass *pass, EEVEE_LightProbesInfo *pinfo) +{ + EEVEE_StorageList *stl = vedata->stl; + const DRWContextState *draw_ctx = DRW_context_state_get(); + View3D *v3d = draw_ctx->v3d; + if (v3d && v3d->drawtype == OB_MATERIAL) + { + StudioLight *sl = BKE_studiolight_find(v3d->shading.studio_light, STUDIOLIGHT_ORIENTATION_WORLD); + if ((sl->flag & STUDIOLIGHT_ORIENTATION_WORLD)) { + struct Gwn_Batch *geom = DRW_cache_fullscreen_quad_get(); + + BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EQUIRECTANGULAR_GPUTEXTURE); + *grp = DRW_shgroup_create(shader, pass); + GPUTexture *tex = sl->equirectangular_gputexture; + DRW_shgroup_uniform_texture(*grp, "image", tex); + + axis_angle_to_mat3_single(stl->studiolight_matrix, 'Z', v3d->shading.studiolight_rot_z); + DRW_shgroup_uniform_mat3(*grp, "StudioLightMatrix", stl->studiolight_matrix); + + DRW_shgroup_uniform_float(*grp, "backgroundAlpha", &stl->g_data->background_alpha, 1); + DRW_shgroup_call_add(*grp, geom, NULL); + + /* Do we need to recalc the lightprobes? */ + if (pinfo && (pinfo->studiolight_index != sl->index || pinfo->studiolight_rot_z != v3d->shading.studiolight_rot_z)) { + pinfo->update_world |= PROBE_UPDATE_ALL; + pinfo->studiolight_index = sl->index; + pinfo->studiolight_rot_z = v3d->shading.studiolight_rot_z; + pinfo->prev_wo_sh_compiled = false; + pinfo->prev_world = NULL; + } + } + } +} + +void EEVEE_lookdev_draw_background(EEVEE_Data *vedata) +{ + EEVEE_PassList *psl = vedata->psl; + EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl; + EEVEE_EffectsInfo *effects = stl->effects; + EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure(); + + const DRWContextState *draw_ctx = DRW_context_state_get(); + + if (psl->lookdev_pass && draw_ctx->v3d) { + DRW_stats_group_start("Look Dev"); + CameraParams params; + BKE_camera_params_init(¶ms); + View3D *v3d = draw_ctx->v3d; + RegionView3D *rv3d = draw_ctx->rv3d; + ARegion *ar = draw_ctx->ar; + + BKE_camera_params_from_view3d(¶ms, draw_ctx->depsgraph, v3d, rv3d); + params.is_ortho = true; + params.ortho_scale = 4.0; + params.zoom = CAMERA_PARAM_ZOOM_INIT_PERSP; + BKE_camera_params_compute_viewplane(¶ms, ar->winx, ar->winy, 1.0f, 1.0f); + BKE_camera_params_compute_matrix(¶ms); + + const float *viewport_size = DRW_viewport_size_get(); + int viewport_inset_x = viewport_size[0]/4; + int viewport_inset_y = viewport_size[1]/4; + + EEVEE_CommonUniformBuffer *common = &sldata->common_data; + common->la_num_light = 0; + common->prb_num_planar = 0; + common->prb_num_render_cube = 1; + common->prb_num_render_grid = 1; + common->ao_dist = 0.0f; + common->ao_factor = 0.0f; + common->ao_settings = 0.0f; + DRW_uniformbuffer_update(sldata->common_ubo, common); + + /* override matrices */ + float winmat[4][4]; + float winmat_inv[4][4]; + copy_m4_m4(winmat, params.winmat); + invert_m4_m4(winmat_inv, winmat); + DRW_viewport_matrix_override_set(winmat, DRW_MAT_WIN); + DRW_viewport_matrix_override_set(winmat_inv, DRW_MAT_WININV); + float viewmat[4][4]; + DRW_viewport_matrix_get(viewmat, DRW_MAT_VIEW); + float persmat[4][4]; + float persmat_inv[4][4]; + mul_m4_m4m4(persmat, winmat, viewmat); + invert_m4_m4(persmat_inv, persmat); + DRW_viewport_matrix_override_set(persmat, DRW_MAT_PERS); + DRW_viewport_matrix_override_set(persmat_inv, DRW_MAT_PERSINV); + + GPUFrameBuffer *fb = effects->final_fb; + GPU_framebuffer_bind(fb); + GPU_framebuffer_viewport_set(fb, viewport_size[0]-viewport_inset_x, 0, viewport_inset_x, viewport_inset_y); + DRW_draw_pass(psl->lookdev_pass); + + DRW_viewport_matrix_override_unset_all(); + DRW_stats_group_end(); + } +} \ No newline at end of file diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index e3c91c2828d..34097a821a4 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -34,6 +34,7 @@ #include "BKE_particle.h" #include "BKE_paint.h" #include "BKE_pbvh.h" +#include "BKE_studiolight.h" #include "DNA_world_types.h" #include "DNA_modifier_types.h" @@ -54,6 +55,7 @@ static struct { struct GPUShader *default_prepass_clip_sh; struct GPUShader *default_lit[VAR_MAT_MAX]; struct GPUShader *default_background; + struct GPUShader *default_studiolight_background; struct GPUShader *update_noise_sh; /* 64*64 array texture containing all LUTs and other utilitarian arrays. @@ -320,6 +322,9 @@ static char *eevee_get_defines(int options) if (((options & VAR_MAT_VOLUME) != 0) && ((options & VAR_MAT_BLEND) != 0)) { BLI_dynstr_appendf(ds, "#define USE_ALPHA_BLEND_VOLUMETRICS\n"); } + if ((options & VAR_MAT_LOOKDEV) != 0) { + BLI_dynstr_appendf(ds, "#define LOOKDEV\n"); + } str = BLI_dynstr_get_cstring(ds); BLI_dynstr_free(ds); @@ -578,6 +583,10 @@ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata, EEVEE_StorageList *stl, E datatoc_background_vert_glsl, NULL, datatoc_default_world_frag_glsl, NULL); + e_data.default_studiolight_background = DRW_shader_create( + datatoc_background_vert_glsl, NULL, datatoc_default_world_frag_glsl, + "#define LOOKDEV\n"); + e_data.default_prepass_sh = DRW_shader_create( datatoc_prepass_vert_glsl, NULL, datatoc_prepass_frag_glsl, NULL); @@ -861,6 +870,35 @@ static struct DRWShadingGroup *EEVEE_default_shading_group_get( return DRW_shgroup_create(e_data.default_lit[options], vedata->psl->default_pass[options]); } +/** + * Create a default shading group inside the lookdev pass without standard uniforms. + **/ +static struct DRWShadingGroup *EEVEE_lookdev_shading_group_get( + EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, + bool use_ssr, int shadow_method) +{ + static int ssr_id; + ssr_id = (use_ssr) ? 1 : -1; + int options = VAR_MAT_MESH | VAR_MAT_LOOKDEV; + + options |= eevee_material_shadow_option(shadow_method); + + if (e_data.default_lit[options] == NULL) { + create_default_shader(options); + } + + if (vedata->psl->lookdev_pass == NULL) { + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS | DRW_STATE_CULL_BACK; + vedata->psl->lookdev_pass = DRW_pass_create("LookDev Pass", state); + + DRWShadingGroup *shgrp = DRW_shgroup_create(e_data.default_lit[options], vedata->psl->lookdev_pass); + /* XXX / WATCH: This creates non persistent binds for the ubos and textures. + * But it's currently OK because the following shgroups does not add any bind. */ + add_standard_uniforms(shgrp, sldata, vedata, &ssr_id, NULL, false, false); + } + + return DRW_shgroup_create(e_data.default_lit[options], vedata->psl->lookdev_pass); +} void EEVEE_materials_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl; @@ -884,7 +922,11 @@ void EEVEE_materials_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) float *col = ts.colorBackground; - if (wo) { + /* LookDev */ + EEVEE_lookdev_cache_init(vedata, &grp, e_data.default_studiolight_background, psl->background_pass, NULL); + /* END */ + + if (!grp && wo) { col = &wo->horr; if (wo->use_nodes && wo->nodetree) { @@ -1588,6 +1630,43 @@ void EEVEE_materials_cache_finish(EEVEE_Data *vedata) { EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl; + /* Look-Dev */ + const DRWContextState *draw_ctx = DRW_context_state_get(); + const View3D *v3d = draw_ctx->v3d; + if (v3d && v3d->drawtype == OB_MATERIAL) { + EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure(); + EEVEE_LampsInfo *linfo = sldata->lamps; + struct Gwn_Batch *sphere = DRW_cache_sphere_get(); + static float mat1[4][4]; + static float color[3] = {1.0, 1.0, 1.0}; + static float metallic_on = 1.0f; + static float metallic_off = 0.00f; + static float specular = 1.0f; + static float roughness = 0.05f; + + float view_mat[4][4]; + DRW_viewport_matrix_get(view_mat, DRW_MAT_VIEWINV); + + DRWShadingGroup *shgrp = EEVEE_lookdev_shading_group_get(sldata, vedata, false, linfo->shadow_method); + DRW_shgroup_uniform_vec3(shgrp, "basecol", color, 1); + DRW_shgroup_uniform_float(shgrp, "metallic", &metallic_on, 1); + DRW_shgroup_uniform_float(shgrp, "specular", &specular, 1); + DRW_shgroup_uniform_float(shgrp, "roughness", &roughness, 1); + unit_m4(mat1); + mul_m4_m4m4(mat1, mat1, view_mat); + translate_m4(mat1, -1.5f, 0.0f, -5.0f); + DRW_shgroup_call_add(shgrp, sphere, mat1); + + shgrp = EEVEE_lookdev_shading_group_get(sldata, vedata, false, linfo->shadow_method); + DRW_shgroup_uniform_vec3(shgrp, "basecol", color, 1); + DRW_shgroup_uniform_float(shgrp, "metallic", &metallic_off, 1); + DRW_shgroup_uniform_float(shgrp, "specular", &specular, 1); + DRW_shgroup_uniform_float(shgrp, "roughness", &roughness, 1); + translate_m4(mat1, 3.0f, 0.0f, 0.0f); + DRW_shgroup_call_add(shgrp, sphere, mat1); + } + /* END */ + BLI_ghash_free(stl->g_data->material_hash, NULL, MEM_freeN); BLI_ghash_free(stl->g_data->hair_material_hash, NULL, NULL); } @@ -1603,6 +1682,7 @@ void EEVEE_materials_free(void) DRW_SHADER_FREE_SAFE(e_data.default_prepass_sh); DRW_SHADER_FREE_SAFE(e_data.default_prepass_clip_sh); DRW_SHADER_FREE_SAFE(e_data.default_background); + DRW_SHADER_FREE_SAFE(e_data.default_studiolight_background); DRW_SHADER_FREE_SAFE(e_data.update_noise_sh); DRW_TEXTURE_FREE_SAFE(e_data.util_tex); DRW_TEXTURE_FREE_SAFE(e_data.noise_tex); diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index 81a74f4da8d..1a63cf53814 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -101,28 +101,29 @@ enum { /* Material shader variations */ enum { - VAR_MAT_MESH = (1 << 0), - VAR_MAT_PROBE = (1 << 1), - VAR_MAT_HAIR = (1 << 2), - VAR_MAT_FLAT = (1 << 3), - VAR_MAT_BLEND = (1 << 4), - VAR_MAT_VSM = (1 << 5), - VAR_MAT_ESM = (1 << 6), - VAR_MAT_VOLUME = (1 << 7), + VAR_MAT_MESH = (1 << 0), + VAR_MAT_PROBE = (1 << 1), + VAR_MAT_HAIR = (1 << 2), + VAR_MAT_FLAT = (1 << 3), + VAR_MAT_BLEND = (1 << 4), + VAR_MAT_VSM = (1 << 5), + VAR_MAT_ESM = (1 << 6), + VAR_MAT_VOLUME = (1 << 7), + VAR_MAT_LOOKDEV = (1 << 8), /* Max number of variation */ /* IMPORTANT : Leave it last and set * it's value accordingly. */ - VAR_MAT_MAX = (1 << 8), + VAR_MAT_MAX = (1 << 9), /* These are options that are not counted in VAR_MAT_MAX * because they are not cumulative with the others above. */ - VAR_MAT_CLIP = (1 << 9), - VAR_MAT_HASH = (1 << 10), - VAR_MAT_MULT = (1 << 11), - VAR_MAT_SHADOW = (1 << 12), - VAR_MAT_REFRACT = (1 << 13), - VAR_MAT_SSS = (1 << 14), - VAR_MAT_TRANSLUC = (1 << 15), - VAR_MAT_SSSALBED = (1 << 16), + VAR_MAT_CLIP = (1 << 10), + VAR_MAT_HASH = (1 << 11), + VAR_MAT_MULT = (1 << 12), + VAR_MAT_SHADOW = (1 << 13), + VAR_MAT_REFRACT = (1 << 14), + VAR_MAT_SSS = (1 << 15), + VAR_MAT_TRANSLUC = (1 << 16), + VAR_MAT_SSSALBED = (1 << 17), }; typedef struct EEVEE_BoundSphere { @@ -205,6 +206,7 @@ typedef struct EEVEE_PassList { struct DRWPass *transparent_pass; struct DRWPass *background_pass; struct DRWPass *update_noise_pass; + struct DRWPass *lookdev_pass; } EEVEE_PassList; typedef struct EEVEE_FramebufferList { @@ -277,6 +279,8 @@ typedef struct EEVEE_StorageList { struct EEVEE_EffectsInfo *effects; struct EEVEE_PrivateData *g_data; + /* XXX: move to better place */ + float studiolight_matrix[3][3]; } EEVEE_StorageList; /* ************ LIGHT UBO ************* */ @@ -452,6 +456,8 @@ typedef struct EEVEE_LightProbesInfo { float visibility_blur; float intensity_fac; int shres; + int studiolight_index; + float studiolight_rot_z; /* List of probes in the scene. */ /* XXX This is fragile, can get out of sync quickly. */ struct Object *probes_cube_ref[MAX_PROBE]; @@ -929,6 +935,10 @@ void EEVEE_render_cache(void *vedata, struct Object *ob, struct RenderEngine *en void EEVEE_render_draw(EEVEE_Data *vedata, struct RenderEngine *engine, struct RenderLayer *render_layer, const struct rcti *rect); void EEVEE_render_update_passes(struct RenderEngine *engine, struct Scene *scene, struct ViewLayer *view_layer); +/** eevee_lookdev.c */ +void EEVEE_lookdev_cache_init(EEVEE_Data *vedata, DRWShadingGroup **grp, GPUShader *shader, DRWPass *pass, EEVEE_LightProbesInfo *pinfo); +void EEVEE_lookdev_draw_background(EEVEE_Data *vedata); + /* Shadow Matrix */ static const float texcomat[4][4] = { /* From NDC to TexCo */ {0.5f, 0.0f, 0.0f, 0.0f}, diff --git a/source/blender/draw/engines/eevee/shaders/default_frag.glsl b/source/blender/draw/engines/eevee/shaders/default_frag.glsl index 6d941ae6ec3..fd1a10de548 100644 --- a/source/blender/draw/engines/eevee/shaders/default_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/default_frag.glsl @@ -15,5 +15,9 @@ Closure nodetree_exec(void) Closure result = Closure(out_spec + out_diff * albedo, 1.0, vec4(ssr_spec, roughness), normal_encode(normalize(viewNormal), viewCameraVec), 0); +#ifdef LOOKDEV + gl_FragDepth = 0.0; +#endif + return result; } diff --git a/source/blender/draw/engines/eevee/shaders/default_world_frag.glsl b/source/blender/draw/engines/eevee/shaders/default_world_frag.glsl index 90af87756f0..472d9c577b4 100644 --- a/source/blender/draw/engines/eevee/shaders/default_world_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/default_world_frag.glsl @@ -1,9 +1,57 @@ +#define M_PI 3.14159265358979323846 uniform float backgroundAlpha; +uniform mat4 ProjectionMatrix; +uniform mat4 ProjectionMatrixInverse; +uniform mat4 ViewMatrixInverse; +#ifdef LOOKDEV +uniform mat3 StudioLightMatrix; +uniform sampler2D image; +in vec3 viewPosition; +#else uniform vec3 color; +#endif out vec4 FragColor; -void main() { - FragColor = vec4(color, backgroundAlpha); +void background_transform_to_world(vec3 viewvec, out vec3 worldvec) +{ + vec4 v = (ProjectionMatrix[3][3] == 0.0) ? vec4(viewvec, 1.0) : vec4(0.0, 0.0, 1.0, 1.0); + vec4 co_homogenous = (ProjectionMatrixInverse * v); + + vec4 co = vec4(co_homogenous.xyz / co_homogenous.w, 0.0); + worldvec = (ViewMatrixInverse * co).xyz; +} + +float hypot(float x, float y) +{ + return sqrt(x * x + y * y); +} + +void node_tex_environment_equirectangular(vec3 co, sampler2D ima, out vec4 color) +{ + vec3 nco = normalize(co); + float u = -atan(nco.y, nco.x) / (2.0 * M_PI) + 0.5; + float v = atan(nco.z, hypot(nco.x, nco.y)) / M_PI + 0.5; + + /* Fix pole bleeding */ + float half_width = 0.5 / float(textureSize(ima, 0).x); + v = clamp(v, half_width, 1.0 - half_width); + + /* Fix u = 0 seam */ + /* This is caused by texture filtering, since uv don't have smooth derivatives + * at u = 0 or 2PI, hardware filtering is using the smallest mipmap for certain + * texels. So we force the highest mipmap and don't do anisotropic filtering. */ + color = textureLod(ima, vec2(u, v), 0.0); +} + +void main() { +#ifdef LOOKDEV + vec3 worldvec; + vec4 color; + background_transform_to_world(viewPosition, worldvec); + node_tex_environment_equirectangular(StudioLightMatrix * worldvec, image, color); +#endif + + FragColor = vec4(clamp(color.rgb, vec3(0.0), vec3(1e10)), backgroundAlpha); } diff --git a/source/blender/draw/engines/workbench/workbench_data.c b/source/blender/draw/engines/workbench/workbench_data.c index 9f8023b38aa..bbd8c57a5b9 100644 --- a/source/blender/draw/engines/workbench/workbench_data.c +++ b/source/blender/draw/engines/workbench/workbench_data.c @@ -11,7 +11,7 @@ void workbench_private_data_init(WORKBENCH_PrivateData *wpd) if (v3d) { wpd->shading = v3d->shading; wpd->drawtype = v3d->drawtype; - wpd->studio_light = BKE_studiolight_find(wpd->shading.studio_light); + wpd->studio_light = BKE_studiolight_find(wpd->shading.studio_light, 0); } else { memset(&wpd->shading, 0, sizeof(wpd->shading)); diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c index 51c3cff721a..bacea087677 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -783,7 +783,7 @@ static DrawInfo *icon_create_drawinfo(Icon *icon) IconImage *img = MEM_mallocN(sizeof(IconImage), __func__); img->w = STUDIOLIGHT_SIZE; img->h = STUDIOLIGHT_SIZE; - img->rect = BKE_studiolight_preview(sl, STUDIOLIGHT_SIZE); + img->rect = BKE_studiolight_preview(sl, STUDIOLIGHT_SIZE, icon->id_type); di->data.buffer.image = img; } else { diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index a925f5ba2f1..65edc619ced 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -655,12 +655,7 @@ static int rna_3DViewShading_type_get(PointerRNA *ptr) RenderEngineType *type = RE_engines_find(scene->r.engine); View3D *v3d = (View3D *)ptr->data; - if (BKE_scene_uses_blender_eevee(scene)) { - if (v3d->drawtype == OB_MATERIAL) { - return OB_RENDER; - } - } - else if (v3d->drawtype == OB_RENDER) { + if (!BKE_scene_uses_blender_eevee(scene) && v3d->drawtype == OB_RENDER) { if (!(type && type->render_to_view)) { return OB_MATERIAL; } @@ -693,6 +688,7 @@ static const EnumPropertyItem *rna_3DViewShading_type_itemf( RNA_enum_items_add_value(&item, &totitem, rna_enum_shading_type_items, OB_TEXTURE); if (BKE_scene_uses_blender_eevee(scene)) { + RNA_enum_items_add_value(&item, &totitem, rna_enum_shading_type_items, OB_MATERIAL); RNA_enum_items_add_value(&item, &totitem, rna_enum_shading_type_items, OB_RENDER); } else { @@ -711,7 +707,7 @@ static const EnumPropertyItem *rna_3DViewShading_type_itemf( static int rna_View3DShading_studio_light_orientation_get(PointerRNA *ptr) { View3D *v3d = (View3D *)ptr->data; - StudioLight *sl = BKE_studiolight_find(v3d->shading.studio_light); + StudioLight *sl = BKE_studiolight_find(v3d->shading.studio_light, 0); return sl->flag & (STUDIOLIGHT_ORIENTATION_WORLD | STUDIOLIGHT_ORIENTATION_CAMERA); } static void rna_View3DShading_studio_light_orientation_set(PointerRNA *UNUSED(ptr), int UNUSED(value)) @@ -721,7 +717,9 @@ static void rna_View3DShading_studio_light_orientation_set(PointerRNA *UNUSED(pt static int rna_View3DShading_studio_light_get(PointerRNA *ptr) { View3D *v3d = (View3D *)ptr->data; - StudioLight *sl = BKE_studiolight_find(v3d->shading.studio_light); + const int flag = v3d->drawtype == OB_MATERIAL? STUDIOLIGHT_ORIENTATION_WORLD: 0; + StudioLight *sl = BKE_studiolight_find(v3d->shading.studio_light, flag); + BLI_strncpy(v3d->shading.studio_light, sl->name, FILE_MAXFILE); return sl->index; } @@ -733,19 +731,40 @@ static void rna_View3DShading_studio_light_set(PointerRNA *ptr, int value) } static const EnumPropertyItem *rna_View3DShading_studio_light_itemf( - bContext *UNUSED(C), PointerRNA *UNUSED(ptr), + bContext *UNUSED(C), PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free) { + View3D *v3d = (View3D *)ptr->data; EnumPropertyItem *item = NULL; EnumPropertyItem *lastitem; int totitem = 0; + bool show_studiolight; LISTBASE_FOREACH(StudioLight *, sl, BKE_studiolight_listbase()) { - if (totitem < NUM_STUDIOLIGHT_ITEMS) { - RNA_enum_items_add_value(&item, &totitem, rna_enum_studio_light_items, totitem); + show_studiolight = false; + int icon_id = sl->irradiance_icon_id; + + if ((sl->flag & STUDIOLIGHT_EXTERNAL_FILE) == 0) { + /* always show internal lights */ + show_studiolight = true; + } else { + switch (v3d->drawtype) { + case OB_SOLID: + case OB_TEXTURE: + show_studiolight = true; + break; + case OB_MATERIAL: + show_studiolight = (sl->flag & STUDIOLIGHT_ORIENTATION_WORLD) > 0; + icon_id = sl->radiance_icon_id; + break; + } + } + + if (show_studiolight && totitem < NUM_STUDIOLIGHT_ITEMS) { + RNA_enum_items_add_value(&item, &totitem, rna_enum_studio_light_items, sl->index); lastitem = &item[totitem - 1]; lastitem->value = sl->index; - lastitem->icon = sl->icon_id; + lastitem->icon = icon_id; lastitem->name = sl->name; } }