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.
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
/* 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);
|
||||
|
||||
/* reattach to have a valid framebuffer. */
|
||||
DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->probe_pool, 0, 0);
|
||||
}
|
||||
|
||||
/* 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)
|
||||
/* 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 */
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
filter_probe(eprobe, sldata, psl, 0);
|
||||
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;
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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) { \
|
||||
|
||||
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user