Eevee: Volumetrics: Add volumetric support to alpha blended meshes.
authorClément Foucault <foucault.clem@gmail.com>
Tue, 24 Oct 2017 15:52:20 +0000 (17:52 +0200)
committerClément Foucault <foucault.clem@gmail.com>
Fri, 27 Oct 2017 20:49:15 +0000 (22:49 +0200)
source/blender/draw/engines/eevee/eevee_effects.c
source/blender/draw/engines/eevee/eevee_materials.c
source/blender/draw/engines/eevee/eevee_private.h
source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl
source/blender/draw/engines/eevee/shaders/volumetric_resolve_frag.glsl

index 2306dbbab0a6b1066f375b8c35df23adeadadb71..e5f942f5e8e452f2b378c59d6f6a8b7a2bded1bd 100644 (file)
@@ -1079,9 +1079,7 @@ void EEVEE_effects_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata)
                DRW_shgroup_uniform_mat4(grp, "PastViewProjectionMatrix", (float *)stl->g_data->prev_persmat);
                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, "grid_block", sldata->grid_ubo);
                DRW_shgroup_uniform_int(grp, "light_count", (volumetrics->use_lights) ? &sldata->lamps->num_light : &zero, 1);
-               DRW_shgroup_uniform_int(grp, "grid_count", &sldata->probes->num_render_grid, 1);
                DRW_shgroup_uniform_buffer(grp, "irradianceGrid", &sldata->irradiance_pool);
                DRW_shgroup_uniform_buffer(grp, "shadowTexture", &sldata->shadow_pool);
                DRW_shgroup_uniform_float(grp, "volume_light_clamp", &volumetrics->light_clamp, 1);
index b555761d5dfd2799c0c6e1c6b773f0c2ea227afd..f5d3898d1bc4a5edb2494be8bff1ffa218ffc3db 100644 (file)
@@ -308,6 +308,9 @@ static char *eevee_get_defines(int options)
        if ((options & VAR_MAT_ESM) != 0) {
                BLI_dynstr_appendf(ds, "#define SHADOW_ESM\n");
        }
+       if (((options & VAR_MAT_VOLUME) != 0) && ((options & VAR_MAT_BLEND) != 0)) {
+               BLI_dynstr_appendf(ds, "#define USE_ALPHA_BLEND_VOLUMETRICS\n");
+       }
 
        str = BLI_dynstr_get_cstring(ds);
        BLI_dynstr_free(ds);
@@ -334,7 +337,7 @@ static char *eevee_get_volume_defines(int UNUSED(options))
  **/
 static void add_standard_uniforms(
         DRWShadingGroup *shgrp, EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata,
-        int *ssr_id, float *refract_depth, bool use_ssrefraction)
+        int *ssr_id, float *refract_depth, bool use_ssrefraction, bool use_alpha_blend)
 {
        if (ssr_id == NULL || !vedata->stl->g_data->valid_double_buffer) {
                static int no_ssr = -1.0f;
@@ -364,15 +367,18 @@ static void add_standard_uniforms(
        DRW_shgroup_uniform_buffer(shgrp, "maxzBuffer", &vedata->txl->maxzbuffer);
        DRW_shgroup_uniform_vec2(shgrp, "mipRatio[0]", (float *)vedata->stl->g_data->mip_ratio, 10);
        DRW_shgroup_uniform_vec4(shgrp, "ssrParameters", &vedata->stl->effects->ssr_quality, 1);
+
        if (refract_depth != NULL) {
                DRW_shgroup_uniform_float(shgrp, "refractionDepth", refract_depth, 1);
        }
+
        if (use_ssrefraction) {
                DRW_shgroup_uniform_buffer(shgrp, "colorBuffer", &vedata->txl->refract_color);
                DRW_shgroup_uniform_float(shgrp, "borderFadeFactor", &vedata->stl->effects->ssr_border_fac, 1);
                DRW_shgroup_uniform_float(shgrp, "maxRoughness", &vedata->stl->effects->ssr_max_roughness, 1);
                DRW_shgroup_uniform_int(shgrp, "rayCount", &vedata->stl->effects->ssr_ray_count, 1);
        }
+
        if (vedata->stl->effects->use_ao) {
                DRW_shgroup_uniform_buffer(shgrp, "horizonBuffer", &vedata->txl->gtao_horizons);
                DRW_shgroup_uniform_ivec2(shgrp, "aoHorizonTexSize", (int *)vedata->stl->effects->ao_texsize, 1);
@@ -381,6 +387,14 @@ static void add_standard_uniforms(
                /* Use shadow_pool as fallback to avoid sampling problem on certain platform, see: T52593 */
                DRW_shgroup_uniform_buffer(shgrp, "horizonBuffer", &sldata->shadow_pool);
        }
+
+       if (vedata->stl->effects->use_volumetrics && use_alpha_blend) {
+               /* Do not use history buffers as they already have been swapped */
+               DRW_shgroup_uniform_buffer(shgrp, "inScattering", &vedata->txl->volume_scatter);
+               DRW_shgroup_uniform_buffer(shgrp, "inTransmittance", &vedata->txl->volume_transmittance);
+               DRW_shgroup_uniform_vec2(shgrp, "volume_uv_ratio", (float *)sldata->volumetrics->volume_coord_scale, 1);
+               DRW_shgroup_uniform_vec3(shgrp, "volume_param", (float *)sldata->volumetrics->depth_param, 1);
+       }
 }
 
 static void create_default_shader(int options)
@@ -474,6 +488,7 @@ void EEVEE_materials_init(EEVEE_StorageList *stl)
                BLI_dynstr_append(ds_frag, datatoc_bsdf_direct_lib_glsl);
                BLI_dynstr_append(ds_frag, datatoc_lamps_lib_glsl);
                BLI_dynstr_append(ds_frag, datatoc_lit_surface_frag_glsl);
+               BLI_dynstr_append(ds_frag, datatoc_volumetric_lib_glsl);
                e_data.frag_shader_lib = BLI_dynstr_get_cstring(ds_frag);
                BLI_dynstr_free(ds_frag);
 
@@ -611,7 +626,7 @@ struct GPUMaterial *EEVEE_material_world_volume_get(struct Scene *scene, World *
 }
 
 struct GPUMaterial *EEVEE_material_mesh_get(
-        struct Scene *scene, Material *ma,
+        struct Scene *scene, Material *ma, EEVEE_Data *vedata,
         bool use_blend, bool use_multiply, bool use_refract, int shadow_method)
 {
        const void *engine = &DRW_engine_viewport_eevee_type;
@@ -620,6 +635,7 @@ struct GPUMaterial *EEVEE_material_mesh_get(
        if (use_blend) options |= VAR_MAT_BLEND;
        if (use_multiply) options |= VAR_MAT_MULT;
        if (use_refract) options |= VAR_MAT_REFRACT;
+       if (vedata->stl->effects->use_volumetrics && use_blend) options |= VAR_MAT_VOLUME;
 
        options |= eevee_material_shadow_option(shadow_method);
 
@@ -722,6 +738,7 @@ static struct DRWShadingGroup *EEVEE_default_shading_group_create(
        if (is_hair) options |= VAR_MAT_HAIR;
        if (is_flat_normal) options |= VAR_MAT_FLAT;
        if (use_blend) options |= VAR_MAT_BLEND;
+       if (vedata->stl->effects->use_volumetrics && use_blend) options |= VAR_MAT_VOLUME;
 
        options |= eevee_material_shadow_option(shadow_method);
 
@@ -730,7 +747,7 @@ static struct DRWShadingGroup *EEVEE_default_shading_group_create(
        }
 
        DRWShadingGroup *shgrp = DRW_shgroup_create(e_data.default_lit[options], pass);
-       add_standard_uniforms(shgrp, sldata, vedata, &ssr_id, NULL, false);
+       add_standard_uniforms(shgrp, sldata, vedata, &ssr_id, NULL, false, use_blend);
 
        return shgrp;
 }
@@ -760,7 +777,7 @@ static struct DRWShadingGroup *EEVEE_default_shading_group_get(
                vedata->psl->default_pass[options] = DRW_pass_create("Default Lit Pass", state);
 
                DRWShadingGroup *shgrp = DRW_shgroup_create(e_data.default_lit[options], vedata->psl->default_pass[options]);
-               add_standard_uniforms(shgrp, sldata, vedata, &ssr_id, NULL, false);
+               add_standard_uniforms(shgrp, sldata, vedata, &ssr_id, NULL, false, false);
        }
 
        return DRW_shgroup_create(e_data.default_lit[options], vedata->psl->default_pass[options]);
@@ -780,6 +797,8 @@ void EEVEE_materials_cache_init(EEVEE_Data *vedata)
                stl->effects->use_bent_normals = BKE_collection_engine_property_value_get_bool(props, "gtao_use_bent_normals");
                /* SSR switch */
                stl->effects->use_ssr = BKE_collection_engine_property_value_get_bool(props, "ssr_enable");
+               /* Volumetrics */
+               stl->effects->use_volumetrics = BKE_collection_engine_property_value_get_bool(props, "volumetric_enable");
        }
 
        /* Create Material Ghash */
@@ -929,7 +948,7 @@ static void material_opaque(
 
                /* This will have been created already, just perform a lookup. */
                *gpumat = (use_gpumat) ? EEVEE_material_mesh_get(
-                       scene, ma, false, false, use_refract, linfo->shadow_method) : NULL;
+                       scene, ma, vedata, false, false, use_refract, linfo->shadow_method) : NULL;
                *gpumat_depth = (use_gpumat) ? EEVEE_material_mesh_depth_get(
                        scene, ma, (ma->blend_method == MA_BM_HASHED), false) : NULL;
                return;
@@ -937,14 +956,14 @@ static void material_opaque(
 
        if (use_gpumat) {
                /* Shading */
-               *gpumat = EEVEE_material_mesh_get(scene, ma, false, false, use_refract, linfo->shadow_method);
+               *gpumat = EEVEE_material_mesh_get(scene, ma, vedata, false, false, use_refract, linfo->shadow_method);
 
                *shgrp = DRW_shgroup_material_create(*gpumat, use_refract ? psl->refract_pass : psl->material_pass);
                if (*shgrp) {
                        static int no_ssr = -1;
                        static int first_ssr = 0;
                        int *ssr_id = (stl->effects->use_ssr && !use_refract) ? &first_ssr : &no_ssr;
-                       add_standard_uniforms(*shgrp, sldata, vedata, ssr_id, &ma->refract_depth, use_refract);
+                       add_standard_uniforms(*shgrp, sldata, vedata, ssr_id, &ma->refract_depth, use_refract, false);
                }
                else {
                        /* Shader failed : pink color */
@@ -971,7 +990,7 @@ static void material_opaque(
                        }
 
                        if (*shgrp_depth != NULL) {
-                               add_standard_uniforms(*shgrp_depth, sldata, vedata, NULL, NULL, false);
+                               add_standard_uniforms(*shgrp_depth, sldata, vedata, NULL, NULL, false, false);
 
                                if (ma->blend_method == MA_BM_CLIP) {
                                        DRW_shgroup_uniform_float(*shgrp_depth, "alphaThreshold", &ma->alpha_threshold, 1);
@@ -1028,12 +1047,13 @@ static void material_transparent(
 
        if (ma->use_nodes && ma->nodetree) {
                /* Shading */
-               *gpumat = EEVEE_material_mesh_get(scene, ma, true, (ma->blend_method == MA_BM_MULTIPLY), use_refract, linfo->shadow_method);
+               *gpumat = EEVEE_material_mesh_get(scene, ma, vedata, true, (ma->blend_method == MA_BM_MULTIPLY), use_refract, linfo->shadow_method);
 
                *shgrp = DRW_shgroup_material_create(*gpumat, psl->transparent_pass);
                if (*shgrp) {
                        static int ssr_id = -1; /* TODO transparent SSR */
-                       add_standard_uniforms(*shgrp, sldata, vedata, &ssr_id, &ma->refract_depth, use_refract);
+                       bool use_blend = (ma->blend_method & MA_BM_BLEND) != 0;
+                       add_standard_uniforms(*shgrp, sldata, vedata, &ssr_id, &ma->refract_depth, use_refract, use_blend);
                }
                else {
                        /* Shader failed : pink color */
@@ -1266,7 +1286,7 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_SceneLayerData *sl
 
                                                                        shgrp = DRW_shgroup_material_create(gpumat, psl->material_pass);
                                                                        if (shgrp) {
-                                                                               add_standard_uniforms(shgrp, sldata, vedata, NULL, NULL, false);
+                                                                               add_standard_uniforms(shgrp, sldata, vedata, NULL, NULL, false, false);
 
                                                                                BLI_ghash_insert(material_hash, ma, shgrp);
 
index 4919189ff910f1d4acbb68d5b97c08923ace9e4a..15cc25788cab7485d0920a1d5e1478e41b6da80e 100644 (file)
@@ -93,6 +93,7 @@ enum {
        VAR_MAT_MULT     = (1 << 10),
        VAR_MAT_SHADOW   = (1 << 11),
        VAR_MAT_REFRACT  = (1 << 12),
+       VAR_MAT_VOLUME   = (1 << 13),
 };
 
 /* Shadow Technique */
@@ -395,6 +396,9 @@ enum {
 typedef struct EEVEE_EffectsInfo {
        int enabled_effects;
 
+       /* Volumetrics */
+       bool use_volumetrics;
+
        /* SSR */
        bool use_ssr;
        bool reflection_trace_full;
@@ -593,7 +597,8 @@ struct GPUMaterial *EEVEE_material_world_lightprobe_get(struct Scene *scene, str
 struct GPUMaterial *EEVEE_material_world_background_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_get(
-        struct Scene *scene, Material *ma, bool use_blend, bool use_multiply, bool use_refract, int shadow_method);
+        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_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);
index c9aa6705b676144667828253d3b670f56a8a676d..eb0b93d5ac4407b25ab67a2732389717cc83cb61 100644 (file)
@@ -631,11 +631,24 @@ layout(location = 2) out vec4 ssrData;
 
 Closure nodetree_exec(void); /* Prototype */
 
+#if defined(USE_ALPHA_BLEND_VOLUMETRICS)
+/* Prototype because this file is included before volumetric_lib.glsl */
+vec4 volumetric_resolve(vec4 scene_color, vec2 frag_uvs, float frag_depth);
+#endif
+
 #define NODETREE_EXEC
 void main()
 {
        Closure cl = nodetree_exec();
+
+#if defined(USE_ALPHA_BLEND_VOLUMETRICS)
+       /* XXX fragile, better use real viewport resolution */
+       vec2 uvs = gl_FragCoord.xy / vec2(2 * textureSize(maxzBuffer, 0).xy);
+       fragColor = volumetric_resolve(vec4(cl.radiance, cl.opacity), uvs, gl_FragCoord.z);
+#else
        fragColor = vec4(cl.radiance, cl.opacity);
+#endif
+
        ssrNormals = cl.ssr_normal.xyyy;
        ssrData = cl.ssr_data;
 }
index fd2630f54f9a5bd7913a17013bb5ff75c460fa0c..c13938e141d1bbac2050a27b7352b66a2e77a140 100644 (file)
@@ -132,3 +132,16 @@ vec3 irradiance_volumetric(vec3 wpos)
        return irradiance;
 }
 #endif
+
+uniform sampler3D inScattering;
+uniform sampler3D inTransmittance;
+
+vec4 volumetric_resolve(vec4 scene_color, vec2 frag_uvs, float frag_depth)
+{
+       vec3 volume_cos = ndc_to_volume(vec3(frag_uvs, frag_depth));
+
+       vec3 scattering = texture(inScattering, volume_cos).rgb;
+       vec3 transmittance = texture(inTransmittance, volume_cos).rgb;
+
+       return vec4(scene_color.rgb * transmittance + scattering, scene_color.a);
+}
index 3e678bbc83fb39fb2d5a0dc837a04d3e3f32420b..0115b2cb99eee9b2741c4387b3a8cb25d31b6e75 100644 (file)
@@ -6,9 +6,6 @@
  * Note that we do the blending ourself instead of relying
  * on hardware blending which would require 2 pass. */
 
-uniform sampler3D inScattering;
-uniform sampler3D inTransmittance;
-
 uniform sampler2D inSceneColor;
 uniform sampler2D inSceneDepth;
 
@@ -17,11 +14,8 @@ out vec4 FragColor;
 void main()
 {
        vec2 uvs = gl_FragCoord.xy / vec2(textureSize(inSceneDepth, 0));
-       vec3 volume_cos = ndc_to_volume(vec3(uvs, texture(inSceneDepth, uvs).r));
-
-       vec3 scene_color = texture(inSceneColor, uvs).rgb;
-       vec3 scattering = texture(inScattering, volume_cos).rgb;
-       vec3 transmittance = texture(inTransmittance, volume_cos).rgb;
+       vec4 scene_color = texture(inSceneColor, uvs);
+       float scene_depth = texture(inSceneDepth, uvs).r;
 
-       FragColor = vec4(scene_color * transmittance + scattering, 1.0);
+       FragColor = volumetric_resolve(scene_color, uvs, scene_depth);
 }