diff options
author | Jeroen Bakker <j.bakker@atmind.nl> | 2018-06-18 16:17:46 +0300 |
---|---|---|
committer | Jeroen Bakker <j.bakker@atmind.nl> | 2018-06-18 16:32:53 +0300 |
commit | 7747d4cecf078589f614813d0e5e0a753d4e10b5 (patch) | |
tree | 099fe569b48e44f1406d8420ea618ad27f00ee84 /source | |
parent | fec97ec94939ab32b43e3221e4c611e1e873a563 (diff) |
Workbench: increased Quality of the diffuse lighting model
- implemented Spherical Harmonics L2 for diffuse shading.
TODO: caching the precalculated harmonics so it won't take soo long to
open the popover
Diffstat (limited to 'source')
8 files changed, 231 insertions, 200 deletions
diff --git a/source/blender/blenkernel/BKE_studiolight.h b/source/blender/blenkernel/BKE_studiolight.h index 36de1e4d22f..0e94411030b 100644 --- a/source/blender/blenkernel/BKE_studiolight.h +++ b/source/blender/blenkernel/BKE_studiolight.h @@ -60,7 +60,7 @@ struct GPUTexture; enum StudioLightFlag { - STUDIOLIGHT_DIFFUSE_LIGHT_CALCULATED = (1 << 0), + STUDIOLIGHT_SPHERICAL_HARMONICS_COEFFICIENTS_CALCULATED = (1 << 0), STUDIOLIGHT_LIGHT_DIRECTION_CALCULATED = (1 << 1), STUDIOLIGHT_INTERNAL = (1 << 2), STUDIOLIGHT_EXTERNAL_FILE = (1 << 3), @@ -91,7 +91,7 @@ typedef struct StudioLight { int icon_id_matcap; int icon_id_matcap_flipped; int index; - float diffuse_light[6][3]; + float spherical_harmonics_coefs[9][3]; float light_direction[3]; ImBuf *equirectangular_radiance_buffer; ImBuf *equirectangular_irradiance_buffer; diff --git a/source/blender/blenkernel/intern/studiolight.c b/source/blender/blenkernel/intern/studiolight.c index c20fe34b46a..b4b82965fbf 100644 --- a/source/blender/blenkernel/intern/studiolight.c +++ b/source/blender/blenkernel/intern/studiolight.c @@ -56,8 +56,8 @@ /* Statics */ static ListBase studiolights; -#define STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE 16 -#define STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_HEIGHT 64 +#define STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE 128 +#define STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_HEIGHT 32 #define STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_WIDTH (STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_HEIGHT * 2) static const char *STUDIOLIGHT_CAMERA_FOLDER = "studiolights/camera/"; @@ -316,63 +316,162 @@ BLI_INLINE void studiolight_evaluate_radiance_buffer( } -static void studiolight_calculate_irradiance(StudioLight *sl, float color[3], const float normal[3]) +BLI_INLINE float studiolight_area_element(float x, float y) +{ + return atan2(x * y, sqrtf(x * x + y * y + 1)); +} + +BLI_INLINE float studiolight_texel_solid_angle(float x, float y, float halfpix) +{ + float v1x = (x - halfpix) * 2.0f - 1.0f; + float v1y = (y - halfpix) * 2.0f - 1.0f; + float v2x = (x + halfpix) * 2.0f - 1.0f; + float v2y = (y + halfpix) * 2.0f - 1.0f; + + return studiolight_area_element(v1x, v1y) - studiolight_area_element(v1x, v2y) - studiolight_area_element(v2x, v1y) + studiolight_area_element(v2x, v2y); +} + +static void studiolight_calculate_cubemap_vector_weight(float normal[3], float *weight, int face, float x, float y) +{ + copy_v3_fl3(normal, x * 2.0f - 1.0f, y * 2.0f - 1.0f, 1.0f); + const float conversion_matrices[6][3][3] = { + { + {0.0f, 0.0f, -1.0f}, + {0.0f, -1.0f, 0.0f}, + {-1.0f, 0.0f, 0.0f}, + }, + { + {0.0f, 0.0f, -1.0f}, + {0.0f, -1.0f, 0.0f}, + {-1.0f, 0.0f, 0.0f}, + }, + { + {1.0f, 0.0f, 0.0f}, + {0.0f, 0.0f, 1.0f}, + {0.0f, -1.0f, 0.0f}, + }, + { + {1.0f, 0.0f, 0.0f}, + {0.0f, 0.0f, -1.0f}, + {0.0f, 1.0f, 0.0f}, + }, + { + {1.0f, 0.0f, 0.0f}, + {0.0f, -1.0f, 0.0f}, + {0.0f, 0.0f, -1.0f}, + }, + { + {-1.0f, 0.0f, 0.0f}, + {0.0f, -1.0f, 0.0f}, + {0.0f, 0.0f, 1.0f}, + } + }; + mul_m3_v3(conversion_matrices[face], normal); + normalize_v3(normal); + const float halfpix = 1.0f / (2.0f* STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE); + *weight = studiolight_texel_solid_angle(x + halfpix, y + halfpix, halfpix); +} + +static void studiolight_calculate_spherical_harmonics_coefficient(StudioLight *sl, int sh_component) { - int hits = 0; - copy_v3_fl(color, 0.0f); + const float M_4PI = M_PI * 4.0f; + + float weight_accum = 0.0f; + float sh[3] = {0.0f, 0.0f, 0.0f}; + for (int face = 0; face < 6; face++) + { + float *color; + color = sl->radiance_cubemap_buffers[face]->rect_float; + for (int y = 0; y < STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE; y++) { + float yf = y / (float)STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE; + for (int x = 0; x < STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE; x++) { + float xf = x / (float)STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE; + float weight, coef; + float cubevec[3]; + studiolight_calculate_cubemap_vector_weight(cubevec, &weight, face, xf, yf); + + switch (sh_component) { + case 0: + { + coef = 0.2822095f; + break; + } - /* back */ - studiolight_evaluate_radiance_buffer(sl->radiance_cubemap_buffers[STUDIOLIGHT_Y_POS], normal, color, &hits, 0, 2, 1, 0.5); - /* front */ - studiolight_evaluate_radiance_buffer(sl->radiance_cubemap_buffers[STUDIOLIGHT_Y_NEG], normal, color, &hits, 0, 2, 1, -0.5); + case 1: + { + coef = -0.488603f * cubevec[2] * 2.0f / 3.0f; + break; + } + case 2: + { + coef = 0.488603f * cubevec[1] * 2.0f / 3.0f; + break; + } + case 3: + { + coef = -0.488603f * cubevec[0] * 2.0f / 3.0f; + break; + } - /* left */ - studiolight_evaluate_radiance_buffer(sl->radiance_cubemap_buffers[STUDIOLIGHT_X_POS], normal, color, &hits, 1, 2, 0, 0.5); - /* right */ - studiolight_evaluate_radiance_buffer(sl->radiance_cubemap_buffers[STUDIOLIGHT_X_NEG], normal, color, &hits, 1, 2, 0, -0.5); + case 4: + { + coef = 1.092548f * cubevec[0] * cubevec[2] * 1.0f / 4.0f; + break; + } + case 5: + { + coef = -1.092548f * cubevec[2] * cubevec[1] * 1.0f / 4.0f; + break; + } + case 6: + { + coef = 0.315392f * (3.0f * cubevec[2] * cubevec[2] - 1.0f) * 1.0f / 4.0f; + break; + } + case 7: + { + coef = 1.092548f * cubevec[0] * cubevec[1] * 1.0f / 4.0f; + break; + } + case 8: + { + coef = 0.546274f * (cubevec[0] * cubevec[0] - cubevec[2] * cubevec[2]) * 1.0f / 4.0f; + break; + } - /* top */ - studiolight_evaluate_radiance_buffer(sl->radiance_cubemap_buffers[STUDIOLIGHT_Z_POS], normal, color, &hits, 0, 1, 2, 0.5); - /* bottom */ - studiolight_evaluate_radiance_buffer(sl->radiance_cubemap_buffers[STUDIOLIGHT_Z_NEG], normal, color, &hits, 0, 1, 2, -0.5); + default: + { + coef = 0.0f; + } + } - if (hits) { - mul_v3_fl(color, 3.0 / hits); - } - else { - copy_v3_fl3(color, 1.0, 0.0, 1.0); + madd_v3_v3fl(sh, color, coef * weight); + weight_accum += weight; + color += 4; + } + } } + + mul_v3_fl(sh, M_4PI / weight_accum); + copy_v3_v3(sl->spherical_harmonics_coefs[sh_component], sh); } static void studiolight_calculate_diffuse_light(StudioLight *sl) { /* init light to black */ - 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], 0.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); - if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) { - const float normal_x_neg[3] = {-1.0f, 0.0f, 0.0f}; - const float normal_x_pos[3] = { 1.0f, 0.0f, 0.0f}; - const float normal_y_neg[3] = { 0.0f, 1.0f, 0.0f}; - const float normal_y_pos[3] = { 0.0f, -1.0f, 0.0f}; - const float normal_z_neg[3] = { 0.0f, 0.0f, -1.0f}; - const float normal_z_pos[3] = { 0.0f, 0.0f, 1.0f}; - BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_RADIANCE_BUFFERS_CALCULATED); - studiolight_calculate_irradiance(sl, sl->diffuse_light[STUDIOLIGHT_X_POS], normal_x_pos); - studiolight_calculate_irradiance(sl, sl->diffuse_light[STUDIOLIGHT_X_NEG], normal_x_neg); - studiolight_calculate_irradiance(sl, sl->diffuse_light[STUDIOLIGHT_Y_POS], normal_y_pos); - studiolight_calculate_irradiance(sl, sl->diffuse_light[STUDIOLIGHT_Y_NEG], normal_y_neg); - studiolight_calculate_irradiance(sl, sl->diffuse_light[STUDIOLIGHT_Z_POS], normal_z_pos); - studiolight_calculate_irradiance(sl, sl->diffuse_light[STUDIOLIGHT_Z_NEG], normal_z_neg); + for (int comp = 0; comp < 9; comp ++) { + studiolight_calculate_spherical_harmonics_coefficient(sl, comp); +#if 0 + print_v3("SH2", sl->spherical_harmonics_coefs[comp]); +#endif + } } - sl->flag |= STUDIOLIGHT_DIFFUSE_LIGHT_CALCULATED; + + sl->flag |= STUDIOLIGHT_SPHERICAL_HARMONICS_COEFFICIENTS_CALCULATED; } static float area_element(float x, float y ) @@ -454,7 +553,6 @@ static void studiolight_calculate_specular_irradiance(StudioLight *sl, float col static bool studiolight_load_irradiance_equirectangular_image(StudioLight *sl) { -#if 1 if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) { ImBuf *ibuf = NULL; ibuf = IMB_loadiffname(sl->path_irr, 0, NULL); @@ -465,7 +563,6 @@ static bool studiolight_load_irradiance_equirectangular_image(StudioLight *sl) return true; } } -#endif return false; } @@ -561,7 +658,6 @@ static void studiolight_add_files_from_datafolder(const int folder_id, const cha BLI_filelist_free(dir, totfile); dir = NULL; } - } static int studiolight_flag_cmp_order(const StudioLight *sl) @@ -633,7 +729,7 @@ static uint *studiolight_radiance_preview(StudioLight *sl, int icon_size) normal[0] = dx * 2.0f - 1.0f; normal[1] = dy * 2.0f - 1.0f; float dist = len_v2(normal); - normal[2] = sqrtf(1.0f - SQUARE(dist)); + normal[2] = -sqrtf(1.0f - SQUARE(dist)); float direction[3]; reflect_v3_v3v3(direction, incoming, normal); @@ -691,105 +787,54 @@ static uint *studiolight_matcap_preview(StudioLight *sl, int icon_size, bool fli static uint *studiolight_irradiance_preview(StudioLight *sl, int icon_size) { -#if 0 - if (!(sl->flag & STUDIOLIGHT_EXTERNAL_FILE)) -#endif - { + BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_SPHERICAL_HARMONICS_COEFFICIENTS_CALCULATED); - BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_DIFFUSE_LIGHT_CALCULATED); - - uint *rect = MEM_mallocN(icon_size * icon_size * sizeof(uint), __func__); - float pixel_size = 1.0f / (float)icon_size; - - int offset = 0; - for (int y = 0; y < icon_size; y++) { - float dy = (y + 0.5f) / (float)icon_size; - dy = dy / STUDIOLIGHT_DIAMETER - (1.0f - STUDIOLIGHT_DIAMETER) / 2.0f; - for (int x = 0; x < icon_size; x++) { - float dx = (x + 0.5f) / (float)icon_size; - dx = dx / STUDIOLIGHT_DIAMETER - (1.0f - STUDIOLIGHT_DIAMETER) / 2.0f; - - uint pixelresult = 0x0; - uint alphamask = alpha_circle_mask(dx, dy, 0.5f - pixel_size, 0.5f); - if (alphamask != 0) { - /* calculate normal */ - float normal[3]; - normal[0] = dx * 2.0f - 1.0f; - normal[1] = dy * 2.0f - 1.0f; - float dist = len_v2(normal); - normal[2] = sqrtf(1.0f - SQUARE(dist)); - - float color[3]; - mul_v3_v3fl(color, sl->diffuse_light[STUDIOLIGHT_X_POS], clamp_f(normal[0], 0.0, 1.0)); - interp_v3_v3v3(color, color, sl->diffuse_light[STUDIOLIGHT_X_NEG], clamp_f(-normal[0], 0.0, 1.0)); - interp_v3_v3v3(color, color, sl->diffuse_light[STUDIOLIGHT_Z_POS], clamp_f(normal[1], 0.0, 1.0)); - interp_v3_v3v3(color, color, sl->diffuse_light[STUDIOLIGHT_Z_NEG], clamp_f(-normal[1], 0.0, 1.0)); - interp_v3_v3v3(color, color, sl->diffuse_light[STUDIOLIGHT_Y_POS], clamp_f(normal[2], 0.0, 1.0)); - - pixelresult = rgb_to_cpack( - linearrgb_to_srgb(color[0]), - linearrgb_to_srgb(color[1]), - linearrgb_to_srgb(color[2])) | alphamask; - } - rect[offset++] = pixelresult; - } - } - return rect; - } -#if 0 - else { - BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EQUIRECTANGULAR_IRRADIANCE_IMAGE_CALCULATED); + uint *rect = MEM_mallocN(icon_size * icon_size * sizeof(uint), __func__); + float pixel_size = 1.0f / (float)icon_size; - uint *rect = MEM_mallocN(icon_size * icon_size * sizeof(uint), __func__); - int icon_center = icon_size / 2; - float sphere_radius = icon_center * 0.9; - - 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); - - 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); - - float direction[3]; - reflect_v3_v3v3(direction, incoming, normal); - - float color[4]; - studiolight_calculate_radiance(sl->equirectangular_irradiance_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; + int offset = 0; + for (int y = 0; y < icon_size; y++) { + float dy = (y + 0.5f) / (float)icon_size; + dy = dy / STUDIOLIGHT_DIAMETER - (1.0f - STUDIOLIGHT_DIAMETER) / 2.0f; + for (int x = 0; x < icon_size; x++) { + float dx = (x + 0.5f) / (float)icon_size; + dx = dx / STUDIOLIGHT_DIAMETER - (1.0f - STUDIOLIGHT_DIAMETER) / 2.0f; + + uint pixelresult = 0x0; + uint alphamask = alpha_circle_mask(dx, dy, 0.5f - pixel_size, 0.5f); + if (alphamask != 0) { + /* calculate normal */ + float normal[3]; + normal[0] = dx * 2.0f - 1.0f; + normal[1] = -(dy * 2.0f - 1.0f); + float dist = len_v2(normal); + normal[2] = -sqrtf(1.0f - SQUARE(dist)); + SWAP(float, normal[1], normal[2]); + + float color[3] = {0.0f, 0.0f, 0.0f}; + /* Spherical Harmonics L0 */ + madd_v3_v3fl(color, sl->spherical_harmonics_coefs[0], 0.282095f); + + /* Spherical Harmonics L1 */ + madd_v3_v3fl(color, sl->spherical_harmonics_coefs[1], -0.488603f * normal[2]); + madd_v3_v3fl(color, sl->spherical_harmonics_coefs[2], 0.488603f * normal[1]); + madd_v3_v3fl(color, sl->spherical_harmonics_coefs[3], -0.488603f * normal[0]); + + /* Spherical Harmonics L1 */ + madd_v3_v3fl(color, sl->spherical_harmonics_coefs[4], 1.092548f * normal[0] * normal[2]); + madd_v3_v3fl(color, sl->spherical_harmonics_coefs[5], -1.092548f * normal[2] * normal[1]); + madd_v3_v3fl(color, sl->spherical_harmonics_coefs[6], 0.315392f * (3.0f * normal[1] * normal[1] - 1.0f)); + madd_v3_v3fl(color, sl->spherical_harmonics_coefs[7], -1.092548 * normal[0] * normal[1]); + madd_v3_v3fl(color, sl->spherical_harmonics_coefs[8], 0.546274 * (normal[0] * normal[0] - normal[2] * normal[2])); + pixelresult = rgb_to_cpack( + linearrgb_to_srgb(color[0]), + linearrgb_to_srgb(color[1]), + linearrgb_to_srgb(color[2])) | alphamask; } + rect[offset++] = pixelresult; } - return rect; } -#endif + return rect; } /* API */ @@ -800,14 +845,19 @@ void BKE_studiolight_init(void) /* order studio lights by name */ /* Also reserve icon space for it. */ /* Add default studio light */ - sl = studiolight_create(STUDIOLIGHT_INTERNAL | STUDIOLIGHT_DIFFUSE_LIGHT_CALCULATED | STUDIOLIGHT_ORIENTATION_CAMERA); + sl = studiolight_create(STUDIOLIGHT_INTERNAL | STUDIOLIGHT_SPHERICAL_HARMONICS_COEFFICIENTS_CALCULATED | STUDIOLIGHT_ORIENTATION_CAMERA); BLI_strncpy(sl->name, "INTERNAL_01", FILE_MAXFILE); - copy_v3_fl(sl->diffuse_light[STUDIOLIGHT_X_POS], 1.5f); - copy_v3_fl(sl->diffuse_light[STUDIOLIGHT_X_NEG], 0.0f); - copy_v3_fl(sl->diffuse_light[STUDIOLIGHT_Y_POS], 0.8f); - copy_v3_fl(sl->diffuse_light[STUDIOLIGHT_Y_NEG], 0.05f); - copy_v3_fl(sl->diffuse_light[STUDIOLIGHT_Z_POS], 0.2f); - copy_v3_fl3(sl->diffuse_light[STUDIOLIGHT_Z_NEG], 0.1f, 0.0f, 0.0f); + + copy_v3_fl3(sl->spherical_harmonics_coefs[0], 1.03271556f, 1.07163882f, 1.11193657f); + copy_v3_fl3(sl->spherical_harmonics_coefs[1], -0.00480952f, 0.05290511f, 0.16394117f); + copy_v3_fl3(sl->spherical_harmonics_coefs[2], -0.29686999f, -0.27378261f, -0.24797194f); + copy_v3_fl3(sl->spherical_harmonics_coefs[3], 0.47932500f, 0.48242140f, 0.47190312f); + copy_v3_fl3(sl->spherical_harmonics_coefs[4], -0.00576984f, 0.00504886f, 0.01640534f); + copy_v3_fl3(sl->spherical_harmonics_coefs[5], 0.15500379f, 0.15415503f, 0.16244425f); + copy_v3_fl3(sl->spherical_harmonics_coefs[6], -0.02483751f, -0.02245096f, -0.00536885f); + copy_v3_fl3(sl->spherical_harmonics_coefs[7], 0.11155496f, 0.11005443f, 0.10839636f); + copy_v3_fl3(sl->spherical_harmonics_coefs[8], 0.01363425f, 0.01278363f, -0.00159006f); + BLI_addtail(&studiolights, sl); studiolight_add_files_from_datafolder(BLENDER_SYSTEM_DATAFILES, STUDIOLIGHT_CAMERA_FOLDER, STUDIOLIGHT_ORIENTATION_CAMERA); @@ -899,7 +949,7 @@ void BKE_studiolight_ensure_flag(StudioLight *sl, int flag) if ((flag & STUDIOLIGHT_RADIANCE_BUFFERS_CALCULATED)) { studiolight_calculate_radiance_cubemap_buffers(sl); } - if ((flag & STUDIOLIGHT_DIFFUSE_LIGHT_CALCULATED)) { + if ((flag & STUDIOLIGHT_SPHERICAL_HARMONICS_COEFFICIENTS_CALCULATED)) { studiolight_calculate_diffuse_light(sl); } if ((flag & STUDIOLIGHT_EQUIRECTANGULAR_RADIANCE_GPUTEXTURE)) { diff --git a/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl index 069cb0f52d8..2ba6e0e8e55 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl @@ -4,12 +4,7 @@ struct LightData { }; struct WorldData { - vec4 diffuse_light_x_pos; - vec4 diffuse_light_x_neg; - vec4 diffuse_light_y_pos; - vec4 diffuse_light_y_neg; - vec4 diffuse_light_z_pos; - vec4 diffuse_light_z_neg; + vec3 spherical_harmonics_coefs[9]; vec4 background_color_low; vec4 background_color_high; vec4 object_outline_color; diff --git a/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl index 9d256e5350a..71adc751f0a 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl @@ -1,24 +1,32 @@ #define BLINN +vec3 spherical_harmonics_L2(vec3 N, vec3 spherical_harmonics_coefs[9]) +{ + vec3 sh = vec3(0.0); + + sh += 0.282095 * spherical_harmonics_coefs[0]; + + sh += -0.488603 * N.z * spherical_harmonics_coefs[1]; + sh += 0.488603 * N.y * spherical_harmonics_coefs[2]; + sh += -0.488603 * N.x * spherical_harmonics_coefs[3]; + + sh += 1.092548 * N.x * N.z * spherical_harmonics_coefs[4]; + sh += -1.092548 * N.z * N.y * spherical_harmonics_coefs[5]; + sh += 0.315392 * (3.0 * N.y * N.y - 1.0) * spherical_harmonics_coefs[6]; + sh += -1.092548 * N.x * N.y * spherical_harmonics_coefs[7]; + sh += 0.546274 * (N.x * N.x - N.z * N.z) * spherical_harmonics_coefs[8]; + + return sh; +} + vec3 get_world_diffuse_light(WorldData world_data, vec3 N) { - vec4 result = world_data.diffuse_light_x_pos * clamp(N.x, 0.0, 1.0); - result = mix(result, world_data.diffuse_light_x_neg, clamp(-N.x, 0.0, 1.0)); - result = mix(result, world_data.diffuse_light_y_pos, clamp(-N.y, 0.0, 1.0)); - result = mix(result, world_data.diffuse_light_y_neg, clamp(N.y, 0.0, 1.0)); - result = mix(result, world_data.diffuse_light_z_pos, clamp(N.z, 0.0, 1.0)); - return mix(result, world_data.diffuse_light_z_neg, clamp(-N.z, 0.0, 1.0)).xyz; + return (spherical_harmonics_L2(vec3(N.x, N.y, -N.z), world_data.spherical_harmonics_coefs)); } vec3 get_camera_diffuse_light(WorldData world_data, vec3 N) { - vec4 result = world_data.diffuse_light_x_pos * clamp(N.x, 0.0, 1.0); - result = mix(result, world_data.diffuse_light_x_neg, clamp(-N.x, 0.0, 1.0)); - result = mix(result, world_data.diffuse_light_z_pos, clamp( N.y, 0.0, 1.0)); - result = mix(result, world_data.diffuse_light_z_neg, clamp(-N.y, 0.0, 1.0)); - result = mix(result, world_data.diffuse_light_y_pos, clamp( N.z, 0.0, 1.0)); - result = mix(result, world_data.diffuse_light_y_neg, clamp(-N.z, 0.0, 1.0)); - return result.rgb; + return (spherical_harmonics_L2(vec3(N.x, -N.z, -N.y), world_data.spherical_harmonics_coefs)); } /* N And I are in View Space. */ diff --git a/source/blender/draw/engines/workbench/workbench_data.c b/source/blender/draw/engines/workbench/workbench_data.c index 45af9366a43..b4a2330f173 100644 --- a/source/blender/draw/engines/workbench/workbench_data.c +++ b/source/blender/draw/engines/workbench/workbench_data.c @@ -118,7 +118,6 @@ void workbench_private_data_init(WORKBENCH_PrivateData *wpd) wpd->viewvecs[1][2] = vec_far[2] - wpd->viewvecs[0][2]; } } - } void workbench_private_data_get_light_direction(WORKBENCH_PrivateData *wpd, float light_direction[3]) @@ -154,20 +153,8 @@ void workbench_private_data_get_light_direction(WORKBENCH_PrivateData *wpd, floa wd->num_lights = light_index; } -#if 0 - if (STUDIOLIGHT_ORIENTATION_WORLD_ENABLED(wpd)) { - BKE_studiolight_ensure_flag(wpd->studio_light, STUDIOLIGHT_LIGHT_DIRECTION_CALCULATED); - float rot_matrix[3][3]; - axis_angle_to_mat3_single(rot_matrix, 'Z', wpd->shading.studiolight_rot_z); - mul_v3_m3v3(e_data.display.light_direction, rot_matrix, wpd->studio_light->light_direction); - } - else { -#else - { -#endif - copy_v3_v3(light_direction, scene->display.light_direction); - negate_v3(light_direction); - } + copy_v3_v3(light_direction, scene->display.light_direction); + negate_v3(light_direction); DRW_uniformbuffer_update(wpd->world_ubo, &wpd->world_data); } diff --git a/source/blender/draw/engines/workbench/workbench_private.h b/source/blender/draw/engines/workbench/workbench_private.h index 90d8cfc3dd2..9e43a5c4a48 100644 --- a/source/blender/draw/engines/workbench/workbench_private.h +++ b/source/blender/draw/engines/workbench/workbench_private.h @@ -112,12 +112,7 @@ typedef struct WORKBENCH_UBO_Light { } WORKBENCH_UBO_Light; typedef struct WORKBENCH_UBO_World { - float diffuse_light_x_pos[4]; - float diffuse_light_x_neg[4]; - float diffuse_light_y_pos[4]; - float diffuse_light_y_neg[4]; - float diffuse_light_z_pos[4]; - float diffuse_light_z_neg[4]; + float spherical_harmonics_coefs[9][4]; float background_color_low[4]; float background_color_high[4]; float object_outline_color[4]; diff --git a/source/blender/draw/engines/workbench/workbench_studiolight.c b/source/blender/draw/engines/workbench/workbench_studiolight.c index 6451d1f57c8..e5e24cbb88a 100644 --- a/source/blender/draw/engines/workbench/workbench_studiolight.c +++ b/source/blender/draw/engines/workbench/workbench_studiolight.c @@ -34,14 +34,10 @@ void studiolight_update_world(StudioLight *sl, WORKBENCH_UBO_World *wd) { - BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_DIFFUSE_LIGHT_CALCULATED); - - copy_v3_v3(wd->diffuse_light_x_pos, sl->diffuse_light[STUDIOLIGHT_X_POS]); - copy_v3_v3(wd->diffuse_light_x_neg, sl->diffuse_light[STUDIOLIGHT_X_NEG]); - copy_v3_v3(wd->diffuse_light_y_pos, sl->diffuse_light[STUDIOLIGHT_Y_POS]); - copy_v3_v3(wd->diffuse_light_y_neg, sl->diffuse_light[STUDIOLIGHT_Y_NEG]); - copy_v3_v3(wd->diffuse_light_z_pos, sl->diffuse_light[STUDIOLIGHT_Z_POS]); - copy_v3_v3(wd->diffuse_light_z_neg, sl->diffuse_light[STUDIOLIGHT_Z_NEG]); + BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_SPHERICAL_HARMONICS_COEFFICIENTS_CALCULATED); + for (int i = 0; i < 9; i++) { + copy_v3_v3(wd->spherical_harmonics_coefs[i], sl->spherical_harmonics_coefs[i]); + } } 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/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 4558cd9c053..60a6e55f700 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -674,7 +674,7 @@ static PointerRNA rna_View3DShading_selected_studio_light_get(PointerRNA *ptr) { View3D *v3d = (View3D *)ptr->data; StudioLight *sl; - if (v3d->shading.light == V3D_LIGHTING_MATCAP) { + if (v3d->drawtype == OB_SOLID && v3d->shading.light == V3D_LIGHTING_MATCAP) { sl = BKE_studiolight_find(v3d->shading.matcap, STUDIOLIGHT_FLAG_ALL); } else { |