2017-11-01 01:03:36 +01:00
|
|
|
/*
|
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
|
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
|
*
|
2019-01-23 11:29:18 +11:00
|
|
|
* Copyright 2016, Blender Foundation.
|
2017-11-01 01:03:36 +01:00
|
|
|
*/
|
|
|
|
|
|
2019-02-18 08:08:12 +11:00
|
|
|
/** \file
|
|
|
|
|
* \ingroup draw_engine
|
2017-11-20 14:11:45 +11:00
|
|
|
*
|
|
|
|
|
* Volumetric effects rendering using frostbite approach.
|
2017-11-01 01:03:36 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "DRW_render.h"
|
|
|
|
|
|
2017-11-20 14:11:45 +11:00
|
|
|
#include "BLI_rand.h"
|
2018-01-17 21:40:43 +11:00
|
|
|
#include "BLI_string_utils.h"
|
2017-11-20 14:11:45 +11:00
|
|
|
|
2018-02-07 11:18:50 +11:00
|
|
|
#include "DNA_object_force_types.h"
|
2019-12-16 15:50:14 +01:00
|
|
|
#include "DNA_fluid_types.h"
|
2017-11-01 01:03:36 +01:00
|
|
|
#include "DNA_world_types.h"
|
|
|
|
|
|
|
|
|
|
#include "BKE_modifier.h"
|
|
|
|
|
#include "BKE_mesh.h"
|
2019-12-16 15:50:14 +01:00
|
|
|
#include "BKE_fluid.h"
|
2017-11-01 01:03:36 +01:00
|
|
|
|
|
|
|
|
#include "ED_screen.h"
|
|
|
|
|
|
2018-05-16 19:34:24 +02:00
|
|
|
#include "DEG_depsgraph_query.h"
|
|
|
|
|
|
2017-11-01 01:03:36 +01:00
|
|
|
#include "eevee_private.h"
|
|
|
|
|
#include "GPU_draw.h"
|
2019-10-29 15:37:19 +01:00
|
|
|
#include "GPU_extensions.h"
|
2017-11-01 01:03:36 +01:00
|
|
|
#include "GPU_texture.h"
|
2018-10-09 17:33:49 +02:00
|
|
|
#include "GPU_material.h"
|
2017-11-01 01:03:36 +01:00
|
|
|
|
|
|
|
|
static struct {
|
2019-04-17 06:17:24 +02:00
|
|
|
char *volumetric_common_lib;
|
|
|
|
|
char *volumetric_common_lights_lib;
|
2017-11-01 01:03:36 +01:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
struct GPUShader *volumetric_clear_sh;
|
2019-05-16 21:41:22 +02:00
|
|
|
struct GPUShader *scatter_sh;
|
|
|
|
|
struct GPUShader *scatter_with_lights_sh;
|
2019-04-17 06:17:24 +02:00
|
|
|
struct GPUShader *volumetric_integration_sh;
|
|
|
|
|
struct GPUShader *volumetric_resolve_sh;
|
2020-02-20 14:53:53 +01:00
|
|
|
struct GPUShader *volumetric_accum_sh;
|
2017-11-01 01:03:36 +01:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
GPUTexture *depth_src;
|
2017-11-01 01:03:36 +01:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
GPUTexture *dummy_density;
|
|
|
|
|
GPUTexture *dummy_flame;
|
2019-04-15 14:36:16 +02:00
|
|
|
|
2019-05-16 21:41:22 +02:00
|
|
|
GPUTexture *dummy_scatter;
|
|
|
|
|
GPUTexture *dummy_transmit;
|
|
|
|
|
|
2019-12-16 15:50:14 +01:00
|
|
|
/* List of all fluid simulation / smoke domains rendered within this frame. */
|
2019-04-17 06:17:24 +02:00
|
|
|
ListBase smoke_domains;
|
2017-11-01 01:03:36 +01:00
|
|
|
} e_data = {NULL}; /* Engine data */
|
|
|
|
|
|
|
|
|
|
extern char datatoc_bsdf_common_lib_glsl[];
|
2018-01-21 17:25:10 +01:00
|
|
|
extern char datatoc_common_uniforms_lib_glsl[];
|
2018-03-10 00:00:04 +01:00
|
|
|
extern char datatoc_common_view_lib_glsl[];
|
2017-11-01 01:03:36 +01:00
|
|
|
extern char datatoc_octahedron_lib_glsl[];
|
|
|
|
|
extern char datatoc_irradiance_lib_glsl[];
|
2019-02-27 12:34:56 +11:00
|
|
|
extern char datatoc_lights_lib_glsl[];
|
2020-02-20 14:53:53 +01:00
|
|
|
extern char datatoc_volumetric_accum_frag_glsl[];
|
2017-11-01 01:03:36 +01:00
|
|
|
extern char datatoc_volumetric_frag_glsl[];
|
|
|
|
|
extern char datatoc_volumetric_geom_glsl[];
|
|
|
|
|
extern char datatoc_volumetric_vert_glsl[];
|
|
|
|
|
extern char datatoc_volumetric_resolve_frag_glsl[];
|
|
|
|
|
extern char datatoc_volumetric_scatter_frag_glsl[];
|
|
|
|
|
extern char datatoc_volumetric_integration_frag_glsl[];
|
|
|
|
|
extern char datatoc_volumetric_lib_glsl[];
|
2018-03-22 16:10:54 +01:00
|
|
|
extern char datatoc_common_fullscreen_vert_glsl[];
|
2017-11-01 01:03:36 +01:00
|
|
|
|
2019-10-29 15:10:26 +01:00
|
|
|
#define USE_VOLUME_OPTI \
|
|
|
|
|
(GLEW_ARB_shader_image_load_store && GLEW_ARB_shading_language_420pack && \
|
|
|
|
|
!GPU_crappy_amd_driver())
|
2019-09-10 21:03:05 +02:00
|
|
|
|
2017-11-01 01:03:36 +01:00
|
|
|
static void eevee_create_shader_volumes(void)
|
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
e_data.volumetric_common_lib = BLI_string_joinN(datatoc_common_view_lib_glsl,
|
|
|
|
|
datatoc_common_uniforms_lib_glsl,
|
|
|
|
|
datatoc_bsdf_common_lib_glsl,
|
|
|
|
|
datatoc_volumetric_lib_glsl);
|
|
|
|
|
|
|
|
|
|
e_data.volumetric_common_lights_lib = BLI_string_joinN(datatoc_common_view_lib_glsl,
|
|
|
|
|
datatoc_common_uniforms_lib_glsl,
|
|
|
|
|
datatoc_bsdf_common_lib_glsl,
|
|
|
|
|
datatoc_octahedron_lib_glsl,
|
|
|
|
|
datatoc_irradiance_lib_glsl,
|
|
|
|
|
datatoc_lights_lib_glsl,
|
|
|
|
|
datatoc_volumetric_lib_glsl);
|
|
|
|
|
|
|
|
|
|
e_data.volumetric_clear_sh = DRW_shader_create_with_lib(datatoc_volumetric_vert_glsl,
|
|
|
|
|
datatoc_volumetric_geom_glsl,
|
|
|
|
|
datatoc_volumetric_frag_glsl,
|
|
|
|
|
e_data.volumetric_common_lib,
|
|
|
|
|
"#define VOLUMETRICS\n"
|
|
|
|
|
"#define CLEAR\n");
|
2019-05-16 21:41:22 +02:00
|
|
|
e_data.scatter_sh = DRW_shader_create_with_lib(datatoc_volumetric_vert_glsl,
|
|
|
|
|
datatoc_volumetric_geom_glsl,
|
|
|
|
|
datatoc_volumetric_scatter_frag_glsl,
|
|
|
|
|
e_data.volumetric_common_lights_lib,
|
|
|
|
|
SHADER_DEFINES
|
|
|
|
|
"#define VOLUMETRICS\n"
|
|
|
|
|
"#define VOLUME_SHADOW\n");
|
|
|
|
|
e_data.scatter_with_lights_sh = DRW_shader_create_with_lib(datatoc_volumetric_vert_glsl,
|
|
|
|
|
datatoc_volumetric_geom_glsl,
|
|
|
|
|
datatoc_volumetric_scatter_frag_glsl,
|
|
|
|
|
e_data.volumetric_common_lights_lib,
|
|
|
|
|
SHADER_DEFINES
|
|
|
|
|
"#define VOLUMETRICS\n"
|
|
|
|
|
"#define VOLUME_LIGHTING\n"
|
|
|
|
|
"#define VOLUME_SHADOW\n");
|
2019-04-17 06:17:24 +02:00
|
|
|
e_data.volumetric_integration_sh = DRW_shader_create_with_lib(
|
|
|
|
|
datatoc_volumetric_vert_glsl,
|
|
|
|
|
datatoc_volumetric_geom_glsl,
|
|
|
|
|
datatoc_volumetric_integration_frag_glsl,
|
|
|
|
|
e_data.volumetric_common_lib,
|
2019-09-10 21:03:05 +02:00
|
|
|
USE_VOLUME_OPTI ? "#extension GL_ARB_shader_image_load_store: enable\n"
|
|
|
|
|
"#extension GL_ARB_shading_language_420pack: enable\n"
|
|
|
|
|
"#define USE_VOLUME_OPTI\n" :
|
|
|
|
|
NULL);
|
2019-04-17 06:17:24 +02:00
|
|
|
e_data.volumetric_resolve_sh = DRW_shader_create_with_lib(datatoc_common_fullscreen_vert_glsl,
|
|
|
|
|
NULL,
|
|
|
|
|
datatoc_volumetric_resolve_frag_glsl,
|
|
|
|
|
e_data.volumetric_common_lib,
|
|
|
|
|
NULL);
|
2020-02-20 14:53:53 +01:00
|
|
|
e_data.volumetric_accum_sh = DRW_shader_create_fullscreen(datatoc_volumetric_accum_frag_glsl,
|
|
|
|
|
NULL);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-03-11 13:56:28 +01:00
|
|
|
const float density[4] = {1.0f, 1.0f, 1.0f, 1.0f};
|
|
|
|
|
e_data.dummy_density = DRW_texture_create_3d(1, 1, 1, GPU_RGBA8, DRW_TEX_WRAP, density);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-03-11 13:56:28 +01:00
|
|
|
const float flame = 0.0f;
|
2019-04-17 06:17:24 +02:00
|
|
|
e_data.dummy_flame = DRW_texture_create_3d(1, 1, 1, GPU_R8, DRW_TEX_WRAP, &flame);
|
2017-11-01 01:03:36 +01:00
|
|
|
}
|
|
|
|
|
|
2018-05-11 07:48:52 +02:00
|
|
|
void EEVEE_volumes_set_jitter(EEVEE_ViewLayerData *sldata, uint current_sample)
|
2018-02-02 01:18:25 +01:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
EEVEE_CommonUniformBuffer *common_data = &sldata->common_data;
|
2018-02-02 01:18:25 +01:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
double ht_point[3];
|
|
|
|
|
double ht_offset[3] = {0.0, 0.0};
|
|
|
|
|
uint ht_primes[3] = {3, 7, 2};
|
2018-02-02 01:18:25 +01:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
BLI_halton_3d(ht_primes, ht_offset, current_sample, ht_point);
|
2018-02-02 01:18:25 +01:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
common_data->vol_jitter[0] = (float)ht_point[0];
|
|
|
|
|
common_data->vol_jitter[1] = (float)ht_point[1];
|
|
|
|
|
common_data->vol_jitter[2] = (float)ht_point[2];
|
2018-02-02 01:18:25 +01:00
|
|
|
}
|
|
|
|
|
|
2019-05-16 21:41:22 +02:00
|
|
|
void EEVEE_volumes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
|
2017-11-01 01:03:36 +01:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
EEVEE_StorageList *stl = vedata->stl;
|
|
|
|
|
EEVEE_FramebufferList *fbl = vedata->fbl;
|
|
|
|
|
EEVEE_TextureList *txl = vedata->txl;
|
|
|
|
|
EEVEE_EffectsInfo *effects = stl->effects;
|
|
|
|
|
EEVEE_CommonUniformBuffer *common_data = &sldata->common_data;
|
|
|
|
|
|
|
|
|
|
const DRWContextState *draw_ctx = DRW_context_state_get();
|
|
|
|
|
const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph);
|
|
|
|
|
|
|
|
|
|
const float *viewport_size = DRW_viewport_size_get();
|
|
|
|
|
|
|
|
|
|
BLI_listbase_clear(&e_data.smoke_domains);
|
|
|
|
|
|
2019-05-16 21:41:22 +02:00
|
|
|
const int tile_size = scene_eval->eevee.volumetric_tile_size;
|
|
|
|
|
|
|
|
|
|
/* Find Froxel Texture resolution. */
|
|
|
|
|
int tex_size[3];
|
|
|
|
|
|
|
|
|
|
tex_size[0] = (int)ceilf(fmaxf(1.0f, viewport_size[0] / (float)tile_size));
|
|
|
|
|
tex_size[1] = (int)ceilf(fmaxf(1.0f, viewport_size[1] / (float)tile_size));
|
|
|
|
|
tex_size[2] = max_ii(scene_eval->eevee.volumetric_samples, 1);
|
|
|
|
|
|
|
|
|
|
common_data->vol_coord_scale[0] = viewport_size[0] / (float)(tile_size * tex_size[0]);
|
|
|
|
|
common_data->vol_coord_scale[1] = viewport_size[1] / (float)(tile_size * tex_size[1]);
|
2019-07-01 14:43:44 +02:00
|
|
|
common_data->vol_coord_scale[2] = 1.0f / viewport_size[0];
|
|
|
|
|
common_data->vol_coord_scale[3] = 1.0f / viewport_size[1];
|
2019-05-16 21:41:22 +02:00
|
|
|
|
|
|
|
|
/* TODO compute snap to maxZBuffer for clustered rendering */
|
|
|
|
|
if ((common_data->vol_tex_size[0] != tex_size[0]) ||
|
|
|
|
|
(common_data->vol_tex_size[1] != tex_size[1]) ||
|
|
|
|
|
(common_data->vol_tex_size[2] != tex_size[2])) {
|
|
|
|
|
DRW_TEXTURE_FREE_SAFE(txl->volume_prop_scattering);
|
|
|
|
|
DRW_TEXTURE_FREE_SAFE(txl->volume_prop_extinction);
|
|
|
|
|
DRW_TEXTURE_FREE_SAFE(txl->volume_prop_emission);
|
|
|
|
|
DRW_TEXTURE_FREE_SAFE(txl->volume_prop_phase);
|
|
|
|
|
DRW_TEXTURE_FREE_SAFE(txl->volume_scatter);
|
|
|
|
|
DRW_TEXTURE_FREE_SAFE(txl->volume_transmit);
|
|
|
|
|
DRW_TEXTURE_FREE_SAFE(txl->volume_scatter_history);
|
|
|
|
|
DRW_TEXTURE_FREE_SAFE(txl->volume_transmit_history);
|
|
|
|
|
GPU_FRAMEBUFFER_FREE_SAFE(fbl->volumetric_fb);
|
|
|
|
|
GPU_FRAMEBUFFER_FREE_SAFE(fbl->volumetric_scat_fb);
|
|
|
|
|
GPU_FRAMEBUFFER_FREE_SAFE(fbl->volumetric_integ_fb);
|
|
|
|
|
copy_v3_v3_int(common_data->vol_tex_size, tex_size);
|
|
|
|
|
|
|
|
|
|
common_data->vol_inv_tex_size[0] = 1.0f / (float)(tex_size[0]);
|
|
|
|
|
common_data->vol_inv_tex_size[1] = 1.0f / (float)(tex_size[1]);
|
|
|
|
|
common_data->vol_inv_tex_size[2] = 1.0f / (float)(tex_size[2]);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-05-16 21:41:22 +02:00
|
|
|
/* Like frostbite's paper, 5% blend of the new frame. */
|
|
|
|
|
common_data->vol_history_alpha = (txl->volume_prop_scattering == NULL) ? 0.0f : 0.95f;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-05-16 21:41:22 +02:00
|
|
|
/* Temporal Super sampling jitter */
|
|
|
|
|
uint ht_primes[3] = {3, 7, 2};
|
|
|
|
|
uint current_sample = 0;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-05-16 21:41:22 +02:00
|
|
|
/* If TAA is in use do not use the history buffer. */
|
|
|
|
|
bool do_taa = ((effects->enabled_effects & EFFECT_TAA) != 0);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-05-16 21:41:22 +02:00
|
|
|
if (draw_ctx->evil_C != NULL) {
|
|
|
|
|
struct wmWindowManager *wm = CTX_wm_manager(draw_ctx->evil_C);
|
|
|
|
|
do_taa = do_taa && (ED_screen_animation_no_scrub(wm) == NULL);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-05-16 21:41:22 +02:00
|
|
|
if (do_taa) {
|
|
|
|
|
common_data->vol_history_alpha = 0.0f;
|
|
|
|
|
current_sample = effects->taa_current_sample - 1;
|
|
|
|
|
effects->volume_current_sample = -1;
|
|
|
|
|
}
|
2019-05-24 16:21:21 +02:00
|
|
|
else if (DRW_state_is_image_render()) {
|
2019-05-16 21:41:22 +02:00
|
|
|
const uint max_sample = (ht_primes[0] * ht_primes[1] * ht_primes[2]);
|
|
|
|
|
current_sample = effects->volume_current_sample = (effects->volume_current_sample + 1) %
|
|
|
|
|
max_sample;
|
|
|
|
|
if (current_sample != max_sample - 1) {
|
|
|
|
|
DRW_viewport_request_redraw();
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2019-05-16 21:41:22 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-05-16 21:41:22 +02:00
|
|
|
EEVEE_volumes_set_jitter(sldata, current_sample);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-05-16 21:41:22 +02:00
|
|
|
float integration_start = scene_eval->eevee.volumetric_start;
|
|
|
|
|
float integration_end = scene_eval->eevee.volumetric_end;
|
|
|
|
|
common_data->vol_light_clamp = scene_eval->eevee.volumetric_light_clamp;
|
|
|
|
|
common_data->vol_shadow_steps = (float)scene_eval->eevee.volumetric_shadow_samples;
|
|
|
|
|
if ((scene_eval->eevee.flag & SCE_EEVEE_VOLUMETRIC_SHADOWS) == 0) {
|
|
|
|
|
common_data->vol_shadow_steps = 0;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-05-16 21:41:22 +02:00
|
|
|
/* Update view_vecs */
|
|
|
|
|
float invproj[4][4], winmat[4][4];
|
2019-05-21 12:34:48 +02:00
|
|
|
DRW_view_winmat_get(NULL, winmat, false);
|
|
|
|
|
DRW_view_winmat_get(NULL, invproj, true);
|
2019-05-16 21:41:22 +02:00
|
|
|
EEVEE_update_viewvecs(invproj, winmat, sldata->common_data.view_vecs);
|
|
|
|
|
|
2019-05-21 21:29:25 +02:00
|
|
|
if (DRW_view_is_persp_get(NULL)) {
|
2019-05-16 21:41:22 +02:00
|
|
|
float sample_distribution = scene_eval->eevee.volumetric_sample_distribution;
|
2019-09-16 12:02:16 +02:00
|
|
|
sample_distribution = 4.0f * (max_ff(1.0f - sample_distribution, 1e-2f));
|
2019-05-16 21:41:22 +02:00
|
|
|
|
|
|
|
|
const float clip_start = common_data->view_vecs[0][2];
|
|
|
|
|
/* Negate */
|
|
|
|
|
float near = integration_start = min_ff(-integration_start, clip_start - 1e-4f);
|
|
|
|
|
float far = integration_end = min_ff(-integration_end, near - 1e-4f);
|
|
|
|
|
|
|
|
|
|
common_data->vol_depth_param[0] = (far - near * exp2(1.0f / sample_distribution)) /
|
|
|
|
|
(far - near);
|
|
|
|
|
common_data->vol_depth_param[1] = (1.0f - common_data->vol_depth_param[0]) / near;
|
|
|
|
|
common_data->vol_depth_param[2] = sample_distribution;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
const float clip_start = common_data->view_vecs[0][2];
|
|
|
|
|
const float clip_end = clip_start + common_data->view_vecs[1][2];
|
|
|
|
|
integration_start = min_ff(integration_end, clip_start);
|
|
|
|
|
integration_end = max_ff(-integration_end, clip_end);
|
|
|
|
|
|
|
|
|
|
common_data->vol_depth_param[0] = integration_start;
|
|
|
|
|
common_data->vol_depth_param[1] = integration_end;
|
|
|
|
|
common_data->vol_depth_param[2] = 1.0f / (integration_end - integration_start);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-05-16 21:41:22 +02:00
|
|
|
/* Disable clamp if equal to 0. */
|
|
|
|
|
if (common_data->vol_light_clamp == 0.0) {
|
|
|
|
|
common_data->vol_light_clamp = FLT_MAX;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-05-16 21:41:22 +02:00
|
|
|
common_data->vol_use_lights = (scene_eval->eevee.flag & SCE_EEVEE_VOLUMETRIC_LIGHTS) != 0;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-05-16 21:41:22 +02:00
|
|
|
if (!e_data.dummy_scatter) {
|
|
|
|
|
float scatter[4] = {0.0f, 0.0f, 0.0f, 0.0f};
|
|
|
|
|
float transmit[4] = {1.0f, 1.0f, 1.0f, 1.0f};
|
|
|
|
|
e_data.dummy_scatter = DRW_texture_create_3d(1, 1, 1, GPU_RGBA8, DRW_TEX_WRAP, scatter);
|
|
|
|
|
e_data.dummy_transmit = DRW_texture_create_3d(1, 1, 1, GPU_RGBA8, DRW_TEX_WRAP, transmit);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2017-11-01 01:03:36 +01:00
|
|
|
}
|
|
|
|
|
|
2017-11-22 10:52:39 -02:00
|
|
|
void EEVEE_volumes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
|
2017-11-01 01:03:36 +01:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
EEVEE_PassList *psl = vedata->psl;
|
|
|
|
|
EEVEE_StorageList *stl = vedata->stl;
|
|
|
|
|
EEVEE_EffectsInfo *effects = stl->effects;
|
|
|
|
|
EEVEE_CommonUniformBuffer *common_data = &sldata->common_data;
|
|
|
|
|
|
2019-05-16 21:41:22 +02:00
|
|
|
const DRWContextState *draw_ctx = DRW_context_state_get();
|
|
|
|
|
Scene *scene = draw_ctx->scene;
|
|
|
|
|
DRWShadingGroup *grp = NULL;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-05-16 21:41:22 +02:00
|
|
|
/* Shaders */
|
|
|
|
|
if (!e_data.scatter_sh) {
|
|
|
|
|
eevee_create_shader_volumes();
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-05-16 21:41:22 +02:00
|
|
|
/* Quick breakdown of the Volumetric rendering:
|
|
|
|
|
*
|
|
|
|
|
* The rendering is separated in 4 stages:
|
|
|
|
|
*
|
|
|
|
|
* - Material Parameters : we collect volume properties of
|
|
|
|
|
* all participating media in the scene and store them in
|
|
|
|
|
* a 3D texture aligned with the 3D frustum.
|
|
|
|
|
* This is done in 2 passes, one that clear the texture
|
|
|
|
|
* and/or evaluate the world volumes, and the 2nd one that
|
|
|
|
|
* additively render object volumes.
|
|
|
|
|
*
|
|
|
|
|
* - Light Scattering : the volume properties then are sampled
|
|
|
|
|
* and light scattering is evaluated for each cell of the
|
|
|
|
|
* volume texture. Temporal super-sampling (if enabled) occurs here.
|
|
|
|
|
*
|
|
|
|
|
* - Volume Integration : the scattered light and extinction is
|
|
|
|
|
* integrated (accumulated) along the view-rays. The result is stored
|
|
|
|
|
* for every cell in another texture.
|
|
|
|
|
*
|
|
|
|
|
* - Full-screen Resolve : From the previous stage, we get two
|
|
|
|
|
* 3D textures that contains integrated scattered light and extinction
|
|
|
|
|
* for "every" positions in the frustum. We only need to sample
|
|
|
|
|
* them and blend the scene color with those factors. This also
|
|
|
|
|
* work for alpha blended materials.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* World pass is not additive as it also clear the buffer. */
|
|
|
|
|
DRW_PASS_CREATE(psl->volumetric_world_ps, DRW_STATE_WRITE_COLOR);
|
2019-05-27 23:21:39 +02:00
|
|
|
DRW_PASS_CREATE(psl->volumetric_objects_ps, DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ADD);
|
2019-05-16 21:41:22 +02:00
|
|
|
|
|
|
|
|
/* World Volumetric */
|
|
|
|
|
struct World *wo = scene->world;
|
|
|
|
|
if (wo != NULL && wo->use_nodes && wo->nodetree &&
|
|
|
|
|
!LOOK_DEV_STUDIO_LIGHT_ENABLED(draw_ctx->v3d)) {
|
|
|
|
|
struct GPUMaterial *mat = EEVEE_material_world_volume_get(scene, wo);
|
|
|
|
|
|
2020-03-11 14:58:19 +01:00
|
|
|
if (GPU_material_has_volume_output(mat)) {
|
2019-05-16 21:41:22 +02:00
|
|
|
grp = DRW_shgroup_material_create(mat, psl->volumetric_world_ps);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2019-05-16 21:41:22 +02:00
|
|
|
if (grp) {
|
2019-04-17 06:17:24 +02:00
|
|
|
DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
|
2019-05-16 21:41:22 +02:00
|
|
|
/* TODO (fclem): remove those (need to clean the GLSL files). */
|
|
|
|
|
DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo);
|
|
|
|
|
DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo);
|
|
|
|
|
DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo);
|
|
|
|
|
DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo);
|
|
|
|
|
DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo);
|
2020-02-20 14:53:53 +01:00
|
|
|
DRW_shgroup_uniform_block(
|
|
|
|
|
grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata));
|
2019-05-16 21:41:22 +02:00
|
|
|
|
|
|
|
|
/* Fix principle volumetric not working with world materials. */
|
2020-03-11 14:58:19 +01:00
|
|
|
ListBase gpu_grids = GPU_material_volume_grids(mat);
|
|
|
|
|
for (GPUMaterialVolumeGrid *gpu_grid = gpu_grids.first; gpu_grid;
|
|
|
|
|
gpu_grid = gpu_grid->next) {
|
|
|
|
|
DRW_shgroup_uniform_texture(grp, gpu_grid->sampler_name, e_data.dummy_density);
|
|
|
|
|
}
|
2019-05-11 17:42:36 +02:00
|
|
|
|
2019-05-29 23:52:37 +02:00
|
|
|
DRW_shgroup_call_procedural_triangles(grp, NULL, common_data->vol_tex_size[2]);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-05-16 21:41:22 +02:00
|
|
|
effects->enabled_effects |= (EFFECT_VOLUMETRIC | EFFECT_POST_BUFFER);
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-05-11 17:42:36 +02:00
|
|
|
|
2019-05-16 21:41:22 +02:00
|
|
|
if (grp == NULL) {
|
|
|
|
|
/* If no world or volume material is present just clear the buffer with this drawcall */
|
|
|
|
|
grp = DRW_shgroup_create(e_data.volumetric_clear_sh, psl->volumetric_world_ps);
|
2019-04-17 06:17:24 +02:00
|
|
|
DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
|
2020-02-20 14:53:53 +01:00
|
|
|
DRW_shgroup_uniform_block(
|
|
|
|
|
grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-05-29 23:52:37 +02:00
|
|
|
DRW_shgroup_call_procedural_triangles(grp, NULL, common_data->vol_tex_size[2]);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2017-11-01 01:03:36 +01:00
|
|
|
}
|
|
|
|
|
|
2019-03-22 19:39:56 +01:00
|
|
|
typedef struct EEVEE_InstanceVolumeMatrix {
|
2019-04-17 06:17:24 +02:00
|
|
|
DrawData dd;
|
|
|
|
|
float volume_mat[4][4];
|
2019-03-22 19:39:56 +01:00
|
|
|
} EEVEE_InstanceVolumeMatrix;
|
|
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata,
|
|
|
|
|
EEVEE_Data *vedata,
|
|
|
|
|
Scene *scene,
|
|
|
|
|
Object *ob)
|
2017-11-01 01:03:36 +01:00
|
|
|
{
|
2019-12-17 09:12:03 +11:00
|
|
|
static const float white[3] = {1.0f, 1.0f, 1.0f};
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
|
float *texcoloc = NULL;
|
|
|
|
|
float *texcosize = NULL;
|
|
|
|
|
struct ModifierData *md = NULL;
|
2020-02-05 11:23:58 +01:00
|
|
|
Material *ma = BKE_object_material_get(ob, 1);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
|
if (ma == NULL) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-27 17:31:12 +01:00
|
|
|
float size[3];
|
|
|
|
|
mat4_to_size(size, ob->obmat);
|
|
|
|
|
/* Check if any of the axes have 0 length. (see T69070) */
|
|
|
|
|
const float epsilon = 1e-8f;
|
|
|
|
|
if ((size[0] < epsilon) || (size[1] < epsilon) || (size[2] < epsilon)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
struct GPUMaterial *mat = EEVEE_material_mesh_volume_get(scene, ma);
|
2019-06-14 19:12:39 +02:00
|
|
|
eGPUMaterialStatus status = GPU_material_status(mat);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-06-14 19:12:39 +02:00
|
|
|
if (status == GPU_MAT_QUEUED) {
|
|
|
|
|
vedata->stl->g_data->queued_shaders_count++;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
/* If shader failed to compile or is currently compiling. */
|
2019-06-14 19:12:39 +02:00
|
|
|
if (status != GPU_MAT_SUCCESS) {
|
2019-04-17 06:17:24 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-11 17:42:36 +02:00
|
|
|
DRWShadingGroup *grp = DRW_shgroup_material_create(mat, vedata->psl->volumetric_objects_ps);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-09-23 15:54:21 +02:00
|
|
|
BKE_mesh_texspace_get_reference((struct Mesh *)ob->data, NULL, &texcoloc, &texcosize);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
|
/* TODO(fclem) remove those "unnecessary" UBOs */
|
|
|
|
|
DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo);
|
|
|
|
|
DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo);
|
|
|
|
|
DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo);
|
|
|
|
|
DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo);
|
|
|
|
|
DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo);
|
2020-02-20 14:53:53 +01:00
|
|
|
DRW_shgroup_uniform_block(
|
|
|
|
|
grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
|
DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
|
|
|
|
|
DRW_shgroup_uniform_vec3(grp, "volumeOrcoLoc", texcoloc, 1);
|
|
|
|
|
DRW_shgroup_uniform_vec3(grp, "volumeOrcoSize", texcosize, 1);
|
|
|
|
|
|
2020-03-11 14:58:19 +01:00
|
|
|
ListBase gpu_grids = GPU_material_volume_grids(mat);
|
2019-04-17 06:17:24 +02:00
|
|
|
/* Smoke Simulation */
|
|
|
|
|
if (((ob->base_flag & BASE_FROM_DUPLI) == 0) &&
|
2019-12-16 15:50:14 +01:00
|
|
|
(md = modifiers_findByType(ob, eModifierType_Fluid)) &&
|
2019-04-17 06:17:24 +02:00
|
|
|
(modifier_isEnabled(scene, md, eModifierMode_Realtime)) &&
|
2019-12-16 15:50:14 +01:00
|
|
|
((FluidModifierData *)md)->domain != NULL) {
|
|
|
|
|
FluidModifierData *mmd = (FluidModifierData *)md;
|
|
|
|
|
FluidDomainSettings *mds = mmd->domain;
|
|
|
|
|
|
|
|
|
|
/* Don't try to show liquid domains here. */
|
|
|
|
|
if (!mds->fluid || !(mds->type == FLUID_DOMAIN_TYPE_GAS)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
|
/* Don't show smoke before simulation starts, this could be made an option in the future. */
|
2019-12-16 15:50:14 +01:00
|
|
|
/* (sebbas): Always show smoke for manta */
|
2019-12-17 09:12:03 +11:00
|
|
|
#if 0
|
|
|
|
|
const DRWContextState *draw_ctx = DRW_context_state_get();
|
|
|
|
|
const bool show_smoke = ((int)DEG_get_ctime(draw_ctx->depsgraph) >=
|
|
|
|
|
*mds->point_cache[0]->startframe);
|
|
|
|
|
#endif
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-12-16 15:50:14 +01:00
|
|
|
if (mds->fluid && (mds->type == FLUID_DOMAIN_TYPE_GAS) /* && show_smoke */) {
|
|
|
|
|
if (!(mds->flags & FLUID_DOMAIN_USE_NOISE)) {
|
|
|
|
|
GPU_create_smoke(mmd, 0);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2019-12-16 15:50:14 +01:00
|
|
|
else if (mds->flags & FLUID_DOMAIN_USE_NOISE) {
|
|
|
|
|
GPU_create_smoke(mmd, 1);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2019-12-16 15:50:14 +01:00
|
|
|
BLI_addtail(&e_data.smoke_domains, BLI_genericNodeN(mmd));
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2020-03-11 14:58:19 +01:00
|
|
|
for (GPUMaterialVolumeGrid *gpu_grid = gpu_grids.first; gpu_grid; gpu_grid = gpu_grid->next) {
|
|
|
|
|
if (STREQ(gpu_grid->name, "density")) {
|
|
|
|
|
DRW_shgroup_uniform_texture_ref(grp,
|
|
|
|
|
gpu_grid->sampler_name,
|
|
|
|
|
mds->tex_density ? &mds->tex_density :
|
|
|
|
|
&e_data.dummy_density);
|
|
|
|
|
}
|
|
|
|
|
else if (STREQ(gpu_grid->name, "color")) {
|
|
|
|
|
DRW_shgroup_uniform_texture_ref(
|
|
|
|
|
grp, gpu_grid->sampler_name, mds->tex_color ? &mds->tex_color : &e_data.dummy_density);
|
|
|
|
|
}
|
|
|
|
|
else if (STREQ(gpu_grid->name, "flame") || STREQ(gpu_grid->name, "temperature")) {
|
|
|
|
|
DRW_shgroup_uniform_texture_ref(
|
|
|
|
|
grp, gpu_grid->sampler_name, mds->tex_flame ? &mds->tex_flame : &e_data.dummy_flame);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
DRW_shgroup_uniform_texture_ref(grp, gpu_grid->sampler_name, &e_data.dummy_density);
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
|
/* Constant Volume color. */
|
2019-12-16 15:50:14 +01:00
|
|
|
bool use_constant_color = ((mds->active_fields & FLUID_DOMAIN_ACTIVE_COLORS) == 0 &&
|
|
|
|
|
(mds->active_fields & FLUID_DOMAIN_ACTIVE_COLOR_SET) != 0);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
|
DRW_shgroup_uniform_vec3(
|
2019-12-16 15:50:14 +01:00
|
|
|
grp, "volumeColor", (use_constant_color) ? mds->active_color : white, 1);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
|
/* Output is such that 0..1 maps to 0..1000K */
|
2020-03-11 14:58:19 +01:00
|
|
|
DRW_shgroup_uniform_vec2(grp, "volumeTemperature", &mds->flame_ignition, 1);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
else {
|
2020-03-11 14:58:19 +01:00
|
|
|
for (GPUMaterialVolumeGrid *gpu_grid = gpu_grids.first; gpu_grid; gpu_grid = gpu_grid->next) {
|
|
|
|
|
DRW_shgroup_uniform_texture(grp, gpu_grid->sampler_name, e_data.dummy_density);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
DRW_shgroup_uniform_vec3(grp, "volumeColor", white, 1);
|
|
|
|
|
}
|
2019-05-11 17:42:36 +02:00
|
|
|
|
|
|
|
|
/* TODO Reduce to number of slices intersecting. */
|
|
|
|
|
/* TODO Preemptive culling. */
|
2019-05-29 23:52:37 +02:00
|
|
|
DRW_shgroup_call_procedural_triangles(grp, ob, sldata->common_data.vol_tex_size[2]);
|
2019-05-16 21:41:22 +02:00
|
|
|
|
|
|
|
|
vedata->stl->effects->enabled_effects |= (EFFECT_VOLUMETRIC | EFFECT_POST_BUFFER);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EEVEE_volumes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
|
|
|
|
|
{
|
|
|
|
|
EEVEE_PassList *psl = vedata->psl;
|
|
|
|
|
EEVEE_TextureList *txl = vedata->txl;
|
|
|
|
|
EEVEE_EffectsInfo *effects = vedata->stl->effects;
|
|
|
|
|
LightCache *lcache = vedata->stl->g_data->light_cache;
|
|
|
|
|
EEVEE_CommonUniformBuffer *common_data = &sldata->common_data;
|
|
|
|
|
|
|
|
|
|
if ((effects->enabled_effects & EFFECT_VOLUMETRIC) != 0) {
|
|
|
|
|
DRWShadingGroup *grp;
|
|
|
|
|
struct GPUShader *sh;
|
|
|
|
|
|
|
|
|
|
DRW_PASS_CREATE(psl->volumetric_scatter_ps, DRW_STATE_WRITE_COLOR);
|
|
|
|
|
sh = (common_data->vol_use_lights) ? e_data.scatter_with_lights_sh : e_data.scatter_sh;
|
|
|
|
|
grp = DRW_shgroup_create(sh, psl->volumetric_scatter_ps);
|
|
|
|
|
DRW_shgroup_uniform_texture_ref(grp, "irradianceGrid", &lcache->grid_tx.tex);
|
|
|
|
|
DRW_shgroup_uniform_texture_ref(grp, "shadowCubeTexture", &sldata->shadow_cube_pool);
|
|
|
|
|
DRW_shgroup_uniform_texture_ref(grp, "shadowCascadeTexture", &sldata->shadow_cascade_pool);
|
|
|
|
|
DRW_shgroup_uniform_texture_ref(grp, "volumeScattering", &txl->volume_prop_scattering);
|
|
|
|
|
DRW_shgroup_uniform_texture_ref(grp, "volumeExtinction", &txl->volume_prop_extinction);
|
|
|
|
|
DRW_shgroup_uniform_texture_ref(grp, "volumeEmission", &txl->volume_prop_emission);
|
|
|
|
|
DRW_shgroup_uniform_texture_ref(grp, "volumePhase", &txl->volume_prop_phase);
|
|
|
|
|
DRW_shgroup_uniform_texture_ref(grp, "historyScattering", &txl->volume_scatter_history);
|
|
|
|
|
DRW_shgroup_uniform_texture_ref(grp, "historyTransmittance", &txl->volume_transmit_history);
|
|
|
|
|
DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo);
|
|
|
|
|
DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo);
|
|
|
|
|
DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
|
2020-02-20 14:53:53 +01:00
|
|
|
DRW_shgroup_uniform_block(
|
|
|
|
|
grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata));
|
2019-05-16 21:41:22 +02:00
|
|
|
|
2019-05-29 23:52:37 +02:00
|
|
|
DRW_shgroup_call_procedural_triangles(grp, NULL, common_data->vol_tex_size[2]);
|
2019-05-16 21:41:22 +02:00
|
|
|
|
|
|
|
|
DRW_PASS_CREATE(psl->volumetric_integration_ps, DRW_STATE_WRITE_COLOR);
|
|
|
|
|
grp = DRW_shgroup_create(e_data.volumetric_integration_sh, psl->volumetric_integration_ps);
|
|
|
|
|
DRW_shgroup_uniform_texture_ref(grp, "volumeScattering", &txl->volume_scatter);
|
|
|
|
|
DRW_shgroup_uniform_texture_ref(grp, "volumeExtinction", &txl->volume_transmit);
|
|
|
|
|
DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
|
2020-02-20 14:53:53 +01:00
|
|
|
DRW_shgroup_uniform_block(
|
|
|
|
|
grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata));
|
2019-05-16 21:41:22 +02:00
|
|
|
|
2019-09-10 21:03:05 +02:00
|
|
|
DRW_shgroup_call_procedural_triangles(
|
|
|
|
|
grp, NULL, USE_VOLUME_OPTI ? 1 : common_data->vol_tex_size[2]);
|
2019-05-16 21:41:22 +02:00
|
|
|
|
2019-06-27 14:40:29 +02:00
|
|
|
DRW_PASS_CREATE(psl->volumetric_resolve_ps, DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM);
|
2019-05-16 21:41:22 +02:00
|
|
|
grp = DRW_shgroup_create(e_data.volumetric_resolve_sh, psl->volumetric_resolve_ps);
|
|
|
|
|
DRW_shgroup_uniform_texture_ref(grp, "inScattering", &txl->volume_scatter);
|
|
|
|
|
DRW_shgroup_uniform_texture_ref(grp, "inTransmittance", &txl->volume_transmit);
|
|
|
|
|
DRW_shgroup_uniform_texture_ref(grp, "inSceneDepth", &e_data.depth_src);
|
|
|
|
|
DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
|
2020-02-20 14:53:53 +01:00
|
|
|
DRW_shgroup_uniform_block(
|
|
|
|
|
grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata));
|
2019-05-16 21:41:22 +02:00
|
|
|
|
2019-05-29 23:52:37 +02:00
|
|
|
DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
|
2019-05-16 21:41:22 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EEVEE_volumes_draw_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
|
|
|
|
|
{
|
|
|
|
|
EEVEE_FramebufferList *fbl = vedata->fbl;
|
|
|
|
|
EEVEE_TextureList *txl = vedata->txl;
|
|
|
|
|
EEVEE_EffectsInfo *effects = vedata->stl->effects;
|
|
|
|
|
EEVEE_CommonUniformBuffer *common_data = &sldata->common_data;
|
|
|
|
|
|
|
|
|
|
if ((effects->enabled_effects & EFFECT_VOLUMETRIC) != 0) {
|
|
|
|
|
int *tex_size = common_data->vol_tex_size;
|
|
|
|
|
|
|
|
|
|
if (txl->volume_prop_scattering == NULL) {
|
|
|
|
|
/* Volume properties: We evaluate all volumetric objects
|
|
|
|
|
* and store their final properties into each froxel */
|
|
|
|
|
txl->volume_prop_scattering = DRW_texture_create_3d(
|
|
|
|
|
tex_size[0], tex_size[1], tex_size[2], GPU_R11F_G11F_B10F, DRW_TEX_FILTER, NULL);
|
|
|
|
|
txl->volume_prop_extinction = DRW_texture_create_3d(
|
|
|
|
|
tex_size[0], tex_size[1], tex_size[2], GPU_R11F_G11F_B10F, DRW_TEX_FILTER, NULL);
|
|
|
|
|
txl->volume_prop_emission = DRW_texture_create_3d(
|
|
|
|
|
tex_size[0], tex_size[1], tex_size[2], GPU_R11F_G11F_B10F, DRW_TEX_FILTER, NULL);
|
|
|
|
|
txl->volume_prop_phase = DRW_texture_create_3d(
|
|
|
|
|
tex_size[0], tex_size[1], tex_size[2], GPU_RG16F, DRW_TEX_FILTER, NULL);
|
|
|
|
|
|
|
|
|
|
/* Volume scattering: We compute for each froxel the
|
|
|
|
|
* Scattered light towards the view. We also resolve temporal
|
|
|
|
|
* super sampling during this stage. */
|
|
|
|
|
txl->volume_scatter = DRW_texture_create_3d(
|
|
|
|
|
tex_size[0], tex_size[1], tex_size[2], GPU_R11F_G11F_B10F, DRW_TEX_FILTER, NULL);
|
|
|
|
|
txl->volume_transmit = DRW_texture_create_3d(
|
|
|
|
|
tex_size[0], tex_size[1], tex_size[2], GPU_R11F_G11F_B10F, DRW_TEX_FILTER, NULL);
|
|
|
|
|
|
|
|
|
|
/* Final integration: We compute for each froxel the
|
|
|
|
|
* amount of scattered light and extinction coef at this
|
2019-08-01 13:53:25 +10:00
|
|
|
* given depth. We use these textures as double buffer
|
2019-05-16 21:41:22 +02:00
|
|
|
* for the volumetric history. */
|
|
|
|
|
txl->volume_scatter_history = DRW_texture_create_3d(
|
|
|
|
|
tex_size[0], tex_size[1], tex_size[2], GPU_R11F_G11F_B10F, DRW_TEX_FILTER, NULL);
|
|
|
|
|
txl->volume_transmit_history = DRW_texture_create_3d(
|
|
|
|
|
tex_size[0], tex_size[1], tex_size[2], GPU_R11F_G11F_B10F, DRW_TEX_FILTER, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GPU_framebuffer_ensure_config(&fbl->volumetric_fb,
|
|
|
|
|
{GPU_ATTACHMENT_NONE,
|
|
|
|
|
GPU_ATTACHMENT_TEXTURE(txl->volume_prop_scattering),
|
|
|
|
|
GPU_ATTACHMENT_TEXTURE(txl->volume_prop_extinction),
|
|
|
|
|
GPU_ATTACHMENT_TEXTURE(txl->volume_prop_emission),
|
|
|
|
|
GPU_ATTACHMENT_TEXTURE(txl->volume_prop_phase)});
|
|
|
|
|
GPU_framebuffer_ensure_config(&fbl->volumetric_scat_fb,
|
|
|
|
|
{GPU_ATTACHMENT_NONE,
|
|
|
|
|
GPU_ATTACHMENT_TEXTURE(txl->volume_scatter),
|
|
|
|
|
GPU_ATTACHMENT_TEXTURE(txl->volume_transmit)});
|
|
|
|
|
GPU_framebuffer_ensure_config(&fbl->volumetric_integ_fb,
|
|
|
|
|
{GPU_ATTACHMENT_NONE,
|
|
|
|
|
GPU_ATTACHMENT_TEXTURE(txl->volume_scatter_history),
|
|
|
|
|
GPU_ATTACHMENT_TEXTURE(txl->volume_transmit_history)});
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
DRW_TEXTURE_FREE_SAFE(txl->volume_prop_scattering);
|
|
|
|
|
DRW_TEXTURE_FREE_SAFE(txl->volume_prop_extinction);
|
|
|
|
|
DRW_TEXTURE_FREE_SAFE(txl->volume_prop_emission);
|
|
|
|
|
DRW_TEXTURE_FREE_SAFE(txl->volume_prop_phase);
|
|
|
|
|
DRW_TEXTURE_FREE_SAFE(txl->volume_scatter);
|
|
|
|
|
DRW_TEXTURE_FREE_SAFE(txl->volume_transmit);
|
|
|
|
|
DRW_TEXTURE_FREE_SAFE(txl->volume_scatter_history);
|
|
|
|
|
DRW_TEXTURE_FREE_SAFE(txl->volume_transmit_history);
|
|
|
|
|
GPU_FRAMEBUFFER_FREE_SAFE(fbl->volumetric_fb);
|
|
|
|
|
GPU_FRAMEBUFFER_FREE_SAFE(fbl->volumetric_scat_fb);
|
|
|
|
|
GPU_FRAMEBUFFER_FREE_SAFE(fbl->volumetric_integ_fb);
|
|
|
|
|
}
|
2019-06-14 18:19:45 +02:00
|
|
|
|
|
|
|
|
effects->volume_scatter = e_data.dummy_scatter;
|
|
|
|
|
effects->volume_transmit = e_data.dummy_transmit;
|
2017-11-01 01:03:36 +01:00
|
|
|
}
|
|
|
|
|
|
2019-08-22 16:04:25 +02:00
|
|
|
void EEVEE_volumes_compute(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
|
2017-11-01 01:03:36 +01:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
EEVEE_PassList *psl = vedata->psl;
|
|
|
|
|
EEVEE_TextureList *txl = vedata->txl;
|
|
|
|
|
EEVEE_FramebufferList *fbl = vedata->fbl;
|
|
|
|
|
EEVEE_StorageList *stl = vedata->stl;
|
|
|
|
|
EEVEE_EffectsInfo *effects = stl->effects;
|
|
|
|
|
if ((effects->enabled_effects & EFFECT_VOLUMETRIC) != 0) {
|
|
|
|
|
DRW_stats_group_start("Volumetrics");
|
|
|
|
|
|
2019-09-07 21:08:20 +10:00
|
|
|
/* We sample the shadow-maps using shadow sampler. We need to enable Comparison mode.
|
2019-08-22 16:04:25 +02:00
|
|
|
* TODO(fclem) avoid this by using sampler objects.*/
|
|
|
|
|
GPU_texture_bind(sldata->shadow_cube_pool, 0);
|
|
|
|
|
GPU_texture_compare_mode(sldata->shadow_cube_pool, true);
|
|
|
|
|
GPU_texture_unbind(sldata->shadow_cube_pool);
|
|
|
|
|
GPU_texture_bind(sldata->shadow_cascade_pool, 0);
|
|
|
|
|
GPU_texture_compare_mode(sldata->shadow_cascade_pool, true);
|
|
|
|
|
GPU_texture_unbind(sldata->shadow_cascade_pool);
|
|
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
GPU_framebuffer_bind(fbl->volumetric_fb);
|
|
|
|
|
DRW_draw_pass(psl->volumetric_world_ps);
|
|
|
|
|
DRW_draw_pass(psl->volumetric_objects_ps);
|
|
|
|
|
|
|
|
|
|
GPU_framebuffer_bind(fbl->volumetric_scat_fb);
|
|
|
|
|
DRW_draw_pass(psl->volumetric_scatter_ps);
|
|
|
|
|
|
2019-09-10 21:03:05 +02:00
|
|
|
if (USE_VOLUME_OPTI) {
|
|
|
|
|
int tex_scatter = GPU_texture_opengl_bindcode(txl->volume_scatter_history);
|
|
|
|
|
int tex_transmit = GPU_texture_opengl_bindcode(txl->volume_transmit_history);
|
|
|
|
|
/* TODO(fclem) Encapsulate these GL calls into DRWManager. */
|
|
|
|
|
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
|
2019-09-19 13:18:52 +10:00
|
|
|
/* Subtlety here! we need to tell the GL that the texture is layered (GL_TRUE)
|
2019-09-10 21:03:05 +02:00
|
|
|
* in order to bind the full 3D texture and not just a 2D slice. */
|
|
|
|
|
glBindImageTexture(0, tex_scatter, 0, GL_TRUE, 0, GL_WRITE_ONLY, GL_R11F_G11F_B10F);
|
|
|
|
|
glBindImageTexture(1, tex_transmit, 0, GL_TRUE, 0, GL_WRITE_ONLY, GL_R11F_G11F_B10F);
|
|
|
|
|
|
|
|
|
|
GPU_framebuffer_bind(fbl->volumetric_fb);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
GPU_framebuffer_bind(fbl->volumetric_integ_fb);
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
DRW_draw_pass(psl->volumetric_integration_ps);
|
|
|
|
|
|
2019-09-10 21:03:05 +02:00
|
|
|
if (USE_VOLUME_OPTI) {
|
|
|
|
|
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
|
|
|
|
|
|
|
|
|
|
glBindImageTexture(0, 0, 0, GL_TRUE, 0, GL_WRITE_ONLY, GL_R11F_G11F_B10F);
|
|
|
|
|
glBindImageTexture(1, 0, 0, GL_TRUE, 0, GL_WRITE_ONLY, GL_R11F_G11F_B10F);
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
SWAP(struct GPUFrameBuffer *, fbl->volumetric_scat_fb, fbl->volumetric_integ_fb);
|
|
|
|
|
SWAP(GPUTexture *, txl->volume_scatter, txl->volume_scatter_history);
|
2019-05-16 21:41:22 +02:00
|
|
|
SWAP(GPUTexture *, txl->volume_transmit, txl->volume_transmit_history);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-06-14 18:19:45 +02:00
|
|
|
effects->volume_scatter = txl->volume_scatter;
|
|
|
|
|
effects->volume_transmit = txl->volume_transmit;
|
|
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* Restore */
|
|
|
|
|
GPU_framebuffer_bind(fbl->main_fb);
|
|
|
|
|
|
|
|
|
|
DRW_stats_group_end();
|
|
|
|
|
}
|
2017-11-01 01:03:36 +01:00
|
|
|
}
|
|
|
|
|
|
2017-11-22 10:52:39 -02:00
|
|
|
void EEVEE_volumes_resolve(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
|
2017-11-01 01:03:36 +01:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
EEVEE_PassList *psl = vedata->psl;
|
|
|
|
|
EEVEE_FramebufferList *fbl = vedata->fbl;
|
|
|
|
|
EEVEE_StorageList *stl = vedata->stl;
|
|
|
|
|
EEVEE_EffectsInfo *effects = stl->effects;
|
|
|
|
|
|
|
|
|
|
if ((effects->enabled_effects & EFFECT_VOLUMETRIC) != 0) {
|
|
|
|
|
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
|
|
|
|
|
e_data.depth_src = dtxl->depth;
|
|
|
|
|
|
2019-06-27 14:40:29 +02:00
|
|
|
/* Apply for opaque geometry. */
|
|
|
|
|
GPU_framebuffer_bind(fbl->main_color_fb);
|
2019-04-17 06:17:24 +02:00
|
|
|
DRW_draw_pass(psl->volumetric_resolve_ps);
|
|
|
|
|
|
2019-06-27 14:40:29 +02:00
|
|
|
/* Restore. */
|
2019-04-17 06:17:24 +02:00
|
|
|
GPU_framebuffer_bind(fbl->main_fb);
|
|
|
|
|
}
|
2017-11-01 01:03:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EEVEE_volumes_free_smoke_textures(void)
|
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
/* Free Smoke Textures after rendering */
|
|
|
|
|
for (LinkData *link = e_data.smoke_domains.first; link; link = link->next) {
|
2019-12-16 15:50:14 +01:00
|
|
|
FluidModifierData *mmd = (FluidModifierData *)link->data;
|
|
|
|
|
GPU_free_smoke(mmd);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
BLI_freelistN(&e_data.smoke_domains);
|
2017-11-01 01:03:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EEVEE_volumes_free(void)
|
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
MEM_SAFE_FREE(e_data.volumetric_common_lib);
|
|
|
|
|
MEM_SAFE_FREE(e_data.volumetric_common_lights_lib);
|
2017-11-01 01:03:36 +01:00
|
|
|
|
2019-05-16 21:41:22 +02:00
|
|
|
DRW_TEXTURE_FREE_SAFE(e_data.dummy_scatter);
|
|
|
|
|
DRW_TEXTURE_FREE_SAFE(e_data.dummy_transmit);
|
|
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
DRW_TEXTURE_FREE_SAFE(e_data.dummy_density);
|
|
|
|
|
DRW_TEXTURE_FREE_SAFE(e_data.dummy_flame);
|
2019-04-15 14:36:16 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
DRW_SHADER_FREE_SAFE(e_data.volumetric_clear_sh);
|
2019-05-16 21:41:22 +02:00
|
|
|
DRW_SHADER_FREE_SAFE(e_data.scatter_sh);
|
|
|
|
|
DRW_SHADER_FREE_SAFE(e_data.scatter_with_lights_sh);
|
2019-04-17 06:17:24 +02:00
|
|
|
DRW_SHADER_FREE_SAFE(e_data.volumetric_integration_sh);
|
|
|
|
|
DRW_SHADER_FREE_SAFE(e_data.volumetric_resolve_sh);
|
2020-02-20 14:53:53 +01:00
|
|
|
DRW_SHADER_FREE_SAFE(e_data.volumetric_accum_sh);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
|
|
/** \name Render Passes
|
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
|
|
void EEVEE_volumes_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, uint tot_samples)
|
|
|
|
|
{
|
|
|
|
|
EEVEE_FramebufferList *fbl = vedata->fbl;
|
|
|
|
|
EEVEE_TextureList *txl = vedata->txl;
|
|
|
|
|
EEVEE_StorageList *stl = vedata->stl;
|
|
|
|
|
EEVEE_PassList *psl = vedata->psl;
|
|
|
|
|
EEVEE_EffectsInfo *effects = stl->effects;
|
|
|
|
|
|
|
|
|
|
float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f};
|
|
|
|
|
|
|
|
|
|
/* Create FrameBuffer. */
|
|
|
|
|
|
|
|
|
|
/* Should be enough precision for many samples. */
|
|
|
|
|
const eGPUTextureFormat texture_format_accum = (tot_samples > 128) ? GPU_RGBA32F : GPU_RGBA16F;
|
|
|
|
|
DRW_texture_ensure_fullscreen_2d(&txl->volume_scatter_accum, texture_format_accum, 0);
|
|
|
|
|
DRW_texture_ensure_fullscreen_2d(&txl->volume_transmittance_accum, texture_format_accum, 0);
|
|
|
|
|
|
|
|
|
|
GPU_framebuffer_ensure_config(&fbl->volumetric_accum_fb,
|
|
|
|
|
{GPU_ATTACHMENT_NONE,
|
|
|
|
|
GPU_ATTACHMENT_TEXTURE(txl->volume_scatter_accum),
|
|
|
|
|
GPU_ATTACHMENT_TEXTURE(txl->volume_transmittance_accum)});
|
|
|
|
|
|
|
|
|
|
/* Clear texture. */
|
|
|
|
|
if (DRW_state_is_image_render() || effects->taa_current_sample == 1) {
|
|
|
|
|
GPU_framebuffer_bind(fbl->volumetric_accum_fb);
|
|
|
|
|
GPU_framebuffer_clear_color(fbl->volumetric_accum_fb, clear);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Create Pass and shgroup. */
|
|
|
|
|
DRW_PASS_CREATE(psl->volumetric_accum_ps, DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ADD_FULL);
|
|
|
|
|
DRWShadingGroup *grp = NULL;
|
|
|
|
|
if ((effects->enabled_effects & EFFECT_VOLUMETRIC) != 0) {
|
|
|
|
|
grp = DRW_shgroup_create(e_data.volumetric_resolve_sh, psl->volumetric_accum_ps);
|
|
|
|
|
DRW_shgroup_uniform_texture_ref(grp, "inScattering", &txl->volume_scatter);
|
|
|
|
|
DRW_shgroup_uniform_texture_ref(grp, "inTransmittance", &txl->volume_transmit);
|
|
|
|
|
DRW_shgroup_uniform_texture_ref(grp, "inSceneDepth", &e_data.depth_src);
|
|
|
|
|
DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
|
|
|
|
|
DRW_shgroup_uniform_block(
|
|
|
|
|
grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata));
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* There is no volumetrics in the scene. Use a shader to fill the accum textures with a default
|
|
|
|
|
* value. */
|
|
|
|
|
grp = DRW_shgroup_create(e_data.volumetric_accum_sh, psl->volumetric_accum_ps);
|
|
|
|
|
}
|
|
|
|
|
DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL);
|
2017-11-01 01:03:36 +01:00
|
|
|
}
|
2020-02-20 14:53:53 +01:00
|
|
|
|
|
|
|
|
void EEVEE_volumes_output_accumulate(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
|
|
|
|
|
{
|
|
|
|
|
EEVEE_FramebufferList *fbl = vedata->fbl;
|
|
|
|
|
EEVEE_PassList *psl = vedata->psl;
|
|
|
|
|
|
|
|
|
|
if (fbl->volumetric_accum_fb != NULL) {
|
|
|
|
|
/* Accum pass */
|
|
|
|
|
GPU_framebuffer_bind(fbl->volumetric_accum_fb);
|
|
|
|
|
DRW_draw_pass(psl->volumetric_accum_ps);
|
|
|
|
|
|
|
|
|
|
/* Restore */
|
|
|
|
|
GPU_framebuffer_bind(fbl->main_fb);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* \} */
|