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
path: root/source
diff options
context:
space:
mode:
authorClément Foucault <foucault.clem@gmail.com>2017-06-13 18:39:39 +0300
committerClément Foucault <foucault.clem@gmail.com>2017-06-15 01:53:41 +0300
commitdccf46f18ffe741ae5f0193b75d4a5688096cf9a (patch)
tree0fc27ad6908b27d4cc0b3bfc65dd8f4d52e84183 /source
parent8e5609665fefb004ce2e759a49e063479cf01b3d (diff)
Eevee: Add Irradiance Grid support
Early implementation. Slow and still has quality 3 ways of storing irradiance: - Spherical Harmonics: Have problem with directionnal lighting. - HL2 diffuse cube: Very low resolution but smooth transitions. - Diffuse cube: High storage requirement. Also include some name change.
Diffstat (limited to 'source')
-rw-r--r--source/blender/draw/CMakeLists.txt4
-rw-r--r--source/blender/draw/engines/eevee/eevee_data.c4
-rw-r--r--source/blender/draw/engines/eevee/eevee_lightprobes.c377
-rw-r--r--source/blender/draw/engines/eevee/eevee_materials.c41
-rw-r--r--source/blender/draw/engines/eevee/eevee_private.h32
-rw-r--r--source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl85
-rw-r--r--source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl19
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl197
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl (renamed from source/blender/draw/engines/eevee/shaders/lightprobe_filter_frag.glsl)0
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_sh_frag.glsl107
-rw-r--r--source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl150
-rw-r--r--source/blender/draw/intern/DRW_render.h2
-rw-r--r--source/blender/draw/intern/draw_manager.c4
13 files changed, 786 insertions, 236 deletions
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index 35df504fa58..48d502eb342 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -118,8 +118,8 @@ data_to_c_simple(engines/clay/shaders/ssao_groundtruth.glsl SRC)
data_to_c_simple(engines/eevee/shaders/default_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/default_world_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/background_vert.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/lightprobe_filter_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/lightprobe_sh_frag.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/lightprobe_geom.glsl SRC)
data_to_c_simple(engines/eevee/shaders/lightprobe_vert.glsl SRC)
data_to_c_simple(engines/eevee/shaders/lit_surface_frag.glsl SRC)
diff --git a/source/blender/draw/engines/eevee/eevee_data.c b/source/blender/draw/engines/eevee/eevee_data.c
index 52dc35b4977..5639250a076 100644
--- a/source/blender/draw/engines/eevee/eevee_data.c
+++ b/source/blender/draw/engines/eevee/eevee_data.c
@@ -53,13 +53,13 @@ static void eevee_scene_layer_data_free(void *storage)
/* Probes */
MEM_SAFE_FREE(sldata->probes);
DRW_UBO_FREE_SAFE(sldata->probe_ubo);
+ DRW_UBO_FREE_SAFE(sldata->grid_ubo);
DRW_FRAMEBUFFER_FREE_SAFE(sldata->probe_fb);
DRW_FRAMEBUFFER_FREE_SAFE(sldata->probe_filter_fb);
- DRW_FRAMEBUFFER_FREE_SAFE(sldata->probe_sh_fb);
DRW_TEXTURE_FREE_SAFE(sldata->probe_rt);
DRW_TEXTURE_FREE_SAFE(sldata->probe_depth_rt);
DRW_TEXTURE_FREE_SAFE(sldata->probe_pool);
- DRW_TEXTURE_FREE_SAFE(sldata->probe_sh);
+ DRW_TEXTURE_FREE_SAFE(sldata->irradiance_pool);
}
static void eevee_lamp_data_free(void *storage)
diff --git a/source/blender/draw/engines/eevee/eevee_lightprobes.c b/source/blender/draw/engines/eevee/eevee_lightprobes.c
index 1acdd50635e..53cd49abf78 100644
--- a/source/blender/draw/engines/eevee/eevee_lightprobes.c
+++ b/source/blender/draw/engines/eevee/eevee_lightprobes.c
@@ -47,13 +47,14 @@
#include "eevee_private.h"
/* TODO Option */
-#define LIGHTPROBE_TYPE_CUBE_SIZE 512
-#define PROBE_SIZE 1024
+#define PROBE_RT_SIZE 512 /* Cube render target */
+#define PROBE_OCTAHEDRON_SIZE 1024
+#define IRRADIANCE_POOL_SIZE 1024
static struct {
struct GPUShader *probe_default_sh;
- struct GPUShader *probe_filter_sh;
- struct GPUShader *probe_spherical_harmonic_sh;
+ struct GPUShader *probe_filter_glossy_sh;
+ struct GPUShader *probe_filter_diffuse_sh;
struct GPUTexture *hammersley;
@@ -62,8 +63,9 @@ static struct {
} e_data = {NULL}; /* Engine data */
extern char datatoc_default_world_frag_glsl[];
-extern char datatoc_lightprobe_filter_frag_glsl[];
-extern char datatoc_lightprobe_sh_frag_glsl[];
+extern char datatoc_fullscreen_vert_glsl[];
+extern char datatoc_lightprobe_filter_glossy_frag_glsl[];
+extern char datatoc_lightprobe_filter_diffuse_frag_glsl[];
extern char datatoc_lightprobe_geom_glsl[];
extern char datatoc_lightprobe_vert_glsl[];
extern char datatoc_bsdf_common_lib_glsl[];
@@ -104,17 +106,18 @@ static struct GPUTexture *create_hammersley_sample_texture(int samples)
void EEVEE_lightprobes_init(EEVEE_SceneLayerData *sldata)
{
- if (!e_data.probe_filter_sh) {
+ /* Shaders */
+ if (!e_data.probe_filter_glossy_sh) {
char *shader_str = NULL;
DynStr *ds_frag = BLI_dynstr_new();
BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl);
BLI_dynstr_append(ds_frag, datatoc_bsdf_sampling_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_lightprobe_filter_frag_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_lightprobe_filter_glossy_frag_glsl);
shader_str = BLI_dynstr_get_cstring(ds_frag);
BLI_dynstr_free(ds_frag);
- e_data.probe_filter_sh = DRW_shader_create(
+ e_data.probe_filter_glossy_sh = DRW_shader_create(
datatoc_lightprobe_vert_glsl, datatoc_lightprobe_geom_glsl, shader_str,
"#define HAMMERSLEY_SIZE 1024\n"
"#define NOISE_SIZE 64\n");
@@ -123,34 +126,47 @@ void EEVEE_lightprobes_init(EEVEE_SceneLayerData *sldata)
datatoc_lightprobe_vert_glsl, datatoc_lightprobe_geom_glsl, datatoc_default_world_frag_glsl, NULL);
MEM_freeN(shader_str);
- }
- /* Shaders */
- if (!e_data.hammersley) {
+ ds_frag = BLI_dynstr_new();
+ BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_bsdf_sampling_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_lightprobe_filter_diffuse_frag_glsl);
+ shader_str = BLI_dynstr_get_cstring(ds_frag);
+ BLI_dynstr_free(ds_frag);
+
+ e_data.probe_filter_diffuse_sh = DRW_shader_create_fullscreen(
+ shader_str,
+#if defined(IRRADIANCE_SH_L2)
+ "#define IRRADIANCE_SH_L2\n"
+#elif defined(IRRADIANCE_CUBEMAP)
+ "#define IRRADIANCE_CUBEMAP\n"
+#elif defined(IRRADIANCE_HL2)
+ "#define IRRADIANCE_HL2\n"
+#endif
+ "#define HAMMERSLEY_SIZE 1024\n"
+ "#define NOISE_SIZE 64\n");
+
+ MEM_freeN(shader_str);
+
e_data.hammersley = create_hammersley_sample_texture(1024);
- e_data.probe_spherical_harmonic_sh = DRW_shader_create_fullscreen(datatoc_lightprobe_sh_frag_glsl, NULL);
}
if (!sldata->probes) {
sldata->probes = MEM_callocN(sizeof(EEVEE_LightProbesInfo), "EEVEE_LightProbesInfo");
sldata->probe_ubo = DRW_uniformbuffer_create(sizeof(EEVEE_LightProbe) * MAX_PROBE, NULL);
+ sldata->grid_ubo = DRW_uniformbuffer_create(sizeof(EEVEE_LightGrid) * MAX_GRID, NULL);
}
/* Setup Render Target Cubemap */
if (!sldata->probe_rt) {
- sldata->probe_rt = DRW_texture_create_cube(LIGHTPROBE_TYPE_CUBE_SIZE, DRW_TEX_RGBA_16, DRW_TEX_FILTER | DRW_TEX_MIPMAP, NULL);
- sldata->probe_depth_rt = DRW_texture_create_cube(LIGHTPROBE_TYPE_CUBE_SIZE, DRW_TEX_DEPTH_24, DRW_TEX_FILTER, NULL);
+ sldata->probe_rt = DRW_texture_create_cube(PROBE_RT_SIZE, DRW_TEX_RGBA_16, DRW_TEX_FILTER | DRW_TEX_MIPMAP, NULL);
+ sldata->probe_depth_rt = DRW_texture_create_cube(PROBE_RT_SIZE, DRW_TEX_DEPTH_24, DRW_TEX_FILTER, NULL);
}
DRWFboTexture tex_probe[2] = {{&sldata->probe_depth_rt, DRW_TEX_DEPTH_24, DRW_TEX_FILTER},
{&sldata->probe_rt, DRW_TEX_RGBA_16, DRW_TEX_FILTER | DRW_TEX_MIPMAP}};
- DRW_framebuffer_init(&sldata->probe_fb, &draw_engine_eevee_type, LIGHTPROBE_TYPE_CUBE_SIZE, LIGHTPROBE_TYPE_CUBE_SIZE, tex_probe, 2);
-
- /* Spherical Harmonic Buffer */
- DRWFboTexture tex_sh = {&sldata->probe_sh, DRW_TEX_RGBA_16, DRW_TEX_FILTER | DRW_TEX_MIPMAP};
-
- DRW_framebuffer_init(&sldata->probe_sh_fb, &draw_engine_eevee_type, 9, 1, &tex_sh, 1);
+ DRW_framebuffer_init(&sldata->probe_fb, &draw_engine_eevee_type, PROBE_RT_SIZE, PROBE_RT_SIZE, tex_probe, 2);
}
void EEVEE_lightprobes_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl)
@@ -158,7 +174,9 @@ void EEVEE_lightprobes_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_PassList *
EEVEE_LightProbesInfo *pinfo = sldata->probes;
pinfo->num_cube = 1; /* at least one for the world */
- memset(pinfo->probes_ref, 0, sizeof(pinfo->probes_ref));
+ pinfo->num_grid = 0;
+ memset(pinfo->probes_cube_ref, 0, sizeof(pinfo->probes_cube_ref));
+ memset(pinfo->probes_grid_ref, 0, sizeof(pinfo->probes_grid_ref));
{
psl->probe_background = DRW_pass_create("World Probe Pass", DRW_STATE_WRITE_COLOR);
@@ -212,11 +230,11 @@ void EEVEE_lightprobes_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_PassList *
}
{
- psl->probe_prefilter = DRW_pass_create("LightProbe Filtering", DRW_STATE_WRITE_COLOR);
+ psl->probe_glossy_compute = DRW_pass_create("LightProbe Glossy Compute", DRW_STATE_WRITE_COLOR);
struct Batch *geom = DRW_cache_fullscreen_quad_get();
- DRWShadingGroup *grp = DRW_shgroup_instance_create(e_data.probe_filter_sh, psl->probe_prefilter, geom);
+ DRWShadingGroup *grp = DRW_shgroup_instance_create(e_data.probe_filter_glossy_sh, psl->probe_glossy_compute, geom);
DRW_shgroup_uniform_float(grp, "sampleCount", &sldata->probes->samples_ct, 1);
DRW_shgroup_uniform_float(grp, "invSampleCount", &sldata->probes->invsamples_ct, 1);
DRW_shgroup_uniform_float(grp, "roughnessSquared", &sldata->probes->roughness, 1);
@@ -233,11 +251,17 @@ void EEVEE_lightprobes_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_PassList *
}
{
- psl->probe_sh_compute = DRW_pass_create("LightProbe SH Compute", DRW_STATE_WRITE_COLOR);
+ psl->probe_diffuse_compute = DRW_pass_create("LightProbe Diffuse Compute", DRW_STATE_WRITE_COLOR);
- DRWShadingGroup *grp = DRW_shgroup_create(e_data.probe_spherical_harmonic_sh, psl->probe_sh_compute);
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.probe_filter_diffuse_sh, psl->probe_diffuse_compute);
+#ifdef IRRADIANCE_SH_L2
DRW_shgroup_uniform_int(grp, "probeSize", &sldata->probes->shres, 1);
- DRW_shgroup_uniform_float(grp, "lodBias", &sldata->probes->lodfactor, 1);
+#else
+ DRW_shgroup_uniform_float(grp, "sampleCount", &sldata->probes->samples_ct, 1);
+ DRW_shgroup_uniform_float(grp, "invSampleCount", &sldata->probes->invsamples_ct, 1);
+ DRW_shgroup_uniform_float(grp, "lodFactor", &sldata->probes->lodfactor, 1);
+ DRW_shgroup_uniform_float(grp, "lodMax", &sldata->probes->lodmax, 1);
+#endif
DRW_shgroup_uniform_texture(grp, "probeHdr", sldata->probe_rt);
struct Batch *geom = DRW_cache_fullscreen_quad_get();
@@ -248,26 +272,34 @@ void EEVEE_lightprobes_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_PassList *
void EEVEE_lightprobes_cache_add(EEVEE_SceneLayerData *sldata, Object *ob)
{
EEVEE_LightProbesInfo *pinfo = sldata->probes;
+ LightProbe *probe = (LightProbe *)ob->data;
/* Step 1 find all lamps in the scene and setup them */
- if (pinfo->num_cube > MAX_PROBE) {
+ if ((probe->type == LIGHTPROBE_TYPE_CUBE && pinfo->num_cube >= MAX_PROBE) ||
+ (probe->type == LIGHTPROBE_TYPE_GRID && pinfo->num_grid >= MAX_PROBE))
+ {
printf("Too much probes in the scene !!!\n");
- pinfo->num_cube = MAX_PROBE;
+ return;
}
- else {
- EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_get(ob);
- if ((ob->deg_update_flag & DEG_RUNTIME_DATA_UPDATE) != 0) {
- ped->need_update = true;
- }
+ EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_get(ob);
- if (e_data.update_world) {
- ped->need_update = true;
- }
+ if ((ob->deg_update_flag & DEG_RUNTIME_DATA_UPDATE) != 0) {
+ ped->need_update = true;
+ }
- pinfo->probes_ref[pinfo->num_cube] = ob;
+ if (e_data.update_world) {
+ ped->need_update = true;
+ }
+
+ if (probe->type == LIGHTPROBE_TYPE_CUBE) {
+ pinfo->probes_cube_ref[pinfo->num_cube] = ob;
pinfo->num_cube++;
}
+ else { /* GRID */
+ pinfo->probes_grid_ref[pinfo->num_grid] = ob;
+ pinfo->num_grid++;
+ }
}
static void EEVEE_lightprobes_updates(EEVEE_SceneLayerData *sldata)
@@ -275,10 +307,13 @@ static void EEVEE_lightprobes_updates(EEVEE_SceneLayerData *sldata)
EEVEE_LightProbesInfo *pinfo = sldata->probes;
Object *ob;
- for (int i = 1; (ob = pinfo->probes_ref[i]) && (i < MAX_PROBE); i++) {
+ for (int i = 1; (ob = pinfo->probes_cube_ref[i]) && (i < MAX_PROBE); i++) {
LightProbe *probe = (LightProbe *)ob->data;
EEVEE_LightProbe *eprobe = &pinfo->probe_data[i];
+ /* Update transforms */
+ copy_v3_v3(eprobe->position, ob->obmat[3]);
+
/* Attenuation */
eprobe->attenuation_type = probe->attenuation_type;
eprobe->attenuation_fac = 1.0f / max_ff(1e-8f, probe->falloff);
@@ -304,6 +339,67 @@ static void EEVEE_lightprobes_updates(EEVEE_SceneLayerData *sldata)
mul_m4_m4m4(eprobe->parallaxmat, ob->obmat, eprobe->parallaxmat);
invert_m4(eprobe->parallaxmat);
}
+
+ int offset = 1; /* to account for the world probe */
+ for (int i = 0; (ob = pinfo->probes_grid_ref[i]) && (i < MAX_GRID); i++) {
+ LightProbe *probe = (LightProbe *)ob->data;
+ EEVEE_LightGrid *egrid = &pinfo->grid_data[i];
+
+ egrid->offset = offset;
+
+ /* Set offset for the next grid */
+ offset += probe->grid_resolution_x * probe->grid_resolution_y * probe->grid_resolution_z;
+
+ /* Update transforms */
+ float tmp[4][4] = {
+ {2.0f, 0.0f, 0.0f, 0.0f},
+ {0.0f, 2.0f, 0.0f, 0.0f},
+ {0.0f, 0.0f, 2.0f, 0.0f},
+ {-1.0f, -1.0f, -1.0f, 1.0f}
+ };
+ float tmp_grid_mat[4][4] = {
+ {1.0f / (float)(probe->grid_resolution_x + 1), 0.0f, 0.0f, 0.0f},
+ {0.0f, 1.0f / (float)(probe->grid_resolution_y + 1), 0.0f, 0.0f},
+ {0.0f, 0.0f, 1.0f / (float)(probe->grid_resolution_z + 1), 0.0f},
+ {0.0f, 0.0f, 0.0f, 1.0f}
+ };
+ mul_m4_m4m4(tmp, tmp, tmp_grid_mat);
+ mul_m4_m4m4(egrid->mat, ob->obmat, tmp);
+ invert_m4(egrid->mat);
+
+ float one_div_res[3];
+ one_div_res[0] = 2.0f / (float)(probe->grid_resolution_x + 1);
+ one_div_res[1] = 2.0f / (float)(probe->grid_resolution_y + 1);
+ one_div_res[2] = 2.0f / (float)(probe->grid_resolution_z + 1);
+
+ /* First cell. */
+ copy_v3_v3(egrid->corner, one_div_res);
+ add_v3_fl(egrid->corner, -1.0f);
+ mul_m4_v3(ob->obmat, egrid->corner);
+
+ /* Opposite neighbor cell. */
+ copy_v3_fl3(egrid->increment_x, one_div_res[0], 0.0f, 0.0f);
+ add_v3_v3(egrid->increment_x, one_div_res);
+ add_v3_fl(egrid->increment_x, -1.0f);
+ mul_m4_v3(ob->obmat, egrid->increment_x);
+ sub_v3_v3(egrid->increment_x, egrid->corner);
+
+ copy_v3_fl3(egrid->increment_y, 0.0f, one_div_res[1], 0.0f);
+ add_v3_v3(egrid->increment_y, one_div_res);
+ add_v3_fl(egrid->increment_y, -1.0f);
+ mul_m4_v3(ob->obmat, egrid->increment_y);
+ sub_v3_v3(egrid->increment_y, egrid->corner);
+
+ copy_v3_fl3(egrid->increment_z, 0.0f, 0.0f, one_div_res[2]);
+ add_v3_v3(egrid->increment_z, one_div_res);
+ add_v3_fl(egrid->increment_z, -1.0f);
+ mul_m4_v3(ob->obmat, egrid->increment_z);
+ sub_v3_v3(egrid->increment_z, egrid->corner);
+
+ copy_v3_v3_int(egrid->resolution, &probe->grid_resolution_x);
+ }
+
+ pinfo->num_render_grid = pinfo->num_grid;
}
void EEVEE_lightprobes_cache_finish(EEVEE_SceneLayerData *sldata)
@@ -318,7 +414,7 @@ void EEVEE_lightprobes_cache_finish(EEVEE_SceneLayerData *sldata)
}
if (!sldata->probe_pool) {
- sldata->probe_pool = DRW_texture_create_2D_array(PROBE_SIZE, PROBE_SIZE, max_ff(1, pinfo->num_cube),
+ sldata->probe_pool = DRW_texture_create_2D_array(PROBE_OCTAHEDRON_SIZE, PROBE_OCTAHEDRON_SIZE, max_ff(1, pinfo->num_cube),
DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER | DRW_TEX_MIPMAP, NULL);
if (sldata->probe_filter_fb) {
DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->probe_pool, 0, 0);
@@ -327,27 +423,35 @@ void EEVEE_lightprobes_cache_finish(EEVEE_SceneLayerData *sldata)
/* Tag probes to refresh */
e_data.update_world = true;
e_data.world_ready_to_shade = false;
- pinfo->num_render_probe = 0;
+ pinfo->num_render_cube = 0;
pinfo->update_flag |= PROBE_UPDATE_CUBE;
pinfo->cache_num_cube = pinfo->num_cube;
- for (int i = 1; (ob = pinfo->probes_ref[i]) && (i < MAX_PROBE); i++) {
+ for (int i = 1; (ob = pinfo->probes_cube_ref[i]) && (i < MAX_PROBE); i++) {
EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_get(ob);
ped->need_update = true;
ped->ready_to_shade = false;
}
}
- DRWFboTexture tex_filter = {&sldata->probe_pool, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER | DRW_TEX_MIPMAP};
+ DRWFboTexture tex_filter = {&sldata->probe_pool, DRW_TEX_RGBA_16, DRW_TEX_FILTER | DRW_TEX_MIPMAP};
- DRW_framebuffer_init(&sldata->probe_filter_fb, &draw_engine_eevee_type, PROBE_SIZE, PROBE_SIZE, &tex_filter, 1);
+ DRW_framebuffer_init(&sldata->probe_filter_fb, &draw_engine_eevee_type, PROBE_OCTAHEDRON_SIZE, PROBE_OCTAHEDRON_SIZE, &tex_filter, 1);
+
+ /* TODO Allocate bigger storage if needed. */
+ if (!sldata->irradiance_pool) {
+ sldata->irradiance_pool = DRW_texture_create_2D(IRRADIANCE_POOL_SIZE, IRRADIANCE_POOL_SIZE, DRW_TEX_RGBA_16, DRW_TEX_FILTER, NULL);
+ pinfo->num_render_grid = 0;
+ }
EEVEE_lightprobes_updates(sldata);
DRW_uniformbuffer_update(sldata->probe_ubo, &sldata->probes->probe_data);
+ DRW_uniformbuffer_update(sldata->grid_ubo, &sldata->probes->grid_data);
}
-static void filter_probe(EEVEE_LightProbe *eprobe, EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl, int probe_idx)
+/* Glossy filter probe_rt to probe_pool at index probe_idx */
+static void glossy_filter_probe(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl, int probe_idx)
{
EEVEE_LightProbesInfo *pinfo = sldata->probes;
@@ -359,8 +463,8 @@ static void filter_probe(EEVEE_LightProbe *eprobe, EEVEE_SceneLayerData *sldata,
/* 3 - Render to probe array to the specified layer, do prefiltering. */
/* Detach to rebind the right mipmap. */
DRW_framebuffer_texture_detach(sldata->probe_pool);
- float mipsize = PROBE_SIZE;
- const int maxlevel = (int)floorf(log2f(PROBE_SIZE));
+ float mipsize = PROBE_OCTAHEDRON_SIZE;
+ const int maxlevel = (int)floorf(log2f(PROBE_OCTAHEDRON_SIZE));
const int min_lod_level = 3;
for (int i = 0; i < maxlevel - min_lod_level; i++) {
float bias = (i == 0) ? 0.0f : 1.0f;
@@ -399,12 +503,12 @@ static void filter_probe(EEVEE_LightProbe *eprobe, EEVEE_SceneLayerData *sldata,
#endif
pinfo->invsamples_ct = 1.0f / pinfo->samples_ct;
- pinfo->lodfactor = bias + 0.5f * log((float)(LIGHTPROBE_TYPE_CUBE_SIZE * LIGHTPROBE_TYPE_CUBE_SIZE) * pinfo->invsamples_ct) / log(2);
- pinfo->lodmax = floorf(log2f(LIGHTPROBE_TYPE_CUBE_SIZE)) - 2.0f;
+ pinfo->lodfactor = bias + 0.5f * log((float)(PROBE_RT_SIZE * PROBE_RT_SIZE) * pinfo->invsamples_ct) / log(2);
+ pinfo->lodmax = floorf(log2f(PROBE_RT_SIZE)) - 2.0f;
DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->probe_pool, 0, i);
- DRW_framebuffer_viewport_size(sldata->probe_filter_fb, mipsize, mipsize);
- DRW_draw_pass(psl->probe_prefilter);
+ DRW_framebuffer_viewport_size(sldata->probe_filter_fb, 0, 0, mipsize, mipsize);
+ DRW_draw_pass(psl->probe_glossy_compute);
DRW_framebuffer_texture_detach(sldata->probe_pool);
mipsize /= 2;
@@ -413,42 +517,83 @@ static void filter_probe(EEVEE_LightProbe *eprobe, EEVEE_SceneLayerData *sldata,
/* For shading, save max level of the octahedron map */
pinfo->lodmax = (float)(maxlevel - min_lod_level) - 1.0f;
+ /* reattach to have a valid framebuffer. */
+ DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->probe_pool, 0, 0);
+}
+
+/* Diffuse filter probe_rt to irradiance_pool at index probe_idx */
+static void diffuse_filter_probe(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl, int cell_idx)
+{
+ EEVEE_LightProbesInfo *pinfo = sldata->probes;
+
+ /* TODO do things properly */
+ float lodmax = pinfo->lodmax;
+
/* 4 - Compute spherical harmonics */
/* Tweaking parameters to balance perf. vs precision */
- pinfo->shres = 16; /* Less texture fetches & reduce branches */
- pinfo->lodfactor = 4.0f; /* Improve cache reuse */
- DRW_framebuffer_bind(sldata->probe_sh_fb);
- DRW_draw_pass(psl->probe_sh_compute);
- DRW_framebuffer_read_data(0, 0, 9, 1, 3, 0, (float *)eprobe->shcoefs);
+ DRW_framebuffer_bind(sldata->probe_filter_fb);
+ DRW_texture_generate_mipmaps(sldata->probe_rt);
+
+ /* Bind the right texture layer (one layer per irradiance grid) */
+ DRW_framebuffer_texture_detach(sldata->probe_pool);
+ DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->irradiance_pool, 0, 0);
+
+ /* find cell position on the virtual 3D texture */
+ /* NOTE : Keep in sync with load_irradiance_cell() */
+#if defined(IRRADIANCE_SH_L2)
+ int size[2] = {3, 3};
+#elif defined(IRRADIANCE_CUBEMAP)
+ int size[2] = {8, 8};
+ pinfo->samples_ct = 1024.0f;
+#elif defined(IRRADIANCE_HL2)
+ int size[2] = {3, 2};
+ pinfo->samples_ct = 1024.0f;
+#endif
+
+ int cell_per_row = IRRADIANCE_POOL_SIZE / size[0];
+ int x = size[0] * (cell_idx % cell_per_row);
+ int y = size[1] * (cell_idx / cell_per_row);
+
+#ifndef IRRADIANCE_SH_L2
+ const float bias = 0.0f;
+ pinfo->invsamples_ct = 1.0f / pinfo->samples_ct;
+ pinfo->lodfactor = bias + 0.5f * log((float)(PROBE_RT_SIZE * PROBE_RT_SIZE) * pinfo->invsamples_ct) / log(2);
+ pinfo->lodmax = floorf(log2f(PROBE_RT_SIZE)) - 2.0f;
+#else
+ pinfo->shres = 32; /* Less texture fetches & reduce branches */
+ pinfo->lodmax = 2.0f; /* Improve cache reuse */
+#endif
+
+ DRW_framebuffer_viewport_size(sldata->probe_filter_fb, x, y, size[0], size[1]);
+ DRW_draw_pass(psl->probe_diffuse_compute);
/* reattach to have a valid framebuffer. */
+ DRW_framebuffer_texture_detach(sldata->irradiance_pool);
DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->probe_pool, 0, 0);
+
+ /* restore */
+ pinfo->lodmax = lodmax;
}
-/* Renders the probe with index probe_idx.
- * Renders the world probe if probe_idx = -1. */
-static void render_one_probe(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl, int probe_idx)
+/* Render the scene to the probe_rt texture. */
+static void render_scene_to_probe(
+ EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl,
+ const float pos[3], float clipsta, float clipend)
{
EEVEE_LightProbesInfo *pinfo = sldata->probes;
- EEVEE_LightProbe *eprobe = &pinfo->probe_data[probe_idx];
- Object *ob = pinfo->probes_ref[probe_idx];
- LightProbe *prb = (LightProbe *)ob->data;
float winmat[4][4], posmat[4][4];
unit_m4(posmat);
- /* Update transforms */
- copy_v3_v3(eprobe->position, ob->obmat[3]);
-
/* Move to capture position */
- negate_v3_v3(posmat[3], ob->obmat[3]);
+ negate_v3_v3(posmat[3], pos);
/* 1 - Render to each cubeface individually.
* We do this instead of using geometry shader because a) it's faster,
* b) it's easier than fixing the nodetree shaders (for view dependant effects). */
pinfo->layer = 0;
- perspective_m4(winmat, -prb->clipsta, prb->clipsta, -prb->clipsta, prb->clipsta, prb->clipsta, prb->clipend);
+ perspective_m4(winmat, -clipsta, clipsta, -clipsta, clipsta, clipsta, clipend);
/* Detach to rebind the right cubeface. */
DRW_framebuffer_bind(sldata->probe_fb);
@@ -460,9 +605,10 @@ static void render_one_probe(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl,
DRW_framebuffer_cubeface_attach(sldata->probe_fb, sldata->probe_rt, 0, i, 0);
DRW_framebuffer_cubeface_attach(sldata->probe_fb, sldata->probe_depth_rt, 0, i, 0);
- DRW_framebuffer_viewport_size(sldata->probe_fb, LIGHTPROBE_TYPE_CUBE_SIZE, LIGHTPROBE_TYPE_CUBE_SIZE);
+ DRW_framebuffer_viewport_size(sldata->probe_fb, 0, 0, PROBE_RT_SIZE, PROBE_RT_SIZE);
- DRW_framebuffer_clear(false, true, false, NULL, 1.0);
+ float clear[4] = {1.0f, 0.0f, 0.0f, 1.0f};
+ DRW_framebuffer_clear(true, true, false, clear, 1.0);
/* Setup custom matrices */
mul_m4_m4m4(viewmat, cubefacemat[i], posmat);
@@ -498,14 +644,11 @@ static void render_one_probe(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl,
DRW_viewport_matrix_override_unset(DRW_MAT_VIEW);
DRW_viewport_matrix_override_unset(DRW_MAT_VIEWINV);
DRW_viewport_matrix_override_unset(DRW_MAT_WIN);
-
- filter_probe(eprobe, sldata, psl, probe_idx);
}
-static void render_world_lightprobe(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl)
+static void render_world_to_probe(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl)
{
EEVEE_LightProbesInfo *pinfo = sldata->probes;
- EEVEE_LightProbe *eprobe = &pinfo->probe_data[0];
/* 1 - Render to cubemap target using geometry shader. */
/* For world probe, we don't need to clear since we render the background directly. */
@@ -513,8 +656,51 @@ static void render_world_lightprobe(EEVEE_SceneLayerData *sldata, EEVEE_PassList
DRW_framebuffer_bind(sldata->probe_fb);
DRW_draw_pass(psl->probe_background);
+}
+
+static void update_irradiance_probe(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl, int probe_idx)
+{
+ EEVEE_LightProbesInfo *pinfo = sldata->probes;
+ EEVEE_LightGrid *egrid = &pinfo->grid_data[probe_idx];
+ Object *ob = pinfo->probes_grid_ref[probe_idx];
+ LightProbe *prb = (LightProbe *)ob->data;
+
+ /* Temporary Remove all grids */
+ int tmp_num_render_grid = pinfo->num_render_grid;
+ int tmp_num_render_cube = pinfo->num_render_cube;
+ pinfo->num_render_grid = 0;
+ pinfo->num_render_cube = 0;
+
+ /* Render a cubemap and compute irradiance for every point inside the irradiance grid */
+ for (int i = 0; i < egrid->resolution[0]; ++i) {
+ for (int j = 0; j < egrid->resolution[1]; ++j) {
+ for (int k = 0; k < egrid->resolution[2]; ++k) {
+ float pos[3], tmp[3];
+ int cell = egrid->offset + k + j * egrid->resolution[2] + i * egrid->resolution[2] * egrid->resolution[1];
+
+ /* Compute world position of the sample */
+ copy_v3_v3(pos, egrid->corner);
+ mul_v3_v3fl(tmp, egrid->increment_x, (float)i);
+ add_v3_v3(pos, tmp);
+ mul_v3_v3fl(tmp, egrid->increment_y, (float)j);
+ add_v3_v3(pos, tmp);
+ mul_v3_v3fl(tmp, egrid->increment_z, (float)k);
+ add_v3_v3(pos, tmp);
+
+ /* TODO Remove specular */
+ render_scene_to_probe(sldata, psl, pos, prb->clipsta, prb->clipend);
+ /* TODO Do not update texture while rendering but write to CPU memory (or another buffer).
+ * This will allow "multiple bounces" computation. */
+ diffuse_filter_probe(sldata, psl, cell);
+ }
+ }
+ }
+
+ /* Restore */
+ pinfo->num_render_grid = tmp_num_render_grid;
+ pinfo->num_render_cube = tmp_num_render_cube;
- filter_probe(eprobe, sldata, psl, 0);
+ /* TODO save in DNA / blendfile */
}
void EEVEE_lightprobes_refresh(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl)
@@ -526,16 +712,17 @@ void EEVEE_lightprobes_refresh(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl
/* Render world in priority */
if (e_data.update_world) {
- render_world_lightprobe(sldata, psl);
+ render_world_to_probe(sldata, psl);
+ glossy_filter_probe(sldata, psl, 0);
+ diffuse_filter_probe(sldata, psl, 0);
+
e_data.update_world = false;
if (!e_data.world_ready_to_shade) {
e_data.world_ready_to_shade = true;
- pinfo->num_render_probe = 1;
+ pinfo->num_render_cube = 1;
}
- DRW_uniformbuffer_update(sldata->probe_ubo, &sldata->probes->probe_data);
-
DRW_viewport_request_redraw();
}
else if (true) { /* TODO if at least one probe needs refresh */
@@ -548,19 +735,41 @@ void EEVEE_lightprobes_refresh(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl
}
}
- for (int i = 1; (ob = pinfo->probes_ref[i]) && (i < MAX_PROBE); i++) {
+ for (int i = 1; (ob = pinfo->probes_cube_ref[i]) && (i < MAX_PROBE); i++) {
EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_get(ob);
if (ped->need_update) {
- render_one_probe(sldata, psl, i);
+ LightProbe *prb = (LightProbe *)ob->data;
+
+ render_scene_to_probe(sldata, psl, ob->obmat[3], prb->clipsta, prb->clipend);
+ glossy_filter_probe(sldata, psl, i);
+
ped->need_update = false;
if (!ped->ready_to_shade) {
- pinfo->num_render_probe++;
+ pinfo->num_render_cube++;
ped->ready_to_shade = true;
}
- DRW_uniformbuffer_update(sldata->probe_ubo, &sldata->probes->probe_data);
+ DRW_viewport_request_redraw();
+
+ /* Only do one probe per frame */
+ break;
+ }
+ }
+
+ for (int i = 0; (ob = pinfo->probes_grid_ref[i]) && (i < MAX_GRID); i++) {
+ EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_get(ob);
+
+ if (ped->need_update) {
+ update_irradiance_probe(sldata, psl, i);
+
+ ped->need_update = false;
+
+ if (!ped->ready_to_shade) {
+ pinfo->num_render_grid++;
+ ped->ready_to_shade = true;
+ }
DRW_viewport_request_redraw();
@@ -574,7 +783,7 @@ void EEVEE_lightprobes_refresh(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl
void EEVEE_lightprobes_free(void)
{
DRW_SHADER_FREE_SAFE(e_data.probe_default_sh);
- DRW_SHADER_FREE_SAFE(e_data.probe_filter_sh);
- DRW_SHADER_FREE_SAFE(e_data.probe_spherical_harmonic_sh);
+ DRW_SHADER_FREE_SAFE(e_data.probe_filter_glossy_sh);
+ DRW_SHADER_FREE_SAFE(e_data.probe_filter_diffuse_sh);
DRW_TEXTURE_FREE_SAFE(e_data.hammersley);
}
diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c
index b9ad507c6ce..40e6a89d209 100644
--- a/source/blender/draw/engines/eevee/eevee_materials.c
+++ b/source/blender/draw/engines/eevee/eevee_materials.c
@@ -41,6 +41,7 @@
#define SHADER_DEFINES \
"#define EEVEE_ENGINE\n" \
"#define MAX_PROBE " STRINGIFY(MAX_PROBE) "\n" \
+ "#define MAX_GRID " STRINGIFY(MAX_GRID) "\n" \
"#define MAX_LIGHT " STRINGIFY(MAX_LIGHT) "\n" \
"#define MAX_SHADOW_CUBE " STRINGIFY(MAX_SHADOW_CUBE) "\n" \
"#define MAX_SHADOW_MAP " STRINGIFY(MAX_SHADOW_MAP) "\n" \
@@ -87,8 +88,6 @@ extern char datatoc_lit_surface_vert_glsl[];
extern char datatoc_shadow_frag_glsl[];
extern char datatoc_shadow_geom_glsl[];
extern char datatoc_shadow_vert_glsl[];
-extern char datatoc_lightprobe_filter_frag_glsl[];
-extern char datatoc_lightprobe_sh_frag_glsl[];
extern char datatoc_lightprobe_geom_glsl[];
extern char datatoc_lightprobe_vert_glsl[];
extern char datatoc_background_vert_glsl[];
@@ -186,11 +185,25 @@ void EEVEE_materials_init(void)
e_data.default_lit = DRW_shader_create(
datatoc_lit_surface_vert_glsl, NULL, frag_str,
SHADER_DEFINES
+#if defined(IRRADIANCE_SH_L2)
+ "#define IRRADIANCE_SH_L2\n"
+#elif defined(IRRADIANCE_CUBEMAP)
+ "#define IRRADIANCE_CUBEMAP\n"
+#elif defined(IRRADIANCE_HL2)
+ "#define IRRADIANCE_HL2\n"
+#endif
"#define MESH_SHADER\n");
e_data.default_lit_flat = DRW_shader_create(
datatoc_lit_surface_vert_glsl, NULL, frag_str,
SHADER_DEFINES
+#if defined(IRRADIANCE_SH_L2)
+ "#define IRRADIANCE_SH_L2\n"
+#elif defined(IRRADIANCE_CUBEMAP)
+ "#define IRRADIANCE_CUBEMAP\n"
+#elif defined(IRRADIANCE_HL2)
+ "#define IRRADIANCE_HL2\n"
+#endif
"#define MESH_SHADER\n"
"#define USE_FLAT_NORMAL\n");
@@ -250,22 +263,21 @@ struct GPUMaterial *EEVEE_material_world_background_get(struct Scene *scene, Wor
SHADER_DEFINES "#define WORLD_BACKGROUND\n");
}
-struct GPUMaterial *EEVEE_material_mesh_lightprobe_get(struct Scene *scene, Material *ma)
-{
- return GPU_material_from_nodetree(
- scene, ma->nodetree, &ma->gpumaterial, &DRW_engine_viewport_eevee_type,
- VAR_MAT_MESH | VAR_MAT_PROBE,
- datatoc_lightprobe_vert_glsl, NULL, e_data.frag_shader_lib,
- SHADER_DEFINES "#define MESH_SHADER\n" "#define PROBE_CAPTURE\n");
-}
-
struct GPUMaterial *EEVEE_material_mesh_get(struct Scene *scene, Material *ma)
{
return GPU_material_from_nodetree(
scene, ma->nodetree, &ma->gpumaterial, &DRW_engine_viewport_eevee_type,
VAR_MAT_MESH,
datatoc_lit_surface_vert_glsl, NULL, e_data.frag_shader_lib,
- SHADER_DEFINES "#define MESH_SHADER\n");
+ SHADER_DEFINES
+#if defined(IRRADIANCE_SH_L2)
+ "#define IRRADIANCE_SH_L2\n"
+#elif defined(IRRADIANCE_CUBEMAP)
+ "#define IRRADIANCE_CUBEMAP\n"
+#elif defined(IRRADIANCE_HL2)
+ "#define IRRADIANCE_HL2\n"
+#endif
+ "#define MESH_SHADER\n");
}
struct GPUMaterial *EEVEE_material_hair_get(struct Scene *scene, Material *ma)
@@ -280,13 +292,16 @@ struct GPUMaterial *EEVEE_material_hair_get(struct Scene *scene, Material *ma)
static void add_standard_uniforms(DRWShadingGroup *shgrp, EEVEE_SceneLayerData *sldata)
{
DRW_shgroup_uniform_block(shgrp, "probe_block", sldata->probe_ubo);
+ DRW_shgroup_uniform_block(shgrp, "grid_block", sldata->grid_ubo);
DRW_shgroup_uniform_block(shgrp, "light_block", sldata->light_ubo);
DRW_shgroup_uniform_block(shgrp, "shadow_block", sldata->shadow_ubo);
DRW_shgroup_uniform_int(shgrp, "light_count", &sldata->lamps->num_light, 1);
- DRW_shgroup_uniform_int(shgrp, "probe_count", &sldata->probes->num_render_probe, 1);
+ DRW_shgroup_uniform_int(shgrp, "probe_count", &sldata->probes->num_render_cube, 1);
+ DRW_shgroup_uniform_int(shgrp, "grid_count", &sldata->probes->num_render_grid, 1);
DRW_shgroup_uniform_float(shgrp, "lodMax", &sldata->probes->lodmax, 1);
DRW_shgroup_uniform_texture(shgrp, "utilTex", e_data.util_tex);
DRW_shgroup_uniform_buffer(shgrp, "probeCubes", &sldata->probe_pool);
+ DRW_shgroup_uniform_buffer(shgrp, "irradianceGrid", &sldata->irradiance_pool);
DRW_shgroup_uniform_buffer(shgrp, "shadowCubes", &sldata->shadow_depth_cube_pool);
DRW_shgroup_uniform_buffer(shgrp, "shadowCascades", &sldata->shadow_depth_cascade_pool);
}
diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h
index f3c8a63a5d7..77aa8d04278 100644
--- a/source/blender/draw/engines/eevee/eevee_private.h
+++ b/source/blender/draw/engines/eevee/eevee_private.h
@@ -32,6 +32,7 @@ extern struct DrawEngineType draw_engine_eevee_type;
/* Minimum UBO is 16384 bytes */
#define MAX_PROBE 128 /* TODO : find size by dividing UBO max size by probe data size */
+#define MAX_GRID 64 /* TODO : find size by dividing UBO max size by grid data size */
#define MAX_LIGHT 128 /* TODO : find size by dividing UBO max size by light data size */
#define MAX_SHADOW_CUBE 42 /* TODO : Make this depends on GL_MAX_ARRAY_TEXTURE_LAYERS */
#define MAX_SHADOW_MAP 64
@@ -39,6 +40,11 @@ extern struct DrawEngineType draw_engine_eevee_type;
#define MAX_CASCADE_NUM 4
#define MAX_BLOOM_STEP 16
+/* Only define one of these. */
+// #define IRRADIANCE_SH_L2
+// #define IRRADIANCE_CUBEMAP
+#define IRRADIANCE_HL2
+
typedef struct EEVEE_PassList {
/* Shadows */
struct DRWPass *shadow_pass;
@@ -49,8 +55,8 @@ typedef struct EEVEE_PassList {
/* Probes */
struct DRWPass *probe_background;
struct DRWPass *probe_meshes;
- struct DRWPass *probe_prefilter;
- struct DRWPass *probe_sh_compute;
+ struct DRWPass *probe_glossy_compute;
+ struct DRWPass *probe_diffuse_compute;
/* Effects */
struct DRWPass *motion_blur;
@@ -169,7 +175,6 @@ enum {
/* ************ PROBE UBO ************* */
typedef struct EEVEE_LightProbe {
float position[3], parallax_type;
- float shcoefs[9][3], pad2;
float attenuation_fac;
float attenuation_type;
float pad3[2];
@@ -177,12 +182,23 @@ typedef struct EEVEE_LightProbe {
float parallaxmat[4][4];
} EEVEE_LightProbe;
+typedef struct EEVEE_LightGrid {
+ float mat[4][4];
+ int resolution[3], offset;
+ float corner[3], pad1;
+ float increment_x[3], pad2; /* world space vector between 2 opposite cells */
+ float increment_y[3], pad3;
+ float increment_z[3], pad4;
+} EEVEE_LightGrid;
+
/* ************ PROBE DATA ************* */
typedef struct EEVEE_LightProbesInfo {
int num_cube, cache_num_cube;
+ int num_grid, cache_num_grid;
int update_flag;
/* Actual number of probes that have datas. */
- int num_render_probe;
+ int num_render_cube;
+ int num_render_grid;
/* For rendering probes */
float probemat[6][4][4];
int layer;
@@ -198,9 +214,11 @@ typedef struct EEVEE_LightProbesInfo {
struct GPUTexture *backgroundtex;
/* List of probes in the scene. */
/* XXX This is fragile, can get out of sync quickly. */
- struct Object *probes_ref[MAX_PROBE];
+ struct Object *probes_cube_ref[MAX_PROBE];
+ struct Object *probes_grid_ref[MAX_GRID];
/* UBO Storage : data used by UBO */
struct EEVEE_LightProbe probe_data[MAX_PROBE];
+ struct EEVEE_LightGrid grid_data[MAX_GRID];
} EEVEE_LightProbesInfo;
/* EEVEE_LightProbesInfo->update_flag */
@@ -274,15 +292,15 @@ typedef struct EEVEE_SceneLayerData {
struct EEVEE_LightProbesInfo *probes;
struct GPUUniformBuffer *probe_ubo;
+ struct GPUUniformBuffer *grid_ubo;
struct GPUFrameBuffer *probe_fb;
struct GPUFrameBuffer *probe_filter_fb;
- struct GPUFrameBuffer *probe_sh_fb;
struct GPUTexture *probe_rt;
struct GPUTexture *probe_depth_rt;
struct GPUTexture *probe_pool;
- struct GPUTexture *probe_sh;
+ struct GPUTexture *irradiance_pool;
struct ListBase probe_queue; /* List of probes to update */
} EEVEE_SceneLayerData;
diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
index 4aa97780637..77ff614b2c1 100644
--- a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
@@ -11,7 +11,6 @@
struct ProbeData {
vec4 position_type;
- vec4 shcoefs[7];
vec4 attenuation_fac_type;
mat4 influencemat;
mat4 parallaxmat;
@@ -25,6 +24,36 @@ struct ProbeData {
#define p_atten_fac attenuation_fac_type.x
#define p_atten_type attenuation_fac_type.y
+struct GridData {
+ mat4 localmat;
+ ivec4 resolution_offset;
+ vec4 ws_corner; /* world space position */
+ vec4 ws_increment_x; /* world space vector between 2 opposite cells */
+ vec4 ws_increment_y;
+ vec4 ws_increment_z;
+};
+
+#define g_corner ws_corner.xyz
+#define g_increment_x ws_increment_x.xyz
+#define g_increment_y ws_increment_y.xyz
+#define g_increment_z ws_increment_z.xyz
+#define g_resolution resolution_offset.xyz
+#define g_offset resolution_offset.w
+
+#ifdef IRRADIANCE_CUBEMAP
+struct IrradianceData {
+ vec3 color;
+};
+#elif defined(IRRADIANCE_SH_L2)
+struct IrradianceData {
+ vec3 shcoefs[9];
+};
+#else /* defined(IRRADIANCE_HL2) */
+struct IrradianceData {
+ vec3 cubesides[3];
+};
+#endif
+
/* TODO remove sh once we have irradiance grid */
#define shcoef0 shcoefs[0].rgb
#define shcoef1 vec3(shcoefs[0].a, shcoefs[1].rg)
@@ -226,38 +255,62 @@ float buffer_depth(bool is_persp, float z, float zf, float zn)
#define spherical_harmonics spherical_harmonics_L2
/* http://seblagarde.wordpress.com/2012/01/08/pi-or-not-to-pi-in-game-lighting-equation/ */
-vec3 spherical_harmonics_L1(vec3 N, vec4 shcoefs[3])
+vec3 spherical_harmonics_L1(vec3 N, vec3 shcoefs[4])
{
vec3 sh = vec3(0.0);
- sh += 0.282095 * shcoef0;
+ sh += 0.282095 * shcoefs[0];
- sh += -0.488603 * N.z * shcoef1;
- sh += 0.488603 * N.y * shcoef2;
- sh += -0.488603 * N.x * shcoef3;
+ sh += -0.488603 * N.z * shcoefs[1];
+ sh += 0.488603 * N.y * shcoefs[2];
+ sh += -0.488603 * N.x * shcoefs[3];
return sh;
}
-vec3 spherical_harmonics_L2(vec3 N, vec4 shcoefs[7])
+vec3 spherical_harmonics_L2(vec3 N, vec3 shcoefs[9])
{
vec3 sh = vec3(0.0);
- sh += 0.282095 * shcoef0;
+ sh += 0.282095 * shcoefs[0];
- sh += -0.488603 * N.z * shcoef1;
- sh += 0.488603 * N.y * shcoef2;
- sh += -0.488603 * N.x * shcoef3;
+ sh += -0.488603 * N.z * shcoefs[1];
+ sh += 0.488603 * N.y * shcoefs[2];
+ sh += -0.488603 * N.x * shcoefs[3];
- sh += 1.092548 * N.x * N.z * shcoef4;
- sh += -1.092548 * N.z * N.y * shcoef5;
- sh += 0.315392 * (3.0 * N.y * N.y - 1.0) * shcoef6;
- sh += -1.092548 * N.x * N.y * shcoef7;
- sh += 0.546274 * (N.x * N.x - N.z * N.z) * shcoef8;
+ sh += 1.092548 * N.x * N.z * shcoefs[4];
+ sh += -1.092548 * N.z * N.y * shcoefs[5];
+ sh += 0.315392 * (3.0 * N.y * N.y - 1.0) * shcoefs[6];
+ sh += -1.092548 * N.x * N.y * shcoefs[7];
+ sh += 0.546274 * (N.x * N.x - N.z * N.z) * shcoefs[8];
return sh;
}
+vec3 hl2_basis(vec3 N, vec3 cubesides[3])
+{
+ vec3 irradiance = vec3(0.0);
+
+ vec3 n_squared = N * N;
+
+ irradiance += n_squared.x * cubesides[0];
+ irradiance += n_squared.y * cubesides[1];
+ irradiance += n_squared.z * cubesides[2];
+
+ return irradiance;
+}
+
+vec3 compute_irradiance(vec3 N, IrradianceData ird)
+{
+#if defined(IRRADIANCE_CUBEMAP)
+ return ird.color;
+#elif defined(IRRADIANCE_SH_L2)
+ return spherical_harmonics_L2(N, ird.shcoefs);
+#else /* defined(IRRADIANCE_HL2) */
+ return hl2_basis(N, ird.cubesides);
+#endif
+}
+
vec3 get_specular_dominant_dir(vec3 N, vec3 R, float roughness)
{
float smoothness = 1.0 - roughness;
diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl
index 898c7bfc578..3997de7a22d 100644
--- a/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl
@@ -37,6 +37,11 @@ float pdf_ggx_reflect(float NH, float a2)
return NH * a2 / D_ggx_opti(NH, a2);
}
+float pdf_hemisphere()
+{
+ return 0.5 * M_1_PI;
+}
+
vec3 sample_ggx(float nsample, float a2, vec3 N, vec3 T, vec3 B)
{
vec3 Xi = hammersley_3d(nsample);
@@ -52,3 +57,17 @@ vec3 sample_ggx(float nsample, float a2, vec3 N, vec3 T, vec3 B)
return tangent_to_world(Ht, N, T, B);
}
+
+vec3 sample_hemisphere(float nsample, vec3 N, vec3 T, vec3 B)
+{
+ vec3 Xi = hammersley_3d(nsample);
+
+ float z = Xi.x; /* cos theta */
+ float r = sqrt( 1.0f - z*z ); /* sin theta */
+ float x = r * Xi.y;
+ float y = r * Xi.z;
+
+ vec3 Ht = vec3(x, y, z);
+
+ return tangent_to_world(Ht, N, T, B);
+} \ No newline at end of file
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl
new file mode 100644
index 00000000000..c08135aa979
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl
@@ -0,0 +1,197 @@
+
+uniform samplerCube probeHdr;
+uniform int probeSize;
+uniform float lodFactor;
+uniform float lodMax;
+
+in vec3 worldPosition;
+
+out vec4 FragColor;
+
+#define M_4PI 12.5663706143591729
+
+const mat3 CUBE_ROTATIONS[6] = mat3[](
+ mat3(vec3( 0.0, 0.0, -1.0),
+ vec3( 0.0, -1.0, 0.0),
+ vec3(-1.0, 0.0, 0.0)),
+ mat3(vec3( 0.0, 0.0, 1.0),
+ vec3( 0.0, -1.0, 0.0),
+ vec3( 1.0, 0.0, 0.0)),
+ mat3(vec3( 1.0, 0.0, 0.0),
+ vec3( 0.0, 0.0, 1.0),
+ vec3( 0.0, -1.0, 0.0)),
+ mat3(vec3( 1.0, 0.0, 0.0),
+ vec3( 0.0, 0.0, -1.0),
+ vec3( 0.0, 1.0, 0.0)),
+ mat3(vec3( 1.0, 0.0, 0.0),
+ vec3( 0.0, -1.0, 0.0),
+ vec3( 0.0, 0.0, -1.0)),
+ mat3(vec3(-1.0, 0.0, 0.0),
+ vec3( 0.0, -1.0, 0.0),
+ vec3( 0.0, 0.0, 1.0)));
+
+vec3 get_cubemap_vector(vec2 co, int face)
+{
+ return normalize(CUBE_ROTATIONS[face] * vec3(co * 2.0 - 1.0, 1.0));
+}
+
+float area_element(float x, float y)
+{
+ return atan(x * y, sqrt(x * x + y * y + 1));
+}
+
+float texel_solid_angle(vec2 co, float halfpix)
+{
+ vec2 v1 = (co - vec2(halfpix)) * 2.0 - 1.0;
+ vec2 v2 = (co + vec2(halfpix)) * 2.0 - 1.0;
+
+ return area_element(v1.x, v1.y) - area_element(v1.x, v2.y) - area_element(v2.x, v1.y) + area_element(v2.x, v2.y);
+}
+
+vec3 octahedral_to_cubemap_proj(vec2 co)
+{
+ co = co * 2.0 - 1.0;
+
+ vec2 abs_co = abs(co);
+ vec3 v = vec3(co, 1.0 - (abs_co.x + abs_co.y));
+
+ if ( abs_co.x + abs_co.y > 1.0 ) {
+ v.xy = (abs(co.yx) - 1.0) * -sign(co.xy);
+ }
+
+ return v;
+}
+
+void main()
+{
+#if defined(IRRADIANCE_SH_L2)
+ float pixstep = 1.0 / probeSize;
+ float halfpix = pixstep / 2.0;
+
+ /* Downside: leaks negative values, very bandwidth consuming */
+ int comp = int(gl_FragCoord.x) % 3 + (int(gl_FragCoord.y) % 3) * 3;
+
+ float weight_accum = 0.0;
+ vec3 sh = vec3(0.0);
+
+ for (int face = 0; face < 6; ++face) {
+ for (float x = halfpix; x < 1.0; x += pixstep) {
+ for (float y = halfpix; y < 1.0; y += pixstep) {
+ float weight, coef;
+ vec2 facecoord = vec2(x,y);
+ vec3 cubevec = get_cubemap_vector(facecoord, face);
+
+ if (comp == 0) {
+ coef = 0.282095;
+ }
+ else if (comp == 1) {
+ coef = -0.488603 * cubevec.z * 2.0 / 3.0;
+ }
+ else if (comp == 2) {
+ coef = 0.488603 * cubevec.y * 2.0 / 3.0;
+ }
+ else if (comp == 3) {
+ coef = -0.488603 * cubevec.x * 2.0 / 3.0;
+ }
+ else if (comp == 4) {
+ coef = 1.092548 * cubevec.x * cubevec.z * 1.0 / 4.0;
+ }
+ else if (comp == 5) {
+ coef = -1.092548 * cubevec.z * cubevec.y * 1.0 / 4.0;
+ }
+ else if (comp == 6) {
+ coef = 0.315392 * (3.0 * cubevec.y * cubevec.y - 1.0) * 1.0 / 4.0;
+ }
+ else if (comp == 7) {
+ coef = 1.092548 * cubevec.x * cubevec.y * 1.0 / 4.0;
+ }
+ else { /* (comp == 8) */
+ coef = 0.546274 * (cubevec.x * cubevec.x - cubevec.z * cubevec.z) * 1.0 / 4.0;
+ }
+
+ weight = texel_solid_angle(facecoord, halfpix);
+
+ vec4 sample = textureLod(probeHdr, cubevec, lodMax);
+ sh += sample.rgb * coef * weight;
+ weight_accum += weight;
+ }
+ }
+ }
+ sh *= M_4PI / weight_accum;
+
+ FragColor = vec4(sh, 1.0);
+#else
+#if defined(IRRADIANCE_CUBEMAP)
+ /* Downside: Need lots of memory for storage, distortion due to octahedral mapping */
+ const vec2 map_size = vec2(16.0);
+ const vec2 texelSize = 1.0 / map_size;
+ vec2 uvs = mod(gl_FragCoord.xy, map_size) * texelSize;
+ const float paddingSize = 1.0;
+
+ /* Add a N pixel border to ensure filtering is correct
+ * for N mipmap levels. */
+ uvs += uvs * texelSize * paddingSize * 2.0;
+ uvs -= texelSize * paddingSize;
+
+ /* edge mirroring : only mirror if directly adjacent
+ * (not diagonally adjacent) */
+ vec2 m = abs(uvs - 0.5) + 0.5;
+ vec2 f = floor(m);
+ if (f.x - f.y != 0.0) {
+ uvs = 1.0 - uvs;
+ }
+
+ /* clamp to [0-1] */
+ uvs = fract(uvs);
+
+ /* get cubemap vector */
+ vec3 cubevec = octahedral_to_cubemap_proj(uvs);
+
+#elif defined(IRRADIANCE_HL2)
+ /* Downside: very very low resolution (6 texels), bleed lighting because of interpolation */
+ int x = int(gl_FragCoord.x) % 3;
+ int y = int(gl_FragCoord.y) % 2;
+
+ vec3 cubevec = vec3(1.0, 0.0, 0.0);
+
+ if (x == 1) {
+ cubevec = cubevec.yxy;
+ }
+ else if (x == 2) {
+ cubevec = cubevec.yyx;
+ }
+
+ if (y == 1) {
+ cubevec = -cubevec;
+ }
+#endif
+
+ vec3 N, T, B, V;
+
+ N = normalize(cubevec);
+
+ make_orthonormal_basis(N, T, B); /* Generate tangent space */
+
+ /* Integrating Envmap */
+ float weight = 0.0;
+ vec3 out_radiance = vec3(0.0);
+ for (float i = 0; i < sampleCount; i++) {
+ vec3 L = sample_hemisphere(i, N, T, B); /* Microfacet normal */
+ float NL = dot(N, L);
+
+ if (NL > 0.0) {
+ /* Coarse Approximation of the mapping distortion
+ * Unit Sphere -> Cubemap Face */
+ const float dist = 4.0 * M_PI / 6.0;
+ float pdf = pdf_hemisphere();
+ /* http://http.developer.nvidia.com/GPUGems3/gpugems3_ch20.html : Equation 13 */
+ float lod = clamp(lodFactor - 0.5 * log2(pdf * dist), 0.0, lodMax) ;
+
+ out_radiance += textureLod(probeHdr, L, lod).rgb * NL / pdf;
+ }
+ weight += 1.0;
+ }
+
+ FragColor = vec4(out_radiance / weight, 1.0);
+#endif
+} \ No newline at end of file
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_filter_frag.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl
index 33714c5293c..33714c5293c 100644
--- a/source/blender/draw/engines/eevee/shaders/lightprobe_filter_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_sh_frag.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_sh_frag.glsl
deleted file mode 100644
index 1bb14b76f42..00000000000
--- a/source/blender/draw/engines/eevee/shaders/lightprobe_sh_frag.glsl
+++ /dev/null
@@ -1,107 +0,0 @@
-
-uniform samplerCube probeHdr;
-uniform int probeSize;
-uniform float lodBias;
-
-in vec3 worldPosition;
-
-out vec4 FragColor;
-
-#define M_4PI 12.5663706143591729
-
-const mat3 CUBE_ROTATIONS[6] = mat3[](
- mat3(vec3( 0.0, 0.0, -1.0),
- vec3( 0.0, -1.0, 0.0),
- vec3(-1.0, 0.0, 0.0)),
- mat3(vec3( 0.0, 0.0, 1.0),
- vec3( 0.0, -1.0, 0.0),
- vec3( 1.0, 0.0, 0.0)),
- mat3(vec3( 1.0, 0.0, 0.0),
- vec3( 0.0, 0.0, 1.0),
- vec3( 0.0, -1.0, 0.0)),
- mat3(vec3( 1.0, 0.0, 0.0),
- vec3( 0.0, 0.0, -1.0),
- vec3( 0.0, 1.0, 0.0)),
- mat3(vec3( 1.0, 0.0, 0.0),
- vec3( 0.0, -1.0, 0.0),
- vec3( 0.0, 0.0, -1.0)),
- mat3(vec3(-1.0, 0.0, 0.0),
- vec3( 0.0, -1.0, 0.0),
- vec3( 0.0, 0.0, 1.0)));
-
-vec3 get_cubemap_vector(vec2 co, int face)
-{
- return normalize(CUBE_ROTATIONS[face] * vec3(co * 2.0 - 1.0, 1.0));
-}
-
-float area_element(float x, float y)
-{
- return atan(x * y, sqrt(x * x + y * y + 1));
-}
-
-float texel_solid_angle(vec2 co, float halfpix)
-{
- vec2 v1 = (co - vec2(halfpix)) * 2.0 - 1.0;
- vec2 v2 = (co + vec2(halfpix)) * 2.0 - 1.0;
-
- return area_element(v1.x, v1.y) - area_element(v1.x, v2.y) - area_element(v2.x, v1.y) + area_element(v2.x, v2.y);
-}
-
-void main()
-{
- float pixstep = 1.0 / probeSize;
- float halfpix = pixstep / 2.0;
-
- float weight_accum = 0.0;
- vec3 sh = vec3(0.0);
-
- int shnbr = int(floor(gl_FragCoord.x));
-
- for (int face = 0; face < 6; ++face) {
- for (float x = halfpix; x < 1.0; x += pixstep) {
- for (float y = halfpix; y < 1.0; y += pixstep) {
- float shcoef;
-
- vec2 facecoord = vec2(x,y);
- vec3 cubevec = get_cubemap_vector(facecoord, face);
- float weight = texel_solid_angle(facecoord, halfpix);
-
- if (shnbr == 0) {
- shcoef = 0.282095;
- }
- else if (shnbr == 1) {
- shcoef = -0.488603 * cubevec.z * 2.0 / 3.0;
- }
- else if (shnbr == 2) {
- shcoef = 0.488603 * cubevec.y * 2.0 / 3.0;
- }
- else if (shnbr == 3) {
- shcoef = -0.488603 * cubevec.x * 2.0 / 3.0;
- }
- else if (shnbr == 4) {
- shcoef = 1.092548 * cubevec.x * cubevec.z * 1.0 / 4.0;
- }
- else if (shnbr == 5) {
- shcoef = -1.092548 * cubevec.z * cubevec.y * 1.0 / 4.0;
- }
- else if (shnbr == 6) {
- shcoef = 0.315392 * (3.0 * cubevec.y * cubevec.y - 1.0) * 1.0 / 4.0;
- }
- else if (shnbr == 7) {
- shcoef = 1.092548 * cubevec.x * cubevec.y * 1.0 / 4.0;
- }
- else { /* (shnbr == 8) */
- shcoef = 0.546274 * (cubevec.x * cubevec.x - cubevec.z * cubevec.z) * 1.0 / 4.0;
- }
-
- vec4 sample = textureLod(probeHdr, cubevec, lodBias);
- sh += sample.rgb * shcoef * weight;
- weight_accum += weight;
- }
- }
- }
-
- sh *= M_4PI / weight_accum;
-
- FragColor = vec4(sh, 1.0);
-} \ No newline at end of file
diff --git a/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl b/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl
index 8f11835a1cc..6dd9bbcdf6c 100644
--- a/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl
@@ -1,12 +1,13 @@
uniform int light_count;
uniform int probe_count;
+uniform int grid_count;
uniform mat4 ProjectionMatrix;
uniform mat4 ViewMatrixInverse;
uniform sampler2DArray probeCubes;
+uniform sampler2D irradianceGrid;
uniform float lodMax;
-uniform vec3 shCoefs[9];
#ifndef UTIL_TEX
#define UTIL_TEX
@@ -20,6 +21,10 @@ layout(std140) uniform probe_block {
ProbeData probes_data[MAX_PROBE];
};
+layout(std140) uniform grid_block {
+ GridData grids_data[MAX_GRID];
+};
+
layout(std140) uniform light_block {
LightData lights_data[MAX_LIGHT];
};
@@ -305,6 +310,88 @@ float probe_attenuation(vec3 W, ProbeData pd)
return fac;
}
+IrradianceData load_irradiance_cell(int cell, vec3 N)
+{
+ /* Keep in sync with diffuse_filter_probe() */
+
+#if defined(IRRADIANCE_CUBEMAP)
+
+ #define AMBIANT_CUBESIZE 8
+ ivec2 cell_co = ivec2(AMBIANT_CUBESIZE);
+ int cell_per_row = textureSize(irradianceGrid, 0).x / cell_co.x;
+ cell_co.x *= cell % cell_per_row;
+ cell_co.y *= cell / cell_per_row;
+
+ vec2 texelSize = 1.0 / vec2(AMBIANT_CUBESIZE);
+
+ vec2 uvs = mapping_octahedron(N, texelSize);
+ uvs *= vec2(AMBIANT_CUBESIZE) / vec2(textureSize(irradianceGrid, 0));
+ uvs += vec2(cell_co) / vec2(textureSize(irradianceGrid, 0));
+
+ IrradianceData ir;
+ ir.color = texture(irradianceGrid, uvs).rgb;
+
+#elif defined(IRRADIANCE_SH_L2)
+
+ ivec2 cell_co = ivec2(3, 3);
+ int cell_per_row = textureSize(irradianceGrid, 0).x / cell_co.x;
+ cell_co.x *= cell % cell_per_row;
+ cell_co.y *= cell / cell_per_row;
+
+ ivec3 ofs = ivec3(0, 1, 2);
+
+ IrradianceData ir;
+ ir.shcoefs[0] = texelFetch(irradianceGrid, cell_co + ofs.xx, 0).rgb;
+ ir.shcoefs[1] = texelFetch(irradianceGrid, cell_co + ofs.yx, 0).rgb;
+ ir.shcoefs[2] = texelFetch(irradianceGrid, cell_co + ofs.zx, 0).rgb;
+ ir.shcoefs[3] = texelFetch(irradianceGrid, cell_co + ofs.xy, 0).rgb;
+ ir.shcoefs[4] = texelFetch(irradianceGrid, cell_co + ofs.yy, 0).rgb;
+ ir.shcoefs[5] = texelFetch(irradianceGrid, cell_co + ofs.zy, 0).rgb;
+ ir.shcoefs[6] = texelFetch(irradianceGrid, cell_co + ofs.xz, 0).rgb;
+ ir.shcoefs[7] = texelFetch(irradianceGrid, cell_co + ofs.yz, 0).rgb;
+ ir.shcoefs[8] = texelFetch(irradianceGrid, cell_co + ofs.zz, 0).rgb;
+
+#else /* defined(IRRADIANCE_HL2) */
+
+ ivec2 cell_co = ivec2(3, 2);
+ int cell_per_row = textureSize(irradianceGrid, 0).x / cell_co.x;
+ cell_co.x *= cell % cell_per_row;
+ cell_co.y *= cell / cell_per_row;
+
+ ivec3 is_negative = ivec3(step(0.0, -N));
+
+ IrradianceData ir;
+ ir.cubesides[0] = texelFetch(irradianceGrid, cell_co + ivec2(0, is_negative.x), 0).rgb;
+ ir.cubesides[1] = texelFetch(irradianceGrid, cell_co + ivec2(1, is_negative.y), 0).rgb;
+ ir.cubesides[2] = texelFetch(irradianceGrid, cell_co + ivec2(2, is_negative.z), 0).rgb;
+
+#endif
+
+ return ir;
+}
+
+vec3 get_cell_color(ivec3 localpos, ivec3 gridres, int offset, vec3 ir_dir)
+{
+ /* Keep in sync with update_irradiance_probe */
+
+ int cell = offset + localpos.z + localpos.y * gridres.z + localpos.x * gridres.z * gridres.y;
+ IrradianceData ir_data = load_irradiance_cell(cell, ir_dir);
+ return compute_irradiance(ir_dir, ir_data);
+}
+
+vec3 trilinear_filtering(vec3 weights,
+ vec3 cell0_col, vec3 cell_x_col, vec3 cell_y_col, vec3 cell_z_col, vec3 cell_xy_col, vec3 cell_xz_col, vec3 cell_yz_col, vec3 cell_xyz_col)
+{
+ vec3 x_mix_0 = mix(cell0_col, cell_x_col, weights.x);
+ vec3 x_mix_y = mix(cell_y_col, cell_xy_col, weights.x);
+ vec3 x_mix_z = mix(cell_z_col, cell_xz_col, weights.x);
+ vec3 x_mix_yz = mix(cell_yz_col, cell_xyz_col, weights.x);
+ vec3 y_mix_0 = mix(x_mix_0, x_mix_y, weights.y);
+ vec3 y_mix_z = mix(x_mix_z, x_mix_yz, weights.y);
+ vec3 z_mix1 = mix(y_mix_0, y_mix_z, weights.z);
+ return z_mix1;
+}
+
vec3 eevee_surface_lit(vec3 world_normal, vec3 albedo, vec3 f0, float roughness, float ao)
{
roughness = clamp(roughness, 1e-8, 0.9999);
@@ -375,12 +462,71 @@ vec3 eevee_surface_lit(vec3 world_normal, vec3 albedo, vec3 f0, float roughness,
}
}
+ for (int i = 0; i < MAX_GRID && i < grid_count; ++i) {
+ GridData gd = grids_data[i];
+
+ vec3 localpos = (gd.localmat * vec4(sd.W, 1.0)).xyz;
+
+ vec3 localpos_max = vec3(gd.g_resolution + ivec3(1)) - localpos;
+ float fade = min(1.0, min_v3(min(localpos_max, localpos)));
+
+ if (fade > 0.0) {
+ localpos -= 1.0;
+ vec3 localpos_floored = floor(localpos);
+ vec3 trilinear_weight = fract(localpos); /* fract(-localpos) */
+
+ float weight_accum = 0.0;
+ vec3 irradiance_accum = vec3(0.0);
+
+ /* For each neighboor cells */
+ for (int i = 0; i < 8; ++i) {
+ ivec3 offset = ivec3(i, i >> 1, i >> 2) & ivec3(1);
+ vec3 cell_cos = clamp(localpos_floored + vec3(offset), vec3(0.0), vec3(gd.g_resolution) - 1.0);
+
+ /* We need this because we render probes in world space (so we need light vector in WS).
+ * And rendering them in local probe space is too much problem. */
+ vec3 ws_cell_location = gd.g_corner +
+ (gd.g_increment_x * cell_cos.x +
+ gd.g_increment_y * cell_cos.y +
+ gd.g_increment_z * cell_cos.z);
+ vec3 ws_point_to_cell = ws_cell_location - sd.W;
+ vec3 ws_light = normalize(ws_point_to_cell);
+
+ vec3 trilinear = mix(1 - trilinear_weight, trilinear_weight, offset);
+ float weight = trilinear.x * trilinear.y * trilinear.z;
+
+ /* Smooth backface test */
+ // weight *= max(0.005, dot(ws_light, sd.N));
+
+ /* Avoid zero weight */
+ weight = max(0.00001, weight);
+
+ vec3 color = get_cell_color(ivec3(cell_cos), gd.g_resolution, gd.g_offset, sd.N);
+
+ weight_accum += weight;
+ irradiance_accum += color * weight;
+ }
+
+ vec3 indirect_diffuse = irradiance_accum / weight_accum;
+
+ // float influ_diff = min(fade, (1.0 - spec_accum.a));
+ float influ_diff = min(1.0, (1.0 - spec_accum.a));
+
+ diff_accum.rgb += indirect_diffuse * influ_diff;
+ diff_accum.a += influ_diff;
+
+ // return texture(irradianceGrid, sd.W.xy).rgb;
+ }
+ }
+
/* World probe */
if (spec_accum.a < 1.0 || diff_accum.a < 1.0) {
ProbeData pd = probes_data[0];
+ IrradianceData ir_data = load_irradiance_cell(0, sd.N);
+
vec3 spec = textureLod_octahedron(probeCubes, vec4(spec_dir, 0), roughness * lodMax).rgb;
- vec3 diff = spherical_harmonics(sd.N, pd.shcoefs);
+ vec3 diff = compute_irradiance(sd.N, ir_data);
diff_accum.rgb += diff * (1.0 - diff_accum.a);
spec_accum.rgb += spec * (1.0 - spec_accum.a);
diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h
index 37b67cd1237..71b0396dc49 100644
--- a/source/blender/draw/intern/DRW_render.h
+++ b/source/blender/draw/intern/DRW_render.h
@@ -201,7 +201,7 @@ void DRW_framebuffer_texture_attach(struct GPUFrameBuffer *fb, struct GPUTexture
void DRW_framebuffer_cubeface_attach(struct GPUFrameBuffer *fb, struct GPUTexture *tex, int slot, int face, int mip);
void DRW_framebuffer_texture_detach(struct GPUTexture *tex);
void DRW_framebuffer_blit(struct GPUFrameBuffer *fb_read, struct GPUFrameBuffer *fb_write, bool depth);
-void DRW_framebuffer_viewport_size(struct GPUFrameBuffer *UNUSED(fb_read), int w, int h);
+void DRW_framebuffer_viewport_size(struct GPUFrameBuffer *fb_read, int x, int y, int w, int h);
void DRW_framebuffer_free(struct GPUFrameBuffer *fb);
#define DRW_FRAMEBUFFER_FREE_SAFE(fb) do { \
if (fb != NULL) { \
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c
index 77206a256f2..62a95bcc22b 100644
--- a/source/blender/draw/intern/draw_manager.c
+++ b/source/blender/draw/intern/draw_manager.c
@@ -2103,9 +2103,9 @@ void DRW_framebuffer_blit(struct GPUFrameBuffer *fb_read, struct GPUFrameBuffer
GPU_framebuffer_blit(fb_read, 0, fb_write, 0, depth);
}
-void DRW_framebuffer_viewport_size(struct GPUFrameBuffer *UNUSED(fb_read), int w, int h)
+void DRW_framebuffer_viewport_size(struct GPUFrameBuffer *UNUSED(fb_read), int x, int y, int w, int h)
{
- glViewport(0, 0, w, h);
+ glViewport(x, y, w, h);
}
/* Use color management profile to draw texture to framebuffer */