Eevee: Add support for volumetrics in node tree.
Only volume scatter is implemented for now.
This commit is contained in:
parent
2eef097831
commit
b09052002c
Notes:
blender-bot
2023-02-14 06:55:44 +01:00
Referenced by issue #51644, Crash upon Startup
|
@ -32,6 +32,7 @@
|
|||
#include "DNA_camera_types.h"
|
||||
#include "DNA_screen_types.h"
|
||||
#include "DNA_view3d_types.h"
|
||||
#include "DNA_world_types.h"
|
||||
|
||||
#include "BKE_camera.h"
|
||||
#include "BKE_object.h"
|
||||
|
@ -402,14 +403,17 @@ void EEVEE_effects_init(EEVEE_Data *vedata)
|
|||
&tex, 1);
|
||||
|
||||
if (BKE_collection_engine_property_value_get_bool(props, "volumetric_enable")) {
|
||||
/* MinMax Pyramid */
|
||||
/* Integration result */
|
||||
DRWFboTexture tex_vol = {&stl->g_data->volumetric, DRW_TEX_RGBA_16, DRW_TEX_MIPMAP | DRW_TEX_FILTER | DRW_TEX_TEMP};
|
||||
|
||||
DRW_framebuffer_init(&fbl->volumetric_fb, &draw_engine_eevee_type,
|
||||
(int)viewport_size[0] / 2, (int)viewport_size[1] / 2,
|
||||
&tex_vol, 1);
|
||||
|
||||
effects->enabled_effects |= EFFECT_VOLUMETRIC;
|
||||
World *wo = scene->world;
|
||||
if ((wo != NULL) && (wo->use_nodes != NULL) && (wo->nodetree != NULL)) {
|
||||
effects->enabled_effects |= EFFECT_VOLUMETRIC;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -441,27 +445,38 @@ void EEVEE_effects_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata)
|
|||
|
||||
struct Gwn_Batch *quad = DRW_cache_fullscreen_quad_get();
|
||||
|
||||
{
|
||||
struct GPUShader *sh = EEVEE_material_world_volume_get(NULL, NULL);
|
||||
psl->volumetric_integrate_ps = DRW_pass_create("Volumetric Integration", DRW_STATE_WRITE_COLOR);
|
||||
DRWShadingGroup *grp = DRW_shgroup_create(sh, psl->volumetric_integrate_ps);
|
||||
DRW_shgroup_uniform_buffer(grp, "depthFull", &e_data.depth_src);
|
||||
DRW_shgroup_uniform_buffer(grp, "shadowCubes", &sldata->shadow_depth_cube_pool);
|
||||
DRW_shgroup_uniform_buffer(grp, "irradianceGrid", &sldata->irradiance_pool);
|
||||
DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo);
|
||||
DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo);
|
||||
DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo);
|
||||
DRW_shgroup_uniform_int(grp, "light_count", &sldata->lamps->num_light, 1);
|
||||
DRW_shgroup_uniform_int(grp, "grid_count", &sldata->probes->num_render_grid, 1);
|
||||
DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex());
|
||||
DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2);
|
||||
DRW_shgroup_call_add(grp, quad, NULL);
|
||||
if ((effects->enabled_effects & EFFECT_VOLUMETRIC) != 0) {
|
||||
const DRWContextState *draw_ctx = DRW_context_state_get();
|
||||
Scene *scene = draw_ctx->scene;
|
||||
struct World *wo = scene->world; /* Already checked non NULL */
|
||||
|
||||
psl->volumetric_resolve_ps = DRW_pass_create("Volumetric Resolve", DRW_STATE_WRITE_COLOR | DRW_STATE_TRANSMISSION);
|
||||
grp = DRW_shgroup_create(e_data.volumetric_upsample_sh, psl->volumetric_resolve_ps);
|
||||
DRW_shgroup_uniform_buffer(grp, "depthFull", &e_data.depth_src);
|
||||
DRW_shgroup_uniform_buffer(grp, "volumetricBuffer", &stl->g_data->volumetric);
|
||||
DRW_shgroup_call_add(grp, quad, NULL);
|
||||
struct GPUMaterial *mat = EEVEE_material_world_volume_get(scene, wo);
|
||||
psl->volumetric_integrate_ps = DRW_pass_create("Volumetric Integration", DRW_STATE_WRITE_COLOR);
|
||||
DRWShadingGroup *grp = DRW_shgroup_material_create(mat, psl->volumetric_integrate_ps);
|
||||
|
||||
if (grp != NULL) {
|
||||
DRW_shgroup_uniform_buffer(grp, "depthFull", &e_data.depth_src);
|
||||
DRW_shgroup_uniform_buffer(grp, "shadowCubes", &sldata->shadow_depth_cube_pool);
|
||||
DRW_shgroup_uniform_buffer(grp, "irradianceGrid", &sldata->irradiance_pool);
|
||||
DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo);
|
||||
DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo);
|
||||
DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo);
|
||||
DRW_shgroup_uniform_int(grp, "light_count", &sldata->lamps->num_light, 1);
|
||||
DRW_shgroup_uniform_int(grp, "grid_count", &sldata->probes->num_render_grid, 1);
|
||||
DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex());
|
||||
DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2);
|
||||
DRW_shgroup_call_add(grp, quad, NULL);
|
||||
|
||||
psl->volumetric_resolve_ps = DRW_pass_create("Volumetric Resolve", DRW_STATE_WRITE_COLOR | DRW_STATE_TRANSMISSION);
|
||||
grp = DRW_shgroup_create(e_data.volumetric_upsample_sh, psl->volumetric_resolve_ps);
|
||||
DRW_shgroup_uniform_buffer(grp, "depthFull", &e_data.depth_src);
|
||||
DRW_shgroup_uniform_buffer(grp, "volumetricBuffer", &stl->g_data->volumetric);
|
||||
DRW_shgroup_call_add(grp, quad, NULL);
|
||||
}
|
||||
else {
|
||||
/* Compilation failled */
|
||||
effects->enabled_effects &= ~EFFECT_VOLUMETRIC;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
|
|
|
@ -73,7 +73,6 @@ static struct {
|
|||
|
||||
extern char datatoc_background_vert_glsl[];
|
||||
extern char datatoc_default_world_frag_glsl[];
|
||||
extern char datatoc_fullscreen_vert_glsl[];
|
||||
extern char datatoc_lightprobe_filter_glossy_frag_glsl[];
|
||||
extern char datatoc_lightprobe_filter_diffuse_frag_glsl[];
|
||||
extern char datatoc_lightprobe_geom_glsl[];
|
||||
|
|
|
@ -63,8 +63,8 @@
|
|||
/* *********** STATIC *********** */
|
||||
static struct {
|
||||
char *frag_shader_lib;
|
||||
char *volume_shader_lib;
|
||||
|
||||
struct GPUShader *default_volume_sh;
|
||||
struct GPUShader *default_prepass_sh;
|
||||
struct GPUShader *default_prepass_clip_sh;
|
||||
struct GPUShader *default_lit[VAR_MAT_MAX];
|
||||
|
@ -271,6 +271,12 @@ void EEVEE_materials_init(EEVEE_StorageList *stl)
|
|||
e_data.frag_shader_lib = BLI_dynstr_get_cstring(ds_frag);
|
||||
BLI_dynstr_free(ds_frag);
|
||||
|
||||
ds_frag = BLI_dynstr_new();
|
||||
BLI_dynstr_append(ds_frag, e_data.frag_shader_lib);
|
||||
BLI_dynstr_append(ds_frag, datatoc_volumetric_frag_glsl);
|
||||
e_data.volume_shader_lib = BLI_dynstr_get_cstring(ds_frag);
|
||||
BLI_dynstr_free(ds_frag);
|
||||
|
||||
ds_frag = BLI_dynstr_new();
|
||||
BLI_dynstr_append(ds_frag, e_data.frag_shader_lib);
|
||||
BLI_dynstr_append(ds_frag, datatoc_default_frag_glsl);
|
||||
|
@ -290,16 +296,6 @@ void EEVEE_materials_init(EEVEE_StorageList *stl)
|
|||
|
||||
MEM_freeN(frag_str);
|
||||
|
||||
ds_frag = BLI_dynstr_new();
|
||||
BLI_dynstr_append(ds_frag, e_data.frag_shader_lib);
|
||||
BLI_dynstr_append(ds_frag, datatoc_volumetric_frag_glsl);
|
||||
frag_str = BLI_dynstr_get_cstring(ds_frag);
|
||||
BLI_dynstr_free(ds_frag);
|
||||
|
||||
e_data.default_volume_sh = DRW_shader_create_fullscreen(frag_str, SHADER_DEFINES "#define STEP_INTEGRATE\n");
|
||||
|
||||
MEM_freeN(frag_str);
|
||||
|
||||
/* Textures */
|
||||
const int layers = 3;
|
||||
float (*texels)[4] = MEM_mallocN(sizeof(float[4]) * 64 * 64 * layers, "utils texels");
|
||||
|
@ -403,9 +399,19 @@ struct GPUMaterial *EEVEE_material_world_background_get(struct Scene *scene, Wor
|
|||
SHADER_DEFINES "#define WORLD_BACKGROUND\n");
|
||||
}
|
||||
|
||||
struct GPUShader *EEVEE_material_world_volume_get(struct Scene *UNUSED(scene), World *UNUSED(wo))
|
||||
struct GPUMaterial *EEVEE_material_world_volume_get(struct Scene *scene, World *wo)
|
||||
{
|
||||
return e_data.default_volume_sh;
|
||||
const void *engine = &DRW_engine_viewport_eevee_type;
|
||||
int options = VAR_WORLD_VOLUME;
|
||||
|
||||
GPUMaterial *mat = GPU_material_from_nodetree_find(&wo->gpumaterial, engine, options);
|
||||
if (mat != NULL) {
|
||||
return mat;
|
||||
}
|
||||
return GPU_material_from_nodetree(
|
||||
scene, wo->nodetree, &wo->gpumaterial, engine, options,
|
||||
datatoc_background_vert_glsl, NULL, e_data.volume_shader_lib,
|
||||
SHADER_DEFINES "#define VOLUMETRICS\n");
|
||||
}
|
||||
|
||||
struct GPUMaterial *EEVEE_material_mesh_get(
|
||||
|
@ -785,7 +791,7 @@ void EEVEE_materials_free(void)
|
|||
DRW_SHADER_FREE_SAFE(e_data.default_lit[i]);
|
||||
}
|
||||
MEM_SAFE_FREE(e_data.frag_shader_lib);
|
||||
DRW_SHADER_FREE_SAFE(e_data.default_volume_sh);
|
||||
MEM_SAFE_FREE(e_data.volume_shader_lib);
|
||||
DRW_SHADER_FREE_SAFE(e_data.default_prepass_sh);
|
||||
DRW_SHADER_FREE_SAFE(e_data.default_prepass_clip_sh);
|
||||
DRW_SHADER_FREE_SAFE(e_data.default_background);
|
||||
|
|
|
@ -50,6 +50,7 @@ extern struct DrawEngineType draw_engine_eevee_type;
|
|||
enum {
|
||||
VAR_WORLD_BACKGROUND,
|
||||
VAR_WORLD_PROBE,
|
||||
VAR_WORLD_VOLUME,
|
||||
};
|
||||
|
||||
/* Material shader variations */
|
||||
|
@ -424,7 +425,7 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_SceneLayerData *sl
|
|||
void EEVEE_materials_cache_finish(EEVEE_Data *vedata);
|
||||
struct GPUMaterial *EEVEE_material_world_lightprobe_get(struct Scene *scene, struct World *wo);
|
||||
struct GPUMaterial *EEVEE_material_world_background_get(struct Scene *scene, struct World *wo);
|
||||
struct GPUShader *EEVEE_material_world_volume_get(struct Scene *scene, struct World *wo);
|
||||
struct GPUMaterial *EEVEE_material_world_volume_get(struct Scene *scene, struct World *wo);
|
||||
struct GPUMaterial *EEVEE_material_mesh_lightprobe_get(struct Scene *scene, Material *ma);
|
||||
struct GPUMaterial *EEVEE_material_mesh_get(struct Scene *scene, Material *ma, bool use_ao, bool use_bent_normals);
|
||||
struct GPUMaterial *EEVEE_material_hair_get(struct Scene *scene, Material *ma, bool use_ao, bool use_bent_normals);
|
||||
|
|
|
@ -17,6 +17,44 @@ uniform vec4 viewvecs[2];
|
|||
#define cameraPos ViewMatrixInverse[3].xyz
|
||||
|
||||
/* ------- Structures -------- */
|
||||
#ifdef VOLUMETRICS
|
||||
|
||||
#define NODETREE_EXEC
|
||||
|
||||
struct Closure {
|
||||
vec3 absorption;
|
||||
vec3 scatter;
|
||||
vec3 emission;
|
||||
float anisotropy;
|
||||
};
|
||||
|
||||
#define CLOSURE_DEFAULT Closure(vec3(0.0), vec3(0.0), vec3(0.0), 0.0);
|
||||
|
||||
Closure closure_mix(Closure cl1, Closure cl2, float fac)
|
||||
{
|
||||
Closure cl;
|
||||
cl.absorption = mix(cl1.absorption, cl2.absorption, fac);
|
||||
cl.scatter = mix(cl1.scatter, cl2.scatter, fac);
|
||||
cl.emission = mix(cl1.emission, cl2.emission, fac);
|
||||
cl.anisotropy = mix(cl1.anisotropy, cl2.anisotropy, fac);
|
||||
return cl;
|
||||
}
|
||||
|
||||
Closure closure_add(Closure cl1, Closure cl2)
|
||||
{
|
||||
Closure cl;
|
||||
cl.absorption = cl1.absorption + cl2.absorption;
|
||||
cl.scatter = cl1.scatter + cl2.scatter;
|
||||
cl.emission = cl1.emission + cl2.emission;
|
||||
cl.anisotropy = cl1.anisotropy + cl2.anisotropy;
|
||||
return cl;
|
||||
}
|
||||
|
||||
Closure nodetree_exec(void); /* Prototype */
|
||||
|
||||
|
||||
#endif /* VOLUMETRICS */
|
||||
|
||||
|
||||
struct LightData {
|
||||
vec4 position_influence; /* w : InfluenceRadius */
|
||||
|
|
|
@ -1,10 +1,42 @@
|
|||
|
||||
out vec4 FragColor;
|
||||
|
||||
#ifdef STEP_INTEGRATE
|
||||
#ifdef VOLUMETRICS
|
||||
|
||||
uniform sampler2D depthFull;
|
||||
|
||||
void participating_media_properties(vec3 wpos, out vec3 absorption, out vec3 scattering, out float anisotropy)
|
||||
{
|
||||
Closure cl = nodetree_exec();
|
||||
|
||||
absorption = cl.absorption;
|
||||
scattering = cl.scatter;
|
||||
anisotropy = cl.anisotropy;
|
||||
}
|
||||
|
||||
float phase_function_isotropic()
|
||||
{
|
||||
return 1.0 / (4.0 * M_PI);
|
||||
}
|
||||
|
||||
float phase_function(vec3 v, vec3 l, float g)
|
||||
{
|
||||
#if 1
|
||||
/* Henyey-Greenstein */
|
||||
float cos_theta = dot(v, l);
|
||||
float sqr_g = g * g;
|
||||
return (1- sqr_g) / (4.0 * M_PI * pow(1 + sqr_g - 2 * g * cos_theta, 3.0 / 2.0));
|
||||
#else
|
||||
return phase_function_isotropic();
|
||||
#endif
|
||||
}
|
||||
|
||||
vec3 light_volume(LightData ld, vec4 l_vector, vec3 l_col)
|
||||
{
|
||||
float dist = max(1e-4, abs(l_vector.w - ld.l_radius));
|
||||
return l_col * (4.0 * ld.l_radius * ld.l_radius * M_PI * M_PI) / (dist * dist);
|
||||
}
|
||||
|
||||
float find_next_step(float near, float far, float noise, int iter, int iter_count)
|
||||
{
|
||||
const float lambda = 0.8f; /* TODO : Parameter */
|
||||
|
@ -22,38 +54,6 @@ float find_next_step(float near, float far, float noise, int iter, int iter_coun
|
|||
}
|
||||
}
|
||||
|
||||
void participating_media_properties(vec3 wpos, out vec3 absorption, out vec3 scattering, out float anisotropy)
|
||||
{
|
||||
/* TODO Call nodetree from here. */
|
||||
absorption = vec3(0.00);
|
||||
scattering = vec3(1.0) * step(-1.0, -wpos.z);
|
||||
|
||||
anisotropy = -0.8;
|
||||
}
|
||||
|
||||
float phase_function_isotropic()
|
||||
{
|
||||
return 1.0 / (4.0 * M_PI);
|
||||
}
|
||||
|
||||
float phase_function(vec3 v, vec3 l, float g)
|
||||
{
|
||||
#if 0
|
||||
/* Henyey-Greenstein */
|
||||
float cos_theta = dot(v, l);
|
||||
float sqr_g = g * g;
|
||||
return (1- sqr_g) / (4.0 * M_PI * pow(1 + sqr_g - 2 * g * cos_theta, 3.0 / 2.0));
|
||||
#else
|
||||
return phase_function_isotropic();
|
||||
#endif
|
||||
}
|
||||
|
||||
vec3 light_volume(LightData ld, vec4 l_vector, vec3 l_col)
|
||||
{
|
||||
float dist = max(1e-4, abs(l_vector.w - ld.l_radius));
|
||||
return l_col * (4.0 * ld.l_radius * ld.l_radius * M_PI * M_PI) / (dist * dist);
|
||||
}
|
||||
|
||||
/* Based on Frosbite Unified Volumetric.
|
||||
* https://www.ea.com/frostbite/news/physically-based-unified-volumetric-rendering-in-frostbite */
|
||||
void main()
|
||||
|
|
|
@ -2653,8 +2653,8 @@ layout(std140) uniform lightSource {
|
|||
glLight glLightSource[NUM_LIGHTS];
|
||||
};
|
||||
|
||||
#ifndef VOLUMETRICS
|
||||
/* bsdfs */
|
||||
|
||||
void node_bsdf_diffuse(vec4 color, float roughness, vec3 N, out Closure result)
|
||||
{
|
||||
/* ambient light */
|
||||
|
@ -2905,13 +2905,18 @@ void node_ambient_occlusion(vec4 color, out Closure result)
|
|||
{
|
||||
result = Closure(color.rgb, color.a);
|
||||
}
|
||||
#endif /* VOLUMETRICS */
|
||||
|
||||
/* emission */
|
||||
|
||||
void node_emission(vec4 color, float strength, vec3 N, out Closure result)
|
||||
{
|
||||
#ifndef VOLUMETRICS
|
||||
color *= strength;
|
||||
result = Closure(color.rgb, color.a);
|
||||
#else
|
||||
result = Closure(vec3(0.0), vec3(0.0), color.rgb * strength, 0.0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* background */
|
||||
|
@ -2931,8 +2936,23 @@ void background_transform_to_world(vec3 viewvec, out vec3 worldvec)
|
|||
|
||||
void node_background(vec4 color, float strength, out Closure result)
|
||||
{
|
||||
#ifndef VOLUMETRICS
|
||||
color *= strength;
|
||||
result = Closure(color.rgb, color.a);
|
||||
#else
|
||||
result = CLOSURE_DEFAULT;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* volumes */
|
||||
|
||||
void node_volume_scatter(vec4 color, float density, float anisotropy, out Closure result)
|
||||
{
|
||||
#ifdef VOLUMETRICS
|
||||
result = Closure(vec3(0.0), color.rgb * density, vec3(0.0), anisotropy);
|
||||
#else
|
||||
result = CLOSURE_DEFAULT;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* closures */
|
||||
|
@ -3947,9 +3967,14 @@ uniform float backgroundAlpha;
|
|||
|
||||
void node_output_world(Closure surface, Closure volume, out Closure result)
|
||||
{
|
||||
#ifndef VOLUMETRICS
|
||||
result = Closure(surface.radiance, backgroundAlpha);
|
||||
#else
|
||||
result = volume;
|
||||
#endif /* VOLUMETRICS */
|
||||
}
|
||||
|
||||
#ifndef VOLUMETRICS
|
||||
/* TODO : clean this ifdef mess */
|
||||
/* EEVEE output */
|
||||
#ifdef EEVEE_ENGINE
|
||||
|
@ -3982,7 +4007,8 @@ void node_output_eevee_material(Closure surface, out Closure result)
|
|||
result = Closure(surface.radiance, length(viewPosition));
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif /* EEVEE_ENGINE */
|
||||
#endif /* VOLUMETRICS */
|
||||
|
||||
/* ********************** matcap style render ******************** */
|
||||
|
||||
|
|
|
@ -41,9 +41,9 @@ static bNodeSocketTemplate sh_node_volume_scatter_out[] = {
|
|||
{ -1, 0, "" }
|
||||
};
|
||||
|
||||
static int node_shader_gpu_volume_scatter(GPUMaterial *UNUSED(mat), bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *UNUSED(in), GPUNodeStack *UNUSED(out))
|
||||
static int node_shader_gpu_volume_scatter(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
|
||||
{
|
||||
return false;
|
||||
return GPU_stack_link(mat, "node_volume_scatter", in, out);
|
||||
}
|
||||
|
||||
/* node type definition */
|
||||
|
|
Loading…
Reference in New Issue