diff --git a/source/blender/draw/engines/eevee/eevee_effects.c b/source/blender/draw/engines/eevee/eevee_effects.c index d3c22ed29f4..f5e47cb0a9d 100644 --- a/source/blender/draw/engines/eevee/eevee_effects.c +++ b/source/blender/draw/engines/eevee/eevee_effects.c @@ -30,12 +30,15 @@ #include "DNA_anim_types.h" #include "DNA_camera_types.h" +#include "DNA_object_force.h" #include "DNA_screen_types.h" +#include "DNA_smoke_types.h" #include "DNA_view3d_types.h" #include "DNA_world_types.h" #include "BKE_global.h" /* for G.debug_value */ #include "BKE_camera.h" +#include "BKE_modifier.h" #include "BKE_mesh.h" #include "BKE_object.h" #include "BKE_animsys.h" @@ -49,6 +52,7 @@ #include "BLI_rand.h" #include "eevee_private.h" +#include "GPU_draw.h" #include "GPU_extensions.h" #include "GPU_framebuffer.h" #include "GPU_texture.h" @@ -117,6 +121,9 @@ static struct { struct GPUTexture *depth_src; struct GPUTexture *color_src; + /* List of all smoke domains rendered within this frame. */ + ListBase smoke_domains; + int depth_src_layer; float cube_texel_size; } e_data = {NULL}; /* Engine data */ @@ -265,6 +272,8 @@ void EEVEE_effects_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata) const float *viewport_size = DRW_viewport_size_get(); + BLI_listbase_clear(&e_data.smoke_domains); + /* Shaders */ if (!e_data.motion_blur_sh) { DynStr *ds_frag = BLI_dynstr_new(); @@ -721,11 +730,17 @@ void EEVEE_effects_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata) double ht_point[3]; double ht_offset[3] = {0.0, 0.0}; unsigned int ht_primes[3] = {3, 7, 2}; - struct wmWindowManager *wm = CTX_wm_manager(draw_ctx->evil_C); unsigned int current_sample = 0; - if (((effects->enabled_effects & EFFECT_TAA) != 0) && (ED_screen_animation_no_scrub(wm) == NULL)) { - /* If TAA is in use do not use the history buffer. */ + /* If TAA is in use do not use the history buffer. */ + bool do_taa = ((effects->enabled_effects & EFFECT_TAA) != 0); + + 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); + } + + if (do_taa) { volumetrics->history_alpha = 0.0f; current_sample = effects->taa_current_sample - 1; effects->volume_current_sample = -1; @@ -1043,6 +1058,7 @@ void EEVEE_effects_cache_volume_object_add(EEVEE_SceneLayerData *sldata, EEVEE_D { float *texcoloc = NULL; float *texcosize = NULL; + struct ModifierData *md = NULL; EEVEE_VolumetricsInfo *volumetrics = sldata->volumetrics; Material *ma = give_current_material(ob, 1); @@ -1069,6 +1085,34 @@ void EEVEE_effects_cache_volume_object_add(EEVEE_SceneLayerData *sldata, EEVEE_D DRW_shgroup_uniform_vec3(grp, "volume_param", (float *)volumetrics->depth_param, 1); DRW_shgroup_uniform_vec3(grp, "volume_jitter", (float *)volumetrics->jitter, 1); } + + /* Smoke Simulation */ + if (((ob->base_flag & BASE_FROMDUPLI) == 0) && + (md = modifiers_findByType(ob, eModifierType_Smoke)) && + (modifier_isEnabled(scene, md, eModifierMode_Realtime))) + { + SmokeModifierData *smd = (SmokeModifierData *)md; + SmokeDomainSettings *sds = smd->domain; + /* Don't show smoke before simulation starts, this could be made an option in the future. */ + const bool show_smoke = (CFRA >= sds->point_cache[0]->startframe); + + if (sds->fluid && show_smoke) { + if (!sds->wt || !(sds->viewsettings & MOD_SMOKE_VIEW_SHOWBIG)) { + GPU_create_smoke(smd, 0); + } + else if (sds->wt && (sds->viewsettings & MOD_SMOKE_VIEW_SHOWBIG)) { + GPU_create_smoke(smd, 1); + } + BLI_addtail(&e_data.smoke_domains, BLI_genericNodeN(smd)); + } + + if (sds->tex != NULL) { + DRW_shgroup_uniform_buffer(grp, "sampdensity", &sds->tex); + } + if (sds->tex_flame != NULL) { + DRW_shgroup_uniform_buffer(grp, "sampflame", &sds->tex_flame); + } + } } void EEVEE_effects_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata) @@ -1887,6 +1931,16 @@ void EEVEE_draw_effects(EEVEE_Data *vedata) } } +void EEVEE_effects_free_smoke_texture(void) +{ + /* Free Smoke Textures after rendering */ + for (LinkData *link = e_data.smoke_domains.first; link; link = link->next) { + SmokeModifierData *smd = (SmokeModifierData *)link->data; + GPU_free_smoke(smd); + } + BLI_freelistN(&e_data.smoke_domains); +} + void EEVEE_effects_free(void) { MEM_SAFE_FREE(e_data.volumetric_common_lib); diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c index 4617d44ef45..12e4c12b148 100644 --- a/source/blender/draw/engines/eevee/eevee_engine.c +++ b/source/blender/draw/engines/eevee/eevee_engine.c @@ -277,6 +277,8 @@ static void EEVEE_draw_scene(void *vedata) } } + EEVEE_effects_free_smoke_texture(); + stl->g_data->view_updated = false; } diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index 20353fdc512..38d4a4b52e1 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -643,6 +643,7 @@ void EEVEE_effects_do_ssr(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata); void EEVEE_effects_do_refraction(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata); void EEVEE_effects_do_gtao(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata); void EEVEE_draw_effects(EEVEE_Data *vedata); +void EEVEE_effects_free_smoke_texture(void); void EEVEE_effects_free(void); /* Shadow Matrix */ diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h index 1508941f706..de274b87f9e 100644 --- a/source/blender/gpu/GPU_material.h +++ b/source/blender/gpu/GPU_material.h @@ -82,11 +82,12 @@ typedef enum GPUType { /* Values not in GPU_DATATYPE_STR */ GPU_TEX2D = 1002, - GPU_SHADOW2D = 1003, - GPU_TEXCUBE = 1004, + GPU_TEX3D = 1003, + GPU_SHADOW2D = 1004, + GPU_TEXCUBE = 1005, /* GLSL Struct types */ - GPU_CLOSURE = 1005, + GPU_CLOSURE = 1006, /* Opengl Attributes */ GPU_ATTRIB = 3001 @@ -108,7 +109,9 @@ typedef enum GPUBuiltin { GPU_PARTICLE_ANG_VELOCITY = (1 << 12), GPU_LOC_TO_VIEW_MATRIX = (1 << 13), GPU_INVERSE_LOC_TO_VIEW_MATRIX = (1 << 14), - GPU_OBJECT_INFO = (1 << 15) + GPU_OBJECT_INFO = (1 << 15), + GPU_VOLUME_DENSITY = (1 << 16), + GPU_VOLUME_FLAME = (1 << 17) } GPUBuiltin; typedef enum GPUOpenGLBuiltin { diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c index b5a7d751f2a..bc91df895c8 100644 --- a/source/blender/gpu/intern/gpu_codegen.c +++ b/source/blender/gpu/intern/gpu_codegen.c @@ -190,6 +190,9 @@ static void gpu_parse_functions_string(GHash *hash, char *code) if (!type && gpu_str_prefix(code, "sampler2D")) { type = GPU_TEX2D; } + if (!type && gpu_str_prefix(code, "sampler3D")) { + type = GPU_TEX3D; + } if (!type && gpu_str_prefix(code, "Closure")) { type = GPU_CLOSURE; @@ -420,6 +423,10 @@ const char *GPU_builtin_name(GPUBuiltin builtin) return "unfparticleangvel"; else if (builtin == GPU_OBJECT_INFO) return "unfobjectinfo"; + else if (builtin == GPU_VOLUME_DENSITY) + return "sampdensity"; + else if (builtin == GPU_VOLUME_FLAME) + return "sampflame"; else return ""; } @@ -537,7 +544,14 @@ static int codegen_process_uniforms_functions(GPUMaterial *material, DynStr *ds, builtins |= input->builtin; name = GPU_builtin_name(input->builtin); - if (gpu_str_prefix(name, "unf")) { + if (gpu_str_prefix(name, "samp")) { + if ((input->builtin == GPU_VOLUME_DENSITY) || + (input->builtin == GPU_VOLUME_FLAME)) + { + BLI_dynstr_appendf(ds, "uniform sampler3D %s;\n", name); + } + } + else if (gpu_str_prefix(name, "unf")) { BLI_dynstr_appendf(ds, "uniform %s %s;\n", GPU_DATATYPE_STR[input->type], name); } diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c index cc6afe983ca..9f1fdcfe551 100644 --- a/source/blender/gpu/intern/gpu_draw.c +++ b/source/blender/gpu/intern/gpu_draw.c @@ -1259,6 +1259,16 @@ void GPU_create_smoke(SmokeModifierData *smd, int highres) else { sds->tex = GPU_texture_create_3D_custom(sds->res[0], sds->res[1], sds->res[2], 1, GPU_R8, smoke_get_density(sds->fluid), NULL); + + /* Swizzle the RGBA components to read the Red channel so + * that the shader stay the same for colored and non color + * density textures. */ + GPU_texture_bind(sds->tex, 0); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_R, GL_RED); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_G, GL_RED); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_B, GL_RED); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_A, GL_RED); + GPU_texture_unbind(sds->tex); } sds->tex_flame = (smoke_has_fuel(sds->fluid)) ? GPU_texture_create_3D_custom(sds->res[0], sds->res[1], sds->res[2], 1, @@ -1277,6 +1287,16 @@ void GPU_create_smoke(SmokeModifierData *smd, int highres) else { sds->tex = GPU_texture_create_3D_custom(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], 1, GPU_R8, smoke_turbulence_get_density(sds->wt), NULL); + + /* Swizzle the RGBA components to read the Red channel so + * that the shader stay the same for colored and non color + * density textures. */ + GPU_texture_bind(sds->tex, 0); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_R, GL_RED); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_G, GL_RED); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_B, GL_RED); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_A, GL_RED); + GPU_texture_unbind(sds->tex); } sds->tex_flame = (smoke_turbulence_has_fuel(sds->wt)) ? GPU_texture_create_3D_custom(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], 1, diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index 312cd7bc20a..cdd3f789cca 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -2401,6 +2401,7 @@ GPUShaderExport *GPU_shader_export(struct Scene *scene, struct Material *ma) break; case GPU_NONE: + case GPU_TEX3D: case GPU_TEXCUBE: case GPU_FLOAT: case GPU_VEC2: @@ -2439,6 +2440,7 @@ GPUShaderExport *GPU_shader_export(struct Scene *scene, struct Material *ma) case GPU_NONE: case GPU_CLOSURE: case GPU_TEX2D: + case GPU_TEX3D: case GPU_TEXCUBE: case GPU_SHADOW2D: case GPU_ATTRIB: diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl index 0dd8e6643b2..afb5eca5263 100644 --- a/source/blender/gpu/shaders/gpu_shader_material.glsl +++ b/source/blender/gpu/shaders/gpu_shader_material.glsl @@ -3093,11 +3093,47 @@ void node_gamma(vec4 col, float gamma, out vec4 outcol) /* geometry */ +void node_attribute_volume_density(sampler3D tex, out vec4 outcol, out vec3 outvec, out float outf) +{ +#if defined(EEVEE_ENGINE) && defined(MESH_SHADER) && defined(VOLUMETRICS) + vec3 cos = volumeObjectLocalCoord; +#else + vec3 cos = vec3(0.0); +#endif + outvec = texture(tex, cos).aaa; + outcol = vec4(outvec, 1.0); + outf = dot(vec3(1.0 / 3.0), outvec); +} + +void node_attribute_volume_color(sampler3D tex, out vec4 outcol, out vec3 outvec, out float outf) +{ +#if defined(EEVEE_ENGINE) && defined(MESH_SHADER) && defined(VOLUMETRICS) + vec3 cos = volumeObjectLocalCoord; +#else + vec3 cos = vec3(0.0); +#endif + outvec = texture(tex, cos).rgb; + outcol = vec4(outvec, 1.0); + outf = dot(vec3(1.0 / 3.0), outvec); +} + +void node_attribute_volume_flame(sampler3D tex, out vec4 outcol, out vec3 outvec, out float outf) +{ +#if defined(EEVEE_ENGINE) && defined(MESH_SHADER) && defined(VOLUMETRICS) + vec3 cos = volumeObjectLocalCoord; +#else + vec3 cos = vec3(0.0); +#endif + outvec = texture(tex, cos).rrr; + outcol = vec4(outvec, 1.0); + outf = dot(vec3(1.0 / 3.0), outvec); +} + void node_attribute(vec3 attr, out vec4 outcol, out vec3 outvec, out float outf) { outcol = vec4(attr, 1.0); outvec = attr; - outf = (attr.x + attr.y + attr.z) / 3.0; + outf = dot(vec3(1.0 / 3.0), attr); } void node_uvmap(vec3 attr_uv, out vec3 outvec) diff --git a/source/blender/nodes/shader/nodes/node_shader_attribute.c b/source/blender/nodes/shader/nodes/node_shader_attribute.c index 3c9b21a4198..5f3699e52eb 100644 --- a/source/blender/nodes/shader/nodes/node_shader_attribute.c +++ b/source/blender/nodes/shader/nodes/node_shader_attribute.c @@ -45,9 +45,24 @@ static void node_shader_init_attribute(bNodeTree *UNUSED(ntree), bNode *node) static int node_shader_gpu_attribute(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out) { NodeShaderAttribute *attr = node->storage; - GPUNodeLink *cd_attr = GPU_attribute(CD_AUTO_FROM_NAME, attr->name); - return GPU_stack_link(mat, node, "node_attribute", in, out, cd_attr); + /* FIXME : if an attribute layer (like vertex color) has one of theses name, it will not work as expected. */ + if (strcmp(attr->name, "density") == 0) { + return GPU_stack_link(mat, node, "node_attribute_volume_density", in, out, + GPU_builtin(GPU_VOLUME_DENSITY)); + } + else if (strcmp(attr->name, "color") == 0) { + return GPU_stack_link(mat, node, "node_attribute_volume_color", in, out, + GPU_builtin(GPU_VOLUME_DENSITY)); + } + else if (strcmp(attr->name, "flame") == 0) { + return GPU_stack_link(mat, node, "node_attribute_volume_flame", in, out, + GPU_builtin(GPU_VOLUME_FLAME)); + } + else { + GPUNodeLink *cd_attr = GPU_attribute(CD_AUTO_FROM_NAME, attr->name); + return GPU_stack_link(mat, node, "node_attribute", in, out, cd_attr); + } } /* node type definition */