diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2017-10-27 17:20:33 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2017-10-27 23:49:15 +0300 |
commit | 4f7665c84410e9e25360b0d80ce073c54242e5d4 (patch) | |
tree | 58b248d3fd41d1312e6f7bfd455cb583f251137b /source/blender/draw | |
parent | 18ba7e26ad445981fb2750ec4bef1273f11d1554 (diff) |
Eevee: Volumetrics: Add Volume object support.
This is quite basic as it only support boundbing boxes.
But the material can refine the volume shape in anyway the user like.
To overcome this limitation, a voxelisation should be done on the mesh (generating a SDF maybe?) and tested against every volumetric cell.
Diffstat (limited to 'source/blender/draw')
6 files changed, 172 insertions, 16 deletions
diff --git a/source/blender/draw/engines/eevee/eevee_effects.c b/source/blender/draw/engines/eevee/eevee_effects.c index c6dcf78d401..d3c22ed29f4 100644 --- a/source/blender/draw/engines/eevee/eevee_effects.c +++ b/source/blender/draw/engines/eevee/eevee_effects.c @@ -36,6 +36,7 @@ #include "BKE_global.h" /* for G.debug_value */ #include "BKE_camera.h" +#include "BKE_mesh.h" #include "BKE_object.h" #include "BKE_animsys.h" #include "BKE_screen.h" @@ -93,6 +94,7 @@ static struct { struct GPUShader *dof_resolve_sh; /* Volumetric */ + struct GPUShader *volumetric_clear_sh; struct GPUShader *volumetric_scatter_sh; struct GPUShader *volumetric_integration_sh; struct GPUShader *volumetric_resolve_sh; @@ -300,6 +302,12 @@ void EEVEE_effects_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata) e_data.volumetric_common_lamps_lib = BLI_dynstr_get_cstring(ds_frag); BLI_dynstr_free(ds_frag); + 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"); e_data.volumetric_scatter_sh = DRW_shader_create_with_lib(datatoc_volumetric_vert_glsl, datatoc_volumetric_geom_glsl, datatoc_volumetric_scatter_frag_glsl, @@ -1031,6 +1039,38 @@ static DRWShadingGroup *eevee_create_bloom_pass(const char *name, EEVEE_EffectsI return grp; } +void EEVEE_effects_cache_volume_object_add(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata, Scene *scene, Object *ob) +{ + float *texcoloc = NULL; + float *texcosize = NULL; + EEVEE_VolumetricsInfo *volumetrics = sldata->volumetrics; + Material *ma = give_current_material(ob, 1); + + if (ma == NULL) { + return; + } + + struct GPUMaterial *mat = EEVEE_material_mesh_volume_get(scene, ma); + + DRWShadingGroup *grp = DRW_shgroup_material_empty_tri_batch_create(mat, vedata->psl->volumetric_objects_ps, volumetrics->froxel_tex_size[2]); + + /* Making sure it's updated. */ + invert_m4_m4(ob->imat, ob->obmat); + + BKE_mesh_texspace_get_reference((struct Mesh *)ob->data, NULL, &texcoloc, NULL, &texcosize); + + if (grp) { + DRW_shgroup_uniform_mat4(grp, "volumeObjectMatrix", (float *)ob->imat); + DRW_shgroup_uniform_vec3(grp, "volumeOrcoLoc", texcoloc, 1); + DRW_shgroup_uniform_vec3(grp, "volumeOrcoSize", texcosize, 1); + DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)vedata->stl->g_data->viewvecs, 2); + DRW_shgroup_uniform_ivec3(grp, "volumeTextureSize", (int *)volumetrics->froxel_tex_size, 1); + DRW_shgroup_uniform_vec2(grp, "volume_uv_ratio", (float *)volumetrics->volume_coord_scale, 1); + DRW_shgroup_uniform_vec3(grp, "volume_param", (float *)volumetrics->depth_param, 1); + DRW_shgroup_uniform_vec3(grp, "volume_jitter", (float *)volumetrics->jitter, 1); + } +} + void EEVEE_effects_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata) { EEVEE_PassList *psl = vedata->psl; @@ -1054,27 +1094,37 @@ void EEVEE_effects_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata) 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 */ EEVEE_VolumetricsInfo *volumetrics = sldata->volumetrics; static int zero = 0; DRWShadingGroup *grp; /* World pass is not additive as it also clear the buffer. */ - psl->volumetric_ps = DRW_pass_create("Volumetric Properties", DRW_STATE_WRITE_COLOR); + psl->volumetric_world_ps = DRW_pass_create("Volumetric World", DRW_STATE_WRITE_COLOR); /* World Volumetric */ - struct GPUMaterial *mat = EEVEE_material_world_volume_get(scene, wo); - - grp = DRW_shgroup_material_empty_tri_batch_create(mat, psl->volumetric_ps, volumetrics->froxel_tex_size[2]); + struct World *wo = scene->world; + if (wo != NULL && wo->use_nodes && wo->nodetree) { + struct GPUMaterial *mat = EEVEE_material_world_volume_get(scene, wo); + + grp = DRW_shgroup_material_empty_tri_batch_create(mat, psl->volumetric_world_ps, volumetrics->froxel_tex_size[2]); + + if (grp) { + DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2); + DRW_shgroup_uniform_ivec3(grp, "volumeTextureSize", (int *)volumetrics->froxel_tex_size, 1); + DRW_shgroup_uniform_vec2(grp, "volume_uv_ratio", (float *)volumetrics->volume_coord_scale, 1); + DRW_shgroup_uniform_vec3(grp, "volume_param", (float *)volumetrics->depth_param, 1); + DRW_shgroup_uniform_vec3(grp, "volume_jitter", (float *)volumetrics->jitter, 1); + } + } + else { + grp = DRW_shgroup_empty_tri_batch_create(e_data.volumetric_clear_sh, psl->volumetric_world_ps, volumetrics->froxel_tex_size[2]); - if (grp) { - DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2); DRW_shgroup_uniform_ivec3(grp, "volumeTextureSize", (int *)volumetrics->froxel_tex_size, 1); - DRW_shgroup_uniform_vec2(grp, "volume_uv_ratio", (float *)volumetrics->volume_coord_scale, 1); - DRW_shgroup_uniform_vec3(grp, "volume_param", (float *)volumetrics->depth_param, 1); - DRW_shgroup_uniform_vec3(grp, "volume_jitter", (float *)volumetrics->jitter, 1); } + /* Volumetric Objects */ + psl->volumetric_objects_ps = DRW_pass_create("Volumetric Properties", DRW_STATE_WRITE_COLOR | DRW_STATE_ADDITIVE); + psl->volumetric_scatter_ps = DRW_pass_create("Volumetric Scattering", DRW_STATE_WRITE_COLOR); grp = DRW_shgroup_empty_tri_batch_create(e_data.volumetric_scatter_sh, psl->volumetric_scatter_ps, volumetrics->froxel_tex_size[2]); DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2); @@ -1490,7 +1540,8 @@ void EEVEE_effects_do_volumetrics(EEVEE_SceneLayerData *UNUSED(sldata), EEVEE_Da /* Step 1: Participating Media Properties */ DRW_framebuffer_bind(fbl->volumetric_fb); - DRW_draw_pass(psl->volumetric_ps); + DRW_draw_pass(psl->volumetric_world_ps); + DRW_draw_pass(psl->volumetric_objects_ps); /* Step 2: Scatter Light */ DRW_framebuffer_bind(fbl->volumetric_scat_fb); @@ -1852,6 +1903,7 @@ void EEVEE_effects_free(void) DRW_SHADER_FREE_SAFE(e_data.gtao_sh); DRW_SHADER_FREE_SAFE(e_data.gtao_debug_sh); + DRW_SHADER_FREE_SAFE(e_data.volumetric_clear_sh); DRW_SHADER_FREE_SAFE(e_data.volumetric_scatter_sh); DRW_SHADER_FREE_SAFE(e_data.volumetric_integration_sh); DRW_SHADER_FREE_SAFE(e_data.volumetric_resolve_sh); diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index f5d3898d1bc..1d551796a60 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -318,7 +318,7 @@ static char *eevee_get_defines(int options) return str; } -static char *eevee_get_volume_defines(int UNUSED(options)) +static char *eevee_get_volume_defines(int options) { char *str = NULL; @@ -326,6 +326,10 @@ static char *eevee_get_volume_defines(int UNUSED(options)) BLI_dynstr_appendf(ds, SHADER_DEFINES); BLI_dynstr_appendf(ds, "#define VOLUMETRICS\n"); + if ((options & VAR_MAT_VOLUME) != 0) { + BLI_dynstr_appendf(ds, "#define MESH_SHADER\n"); + } + str = BLI_dynstr_get_cstring(ds); BLI_dynstr_free(ds); @@ -656,6 +660,28 @@ struct GPUMaterial *EEVEE_material_mesh_get( return mat; } +struct GPUMaterial *EEVEE_material_mesh_volume_get(struct Scene *scene, Material *ma) +{ + const void *engine = &DRW_engine_viewport_eevee_type; + int options = VAR_MAT_VOLUME; + + GPUMaterial *mat = GPU_material_from_nodetree_find(&ma->gpumaterial, engine, options); + if (mat != NULL) { + return mat; + } + + char *defines = eevee_get_volume_defines(options); + + mat = GPU_material_from_nodetree( + scene, ma->nodetree, &ma->gpumaterial, engine, options, + datatoc_volumetric_vert_glsl, datatoc_volumetric_geom_glsl, e_data.volume_shader_lib, + defines); + + MEM_freeN(defines); + + return mat; +} + struct GPUMaterial *EEVEE_material_mesh_depth_get( struct Scene *scene, Material *ma, bool use_hashed_alpha, bool is_shadow) @@ -1200,6 +1226,12 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_SceneLayerData *sl DRW_cache_mesh_sculpt_coords_ensure(ob); } + /* Only support single volume material for now. */ + /* XXX We rely on the previously compiled surface shader + * to know if the material has a "volume nodetree". + */ + bool use_volume_material = (gpumat_array[0] && GPU_material_use_domain_volume(gpumat_array[0])); + /* Get per-material split surface */ struct Gwn_Batch **mat_geom = DRW_cache_object_surface_material_get(ob, gpumat_array, materials_len); if (mat_geom) { @@ -1209,6 +1241,14 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_SceneLayerData *sl if (ma == NULL) ma = &defmaterial; + /* Do not render surface if we are rendering a volume object + * and do not have a surface closure. */ + if (use_volume_material && + (gpumat_array[i] && !GPU_material_use_domain_surface(gpumat_array[i]))) + { + continue; + } + /* Shading pass */ ADD_SHGROUP_CALL(shgrp_array[i], ob, mat_geom[i]); @@ -1241,6 +1281,11 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_SceneLayerData *sl } } } + + /* Volumetrics */ + if (vedata->stl->effects->use_volumetrics && use_volume_material) { + EEVEE_effects_cache_volume_object_add(sldata, vedata, scene, ob); + } } if (ob->type == OB_MESH) { diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index ced44fad0c9..20353fdc512 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -133,7 +133,8 @@ typedef struct EEVEE_PassList { struct DRWPass *dof_down; struct DRWPass *dof_scatter; struct DRWPass *dof_resolve; - struct DRWPass *volumetric_ps; + struct DRWPass *volumetric_world_ps; + struct DRWPass *volumetric_objects_ps; struct DRWPass *volumetric_scatter_ps; struct DRWPass *volumetric_integration_ps; struct DRWPass *volumetric_resolve_ps; @@ -600,6 +601,7 @@ struct GPUMaterial *EEVEE_material_world_volume_get(struct Scene *scene, struct struct GPUMaterial *EEVEE_material_mesh_get( struct Scene *scene, Material *ma, EEVEE_Data *vedata, bool use_blend, bool use_multiply, bool use_refract, int shadow_method); +struct GPUMaterial *EEVEE_material_mesh_volume_get(struct Scene *scene, Material *ma); struct GPUMaterial *EEVEE_material_mesh_depth_get(struct Scene *scene, Material *ma, bool use_hashed_alpha, bool is_shadow); struct GPUMaterial *EEVEE_material_hair_get(struct Scene *scene, Material *ma, int shadow_method); void EEVEE_materials_free(void); @@ -632,6 +634,7 @@ void EEVEE_lightprobes_free(void); /* eevee_effects.c */ void EEVEE_effects_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata); void EEVEE_effects_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata); +void EEVEE_effects_cache_volume_object_add(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata, struct Scene *scene, Object *ob); void EEVEE_create_minmax_buffer(EEVEE_Data *vedata, struct GPUTexture *depth_src, int layer); void EEVEE_downsample_buffer(EEVEE_Data *vedata, struct GPUFrameBuffer *fb_src, struct GPUTexture *texture_src, int level); void EEVEE_downsample_cube_buffer(EEVEE_Data *vedata, struct GPUFrameBuffer *fb_src, struct GPUTexture *texture_src, int level); diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl index eb0b93d5ac4..b2c72126c40 100644 --- a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl @@ -574,7 +574,8 @@ Closure closure_add(Closure cl1, Closure cl2) cl.anisotropy = (cl1.anisotropy + cl2.anisotropy) / 2.0; /* Average phase (no multi lobe) */ return cl; } -#else + +#else /* VOLUMETRICS */ struct Closure { vec3 radiance; diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl index a3e2979a9b4..00e01e753f9 100644 --- a/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl @@ -7,12 +7,21 @@ uniform ivec3 volumeTextureSize; uniform vec3 volume_jitter; +#ifdef MESH_SHADER +uniform mat4 volumeObjectMatrix; +uniform vec3 volumeOrcoLoc; +uniform vec3 volumeOrcoSize; +#endif + flat in int slice; /* Warning: theses are not attributes, theses are global vars. */ vec3 worldPosition = vec3(0.0); vec3 viewPosition = vec3(0.0); vec3 viewNormal = vec3(0.0); +#ifdef MESH_SHADER +vec3 volumeObjectLocalCoord = vec3(0.0); +#endif layout(location = 0) out vec4 volumeScattering; layout(location = 1) out vec4 volumeExtinction; @@ -28,11 +37,30 @@ void main() viewPosition = get_view_space_from_depth(ndc_cell.xy, ndc_cell.z); worldPosition = transform_point(ViewMatrixInverse, viewPosition); +#ifdef MESH_SHADER + volumeObjectLocalCoord = transform_point(volumeObjectMatrix, worldPosition); + volumeObjectLocalCoord = (volumeObjectLocalCoord - volumeOrcoLoc + volumeOrcoSize) / (volumeOrcoSize * 2.0); + + if (any(lessThan(volumeObjectLocalCoord, vec3(0.0))) || + any(greaterThan(volumeObjectLocalCoord, vec3(1.0)))) + discard; +#endif +#ifdef CLEAR + Closure cl = CLOSURE_DEFAULT; +#else Closure cl = nodetree_exec(); +#endif volumeScattering = vec4(cl.scatter, 1.0); volumeExtinction = vec4(max(vec3(1e-4), cl.absorption + cl.scatter), 1.0); volumeEmissive = vec4(cl.emission, 1.0); - volumePhase = vec4(cl.anisotropy, vec3(1.0)); + + /* Do not add phase weight if no scattering. */ + if (all(equal(cl.scatter, vec3(0.0)))) { + volumePhase = vec4(0.0); + } + else { + volumePhase = vec4(cl.anisotropy, vec3(1.0)); + } } diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_geom.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_geom.glsl index f944184058d..208e8165689 100644 --- a/source/blender/draw/engines/eevee/shaders/volumetric_geom.glsl +++ b/source/blender/draw/engines/eevee/shaders/volumetric_geom.glsl @@ -1,11 +1,36 @@ +#ifdef MESH_SHADER +/* TODO tight slices */ layout(triangles) in; layout(triangle_strip, max_vertices=3) out; +#else /* World */ +layout(triangles) in; +layout(triangle_strip, max_vertices=3) out; +#endif in vec4 vPos[]; flat out int slice; +#ifdef MESH_SHADER +/* TODO tight slices */ +void main() { + gl_Layer = slice = int(vPos[0].z); + + gl_Position = vPos[0].xyww; + EmitVertex(); + + gl_Position = vPos[1].xyww; + EmitVertex(); + + gl_Position = vPos[2].xyww; + EmitVertex(); + + EndPrimitive(); +} + +#else /* World */ + /* This is just a pass-through geometry shader that send the geometry * to the layer corresponding to it's depth. */ @@ -22,4 +47,6 @@ void main() { EmitVertex(); EndPrimitive(); -}
\ No newline at end of file +} + +#endif |