Eevee: Irradiance Visibility: Initial Implementation
This augment the existing irradiance grid with a new visibility precomputation. We store a small shadowmap for each grid sample so that light does not leak through walls and such. The visibility parameter are similar to the one used by the Variance Shadow Map for point lights. Technical details: We store the visibility in the same texture (array) as the irradiance itself (in order to reduce the number of sampler). But the irradiance and the visibility are not the same data so we must encode them in order to use the same texture format. We use RGBA8 normalized texture and encode irradiance as RGBE (shared exponent). Using RGBE encoding instead of R11_G11_B10 may lead to some lighting changes, but quality seems to be nearly the same in my test cases. Using full RGBA16/32F maybe a future option but that will require much more memory and reduce the perf significantly. Visibility moments (VSM) are encoded as 16bits fixed point precision using a special range. This seems to retain enough precision for the needs. Also interpolation does not seems to be big problem (even though it's incorrect).
This commit is contained in:
parent
847f568bf5
commit
5b6cfa705c
|
@ -137,6 +137,7 @@ data_to_c_simple(engines/eevee/shaders/lamps_lib.glsl SRC)
|
|||
data_to_c_simple(engines/eevee/shaders/lightprobe_lib.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_filter_visibility_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/lightprobe_cube_display_frag.glsl SRC)
|
||||
|
|
|
@ -55,6 +55,7 @@ static void eevee_view_layer_data_free(void *storage)
|
|||
DRW_FRAMEBUFFER_FREE_SAFE(sldata->probe_fb);
|
||||
DRW_FRAMEBUFFER_FREE_SAFE(sldata->probe_filter_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->irradiance_pool);
|
||||
DRW_TEXTURE_FREE_SAFE(sldata->irradiance_rt);
|
||||
|
|
|
@ -47,11 +47,13 @@
|
|||
#include "ED_screen.h"
|
||||
|
||||
#define IRRADIANCE_POOL_SIZE 1024
|
||||
#define HAMMERSLEY_SIZE 1024
|
||||
|
||||
static struct {
|
||||
struct GPUShader *probe_default_sh;
|
||||
struct GPUShader *probe_filter_glossy_sh;
|
||||
struct GPUShader *probe_filter_diffuse_sh;
|
||||
struct GPUShader *probe_filter_visibility_sh;
|
||||
struct GPUShader *probe_grid_fill_sh;
|
||||
struct GPUShader *probe_grid_display_sh;
|
||||
struct GPUShader *probe_planar_display_sh;
|
||||
|
@ -62,7 +64,6 @@ static struct {
|
|||
struct GPUTexture *planar_pool_placeholder;
|
||||
struct GPUTexture *depth_placeholder;
|
||||
struct GPUTexture *depth_array_placeholder;
|
||||
struct GPUTexture *cube_face_depth;
|
||||
struct GPUTexture *cube_face_minmaxz;
|
||||
|
||||
int update_world;
|
||||
|
@ -73,6 +74,7 @@ extern char datatoc_background_vert_glsl[];
|
|||
extern char datatoc_default_world_frag_glsl[];
|
||||
extern char datatoc_lightprobe_filter_glossy_frag_glsl[];
|
||||
extern char datatoc_lightprobe_filter_diffuse_frag_glsl[];
|
||||
extern char datatoc_lightprobe_filter_visibility_frag_glsl[];
|
||||
extern char datatoc_lightprobe_geom_glsl[];
|
||||
extern char datatoc_lightprobe_vert_glsl[];
|
||||
extern char datatoc_lightprobe_planar_display_frag_glsl[];
|
||||
|
@ -159,6 +161,7 @@ static void planar_pool_ensure_alloc(EEVEE_Data *vedata, int num_planar_ref)
|
|||
|
||||
void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *UNUSED(vedata))
|
||||
{
|
||||
bool update_all = false;
|
||||
const DRWContextState *draw_ctx = DRW_context_state_get();
|
||||
ViewLayer *view_layer = draw_ctx->view_layer;
|
||||
IDProperty *props = BKE_view_layer_engine_evaluated_get(view_layer, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_EEVEE);
|
||||
|
@ -176,7 +179,7 @@ void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *UNUSED(veda
|
|||
|
||||
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 HAMMERSLEY_SIZE " STRINGIFY(HAMMERSLEY_SIZE) "\n"
|
||||
"#define NOISE_SIZE 64\n");
|
||||
|
||||
e_data.probe_default_sh = DRW_shader_create(
|
||||
|
@ -200,7 +203,21 @@ void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *UNUSED(veda
|
|||
#elif defined(IRRADIANCE_HL2)
|
||||
"#define IRRADIANCE_HL2\n"
|
||||
#endif
|
||||
"#define HAMMERSLEY_SIZE 1024\n"
|
||||
"#define HAMMERSLEY_SIZE " STRINGIFY(HAMMERSLEY_SIZE) "\n"
|
||||
"#define NOISE_SIZE 64\n");
|
||||
|
||||
MEM_freeN(shader_str);
|
||||
|
||||
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_visibility_frag_glsl);
|
||||
shader_str = BLI_dynstr_get_cstring(ds_frag);
|
||||
BLI_dynstr_free(ds_frag);
|
||||
|
||||
e_data.probe_filter_visibility_sh = DRW_shader_create_fullscreen(
|
||||
shader_str,
|
||||
"#define HAMMERSLEY_SIZE " STRINGIFY(HAMMERSLEY_SIZE) "\n"
|
||||
"#define NOISE_SIZE 64\n");
|
||||
|
||||
MEM_freeN(shader_str);
|
||||
|
@ -260,7 +277,7 @@ void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *UNUSED(veda
|
|||
datatoc_lightprobe_planar_downsample_frag_glsl,
|
||||
NULL);
|
||||
|
||||
e_data.hammersley = create_hammersley_sample_texture(1024);
|
||||
e_data.hammersley = create_hammersley_sample_texture(HAMMERSLEY_SIZE);
|
||||
}
|
||||
|
||||
if (!sldata->probes) {
|
||||
|
@ -275,21 +292,15 @@ void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *UNUSED(veda
|
|||
}
|
||||
|
||||
int prop_bounce_num = BKE_collection_engine_property_value_get_int(props, "gi_diffuse_bounces");
|
||||
/* Update all probes if number of bounces mismatch. */
|
||||
if (sldata->probes->num_bounce != prop_bounce_num) {
|
||||
e_data.update_world |= PROBE_UPDATE_ALL;
|
||||
sldata->probes->updated_bounce = 0;
|
||||
sldata->probes->grid_initialized = false;
|
||||
sldata->probes->num_bounce = prop_bounce_num;
|
||||
update_all = true;
|
||||
}
|
||||
sldata->probes->num_bounce = prop_bounce_num;
|
||||
|
||||
int prop_cubemap_res = BKE_collection_engine_property_value_get_int(props, "gi_cubemap_resolution");
|
||||
if (sldata->probes->cubemap_res != prop_cubemap_res) {
|
||||
sldata->probes->cubemap_res = prop_cubemap_res;
|
||||
|
||||
e_data.update_world |= PROBE_UPDATE_ALL;
|
||||
sldata->probes->updated_bounce = 0;
|
||||
sldata->probes->grid_initialized = false;
|
||||
update_all = true;
|
||||
|
||||
sldata->probes->target_size = prop_cubemap_res >> 1;
|
||||
|
||||
|
@ -297,25 +308,27 @@ void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *UNUSED(veda
|
|||
DRW_TEXTURE_FREE_SAFE(sldata->probe_pool);
|
||||
}
|
||||
|
||||
/* Setup Render Target Cubemap */
|
||||
|
||||
/* We do this detach / attach dance to not generate an invalid framebuffer (mixed cubemap / 2D map) */
|
||||
if (sldata->probe_rt) {
|
||||
/* XXX Silly,TODO Cleanup this mess */
|
||||
DRW_framebuffer_texture_detach(sldata->probe_rt);
|
||||
int visibility_res = BKE_collection_engine_property_value_get_int(props, "gi_visibility_resolution");
|
||||
if (sldata->probes->irradiance_vis_size != visibility_res) {
|
||||
sldata->probes->irradiance_vis_size = visibility_res;
|
||||
update_all = true;
|
||||
}
|
||||
|
||||
DRWFboTexture tex_probe = {&e_data.cube_face_depth, DRW_TEX_DEPTH_24, DRW_TEX_TEMP};
|
||||
DRW_framebuffer_init(&sldata->probe_fb, &draw_engine_eevee_type, sldata->probes->target_size, sldata->probes->target_size, &tex_probe, 1);
|
||||
if (update_all) {
|
||||
e_data.update_world |= PROBE_UPDATE_ALL;
|
||||
sldata->probes->updated_bounce = 0;
|
||||
sldata->probes->grid_initialized = false;
|
||||
}
|
||||
|
||||
/* Setup Render Target Cubemap */
|
||||
if (!sldata->probe_rt) {
|
||||
sldata->probe_depth_rt = DRW_texture_create_cube(sldata->probes->target_size, DRW_TEX_DEPTH_24, 0, NULL);
|
||||
sldata->probe_rt = DRW_texture_create_cube(sldata->probes->target_size, DRW_TEX_RGBA_16, DRW_TEX_FILTER | DRW_TEX_MIPMAP, NULL);
|
||||
}
|
||||
|
||||
if (sldata->probe_rt) {
|
||||
/* XXX Silly,TODO Cleanup this mess */
|
||||
DRW_framebuffer_texture_attach(sldata->probe_fb, sldata->probe_rt, 0, 0);
|
||||
}
|
||||
DRWFboTexture tex_probe[2] = {{&sldata->probe_depth_rt, DRW_TEX_DEPTH_24, 0},
|
||||
{&sldata->probe_rt, DRW_TEX_RGBA_16, DRW_TEX_FILTER | DRW_TEX_MIPMAP}};
|
||||
DRW_framebuffer_init(&sldata->probe_fb, &draw_engine_eevee_type, sldata->probes->target_size, sldata->probes->target_size, tex_probe, 2);
|
||||
|
||||
/* Minmaxz Pyramid */
|
||||
// DRWFboTexture tex_minmaxz = {&e_data.cube_face_minmaxz, DRW_TEX_RG_32, DRW_TEX_MIPMAP | DRW_TEX_TEMP};
|
||||
|
@ -434,11 +447,30 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat
|
|||
DRW_shgroup_call_add(grp, geom, NULL);
|
||||
}
|
||||
|
||||
{
|
||||
psl->probe_visibility_compute = DRW_pass_create("LightProbe Visibility Compute", DRW_STATE_WRITE_COLOR);
|
||||
|
||||
DRWShadingGroup *grp = DRW_shgroup_create(e_data.probe_filter_visibility_sh, psl->probe_visibility_compute);
|
||||
DRW_shgroup_uniform_int(grp, "outputSize", &sldata->probes->shres, 1);
|
||||
DRW_shgroup_uniform_float(grp, "visibilityRange", &sldata->probes->visibility_range, 1);
|
||||
DRW_shgroup_uniform_float(grp, "visibilityBlur", &sldata->probes->visibility_blur, 1);
|
||||
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, "storedTexelSize", &sldata->probes->texel_size, 1);
|
||||
DRW_shgroup_uniform_float(grp, "nearClip", &sldata->probes->near_clip, 1);
|
||||
DRW_shgroup_uniform_float(grp, "farClip", &sldata->probes->far_clip, 1);
|
||||
DRW_shgroup_uniform_texture(grp, "texHammersley", e_data.hammersley);
|
||||
DRW_shgroup_uniform_texture(grp, "probeDepth", sldata->probe_depth_rt);
|
||||
|
||||
struct Gwn_Batch *geom = DRW_cache_fullscreen_quad_get();
|
||||
DRW_shgroup_call_add(grp, geom, NULL);
|
||||
}
|
||||
|
||||
{
|
||||
psl->probe_grid_fill = DRW_pass_create("LightProbe Grid Floodfill", DRW_STATE_WRITE_COLOR);
|
||||
|
||||
DRWShadingGroup *grp = DRW_shgroup_create(e_data.probe_grid_fill_sh, psl->probe_grid_fill);
|
||||
DRW_shgroup_uniform_buffer(grp, "gridTexture", &sldata->irradiance_pool);
|
||||
DRW_shgroup_uniform_buffer(grp, "irradianceGrid", &sldata->irradiance_pool);
|
||||
|
||||
struct Gwn_Batch *geom = DRW_cache_fullscreen_quad_get();
|
||||
DRW_shgroup_call_add(grp, geom, NULL);
|
||||
|
@ -751,6 +783,13 @@ static void EEVEE_lightprobes_updates(EEVEE_ViewLayerData *sldata, EEVEE_PassLis
|
|||
|
||||
copy_v3_v3_int(egrid->resolution, &probe->grid_resolution_x);
|
||||
|
||||
/* Visibility bias */
|
||||
egrid->visibility_bias = 0.05f * probe->vis_bias;
|
||||
egrid->visibility_bleed = probe->vis_bleedbias;
|
||||
egrid->visibility_range = max_ff(max_ff(len_v3(egrid->increment_x),
|
||||
len_v3(egrid->increment_y)),
|
||||
len_v3(egrid->increment_z)) + 1.0f;
|
||||
|
||||
/* Debug Display */
|
||||
if (BKE_object_is_visible(ob) &&
|
||||
DRW_state_draw_support() &&
|
||||
|
@ -825,16 +864,18 @@ void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved
|
|||
/* we need a signed format for Spherical Harmonics */
|
||||
int irradiance_format = DRW_TEX_RGBA_16;
|
||||
#else
|
||||
int irradiance_format = DRW_TEX_RGB_11_11_10;
|
||||
int irradiance_format = DRW_TEX_RGBA_8;
|
||||
#endif
|
||||
|
||||
/* TODO Allocate bigger storage if needed. */
|
||||
if (!sldata->irradiance_pool || !sldata->irradiance_rt) {
|
||||
if (!sldata->irradiance_pool) {
|
||||
sldata->irradiance_pool = DRW_texture_create_2D(IRRADIANCE_POOL_SIZE, IRRADIANCE_POOL_SIZE, irradiance_format, DRW_TEX_FILTER, NULL);
|
||||
sldata->irradiance_pool = DRW_texture_create_2D_array(IRRADIANCE_POOL_SIZE, IRRADIANCE_POOL_SIZE, 2,
|
||||
irradiance_format, DRW_TEX_FILTER, NULL);
|
||||
}
|
||||
if (!sldata->irradiance_rt) {
|
||||
sldata->irradiance_rt = DRW_texture_create_2D(IRRADIANCE_POOL_SIZE, IRRADIANCE_POOL_SIZE, irradiance_format, DRW_TEX_FILTER, NULL);
|
||||
sldata->irradiance_rt = DRW_texture_create_2D_array(IRRADIANCE_POOL_SIZE, IRRADIANCE_POOL_SIZE, 2,
|
||||
irradiance_format, DRW_TEX_FILTER, NULL);
|
||||
}
|
||||
pinfo->num_render_grid = 0;
|
||||
pinfo->updated_bounce = 0;
|
||||
|
@ -953,7 +994,9 @@ static void glossy_filter_probe(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata,
|
|||
}
|
||||
|
||||
/* Diffuse filter probe_rt to irradiance_pool at index probe_idx */
|
||||
static void diffuse_filter_probe(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, EEVEE_PassList *psl, int offset)
|
||||
static void diffuse_filter_probe(
|
||||
EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, EEVEE_PassList *psl, int offset,
|
||||
float clipsta, float clipend, float vis_range, float vis_blur)
|
||||
{
|
||||
EEVEE_LightProbesInfo *pinfo = sldata->probes;
|
||||
|
||||
|
@ -994,6 +1037,26 @@ static void diffuse_filter_probe(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata
|
|||
DRW_framebuffer_viewport_size(sldata->probe_filter_fb, x, y, size[0], size[1]);
|
||||
DRW_draw_pass(psl->probe_diffuse_compute);
|
||||
|
||||
/* Compute visibility */
|
||||
pinfo->samples_ct = 512.0f; /* TODO refine */
|
||||
pinfo->invsamples_ct = 1.0f / pinfo->samples_ct;
|
||||
pinfo->shres = pinfo->irradiance_vis_size;
|
||||
pinfo->visibility_range = vis_range;
|
||||
pinfo->visibility_blur = vis_blur;
|
||||
pinfo->near_clip = -clipsta;
|
||||
pinfo->far_clip = -clipend;
|
||||
pinfo->texel_size = 1.0f / (float)pinfo->irradiance_vis_size;
|
||||
|
||||
cell_per_row = IRRADIANCE_POOL_SIZE / pinfo->irradiance_vis_size;
|
||||
x = pinfo->irradiance_vis_size * (offset % cell_per_row);
|
||||
y = pinfo->irradiance_vis_size * (offset / cell_per_row);
|
||||
|
||||
DRW_framebuffer_texture_detach(sldata->irradiance_rt);
|
||||
DRW_framebuffer_texture_layer_attach(sldata->probe_filter_fb, sldata->irradiance_rt, 0, 1, 0);
|
||||
|
||||
DRW_framebuffer_viewport_size(sldata->probe_filter_fb, x, y, pinfo->irradiance_vis_size, sldata->probes->irradiance_vis_size);
|
||||
DRW_draw_pass(psl->probe_visibility_compute);
|
||||
|
||||
/* reattach to have a valid framebuffer. */
|
||||
DRW_framebuffer_texture_detach(sldata->irradiance_rt);
|
||||
DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->probe_pool, 0, 0);
|
||||
|
@ -1044,8 +1107,8 @@ static void render_scene_to_probe(
|
|||
|
||||
/* Detach to rebind the right cubeface. */
|
||||
DRW_framebuffer_bind(sldata->probe_fb);
|
||||
DRW_framebuffer_texture_attach(sldata->probe_fb, e_data.cube_face_depth, 0, 0);
|
||||
DRW_framebuffer_texture_detach(sldata->probe_rt);
|
||||
DRW_framebuffer_texture_detach(sldata->probe_depth_rt);
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
float viewmat[4][4], persmat[4][4];
|
||||
float viewinv[4][4], persinv[4][4];
|
||||
|
@ -1068,6 +1131,7 @@ static void render_scene_to_probe(
|
|||
EEVEE_draw_shadows(sldata, 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, 0, 0, pinfo->target_size, pinfo->target_size);
|
||||
|
||||
DRW_framebuffer_clear(false, true, false, NULL, 1.0);
|
||||
|
@ -1078,7 +1142,7 @@ static void render_scene_to_probe(
|
|||
|
||||
DRW_draw_pass(psl->probe_background);
|
||||
|
||||
// EEVEE_create_minmax_buffer(vedata, e_data.cube_face_depth);
|
||||
// EEVEE_create_minmax_buffer(vedata, sldata->probe_depth_rt);
|
||||
|
||||
/* Rebind Planar FB */
|
||||
DRW_framebuffer_bind(sldata->probe_fb);
|
||||
|
@ -1089,9 +1153,10 @@ static void render_scene_to_probe(
|
|||
DRW_draw_pass(psl->sss_pass); /* Only output standard pass */
|
||||
|
||||
DRW_framebuffer_texture_detach(sldata->probe_rt);
|
||||
DRW_framebuffer_texture_detach(sldata->probe_depth_rt);
|
||||
}
|
||||
DRW_framebuffer_texture_attach(sldata->probe_fb, sldata->probe_rt, 0, 0);
|
||||
DRW_framebuffer_texture_detach(e_data.cube_face_depth);
|
||||
DRW_framebuffer_texture_attach(sldata->probe_fb, sldata->probe_depth_rt, 0, 0);
|
||||
|
||||
DRW_viewport_matrix_override_unset(DRW_MAT_PERS);
|
||||
DRW_viewport_matrix_override_unset(DRW_MAT_PERSINV);
|
||||
|
@ -1212,6 +1277,7 @@ static void render_world_to_probe(EEVEE_ViewLayerData *sldata, EEVEE_PassList *p
|
|||
/* Detach to rebind the right cubeface. */
|
||||
DRW_framebuffer_bind(sldata->probe_fb);
|
||||
DRW_framebuffer_texture_detach(sldata->probe_rt);
|
||||
DRW_framebuffer_texture_detach(sldata->probe_depth_rt);
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
float viewmat[4][4], persmat[4][4];
|
||||
float viewinv[4][4], persinv[4][4];
|
||||
|
@ -1237,6 +1303,7 @@ static void render_world_to_probe(EEVEE_ViewLayerData *sldata, EEVEE_PassList *p
|
|||
DRW_framebuffer_texture_detach(sldata->probe_rt);
|
||||
}
|
||||
DRW_framebuffer_texture_attach(sldata->probe_fb, sldata->probe_rt, 0, 0);
|
||||
DRW_framebuffer_texture_attach(sldata->probe_fb, sldata->probe_depth_rt, 0, 0);
|
||||
|
||||
DRW_viewport_matrix_override_unset(DRW_MAT_PERS);
|
||||
DRW_viewport_matrix_override_unset(DRW_MAT_PERSINV);
|
||||
|
@ -1276,7 +1343,7 @@ static void lightprobes_refresh_world(EEVEE_ViewLayerData *sldata, EEVEE_Data *v
|
|||
glossy_filter_probe(sldata, vedata, psl, 0);
|
||||
}
|
||||
if (e_data.update_world & PROBE_UPDATE_GRID) {
|
||||
diffuse_filter_probe(sldata, vedata, psl, 0);
|
||||
diffuse_filter_probe(sldata, vedata, psl, 0, 0.0, 0.0, 0.0, 0.0);
|
||||
SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt);
|
||||
DRW_framebuffer_texture_detach(sldata->probe_pool);
|
||||
DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->irradiance_rt, 0, 0);
|
||||
|
@ -1465,7 +1532,8 @@ static void lightprobes_refresh_all_no_world(EEVEE_ViewLayerData *sldata, EEVEE_
|
|||
DRW_uniformbuffer_update(sldata->grid_ubo, &sldata->probes->grid_data);
|
||||
}
|
||||
render_scene_to_probe(sldata, vedata, pos, prb->clipsta, prb->clipend);
|
||||
diffuse_filter_probe(sldata, vedata, psl, egrid->offset + cell_id);
|
||||
diffuse_filter_probe(sldata, vedata, psl, egrid->offset + cell_id,
|
||||
prb->clipsta, prb->clipend, egrid->visibility_range, prb->vis_blur);
|
||||
/* To see what is going on. */
|
||||
SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt);
|
||||
/* Restore */
|
||||
|
@ -1543,6 +1611,7 @@ void EEVEE_lightprobes_free(void)
|
|||
DRW_SHADER_FREE_SAFE(e_data.probe_default_sh);
|
||||
DRW_SHADER_FREE_SAFE(e_data.probe_filter_glossy_sh);
|
||||
DRW_SHADER_FREE_SAFE(e_data.probe_filter_diffuse_sh);
|
||||
DRW_SHADER_FREE_SAFE(e_data.probe_filter_visibility_sh);
|
||||
DRW_SHADER_FREE_SAFE(e_data.probe_grid_fill_sh);
|
||||
DRW_SHADER_FREE_SAFE(e_data.probe_grid_display_sh);
|
||||
DRW_SHADER_FREE_SAFE(e_data.probe_planar_display_sh);
|
||||
|
|
|
@ -374,6 +374,7 @@ static void add_standard_uniforms(
|
|||
DRW_shgroup_uniform_buffer(shgrp, "probeCubes", &sldata->probe_pool);
|
||||
DRW_shgroup_uniform_buffer(shgrp, "probePlanars", &vedata->txl->planar_pool);
|
||||
DRW_shgroup_uniform_buffer(shgrp, "irradianceGrid", &sldata->irradiance_pool);
|
||||
DRW_shgroup_uniform_int(shgrp, "irradianceVisibilitySize", &sldata->probes->irradiance_vis_size, 1);
|
||||
DRW_shgroup_uniform_buffer(shgrp, "shadowTexture", &sldata->shadow_pool);
|
||||
DRW_shgroup_uniform_int(shgrp, "outputSsrId", ssr_id, 1);
|
||||
DRW_shgroup_uniform_vec4(shgrp, "aoParameters[0]", &vedata->stl->effects->ao_dist, 2);
|
||||
|
|
|
@ -141,6 +141,7 @@ typedef struct EEVEE_PassList {
|
|||
struct DRWPass *probe_background;
|
||||
struct DRWPass *probe_glossy_compute;
|
||||
struct DRWPass *probe_diffuse_compute;
|
||||
struct DRWPass *probe_visibility_compute;
|
||||
struct DRWPass *probe_grid_fill;
|
||||
struct DRWPass *probe_display;
|
||||
struct DRWPass *probe_planar_downsample_ps;
|
||||
|
@ -369,6 +370,7 @@ typedef struct EEVEE_LightGrid {
|
|||
float increment_x[3], attenuation_bias; /* world space vector between 2 opposite cells */
|
||||
float increment_y[3], level_bias;
|
||||
float increment_z[3], pad4;
|
||||
float visibility_bias, visibility_bleed, visibility_range, pad5;
|
||||
} EEVEE_LightGrid;
|
||||
|
||||
typedef struct EEVEE_PlanarReflection {
|
||||
|
@ -391,6 +393,7 @@ typedef struct EEVEE_LightProbesInfo {
|
|||
int num_bounce;
|
||||
int cubemap_res;
|
||||
int target_size;
|
||||
int irradiance_vis_size;
|
||||
int grid_initialized;
|
||||
/* Actual number of probes that have datas. */
|
||||
int num_render_cube;
|
||||
|
@ -402,9 +405,13 @@ typedef struct EEVEE_LightProbesInfo {
|
|||
float padding_size;
|
||||
float samples_ct;
|
||||
float invsamples_ct;
|
||||
float near_clip;
|
||||
float far_clip;
|
||||
float roughness;
|
||||
float lodfactor;
|
||||
float lod_rt_max, lod_cube_max, lod_planar_max;
|
||||
float visibility_range;
|
||||
float visibility_blur;
|
||||
int shres;
|
||||
int shnbr;
|
||||
bool specular_toggle;
|
||||
|
@ -550,6 +557,7 @@ typedef struct EEVEE_ViewLayerData {
|
|||
struct GPUFrameBuffer *probe_filter_fb;
|
||||
|
||||
struct GPUTexture *probe_rt;
|
||||
struct GPUTexture *probe_depth_rt;
|
||||
struct GPUTexture *probe_pool;
|
||||
struct GPUTexture *irradiance_pool;
|
||||
struct GPUTexture *irradiance_rt;
|
||||
|
|
|
@ -86,8 +86,8 @@ static void eevee_create_shader_volumes(void)
|
|||
ds_frag = BLI_dynstr_new();
|
||||
BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl);
|
||||
BLI_dynstr_append(ds_frag, datatoc_bsdf_direct_lib_glsl);
|
||||
BLI_dynstr_append(ds_frag, datatoc_irradiance_lib_glsl);
|
||||
BLI_dynstr_append(ds_frag, datatoc_octahedron_lib_glsl);
|
||||
BLI_dynstr_append(ds_frag, datatoc_irradiance_lib_glsl);
|
||||
BLI_dynstr_append(ds_frag, datatoc_lamps_lib_glsl);
|
||||
BLI_dynstr_append(ds_frag, datatoc_volumetric_lib_glsl);
|
||||
e_data.volumetric_common_lamps_lib = BLI_dynstr_get_cstring(ds_frag);
|
||||
|
|
|
@ -432,6 +432,78 @@ vec3 normal_decode(vec2 enc, vec3 view)
|
|||
return n;
|
||||
}
|
||||
|
||||
/* ---- RGBM (shared multiplier) encoding ---- */
|
||||
/* From http://iwasbeingirony.blogspot.fr/2010/06/difference-between-rgbm-and-rgbd.html */
|
||||
|
||||
/* Higher RGBM_MAX_RANGE gives imprecision issues in low intensity. */
|
||||
#define RGBM_MAX_RANGE 512.0
|
||||
|
||||
vec4 rgbm_encode(vec3 rgb)
|
||||
{
|
||||
float maxRGB = max_v3(rgb);
|
||||
float M = maxRGB / RGBM_MAX_RANGE;
|
||||
M = ceil(M * 255.0) / 255.0;
|
||||
return vec4(rgb / (M * RGBM_MAX_RANGE), M);
|
||||
}
|
||||
|
||||
vec3 rgbm_decode(vec4 data)
|
||||
{
|
||||
return data.rgb * (data.a * RGBM_MAX_RANGE);
|
||||
}
|
||||
|
||||
/* ---- RGBE (shared exponent) encoding ---- */
|
||||
vec4 rgbe_encode(vec3 rgb)
|
||||
{
|
||||
float maxRGB = max_v3(rgb);
|
||||
float fexp = ceil(log2(maxRGB));
|
||||
return vec4(rgb / exp2(fexp), (fexp + 128.0) / 255.0);
|
||||
}
|
||||
|
||||
vec3 rgbe_decode(vec4 data)
|
||||
{
|
||||
float fexp = data.a * 255.0 - 128.0;
|
||||
return data.rgb * exp2(fexp);
|
||||
}
|
||||
|
||||
#if 1
|
||||
#define irradiance_encode rgbe_encode
|
||||
#define irradiance_decode rgbe_decode
|
||||
#else /* No ecoding (when using floating point format) */
|
||||
#define irradiance_encode(X) (X).rgbb
|
||||
#define irradiance_decode(X) (X).rgb
|
||||
#endif
|
||||
|
||||
/* Irradiance Visibility Encoding */
|
||||
#if 1
|
||||
vec4 visibility_encode(vec2 accum, float range)
|
||||
{
|
||||
accum /= range;
|
||||
|
||||
vec4 data;
|
||||
data.x = fract(accum.x);
|
||||
data.y = floor(accum.x) / 255.0;
|
||||
data.z = fract(accum.y);
|
||||
data.w = floor(accum.y) / 255.0;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
vec2 visibility_decode(vec4 data, float range)
|
||||
{
|
||||
return (data.xz + data.yw * 255.0) * range;
|
||||
}
|
||||
#else /* No ecoding (when using floating point format) */
|
||||
vec4 visibility_encode(vec2 accum, float range)
|
||||
{
|
||||
return accum.xyxy;
|
||||
}
|
||||
|
||||
vec2 visibility_decode(vec4 data, float range)
|
||||
{
|
||||
return data.xy;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Fresnel monochromatic, perfect mirror */
|
||||
float F_eta(float eta, float cos_theta)
|
||||
{
|
||||
|
|
|
@ -90,4 +90,18 @@ vec3 sample_hemisphere(float nsample, vec3 N, vec3 T, vec3 B)
|
|||
|
||||
return tangent_to_world(Ht, N, T, B);
|
||||
}
|
||||
|
||||
vec3 sample_cone(float nsample, float angle, vec3 N, vec3 T, vec3 B)
|
||||
{
|
||||
vec3 Xi = hammersley_3d(nsample);
|
||||
|
||||
float z = cos(angle * 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);
|
||||
}
|
||||
#endif
|
|
@ -1,5 +1,6 @@
|
|||
|
||||
uniform sampler2D irradianceGrid;
|
||||
uniform sampler2DArray irradianceGrid;
|
||||
uniform int irradianceVisibilitySize;
|
||||
|
||||
#define IRRADIANCE_LIB
|
||||
|
||||
|
@ -36,7 +37,7 @@ IrradianceData load_irradiance_cell(int cell, vec3 N)
|
|||
uvs += vec2(cell_co) / vec2(textureSize(irradianceGrid, 0));
|
||||
|
||||
IrradianceData ir;
|
||||
ir.color = texture(irradianceGrid, uvs).rgb;
|
||||
ir.color = texture(irradianceGrid, vec3(uvs, 0.0)).rgb;
|
||||
|
||||
#elif defined(IRRADIANCE_SH_L2)
|
||||
|
||||
|
@ -48,15 +49,15 @@ IrradianceData load_irradiance_cell(int cell, vec3 N)
|
|||
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;
|
||||
ir.shcoefs[0] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.xx, 0), 0).rgb;
|
||||
ir.shcoefs[1] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.yx, 0), 0).rgb;
|
||||
ir.shcoefs[2] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.zx, 0), 0).rgb;
|
||||
ir.shcoefs[3] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.xy, 0), 0).rgb;
|
||||
ir.shcoefs[4] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.yy, 0), 0).rgb;
|
||||
ir.shcoefs[5] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.zy, 0), 0).rgb;
|
||||
ir.shcoefs[6] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.xz, 0), 0).rgb;
|
||||
ir.shcoefs[7] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.yz, 0), 0).rgb;
|
||||
ir.shcoefs[8] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.zz, 0), 0).rgb;
|
||||
|
||||
#else /* defined(IRRADIANCE_HL2) */
|
||||
|
||||
|
@ -68,15 +69,50 @@ IrradianceData load_irradiance_cell(int cell, vec3 N)
|
|||
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;
|
||||
ir.cubesides[0] = irradiance_decode(texelFetch(irradianceGrid, ivec3(cell_co + ivec2(0, is_negative.x), 0), 0));
|
||||
ir.cubesides[1] = irradiance_decode(texelFetch(irradianceGrid, ivec3(cell_co + ivec2(1, is_negative.y), 0), 0));
|
||||
ir.cubesides[2] = irradiance_decode(texelFetch(irradianceGrid, ivec3(cell_co + ivec2(2, is_negative.z), 0), 0));
|
||||
|
||||
#endif
|
||||
|
||||
return ir;
|
||||
}
|
||||
|
||||
float load_visibility_cell(int cell, vec3 L, float dist, float bias, float bleed_bias, float range)
|
||||
{
|
||||
/* Keep in sync with diffuse_filter_probe() */
|
||||
ivec2 cell_co = ivec2(irradianceVisibilitySize);
|
||||
int cell_per_row = textureSize(irradianceGrid, 0).x / irradianceVisibilitySize;
|
||||
cell_co.x *= (cell) % cell_per_row;
|
||||
cell_co.y *= (cell) / cell_per_row;
|
||||
|
||||
vec2 texel_size = 1.0 / vec2(textureSize(irradianceGrid, 0).xy);
|
||||
vec2 co = vec2(cell_co) * texel_size;
|
||||
|
||||
vec2 uv = mapping_octahedron(-L, vec2(1.0 / float(irradianceVisibilitySize)));
|
||||
uv *= vec2(irradianceVisibilitySize) * texel_size;
|
||||
|
||||
vec4 data = texture(irradianceGrid, vec3(co + uv, 1.0));
|
||||
|
||||
/* Decoding compressed data */
|
||||
vec2 moments = visibility_decode(data, range);
|
||||
|
||||
/* Doing chebishev test */
|
||||
float variance = abs(moments.x * moments.x - moments.y);
|
||||
variance = max(variance, bias / 10.0);
|
||||
|
||||
float d = dist - moments.x;
|
||||
float p_max = variance / (variance + d * d);
|
||||
|
||||
/* Increase contrast in the weight by squaring it */
|
||||
p_max *= p_max;
|
||||
|
||||
/* Now reduce light-bleeding by removing the [0, x] tail and linearly rescaling (x, 1] */
|
||||
p_max = clamp((p_max - bleed_bias) / (1.0 - bleed_bias), 0.0, 1.0);
|
||||
|
||||
return (dist <= moments.x) ? 1.0 : p_max;
|
||||
}
|
||||
|
||||
/* http://seblagarde.wordpress.com/2012/01/08/pi-or-not-to-pi-in-game-lighting-equation/ */
|
||||
vec3 spherical_harmonics_L1(vec3 N, vec3 shcoefs[4])
|
||||
{
|
||||
|
|
|
@ -192,6 +192,6 @@ void main()
|
|||
}
|
||||
}
|
||||
|
||||
FragColor = vec4(out_radiance / weight, 1.0);
|
||||
FragColor = irradiance_encode(out_radiance / weight);
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
|
||||
uniform samplerCube probeDepth;
|
||||
uniform int outputSize;
|
||||
uniform float lodFactor;
|
||||
uniform float storedTexelSize;
|
||||
uniform float lodMax;
|
||||
uniform float nearClip;
|
||||
uniform float farClip;
|
||||
uniform float visibilityRange;
|
||||
uniform float visibilityBlur;
|
||||
|
||||
out vec4 FragColor;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
float linear_depth(float z)
|
||||
{
|
||||
return (nearClip * farClip) / (z * (nearClip - farClip) + farClip);
|
||||
}
|
||||
|
||||
float get_world_distance(float depth, vec3 cos)
|
||||
{
|
||||
float is_background = step(1.0, depth);
|
||||
depth = linear_depth(depth);
|
||||
depth += 1e1 * is_background;
|
||||
cos = normalize(abs(cos));
|
||||
float cos_vec = max(cos.x, max(cos.y, cos.z));
|
||||
return depth / cos_vec;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
ivec2 texel = ivec2(gl_FragCoord.xy) % ivec2(outputSize);
|
||||
|
||||
vec3 cos;
|
||||
|
||||
cos.xy = (vec2(texel) + 0.5) * storedTexelSize;
|
||||
|
||||
/* add a 2 pixel border to ensure filtering is correct */
|
||||
cos.xy *= 1.0 + storedTexelSize * 2.0;
|
||||
cos.xy -= storedTexelSize;
|
||||
|
||||
float pattern = 1.0;
|
||||
|
||||
/* edge mirroring : only mirror if directly adjacent
|
||||
* (not diagonally adjacent) */
|
||||
vec2 m = abs(cos.xy - 0.5) + 0.5;
|
||||
vec2 f = floor(m);
|
||||
if (f.x - f.y != 0.0) {
|
||||
cos.xy = 1.0 - cos.xy;
|
||||
}
|
||||
|
||||
/* clamp to [0-1] */
|
||||
cos.xy = fract(cos.xy);
|
||||
|
||||
/* get cubemap vector */
|
||||
cos = normalize(octahedral_to_cubemap_proj(cos.xy));
|
||||
|
||||
vec3 T, B;
|
||||
make_orthonormal_basis(cos, T, B); /* Generate tangent space */
|
||||
|
||||
vec2 accum = vec2(0.0);
|
||||
|
||||
for (float i = 0; i < sampleCount; i++) {
|
||||
vec3 sample = sample_cone(i, M_PI_2 * visibilityBlur, cos, T, B);
|
||||
float depth = texture(probeDepth, sample).r;
|
||||
depth = get_world_distance(depth, sample);
|
||||
accum += vec2(depth, depth * depth);
|
||||
}
|
||||
|
||||
accum *= invSampleCount;
|
||||
accum = abs(accum);
|
||||
|
||||
/* Encode to normalized RGBA 8 */
|
||||
FragColor = visibility_encode(accum, visibilityRange);
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
uniform sampler2D gridTexture;
|
||||
uniform sampler2DArray irradianceGrid;
|
||||
|
||||
out vec4 FragColor;
|
||||
|
||||
|
@ -12,7 +12,7 @@ void main()
|
|||
const ivec2 data_size = ivec2(3, 2);
|
||||
#endif
|
||||
ivec2 coord = ivec2(gl_FragCoord.xy) % data_size;
|
||||
FragColor = texelFetch(gridTexture, coord, 0);
|
||||
FragColor = texelFetch(irradianceGrid, ivec3(coord, 0), 0);
|
||||
|
||||
if (any(greaterThanEqual(ivec2(gl_FragCoord.xy), data_size))) {
|
||||
FragColor = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
|
|
|
@ -49,6 +49,7 @@ struct GridData {
|
|||
vec4 ws_increment_x_atten_bias; /* world space vector between 2 opposite cells */
|
||||
vec4 ws_increment_y_lvl_bias;
|
||||
vec4 ws_increment_z;
|
||||
vec4 vis_bias_bleed_range;
|
||||
};
|
||||
|
||||
#define g_corner ws_corner_atten_scale.xyz
|
||||
|
@ -60,6 +61,9 @@ struct GridData {
|
|||
#define g_increment_z ws_increment_z.xyz
|
||||
#define g_resolution resolution_offset.xyz
|
||||
#define g_offset resolution_offset.w
|
||||
#define g_vis_bias vis_bias_bleed_range.x
|
||||
#define g_vis_bleed vis_bias_bleed_range.y
|
||||
#define g_vis_range vis_bias_bleed_range.z
|
||||
|
||||
#ifndef MAX_PROBE
|
||||
#define MAX_PROBE 1
|
||||
|
@ -227,14 +231,18 @@ vec3 probe_evaluate_grid(GridData gd, vec3 W, vec3 N, vec3 localpos)
|
|||
gd.g_increment_y * cell_cos.y +
|
||||
gd.g_increment_z * cell_cos.z);
|
||||
|
||||
// vec3 ws_point_to_cell = ws_cell_location - W;
|
||||
// vec3 ws_light = normalize(ws_point_to_cell);
|
||||
vec3 ws_point_to_cell = ws_cell_location - W;
|
||||
float ws_dist_point_to_cell = length(ws_point_to_cell);
|
||||
vec3 ws_light = ws_point_to_cell / ws_dist_point_to_cell;
|
||||
|
||||
vec3 trilinear = mix(1 - trilinear_weight, trilinear_weight, offset);
|
||||
float weight = trilinear.x * trilinear.y * trilinear.z;
|
||||
|
||||
/* Precomputed visibility */
|
||||
weight *= load_visibility_cell(cell, ws_light, ws_dist_point_to_cell, gd.g_vis_bias, gd.g_vis_bleed, gd.g_vis_range);
|
||||
|
||||
/* Smooth backface test */
|
||||
// weight *= sqrt(max(0.002, dot(ws_light, N)));
|
||||
weight *= sqrt(max(0.002, dot(ws_light, N)));
|
||||
|
||||
/* Avoid zero weight */
|
||||
weight = max(0.00001, weight);
|
||||
|
|
|
@ -128,12 +128,16 @@ vec3 light_volume_shadow(LightData ld, vec3 ray_wpos, vec4 l_vector, sampler3D v
|
|||
#ifdef IRRADIANCE_LIB
|
||||
vec3 irradiance_volumetric(vec3 wpos)
|
||||
{
|
||||
#ifdef IRRADIANCE_HL2
|
||||
IrradianceData ir_data = load_irradiance_cell(0, vec3(1.0));
|
||||
vec3 irradiance = ir_data.cubesides[0] + ir_data.cubesides[1] + ir_data.cubesides[2];
|
||||
ir_data = load_irradiance_cell(0, vec3(-1.0));
|
||||
irradiance += ir_data.cubesides[0] + ir_data.cubesides[1] + ir_data.cubesides[2];
|
||||
irradiance *= 0.16666666; /* 1/6 */
|
||||
return irradiance;
|
||||
#else
|
||||
return vec3(0.0);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
Loading…
Reference in New Issue