This repository has been archived on 2023-10-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
blender-archive/source/blender/draw/engines/eevee/eevee_shaders.c
Jeroen Bakker 76a0b322e4 EEVEE Cryptomatte
Cryptomatte is a standard to efficiently create mattes for compositing. The
renderer outputs the required render passes, which can then be used in the
compositor to create masks for specified objects. Unlike the Material and Object
Index passes, the objects to isolate are selected in compositing, and mattes
will be anti-aliased.

Cryptomatte was already available in Cycles this patch adds it to the EEVEE
render engine. Original specification can be found at
https://raw.githubusercontent.com/Psyop/Cryptomatte/master/specification/IDmattes_poster.pdf

**Accurate mode**

Following Cycles, there are two accuracy modes. The difference between the two
modes is the number of render samples they take into account to create the
render passes. When accurate mode is off the number of levels is used. When
accuracy mode is active, the number of render samples is used.

**Deviation from standard**

Cryptomatte specification is based on a path trace approach where samples and
coverage are calculated at the same time. In EEVEE a sample is an exact match on
top of a prepared depth buffer. Coverage is at that moment always 1. By sampling
multiple times the number of surface hits decides the actual surface coverage
for a matte per pixel.

**Implementation Overview**

When drawing to the cryptomatte GPU buffer the depth of the fragment is matched
to the active depth buffer. The hashes of each cryptomatte layer is written in
the GPU buffer. The exact layout depends on the active cryptomatte layers. The
GPU buffer is downloaded and integrated into an accumulation buffer (stored in
CPU RAM).

The accumulation buffer stores the hashes + weights for a number of levels,
layers per pixel. When a hash already exists the weight will be increased. When
the hash doesn't exists it will be added to the buffer.

After all the samples have been calculated the accumulation buffer is processed.
During this phase the total pixel weights of each layer is mapped to be in a
range between 0 and 1. The hashes are also sorted (highest weight first).

Blender Kernel now has a `BKE_cryptomatte` header that access to common
functions for cryptomatte. This will in the future be used by the API.

* Alpha blended materials aren't supported. Alpha blended materials support in
  render passes needs research how to implement it in a maintainable way for any
  render pass.

This is a list of tasks that needs to be done for the same release that this
patch lands on (Blender 2.92)

* T82571 Add render tests.
* T82572 Documentation.
* T82573 Store hashes + Object names in the render result header.
* T82574 Use threading to increase performance in accumulation and post
  processing.
* T82575 Merge the cycles and EEVEE settings as they are identical.
* T82576 Add RNA to extract the cryptomatte hashes to use in python scripts.

Reviewed By: Clément Foucault

Maniphest Tasks: T81058

Differential Revision: https://developer.blender.org/D9165
2020-12-04 08:46:34 +01:00

1504 lines
52 KiB
C

/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Copyright 2016, Blender Foundation.
*/
/** \file
* \ingroup draw_engine
*/
#include "DRW_render.h"
#include "BKE_lib_id.h"
#include "BKE_node.h"
#include "BLI_dynstr.h"
#include "BLI_string_utils.h"
#include "DNA_world_types.h"
#include "MEM_guardedalloc.h"
#include "GPU_capabilities.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"
#if defined(IRRADIANCE_SH_L2)
"#define IRRADIANCE_SH_L2\n";
#elif defined(IRRADIANCE_HL2)
"#define IRRADIANCE_HL2\n";
#endif
static struct {
/* Lookdev */
struct GPUShader *studiolight_probe_sh;
struct GPUShader *studiolight_background_sh;
/* Probes */
struct GPUShader *probe_grid_display_sh;
struct GPUShader *probe_cube_display_sh;
struct GPUShader *probe_planar_display_sh;
struct GPUShader *probe_filter_glossy_sh;
struct GPUShader *probe_filter_diffuse_sh;
struct GPUShader *probe_filter_visibility_sh;
struct GPUShader *probe_grid_fill_sh;
struct GPUShader *probe_planar_downsample_sh;
/* Velocity Resolve */
struct GPUShader *velocity_resolve_sh;
/* Temporal Anti Aliasing */
struct GPUShader *taa_resolve_sh;
struct GPUShader *taa_resolve_reproject_sh;
/* Bloom */
struct GPUShader *bloom_blit_sh[2];
struct GPUShader *bloom_downsample_sh[2];
struct GPUShader *bloom_upsample_sh[2];
struct GPUShader *bloom_resolve_sh[2];
/* Depth Of Field */
struct GPUShader *dof_downsample_sh[2];
struct GPUShader *dof_scatter_sh[2];
struct GPUShader *dof_resolve_sh[2];
/* General purpose Shaders. */
struct GPUShader *lookdev_background;
struct GPUShader *update_noise_sh;
/* Downsample Depth */
struct GPUShader *minz_downlevel_sh;
struct GPUShader *maxz_downlevel_sh;
struct GPUShader *minz_downdepth_sh;
struct GPUShader *maxz_downdepth_sh;
struct GPUShader *minz_downdepth_layer_sh;
struct GPUShader *maxz_downdepth_layer_sh;
struct GPUShader *maxz_copydepth_layer_sh;
struct GPUShader *minz_copydepth_sh;
struct GPUShader *maxz_copydepth_sh;
/* Simple Downsample */
struct GPUShader *downsample_sh;
struct GPUShader *downsample_cube_sh;
/* Mist */
struct GPUShader *mist_sh;
/* Motion Blur */
struct GPUShader *motion_blur_sh;
struct GPUShader *motion_blur_object_sh;
struct GPUShader *motion_blur_hair_sh;
struct GPUShader *velocity_tiles_sh;
struct GPUShader *velocity_tiles_expand_sh;
/* Ground Truth Ambient Occlusion */
struct GPUShader *gtao_sh;
struct GPUShader *gtao_layer_sh;
struct GPUShader *gtao_debug_sh;
/* GGX LUT */
struct GPUShader *ggx_lut_sh;
struct GPUShader *ggx_refraction_lut_sh;
/* Render Passes */
struct GPUShader *postprocess_sh;
struct GPUShader *cryptomatte_sh[2];
/* Screen Space Reflection */
struct GPUShader *ssr_sh[SSR_MAX_SHADER];
/* Shadows */
struct GPUShader *shadow_sh;
struct GPUShader *shadow_accum_sh;
/* Subsurface */
struct GPUShader *sss_sh[3];
/* Volume */
struct GPUShader *volumetric_clear_sh;
struct GPUShader *scatter_sh;
struct GPUShader *scatter_with_lights_sh;
struct GPUShader *volumetric_integration_sh;
struct GPUShader *volumetric_resolve_sh[2];
struct GPUShader *volumetric_accum_sh;
/* Shader strings */
char *closure_lit_lib;
char *surface_lit_frag;
char *surface_prepass_frag;
char *surface_geom_barycentric;
DRWShaderLibrary *lib;
/* LookDev Materials */
Material *glossy_mat;
Material *diffuse_mat;
Material *error_mat;
World *default_world;
/* 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_common_hair_lib_glsl[];
extern char datatoc_common_math_lib_glsl[];
extern char datatoc_common_math_geom_lib_glsl[];
extern char datatoc_common_view_lib_glsl[];
extern char datatoc_gpu_shader_common_obinfos_lib_glsl[];
extern char datatoc_ambient_occlusion_lib_glsl[];
extern char datatoc_background_vert_glsl[];
extern char datatoc_bsdf_common_lib_glsl[];
extern char datatoc_bsdf_lut_frag_glsl[];
extern char datatoc_bsdf_sampling_lib_glsl[];
extern char datatoc_btdf_lut_frag_glsl[];
extern char datatoc_closure_lib_glsl[];
extern char datatoc_common_uniforms_lib_glsl[];
extern char datatoc_common_utiltex_lib_glsl[];
extern char datatoc_cryptomatte_frag_glsl[];
extern char datatoc_cubemap_lib_glsl[];
extern char datatoc_default_frag_glsl[];
extern char datatoc_lookdev_world_frag_glsl[];
extern char datatoc_effect_bloom_frag_glsl[];
extern char datatoc_effect_dof_frag_glsl[];
extern char datatoc_effect_dof_vert_glsl[];
extern char datatoc_effect_downsample_cube_frag_glsl[];
extern char datatoc_effect_downsample_frag_glsl[];
extern char datatoc_effect_gtao_frag_glsl[];
extern char datatoc_effect_minmaxz_frag_glsl[];
extern char datatoc_effect_mist_frag_glsl[];
extern char datatoc_effect_motion_blur_frag_glsl[];
extern char datatoc_effect_ssr_frag_glsl[];
extern char datatoc_effect_subsurface_frag_glsl[];
extern char datatoc_effect_temporal_aa_glsl[];
extern char datatoc_effect_translucency_frag_glsl[];
extern char datatoc_effect_velocity_resolve_frag_glsl[];
extern char datatoc_effect_velocity_tile_frag_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_lightprobe_vert_glsl[];
extern char datatoc_lights_lib_glsl[];
extern char datatoc_closure_lit_lib_glsl[];
extern char datatoc_ltc_lib_glsl[];
extern char datatoc_object_motion_frag_glsl[];
extern char datatoc_object_motion_vert_glsl[];
extern char datatoc_octahedron_lib_glsl[];
extern char datatoc_prepass_frag_glsl[];
extern char datatoc_prepass_vert_glsl[];
extern char datatoc_raytrace_lib_glsl[];
extern char datatoc_renderpass_lib_glsl[];
extern char datatoc_renderpass_postprocess_frag_glsl[];
extern char datatoc_shadow_accum_frag_glsl[];
extern char datatoc_shadow_frag_glsl[];
extern char datatoc_shadow_vert_glsl[];
extern char datatoc_ssr_lib_glsl[];
extern char datatoc_surface_frag_glsl[];
extern char datatoc_surface_geom_glsl[];
extern char datatoc_surface_lib_glsl[];
extern char datatoc_surface_vert_glsl[];
extern char datatoc_update_noise_frag_glsl[];
extern char datatoc_volumetric_accum_frag_glsl[];
extern char datatoc_volumetric_frag_glsl[];
extern char datatoc_volumetric_geom_glsl[];
extern char datatoc_volumetric_integration_frag_glsl[];
extern char datatoc_volumetric_lib_glsl[];
extern char datatoc_volumetric_resolve_frag_glsl[];
extern char datatoc_volumetric_scatter_frag_glsl[];
extern char datatoc_volumetric_vert_glsl[];
/* *********** FUNCTIONS *********** */
static void eevee_shader_library_ensure(void)
{
if (e_data.lib == NULL) {
e_data.lib = DRW_shader_library_create();
/* NOTE: Theses needs to be ordered by dependencies. */
DRW_SHADER_LIB_ADD(e_data.lib, common_math_lib);
DRW_SHADER_LIB_ADD(e_data.lib, common_math_geom_lib);
DRW_SHADER_LIB_ADD(e_data.lib, common_hair_lib);
DRW_SHADER_LIB_ADD(e_data.lib, common_view_lib);
DRW_SHADER_LIB_ADD(e_data.lib, common_uniforms_lib);
DRW_SHADER_LIB_ADD(e_data.lib, gpu_shader_common_obinfos_lib);
DRW_SHADER_LIB_ADD(e_data.lib, renderpass_lib);
DRW_SHADER_LIB_ADD(e_data.lib, bsdf_common_lib);
DRW_SHADER_LIB_ADD(e_data.lib, common_utiltex_lib);
DRW_SHADER_LIB_ADD(e_data.lib, bsdf_sampling_lib);
DRW_SHADER_LIB_ADD(e_data.lib, cubemap_lib);
DRW_SHADER_LIB_ADD(e_data.lib, raytrace_lib);
DRW_SHADER_LIB_ADD(e_data.lib, ambient_occlusion_lib);
DRW_SHADER_LIB_ADD(e_data.lib, octahedron_lib);
DRW_SHADER_LIB_ADD(e_data.lib, irradiance_lib);
DRW_SHADER_LIB_ADD(e_data.lib, lightprobe_lib);
DRW_SHADER_LIB_ADD(e_data.lib, ltc_lib);
DRW_SHADER_LIB_ADD(e_data.lib, lights_lib);
DRW_SHADER_LIB_ADD(e_data.lib, surface_lib);
DRW_SHADER_LIB_ADD(e_data.lib, volumetric_lib);
DRW_SHADER_LIB_ADD(e_data.lib, closure_lib);
DRW_SHADER_LIB_ADD(e_data.lib, ssr_lib);
/* Add one for each Closure */
e_data.closure_lit_lib = BLI_string_joinN(datatoc_closure_lit_lib_glsl,
datatoc_closure_lit_lib_glsl,
datatoc_closure_lit_lib_glsl,
datatoc_closure_lit_lib_glsl,
datatoc_closure_lit_lib_glsl,
datatoc_closure_lit_lib_glsl,
datatoc_closure_lit_lib_glsl,
datatoc_closure_lit_lib_glsl,
datatoc_closure_lit_lib_glsl,
datatoc_closure_lit_lib_glsl,
datatoc_closure_lit_lib_glsl);
DRW_shader_library_add_file(e_data.lib, e_data.closure_lit_lib, "closure_lit_lib.glsl");
e_data.surface_lit_frag = DRW_shader_library_create_shader_string(e_data.lib,
datatoc_surface_frag_glsl);
e_data.surface_prepass_frag = DRW_shader_library_create_shader_string(
e_data.lib, datatoc_prepass_frag_glsl);
e_data.surface_geom_barycentric = DRW_shader_library_create_shader_string(
e_data.lib, datatoc_surface_geom_glsl);
}
}
void EEVEE_shaders_lightprobe_shaders_init(void)
{
BLI_assert(e_data.probe_filter_glossy_sh == NULL);
eevee_shader_library_ensure();
e_data.probe_filter_glossy_sh = DRW_shader_create_with_shaderlib(
datatoc_lightprobe_vert_glsl,
datatoc_lightprobe_geom_glsl,
datatoc_lightprobe_filter_glossy_frag_glsl,
e_data.lib,
filter_defines);
e_data.probe_filter_diffuse_sh = DRW_shader_create_fullscreen_with_shaderlib(
datatoc_lightprobe_filter_diffuse_frag_glsl, e_data.lib, filter_defines);
e_data.probe_filter_visibility_sh = DRW_shader_create_fullscreen_with_shaderlib(
datatoc_lightprobe_filter_visibility_frag_glsl, e_data.lib, filter_defines);
e_data.probe_grid_fill_sh = DRW_shader_create_fullscreen_with_shaderlib(
datatoc_lightprobe_grid_fill_frag_glsl, e_data.lib, filter_defines);
e_data.probe_planar_downsample_sh = DRW_shader_create(
datatoc_lightprobe_planar_downsample_vert_glsl,
datatoc_lightprobe_planar_downsample_geom_glsl,
datatoc_lightprobe_planar_downsample_frag_glsl,
NULL);
}
void EEVEE_shaders_material_shaders_init(void)
{
eevee_shader_library_ensure();
}
DRWShaderLibrary *EEVEE_shader_lib_get(void)
{
eevee_shader_library_ensure();
return e_data.lib;
}
GPUShader *EEVEE_shaders_probe_filter_glossy_sh_get(void)
{
return e_data.probe_filter_glossy_sh;
}
GPUShader *EEVEE_shaders_probe_filter_diffuse_sh_get(void)
{
return e_data.probe_filter_diffuse_sh;
}
GPUShader *EEVEE_shaders_probe_filter_visibility_sh_get(void)
{
return e_data.probe_filter_visibility_sh;
}
GPUShader *EEVEE_shaders_probe_grid_fill_sh_get(void)
{
return e_data.probe_grid_fill_sh;
}
GPUShader *EEVEE_shaders_probe_planar_downsample_sh_get(void)
{
return e_data.probe_planar_downsample_sh;
}
GPUShader *EEVEE_shaders_studiolight_probe_sh_get(void)
{
if (e_data.studiolight_probe_sh == NULL) {
e_data.studiolight_probe_sh = DRW_shader_create_with_shaderlib(datatoc_background_vert_glsl,
NULL,
datatoc_lookdev_world_frag_glsl,
e_data.lib,
SHADER_DEFINES);
}
return e_data.studiolight_probe_sh;
}
GPUShader *EEVEE_shaders_studiolight_background_sh_get(void)
{
if (e_data.studiolight_background_sh == NULL) {
e_data.studiolight_background_sh = DRW_shader_create_with_shaderlib(
datatoc_background_vert_glsl,
NULL,
datatoc_lookdev_world_frag_glsl,
e_data.lib,
"#define LOOKDEV_BG\n" SHADER_DEFINES);
}
return e_data.studiolight_background_sh;
}
GPUShader *EEVEE_shaders_probe_cube_display_sh_get(void)
{
if (e_data.probe_cube_display_sh == NULL) {
e_data.probe_cube_display_sh = DRW_shader_create_with_shaderlib(
datatoc_lightprobe_cube_display_vert_glsl,
NULL,
datatoc_lightprobe_cube_display_frag_glsl,
e_data.lib,
SHADER_DEFINES);
}
return e_data.probe_cube_display_sh;
}
GPUShader *EEVEE_shaders_probe_grid_display_sh_get(void)
{
if (e_data.probe_grid_display_sh == NULL) {
e_data.probe_grid_display_sh = DRW_shader_create_with_shaderlib(
datatoc_lightprobe_grid_display_vert_glsl,
NULL,
datatoc_lightprobe_grid_display_frag_glsl,
e_data.lib,
filter_defines);
}
return e_data.probe_grid_display_sh;
}
GPUShader *EEVEE_shaders_probe_planar_display_sh_get(void)
{
if (e_data.probe_planar_display_sh == NULL) {
e_data.probe_planar_display_sh = DRW_shader_create_with_shaderlib(
datatoc_lightprobe_planar_display_vert_glsl,
NULL,
datatoc_lightprobe_planar_display_frag_glsl,
e_data.lib,
NULL);
}
return e_data.probe_planar_display_sh;
}
/* -------------------------------------------------------------------- */
/** \name Downsampling
* \{ */
GPUShader *EEVEE_shaders_effect_downsample_sh_get(void)
{
if (e_data.downsample_sh == NULL) {
e_data.downsample_sh = DRW_shader_create_fullscreen(datatoc_effect_downsample_frag_glsl, NULL);
}
return e_data.downsample_sh;
}
GPUShader *EEVEE_shaders_effect_downsample_cube_sh_get(void)
{
if (e_data.downsample_cube_sh == NULL) {
e_data.downsample_cube_sh = DRW_shader_create(datatoc_lightprobe_vert_glsl,
datatoc_lightprobe_geom_glsl,
datatoc_effect_downsample_cube_frag_glsl,
NULL);
}
return e_data.downsample_cube_sh;
}
GPUShader *EEVEE_shaders_effect_minz_downlevel_sh_get(void)
{
if (e_data.minz_downlevel_sh == NULL) {
e_data.minz_downlevel_sh = DRW_shader_create_fullscreen(datatoc_effect_minmaxz_frag_glsl,
"#define MIN_PASS\n");
}
return e_data.minz_downlevel_sh;
}
GPUShader *EEVEE_shaders_effect_maxz_downlevel_sh_get(void)
{
if (e_data.maxz_downlevel_sh == NULL) {
e_data.maxz_downlevel_sh = DRW_shader_create_fullscreen(datatoc_effect_minmaxz_frag_glsl,
"#define MAX_PASS\n");
}
return e_data.maxz_downlevel_sh;
}
GPUShader *EEVEE_shaders_effect_minz_downdepth_sh_get(void)
{
if (e_data.minz_downdepth_sh == NULL) {
e_data.minz_downdepth_sh = DRW_shader_create_fullscreen(datatoc_effect_minmaxz_frag_glsl,
"#define MIN_PASS\n");
}
return e_data.minz_downdepth_sh;
}
GPUShader *EEVEE_shaders_effect_maxz_downdepth_sh_get(void)
{
if (e_data.maxz_downdepth_sh == NULL) {
e_data.maxz_downdepth_sh = DRW_shader_create_fullscreen(datatoc_effect_minmaxz_frag_glsl,
"#define MAX_PASS\n");
}
return e_data.maxz_downdepth_sh;
}
GPUShader *EEVEE_shaders_effect_minz_downdepth_layer_sh_get(void)
{
if (e_data.minz_downdepth_layer_sh == NULL) {
e_data.minz_downdepth_layer_sh = DRW_shader_create_fullscreen(datatoc_effect_minmaxz_frag_glsl,
"#define MIN_PASS\n"
"#define LAYERED\n");
}
return e_data.minz_downdepth_layer_sh;
}
GPUShader *EEVEE_shaders_effect_maxz_downdepth_layer_sh_get(void)
{
if (e_data.maxz_downdepth_layer_sh == NULL) {
e_data.maxz_downdepth_layer_sh = DRW_shader_create_fullscreen(datatoc_effect_minmaxz_frag_glsl,
"#define MAX_PASS\n"
"#define LAYERED\n");
}
return e_data.maxz_downdepth_layer_sh;
}
GPUShader *EEVEE_shaders_effect_maxz_copydepth_layer_sh_get(void)
{
if (e_data.maxz_copydepth_layer_sh == NULL) {
e_data.maxz_copydepth_layer_sh = DRW_shader_create_fullscreen(datatoc_effect_minmaxz_frag_glsl,
"#define MAX_PASS\n"
"#define COPY_DEPTH\n"
"#define LAYERED\n");
}
return e_data.maxz_copydepth_layer_sh;
}
GPUShader *EEVEE_shaders_effect_minz_copydepth_sh_get(void)
{
if (e_data.minz_copydepth_sh == NULL) {
e_data.minz_copydepth_sh = DRW_shader_create_fullscreen(datatoc_effect_minmaxz_frag_glsl,
"#define MIN_PASS\n"
"#define COPY_DEPTH\n");
}
return e_data.minz_copydepth_sh;
}
GPUShader *EEVEE_shaders_effect_maxz_copydepth_sh_get(void)
{
if (e_data.maxz_copydepth_sh == NULL) {
e_data.maxz_copydepth_sh = DRW_shader_create_fullscreen(datatoc_effect_minmaxz_frag_glsl,
"#define MAX_PASS\n"
"#define COPY_DEPTH\n");
}
return e_data.maxz_copydepth_sh;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name GGX LUT
* \{ */
GPUShader *EEVEE_shaders_ggx_lut_sh_get(void)
{
if (e_data.ggx_lut_sh == NULL) {
e_data.ggx_lut_sh = DRW_shader_create_with_shaderlib(datatoc_lightprobe_vert_glsl,
datatoc_lightprobe_geom_glsl,
datatoc_bsdf_lut_frag_glsl,
e_data.lib,
"#define HAMMERSLEY_SIZE 8192\n");
}
return e_data.ggx_lut_sh;
}
GPUShader *EEVEE_shaders_ggx_refraction_lut_sh_get(void)
{
if (e_data.ggx_refraction_lut_sh == NULL) {
e_data.ggx_refraction_lut_sh = DRW_shader_create_fullscreen_with_shaderlib(
datatoc_btdf_lut_frag_glsl, e_data.lib, "#define HAMMERSLEY_SIZE 8192\n");
}
return e_data.ggx_refraction_lut_sh;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Mist
* \{ */
GPUShader *EEVEE_shaders_effect_mist_sh_get(void)
{
if (e_data.mist_sh == NULL) {
e_data.mist_sh = DRW_shader_create_fullscreen_with_shaderlib(
datatoc_effect_mist_frag_glsl, e_data.lib, "#define FIRST_PASS\n");
}
return e_data.mist_sh;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Motion Blur
* \{ */
#define TILE_SIZE_STR "#define EEVEE_VELOCITY_TILE_SIZE " STRINGIFY(EEVEE_VELOCITY_TILE_SIZE) "\n"
GPUShader *EEVEE_shaders_effect_motion_blur_sh_get(void)
{
if (e_data.motion_blur_sh == NULL) {
e_data.motion_blur_sh = DRW_shader_create_fullscreen_with_shaderlib(
datatoc_effect_motion_blur_frag_glsl, e_data.lib, TILE_SIZE_STR);
}
return e_data.motion_blur_sh;
}
GPUShader *EEVEE_shaders_effect_motion_blur_object_sh_get(void)
{
if (e_data.motion_blur_object_sh == NULL) {
e_data.motion_blur_object_sh = DRW_shader_create_with_shaderlib(
datatoc_object_motion_vert_glsl, NULL, datatoc_object_motion_frag_glsl, e_data.lib, NULL);
}
return e_data.motion_blur_object_sh;
}
GPUShader *EEVEE_shaders_effect_motion_blur_hair_sh_get(void)
{
if (e_data.motion_blur_hair_sh == NULL) {
e_data.motion_blur_hair_sh = DRW_shader_create_with_shaderlib(datatoc_object_motion_vert_glsl,
NULL,
datatoc_object_motion_frag_glsl,
e_data.lib,
"#define HAIR\n");
}
return e_data.motion_blur_hair_sh;
}
GPUShader *EEVEE_shaders_effect_motion_blur_velocity_tiles_sh_get(void)
{
if (e_data.velocity_tiles_sh == NULL) {
e_data.velocity_tiles_sh = DRW_shader_create_fullscreen(datatoc_effect_velocity_tile_frag_glsl,
"#define TILE_GATHER\n" TILE_SIZE_STR);
}
return e_data.velocity_tiles_sh;
}
GPUShader *EEVEE_shaders_effect_motion_blur_velocity_tiles_expand_sh_get(void)
{
if (e_data.velocity_tiles_expand_sh == NULL) {
e_data.velocity_tiles_expand_sh = DRW_shader_create_fullscreen(
datatoc_effect_velocity_tile_frag_glsl, "#define TILE_EXPANSION\n" TILE_SIZE_STR);
}
return e_data.velocity_tiles_expand_sh;
}
#undef TILE_SIZE_STR
/** \} */
/* -------------------------------------------------------------------- */
/** \name Ambient Occlusion
* \{ */
GPUShader *EEVEE_shaders_effect_ambient_occlusion_sh_get(void)
{
if (e_data.gtao_sh == NULL) {
e_data.gtao_sh = DRW_shader_create_fullscreen_with_shaderlib(
datatoc_effect_gtao_frag_glsl, e_data.lib, NULL);
}
return e_data.gtao_sh;
}
GPUShader *EEVEE_shaders_effect_ambient_occlusion_layer_sh_get(void)
{
if (e_data.gtao_layer_sh == NULL) {
e_data.gtao_layer_sh = DRW_shader_create_fullscreen_with_shaderlib(
datatoc_effect_gtao_frag_glsl, e_data.lib, "#define LAYERED_DEPTH\n");
}
return e_data.gtao_layer_sh;
}
GPUShader *EEVEE_shaders_effect_ambient_occlusion_debug_sh_get(void)
{
if (e_data.gtao_debug_sh == NULL) {
e_data.gtao_debug_sh = DRW_shader_create_fullscreen_with_shaderlib(
datatoc_effect_gtao_frag_glsl, e_data.lib, "#define DEBUG_AO\n");
}
return e_data.gtao_debug_sh;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Render Passes
* \{ */
GPUShader *EEVEE_shaders_renderpasses_post_process_sh_get(void)
{
if (e_data.postprocess_sh == NULL) {
e_data.postprocess_sh = DRW_shader_create_fullscreen_with_shaderlib(
datatoc_renderpass_postprocess_frag_glsl, e_data.lib, NULL);
}
return e_data.postprocess_sh;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Cryptomatte
* \{ */
GPUShader *EEVEE_shaders_cryptomatte_sh_get(bool is_hair)
{
const int index = is_hair ? 1 : 0;
if (e_data.cryptomatte_sh[index] == NULL) {
DynStr *ds = BLI_dynstr_new();
BLI_dynstr_append(ds, SHADER_DEFINES);
if (is_hair) {
BLI_dynstr_append(ds, "#define HAIR_SHADER\n");
}
else {
BLI_dynstr_append(ds, "#define MESH_SHADER\n");
}
char *defines = BLI_dynstr_get_cstring(ds);
e_data.cryptomatte_sh[index] = DRW_shader_create_with_shaderlib(
datatoc_surface_vert_glsl, NULL, datatoc_cryptomatte_frag_glsl, e_data.lib, defines);
BLI_dynstr_free(ds);
MEM_freeN(defines);
}
return e_data.cryptomatte_sh[index];
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Screen Raytrace
* \{ */
struct GPUShader *EEVEE_shaders_effect_screen_raytrace_sh_get(EEVEE_SSRShaderOptions options)
{
if (e_data.ssr_sh[options] == NULL) {
DRWShaderLibrary *lib = EEVEE_shader_lib_get();
DynStr *ds_defines = BLI_dynstr_new();
BLI_dynstr_append(ds_defines, SHADER_DEFINES);
if (options & SSR_RESOLVE) {
BLI_dynstr_append(ds_defines, "#define STEP_RESOLVE\n");
}
else {
BLI_dynstr_append(ds_defines, "#define STEP_RAYTRACE\n");
BLI_dynstr_append(ds_defines, "#define PLANAR_PROBE_RAYTRACE\n");
}
if (options & SSR_FULL_TRACE) {
BLI_dynstr_append(ds_defines, "#define FULLRES\n");
}
if (options & SSR_AO) {
BLI_dynstr_append(ds_defines, "#define SSR_AO\n");
}
char *ssr_define_str = BLI_dynstr_get_cstring(ds_defines);
BLI_dynstr_free(ds_defines);
e_data.ssr_sh[options] = DRW_shader_create_fullscreen_with_shaderlib(
datatoc_effect_ssr_frag_glsl, lib, ssr_define_str);
MEM_freeN(ssr_define_str);
}
return e_data.ssr_sh[options];
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Shadows
* \{ */
struct GPUShader *EEVEE_shaders_shadow_sh_get()
{
if (e_data.shadow_sh == NULL) {
e_data.shadow_sh = DRW_shader_create_with_shaderlib(
datatoc_shadow_vert_glsl, NULL, datatoc_shadow_frag_glsl, e_data.lib, NULL);
}
return e_data.shadow_sh;
}
struct GPUShader *EEVEE_shaders_shadow_accum_sh_get()
{
if (e_data.shadow_accum_sh == NULL) {
e_data.shadow_accum_sh = DRW_shader_create_fullscreen_with_shaderlib(
datatoc_shadow_accum_frag_glsl, e_data.lib, SHADER_DEFINES);
}
return e_data.shadow_accum_sh;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Subsurface
* \{ */
struct GPUShader *EEVEE_shaders_subsurface_first_pass_sh_get()
{
if (e_data.sss_sh[0] == NULL) {
e_data.sss_sh[0] = DRW_shader_create_fullscreen_with_shaderlib(
datatoc_effect_subsurface_frag_glsl, e_data.lib, "#define FIRST_PASS\n");
}
return e_data.sss_sh[0];
}
struct GPUShader *EEVEE_shaders_subsurface_second_pass_sh_get()
{
if (e_data.sss_sh[1] == NULL) {
e_data.sss_sh[1] = DRW_shader_create_fullscreen_with_shaderlib(
datatoc_effect_subsurface_frag_glsl, e_data.lib, "#define SECOND_PASS\n");
}
return e_data.sss_sh[1];
}
struct GPUShader *EEVEE_shaders_subsurface_translucency_sh_get()
{
if (e_data.sss_sh[2] == NULL) {
e_data.sss_sh[2] = DRW_shader_create_fullscreen_with_shaderlib(
datatoc_effect_translucency_frag_glsl,
e_data.lib,
"#define EEVEE_TRANSLUCENCY\n" SHADER_DEFINES);
}
return e_data.sss_sh[2];
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Volumes
* \{ */
struct GPUShader *EEVEE_shaders_volumes_clear_sh_get()
{
if (e_data.volumetric_clear_sh == NULL) {
e_data.volumetric_clear_sh = DRW_shader_create_with_shaderlib(datatoc_volumetric_vert_glsl,
datatoc_volumetric_geom_glsl,
datatoc_volumetric_frag_glsl,
e_data.lib,
SHADER_DEFINES
"#define VOLUMETRICS\n"
"#define CLEAR\n");
}
return e_data.volumetric_clear_sh;
}
struct GPUShader *EEVEE_shaders_volumes_scatter_sh_get()
{
if (e_data.scatter_sh == NULL) {
e_data.scatter_sh = DRW_shader_create_with_shaderlib(datatoc_volumetric_vert_glsl,
datatoc_volumetric_geom_glsl,
datatoc_volumetric_scatter_frag_glsl,
e_data.lib,
SHADER_DEFINES
"#define VOLUMETRICS\n"
"#define VOLUME_SHADOW\n");
}
return e_data.scatter_sh;
}
struct GPUShader *EEVEE_shaders_volumes_scatter_with_lights_sh_get()
{
if (e_data.scatter_with_lights_sh == NULL) {
e_data.scatter_with_lights_sh = DRW_shader_create_with_shaderlib(
datatoc_volumetric_vert_glsl,
datatoc_volumetric_geom_glsl,
datatoc_volumetric_scatter_frag_glsl,
e_data.lib,
SHADER_DEFINES
"#define VOLUMETRICS\n"
"#define VOLUME_LIGHTING\n"
"#define VOLUME_SHADOW\n");
}
return e_data.scatter_with_lights_sh;
}
struct GPUShader *EEVEE_shaders_volumes_integration_sh_get()
{
if (e_data.volumetric_integration_sh == NULL) {
e_data.volumetric_integration_sh = DRW_shader_create_with_shaderlib(
datatoc_volumetric_vert_glsl,
datatoc_volumetric_geom_glsl,
datatoc_volumetric_integration_frag_glsl,
e_data.lib,
USE_VOLUME_OPTI ? "#extension GL_ARB_shader_image_load_store: enable\n"
"#extension GL_ARB_shading_language_420pack: enable\n"
"#define USE_VOLUME_OPTI\n" SHADER_DEFINES :
SHADER_DEFINES);
}
return e_data.volumetric_integration_sh;
}
struct GPUShader *EEVEE_shaders_volumes_resolve_sh_get(bool accum)
{
const int index = accum ? 1 : 0;
if (e_data.volumetric_resolve_sh[index] == NULL) {
e_data.volumetric_resolve_sh[index] = DRW_shader_create_fullscreen_with_shaderlib(
datatoc_volumetric_resolve_frag_glsl,
e_data.lib,
accum ? "#define VOLUMETRICS_ACCUM\n" SHADER_DEFINES : SHADER_DEFINES);
}
return e_data.volumetric_resolve_sh[index];
}
struct GPUShader *EEVEE_shaders_volumes_accum_sh_get()
{
if (e_data.volumetric_accum_sh == NULL) {
e_data.volumetric_accum_sh = DRW_shader_create_fullscreen_with_shaderlib(
datatoc_volumetric_accum_frag_glsl, e_data.lib, SHADER_DEFINES);
}
return e_data.volumetric_accum_sh;
}
/** \} */
GPUShader *EEVEE_shaders_velocity_resolve_sh_get(void)
{
if (e_data.velocity_resolve_sh == NULL) {
e_data.velocity_resolve_sh = DRW_shader_create_fullscreen_with_shaderlib(
datatoc_effect_velocity_resolve_frag_glsl, e_data.lib, NULL);
}
return e_data.velocity_resolve_sh;
}
GPUShader *EEVEE_shaders_update_noise_sh_get(void)
{
if (e_data.update_noise_sh == NULL) {
e_data.update_noise_sh = DRW_shader_create_fullscreen_with_shaderlib(
datatoc_update_noise_frag_glsl, e_data.lib, NULL);
}
return e_data.update_noise_sh;
}
GPUShader *EEVEE_shaders_taa_resolve_sh_get(EEVEE_EffectsFlag enabled_effects)
{
GPUShader **sh;
const char *define = NULL;
if (enabled_effects & EFFECT_TAA_REPROJECT) {
sh = &e_data.taa_resolve_reproject_sh;
define = "#define USE_REPROJECTION\n";
}
else {
sh = &e_data.taa_resolve_sh;
}
if (*sh == NULL) {
*sh = DRW_shader_create_fullscreen_with_shaderlib(
datatoc_effect_temporal_aa_glsl, e_data.lib, define);
}
return *sh;
}
/* -------------------------------------------------------------------- */
/** \name Bloom
* \{ */
GPUShader *EEVEE_shaders_bloom_blit_get(bool high_quality)
{
int index = high_quality ? 1 : 0;
if (e_data.bloom_blit_sh[index] == NULL) {
const char *define = high_quality ? "#define STEP_BLIT\n"
"#define HIGH_QUALITY\n" :
"#define STEP_BLIT\n";
e_data.bloom_blit_sh[index] = DRW_shader_create_fullscreen(datatoc_effect_bloom_frag_glsl,
define);
}
return e_data.bloom_blit_sh[index];
}
GPUShader *EEVEE_shaders_bloom_downsample_get(bool high_quality)
{
int index = high_quality ? 1 : 0;
if (e_data.bloom_downsample_sh[index] == NULL) {
const char *define = high_quality ? "#define STEP_DOWNSAMPLE\n"
"#define HIGH_QUALITY\n" :
"#define STEP_DOWNSAMPLE\n";
e_data.bloom_downsample_sh[index] = DRW_shader_create_fullscreen(
datatoc_effect_bloom_frag_glsl, define);
}
return e_data.bloom_downsample_sh[index];
}
GPUShader *EEVEE_shaders_bloom_upsample_get(bool high_quality)
{
int index = high_quality ? 1 : 0;
if (e_data.bloom_upsample_sh[index] == NULL) {
const char *define = high_quality ? "#define STEP_UPSAMPLE\n"
"#define HIGH_QUALITY\n" :
"#define STEP_UPSAMPLE\n";
e_data.bloom_upsample_sh[index] = DRW_shader_create_fullscreen(datatoc_effect_bloom_frag_glsl,
define);
}
return e_data.bloom_upsample_sh[index];
}
GPUShader *EEVEE_shaders_bloom_resolve_get(bool high_quality)
{
int index = high_quality ? 1 : 0;
if (e_data.bloom_resolve_sh[index] == NULL) {
const char *define = high_quality ? "#define STEP_RESOLVE\n"
"#define HIGH_QUALITY\n" :
"#define STEP_RESOLVE\n";
e_data.bloom_resolve_sh[index] = DRW_shader_create_fullscreen(datatoc_effect_bloom_frag_glsl,
define);
}
return e_data.bloom_resolve_sh[index];
}
/* \} */
/* -------------------------------------------------------------------- */
/** \name Depth of field
* \{ */
GPUShader *EEVEE_shaders_depth_of_field_downsample_get(bool use_alpha)
{
int index = use_alpha ? 1 : 0;
if (e_data.dof_downsample_sh[index] == NULL) {
e_data.dof_downsample_sh[index] = DRW_shader_create_fullscreen_with_shaderlib(
datatoc_effect_dof_frag_glsl,
e_data.lib,
use_alpha ? "#define USE_ALPHA_DOF\n"
"#define STEP_DOWNSAMPLE\n" :
"#define STEP_DOWNSAMPLE\n");
}
return e_data.dof_downsample_sh[index];
}
GPUShader *EEVEE_shaders_depth_of_field_scatter_get(bool use_alpha)
{
int index = use_alpha ? 1 : 0;
if (e_data.dof_scatter_sh[index] == NULL) {
e_data.dof_scatter_sh[index] = DRW_shader_create_with_shaderlib(datatoc_effect_dof_vert_glsl,
NULL,
datatoc_effect_dof_frag_glsl,
e_data.lib,
use_alpha ?
"#define USE_ALPHA_DOF\n"
"#define STEP_SCATTER\n" :
"#define STEP_SCATTER\n");
}
return e_data.dof_scatter_sh[index];
}
GPUShader *EEVEE_shaders_depth_of_field_resolve_get(bool use_alpha)
{
int index = use_alpha ? 1 : 0;
if (e_data.dof_resolve_sh[index] == NULL) {
e_data.dof_resolve_sh[index] = DRW_shader_create_fullscreen_with_shaderlib(
datatoc_effect_dof_frag_glsl,
e_data.lib,
use_alpha ? "#define USE_ALPHA_DOF\n"
"#define STEP_RESOLVE\n" :
"#define STEP_RESOLVE\n");
}
return e_data.dof_resolve_sh[index];
}
/* \} */
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;
}
World *EEVEE_world_default_get(void)
{
if (e_data.default_world == NULL) {
e_data.default_world = BKE_id_new_nomain(ID_WO, "EEVEEE default world");
copy_v3_fl(&e_data.default_world->horr, 0.0f);
e_data.default_world->use_nodes = 0;
e_data.default_world->nodetree = NULL;
BLI_listbase_clear(&e_data.default_world->gpumaterial);
}
return e_data.default_world;
}
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_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 = DRW_shader_library_create_shader_string(e_data.lib, datatoc_volumetric_vert_glsl);
}
else if ((options & (VAR_WORLD_PROBE | VAR_WORLD_BACKGROUND)) != 0) {
str = DRW_shader_library_create_shader_string(e_data.lib, datatoc_background_vert_glsl);
}
else {
str = DRW_shader_library_create_shader_string(e_data.lib, datatoc_surface_vert_glsl);
}
return str;
}
static char *eevee_get_geom(int options)
{
char *str = NULL;
if ((options & VAR_MAT_VOLUME) != 0) {
str = DRW_shader_library_create_shader_string(e_data.lib, datatoc_volumetric_geom_glsl);
}
return str;
}
static char *eevee_get_frag(int options)
{
char *str = NULL;
if ((options & VAR_MAT_VOLUME) != 0) {
str = DRW_shader_library_create_shader_string(e_data.lib, datatoc_volumetric_frag_glsl);
}
else if ((options & VAR_MAT_DEPTH) != 0) {
str = BLI_strdup(e_data.surface_prepass_frag);
}
else {
str = BLI_strdup(e_data.surface_lit_frag);
}
return str;
}
static void eevee_material_post_eval(GPUMaterial *mat,
int options,
const char **UNUSED(vert_code),
const char **geom_code,
const char **UNUSED(frag_lib),
const char **UNUSED(defines))
{
const bool is_hair = (options & VAR_MAT_HAIR) != 0;
const bool is_mesh = (options & VAR_MAT_MESH) != 0;
/* Force geometry usage if GPU_BARYCENTRIC_DIST or GPU_BARYCENTRIC_TEXCO are used.
* Note: GPU_BARYCENTRIC_TEXCO only requires it if the shader is not drawing hairs. */
if (!is_hair && is_mesh && GPU_material_flag_get(mat, GPU_MATFLAG_BARYCENTRIC) &&
*geom_code == NULL) {
*geom_code = e_data.surface_geom_barycentric;
}
}
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) {
GPUMaterialEvalCallbackFn cbfn = &eevee_material_post_eval;
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, cbfn);
}
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, NULL);
}
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 immediately. */
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.closure_lit_lib);
MEM_SAFE_FREE(e_data.surface_prepass_frag);
MEM_SAFE_FREE(e_data.surface_lit_frag);
MEM_SAFE_FREE(e_data.surface_geom_barycentric);
DRW_SHADER_FREE_SAFE(e_data.lookdev_background);
DRW_SHADER_FREE_SAFE(e_data.update_noise_sh);
DRW_SHADER_FREE_SAFE(e_data.downsample_sh);
DRW_SHADER_FREE_SAFE(e_data.downsample_cube_sh);
DRW_SHADER_FREE_SAFE(e_data.minz_downlevel_sh);
DRW_SHADER_FREE_SAFE(e_data.maxz_downlevel_sh);
DRW_SHADER_FREE_SAFE(e_data.minz_downdepth_sh);
DRW_SHADER_FREE_SAFE(e_data.maxz_downdepth_sh);
DRW_SHADER_FREE_SAFE(e_data.minz_downdepth_layer_sh);
DRW_SHADER_FREE_SAFE(e_data.maxz_downdepth_layer_sh);
DRW_SHADER_FREE_SAFE(e_data.maxz_copydepth_layer_sh);
DRW_SHADER_FREE_SAFE(e_data.minz_copydepth_sh);
DRW_SHADER_FREE_SAFE(e_data.maxz_copydepth_sh);
DRW_SHADER_FREE_SAFE(e_data.ggx_lut_sh);
DRW_SHADER_FREE_SAFE(e_data.ggx_refraction_lut_sh);
DRW_SHADER_FREE_SAFE(e_data.mist_sh);
DRW_SHADER_FREE_SAFE(e_data.motion_blur_sh);
DRW_SHADER_FREE_SAFE(e_data.motion_blur_object_sh);
DRW_SHADER_FREE_SAFE(e_data.motion_blur_hair_sh);
DRW_SHADER_FREE_SAFE(e_data.velocity_tiles_sh);
DRW_SHADER_FREE_SAFE(e_data.velocity_tiles_expand_sh);
DRW_SHADER_FREE_SAFE(e_data.gtao_sh);
DRW_SHADER_FREE_SAFE(e_data.gtao_layer_sh);
DRW_SHADER_FREE_SAFE(e_data.gtao_debug_sh);
DRW_SHADER_FREE_SAFE(e_data.velocity_resolve_sh);
DRW_SHADER_FREE_SAFE(e_data.postprocess_sh);
DRW_SHADER_FREE_SAFE(e_data.shadow_sh);
DRW_SHADER_FREE_SAFE(e_data.shadow_accum_sh);
DRW_SHADER_FREE_SAFE(e_data.sss_sh[0]);
DRW_SHADER_FREE_SAFE(e_data.sss_sh[1]);
DRW_SHADER_FREE_SAFE(e_data.sss_sh[2]);
DRW_SHADER_FREE_SAFE(e_data.volumetric_clear_sh);
DRW_SHADER_FREE_SAFE(e_data.scatter_sh);
DRW_SHADER_FREE_SAFE(e_data.scatter_with_lights_sh);
DRW_SHADER_FREE_SAFE(e_data.volumetric_integration_sh);
DRW_SHADER_FREE_SAFE(e_data.volumetric_resolve_sh[0]);
DRW_SHADER_FREE_SAFE(e_data.volumetric_resolve_sh[1]);
DRW_SHADER_FREE_SAFE(e_data.volumetric_accum_sh);
DRW_SHADER_FREE_SAFE(e_data.probe_filter_glossy_sh);
DRW_SHADER_FREE_SAFE(e_data.probe_filter_diffuse_sh);
DRW_SHADER_FREE_SAFE(e_data.probe_filter_visibility_sh);
DRW_SHADER_FREE_SAFE(e_data.probe_grid_fill_sh);
DRW_SHADER_FREE_SAFE(e_data.probe_planar_downsample_sh);
DRW_SHADER_FREE_SAFE(e_data.studiolight_probe_sh);
DRW_SHADER_FREE_SAFE(e_data.studiolight_background_sh);
DRW_SHADER_FREE_SAFE(e_data.probe_grid_display_sh);
DRW_SHADER_FREE_SAFE(e_data.probe_cube_display_sh);
DRW_SHADER_FREE_SAFE(e_data.probe_planar_display_sh);
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);
DRW_SHADER_FREE_SAFE(e_data.cryptomatte_sh[0]);
DRW_SHADER_FREE_SAFE(e_data.cryptomatte_sh[1]);
for (int i = 0; i < 2; i++) {
DRW_SHADER_FREE_SAFE(e_data.bloom_blit_sh[i]);
DRW_SHADER_FREE_SAFE(e_data.bloom_downsample_sh[i]);
DRW_SHADER_FREE_SAFE(e_data.bloom_upsample_sh[i]);
DRW_SHADER_FREE_SAFE(e_data.bloom_resolve_sh[i]);
DRW_SHADER_FREE_SAFE(e_data.dof_downsample_sh[i]);
DRW_SHADER_FREE_SAFE(e_data.dof_scatter_sh[i]);
DRW_SHADER_FREE_SAFE(e_data.dof_resolve_sh[i]);
}
for (int i = 0; i < SSR_MAX_SHADER; i++) {
DRW_SHADER_FREE_SAFE(e_data.ssr_sh[i]);
}
DRW_SHADER_LIB_FREE_SAFE(e_data.lib);
if (e_data.default_world) {
BKE_id_free(NULL, e_data.default_world);
e_data.default_world = NULL;
}
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;
}
}