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.
This commit is contained in:
Clément Foucault 2017-07-10 11:41:33 +02:00
parent 55022884ba
commit d35c24f87b
7 changed files with 152 additions and 17 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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