diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2017-07-10 12:41:33 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2017-07-11 13:39:35 +0300 |
commit | d35c24f87b133202abf85f8d0f2512a20caf0cda (patch) | |
tree | 6dd9b3f2b4204db20c91ca19c5c757bde2c34928 | |
parent | 55022884ba690bc35b906053e933b9d4097356c1 (diff) |
Eevee: Transparency: Add support for blend ADD and MULTIPLY.
This introduces a new transparency pass.
It bypass the radial distance encoding in alpha for the transparent shaders.
7 files changed, 152 insertions, 17 deletions
diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c index 3475bbb7fad..c8f85d3ae87 100644 --- a/source/blender/draw/engines/eevee/eevee_engine.c +++ b/source/blender/draw/engines/eevee/eevee_engine.c @@ -81,7 +81,6 @@ static void EEVEE_cache_init(void *vedata) static void EEVEE_cache_populate(void *vedata, Object *ob) { - EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl; EEVEE_SceneLayerData *sldata = EEVEE_scene_layer_data_get(); const DRWContextState *draw_ctx = DRW_context_state_get(); @@ -161,6 +160,9 @@ static void EEVEE_draw_scene(void *vedata) /* Volumetrics */ EEVEE_effects_do_volumetrics(sldata, vedata); + /* Transparent */ + DRW_draw_pass(psl->transparent_pass); + /* Post Process */ EEVEE_draw_effects(vedata); } diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index b85745732e1..929e0932144 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -206,6 +206,12 @@ static char *eevee_get_defines(int options) if ((options & VAR_MAT_HASH) != 0) { BLI_dynstr_appendf(ds, "#define USE_ALPHA_HASH\n"); } + if ((options & VAR_MAT_BLEND) != 0) { + BLI_dynstr_appendf(ds, "#define USE_ALPHA_BLEND\n"); + } + if ((options & VAR_MAT_MULT) != 0) { + BLI_dynstr_appendf(ds, "#define USE_MULTIPLY\n"); + } str = BLI_dynstr_get_cstring(ds); BLI_dynstr_free(ds); @@ -470,13 +476,15 @@ struct GPUMaterial *EEVEE_material_world_volume_get( struct GPUMaterial *EEVEE_material_mesh_get( struct Scene *scene, Material *ma, - bool use_ao, bool use_bent_normals) + bool use_ao, bool use_bent_normals, bool use_blend, bool use_multiply) { const void *engine = &DRW_engine_viewport_eevee_type; int options = VAR_MAT_MESH; if (use_ao) options |= VAR_MAT_AO; if (use_bent_normals) options |= VAR_MAT_BENT; + if (use_blend) options |= VAR_MAT_BLEND; + if (use_multiply) options |= VAR_MAT_MULT; GPUMaterial *mat = GPU_material_from_nodetree_find(&ma->gpumaterial, engine, options); if (mat) { @@ -558,6 +566,34 @@ struct GPUMaterial *EEVEE_material_hair_get( return mat; } +/** + * Create a default shading group inside the given pass. + **/ +static struct DRWShadingGroup *EEVEE_default_shading_group_create( + EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata, DRWPass *pass, + bool is_hair, bool is_flat_normal, bool use_ao, bool use_bent_normals, bool use_blend) +{ + int options = VAR_MAT_MESH; + + if (is_hair) options |= VAR_MAT_HAIR; + if (use_ao) options |= VAR_MAT_AO; + if (use_bent_normals) options |= VAR_MAT_BENT; + if (is_flat_normal) options |= VAR_MAT_FLAT; + if (use_blend) options |= VAR_MAT_BLEND; + + if (e_data.default_lit[options] == NULL) { + create_default_shader(options); + } + + DRWShadingGroup *shgrp = DRW_shgroup_create(e_data.default_lit[options], pass); + add_standard_uniforms(shgrp, sldata, vedata); + + return shgrp; +} + +/** + * Create a default shading group inside the default pass without standard uniforms. + **/ static struct DRWShadingGroup *EEVEE_default_shading_group_get( EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata, bool is_hair, bool is_flat_normal, bool use_ao, bool use_bent_normals) @@ -666,6 +702,11 @@ void EEVEE_materials_cache_init(EEVEE_Data *vedata) DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_CLIP_PLANES | DRW_STATE_WIRE; psl->material_pass = DRW_pass_create("Material Shader Pass", state); } + + { + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS | DRW_STATE_CLIP_PLANES | DRW_STATE_WIRE; + psl->transparent_pass = DRW_pass_create("Material Transparent Pass", state); + } } #define ADD_SHGROUP_CALL(shgrp, ob, geom) do { \ @@ -677,6 +718,12 @@ void EEVEE_materials_cache_init(EEVEE_Data *vedata) } \ } while (0) +#define ADD_SHGROUP_CALL_SAFE(shgrp, ob, geom) do { \ + if (shgrp) { \ + ADD_SHGROUP_CALL(shgrp, ob, geom); \ + } \ +} while (0) + typedef struct EeveeMaterialShadingGroups{ struct DRWShadingGroup *shading_grp; struct DRWShadingGroup *depth_grp; @@ -709,16 +756,16 @@ static void material_opaque( /* This will have been created already, just perform a lookup. */ *gpumat = (use_gpumat) ? EEVEE_material_mesh_get( - draw_ctx->scene, ma, stl->effects->use_ao, stl->effects->use_bent_normals) : NULL; + scene, ma, stl->effects->use_ao, stl->effects->use_bent_normals, false, false) : NULL; *gpumat_depth = (use_gpumat) ? EEVEE_material_mesh_depth_get( - draw_ctx->scene, ma, (ma->blend_method == MA_BM_HASHED)) : NULL; + scene, ma, (ma->blend_method == MA_BM_HASHED)) : NULL; return; } if (use_gpumat) { /* Shading */ *gpumat = EEVEE_material_mesh_get(scene, ma, - stl->effects->use_ao, stl->effects->use_bent_normals); + stl->effects->use_ao, stl->effects->use_bent_normals, false, false); *shgrp = DRW_shgroup_material_create(*gpumat, psl->material_pass); if (*shgrp) { @@ -774,7 +821,70 @@ static void material_opaque( BLI_ghash_insert(material_hash, ma, emsg); } -// void EEVEE_materials_cache_blended(); +static void material_transparent( + Material *ma, EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata, + bool do_cull, bool use_flat_nor, struct GPUMaterial **gpumat, struct DRWShadingGroup **shgrp) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + Scene *scene = draw_ctx->scene; + EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl; + EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl; + + float *color_p = &ma->r; + float *metal_p = &ma->ray_mirror; + float *spec_p = &ma->spec; + float *rough_p = &ma->gloss_mir; + + if (ma->use_nodes && ma->nodetree) { + /* Shading */ + *gpumat = EEVEE_material_mesh_get(scene, ma, + stl->effects->use_ao, stl->effects->use_bent_normals, + true, (ma->blend_method == MA_BM_MULTIPLY)); + + *shgrp = DRW_shgroup_material_create(*gpumat, psl->transparent_pass); + if (*shgrp) { + add_standard_uniforms(*shgrp, sldata, vedata); + } + else { + /* Shader failed : pink color */ + static float col[3] = {1.0f, 0.0f, 1.0f}; + static float half = 0.5f; + + color_p = col; + metal_p = spec_p = rough_p = ½ + } + } + + /* Fallback to default shader */ + if (*shgrp == NULL) { + *shgrp = EEVEE_default_shading_group_create( + sldata, vedata, psl->transparent_pass, + false, use_flat_nor, stl->effects->use_ao, stl->effects->use_bent_normals, true); + DRW_shgroup_uniform_vec3(*shgrp, "basecol", color_p, 1); + DRW_shgroup_uniform_float(*shgrp, "metallic", metal_p, 1); + DRW_shgroup_uniform_float(*shgrp, "specular", spec_p, 1); + DRW_shgroup_uniform_float(*shgrp, "roughness", rough_p, 1); + } + + DRWState cur_state = (do_cull) ? DRW_STATE_CULL_BACK : 0; + DRWState all_state = DRW_STATE_CULL_BACK | DRW_STATE_BLEND | DRW_STATE_ADDITIVE | DRW_STATE_MULTIPLY; + + switch (ma->blend_method) { + case MA_BM_ADD: + cur_state |= DRW_STATE_ADDITIVE; + break; + case MA_BM_MULTIPLY: + cur_state |= DRW_STATE_MULTIPLY; + break; + default: + BLI_assert(0); + break; + } + + /* Disable other blend modes and use the one we want. */ + DRW_shgroup_state_disable(*shgrp, all_state); + DRW_shgroup_state_enable(*shgrp, cur_state); +} void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_SceneLayerData *sldata, Object *ob) { @@ -830,7 +940,8 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_SceneLayerData *sl break; case MA_BM_ADD: case MA_BM_MULTIPLY: - // material_transparent(ma, material_hash, &shgrp); + material_transparent(ma, sldata, vedata, do_cull, use_flat_nor, + &gpumat_array[i], &shgrp_array[i]); break; } } @@ -843,8 +954,8 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_SceneLayerData *sl ADD_SHGROUP_CALL(shgrp_array[i], ob, mat_geom[i]); /* Depth Prepass */ - ADD_SHGROUP_CALL(shgrp_depth_array[i], ob, mat_geom[i]); - ADD_SHGROUP_CALL(shgrp_depth_clip_array[i], ob, mat_geom[i]); + ADD_SHGROUP_CALL_SAFE(shgrp_depth_array[i], ob, mat_geom[i]); + ADD_SHGROUP_CALL_SAFE(shgrp_depth_clip_array[i], ob, mat_geom[i]); /* Shadow Pass */ EEVEE_lights_cache_shcaster_add(sldata, psl, mat_geom[i], ob->obmat); diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index 92a4df27718..5e0d3ea177b 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -66,14 +66,16 @@ enum { VAR_MAT_AO = (1 << 3), VAR_MAT_FLAT = (1 << 4), VAR_MAT_BENT = (1 << 5), + VAR_MAT_BLEND = (1 << 6), /* Max number of variation */ /* IMPORTANT : Leave it last and set * it's value accordingly. */ - VAR_MAT_MAX = (1 << 6), + VAR_MAT_MAX = (1 << 7), /* These are options that are not counted in VAR_MAT_MAX * because they are not cumulative with the others above. */ - VAR_MAT_CLIP = (1 << 7), - VAR_MAT_HASH = (1 << 8), + VAR_MAT_CLIP = (1 << 8), + VAR_MAT_HASH = (1 << 9), + VAR_MAT_MULT = (1 << 10), }; typedef struct EEVEE_PassList { @@ -113,6 +115,7 @@ typedef struct EEVEE_PassList { struct DRWPass *depth_pass_clip_cull; struct DRWPass *default_pass[VAR_MAT_MAX]; struct DRWPass *material_pass; + struct DRWPass *transparent_pass; struct DRWPass *background_pass; } EEVEE_PassList; @@ -448,7 +451,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, bool use_lights, bool use_volume_shadows, bool is_homogeneous, bool use_color_transmit); -struct GPUMaterial *EEVEE_material_mesh_get(struct Scene *scene, Material *ma, bool use_ao, bool use_bent_normals); +struct GPUMaterial *EEVEE_material_mesh_get( + struct Scene *scene, Material *ma, bool use_ao, bool use_bent_normals, bool use_blend, bool use_multiply); struct GPUMaterial *EEVEE_material_mesh_depth_get(struct Scene *scene, Material *ma, bool use_hashed_alpha); struct GPUMaterial *EEVEE_material_hair_get(struct Scene *scene, Material *ma, bool use_ao, bool use_bent_normals); void EEVEE_materials_free(void); 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 edf13b911dc..5aac853da00 100644 --- a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl @@ -76,6 +76,19 @@ Closure closure_add(Closure cl1, Closure cl2) Closure nodetree_exec(void); /* Prototype */ +/* TODO find a better place */ +#ifdef USE_MULTIPLY + +out vec4 fragColor; + +#define NODETREE_EXEC +void main() +{ + Closure cl = nodetree_exec(); + fragColor = vec4(mix(vec3(1.0), cl.radiance, cl.opacity), 1.0); +} + +#endif struct LightData { vec4 position_influence; /* w : InfluenceRadius */ diff --git a/source/blender/draw/engines/eevee/shaders/default_frag.glsl b/source/blender/draw/engines/eevee/shaders/default_frag.glsl index 004db999149..b50eb481f94 100644 --- a/source/blender/draw/engines/eevee/shaders/default_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/default_frag.glsl @@ -11,5 +11,10 @@ void main() vec3 dielectric = vec3(0.034) * specular * 2.0; vec3 diffuse = mix(basecol, vec3(0.0), metallic); vec3 f0 = mix(dielectric, basecol, metallic); - FragColor = vec4(eevee_surface_lit((gl_FrontFacing) ? worldNormal : -worldNormal, diffuse, f0, roughness, 1.0), length(viewPosition)); + vec3 radiance = eevee_surface_lit((gl_FrontFacing) ? worldNormal : -worldNormal, diffuse, f0, roughness, 1.0); +#if defined(USE_ALPHA_BLEND) + FragColor = vec4(radiance, 1.0); +#else + FragColor = vec4(radiance, length(viewPosition)); +#endif } diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl index 3235dad8d04..dbd3a941e57 100644 --- a/source/blender/gpu/shaders/gpu_shader_material.glsl +++ b/source/blender/gpu/shaders/gpu_shader_material.glsl @@ -4031,7 +4031,7 @@ void node_eevee_specular( void node_output_eevee_material(Closure surface, out Closure result) { -#if defined(USE_ALPHA_HASH) || defined(USE_ALPHA_CLIP) +#if defined(USE_ALPHA_HASH) || defined(USE_ALPHA_CLIP) || defined(USE_ALPHA_BLEND) result = surface; #else result = Closure(surface.radiance, length(viewPosition)); diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c index a3c1ae7378e..27b9778f280 100644 --- a/source/blender/makesrna/intern/rna_material.c +++ b/source/blender/makesrna/intern/rna_material.c @@ -1807,8 +1807,8 @@ void RNA_def_material(BlenderRNA *brna) static EnumPropertyItem prop_eevee_blend_items[] = { {MA_BM_SOLID, "OPAQUE", 0, "Opaque", "Render surface without transparency"}, - // {MA_BM_ADD, "ADD", 0, "Additive", "Render surface and blend the result with additive blending"}, - // {MA_BM_MULTIPLY, "MULTIPLY", 0, "Multiply", "Render surface and blend the result with multiplicative blending"}, + {MA_BM_ADD, "ADD", 0, "Additive", "Render surface and blend the result with additive blending"}, + {MA_BM_MULTIPLY, "MULTIPLY", 0, "Multiply", "Render surface and blend the result with multiplicative blending"}, {MA_BM_CLIP, "CLIP", 0, "Alpha Clip", "Use the alpha threshold to clip the visibility (binary visibility)"}, {MA_BM_HASHED, "HASHED", 0, "Alpha Hashed", "Use noise to dither the binary visibility (works well with multi-samples)"}, {0, NULL, 0, NULL, NULL} |