Eevee: Initial implementation of planar reflections.
Still pretty barebone: No roughness support, No normal distortion support.
This commit is contained in:
parent
5c67ac2236
commit
3e4b9d2b5a
|
@ -54,6 +54,7 @@ static void eevee_scene_layer_data_free(void *storage)
|
|||
MEM_SAFE_FREE(sldata->probes);
|
||||
DRW_UBO_FREE_SAFE(sldata->probe_ubo);
|
||||
DRW_UBO_FREE_SAFE(sldata->grid_ubo);
|
||||
DRW_UBO_FREE_SAFE(sldata->planar_ubo);
|
||||
DRW_FRAMEBUFFER_FREE_SAFE(sldata->probe_fb);
|
||||
DRW_FRAMEBUFFER_FREE_SAFE(sldata->probe_filter_fb);
|
||||
DRW_TEXTURE_FREE_SAFE(sldata->probe_rt);
|
||||
|
|
|
@ -57,7 +57,7 @@ static void EEVEE_engine_init(void *ved)
|
|||
|
||||
EEVEE_materials_init();
|
||||
EEVEE_lights_init(sldata);
|
||||
EEVEE_lightprobes_init(sldata);
|
||||
EEVEE_lightprobes_init(sldata, vedata);
|
||||
EEVEE_effects_init(vedata);
|
||||
}
|
||||
|
||||
|
@ -134,7 +134,7 @@ static void EEVEE_draw_scene(void *vedata)
|
|||
EEVEE_draw_shadows(sldata, psl);
|
||||
|
||||
/* Refresh Probes */
|
||||
EEVEE_lightprobes_refresh(sldata, psl);
|
||||
EEVEE_lightprobes_refresh(sldata, vedata);
|
||||
|
||||
/* Attach depth to the hdr buffer and bind it */
|
||||
DRW_framebuffer_texture_detach(dtxl->depth);
|
||||
|
|
|
@ -59,6 +59,7 @@ static struct {
|
|||
struct GPUShader *probe_cube_display_sh;
|
||||
|
||||
struct GPUTexture *hammersley;
|
||||
struct GPUTexture *planar_depth;
|
||||
|
||||
bool update_world;
|
||||
bool world_ready_to_shade;
|
||||
|
@ -112,7 +113,46 @@ static struct GPUTexture *create_hammersley_sample_texture(int samples)
|
|||
return tex;
|
||||
}
|
||||
|
||||
void EEVEE_lightprobes_init(EEVEE_SceneLayerData *sldata)
|
||||
static void planar_pool_ensure_alloc(EEVEE_Data *vedata, int num_planar_ref)
|
||||
{
|
||||
/* XXX TODO OPTIMISATION : This is a complete waist of texture memory.
|
||||
* Instead of allocating each planar probe for each viewport,
|
||||
* only alloc them once using the biggest viewport resolution. */
|
||||
EEVEE_FramebufferList *fbl = vedata->fbl;
|
||||
EEVEE_TextureList *txl = vedata->txl;
|
||||
|
||||
const float *viewport_size = DRW_viewport_size_get();
|
||||
|
||||
/* TODO get screen percentage from layer setting */
|
||||
// const DRWContextState *draw_ctx = DRW_context_state_get();
|
||||
// SceneLayer *sl = draw_ctx->sl;
|
||||
float screen_percentage = 1.0f;
|
||||
|
||||
int width = (int)(viewport_size[0] * screen_percentage);
|
||||
int height = (int)(viewport_size[1] * screen_percentage);
|
||||
|
||||
/* We need an Array texture so allocate it ourself */
|
||||
if (!txl->planar_pool && (num_planar_ref > 0)) {
|
||||
txl->planar_pool = DRW_texture_create_2D_array(width, height, max_ff(1, num_planar_ref),
|
||||
DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER | DRW_TEX_MIPMAP, NULL);
|
||||
}
|
||||
else if (txl->planar_pool && (num_planar_ref == 0)) {
|
||||
DRW_TEXTURE_FREE_SAFE(txl->planar_pool);
|
||||
}
|
||||
|
||||
if (num_planar_ref > 0) {
|
||||
/* NOTE : Depth buffer is 2D but the planar_pool tex is 2D array.
|
||||
* DRW_framebuffer_init binds the whole texture making the framebuffer invalid.
|
||||
* To overcome this, we bind the planar pool ourselves later */
|
||||
|
||||
DRWFboTexture tex = {&e_data.planar_depth, DRW_TEX_DEPTH_24, DRW_TEX_TEMP};
|
||||
|
||||
DRW_framebuffer_init(&fbl->planarref_fb, &draw_engine_eevee_type,
|
||||
width, height, &tex, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void EEVEE_lightprobes_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *UNUSED(vedata))
|
||||
{
|
||||
/* Shaders */
|
||||
if (!e_data.probe_filter_glossy_sh) {
|
||||
|
@ -195,6 +235,7 @@ void EEVEE_lightprobes_init(EEVEE_SceneLayerData *sldata)
|
|||
sldata->probes->specular_toggle = true;
|
||||
sldata->probe_ubo = DRW_uniformbuffer_create(sizeof(EEVEE_LightProbe) * MAX_PROBE, NULL);
|
||||
sldata->grid_ubo = DRW_uniformbuffer_create(sizeof(EEVEE_LightGrid) * MAX_GRID, NULL);
|
||||
sldata->planar_ubo = DRW_uniformbuffer_create(sizeof(EEVEE_PlanarReflection) * MAX_PLANAR, NULL);
|
||||
}
|
||||
|
||||
/* Setup Render Target Cubemap */
|
||||
|
@ -215,8 +256,10 @@ void EEVEE_lightprobes_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_PassList *
|
|||
|
||||
pinfo->num_cube = 1; /* at least one for the world */
|
||||
pinfo->num_grid = 1;
|
||||
pinfo->num_planar = 0;
|
||||
memset(pinfo->probes_cube_ref, 0, sizeof(pinfo->probes_cube_ref));
|
||||
memset(pinfo->probes_grid_ref, 0, sizeof(pinfo->probes_grid_ref));
|
||||
memset(pinfo->probes_planar_ref, 0, sizeof(pinfo->probes_planar_ref));
|
||||
|
||||
{
|
||||
psl->probe_background = DRW_pass_create("World Probe Pass", DRW_STATE_WRITE_COLOR);
|
||||
|
@ -356,17 +399,122 @@ void EEVEE_lightprobes_cache_add(EEVEE_SceneLayerData *sldata, Object *ob)
|
|||
pinfo->probes_cube_ref[pinfo->num_cube] = ob;
|
||||
pinfo->num_cube++;
|
||||
}
|
||||
else if (probe->type == LIGHTPROBE_TYPE_PLANAR) {
|
||||
pinfo->probes_planar_ref[pinfo->num_planar] = ob;
|
||||
pinfo->num_planar++;
|
||||
}
|
||||
else { /* GRID */
|
||||
pinfo->probes_grid_ref[pinfo->num_grid] = ob;
|
||||
pinfo->num_grid++;
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO find a nice name to push it to math_matrix.c */
|
||||
static void scale_m4_v3(float R[4][4], float v[3])
|
||||
{
|
||||
for (int i = 0; i < 4; ++i)
|
||||
mul_v3_v3(R[i], v);
|
||||
}
|
||||
|
||||
static void EEVEE_planar_reflections_updates(EEVEE_SceneLayerData *sldata)
|
||||
{
|
||||
EEVEE_LightProbesInfo *pinfo = sldata->probes;
|
||||
Object *ob;
|
||||
float mtx[4][4], normat[4][4], imat[4][4], rangemat[4][4];
|
||||
|
||||
float viewmat[4][4], winmat[4][4];
|
||||
DRW_viewport_matrix_get(viewmat, DRW_MAT_VIEW);
|
||||
DRW_viewport_matrix_get(winmat, DRW_MAT_WIN);
|
||||
|
||||
zero_m4(rangemat);
|
||||
rangemat[0][0] = rangemat[1][1] = rangemat[2][2] = 0.5f;
|
||||
rangemat[3][0] = rangemat[3][1] = rangemat[3][2] = 0.5f;
|
||||
rangemat[3][3] = 1.0f;
|
||||
|
||||
/* PLANAR REFLECTION */
|
||||
for (int i = 0; (ob = pinfo->probes_planar_ref[i]) && (i < MAX_PLANAR); i++) {
|
||||
LightProbe *probe = (LightProbe *)ob->data;
|
||||
EEVEE_PlanarReflection *eplanar = &pinfo->planar_data[i];
|
||||
EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_get(ob);
|
||||
|
||||
/* Computing mtx : matrix that mirror position around object's XY plane. */
|
||||
normalize_m4_m4(normat, ob->obmat); /* object > world */
|
||||
invert_m4_m4(imat, normat); /* world > object */
|
||||
|
||||
float reflect[3] = {1.0f, 1.0f, -1.0f}; /* XY reflection plane */
|
||||
scale_m4_v3(imat, reflect); /* world > object > mirrored obj */
|
||||
mul_m4_m4m4(mtx, normat, imat); /* world > object > mirrored obj > world */
|
||||
|
||||
/* Reflect Camera Matrix. */
|
||||
mul_m4_m4m4(ped->viewmat, viewmat, mtx);
|
||||
|
||||
/* TODO FOV margin */
|
||||
float winmat_fov[4][4];
|
||||
copy_m4_m4(winmat_fov, winmat);
|
||||
|
||||
/* Apply Perspective Matrix. */
|
||||
mul_m4_m4m4(ped->persmat, winmat_fov, ped->viewmat);
|
||||
|
||||
/* This is the matrix used to reconstruct texture coordinates.
|
||||
* We use the original view matrix because it does not create
|
||||
* visual artifacts if receiver is not perfectly aligned with
|
||||
* the planar reflection probe. */
|
||||
mul_m4_m4m4(eplanar->reflectionmat, winmat_fov, viewmat); /* TODO FOV margin */
|
||||
/* Convert from [-1, 1] to [0, 1] (NDC to Texture coord). */
|
||||
mul_m4_m4m4(eplanar->reflectionmat, rangemat, eplanar->reflectionmat);
|
||||
|
||||
/* TODO frustum check. */
|
||||
ped->need_update = true;
|
||||
|
||||
/* Compute clip plane equation / normal. */
|
||||
float refpoint[3];
|
||||
copy_v3_v3(eplanar->plane_equation, ob->obmat[2]);
|
||||
normalize_v3(eplanar->plane_equation); /* plane normal */
|
||||
mul_v3_v3fl(refpoint, eplanar->plane_equation, -probe->clipsta);
|
||||
add_v3_v3(refpoint, ob->obmat[3]);
|
||||
eplanar->plane_equation[3] = -dot_v3v3(eplanar->plane_equation, refpoint);
|
||||
|
||||
/* Compute XY clip planes. */
|
||||
normalize_v3_v3(eplanar->clip_vec_x, ob->obmat[0]);
|
||||
normalize_v3_v3(eplanar->clip_vec_y, ob->obmat[1]);
|
||||
|
||||
float vec[3] = {0.0f, 0.0f, 0.0f};
|
||||
vec[0] = 1.0f; vec[1] = 0.0f; vec[2] = 0.0f;
|
||||
mul_m4_v3(ob->obmat, vec); /* Point on the edge */
|
||||
eplanar->clip_edge_x_pos = dot_v3v3(eplanar->clip_vec_x, vec);
|
||||
|
||||
vec[0] = 0.0f; vec[1] = 1.0f; vec[2] = 0.0f;
|
||||
mul_m4_v3(ob->obmat, vec); /* Point on the edge */
|
||||
eplanar->clip_edge_y_pos = dot_v3v3(eplanar->clip_vec_y, vec);
|
||||
|
||||
vec[0] = -1.0f; vec[1] = 0.0f; vec[2] = 0.0f;
|
||||
mul_m4_v3(ob->obmat, vec); /* Point on the edge */
|
||||
eplanar->clip_edge_x_neg = dot_v3v3(eplanar->clip_vec_x, vec);
|
||||
|
||||
vec[0] = 0.0f; vec[1] = -1.0f; vec[2] = 0.0f;
|
||||
mul_m4_v3(ob->obmat, vec); /* Point on the edge */
|
||||
eplanar->clip_edge_y_neg = dot_v3v3(eplanar->clip_vec_y, vec);
|
||||
|
||||
/* Facing factors */
|
||||
float max_angle = max_ff(1e-2f, probe->falloff) * M_PI * 0.5f;
|
||||
float min_angle = 0.0f;
|
||||
eplanar->facing_scale = 1.0f / max_ff(1e-8f, cosf(min_angle) - cosf(max_angle));
|
||||
eplanar->facing_bias = -min_ff(1.0f - 1e-8f, cosf(max_angle)) * eplanar->facing_scale;
|
||||
|
||||
/* Distance factors */
|
||||
float max_dist = probe->distinf;
|
||||
float min_dist = min_ff(1.0f - 1e-8f, 1.0f - probe->falloff) * probe->distinf;
|
||||
eplanar->attenuation_scale = -1.0f / max_ff(1e-8f, max_dist - min_dist);
|
||||
eplanar->attenuation_bias = max_dist * -eplanar->attenuation_scale;
|
||||
}
|
||||
}
|
||||
|
||||
static void EEVEE_lightprobes_updates(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl, EEVEE_StorageList *stl)
|
||||
{
|
||||
EEVEE_LightProbesInfo *pinfo = sldata->probes;
|
||||
Object *ob;
|
||||
|
||||
/* CUBE REFLECTION */
|
||||
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];
|
||||
|
@ -406,6 +554,7 @@ static void EEVEE_lightprobes_updates(EEVEE_SceneLayerData *sldata, EEVEE_PassLi
|
|||
}
|
||||
}
|
||||
|
||||
/* IRRADIANCE GRID */
|
||||
int offset = 1; /* to account for the world probe */
|
||||
for (int i = 1; (ob = pinfo->probes_grid_ref[i]) && (i < MAX_GRID); i++) {
|
||||
LightProbe *probe = (LightProbe *)ob->data;
|
||||
|
@ -485,6 +634,14 @@ void EEVEE_lightprobes_cache_finish(EEVEE_SceneLayerData *sldata, EEVEE_Data *ve
|
|||
DRW_TEXTURE_FREE_SAFE(sldata->probe_pool);
|
||||
}
|
||||
|
||||
if (pinfo->num_planar != pinfo->cache_num_planar) {
|
||||
DRW_TEXTURE_FREE_SAFE(vedata->txl->planar_pool);
|
||||
pinfo->cache_num_planar = pinfo->num_planar;
|
||||
}
|
||||
|
||||
/* XXX this should be run each frame as it ensure planar_depth is set */
|
||||
planar_pool_ensure_alloc(vedata, pinfo->num_planar);
|
||||
|
||||
if (!sldata->probe_pool) {
|
||||
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);
|
||||
|
@ -511,6 +668,7 @@ void EEVEE_lightprobes_cache_finish(EEVEE_SceneLayerData *sldata, EEVEE_Data *ve
|
|||
|
||||
DRW_framebuffer_init(&sldata->probe_filter_fb, &draw_engine_eevee_type, PROBE_OCTAHEDRON_SIZE, PROBE_OCTAHEDRON_SIZE, &tex_filter, 1);
|
||||
|
||||
|
||||
#ifdef IRRADIANCE_SH_L2
|
||||
/* we need a signed format for Spherical Harmonics */
|
||||
int irradiance_format = DRW_TEX_RGBA_16;
|
||||
|
@ -544,9 +702,11 @@ void EEVEE_lightprobes_cache_finish(EEVEE_SceneLayerData *sldata, EEVEE_Data *ve
|
|||
}
|
||||
|
||||
EEVEE_lightprobes_updates(sldata, vedata->psl, vedata->stl);
|
||||
EEVEE_planar_reflections_updates(sldata);
|
||||
|
||||
DRW_uniformbuffer_update(sldata->probe_ubo, &sldata->probes->probe_data);
|
||||
DRW_uniformbuffer_update(sldata->grid_ubo, &sldata->probes->grid_data);
|
||||
DRW_uniformbuffer_update(sldata->planar_ubo, &sldata->probes->planar_data);
|
||||
}
|
||||
|
||||
/* Glossy filter probe_rt to probe_pool at index probe_idx */
|
||||
|
@ -709,8 +869,7 @@ static void render_scene_to_probe(
|
|||
DRW_framebuffer_cubeface_attach(sldata->probe_fb, sldata->probe_depth_rt, 0, i, 0);
|
||||
DRW_framebuffer_viewport_size(sldata->probe_fb, 0, 0, PROBE_RT_SIZE, PROBE_RT_SIZE);
|
||||
|
||||
float clear[4] = {1.0f, 0.0f, 0.0f, 1.0f};
|
||||
DRW_framebuffer_clear(true, true, false, clear, 1.0);
|
||||
DRW_framebuffer_clear(false, true, false, NULL, 1.0);
|
||||
|
||||
/* Setup custom matrices */
|
||||
mul_m4_m4m4(viewmat, cubefacemat[i], posmat);
|
||||
|
@ -751,6 +910,67 @@ static void render_scene_to_probe(
|
|||
sldata->probes->specular_toggle = true;
|
||||
}
|
||||
|
||||
static void render_scene_to_planar(
|
||||
EEVEE_Data *vedata, int layer,
|
||||
float (*viewmat)[4], float (*persmat)[4],
|
||||
float clip_plane[4])
|
||||
{
|
||||
EEVEE_FramebufferList *fbl = vedata->fbl;
|
||||
EEVEE_TextureList *txl = vedata->txl;
|
||||
EEVEE_PassList *psl = vedata->psl;
|
||||
|
||||
float viewinv[4][4];
|
||||
float persinv[4][4];
|
||||
|
||||
invert_m4_m4(viewinv, viewmat);
|
||||
invert_m4_m4(persinv, persmat);
|
||||
|
||||
/* Attach depth here since it's a DRW_TEX_TEMP */
|
||||
DRW_framebuffer_texture_attach(fbl->planarref_fb, e_data.planar_depth, 0, 0);
|
||||
DRW_framebuffer_texture_layer_attach(fbl->planarref_fb, txl->planar_pool, 0, layer, 0);
|
||||
DRW_framebuffer_bind(fbl->planarref_fb);
|
||||
|
||||
DRW_framebuffer_clear(false, true, false, NULL, 1.0);
|
||||
|
||||
/* Avoid using the texture attached to framebuffer when rendering. */
|
||||
GPUTexture *tmp_planar_pool = txl->planar_pool;
|
||||
txl->planar_pool = NULL;
|
||||
DRW_viewport_matrix_override_set(persmat, DRW_MAT_PERS);
|
||||
DRW_viewport_matrix_override_set(persinv, DRW_MAT_PERSINV);
|
||||
DRW_viewport_matrix_override_set(viewmat, DRW_MAT_VIEW);
|
||||
DRW_viewport_matrix_override_set(viewinv, DRW_MAT_VIEWINV);
|
||||
|
||||
/* Background */
|
||||
DRW_draw_pass(psl->background_pass);
|
||||
|
||||
/* Since we are rendering with an inverted view matrix, we need
|
||||
* to invert the facing for backface culling to be the same. */
|
||||
DRW_state_invert_facing();
|
||||
DRW_state_clip_planes_add(clip_plane);
|
||||
|
||||
/* Depth prepass */
|
||||
DRW_draw_pass(psl->depth_pass_clip);
|
||||
DRW_draw_pass(psl->depth_pass_clip_cull);
|
||||
|
||||
/* Shading pass */
|
||||
DRW_draw_pass(psl->default_pass);
|
||||
DRW_draw_pass(psl->default_flat_pass);
|
||||
DRW_draw_pass(psl->material_pass);
|
||||
|
||||
DRW_state_invert_facing();
|
||||
DRW_state_clip_planes_reset();
|
||||
|
||||
/* Restore */
|
||||
txl->planar_pool = tmp_planar_pool;
|
||||
DRW_viewport_matrix_override_unset(DRW_MAT_PERS);
|
||||
DRW_viewport_matrix_override_unset(DRW_MAT_PERSINV);
|
||||
DRW_viewport_matrix_override_unset(DRW_MAT_VIEW);
|
||||
DRW_viewport_matrix_override_unset(DRW_MAT_VIEWINV);
|
||||
|
||||
DRW_framebuffer_texture_detach(txl->planar_pool);
|
||||
DRW_framebuffer_texture_detach(e_data.planar_depth);
|
||||
}
|
||||
|
||||
static void render_world_to_probe(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl)
|
||||
{
|
||||
EEVEE_LightProbesInfo *pinfo = sldata->probes;
|
||||
|
@ -780,8 +1000,9 @@ static void lightprobe_cell_location_get(EEVEE_LightGrid *egrid, int cell_idx, f
|
|||
add_v3_v3(r_pos, tmp);
|
||||
}
|
||||
|
||||
void EEVEE_lightprobes_refresh(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl)
|
||||
void EEVEE_lightprobes_refresh(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata)
|
||||
{
|
||||
EEVEE_PassList *psl = vedata->psl;
|
||||
EEVEE_LightProbesInfo *pinfo = sldata->probes;
|
||||
Object *ob;
|
||||
const DRWContextState *draw_ctx = DRW_context_state_get();
|
||||
|
@ -814,7 +1035,7 @@ void EEVEE_lightprobes_refresh(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl
|
|||
/* Only compute probes if not navigating or in playback */
|
||||
struct wmWindowManager *wm = CTX_wm_manager(draw_ctx->evil_C);
|
||||
if (((rv3d->rflag & RV3D_NAVIGATING) != 0) || ED_screen_animation_no_scrub(wm) != NULL) {
|
||||
return;
|
||||
goto update_planar;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -836,7 +1057,9 @@ void EEVEE_lightprobes_refresh(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl
|
|||
/* Temporary Remove all probes. */
|
||||
int tmp_num_render_grid = pinfo->num_render_grid;
|
||||
int tmp_num_render_cube = pinfo->num_render_cube;
|
||||
int tmp_num_planar = pinfo->num_planar;
|
||||
pinfo->num_render_cube = 0;
|
||||
pinfo->num_planar = 0;
|
||||
|
||||
/* Use light from previous bounce when capturing radiance. */
|
||||
if (pinfo->updated_bounce == 0) {
|
||||
|
@ -852,6 +1075,7 @@ void EEVEE_lightprobes_refresh(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl
|
|||
/* Restore */
|
||||
pinfo->num_render_grid = tmp_num_render_grid;
|
||||
pinfo->num_render_cube = tmp_num_render_cube;
|
||||
pinfo->num_planar = tmp_num_planar;
|
||||
|
||||
/* To see what is going on. */
|
||||
SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt);
|
||||
|
@ -863,7 +1087,7 @@ void EEVEE_lightprobes_refresh(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl
|
|||
|
||||
/* Only do one probe per frame */
|
||||
DRW_viewport_request_redraw();
|
||||
return;
|
||||
goto update_planar;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -901,10 +1125,31 @@ void EEVEE_lightprobes_refresh(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl
|
|||
DRW_viewport_request_redraw();
|
||||
|
||||
/* Only do one probe per frame */
|
||||
return;
|
||||
goto update_planar;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
update_planar:
|
||||
|
||||
for (int i = 0; (ob = pinfo->probes_planar_ref[i]) && (i < MAX_PLANAR); i++) {
|
||||
EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_get(ob);
|
||||
|
||||
if (ped->need_update) {
|
||||
EEVEE_PlanarReflection *eplanar = &pinfo->planar_data[i];
|
||||
|
||||
/* Temporary Remove all planar reflections (avoid lag effect). */
|
||||
int tmp_num_planar = pinfo->num_planar;
|
||||
pinfo->num_planar = 0;
|
||||
|
||||
render_scene_to_planar(vedata, i, ped->viewmat, ped->persmat, eplanar->plane_equation);
|
||||
|
||||
/* Restore */
|
||||
pinfo->num_planar = tmp_num_planar;
|
||||
|
||||
ped->need_update = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EEVEE_lightprobes_free(void)
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
"#define EEVEE_ENGINE\n" \
|
||||
"#define MAX_PROBE " STRINGIFY(MAX_PROBE) "\n" \
|
||||
"#define MAX_GRID " STRINGIFY(MAX_GRID) "\n" \
|
||||
"#define MAX_PLANAR " STRINGIFY(MAX_PLANAR) "\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" \
|
||||
|
@ -305,19 +306,22 @@ struct GPUMaterial *EEVEE_material_hair_get(struct Scene *scene, Material *ma)
|
|||
SHADER_DEFINES "#define MESH_SHADER\n" "#define HAIR_SHADER\n");
|
||||
}
|
||||
|
||||
static void add_standard_uniforms(DRWShadingGroup *shgrp, EEVEE_SceneLayerData *sldata)
|
||||
static void add_standard_uniforms(DRWShadingGroup *shgrp, EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata)
|
||||
{
|
||||
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, "planar_block", sldata->planar_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_cube, 1);
|
||||
DRW_shgroup_uniform_int(shgrp, "grid_count", &sldata->probes->num_render_grid, 1);
|
||||
DRW_shgroup_uniform_int(shgrp, "planar_count", &sldata->probes->num_planar, 1);
|
||||
DRW_shgroup_uniform_bool(shgrp, "specToggle", &sldata->probes->specular_toggle, 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, "probePlanars", &vedata->txl->planar_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);
|
||||
|
@ -395,15 +399,15 @@ void EEVEE_materials_cache_init(EEVEE_Data *vedata)
|
|||
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_WIRE;
|
||||
psl->default_pass = DRW_pass_create("Default Lit Pass", state);
|
||||
DRWShadingGroup *shgrp = DRW_shgroup_create(e_data.default_lit, psl->default_pass);
|
||||
add_standard_uniforms(shgrp, sldata);
|
||||
add_standard_uniforms(shgrp, sldata, vedata);
|
||||
|
||||
psl->default_flat_pass = DRW_pass_create("Default Flat Lit Pass", state);
|
||||
shgrp = DRW_shgroup_create(e_data.default_lit_flat, psl->default_flat_pass);
|
||||
add_standard_uniforms(shgrp, sldata);
|
||||
add_standard_uniforms(shgrp, sldata, vedata);
|
||||
|
||||
psl->default_hair_pass = DRW_pass_create("Default Hair Lit Pass", state);
|
||||
shgrp = DRW_shgroup_create(e_data.default_lit_hair, psl->default_hair_pass);
|
||||
add_standard_uniforms(shgrp, sldata);
|
||||
add_standard_uniforms(shgrp, sldata, vedata);
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -477,7 +481,7 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_SceneLayerData *sl
|
|||
|
||||
shgrp = DRW_shgroup_material_create(gpumat, psl->material_pass);
|
||||
if (shgrp) {
|
||||
add_standard_uniforms(shgrp, sldata);
|
||||
add_standard_uniforms(shgrp, sldata, vedata);
|
||||
|
||||
BLI_ghash_insert(material_hash, ma, shgrp);
|
||||
|
||||
|
@ -549,7 +553,7 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_SceneLayerData *sl
|
|||
|
||||
shgrp = DRW_shgroup_material_create(gpumat, psl->material_pass);
|
||||
if (shgrp) {
|
||||
add_standard_uniforms(shgrp, sldata);
|
||||
add_standard_uniforms(shgrp, sldata, vedata);
|
||||
|
||||
BLI_ghash_insert(material_hash, ma, shgrp);
|
||||
|
||||
|
|
|
@ -33,6 +33,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_PLANAR 16 /* 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
|
||||
|
@ -90,6 +91,8 @@ typedef struct EEVEE_FramebufferList {
|
|||
struct GPUFrameBuffer *dof_scatter_far_fb;
|
||||
struct GPUFrameBuffer *dof_scatter_near_fb;
|
||||
|
||||
struct GPUFrameBuffer *planarref_fb;
|
||||
|
||||
struct GPUFrameBuffer *main; /* HDR */
|
||||
} EEVEE_FramebufferList;
|
||||
|
||||
|
@ -105,6 +108,8 @@ typedef struct EEVEE_TextureList {
|
|||
struct GPUTexture *bloom_downsample[MAX_BLOOM_STEP]; /* R16_G16_B16 */
|
||||
struct GPUTexture *bloom_upsample[MAX_BLOOM_STEP-1]; /* R16_G16_B16 */
|
||||
|
||||
struct GPUTexture *planar_pool;
|
||||
|
||||
struct GPUTexture *color; /* R16_G16_B16 */
|
||||
} EEVEE_TextureList;
|
||||
|
||||
|
@ -193,10 +198,21 @@ typedef struct EEVEE_LightGrid {
|
|||
float increment_z[3], pad4;
|
||||
} EEVEE_LightGrid;
|
||||
|
||||
typedef struct EEVEE_PlanarReflection {
|
||||
float plane_equation[4];
|
||||
float clip_vec_x[3], attenuation_scale;
|
||||
float clip_vec_y[3], attenuation_bias;
|
||||
float clip_edge_x_pos, clip_edge_x_neg;
|
||||
float clip_edge_y_pos, clip_edge_y_neg;
|
||||
float facing_scale, facing_bias, pad[2];
|
||||
float reflectionmat[4][4];
|
||||
} EEVEE_PlanarReflection;
|
||||
|
||||
/* ************ PROBE DATA ************* */
|
||||
typedef struct EEVEE_LightProbesInfo {
|
||||
int num_cube, cache_num_cube;
|
||||
int num_grid, cache_num_grid;
|
||||
int num_planar, cache_num_planar;
|
||||
int update_flag;
|
||||
int updated_bounce;
|
||||
/* Actual number of probes that have datas. */
|
||||
|
@ -219,9 +235,11 @@ typedef struct EEVEE_LightProbesInfo {
|
|||
/* XXX This is fragile, can get out of sync quickly. */
|
||||
struct Object *probes_cube_ref[MAX_PROBE];
|
||||
struct Object *probes_grid_ref[MAX_GRID];
|
||||
struct Object *probes_planar_ref[MAX_PLANAR];
|
||||
/* UBO Storage : data used by UBO */
|
||||
struct EEVEE_LightProbe probe_data[MAX_PROBE];
|
||||
struct EEVEE_LightGrid grid_data[MAX_GRID];
|
||||
struct EEVEE_PlanarReflection planar_data[MAX_PLANAR];
|
||||
} EEVEE_LightProbesInfo;
|
||||
|
||||
/* EEVEE_LightProbesInfo->update_flag */
|
||||
|
@ -296,6 +314,7 @@ typedef struct EEVEE_SceneLayerData {
|
|||
|
||||
struct GPUUniformBuffer *probe_ubo;
|
||||
struct GPUUniformBuffer *grid_ubo;
|
||||
struct GPUUniformBuffer *planar_ubo;
|
||||
|
||||
struct GPUFrameBuffer *probe_fb;
|
||||
struct GPUFrameBuffer *probe_filter_fb;
|
||||
|
@ -322,6 +341,9 @@ typedef struct EEVEE_LightProbeEngineData {
|
|||
int updated_cells;
|
||||
int num_cell;
|
||||
int probe_id; /* Only used for display data */
|
||||
/* For planar reflection rendering */
|
||||
float viewmat[4][4];
|
||||
float persmat[4][4];
|
||||
struct ListBase captured_object_list;
|
||||
} EEVEE_LightProbeEngineData;
|
||||
|
||||
|
@ -380,11 +402,11 @@ void EEVEE_draw_shadows(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl);
|
|||
void EEVEE_lights_free(void);
|
||||
|
||||
/* eevee_lightprobes.c */
|
||||
void EEVEE_lightprobes_init(EEVEE_SceneLayerData *sldata);
|
||||
void EEVEE_lightprobes_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata);
|
||||
void EEVEE_lightprobes_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl, EEVEE_StorageList *stl);
|
||||
void EEVEE_lightprobes_cache_add(EEVEE_SceneLayerData *sldata, Object *ob);
|
||||
void EEVEE_lightprobes_cache_finish(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata);
|
||||
void EEVEE_lightprobes_refresh(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl);
|
||||
void EEVEE_lightprobes_refresh(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata);
|
||||
void EEVEE_lightprobes_free(void);
|
||||
|
||||
/* eevee_effects.c */
|
||||
|
|
|
@ -24,6 +24,25 @@ struct ProbeData {
|
|||
#define p_atten_fac attenuation_fac_type.x
|
||||
#define p_atten_type attenuation_fac_type.y
|
||||
|
||||
struct PlanarData {
|
||||
vec4 plane_equation;
|
||||
vec4 clip_vec_x_fade_scale;
|
||||
vec4 clip_vec_y_fade_bias;
|
||||
vec4 clip_edges;
|
||||
vec4 facing_scale_bias;
|
||||
mat4 reflectionmat; /* transform world space into reflection texture space */
|
||||
};
|
||||
|
||||
#define pl_plane_eq plane_equation
|
||||
#define pl_normal plane_equation.xyz
|
||||
#define pl_facing_scale facing_scale_bias.x
|
||||
#define pl_facing_bias facing_scale_bias.y
|
||||
#define pl_fade_scale clip_vec_x_fade_scale.w
|
||||
#define pl_fade_bias clip_vec_y_fade_bias.w
|
||||
#define pl_clip_pos_x clip_vec_x_fade_scale.xyz
|
||||
#define pl_clip_pos_y clip_vec_y_fade_bias.xyz
|
||||
#define pl_clip_edges clip_edges
|
||||
|
||||
struct GridData {
|
||||
mat4 localmat;
|
||||
ivec4 resolution_offset;
|
||||
|
|
|
@ -2,9 +2,12 @@
|
|||
uniform int light_count;
|
||||
uniform int probe_count;
|
||||
uniform int grid_count;
|
||||
uniform int planar_count;
|
||||
uniform mat4 ProjectionMatrix;
|
||||
uniform mat4 ViewMatrixInverse;
|
||||
|
||||
uniform sampler2DArray probePlanars;
|
||||
|
||||
uniform sampler2DArray probeCubes;
|
||||
uniform float lodMax;
|
||||
uniform bool specToggle;
|
||||
|
@ -25,6 +28,10 @@ layout(std140) uniform grid_block {
|
|||
GridData grids_data[MAX_GRID];
|
||||
};
|
||||
|
||||
layout(std140) uniform planar_block {
|
||||
PlanarData planars_data[MAX_PLANAR];
|
||||
};
|
||||
|
||||
layout(std140) uniform light_block {
|
||||
LightData lights_data[MAX_LIGHT];
|
||||
};
|
||||
|
@ -275,6 +282,25 @@ float probe_attenuation(vec3 W, ProbeData pd)
|
|||
return fac;
|
||||
}
|
||||
|
||||
float planar_attenuation(vec3 W, vec3 N, PlanarData pd)
|
||||
{
|
||||
float fac;
|
||||
|
||||
/* Normal Facing */
|
||||
fac = saturate(dot(pd.pl_normal, N) * pd.pl_facing_scale + pd.pl_facing_bias);
|
||||
|
||||
/* Distance from plane */
|
||||
fac *= saturate(abs(dot(pd.pl_plane_eq, vec4(W, 1.0))) * pd.pl_fade_scale + pd.pl_fade_bias);
|
||||
|
||||
/* Fancy fast clipping calculation */
|
||||
vec2 dist_to_clip;
|
||||
dist_to_clip.x = dot(pd.pl_clip_pos_x, W);
|
||||
dist_to_clip.y = dot(pd.pl_clip_pos_y, W);
|
||||
fac *= step(2.0, dot(step(pd.pl_clip_edges, dist_to_clip.xxyy), vec2(-1.0, 1.0).xyxy)); /* compare and add all tests */
|
||||
|
||||
return fac;
|
||||
}
|
||||
|
||||
vec3 eevee_surface_lit(vec3 world_normal, vec3 albedo, vec3 f0, float roughness, float ao)
|
||||
{
|
||||
roughness = clamp(roughness, 1e-8, 0.9999);
|
||||
|
@ -325,6 +351,24 @@ vec3 eevee_surface_lit(vec3 world_normal, vec3 albedo, vec3 f0, float roughness,
|
|||
vec4 spec_accum = vec4(0.0);
|
||||
vec4 diff_accum = vec4(0.0);
|
||||
|
||||
/* Planar Reflections */
|
||||
for (int i = 0; i < MAX_PLANAR && i < planar_count && spec_accum.a < 0.999; ++i) {
|
||||
PlanarData pd = planars_data[i];
|
||||
|
||||
float influence = planar_attenuation(sd.W, sd.N, pd);
|
||||
|
||||
if (influence > 0.0) {
|
||||
float influ_spec = min(influence, (1.0 - spec_accum.a));
|
||||
|
||||
vec4 refco = pd.reflectionmat * vec4(sd.W, 1.0);
|
||||
refco.xy /= refco.w;
|
||||
vec3 sample = textureLod(probePlanars, vec3(refco.xy, i), 0.0).rgb;
|
||||
|
||||
spec_accum.rgb += sample * influ_spec;
|
||||
spec_accum.a += influ_spec;
|
||||
}
|
||||
}
|
||||
|
||||
/* Specular probes */
|
||||
/* Start at 1 because 0 is world probe */
|
||||
for (int i = 1; i < MAX_PROBE && i < probe_count && spec_accum.a < 0.999; ++i) {
|
||||
|
|
Loading…
Reference in New Issue