Eevee: Volumetrics: Support Smoke simulation textures.

It should behave like cycles.

Even if not efficient at all, we still do the same create - draw - free process that was done in the old viewport to save vram (maybe not really the case now) and not care about simulation's GPU texture state sync.
This commit is contained in:
Clément Foucault 2017-10-27 22:35:48 +02:00
parent 4f7665c844
commit bc7c0335dc
9 changed files with 158 additions and 11 deletions

View File

@ -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);

View File

@ -277,6 +277,8 @@ static void EEVEE_draw_scene(void *vedata)
}
}
EEVEE_effects_free_smoke_texture();
stl->g_data->view_updated = false;
}

View File

@ -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 */

View File

@ -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 {

View File

@ -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);
}

View File

@ -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,

View File

@ -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:

View File

@ -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)

View File

@ -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 */