diff options
Diffstat (limited to 'source/blender/draw/engines/eevee/eevee_shaders.c')
-rw-r--r-- | source/blender/draw/engines/eevee/eevee_shaders.c | 488 |
1 files changed, 483 insertions, 5 deletions
diff --git a/source/blender/draw/engines/eevee/eevee_shaders.c b/source/blender/draw/engines/eevee/eevee_shaders.c index 50b7c5c5f97..4d25f62a317 100644 --- a/source/blender/draw/engines/eevee/eevee_shaders.c +++ b/source/blender/draw/engines/eevee/eevee_shaders.c @@ -22,12 +22,20 @@ #include "DRW_render.h" +#include "BKE_lib_id.h" +#include "BKE_node.h" + +#include "BLI_dynstr.h" #include "BLI_string_utils.h" #include "MEM_guardedalloc.h" +#include "GPU_material.h" #include "GPU_shader.h" +#include "NOD_shader.h" + +#include "eevee_engine.h" #include "eevee_private.h" static const char *filter_defines = "#define HAMMERSLEY_SIZE " STRINGIFY(HAMMERSLEY_SIZE) "\n" @@ -61,6 +69,38 @@ static struct { struct GPUShader *taa_resolve_sh; struct GPUShader *taa_resolve_reproject_sh; + /* General purpose Shaders. */ + struct GPUShader *default_background; + struct GPUShader *update_noise_sh; + + /* Shader strings */ + char *frag_shader_lib; + char *vert_shader_str; + char *vert_shadow_shader_str; + char *vert_background_shader_str; + char *vert_volume_shader_str; + char *geom_volume_shader_str; + char *volume_shader_lib; + + /* LookDev Materials */ + Material *glossy_mat; + Material *diffuse_mat; + + Material *error_mat; + + /* Default Material */ + struct { + bNodeTree *ntree; + bNodeSocketValueRGBA *color_socket; + bNodeSocketValueFloat *metallic_socket; + bNodeSocketValueFloat *roughness_socket; + bNodeSocketValueFloat *specular_socket; + } surface; + + struct { + bNodeTree *ntree; + bNodeSocketValueRGBA *color_socket; + } world; } e_data = {NULL}; /* Engine data */ extern char datatoc_bsdf_common_lib_glsl[]; @@ -68,27 +108,42 @@ extern char datatoc_bsdf_sampling_lib_glsl[]; extern char datatoc_common_uniforms_lib_glsl[]; extern char datatoc_common_view_lib_glsl[]; +extern char datatoc_ambient_occlusion_lib_glsl[]; extern char datatoc_background_vert_glsl[]; +extern char datatoc_common_hair_lib_glsl[]; +extern char datatoc_cubemap_lib_glsl[]; extern char datatoc_default_world_frag_glsl[]; -extern char datatoc_lightprobe_geom_glsl[]; -extern char datatoc_lightprobe_vert_glsl[]; +extern char datatoc_irradiance_lib_glsl[]; extern char datatoc_lightprobe_cube_display_frag_glsl[]; extern char datatoc_lightprobe_cube_display_vert_glsl[]; extern char datatoc_lightprobe_filter_diffuse_frag_glsl[]; extern char datatoc_lightprobe_filter_glossy_frag_glsl[]; extern char datatoc_lightprobe_filter_visibility_frag_glsl[]; +extern char datatoc_lightprobe_geom_glsl[]; extern char datatoc_lightprobe_grid_display_frag_glsl[]; extern char datatoc_lightprobe_grid_display_vert_glsl[]; extern char datatoc_lightprobe_grid_fill_frag_glsl[]; +extern char datatoc_lightprobe_lib_glsl[]; extern char datatoc_lightprobe_planar_display_frag_glsl[]; extern char datatoc_lightprobe_planar_display_vert_glsl[]; extern char datatoc_lightprobe_planar_downsample_frag_glsl[]; extern char datatoc_lightprobe_planar_downsample_geom_glsl[]; extern char datatoc_lightprobe_planar_downsample_vert_glsl[]; -extern char datatoc_irradiance_lib_glsl[]; -extern char datatoc_lightprobe_lib_glsl[]; +extern char datatoc_lightprobe_vert_glsl[]; +extern char datatoc_lights_lib_glsl[]; +extern char datatoc_lit_surface_frag_glsl[]; +extern char datatoc_lit_surface_vert_glsl[]; +extern char datatoc_ltc_lib_glsl[]; extern char datatoc_octahedron_lib_glsl[]; -extern char datatoc_cubemap_lib_glsl[]; +extern char datatoc_prepass_frag_glsl[]; +extern char datatoc_raytrace_lib_glsl[]; +extern char datatoc_shadow_vert_glsl[]; +extern char datatoc_ssr_lib_glsl[]; +extern char datatoc_update_noise_frag_glsl[]; +extern char datatoc_volumetric_frag_glsl[]; +extern char datatoc_volumetric_geom_glsl[]; +extern char datatoc_volumetric_lib_glsl[]; +extern char datatoc_volumetric_vert_glsl[]; /* Velocity Resolve */ extern char datatoc_effect_velocity_resolve_frag_glsl[]; @@ -150,6 +205,64 @@ void EEVEE_shaders_lightprobe_shaders_init(void) NULL); } +void EEVEE_shaders_material_shaders_init(void) +{ + e_data.frag_shader_lib = BLI_string_joinN(datatoc_common_view_lib_glsl, + datatoc_common_uniforms_lib_glsl, + datatoc_bsdf_common_lib_glsl, + datatoc_bsdf_sampling_lib_glsl, + datatoc_ambient_occlusion_lib_glsl, + datatoc_raytrace_lib_glsl, + datatoc_ssr_lib_glsl, + datatoc_octahedron_lib_glsl, + datatoc_cubemap_lib_glsl, + datatoc_irradiance_lib_glsl, + datatoc_lightprobe_lib_glsl, + datatoc_ltc_lib_glsl, + datatoc_lights_lib_glsl, + /* Add one for each Closure */ + datatoc_lit_surface_frag_glsl, + datatoc_lit_surface_frag_glsl, + datatoc_lit_surface_frag_glsl, + datatoc_lit_surface_frag_glsl, + datatoc_lit_surface_frag_glsl, + datatoc_lit_surface_frag_glsl, + datatoc_lit_surface_frag_glsl, + datatoc_lit_surface_frag_glsl, + datatoc_lit_surface_frag_glsl, + datatoc_lit_surface_frag_glsl, + datatoc_lit_surface_frag_glsl, + datatoc_volumetric_lib_glsl); + + e_data.volume_shader_lib = BLI_string_joinN(datatoc_common_view_lib_glsl, + datatoc_common_uniforms_lib_glsl, + datatoc_bsdf_common_lib_glsl, + datatoc_ambient_occlusion_lib_glsl, + datatoc_octahedron_lib_glsl, + datatoc_cubemap_lib_glsl, + datatoc_irradiance_lib_glsl, + datatoc_lightprobe_lib_glsl, + datatoc_ltc_lib_glsl, + datatoc_lights_lib_glsl, + datatoc_volumetric_lib_glsl, + datatoc_volumetric_frag_glsl); + + e_data.vert_shader_str = BLI_string_joinN( + datatoc_common_view_lib_glsl, datatoc_common_hair_lib_glsl, datatoc_lit_surface_vert_glsl); + + e_data.vert_shadow_shader_str = BLI_string_joinN( + datatoc_common_view_lib_glsl, datatoc_common_hair_lib_glsl, datatoc_shadow_vert_glsl); + + e_data.vert_background_shader_str = BLI_string_joinN(datatoc_common_view_lib_glsl, + datatoc_background_vert_glsl); + + e_data.vert_volume_shader_str = BLI_string_joinN(datatoc_common_view_lib_glsl, + datatoc_volumetric_vert_glsl); + + e_data.geom_volume_shader_str = BLI_string_joinN(datatoc_common_view_lib_glsl, + datatoc_volumetric_geom_glsl); +} + GPUShader *EEVEE_shaders_probe_filter_glossy_sh_get(void) { return e_data.probe_filter_glossy_sh; @@ -292,6 +405,26 @@ GPUShader *EEVEE_shaders_velocity_resolve_sh_get(void) return e_data.velocity_resolve_sh; } +GPUShader *EEVEE_shaders_default_background_sh_get(void) +{ + if (e_data.default_background == NULL) { + e_data.default_background = DRW_shader_create_with_lib(datatoc_background_vert_glsl, + NULL, + datatoc_default_world_frag_glsl, + datatoc_common_view_lib_glsl, + NULL); + } + return e_data.default_background; +} + +GPUShader *EEVEE_shaders_update_noise_sh_get(void) +{ + if (e_data.update_noise_sh == NULL) { + e_data.update_noise_sh = DRW_shader_create_fullscreen(datatoc_update_noise_frag_glsl, NULL); + } + return e_data.update_noise_sh; +} + GPUShader *EEVEE_shaders_taa_resolve_sh_get(EEVEE_EffectsFlag enabled_effects) { GPUShader **sh; @@ -316,8 +449,330 @@ GPUShader *EEVEE_shaders_taa_resolve_sh_get(EEVEE_EffectsFlag enabled_effects) return *sh; } +Material *EEVEE_material_default_diffuse_get(void) +{ + if (!e_data.diffuse_mat) { + Material *ma = BKE_id_new_nomain(ID_MA, "EEVEEE default diffuse"); + + bNodeTree *ntree = ntreeAddTree(NULL, "Shader Nodetree", ntreeType_Shader->idname); + ma->nodetree = ntree; + ma->use_nodes = true; + + bNode *bsdf = nodeAddStaticNode(NULL, ntree, SH_NODE_BSDF_DIFFUSE); + bNodeSocket *base_color = nodeFindSocket(bsdf, SOCK_IN, "Color"); + copy_v3_fl(((bNodeSocketValueRGBA *)base_color->default_value)->value, 0.8f); + + bNode *output = nodeAddStaticNode(NULL, ntree, SH_NODE_OUTPUT_MATERIAL); + + nodeAddLink(ntree, + bsdf, + nodeFindSocket(bsdf, SOCK_OUT, "BSDF"), + output, + nodeFindSocket(output, SOCK_IN, "Surface")); + + nodeSetActive(ntree, output); + e_data.diffuse_mat = ma; + } + return e_data.diffuse_mat; +} + +Material *EEVEE_material_default_glossy_get(void) +{ + if (!e_data.glossy_mat) { + Material *ma = BKE_id_new_nomain(ID_MA, "EEVEEE default metal"); + + bNodeTree *ntree = ntreeAddTree(NULL, "Shader Nodetree", ntreeType_Shader->idname); + ma->nodetree = ntree; + ma->use_nodes = true; + + bNode *bsdf = nodeAddStaticNode(NULL, ntree, SH_NODE_BSDF_GLOSSY); + bNodeSocket *base_color = nodeFindSocket(bsdf, SOCK_IN, "Color"); + copy_v3_fl(((bNodeSocketValueRGBA *)base_color->default_value)->value, 1.0f); + bNodeSocket *roughness = nodeFindSocket(bsdf, SOCK_IN, "Roughness"); + ((bNodeSocketValueFloat *)roughness->default_value)->value = 0.0f; + + bNode *output = nodeAddStaticNode(NULL, ntree, SH_NODE_OUTPUT_MATERIAL); + + nodeAddLink(ntree, + bsdf, + nodeFindSocket(bsdf, SOCK_OUT, "BSDF"), + output, + nodeFindSocket(output, SOCK_IN, "Surface")); + + nodeSetActive(ntree, output); + e_data.glossy_mat = ma; + } + return e_data.glossy_mat; +} + +Material *EEVEE_material_default_error_get(void) +{ + if (!e_data.error_mat) { + Material *ma = BKE_id_new_nomain(ID_MA, "EEVEEE default metal"); + + bNodeTree *ntree = ntreeAddTree(NULL, "Shader Nodetree", ntreeType_Shader->idname); + ma->nodetree = ntree; + ma->use_nodes = true; + + /* Use emission and output material to be compatible with both World and Material. */ + bNode *bsdf = nodeAddStaticNode(NULL, ntree, SH_NODE_EMISSION); + bNodeSocket *color = nodeFindSocket(bsdf, SOCK_IN, "Color"); + copy_v3_fl3(((bNodeSocketValueRGBA *)color->default_value)->value, 1.0f, 0.0f, 1.0f); + + bNode *output = nodeAddStaticNode(NULL, ntree, SH_NODE_OUTPUT_MATERIAL); + + nodeAddLink(ntree, + bsdf, + nodeFindSocket(bsdf, SOCK_OUT, "Emission"), + output, + nodeFindSocket(output, SOCK_IN, "Surface")); + + nodeSetActive(ntree, output); + e_data.error_mat = ma; + } + return e_data.error_mat; +} + +/* Configure a default nodetree with the given material. */ +struct bNodeTree *EEVEE_shader_default_surface_nodetree(Material *ma) +{ + /* WARNING: This function is not threadsafe. Which is not a problem for the moment. */ + if (!e_data.surface.ntree) { + bNodeTree *ntree = ntreeAddTree(NULL, "Shader Nodetree", ntreeType_Shader->idname); + bNode *bsdf = nodeAddStaticNode(NULL, ntree, SH_NODE_BSDF_PRINCIPLED); + bNode *output = nodeAddStaticNode(NULL, ntree, SH_NODE_OUTPUT_MATERIAL); + bNodeSocket *bsdf_out = nodeFindSocket(bsdf, SOCK_OUT, "BSDF"); + bNodeSocket *output_in = nodeFindSocket(output, SOCK_IN, "Surface"); + nodeAddLink(ntree, bsdf, bsdf_out, output, output_in); + nodeSetActive(ntree, output); + + e_data.surface.color_socket = nodeFindSocket(bsdf, SOCK_IN, "Base Color")->default_value; + e_data.surface.metallic_socket = nodeFindSocket(bsdf, SOCK_IN, "Metallic")->default_value; + e_data.surface.roughness_socket = nodeFindSocket(bsdf, SOCK_IN, "Roughness")->default_value; + e_data.surface.specular_socket = nodeFindSocket(bsdf, SOCK_IN, "Specular")->default_value; + e_data.surface.ntree = ntree; + } + /* Update */ + copy_v3_fl3(e_data.surface.color_socket->value, ma->r, ma->g, ma->b); + e_data.surface.metallic_socket->value = ma->metallic; + e_data.surface.roughness_socket->value = ma->roughness; + e_data.surface.specular_socket->value = ma->spec; + + return e_data.surface.ntree; +} + +/* Configure a default nodetree with the given world. */ +struct bNodeTree *EEVEE_shader_default_world_nodetree(World *wo) +{ + /* WARNING: This function is not threadsafe. Which is not a problem for the moment. */ + if (!e_data.world.ntree) { + bNodeTree *ntree = ntreeAddTree(NULL, "Shader Nodetree", ntreeType_Shader->idname); + bNode *bg = nodeAddStaticNode(NULL, ntree, SH_NODE_BACKGROUND); + bNode *output = nodeAddStaticNode(NULL, ntree, SH_NODE_OUTPUT_WORLD); + bNodeSocket *bg_out = nodeFindSocket(bg, SOCK_OUT, "Background"); + bNodeSocket *output_in = nodeFindSocket(output, SOCK_IN, "Surface"); + nodeAddLink(ntree, bg, bg_out, output, output_in); + nodeSetActive(ntree, output); + + e_data.world.color_socket = nodeFindSocket(bg, SOCK_IN, "Color")->default_value; + e_data.world.ntree = ntree; + } + + copy_v3_fl3(e_data.world.color_socket->value, wo->horr, wo->horg, wo->horb); + + return e_data.world.ntree; +} + +static char *eevee_get_defines(int options) +{ + char *str = NULL; + + DynStr *ds = BLI_dynstr_new(); + BLI_dynstr_append(ds, SHADER_DEFINES); + + if ((options & VAR_WORLD_BACKGROUND) != 0) { + BLI_dynstr_append(ds, "#define WORLD_BACKGROUND\n"); + } + if ((options & VAR_MAT_VOLUME) != 0) { + BLI_dynstr_append(ds, "#define VOLUMETRICS\n"); + } + if ((options & VAR_MAT_MESH) != 0) { + BLI_dynstr_append(ds, "#define MESH_SHADER\n"); + } + if ((options & VAR_MAT_DEPTH) != 0) { + BLI_dynstr_append(ds, "#define DEPTH_SHADER\n"); + } + if ((options & VAR_MAT_HAIR) != 0) { + BLI_dynstr_append(ds, "#define HAIR_SHADER\n"); + } + if ((options & (VAR_MAT_PROBE | VAR_WORLD_PROBE)) != 0) { + BLI_dynstr_append(ds, "#define PROBE_CAPTURE\n"); + } + if ((options & VAR_MAT_HASH) != 0) { + BLI_dynstr_append(ds, "#define USE_ALPHA_HASH\n"); + } + if ((options & VAR_MAT_BLEND) != 0) { + BLI_dynstr_append(ds, "#define USE_ALPHA_BLEND\n"); + } + if ((options & VAR_MAT_REFRACT) != 0) { + BLI_dynstr_append(ds, "#define USE_REFRACTION\n"); + } + if ((options & VAR_MAT_LOOKDEV) != 0) { + BLI_dynstr_append(ds, "#define LOOKDEV\n"); + } + if ((options & VAR_MAT_HOLDOUT) != 0) { + BLI_dynstr_append(ds, "#define HOLDOUT\n"); + } + + str = BLI_dynstr_get_cstring(ds); + BLI_dynstr_free(ds); + + return str; +} + +static char *eevee_get_vert(int options) +{ + char *str = NULL; + + if ((options & VAR_MAT_VOLUME) != 0) { + str = BLI_strdup(e_data.vert_volume_shader_str); + } + else if ((options & (VAR_WORLD_PROBE | VAR_WORLD_BACKGROUND)) != 0) { + str = BLI_strdup(e_data.vert_background_shader_str); + } + else { + str = BLI_strdup(e_data.vert_shader_str); + } + + return str; +} + +static char *eevee_get_geom(int options) +{ + char *str = NULL; + + if ((options & VAR_MAT_VOLUME) != 0) { + str = BLI_strdup(e_data.geom_volume_shader_str); + } + + return str; +} + +static char *eevee_get_frag(int options) +{ + char *str = NULL; + + if ((options & VAR_MAT_VOLUME) != 0) { + str = BLI_strdup(e_data.volume_shader_lib); + } + else if ((options & VAR_MAT_DEPTH) != 0) { + str = BLI_string_joinN(e_data.frag_shader_lib, datatoc_prepass_frag_glsl); + } + else { + str = BLI_strdup(e_data.frag_shader_lib); + } + + return str; +} + +static struct GPUMaterial *eevee_material_get_ex( + struct Scene *scene, Material *ma, World *wo, int options, bool deferred) +{ + BLI_assert(ma || wo); + const bool is_volume = (options & VAR_MAT_VOLUME) != 0; + const bool is_default = (options & VAR_DEFAULT) != 0; + const void *engine = &DRW_engine_viewport_eevee_type; + + GPUMaterial *mat = NULL; + + if (ma) { + mat = DRW_shader_find_from_material(ma, engine, options, deferred); + } + else { + mat = DRW_shader_find_from_world(wo, engine, options, deferred); + } + + if (mat) { + return mat; + } + + char *defines = eevee_get_defines(options); + char *vert = eevee_get_vert(options); + char *geom = eevee_get_geom(options); + char *frag = eevee_get_frag(options); + + if (ma) { + bNodeTree *ntree = !is_default ? ma->nodetree : EEVEE_shader_default_surface_nodetree(ma); + mat = DRW_shader_create_from_material( + scene, ma, ntree, engine, options, is_volume, vert, geom, frag, defines, deferred); + } + else { + bNodeTree *ntree = !is_default ? wo->nodetree : EEVEE_shader_default_world_nodetree(wo); + mat = DRW_shader_create_from_world( + scene, wo, ntree, engine, options, is_volume, vert, geom, frag, defines, deferred); + } + + MEM_SAFE_FREE(defines); + MEM_SAFE_FREE(vert); + MEM_SAFE_FREE(geom); + MEM_SAFE_FREE(frag); + + return mat; +} + +/* Note: Compilation is not deferred. */ +struct GPUMaterial *EEVEE_material_default_get(struct Scene *scene, Material *ma, int options) +{ + Material *def_ma = (ma && (options & VAR_MAT_VOLUME)) ? BKE_material_default_volume() : + BKE_material_default_surface(); + BLI_assert(def_ma->use_nodes && def_ma->nodetree); + + return eevee_material_get_ex(scene, def_ma, NULL, options, false); +} + +struct GPUMaterial *EEVEE_material_get( + EEVEE_Data *vedata, struct Scene *scene, Material *ma, World *wo, int options) +{ + if ((ma && (!ma->use_nodes || !ma->nodetree)) || (wo && (!wo->use_nodes || !wo->nodetree))) { + options |= VAR_DEFAULT; + } + + /* Meh, implicit option. World probe cannot be deferred because they need + * to be rendered immediatly. */ + const bool deferred = (options & VAR_WORLD_PROBE) == 0; + + GPUMaterial *mat = eevee_material_get_ex(scene, ma, wo, options, deferred); + + int status = GPU_material_status(mat); + switch (status) { + case GPU_MAT_SUCCESS: + break; + case GPU_MAT_QUEUED: + vedata->stl->g_data->queued_shaders_count++; + mat = EEVEE_material_default_get(scene, ma, options); + break; + case GPU_MAT_FAILED: + default: + ma = EEVEE_material_default_error_get(); + mat = eevee_material_get_ex(scene, ma, NULL, options, false); + break; + } + /* Returned material should be ready to be drawn. */ + BLI_assert(GPU_material_status(mat) == GPU_MAT_SUCCESS); + return mat; +} + void EEVEE_shaders_free(void) { + MEM_SAFE_FREE(e_data.frag_shader_lib); + MEM_SAFE_FREE(e_data.vert_shader_str); + MEM_SAFE_FREE(e_data.vert_shadow_shader_str); + MEM_SAFE_FREE(e_data.vert_background_shader_str); + MEM_SAFE_FREE(e_data.vert_volume_shader_str); + MEM_SAFE_FREE(e_data.geom_volume_shader_str); + MEM_SAFE_FREE(e_data.volume_shader_lib); + DRW_SHADER_FREE_SAFE(e_data.default_background); + DRW_SHADER_FREE_SAFE(e_data.update_noise_sh); DRW_SHADER_FREE_SAFE(e_data.probe_default_sh); DRW_SHADER_FREE_SAFE(e_data.probe_filter_glossy_sh); DRW_SHADER_FREE_SAFE(e_data.probe_filter_diffuse_sh); @@ -332,4 +787,27 @@ void EEVEE_shaders_free(void) DRW_SHADER_FREE_SAFE(e_data.velocity_resolve_sh); DRW_SHADER_FREE_SAFE(e_data.taa_resolve_sh); DRW_SHADER_FREE_SAFE(e_data.taa_resolve_reproject_sh); + + if (e_data.glossy_mat) { + BKE_id_free(NULL, e_data.glossy_mat); + e_data.glossy_mat = NULL; + } + if (e_data.diffuse_mat) { + BKE_id_free(NULL, e_data.diffuse_mat); + e_data.diffuse_mat = NULL; + } + if (e_data.error_mat) { + BKE_id_free(NULL, e_data.error_mat); + e_data.error_mat = NULL; + } + if (e_data.surface.ntree) { + ntreeFreeEmbeddedTree(e_data.surface.ntree); + MEM_freeN(e_data.surface.ntree); + e_data.surface.ntree = NULL; + } + if (e_data.world.ntree) { + ntreeFreeEmbeddedTree(e_data.world.ntree); + MEM_freeN(e_data.world.ntree); + e_data.world.ntree = NULL; + } } |