[Bf-blender-cvs] [66700196074] master: Workbench: Specular Highlighting for MatCaps
Jeroen Bakker
noreply at git.blender.org
Tue Aug 27 08:58:48 CEST 2019
Commit: 66700196074ad168f3322f2766846a0a07f7a00f
Author: Jeroen Bakker
Date: Tue Aug 27 08:42:50 2019 +0200
Branches: master
https://developer.blender.org/rB66700196074ad168f3322f2766846a0a07f7a00f
Workbench: Specular Highlighting for MatCaps
With Blender 2.80 we introduced a more flexible matcap system. One
change we did was to multiply the matcap with the base color that was
shaded. As matcaps contains diffuse and specular lighting in a single
texture this lead to rendering artifacts. Artists were complaining that
everything looked to metalic.
We now support a separate `diffuse` and `specular` pass for matcaps.
`shaded_color = diffuse_light * base_color + specular_light`
For matcaps to support this feature they need to be multilayer openexr
files with 2 renderpasses (named `diffuse` and `specular`). In the future
we can change this to first pass/second pass in stead of this naming
convention.
Reviewed By: fclem, brecht
Differential Revision: https://developer.blender.org/D5335
===================================================================
M release/scripts/startup/bl_ui/space_view3d.py
M source/blender/blenkernel/BKE_studiolight.h
M source/blender/blenkernel/intern/studiolight.c
M source/blender/draw/engines/workbench/shaders/workbench_deferred_composite_frag.glsl
M source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl
M source/blender/draw/engines/workbench/workbench_deferred.c
M source/blender/draw/engines/workbench/workbench_forward.c
M source/blender/draw/engines/workbench/workbench_materials.c
M source/blender/draw/engines/workbench/workbench_private.h
M source/blender/gpu/intern/gpu_draw.c
M source/blender/imbuf/IMB_imbuf.h
M source/blender/imbuf/intern/allocimbuf.c
M source/blender/makesrna/intern/rna_userdef.c
===================================================================
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index 20d3e83bf79..ae2a2ce3e7c 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -5251,8 +5251,10 @@ class VIEW3D_PT_shading_options(Panel):
sub.active = shading.show_object_outline
sub.prop(shading, "object_outline_color", text="")
+ if shading.type == 'SOLID':
col = layout.column()
- if (shading.light == 'STUDIO') and (shading.type != 'WIREFRAME'):
+ if (shading.light in ['STUDIO', 'MATCAP']):
+ col.active = shading.selected_studio_light.has_specular_highlight_pass
col.prop(shading, "show_specular_highlight", text="Specular Lighting")
diff --git a/source/blender/blenkernel/BKE_studiolight.h b/source/blender/blenkernel/BKE_studiolight.h
index d6fff528348..108e93d9caa 100644
--- a/source/blender/blenkernel/BKE_studiolight.h
+++ b/source/blender/blenkernel/BKE_studiolight.h
@@ -87,6 +87,11 @@ enum StudioLightFlag {
STUDIOLIGHT_RADIANCE_BUFFERS_CALCULATED = (1 << 11),
STUDIOLIGHT_USER_DEFINED = (1 << 12),
STUDIOLIGHT_UI_EXPANDED = (1 << 13),
+
+ STUDIOLIGHT_MATCAP_DIFFUSE_GPUTEXTURE = (1 << 14),
+ STUDIOLIGHT_MATCAP_SPECULAR_GPUTEXTURE = (1 << 15),
+ /* Is set for studio lights and matcaps with specular highlight pass. */
+ STUDIOLIGHT_SPECULAR_HIGHLIGHT_PASS = (1 << 16),
};
#define STUDIOLIGHT_FLAG_ALL (STUDIOLIGHT_INTERNAL | STUDIOLIGHT_EXTERNAL_FILE)
@@ -97,6 +102,11 @@ enum StudioLightFlag {
typedef void StudioLightFreeFunction(struct StudioLight *, void *data);
+typedef struct StudioLightImage {
+ ImBuf *ibuf;
+ struct GPUTexture *gputexture;
+} StudioLightImage;
+
typedef struct StudioLight {
struct StudioLight *next, *prev;
@@ -112,6 +122,8 @@ typedef struct StudioLight {
int icon_id_matcap_flipped;
float spherical_harmonics_coefs[STUDIOLIGHT_SH_EFFECTIVE_COEFS_LEN][3];
float light_direction[3];
+ StudioLightImage matcap_diffuse;
+ StudioLightImage matcap_specular;
ImBuf *equirect_radiance_buffer;
ImBuf *equirect_irradiance_buffer;
ImBuf *radiance_cubemap_buffers[6];
diff --git a/source/blender/blenkernel/intern/studiolight.c b/source/blender/blenkernel/intern/studiolight.c
index 6e83f5d75e2..8466f9eaa98 100644
--- a/source/blender/blenkernel/intern/studiolight.c
+++ b/source/blender/blenkernel/intern/studiolight.c
@@ -46,13 +46,16 @@
#include "MEM_guardedalloc.h"
+#include "intern/openexr/openexr_multi.h"
+
/* Statics */
static ListBase studiolights;
static int last_studiolight_id = 0;
#define STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE 96
#define STUDIOLIGHT_IRRADIANCE_EQUIRECT_HEIGHT 32
#define STUDIOLIGHT_IRRADIANCE_EQUIRECT_WIDTH (STUDIOLIGHT_IRRADIANCE_EQUIRECT_HEIGHT * 2)
-
+#define STUDIOLIGHT_PASSNAME_DIFFUSE "diffuse"
+#define STUDIOLIGHT_PASSNAME_SPECULAR "specular"
/*
* The method to calculate the irradiance buffers
* The irradiance buffer is only shown in the background when in LookDev.
@@ -152,6 +155,10 @@ static void studiolight_free(struct StudioLight *sl)
GPU_TEXTURE_SAFE_FREE(sl->equirect_irradiance_gputexture);
IMB_SAFE_FREE(sl->equirect_radiance_buffer);
IMB_SAFE_FREE(sl->equirect_irradiance_buffer);
+ GPU_TEXTURE_SAFE_FREE(sl->matcap_diffuse.gputexture);
+ GPU_TEXTURE_SAFE_FREE(sl->matcap_specular.gputexture);
+ IMB_SAFE_FREE(sl->matcap_diffuse.ibuf);
+ IMB_SAFE_FREE(sl->matcap_specular.ibuf);
MEM_SAFE_FREE(sl->path_irr_cache);
MEM_SAFE_FREE(sl->path_sh_cache);
MEM_SAFE_FREE(sl);
@@ -342,72 +349,232 @@ static void cube_face_uv_to_direction(float r_dir[3], float x, float y, int face
normalize_v3(r_dir);
}
+typedef struct MultilayerConvertContext {
+ int num_diffuse_channels;
+ float *diffuse_pass;
+ int num_specular_channels;
+ float *specular_pass;
+} MultilayerConvertContext;
+
+static void *studiolight_multilayer_addview(void *UNUSED(base), const char *UNUSED(view_name))
+{
+ return NULL;
+}
+static void *studiolight_multilayer_addlayer(void *base, const char *UNUSED(layer_name))
+{
+ return base;
+}
+
+/* Convert a multilayer pass to ImBuf channel 4 float buffer.
+ * NOTE: Parameter rect will become invalid. Do not use rect after calling this
+ * function */
+static float *studiolight_multilayer_convert_pass(ImBuf *ibuf,
+ float *rect,
+ const unsigned int channels)
+{
+ if (channels == 4) {
+ return rect;
+ }
+ else {
+ float *new_rect = MEM_callocN(sizeof(float[4]) * ibuf->x * ibuf->y, __func__);
+
+ IMB_buffer_float_from_float(new_rect,
+ rect,
+ channels,
+ IB_PROFILE_LINEAR_RGB,
+ IB_PROFILE_LINEAR_RGB,
+ false,
+ ibuf->x,
+ ibuf->y,
+ ibuf->x,
+ ibuf->x);
+
+ MEM_freeN(rect);
+ return new_rect;
+ }
+}
+
+static void studiolight_multilayer_addpass(void *base,
+ void *UNUSED(lay),
+ const char *pass_name,
+ float *rect,
+ int num_channels,
+ const char *UNUSED(chan_id),
+ const char *UNUSED(view_name))
+{
+ MultilayerConvertContext *ctx = base;
+ /* NOTE: This function must free pass pixels data if it is not used, this
+ * is how IMB_exr_multilayer_convert() is working. */
+ /* If we've found a first combined pass, skip all the rest ones. */
+ if (STREQ(pass_name, STUDIOLIGHT_PASSNAME_DIFFUSE)) {
+ ctx->diffuse_pass = rect;
+ ctx->num_diffuse_channels = num_channels;
+ }
+ else if (STREQ(pass_name, STUDIOLIGHT_PASSNAME_SPECULAR)) {
+ ctx->specular_pass = rect;
+ ctx->num_specular_channels = num_channels;
+ }
+ else {
+ MEM_freeN(rect);
+ }
+}
+
static void studiolight_load_equirect_image(StudioLight *sl)
{
if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
- ImBuf *ibuf = NULL;
- ibuf = IMB_loadiffname(sl->path, 0, NULL);
- if (ibuf == NULL) {
- float *colbuf = MEM_mallocN(sizeof(float[4]), __func__);
- copy_v4_fl4(colbuf, 1.0f, 0.0f, 1.0f, 1.0f);
- ibuf = IMB_allocFromBuffer(NULL, colbuf, 1, 1);
+ ImBuf *ibuf = IMB_loadiffname(sl->path, IB_multilayer, NULL);
+ ImBuf *specular_ibuf = NULL;
+ ImBuf *diffuse_ibuf = NULL;
+ const bool failed = (ibuf == NULL);
+
+ if (ibuf) {
+ if (ibuf->ftype == IMB_FTYPE_OPENEXR && ibuf->userdata) {
+ /* the read file is a multilayered openexr file (userdata != NULL)
+ * This file is currently only supported for MATCAPS where
+ * the first found 'diffuse' pass will be used for diffuse lighting
+ * and the first found 'specular' pass will be used for specular lighting */
+ MultilayerConvertContext ctx = {};
+ IMB_exr_multilayer_convert(ibuf->userdata,
+ &ctx,
+ &studiolight_multilayer_addview,
+ &studiolight_multilayer_addlayer,
+ &studiolight_multilayer_addpass);
+
+ /* `ctx.diffuse_pass` and `ctx.specular_pass` can be freed inside
+ * `studiolight_multilayer_convert_pass` when conversion happens.
+ * When not converted we move the ownership of the buffer to the
+ * `converted_pass`. We only need to free `converted_pass` as it holds
+ * the unmodified allocation from the `ctx.*_pass` or the converted data.
+ */
+ if (ctx.diffuse_pass != NULL) {
+ float *converted_pass = studiolight_multilayer_convert_pass(
+ ibuf, ctx.diffuse_pass, ctx.num_diffuse_channels);
+ diffuse_ibuf = IMB_allocFromBuffer(
+ NULL, converted_pass, ibuf->x, ibuf->y, ctx.num_diffuse_channels);
+ MEM_freeN(converted_pass);
+ }
+
+ if (ctx.specular_pass != NULL) {
+ float *converted_pass = studiolight_multilayer_convert_pass(
+ ibuf, ctx.specular_pass, ctx.num_specular_channels);
+ specular_ibuf = IMB_allocFromBuffer(
+ NULL, converted_pass, ibuf->x, ibuf->y, ctx.num_specular_channels);
+ MEM_freeN(converted_pass);
+ }
+
+ IMB_exr_close(ibuf->userdata);
+ ibuf->userdata = NULL;
+ IMB_freeImBuf(ibuf);
+ ibuf = NULL;
+ }
+ else {
+ /* read file is an single layer openexr file or the read file isn't
+ * an openexr file */
+ IMB_float_from_rect(ibuf);
+ diffuse_ibuf = ibuf;
+ ibuf = NULL;
+ }
+ }
+
+ if (diffuse_ibuf == NULL) {
+ /* Create 1x1 diffuse buffer, in case image failed to load or if there was
+ * only a specular pass in the multilayer file or no passes were found. */
+ const float black[4] = {0.0f, 0.0f, 0.0f, 1.0f};
+ const float magenta[4] = {1.0f, 0.0f, 1.0f, 1.0f};
+ diffuse_ibuf = IMB_allocFromBuffer(
+ NULL, (failed || (specular_ibuf == NULL)) ? magenta : black, 1, 1, 4);
+ }
+
+ if ((sl->flag & STUDIOLIGHT_TYPE_MATCAP)) {
+ sl->matcap_diffuse.ibuf = diffuse_ibuf;
+ sl->matcap_specular.ibuf = specular_ibuf;
+ if (specular_ibuf != NULL) {
+ sl->flag |= STUDIOLIGHT_SPECULAR_HIGHLIGHT_PASS;
+ }
+ }
+ else {
+ sl->equirect_radiance_buffer = diffuse_ibuf;
+ if (specular_ibuf != NULL) {
+ IMB_freeImBuf(specular_ibuf);
+ }
}
- IMB_float_from_rect(ibuf);
- sl->equirect_radiance_buffer = ibuf;
}
+
sl->flag |= STUDIOLIGHT_EXTERNAL_IMAGE_LOADED;
}
static void studiolight_create_equirect_radiance_gputexture(StudioLight *sl)
{
if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
- char error[256];
BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EXTERNAL_IMAGE_LOADED);
ImBuf *ibuf = sl->equirect
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list