diff options
-rw-r--r-- | release/scripts/startup/bl_operators/wm.py | 54 | ||||
-rw-r--r-- | release/scripts/startup/bl_ui/space_userpref.py | 16 | ||||
-rw-r--r-- | release/scripts/startup/bl_ui/space_view3d.py | 6 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_studiolight.h | 11 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/studiolight.c | 274 | ||||
-rw-r--r-- | source/blender/blenloader/intern/versioning_280.c | 13 | ||||
-rw-r--r-- | source/blender/draw/engines/eevee/eevee_lookdev.c | 2 | ||||
-rw-r--r-- | source/blender/draw/engines/workbench/workbench_data.c | 49 | ||||
-rw-r--r-- | source/blender/draw/engines/workbench/workbench_private.h | 2 | ||||
-rw-r--r-- | source/blender/draw/engines/workbench/workbench_studiolight.c | 51 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_userdef_types.h | 3 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_view3d_types.h | 1 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_space.c | 18 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_userdef.c | 27 |
14 files changed, 430 insertions, 97 deletions
diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py index 4206adcfb91..65ac0cb745b 100644 --- a/release/scripts/startup/bl_operators/wm.py +++ b/release/scripts/startup/bl_operators/wm.py @@ -2462,7 +2462,7 @@ class WM_OT_studiolight_install(Operator): for filepath in filepaths: shutil.copy(str(filepath), str(path_studiolights)) - userpref.studio_lights.new(str(path_studiolights.joinpath(filepath.name)), self.type) + userpref.studio_lights.load(str(path_studiolights.joinpath(filepath.name)), self.type) # print message msg = ( @@ -2479,6 +2479,57 @@ class WM_OT_studiolight_install(Operator): return {'RUNNING_MODAL'} +class WM_OT_studiolight_new(Operator): + bl_idname = 'wm.studiolight_new' + bl_label = "Create Studio Light from default light setup" + + filename: StringProperty( + name="Filename", + default="StudioLight", + ) + + def execute(self, context): + import pathlib + userpref = context.user_preferences + + path_studiolights = bpy.utils.user_resource('DATAFILES') + + if not path_studiolights: + self.report({'ERROR'}, "Failed to get Studio Light path") + return {'CANCELLED'} + + path_studiolights = pathlib.Path(path_studiolights, "studiolights", "studio") + if not path_studiolights.exists(): + try: + path_studiolights.mkdir(parents=True, exist_ok=True) + except: + traceback.print_exc() + + finalpath = str(path_studiolights.joinpath(self.filename)); + if pathlib.Path(finalpath + ".sl").is_file(): + self.report({'ERROR'}, "File already exists") + return {'CANCELLED'} + + userpref.studio_lights.new(path=finalpath) + + # print message + msg = ( + tip_("StudioLight Installed %r into %r") % + (self.filename, str(path_studiolights)) + ) + print(msg) + self.report({'INFO'}, msg) + return {'FINISHED'} + + def draw(self, context): + layout = self.layout + layout.prop(self, "filename") + + def invoke(self, context, event): + wm = context.window_manager + return wm.invoke_props_dialog(self, width=600) + + class WM_OT_studiolight_uninstall(Operator): bl_idname = 'wm.studiolight_uninstall' bl_label = "Uninstall Studio Light" @@ -2765,6 +2816,7 @@ classes = ( WM_OT_owner_enable, WM_OT_url_open, WM_OT_studiolight_install, + WM_OT_studiolight_new, WM_OT_studiolight_uninstall, WM_OT_studiolight_userpref_show, WM_OT_tool_set_by_name, diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index 72b07d55f70..261eccc7c55 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -47,7 +47,9 @@ class USERPREF_HT_header(Header): elif userpref.active_section == 'LIGHTS': layout.operator('wm.studiolight_install', text="Add MatCap").type = 'MATCAP' layout.operator('wm.studiolight_install', text="Add LookDev HDRI").type = 'WORLD' - layout.operator('wm.studiolight_install', text="Add Studio Light").type = 'STUDIO' + op = layout.operator('wm.studiolight_install', text="Add Studio Light") + op.type = 'STUDIO' + op.filter_glob = ".sl" elif userpref.active_section == 'THEMES': layout.operator("wm.theme_install", icon='FILEBROWSER') layout.operator("ui.reset_default_theme", icon='LOOP_BACK') @@ -1498,6 +1500,10 @@ class StudioLightPanelMixin(): layout = self.layout userpref = context.user_preferences lights = self._get_lights(userpref) + + self.draw_light_list(layout, lights) + + def draw_light_list(self, layout, lights): if lights: flow = layout.column_flow(columns=4) for studio_light in lights: @@ -1569,8 +1575,16 @@ class USERPREF_PT_studiolight_lights(Panel, StudioLightPanelMixin): layout.separator() + layout.prop(system, "edit_solid_light") layout.prop(system, "light_ambient") + layout.operator('wm.studiolight_new', text="Save as Studio light") + + lights = self._get_lights(userpref) + + self.draw_light_list(layout, lights) + + classes = ( USERPREF_HT_header, USERPREF_PT_navigation, diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index 0ba3b2217f2..bc38214f101 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -4190,9 +4190,9 @@ class VIEW3D_PT_shading_lighting(Panel): if shading.light == 'STUDIO': # Not implemented right now - # sub.template_icon_view(shading, "studio_light", scale=3) + sub.template_icon_view(shading, "studio_light", scale=3) - # if shading.selected_studio_light.orientation == 'WORLD': + # if shading.selected_studio_light.type == 'WORLD': # col.prop(shading, "studiolight_rotate_z", text="Rotation") col = split.column() @@ -4221,7 +4221,7 @@ class VIEW3D_PT_shading_lighting(Panel): col = split.column() col.operator('wm.studiolight_userpref_show', emboss=False, text="", icon='PREFERENCES') - if shading.selected_studio_light.orientation == 'WORLD': + if shading.selected_studio_light.type == 'WORLD': split = layout.split(factor=0.9) col = split.column() col.prop(shading, "studiolight_rotate_z", text="Rotation") diff --git a/source/blender/blenkernel/BKE_studiolight.h b/source/blender/blenkernel/BKE_studiolight.h index 6616af355ac..25931e2bbf5 100644 --- a/source/blender/blenkernel/BKE_studiolight.h +++ b/source/blender/blenkernel/BKE_studiolight.h @@ -39,6 +39,7 @@ #include "BLI_sys_types.h" #include "DNA_space_types.h" +#include "DNA_userdef_types.h" #include "IMB_imbuf_types.h" @@ -59,6 +60,8 @@ #define STUDIOLIGHT_ICON_ID_TYPE_MATCAP (1 << 2) #define STUDIOLIGHT_ICON_ID_TYPE_MATCAP_FLIPPED (1 << 3) +#define STUDIOLIGHT_MAX_LIGHT 4 + #define STUDIOLIGHT_ICON_SIZE 96 /* Only 1 - 5 is supported */ @@ -97,7 +100,7 @@ enum StudioLightFlag { #define STUDIOLIGHT_FLAG_ALL (STUDIOLIGHT_INTERNAL | STUDIOLIGHT_EXTERNAL_FILE) #define STUDIOLIGHT_FLAG_ORIENTATIONS (STUDIOLIGHT_TYPE_STUDIO | STUDIOLIGHT_TYPE_WORLD | STUDIOLIGHT_TYPE_MATCAP) #define STUDIOLIGHT_ORIENTATIONS_MATERIAL_MODE (STUDIOLIGHT_TYPE_WORLD) -#define STUDIOLIGHT_ORIENTATIONS_SOLID (STUDIOLIGHT_INTERNAL | STUDIOLIGHT_TYPE_STUDIO | STUDIOLIGHT_TYPE_WORLD) +#define STUDIOLIGHT_ORIENTATIONS_SOLID (STUDIOLIGHT_INTERNAL | STUDIOLIGHT_TYPE_STUDIO) typedef void StudioLightFreeFunction(struct StudioLight *, void *data); @@ -121,6 +124,8 @@ typedef struct StudioLight { ImBuf *radiance_cubemap_buffers[6]; struct GPUTexture *equirect_radiance_gputexture; struct GPUTexture *equirect_irradiance_gputexture; + SolidLight light[STUDIOLIGHT_MAX_LIGHT]; + float light_ambient[3]; /* * Free function to clean up the running icons previews (wmJob) the usage is in @@ -140,7 +145,9 @@ void BKE_studiolight_preview(uint *icon_buffer, StudioLight *sl, int icon_id_typ struct ListBase *BKE_studiolight_listbase(void); void BKE_studiolight_ensure_flag(StudioLight *sl, int flag); void BKE_studiolight_refresh(void); -StudioLight *BKE_studiolight_new(const char *path, int orientation); +StudioLight *BKE_studiolight_load(const char *path, int orientation); +StudioLight *BKE_studiolight_create(const char *path, const SolidLight light[4], const float light_ambient[3]); +StudioLight *BKE_studiolight_studio_edit_get(void); void BKE_studiolight_remove(StudioLight *sl); void BKE_studiolight_set_free_function(StudioLight *sl, StudioLightFreeFunction *free_function, void *data); void BKE_studiolight_unset_icon_id(StudioLight *sl, int icon_id); diff --git a/source/blender/blenkernel/intern/studiolight.c b/source/blender/blenkernel/intern/studiolight.c index 937c24c47e6..10d9dcfbfec 100644 --- a/source/blender/blenkernel/intern/studiolight.c +++ b/source/blender/blenkernel/intern/studiolight.c @@ -35,9 +35,11 @@ #include "BKE_appdir.h" #include "BKE_icons.h" +#include "BLI_dynstr.h" #include "BLI_fileops.h" #include "BLI_fileops_types.h" #include "BLI_listbase.h" +#include "BLI_linklist.h" #include "BLI_math.h" #include "BLI_math_color.h" #include "BLI_path_util.h" @@ -82,7 +84,7 @@ static int last_studiolight_id = 0; */ #define STUDIOLIGHT_LOAD_CACHED_FILES -static const char *STUDIOLIGHT_LIGHTS_FOLDER = "studiolights/light/"; +static const char *STUDIOLIGHT_LIGHTS_FOLDER = "studiolights/studio/"; static const char *STUDIOLIGHT_WORLD_FOLDER = "studiolights/world/"; static const char *STUDIOLIGHT_MATCAP_FOLDER = "studiolights/matcap/"; @@ -168,13 +170,15 @@ static struct StudioLight *studiolight_create(int flag) sl->free_function = NULL; sl->flag = flag; sl->index = ++last_studiolight_id; - if (flag & STUDIOLIGHT_TYPE_MATCAP) { + if (flag & STUDIOLIGHT_TYPE_STUDIO) { + sl->icon_id_irradiance = BKE_icon_ensure_studio_light(sl, STUDIOLIGHT_ICON_ID_TYPE_IRRADIANCE); + } + else if (flag & STUDIOLIGHT_TYPE_MATCAP) { sl->icon_id_matcap = BKE_icon_ensure_studio_light(sl, STUDIOLIGHT_ICON_ID_TYPE_MATCAP); sl->icon_id_matcap_flipped = BKE_icon_ensure_studio_light(sl, STUDIOLIGHT_ICON_ID_TYPE_MATCAP_FLIPPED); } else { sl->icon_id_radiance = BKE_icon_ensure_studio_light(sl, STUDIOLIGHT_ICON_ID_TYPE_RADIANCE); - sl->icon_id_irradiance = BKE_icon_ensure_studio_light(sl, STUDIOLIGHT_ICON_ID_TYPE_IRRADIANCE); } for (int index = 0; index < 6; index++) { @@ -184,6 +188,99 @@ static struct StudioLight *studiolight_create(int flag) return sl; } +#define STUDIOLIGHT_FILE_VERSION 1 + +#define READ_VAL(type, parser, id, val, lines) do { \ + for (LinkNode *line = lines; line; line = line->next) { \ + char *val_str, *str = line->link; \ + if ((val_str = strstr(str, id " "))) { \ + val_str += sizeof(id); /* Skip id + spacer. */ \ + val = parser(val_str); \ + } \ + } \ +} while (0) + +#define READ_FVAL(id, val, lines) READ_VAL(float, atof, id, val, lines) +#define READ_IVAL(id, val, lines) READ_VAL(int, atoi, id, val, lines) + +#define READ_VEC3(id, val, lines) do { \ + READ_FVAL(id ".x", val[0], lines); \ + READ_FVAL(id ".y", val[1], lines); \ + READ_FVAL(id ".z", val[2], lines); \ +} while (0) + +#define READ_SOLIDLIGHT(sl, i, lines) do { \ + READ_IVAL("light[" STRINGIFY(i) "].flag", sl[i].flag, lines); \ + READ_FVAL("light[" STRINGIFY(i) "].smooth", sl[i].smooth, lines); \ + READ_VEC3("light[" STRINGIFY(i) "].col", sl[i].col, lines); \ + READ_VEC3("light[" STRINGIFY(i) "].spec", sl[i].spec, lines); \ + READ_VEC3("light[" STRINGIFY(i) "].vec", sl[i].vec, lines); \ +} while (0) + +static void studiolight_load_solid_light(StudioLight *sl) +{ + LinkNode *lines = BLI_file_read_as_lines(sl->path); + if (lines) { + READ_VEC3("light_ambient", sl->light_ambient, lines); + READ_SOLIDLIGHT(sl->light, 0, lines); + READ_SOLIDLIGHT(sl->light, 1, lines); + READ_SOLIDLIGHT(sl->light, 2, lines); + READ_SOLIDLIGHT(sl->light, 3, lines); + } + BLI_file_free_lines(lines); +} + +#undef READ_SOLIDLIGHT +#undef READ_VEC3 +#undef READ_IVAL +#undef READ_FVAL + +#define WRITE_FVAL(str, id, val) (BLI_dynstr_appendf(str, id " %f\n", val)) +#define WRITE_IVAL(str, id, val) (BLI_dynstr_appendf(str, id " %d\n", val)) + +#define WRITE_VEC3(str, id, val) do { \ + WRITE_FVAL(str, id ".x", val[0]); \ + WRITE_FVAL(str, id ".y", val[1]); \ + WRITE_FVAL(str, id ".z", val[2]); \ +} while (0) + +#define WRITE_SOLIDLIGHT(str, sl, i) do { \ + WRITE_IVAL(str, "light[" STRINGIFY(i) "].flag", sl[i].flag); \ + WRITE_FVAL(str, "light[" STRINGIFY(i) "].smooth", sl[i].smooth); \ + WRITE_VEC3(str, "light[" STRINGIFY(i) "].col", sl[i].col); \ + WRITE_VEC3(str, "light[" STRINGIFY(i) "].spec", sl[i].spec); \ + WRITE_VEC3(str, "light[" STRINGIFY(i) "].vec", sl[i].vec); \ +} while (0) + +static void studiolight_write_solid_light(StudioLight *sl) +{ + FILE *fp = BLI_fopen(sl->path, "wb"); + if (fp) { + DynStr *str = BLI_dynstr_new(); + + /* Very dumb ascii format. One value per line separated by a space. */ + WRITE_IVAL(str, "version", STUDIOLIGHT_FILE_VERSION); + WRITE_VEC3(str, "light_ambient", sl->light_ambient); + WRITE_SOLIDLIGHT(str, sl->light, 0); + WRITE_SOLIDLIGHT(str, sl->light, 1); + WRITE_SOLIDLIGHT(str, sl->light, 2); + WRITE_SOLIDLIGHT(str, sl->light, 3); + + char *cstr = BLI_dynstr_get_cstring(str); + + fwrite(cstr, BLI_dynstr_get_len(str), 1, fp); + fclose(fp); + + MEM_freeN(cstr); + BLI_dynstr_free(str); + } +} + +#undef WRITE_SOLIDLIGHT +#undef WRITE_VEC3 +#undef WRITE_IVAL +#undef WRITE_FVAL + static void direction_to_equirect(float r[2], const float dir[3]) { r[0] = (atan2f(dir[1], dir[0]) - M_PI) / -(M_PI * 2); @@ -732,6 +829,83 @@ static void studiolight_irradiance_eval(StudioLight *sl, float color[3], const f } #endif +static float brdf_approx(float spec_color, float roughness, float NV) +{ + /* Very rough own approx. We don't need it to be correct, just fast. + * Just simulate fresnel effect with roughness attenuation. */ + float fresnel = exp2(-8.35f * NV) * (1.0f - roughness); + return spec_color * (1.0f - fresnel) + fresnel; +} + +/* NL need to be unclamped. w in [0..1] range. */ +static float wrapped_lighting(float NL, float w) +{ + float w_1 = w + 1.0f; + return max_ff((NL + w) / (w_1 * w_1), 0.0f); +} + +static float blinn_specular( + const float L[3], const float I[3], const float N[3], float R[3], float NL, float roughness, float wrap) +{ + float half_dir[3]; + float wrapped_NL = dot_v3v3(L, R); + add_v3_v3v3(half_dir, L, I); + normalize_v3(half_dir); + float spec_angle = max_ff(dot_v3v3(half_dir, N), 0.0f); + + float gloss = 1.0f - roughness; + /* Reduce gloss for smooth light. (simulate bigger light) */ + gloss *= 1.0f - wrap; + float shininess = exp2(10.0f * gloss + 1.0f); + + /* Pi is already divided in the lamp power. + * normalization_factor = (shininess + 8.0) / (8.0 * M_PI) */ + float normalization_factor = shininess * 0.125f + 1.0f; + float spec_light = powf(spec_angle, shininess) * max_ff(NL, 0.0f) * normalization_factor; + + /* Simulate Env. light. */ + float w = wrap * (1.0 - roughness) + roughness; + float spec_env = wrapped_lighting(wrapped_NL, w); + + float w2 = wrap * wrap; + + return spec_light * (1.0 - w2) + spec_env * w2; +} + +/* Keep in sync with the glsl shader function get_world_lighting() */ +static void studiolight_lights_eval(StudioLight *sl, float color[3], const float normal[3]) +{ + float R[3], I[3] = {0.0f, 0.0f, 1.0f}, N[3] = {normal[0], normal[2], -normal[1]}; + const float roughness = 0.5f; + const float diffuse_color = 0.8f; + const float specular_color = brdf_approx(0.05f, roughness, N[2]); + float diff_light[3], spec_light[3]; + + /* Ambient lighting */ + copy_v3_v3(diff_light, sl->light_ambient); + copy_v3_v3(spec_light, sl->light_ambient); + + reflect_v3_v3v3(R, I, N); + for (int i = 0; i < 3; ++i) { + SolidLight *light = &sl->light[i]; + if (light->flag) { + /* Diffuse lighting */ + float NL = dot_v3v3(light->vec, N); + float diff = wrapped_lighting(NL, light->smooth); + madd_v3_v3fl(diff_light, light->col, diff); + /* Specular lighting */ + float spec = blinn_specular(light->vec, I, N, R, NL, roughness, light->smooth); + madd_v3_v3fl(spec_light, light->spec, spec); + } + } + + /* Multiply result by surface colors. */ + mul_v3_fl(diff_light, diffuse_color * (1.0 - specular_color)); + mul_v3_fl(spec_light, specular_color); + + add_v3_v3v3(color, diff_light, spec_light); +} + static bool studiolight_load_irradiance_equirect_image(StudioLight *sl) { #ifdef STUDIOLIGHT_LOAD_CACHED_FILES @@ -819,12 +993,21 @@ static StudioLight *studiolight_add_file(const char *path, int flag) { char filename[FILE_MAXFILE]; BLI_split_file_part(path, filename, FILE_MAXFILE); - if (BLI_path_extension_check_array(filename, imb_ext_image)) { + + if ((((flag & STUDIOLIGHT_TYPE_STUDIO) != 0) && BLI_path_extension_check(filename, ".sl")) || + BLI_path_extension_check_array(filename, imb_ext_image)) + { StudioLight *sl = studiolight_create(STUDIOLIGHT_EXTERNAL_FILE | flag); BLI_strncpy(sl->name, filename, FILE_MAXFILE); BLI_strncpy(sl->path, path, FILE_MAXFILE); - sl->path_irr_cache = BLI_string_joinN(path, ".irr"); - sl->path_sh_cache = BLI_string_joinN(path, ".sh2"); + + if ((flag & STUDIOLIGHT_TYPE_STUDIO) != 0) { + studiolight_load_solid_light(sl); + } + else { + sl->path_irr_cache = BLI_string_joinN(path, ".irr"); + sl->path_sh_cache = BLI_string_joinN(path, ".sh2"); + } BLI_addtail(&studiolights, sl); return sl; } @@ -971,8 +1154,6 @@ static void studiolight_matcap_preview(uint *icon_buffer, StudioLight *sl, bool static void studiolight_irradiance_preview(uint *icon_buffer, StudioLight *sl) { - BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_SPHERICAL_HARMONICS_COEFFICIENTS_CALCULATED); - ITER_PIXELS(uint, icon_buffer, 1, STUDIOLIGHT_ICON_SIZE, STUDIOLIGHT_ICON_SIZE) @@ -988,7 +1169,7 @@ static void studiolight_irradiance_preview(uint *icon_buffer, StudioLight *sl) SWAP(float, normal[1], normal[2]); normal[1] = -normal[1]; - studiolight_spherical_harmonics_eval(sl, color, normal); + studiolight_lights_eval(sl, color, normal); *pixel = rgb_to_cpack( linearrgb_to_srgb(color[0]), @@ -1005,31 +1186,34 @@ static void studiolight_irradiance_preview(uint *icon_buffer, StudioLight *sl) /* 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(STUDIOLIGHT_INTERNAL | STUDIOLIGHT_SPHERICAL_HARMONICS_COEFFICIENTS_CALCULATED | STUDIOLIGHT_TYPE_STUDIO); + StudioLight * sl = studiolight_create(STUDIOLIGHT_INTERNAL | STUDIOLIGHT_SPHERICAL_HARMONICS_COEFFICIENTS_CALCULATED | STUDIOLIGHT_TYPE_STUDIO); BLI_strncpy(sl->name, "Default", FILE_MAXFILE); - int i = 0; - copy_v3_fl3(sl->spherical_harmonics_coefs[i++], 1.03271556f, 1.07163882f, 1.11193657f); -#if STUDIOLIGHT_SH_BANDS > 1 - copy_v3_fl3(sl->spherical_harmonics_coefs[i++], -0.00480952f, 0.05290511f, 0.16394117f); - copy_v3_fl3(sl->spherical_harmonics_coefs[i++], -0.29686999f, -0.27378261f, -0.24797194f); - copy_v3_fl3(sl->spherical_harmonics_coefs[i++], 0.47932500f, 0.48242140f, 0.47190312f); -#endif -#if STUDIOLIGHT_SH_BANDS > 2 - copy_v3_fl3(sl->spherical_harmonics_coefs[i++], -0.00576984f, 0.00504886f, 0.01640534f); - copy_v3_fl3(sl->spherical_harmonics_coefs[i++], 0.15500379f, 0.15415503f, 0.16244425f); - copy_v3_fl3(sl->spherical_harmonics_coefs[i++], -0.02483751f, -0.02245096f, -0.00536885f); - copy_v3_fl3(sl->spherical_harmonics_coefs[i++], 0.11155496f, 0.11005443f, 0.10839636f); - copy_v3_fl3(sl->spherical_harmonics_coefs[i++], 0.01363425f, 0.01278363f, -0.00159006f); -#endif + copy_v4_fl4(sl->light_ambient, 0.025000, 0.025000, 0.025000, 1.000000); + + copy_v4_fl4(sl->light[0].vec, -0.580952, 0.228571, 0.781185, 0.0); + copy_v4_fl4(sl->light[0].col, 0.900000, 0.900000, 0.900000, 1.000000); + copy_v4_fl4(sl->light[0].spec, 0.318547, 0.318547, 0.318547, 1.000000); + sl->light[0].flag = 1; + sl->light[0].smooth = 0.1; + + copy_v4_fl4(sl->light[1].vec, 0.788218, 0.593482, -0.162765, 0.0); + copy_v4_fl4(sl->light[1].col, 0.267115, 0.269928, 0.358840, 1.000000); + copy_v4_fl4(sl->light[1].spec, 0.090838, 0.090838, 0.090838, 1.000000); + sl->light[1].flag = 1; + sl->light[1].smooth = 0.25; + + copy_v4_fl4(sl->light[2].vec, 0.696472, -0.696472, -0.172785, 0.0); + copy_v4_fl4(sl->light[2].col, 0.293216, 0.304662, 0.401968, 1.000000); + copy_v4_fl4(sl->light[2].spec, 0.069399, 0.020331, 0.020331, 1.000000); + sl->light[2].flag = 1; + sl->light[2].smooth = 0.5; BLI_addtail(&studiolights, sl); + /* go over the preset folder and add a studiolight for every image with its path */ + /* Also reserve icon space for it. */ studiolight_add_files_from_datafolder(BLENDER_SYSTEM_DATAFILES, STUDIOLIGHT_LIGHTS_FOLDER, STUDIOLIGHT_TYPE_STUDIO); studiolight_add_files_from_datafolder(BLENDER_USER_DATAFILES, STUDIOLIGHT_LIGHTS_FOLDER, STUDIOLIGHT_TYPE_STUDIO | STUDIOLIGHT_USER_DEFINED); studiolight_add_files_from_datafolder(BLENDER_SYSTEM_DATAFILES, STUDIOLIGHT_WORLD_FOLDER, STUDIOLIGHT_TYPE_WORLD); @@ -1161,12 +1345,42 @@ void BKE_studiolight_remove(StudioLight *sl) } } -StudioLight *BKE_studiolight_new(const char *path, int orientation) +StudioLight *BKE_studiolight_load(const char *path, int type) { - StudioLight *sl = studiolight_add_file(path, orientation | STUDIOLIGHT_USER_DEFINED); + StudioLight *sl = studiolight_add_file(path, type | STUDIOLIGHT_USER_DEFINED); return sl; } +StudioLight *BKE_studiolight_create(const char *path, const SolidLight light[4], const float light_ambient[3]) +{ + StudioLight *sl = studiolight_create(STUDIOLIGHT_EXTERNAL_FILE | STUDIOLIGHT_USER_DEFINED | STUDIOLIGHT_TYPE_STUDIO); + + char filename[FILE_MAXFILE]; + BLI_split_file_part(path, filename, FILE_MAXFILE); + BLI_snprintf(sl->path, FILE_MAXFILE, "%s%s", path, ".sl"); + BLI_snprintf(sl->name, FILE_MAXFILE, "%s%s", filename, ".sl"); + + memcpy(sl->light, light, sizeof(*light) * 3); + memcpy(sl->light_ambient, light_ambient, sizeof(*light_ambient) * 3); + + studiolight_write_solid_light(sl); + + BLI_addtail(&studiolights, sl); + return sl; +} + +/* Only useful for workbench while editing the userprefs. */ +StudioLight *BKE_studiolight_studio_edit_get(void) +{ + static StudioLight sl = {0}; + sl.flag = STUDIOLIGHT_TYPE_STUDIO; + + memcpy(sl.light, U.light, sizeof(*sl.light) * 3); + memcpy(sl.light_ambient, U.light_ambient, sizeof(sl.light_ambient) * 3); + + return &sl; +} + void BKE_studiolight_refresh(void) { BKE_studiolight_free(); diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c index b2d9a385c6f..5559982d820 100644 --- a/source/blender/blenloader/intern/versioning_280.c +++ b/source/blender/blenloader/intern/versioning_280.c @@ -2467,5 +2467,18 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) } } + /* Move studio_light selection to lookdev_light. */ + if (!DNA_struct_elem_find(fd->filesdna, "View3DShading", "char", "lookdev_light[256]")) { + for (bScreen *screen = bmain->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; + memcpy(v3d->shading.lookdev_light, v3d->shading.studio_light, sizeof(char) * 256); + } + } + } + } + } } } diff --git a/source/blender/draw/engines/eevee/eevee_lookdev.c b/source/blender/draw/engines/eevee/eevee_lookdev.c index 298a67b811b..aa2f480597b 100644 --- a/source/blender/draw/engines/eevee/eevee_lookdev.c +++ b/source/blender/draw/engines/eevee/eevee_lookdev.c @@ -62,7 +62,7 @@ void EEVEE_lookdev_cache_init( const DRWContextState *draw_ctx = DRW_context_state_get(); View3D *v3d = draw_ctx->v3d; if (LOOK_DEV_STUDIO_LIGHT_ENABLED(v3d)) { - StudioLight *sl = BKE_studiolight_find(v3d->shading.studio_light, STUDIOLIGHT_ORIENTATIONS_MATERIAL_MODE); + StudioLight *sl = BKE_studiolight_find(v3d->shading.lookdev_light, STUDIOLIGHT_ORIENTATIONS_MATERIAL_MODE); if (sl && (sl->flag & STUDIOLIGHT_TYPE_WORLD)) { GPUShader *shader = EEVEE_shaders_default_studiolight_sh_get(); struct GPUBatch *geom = DRW_cache_fullscreen_quad_get(); diff --git a/source/blender/draw/engines/workbench/workbench_data.c b/source/blender/draw/engines/workbench/workbench_data.c index fd72848da49..1cdf4c2b443 100644 --- a/source/blender/draw/engines/workbench/workbench_data.c +++ b/source/blender/draw/engines/workbench/workbench_data.c @@ -40,13 +40,13 @@ void workbench_private_data_init(WORKBENCH_PrivateData *wpd) } else { wpd->studio_light = BKE_studiolight_find( - wpd->shading.studio_light, STUDIOLIGHT_TYPE_STUDIO | STUDIOLIGHT_TYPE_WORLD); + wpd->shading.studio_light, STUDIOLIGHT_TYPE_STUDIO); } /* If matcaps are missing, use this as fallback. */ if (UNLIKELY(wpd->studio_light == NULL)) { wpd->studio_light = BKE_studiolight_find( - wpd->shading.studio_light, STUDIOLIGHT_TYPE_STUDIO | STUDIOLIGHT_TYPE_WORLD); + wpd->shading.studio_light, STUDIOLIGHT_TYPE_STUDIO); } wpd->shadow_multiplier = 1.0 - wpd->shading.shadow_intensity; @@ -79,7 +79,7 @@ void workbench_private_data_init(WORKBENCH_PrivateData *wpd) zero_v3(wd->background_color_high); } - studiolight_update_world(wpd->studio_light, wd); + studiolight_update_world(wpd, wpd->studio_light, wd); copy_v3_v3(wd->object_outline_color, wpd->shading.object_outline_color); wd->object_outline_color[3] = 1.0f; @@ -157,9 +157,8 @@ void workbench_private_data_get_light_direction(WORKBENCH_PrivateData *wpd, floa const DRWContextState *draw_ctx = DRW_context_state_get(); Scene *scene = draw_ctx->scene; WORKBENCH_UBO_World *wd = &wpd->world_data; - float view_matrix[4][4], view_inv[4][4], rot_matrix[4][4]; + float view_matrix[4][4]; DRW_viewport_matrix_get(view_matrix, DRW_MAT_VIEW); - DRW_viewport_matrix_get(view_inv, DRW_MAT_VIEWINV); copy_v3_v3(r_light_direction, scene->display.light_direction); negate_v3(r_light_direction); @@ -167,46 +166,6 @@ void workbench_private_data_get_light_direction(WORKBENCH_PrivateData *wpd, floa /* Shadow direction. */ mul_v3_mat3_m4v3(wd->shadow_direction_vs, view_matrix, r_light_direction); - /* TODO enable when we support studiolight presets. */ - if (STUDIOLIGHT_TYPE_WORLD_ENABLED(wpd) && false) { - axis_angle_to_mat4_single(rot_matrix, 'Y', -wpd->shading.studiolight_rot_z); - mul_m4_m4m4(rot_matrix, rot_matrix, view_matrix); - swap_v3_v3(rot_matrix[2], rot_matrix[1]); - negate_v3(rot_matrix[2]); - } - else { - unit_m4(rot_matrix); - } - - /* Studio Lights. */ - for (int i = 0; i < 4; i++) { - WORKBENCH_UBO_Light *light = &wd->lights[i]; - /* TODO use 4 lights in studiolights prefs. */ - if (i > 2) { - copy_v3_fl3(light->light_direction, 1.0f, 0.0f, 0.0f); - copy_v3_fl(light->specular_color, 0.0f); - copy_v3_fl(light->diffuse_color, 0.0f); - continue; - } - - SolidLight *sl = &U.light[i]; - if (sl->flag) { - copy_v3_v3(light->light_direction, sl->vec); - mul_mat3_m4_v3(rot_matrix, light->light_direction); - /* We should predivide the power by PI but that makes the lights really dim. */ - copy_v3_v3(light->specular_color, sl->spec); - copy_v3_v3(light->diffuse_color, sl->col); - light->wrapped = sl->smooth; - } - else { - copy_v3_fl3(light->light_direction, 1.0f, 0.0f, 0.0f); - copy_v3_fl(light->specular_color, 0.0f); - copy_v3_fl(light->diffuse_color, 0.0f); - } - } - - copy_v4_v4(wd->ambient_color, U.light_ambient); - DRW_uniformbuffer_update(wpd->world_ubo, wd); } diff --git a/source/blender/draw/engines/workbench/workbench_private.h b/source/blender/draw/engines/workbench/workbench_private.h index 4ab0d39aa55..b1f3a589d05 100644 --- a/source/blender/draw/engines/workbench/workbench_private.h +++ b/source/blender/draw/engines/workbench/workbench_private.h @@ -299,7 +299,7 @@ void workbench_material_shgroup_uniform( void workbench_material_copy(WORKBENCH_MaterialData *dest_material, const WORKBENCH_MaterialData *source_material); /* workbench_studiolight.c */ -void studiolight_update_world(StudioLight *sl, WORKBENCH_UBO_World *wd); +void studiolight_update_world(WORKBENCH_PrivateData *wpd, StudioLight *sl, WORKBENCH_UBO_World *wd); void studiolight_update_light(WORKBENCH_PrivateData *wpd, const float light_direction[3]); bool studiolight_object_cast_visible_shadow(WORKBENCH_PrivateData *wpd, Object *ob, WORKBENCH_ObjectData *oed); float studiolight_object_shadow_distance(WORKBENCH_PrivateData *wpd, Object *ob, WORKBENCH_ObjectData *oed); diff --git a/source/blender/draw/engines/workbench/workbench_studiolight.c b/source/blender/draw/engines/workbench/workbench_studiolight.c index 901260d0660..183b285c69c 100644 --- a/source/blender/draw/engines/workbench/workbench_studiolight.c +++ b/source/blender/draw/engines/workbench/workbench_studiolight.c @@ -32,8 +32,56 @@ #include "BLI_math.h" #include "BKE_global.h" -void studiolight_update_world(StudioLight *sl, WORKBENCH_UBO_World *wd) +void studiolight_update_world(WORKBENCH_PrivateData *wpd, StudioLight *studiolight, WORKBENCH_UBO_World *wd) { + float view_matrix[4][4], rot_matrix[4][4]; + DRW_viewport_matrix_get(view_matrix, DRW_MAT_VIEW); + + /* TODO enable when we support studiolight presets. */ + if (STUDIOLIGHT_TYPE_WORLD_ENABLED(wpd) && false) { + axis_angle_to_mat4_single(rot_matrix, 'Y', -wpd->shading.studiolight_rot_z); + mul_m4_m4m4(rot_matrix, rot_matrix, view_matrix); + swap_v3_v3(rot_matrix[2], rot_matrix[1]); + negate_v3(rot_matrix[2]); + } + else { + unit_m4(rot_matrix); + } + + if (U.edit_solid_light) { + studiolight = BKE_studiolight_studio_edit_get(); + } + + /* Studio Lights. */ + for (int i = 0; i < 4; i++) { + WORKBENCH_UBO_Light *light = &wd->lights[i]; + /* TODO use 4 lights in studiolights prefs. */ + if (i > 2) { + copy_v3_fl3(light->light_direction, 1.0f, 0.0f, 0.0f); + copy_v3_fl(light->specular_color, 0.0f); + copy_v3_fl(light->diffuse_color, 0.0f); + continue; + } + + SolidLight *sl = &studiolight->light[i]; + if (sl->flag) { + copy_v3_v3(light->light_direction, sl->vec); + mul_mat3_m4_v3(rot_matrix, light->light_direction); + /* We should predivide the power by PI but that makes the lights really dim. */ + copy_v3_v3(light->specular_color, sl->spec); + copy_v3_v3(light->diffuse_color, sl->col); + light->wrapped = sl->smooth; + } + else { + copy_v3_fl3(light->light_direction, 1.0f, 0.0f, 0.0f); + copy_v3_fl(light->specular_color, 0.0f); + copy_v3_fl(light->diffuse_color, 0.0f); + } + } + + copy_v3_v3(wd->ambient_color, studiolight->light_ambient); + +#if 0 BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_SPHERICAL_HARMONICS_COEFFICIENTS_CALCULATED); #if STUDIOLIGHT_SH_BANDS == 2 @@ -87,6 +135,7 @@ void studiolight_update_world(StudioLight *sl, WORKBENCH_UBO_World *wd) copy_v3_v3(wd->spherical_harmonics_coefs[i], sl->spherical_harmonics_coefs[i]); } #endif +#endif } static void compute_parallel_lines_nor_and_dist(const float v1[2], const float v2[2], const float v3[2], float r_line[2]) diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index 5bb3523a458..e0bed7216e2 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -589,7 +589,8 @@ typedef struct UserDef { struct SolidLight light[3]; float light_ambient[3], pad7; short gizmo_flag, gizmo_size; - short pad6[3]; + short edit_solid_light; + short pad6[2]; short textimeout, texcollectrate; short dragthreshold; int memcachelimit; diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h index b06f94db064..5c31f377447 100644 --- a/source/blender/makesdna/DNA_view3d_types.h +++ b/source/blender/makesdna/DNA_view3d_types.h @@ -148,6 +148,7 @@ typedef struct View3DShading { char pad[7]; char studio_light[256]; /* FILE_MAXFILE */ + char lookdev_light[256]; /* FILE_MAXFILE */ char matcap[256]; /* FILE_MAXFILE */ float shadow_intensity; diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index fd6e7436351..74fb09f8088 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -754,9 +754,12 @@ static PointerRNA rna_View3DShading_selected_studio_light_get(PointerRNA *ptr) if (shading->type == OB_SOLID && shading->light == V3D_LIGHTING_MATCAP) { sl = BKE_studiolight_find(shading->matcap, STUDIOLIGHT_FLAG_ALL); } - else { + else if (shading->type == OB_SOLID && shading->light == V3D_LIGHTING_STUDIO) { sl = BKE_studiolight_find(shading->studio_light, STUDIOLIGHT_FLAG_ALL); } + else { + sl = BKE_studiolight_find(shading->lookdev_light, STUDIOLIGHT_FLAG_ALL); + } return rna_pointer_inherit_refine(ptr, &RNA_StudioLight, sl); } @@ -805,13 +808,14 @@ static int rna_View3DShading_studio_light_get(PointerRNA *ptr) View3DShading *shading = (View3DShading *)ptr->data; char *dna_storage = shading->studio_light; - int flag = STUDIOLIGHT_ORIENTATIONS_SOLID; + int flag = STUDIOLIGHT_TYPE_STUDIO; if (shading->type == OB_SOLID && shading->light == V3D_LIGHTING_MATCAP) { flag = STUDIOLIGHT_TYPE_MATCAP; dna_storage = shading->matcap; } else if (shading->type == OB_MATERIAL) { - flag = STUDIOLIGHT_ORIENTATIONS_MATERIAL_MODE; + flag = STUDIOLIGHT_TYPE_WORLD; + dna_storage = shading->lookdev_light; } StudioLight *sl = BKE_studiolight_find(dna_storage, flag); if (sl) { @@ -828,13 +832,14 @@ static void rna_View3DShading_studio_light_set(PointerRNA *ptr, int value) View3DShading *shading = (View3DShading *)ptr->data; char *dna_storage = shading->studio_light; - int flag = STUDIOLIGHT_ORIENTATIONS_SOLID; + int flag = STUDIOLIGHT_TYPE_STUDIO; if (shading->type == OB_SOLID && shading->light == V3D_LIGHTING_MATCAP) { flag = STUDIOLIGHT_TYPE_MATCAP; dna_storage = shading->matcap; } else if (shading->type == OB_MATERIAL) { - flag = STUDIOLIGHT_ORIENTATIONS_MATERIAL_MODE; + flag = STUDIOLIGHT_TYPE_WORLD; + dna_storage = shading->lookdev_light; } StudioLight *sl = BKE_studiolight_findindex(value, flag); if (sl) { @@ -876,8 +881,7 @@ static const EnumPropertyItem *rna_View3DShading_studio_light_itemf( switch (shading->type) { case OB_SOLID: case OB_TEXTURE: - show_studiolight = ( - (sl->flag & (STUDIOLIGHT_TYPE_WORLD | STUDIOLIGHT_TYPE_STUDIO)) != 0); + show_studiolight = ((sl->flag & STUDIOLIGHT_TYPE_STUDIO) != 0); break; case OB_MATERIAL: diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index 89f777625a0..af6150704e0 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -628,9 +628,15 @@ static void rna_StudioLights_remove(UserDef *UNUSED(userdef), StudioLight *studi BKE_studiolight_remove(studio_light); } -static StudioLight *rna_StudioLights_new(UserDef *UNUSED(userdef), const char *path, int type) +static StudioLight *rna_StudioLights_load(UserDef *UNUSED(userdef), const char *path, int type) { - return BKE_studiolight_new(path, type); + return BKE_studiolight_load(path, type); +} + +/* TODO: Make it accept arguments. */ +static StudioLight *rna_StudioLights_new(UserDef *userdef, const char *name) +{ + return BKE_studiolight_create(name, userdef->light, userdef->light_ambient); } /* StudioLight.name */ @@ -3315,8 +3321,8 @@ static void rna_def_userdef_studiolights(BlenderRNA *brna) RNA_def_struct_sdna(srna, "UserDef"); RNA_def_struct_ui_text(srna, "Studio Lights", "Collection of studio lights"); - func = RNA_def_function(srna, "new", "rna_StudioLights_new"); - RNA_def_function_ui_description(func, "Create a new studiolight"); + func = RNA_def_function(srna, "load", "rna_StudioLights_load"); + RNA_def_function_ui_description(func, "Load studiolight from file"); parm = RNA_def_string(func, "path", NULL, 0, "File Path", "File path where the studio light file can be found"); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_enum(func, "type", rna_enum_studio_light_type_items, STUDIOLIGHT_TYPE_WORLD, "Type", "The type for the new studio light"); @@ -3324,6 +3330,13 @@ static void rna_def_userdef_studiolights(BlenderRNA *brna) parm = RNA_def_pointer(func, "studio_light", "StudioLight", "", "Newly created StudioLight"); RNA_def_function_return(func, parm); + func = RNA_def_function(srna, "new", "rna_StudioLights_new"); + RNA_def_function_ui_description(func, "Create studiolight from default lighting"); + parm = RNA_def_string(func, "path", NULL, 0, "Path", "Path to the file that will contain the lighing info (without extension)"); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_pointer(func, "studio_light", "StudioLight", "", "Newly created StudioLight"); + RNA_def_function_return(func, parm); + func = RNA_def_function(srna, "remove", "rna_StudioLights_remove"); RNA_def_function_ui_description(func, "Remove a studio light"); parm = RNA_def_pointer(func, "studio_light", "StudioLight", "", "The studio light to remove"); @@ -4297,6 +4310,12 @@ static void rna_def_userdef_system(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Ambient Color", "Color of the ambient light that uniformly lit the scene"); RNA_def_property_update(prop, 0, "rna_UserDef_viewport_lights_update"); + prop = RNA_def_property(srna, "edit_solid_light", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "edit_solid_light", 1); + RNA_def_property_ui_text(prop, "Edit Solid Light", + "View the result of the solid lights in the viewport"); + RNA_def_property_update(prop, 0, "rna_UserDef_viewport_lights_update"); + prop = RNA_def_property(srna, "use_weight_color_range", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_CUSTOM_RANGE); RNA_def_property_ui_text(prop, "Use Weight Color Range", |