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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--release/scripts/startup/bl_operators/wm.py54
-rw-r--r--release/scripts/startup/bl_ui/space_userpref.py16
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py6
-rw-r--r--source/blender/blenkernel/BKE_studiolight.h11
-rw-r--r--source/blender/blenkernel/intern/studiolight.c274
-rw-r--r--source/blender/blenloader/intern/versioning_280.c13
-rw-r--r--source/blender/draw/engines/eevee/eevee_lookdev.c2
-rw-r--r--source/blender/draw/engines/workbench/workbench_data.c49
-rw-r--r--source/blender/draw/engines/workbench/workbench_private.h2
-rw-r--r--source/blender/draw/engines/workbench/workbench_studiolight.c51
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h3
-rw-r--r--source/blender/makesdna/DNA_view3d_types.h1
-rw-r--r--source/blender/makesrna/intern/rna_space.c18
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c27
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",