Compare commits
30 Commits
obj-import
...
temp-ssr
Author | SHA1 | Date | |
---|---|---|---|
678c5e3752 | |||
e0eb879562 | |||
601b4ddfc0 | |||
455aeb1495 | |||
f359db1977 | |||
647f9c2325 | |||
03c0525b4c | |||
d2131b8f16 | |||
47044f7061 | |||
ada51744b6 | |||
b3472b67ea | |||
e785648f2e | |||
c02f8eb749 | |||
3272640d6e | |||
33d76061b6 | |||
79d4180c41 | |||
d8e2e4d490 | |||
e4c43b377d | |||
3c9b318b7e | |||
b8c8e27586 | |||
9857ee6cf1 | |||
ab0d7492e6 | |||
e1d4bb91d7 | |||
f3fdc1f4e2 | |||
644522da01 | |||
f3e8cd97fa | |||
93134fc578 | |||
76c323ff30 | |||
37653aaf58 | |||
471709176c |
@@ -710,6 +710,34 @@ class RENDER_PT_eevee_volumetric(RenderButtonsPanel, Panel):
|
||||
col.prop(props, "volumetric_colored_transmittance")
|
||||
|
||||
|
||||
class RENDER_PT_eevee_screen_space_reflections(RenderButtonsPanel, Panel):
|
||||
bl_label = "Screen Space Reflections"
|
||||
COMPAT_ENGINES = {'BLENDER_EEVEE'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
scene = context.scene
|
||||
return scene and (scene.render.engine in cls.COMPAT_ENGINES)
|
||||
|
||||
def draw_header(self, context):
|
||||
scene = context.scene
|
||||
props = scene.layer_properties['BLENDER_EEVEE']
|
||||
self.layout.prop(props, "ssr_enable", text="")
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
scene = context.scene
|
||||
props = scene.layer_properties['BLENDER_EEVEE']
|
||||
|
||||
col = layout.column()
|
||||
col.prop(props, "ssr_halfres")
|
||||
col.prop(props, "ssr_ray_count")
|
||||
col.prop(props, "ssr_stride")
|
||||
col.prop(props, "ssr_thickness")
|
||||
col.prop(props, "ssr_border_fade")
|
||||
col.prop(props, "ssr_firefly_fac")
|
||||
|
||||
|
||||
classes = (
|
||||
RENDER_MT_presets,
|
||||
RENDER_MT_ffmpeg_presets,
|
||||
@@ -727,9 +755,10 @@ classes = (
|
||||
RENDER_PT_bake,
|
||||
RENDER_PT_clay_layer_settings,
|
||||
RENDER_PT_clay_collection_settings,
|
||||
RENDER_PT_eevee_volumetric,
|
||||
RENDER_PT_eevee_screen_space_reflections,
|
||||
RENDER_PT_eevee_poststack_settings,
|
||||
RENDER_PT_eevee_postprocess_settings,
|
||||
RENDER_PT_eevee_volumetric,
|
||||
)
|
||||
|
||||
if __name__ == "__main__": # only for live edit.
|
||||
|
@@ -250,6 +250,39 @@ class RENDERLAYER_PT_eevee_volumetric(RenderLayerButtonsPanel, Panel):
|
||||
col.template_override_property(layer_props, scene_props, "volumetric_colored_transmittance")
|
||||
|
||||
|
||||
class RENDERLAYER_PT_eevee_screen_space_reflections(RenderLayerButtonsPanel, Panel):
|
||||
bl_label = "Screen Space Reflections"
|
||||
COMPAT_ENGINES = {'BLENDER_EEVEE'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
scene = context.scene
|
||||
return scene and (scene.render.engine in cls.COMPAT_ENGINES)
|
||||
|
||||
def draw_header(self, context):
|
||||
scene = context.scene
|
||||
scene_props = scene.layer_properties['BLENDER_EEVEE']
|
||||
layer = bpy.context.render_layer
|
||||
layer_props = layer.engine_overrides['BLENDER_EEVEE']
|
||||
|
||||
self.layout.template_override_property(layer_props, scene_props, "ssr_enable", text="")
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
scene = context.scene
|
||||
scene_props = scene.layer_properties['BLENDER_EEVEE']
|
||||
layer = bpy.context.render_layer
|
||||
layer_props = layer.engine_overrides['BLENDER_EEVEE']
|
||||
|
||||
col = layout.column()
|
||||
col.template_override_property(layer_props, scene_props, "ssr_halfres")
|
||||
col.template_override_property(layer_props, scene_props, "ssr_ray_count")
|
||||
col.template_override_property(layer_props, scene_props, "ssr_stride")
|
||||
col.template_override_property(layer_props, scene_props, "ssr_thickness")
|
||||
col.template_override_property(layer_props, scene_props, "ssr_border_fade")
|
||||
col.template_override_property(layer_props, scene_props, "ssr_firefly_fac")
|
||||
|
||||
|
||||
classes = (
|
||||
RENDERLAYER_UL_renderlayers,
|
||||
RENDERLAYER_PT_layers,
|
||||
@@ -258,6 +291,7 @@ classes = (
|
||||
RENDERLAYER_PT_clay_settings,
|
||||
RENDERLAYER_PT_eevee_poststack_settings,
|
||||
RENDERLAYER_PT_eevee_postprocess_settings,
|
||||
RENDERLAYER_PT_eevee_screen_space_reflections,
|
||||
RENDERLAYER_PT_eevee_volumetric,
|
||||
)
|
||||
|
||||
|
@@ -138,7 +138,9 @@ data_to_c_simple(engines/eevee/shaders/effect_bloom_frag.glsl SRC)
|
||||
data_to_c_simple(engines/eevee/shaders/effect_dof_vert.glsl SRC)
|
||||
data_to_c_simple(engines/eevee/shaders/effect_dof_geom.glsl SRC)
|
||||
data_to_c_simple(engines/eevee/shaders/effect_dof_frag.glsl SRC)
|
||||
data_to_c_simple(engines/eevee/shaders/effect_downsample_frag.glsl SRC)
|
||||
data_to_c_simple(engines/eevee/shaders/effect_motion_blur_frag.glsl SRC)
|
||||
data_to_c_simple(engines/eevee/shaders/effect_ssr_frag.glsl SRC)
|
||||
data_to_c_simple(engines/eevee/shaders/lightprobe_planar_downsample_frag.glsl SRC)
|
||||
data_to_c_simple(engines/eevee/shaders/lightprobe_planar_downsample_geom.glsl SRC)
|
||||
data_to_c_simple(engines/eevee/shaders/lightprobe_planar_downsample_vert.glsl SRC)
|
||||
@@ -156,6 +158,7 @@ data_to_c_simple(engines/eevee/shaders/bsdf_common_lib.glsl SRC)
|
||||
data_to_c_simple(engines/eevee/shaders/irradiance_lib.glsl SRC)
|
||||
data_to_c_simple(engines/eevee/shaders/octahedron_lib.glsl SRC)
|
||||
data_to_c_simple(engines/eevee/shaders/bsdf_sampling_lib.glsl SRC)
|
||||
data_to_c_simple(engines/eevee/shaders/raytrace_lib.glsl SRC)
|
||||
data_to_c_simple(engines/eevee/shaders/ltc_lib.glsl SRC)
|
||||
data_to_c_simple(engines/eevee/shaders/volumetric_frag.glsl SRC)
|
||||
|
||||
|
@@ -34,6 +34,7 @@
|
||||
#include "DNA_view3d_types.h"
|
||||
#include "DNA_world_types.h"
|
||||
|
||||
#include "BKE_global.h" /* for G.debug_value */
|
||||
#include "BKE_camera.h"
|
||||
#include "BKE_object.h"
|
||||
#include "BKE_animsys.h"
|
||||
@@ -43,16 +44,35 @@
|
||||
|
||||
#include "eevee_private.h"
|
||||
#include "GPU_texture.h"
|
||||
#include "GPU_framebuffer.h"
|
||||
|
||||
#define SHADER_DEFINES \
|
||||
"#define EEVEE_ENGINE\n" \
|
||||
"#define MAX_PROBE " STRINGIFY(MAX_PROBE) "\n" \
|
||||
"#define MAX_GRID " STRINGIFY(MAX_GRID) "\n" \
|
||||
"#define MAX_PLANAR " STRINGIFY(MAX_PLANAR) "\n"
|
||||
|
||||
typedef struct EEVEE_LightProbeData {
|
||||
short probe_id, shadow_id;
|
||||
} EEVEE_LightProbeData;
|
||||
|
||||
/* SSR shader variations */
|
||||
enum {
|
||||
SSR_RESOLVE = (1 << 0),
|
||||
SSR_FULL_TRACE = (1 << 1),
|
||||
SSR_MAX_SHADER = (1 << 2),
|
||||
};
|
||||
|
||||
static struct {
|
||||
/* Downsample Depth */
|
||||
struct GPUShader *minmaxz_downlevel_sh;
|
||||
struct GPUShader *minmaxz_downdepth_sh;
|
||||
struct GPUShader *minmaxz_copydepth_sh;
|
||||
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 *minz_copydepth_sh;
|
||||
struct GPUShader *maxz_copydepth_sh;
|
||||
|
||||
/* Motion Blur */
|
||||
struct GPUShader *motion_blur_sh;
|
||||
@@ -71,15 +91,32 @@ static struct {
|
||||
/* Volumetric */
|
||||
struct GPUShader *volumetric_upsample_sh;
|
||||
|
||||
/* Screen Space Reflection */
|
||||
struct GPUShader *ssr_sh[SSR_MAX_SHADER];
|
||||
|
||||
/* Simple Downsample */
|
||||
struct GPUShader *downsample_sh;
|
||||
|
||||
struct GPUTexture *depth_src;
|
||||
struct GPUTexture *color_src;
|
||||
int depth_src_layer;
|
||||
|
||||
float pixelprojmat[4][4];
|
||||
} e_data = {NULL}; /* Engine data */
|
||||
|
||||
extern char datatoc_bsdf_common_lib_glsl[];
|
||||
extern char datatoc_bsdf_sampling_lib_glsl[];
|
||||
extern char datatoc_octahedron_lib_glsl[];
|
||||
extern char datatoc_effect_ssr_frag_glsl[];
|
||||
extern char datatoc_effect_minmaxz_frag_glsl[];
|
||||
extern char datatoc_effect_motion_blur_frag_glsl[];
|
||||
extern char datatoc_effect_bloom_frag_glsl[];
|
||||
extern char datatoc_effect_dof_vert_glsl[];
|
||||
extern char datatoc_effect_dof_geom_glsl[];
|
||||
extern char datatoc_effect_dof_frag_glsl[];
|
||||
extern char datatoc_effect_downsample_frag_glsl[];
|
||||
extern char datatoc_lightprobe_lib_glsl[];
|
||||
extern char datatoc_raytrace_lib_glsl[];
|
||||
extern char datatoc_tonemap_frag_glsl[];
|
||||
extern char datatoc_volumetric_frag_glsl[];
|
||||
|
||||
@@ -134,6 +171,42 @@ static void eevee_motion_blur_camera_get_matrix_at_time(
|
||||
mul_m4_m4m4(r_mat, params.winmat, obmat);
|
||||
}
|
||||
|
||||
static struct GPUShader *eevee_effects_ssr_shader_get(int options)
|
||||
{
|
||||
if (e_data.ssr_sh[options] == NULL) {
|
||||
DynStr *ds_frag = BLI_dynstr_new();
|
||||
BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl);
|
||||
BLI_dynstr_append(ds_frag, datatoc_bsdf_sampling_lib_glsl);
|
||||
BLI_dynstr_append(ds_frag, datatoc_octahedron_lib_glsl);
|
||||
BLI_dynstr_append(ds_frag, datatoc_lightprobe_lib_glsl);
|
||||
BLI_dynstr_append(ds_frag, datatoc_raytrace_lib_glsl);
|
||||
BLI_dynstr_append(ds_frag, datatoc_effect_ssr_frag_glsl);
|
||||
char *ssr_shader_str = BLI_dynstr_get_cstring(ds_frag);
|
||||
BLI_dynstr_free(ds_frag);
|
||||
|
||||
DynStr *ds_defines = BLI_dynstr_new();
|
||||
BLI_dynstr_appendf(ds_defines, SHADER_DEFINES);
|
||||
if (options & SSR_RESOLVE) {
|
||||
BLI_dynstr_appendf(ds_defines, "#define STEP_RESOLVE\n");
|
||||
}
|
||||
else {
|
||||
BLI_dynstr_appendf(ds_defines, "#define STEP_RAYTRACE\n");
|
||||
}
|
||||
if (options & SSR_FULL_TRACE) {
|
||||
BLI_dynstr_appendf(ds_defines, "#define FULLRES\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(ssr_shader_str, ssr_define_str);
|
||||
|
||||
MEM_freeN(ssr_shader_str);
|
||||
MEM_freeN(ssr_define_str);
|
||||
}
|
||||
|
||||
return e_data.ssr_sh[options];
|
||||
}
|
||||
|
||||
void EEVEE_effects_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata)
|
||||
{
|
||||
EEVEE_StorageList *stl = vedata->stl;
|
||||
@@ -153,12 +226,28 @@ void EEVEE_effects_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata)
|
||||
|
||||
/* Shaders */
|
||||
if (!e_data.motion_blur_sh) {
|
||||
e_data.downsample_sh = DRW_shader_create_fullscreen(datatoc_effect_downsample_frag_glsl, NULL);
|
||||
|
||||
e_data.volumetric_upsample_sh = DRW_shader_create_fullscreen(datatoc_volumetric_frag_glsl, "#define STEP_UPSAMPLE\n");
|
||||
|
||||
e_data.minmaxz_downlevel_sh = DRW_shader_create_fullscreen(datatoc_effect_minmaxz_frag_glsl, NULL);
|
||||
e_data.minmaxz_downdepth_sh = DRW_shader_create_fullscreen(datatoc_effect_minmaxz_frag_glsl, "#define INPUT_DEPTH\n");
|
||||
e_data.minmaxz_copydepth_sh = DRW_shader_create_fullscreen(datatoc_effect_minmaxz_frag_glsl, "#define INPUT_DEPTH\n"
|
||||
"#define COPY_DEPTH\n");
|
||||
e_data.minz_downlevel_sh = DRW_shader_create_fullscreen(datatoc_effect_minmaxz_frag_glsl, "#define MIN_PASS\n");
|
||||
e_data.maxz_downlevel_sh = DRW_shader_create_fullscreen(datatoc_effect_minmaxz_frag_glsl, "#define MAX_PASS\n");
|
||||
e_data.minz_downdepth_sh = DRW_shader_create_fullscreen(datatoc_effect_minmaxz_frag_glsl, "#define MIN_PASS\n"
|
||||
"#define INPUT_DEPTH\n");
|
||||
e_data.maxz_downdepth_sh = DRW_shader_create_fullscreen(datatoc_effect_minmaxz_frag_glsl, "#define MAX_PASS\n"
|
||||
"#define INPUT_DEPTH\n");
|
||||
e_data.minz_downdepth_layer_sh = DRW_shader_create_fullscreen(datatoc_effect_minmaxz_frag_glsl, "#define MIN_PASS\n"
|
||||
"#define LAYERED\n"
|
||||
"#define INPUT_DEPTH\n");
|
||||
e_data.maxz_downdepth_layer_sh = DRW_shader_create_fullscreen(datatoc_effect_minmaxz_frag_glsl, "#define MAX_PASS\n"
|
||||
"#define LAYERED\n"
|
||||
"#define INPUT_DEPTH\n");
|
||||
e_data.minz_copydepth_sh = DRW_shader_create_fullscreen(datatoc_effect_minmaxz_frag_glsl, "#define MIN_PASS\n"
|
||||
"#define INPUT_DEPTH\n"
|
||||
"#define COPY_DEPTH\n");
|
||||
e_data.maxz_copydepth_sh = DRW_shader_create_fullscreen(datatoc_effect_minmaxz_frag_glsl, "#define MAX_PASS\n"
|
||||
"#define INPUT_DEPTH\n"
|
||||
"#define COPY_DEPTH\n");
|
||||
|
||||
e_data.motion_blur_sh = DRW_shader_create_fullscreen(datatoc_effect_motion_blur_frag_glsl, NULL);
|
||||
|
||||
@@ -395,12 +484,16 @@ void EEVEE_effects_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata)
|
||||
}
|
||||
|
||||
/* MinMax Pyramid */
|
||||
/* TODO reduce precision */
|
||||
DRWFboTexture tex = {&stl->g_data->minmaxz, DRW_TEX_RG_32, DRW_TEX_MIPMAP | DRW_TEX_TEMP};
|
||||
DRWFboTexture texmin = {&stl->g_data->minzbuffer, DRW_TEX_DEPTH_24, DRW_TEX_MIPMAP | DRW_TEX_TEMP};
|
||||
|
||||
DRW_framebuffer_init(&fbl->minmaxz_fb, &draw_engine_eevee_type,
|
||||
DRW_framebuffer_init(&fbl->downsample_fb, &draw_engine_eevee_type,
|
||||
(int)viewport_size[0] / 2, (int)viewport_size[1] / 2,
|
||||
&tex, 1);
|
||||
&texmin, 1);
|
||||
|
||||
/* Cannot define 2 depth texture for one framebuffer. So allocate ourself. */
|
||||
if (txl->maxzbuffer == NULL) {
|
||||
txl->maxzbuffer = DRW_texture_create_2D((int)viewport_size[0] / 2, (int)viewport_size[1] / 2, DRW_TEX_DEPTH_24, DRW_TEX_MIPMAP, NULL);
|
||||
}
|
||||
|
||||
if (BKE_collection_engine_property_value_get_bool(props, "volumetric_enable")) {
|
||||
World *wo = scene->world;
|
||||
@@ -473,6 +566,97 @@ void EEVEE_effects_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (BKE_collection_engine_property_value_get_bool(props, "ssr_enable")) {
|
||||
effects->enabled_effects |= EFFECT_SSR;
|
||||
|
||||
/* Enable double buffering to be able to read previous frame color */
|
||||
effects->enabled_effects |= EFFECT_DOUBLE_BUFFER;
|
||||
|
||||
effects->ssr_ray_count = BKE_collection_engine_property_value_get_int(props, "ssr_ray_count");
|
||||
effects->reflection_trace_full = !BKE_collection_engine_property_value_get_bool(props, "ssr_halfres");
|
||||
effects->ssr_use_normalization = BKE_collection_engine_property_value_get_bool(props, "ssr_normalize_weight");
|
||||
effects->ssr_stride = (float)BKE_collection_engine_property_value_get_int(props, "ssr_stride");
|
||||
effects->ssr_thickness = BKE_collection_engine_property_value_get_float(props, "ssr_thickness");
|
||||
effects->ssr_border_fac = BKE_collection_engine_property_value_get_float(props, "ssr_border_fade");
|
||||
effects->ssr_firefly_fac = BKE_collection_engine_property_value_get_float(props, "ssr_firefly_fac");
|
||||
|
||||
/* Important, can lead to breakage otherwise. */
|
||||
CLAMP(effects->ssr_ray_count, 1, 4);
|
||||
|
||||
const int divisor = (effects->reflection_trace_full) ? 1 : 2;
|
||||
int tracing_res[2] = {(int)viewport_size[0] / divisor, (int)viewport_size[1] / divisor};
|
||||
const bool high_qual_input = true; /* TODO dither low quality input */
|
||||
|
||||
/* MRT for the shading pass in order to output needed data for the SSR pass. */
|
||||
/* TODO create one texture layer per lobe */
|
||||
if (txl->ssr_normal_input == NULL) {
|
||||
DRWTextureFormat nor_format = DRW_TEX_RG_16;
|
||||
txl->ssr_normal_input = DRW_texture_create_2D((int)viewport_size[0], (int)viewport_size[1], nor_format, 0, NULL);
|
||||
}
|
||||
|
||||
if (txl->ssr_specrough_input == NULL) {
|
||||
DRWTextureFormat specrough_format = (high_qual_input) ? DRW_TEX_RGBA_16 : DRW_TEX_RGBA_8;
|
||||
txl->ssr_specrough_input = DRW_texture_create_2D((int)viewport_size[0], (int)viewport_size[1], specrough_format, 0, NULL);
|
||||
}
|
||||
|
||||
/* Reattach textures to the right buffer (because we are alternating between buffers) */
|
||||
/* TODO multiple FBO per texture!!!! */
|
||||
DRW_framebuffer_texture_detach(txl->ssr_normal_input);
|
||||
DRW_framebuffer_texture_detach(txl->ssr_specrough_input);
|
||||
DRW_framebuffer_texture_attach(fbl->main, txl->ssr_normal_input, 1, 0);
|
||||
DRW_framebuffer_texture_attach(fbl->main, txl->ssr_specrough_input, 2, 0);
|
||||
|
||||
/* Raytracing output */
|
||||
/* TODO try integer format for hit coord to increase precision */
|
||||
DRWFboTexture tex_output[4] = {{&stl->g_data->ssr_hit_output[0], DRW_TEX_RGBA_16, DRW_TEX_TEMP},
|
||||
{&stl->g_data->ssr_hit_output[1], DRW_TEX_RGBA_16, DRW_TEX_TEMP},
|
||||
{&stl->g_data->ssr_hit_output[2], DRW_TEX_RGBA_16, DRW_TEX_TEMP},
|
||||
{&stl->g_data->ssr_hit_output[3], DRW_TEX_RGBA_16, DRW_TEX_TEMP}};
|
||||
|
||||
DRW_framebuffer_init(&fbl->screen_tracing_fb, &draw_engine_eevee_type, tracing_res[0], tracing_res[1], tex_output, effects->ssr_ray_count);
|
||||
|
||||
/* Compute pixel projection matrix */
|
||||
{
|
||||
float uvpix[4][4], ndcuv[4][4], tmp[4][4], winmat[4][4];
|
||||
DRW_viewport_matrix_get(winmat, DRW_MAT_WIN);
|
||||
|
||||
/* NDC to UVs */
|
||||
unit_m4(ndcuv);
|
||||
ndcuv[0][0] = ndcuv[1][1] = ndcuv[3][0] = ndcuv[3][1] = 0.5f;
|
||||
|
||||
/* UVs to pixels */
|
||||
unit_m4(uvpix);
|
||||
uvpix[0][0] = viewport_size[0];
|
||||
uvpix[1][1] = viewport_size[1];
|
||||
|
||||
mul_m4_m4m4(tmp, uvpix, ndcuv);
|
||||
mul_m4_m4m4(e_data.pixelprojmat, tmp, winmat);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Cleanup to release memory */
|
||||
DRW_TEXTURE_FREE_SAFE(txl->ssr_normal_input);
|
||||
DRW_TEXTURE_FREE_SAFE(txl->ssr_specrough_input);
|
||||
DRW_FRAMEBUFFER_FREE_SAFE(fbl->screen_tracing_fb);
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
stl->g_data->ssr_hit_output[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Setup double buffer so we can access last frame as it was before post processes */
|
||||
if ((effects->enabled_effects & EFFECT_DOUBLE_BUFFER) != 0) {
|
||||
DRWFboTexture tex_double_buffer = {&txl->color_double_buffer, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER | DRW_TEX_MIPMAP};
|
||||
|
||||
DRW_framebuffer_init(&fbl->double_buffer, &draw_engine_eevee_type,
|
||||
(int)viewport_size[0], (int)viewport_size[1],
|
||||
&tex_double_buffer, 1);
|
||||
}
|
||||
else {
|
||||
/* Cleanup to release memory */
|
||||
DRW_TEXTURE_FREE_SAFE(txl->color_double_buffer);
|
||||
DRW_FRAMEBUFFER_FREE_SAFE(fbl->double_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
static DRWShadingGroup *eevee_create_bloom_pass(const char *name, EEVEE_EffectsInfo *effects, struct GPUShader *sh, DRWPass **pass, bool upsample)
|
||||
@@ -561,19 +745,100 @@ void EEVEE_effects_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata)
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
psl->minmaxz_downlevel = DRW_pass_create("HiZ Down Level", DRW_STATE_WRITE_COLOR);
|
||||
DRWShadingGroup *grp = DRW_shgroup_create(e_data.minmaxz_downlevel_sh, psl->minmaxz_downlevel);
|
||||
DRW_shgroup_uniform_buffer(grp, "depthBuffer", &stl->g_data->minmaxz);
|
||||
if ((effects->enabled_effects & EFFECT_SSR) != 0) {
|
||||
int options = (effects->reflection_trace_full) ? SSR_FULL_TRACE : 0;
|
||||
|
||||
struct GPUShader *trace_shader = eevee_effects_ssr_shader_get(options);
|
||||
struct GPUShader *resolve_shader = eevee_effects_ssr_shader_get(SSR_RESOLVE | options);
|
||||
|
||||
psl->ssr_raytrace = DRW_pass_create("SSR Raytrace", DRW_STATE_WRITE_COLOR);
|
||||
DRWShadingGroup *grp = DRW_shgroup_create(trace_shader, psl->ssr_raytrace);
|
||||
DRW_shgroup_uniform_buffer(grp, "depthBuffer", &e_data.depth_src);
|
||||
DRW_shgroup_uniform_buffer(grp, "normalBuffer", &txl->ssr_normal_input);
|
||||
DRW_shgroup_uniform_buffer(grp, "specroughBuffer", &txl->ssr_specrough_input);
|
||||
DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex());
|
||||
DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2);
|
||||
DRW_shgroup_uniform_vec2(grp, "ssrParameters", &effects->ssr_stride, 1);
|
||||
DRW_shgroup_uniform_mat4(grp, "PixelProjMatrix", (float *)&e_data.pixelprojmat);
|
||||
DRW_shgroup_uniform_int(grp, "rayCount", &effects->ssr_ray_count, 1);
|
||||
DRW_shgroup_call_add(grp, quad, NULL);
|
||||
|
||||
psl->minmaxz_downdepth = DRW_pass_create("HiZ Down Depth", DRW_STATE_WRITE_COLOR);
|
||||
grp = DRW_shgroup_create(e_data.minmaxz_downdepth_sh, psl->minmaxz_downdepth);
|
||||
psl->ssr_resolve = DRW_pass_create("SSR Resolve", DRW_STATE_WRITE_COLOR | DRW_STATE_ADDITIVE);
|
||||
grp = DRW_shgroup_create(resolve_shader, psl->ssr_resolve);
|
||||
DRW_shgroup_uniform_buffer(grp, "depthBuffer", &e_data.depth_src);
|
||||
DRW_shgroup_uniform_buffer(grp, "normalBuffer", &txl->ssr_normal_input);
|
||||
DRW_shgroup_uniform_buffer(grp, "specroughBuffer", &txl->ssr_specrough_input);
|
||||
DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex());
|
||||
DRW_shgroup_uniform_buffer(grp, "colorBuffer", &txl->color_double_buffer);
|
||||
DRW_shgroup_uniform_mat4(grp, "PastViewProjectionMatrix", (float *)stl->g_data->prev_persmat);
|
||||
DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2);
|
||||
DRW_shgroup_uniform_int(grp, "probe_count", &sldata->probes->num_render_cube, 1);
|
||||
DRW_shgroup_uniform_float(grp, "borderFadeFactor", &effects->ssr_border_fac, 1);
|
||||
DRW_shgroup_uniform_float(grp, "lodCubeMax", &sldata->probes->lod_cube_max, 1);
|
||||
DRW_shgroup_uniform_float(grp, "lodPlanarMax", &sldata->probes->lod_planar_max, 1);
|
||||
DRW_shgroup_uniform_float(grp, "fireflyFactor", &effects->ssr_firefly_fac, 1);
|
||||
DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo);
|
||||
DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo);
|
||||
DRW_shgroup_uniform_buffer(grp, "probeCubes", &sldata->probe_pool);
|
||||
DRW_shgroup_uniform_buffer(grp, "probePlanars", &vedata->txl->planar_pool);
|
||||
DRW_shgroup_uniform_buffer(grp, "hitBuffer0", &stl->g_data->ssr_hit_output[0]);
|
||||
DRW_shgroup_uniform_buffer(grp, "hitBuffer1", (effects->ssr_ray_count < 2) ? &stl->g_data->ssr_hit_output[0] : &stl->g_data->ssr_hit_output[1]);
|
||||
DRW_shgroup_uniform_buffer(grp, "hitBuffer2", (effects->ssr_ray_count < 3) ? &stl->g_data->ssr_hit_output[0] : &stl->g_data->ssr_hit_output[2]);
|
||||
DRW_shgroup_uniform_buffer(grp, "hitBuffer3", (effects->ssr_ray_count < 4) ? &stl->g_data->ssr_hit_output[0] : &stl->g_data->ssr_hit_output[3]);
|
||||
DRW_shgroup_uniform_int(grp, "rayCount", &effects->ssr_ray_count, 1);
|
||||
DRW_shgroup_call_add(grp, quad, NULL);
|
||||
}
|
||||
|
||||
{
|
||||
psl->color_downsample_ps = DRW_pass_create("Downsample", DRW_STATE_WRITE_COLOR);
|
||||
DRWShadingGroup *grp = DRW_shgroup_create(e_data.downsample_sh, psl->color_downsample_ps);
|
||||
DRW_shgroup_uniform_buffer(grp, "source", &e_data.color_src);
|
||||
DRW_shgroup_call_add(grp, quad, NULL);
|
||||
}
|
||||
|
||||
{
|
||||
/* Perform min/max downsample */
|
||||
psl->minz_downlevel_ps = DRW_pass_create("HiZ Min Down Level", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS);
|
||||
DRWShadingGroup *grp = DRW_shgroup_create(e_data.minz_downlevel_sh, psl->minz_downlevel_ps);
|
||||
DRW_shgroup_uniform_buffer(grp, "depthBuffer", &stl->g_data->minzbuffer);
|
||||
DRW_shgroup_call_add(grp, quad, NULL);
|
||||
|
||||
psl->maxz_downlevel_ps = DRW_pass_create("HiZ Max Down Level", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS);
|
||||
grp = DRW_shgroup_create(e_data.maxz_downlevel_sh, psl->maxz_downlevel_ps);
|
||||
DRW_shgroup_uniform_buffer(grp, "depthBuffer", &txl->maxzbuffer);
|
||||
DRW_shgroup_call_add(grp, quad, NULL);
|
||||
|
||||
/* Copy depth buffer to halfres top level of HiZ */
|
||||
psl->minz_downdepth_ps = DRW_pass_create("HiZ Min Copy Depth Halfres", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS);
|
||||
grp = DRW_shgroup_create(e_data.minz_downdepth_sh, psl->minz_downdepth_ps);
|
||||
DRW_shgroup_uniform_buffer(grp, "depthBuffer", &e_data.depth_src);
|
||||
DRW_shgroup_call_add(grp, quad, NULL);
|
||||
|
||||
psl->minmaxz_copydepth = DRW_pass_create("HiZ Copy Depth", DRW_STATE_WRITE_COLOR);
|
||||
grp = DRW_shgroup_create(e_data.minmaxz_copydepth_sh, psl->minmaxz_copydepth);
|
||||
psl->maxz_downdepth_ps = DRW_pass_create("HiZ Max Copy Depth Halfres", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS);
|
||||
grp = DRW_shgroup_create(e_data.maxz_downdepth_sh, psl->maxz_downdepth_ps);
|
||||
DRW_shgroup_uniform_buffer(grp, "depthBuffer", &e_data.depth_src);
|
||||
DRW_shgroup_call_add(grp, quad, NULL);
|
||||
|
||||
psl->minz_downdepth_layer_ps = DRW_pass_create("HiZ Min Copy DepthLayer Halfres", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS);
|
||||
grp = DRW_shgroup_create(e_data.minz_downdepth_layer_sh, psl->minz_downdepth_layer_ps);
|
||||
DRW_shgroup_uniform_buffer(grp, "depthBuffer", &e_data.depth_src);
|
||||
DRW_shgroup_uniform_int(grp, "depthLayer", &e_data.depth_src_layer, 1);
|
||||
DRW_shgroup_call_add(grp, quad, NULL);
|
||||
|
||||
psl->maxz_downdepth_layer_ps = DRW_pass_create("HiZ Max Copy DepthLayer Halfres", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS);
|
||||
grp = DRW_shgroup_create(e_data.maxz_downdepth_layer_sh, psl->maxz_downdepth_layer_ps);
|
||||
DRW_shgroup_uniform_buffer(grp, "depthBuffer", &e_data.depth_src);
|
||||
DRW_shgroup_uniform_int(grp, "depthLayer", &e_data.depth_src_layer, 1);
|
||||
DRW_shgroup_call_add(grp, quad, NULL);
|
||||
|
||||
/* Copy depth buffer to halfres top level of HiZ */
|
||||
psl->minz_copydepth_ps = DRW_pass_create("HiZ Min Copy Depth Fullres", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS);
|
||||
grp = DRW_shgroup_create(e_data.minz_copydepth_sh, psl->minz_copydepth_ps);
|
||||
DRW_shgroup_uniform_buffer(grp, "depthBuffer", &e_data.depth_src);
|
||||
DRW_shgroup_call_add(grp, quad, NULL);
|
||||
|
||||
psl->maxz_copydepth_ps = DRW_pass_create("HiZ Max Copy Depth Fullres", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS);
|
||||
grp = DRW_shgroup_create(e_data.maxz_copydepth_sh, psl->maxz_copydepth_ps);
|
||||
DRW_shgroup_uniform_buffer(grp, "depthBuffer", &e_data.depth_src);
|
||||
DRW_shgroup_call_add(grp, quad, NULL);
|
||||
}
|
||||
@@ -678,39 +943,73 @@ void EEVEE_effects_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata)
|
||||
}
|
||||
}
|
||||
|
||||
#define SWAP_BUFFERS() { \
|
||||
if (effects->source_buffer == txl->color) { \
|
||||
effects->source_buffer = txl->color_post; \
|
||||
effects->target_buffer = fbl->main; \
|
||||
} \
|
||||
else { \
|
||||
effects->source_buffer = txl->color; \
|
||||
effects->target_buffer = fbl->effect_fb; \
|
||||
} \
|
||||
} ((void)0)
|
||||
|
||||
static void minmax_downsample_cb(void *vedata, int UNUSED(level))
|
||||
static void min_downsample_cb(void *vedata, int UNUSED(level))
|
||||
{
|
||||
EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl;
|
||||
DRW_draw_pass(psl->minmaxz_downlevel);
|
||||
DRW_draw_pass(psl->minz_downlevel_ps);
|
||||
}
|
||||
|
||||
void EEVEE_create_minmax_buffer(EEVEE_Data *vedata, GPUTexture *depth_src)
|
||||
static void max_downsample_cb(void *vedata, int UNUSED(level))
|
||||
{
|
||||
EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl;
|
||||
DRW_draw_pass(psl->maxz_downlevel_ps);
|
||||
}
|
||||
|
||||
static void simple_downsample_cb(void *vedata, int UNUSED(level))
|
||||
{
|
||||
EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl;
|
||||
DRW_draw_pass(psl->color_downsample_ps);
|
||||
}
|
||||
|
||||
void EEVEE_create_minmax_buffer(EEVEE_Data *vedata, GPUTexture *depth_src, int layer)
|
||||
{
|
||||
EEVEE_PassList *psl = vedata->psl;
|
||||
EEVEE_FramebufferList *fbl = vedata->fbl;
|
||||
EEVEE_StorageList *stl = vedata->stl;
|
||||
EEVEE_TextureList *txl = vedata->txl;
|
||||
|
||||
e_data.depth_src = depth_src;
|
||||
|
||||
/* Copy depth buffer to minmax texture top level */
|
||||
DRW_framebuffer_texture_attach(fbl->minmaxz_fb, stl->g_data->minmaxz, 0, 0);
|
||||
DRW_framebuffer_bind(fbl->minmaxz_fb);
|
||||
DRW_draw_pass(psl->minmaxz_downdepth);
|
||||
DRW_framebuffer_texture_detach(stl->g_data->minmaxz);
|
||||
/* Copy depth buffer to min texture top level */
|
||||
DRW_framebuffer_texture_attach(fbl->downsample_fb, stl->g_data->minzbuffer, 0, 0);
|
||||
DRW_framebuffer_bind(fbl->downsample_fb);
|
||||
if (layer >= 0) {
|
||||
e_data.depth_src_layer = layer;
|
||||
DRW_draw_pass(psl->minz_downdepth_layer_ps);
|
||||
}
|
||||
else {
|
||||
DRW_draw_pass(psl->minz_downdepth_ps);
|
||||
}
|
||||
DRW_framebuffer_texture_detach(stl->g_data->minzbuffer);
|
||||
|
||||
/* Create lower levels */
|
||||
DRW_framebuffer_recursive_downsample(fbl->minmaxz_fb, stl->g_data->minmaxz, 6, &minmax_downsample_cb, vedata);
|
||||
DRW_framebuffer_recursive_downsample(fbl->downsample_fb, stl->g_data->minzbuffer, 8, &min_downsample_cb, vedata);
|
||||
|
||||
/* Copy depth buffer to max texture top level */
|
||||
DRW_framebuffer_texture_attach(fbl->downsample_fb, txl->maxzbuffer, 0, 0);
|
||||
DRW_framebuffer_bind(fbl->downsample_fb);
|
||||
if (layer >= 0) {
|
||||
e_data.depth_src_layer = layer;
|
||||
DRW_draw_pass(psl->maxz_downdepth_layer_ps);
|
||||
}
|
||||
else {
|
||||
DRW_draw_pass(psl->maxz_downdepth_ps);
|
||||
}
|
||||
DRW_framebuffer_texture_detach(txl->maxzbuffer);
|
||||
|
||||
/* Create lower levels */
|
||||
DRW_framebuffer_recursive_downsample(fbl->downsample_fb, txl->maxzbuffer, 8, &max_downsample_cb, vedata);
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple downsampling algorithm. Reconstruct mip chain up to mip level.
|
||||
**/
|
||||
void EEVEE_downsample_buffer(EEVEE_Data *vedata, struct GPUFrameBuffer *fb_src, GPUTexture *texture_src, int level)
|
||||
{
|
||||
e_data.color_src = texture_src;
|
||||
|
||||
/* Create lower levels */
|
||||
DRW_framebuffer_recursive_downsample(fb_src, texture_src, level, &simple_downsample_cb, vedata);
|
||||
}
|
||||
|
||||
void EEVEE_effects_do_volumetrics(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata)
|
||||
@@ -753,6 +1052,72 @@ void EEVEE_effects_do_volumetrics(EEVEE_SceneLayerData *sldata, EEVEE_Data *veda
|
||||
}
|
||||
}
|
||||
|
||||
void EEVEE_effects_do_ssr(EEVEE_SceneLayerData *UNUSED(sldata), EEVEE_Data *vedata)
|
||||
{
|
||||
EEVEE_PassList *psl = vedata->psl;
|
||||
EEVEE_FramebufferList *fbl = vedata->fbl;
|
||||
EEVEE_StorageList *stl = vedata->stl;
|
||||
EEVEE_TextureList *txl = vedata->txl;
|
||||
EEVEE_EffectsInfo *effects = stl->effects;
|
||||
|
||||
if ((effects->enabled_effects & EFFECT_SSR) != 0) {
|
||||
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
|
||||
e_data.depth_src = dtxl->depth;
|
||||
|
||||
for (int i = 0; i < effects->ssr_ray_count; ++i) {
|
||||
DRW_framebuffer_texture_attach(fbl->screen_tracing_fb, stl->g_data->ssr_hit_output[i], i, 0);
|
||||
}
|
||||
DRW_framebuffer_bind(fbl->screen_tracing_fb);
|
||||
|
||||
if (stl->g_data->valid_double_buffer) {
|
||||
/* Raytrace. */
|
||||
DRW_draw_pass(psl->ssr_raytrace);
|
||||
}
|
||||
else {
|
||||
float clear_col[4] = {0.0f, 0.0f, -1.0f, 0.001f};
|
||||
DRW_framebuffer_clear(true, false, false, clear_col, 0.0f);
|
||||
}
|
||||
|
||||
for (int i = 0; i < effects->ssr_ray_count; ++i) {
|
||||
DRW_framebuffer_texture_detach(stl->g_data->ssr_hit_output[i]);
|
||||
}
|
||||
|
||||
EEVEE_downsample_buffer(vedata, fbl->downsample_fb, txl->color_double_buffer, 9);
|
||||
|
||||
/* Resolve at fullres */
|
||||
DRW_framebuffer_texture_detach(dtxl->depth);
|
||||
DRW_framebuffer_texture_detach(txl->ssr_normal_input);
|
||||
DRW_framebuffer_texture_detach(txl->ssr_specrough_input);
|
||||
DRW_framebuffer_bind(fbl->main);
|
||||
DRW_draw_pass(psl->ssr_resolve);
|
||||
|
||||
/* Restore */
|
||||
DRW_framebuffer_texture_attach(fbl->main, dtxl->depth, 0, 0);
|
||||
DRW_framebuffer_texture_attach(fbl->main, txl->ssr_normal_input, 1, 0);
|
||||
DRW_framebuffer_texture_attach(fbl->main, txl->ssr_specrough_input, 2, 0);
|
||||
}
|
||||
}
|
||||
|
||||
#define SWAP_DOUBLE_BUFFERS() { \
|
||||
if (swap_double_buffer) { \
|
||||
SWAP(struct GPUFrameBuffer *, fbl->main, fbl->double_buffer); \
|
||||
SWAP(GPUTexture *, txl->color, txl->color_double_buffer); \
|
||||
swap_double_buffer = false; \
|
||||
} \
|
||||
} ((void)0)
|
||||
|
||||
#define SWAP_BUFFERS() { \
|
||||
if (effects->source_buffer == txl->color) { \
|
||||
effects->source_buffer = txl->color_post; \
|
||||
effects->target_buffer = fbl->main; \
|
||||
} \
|
||||
else { \
|
||||
effects->source_buffer = txl->color; \
|
||||
effects->target_buffer = fbl->effect_fb; \
|
||||
} \
|
||||
SWAP_DOUBLE_BUFFERS(); \
|
||||
} ((void)0)
|
||||
|
||||
void EEVEE_draw_effects(EEVEE_Data *vedata)
|
||||
{
|
||||
EEVEE_PassList *psl = vedata->psl;
|
||||
@@ -761,6 +1126,9 @@ void EEVEE_draw_effects(EEVEE_Data *vedata)
|
||||
EEVEE_StorageList *stl = vedata->stl;
|
||||
EEVEE_EffectsInfo *effects = stl->effects;
|
||||
|
||||
/* only once per frame after the first post process */
|
||||
bool swap_double_buffer = ((effects->enabled_effects & EFFECT_DOUBLE_BUFFER) != 0);
|
||||
|
||||
/* Default framebuffer and texture */
|
||||
DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
|
||||
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
|
||||
@@ -872,15 +1240,68 @@ void EEVEE_draw_effects(EEVEE_Data *vedata)
|
||||
|
||||
/* Tonemapping */
|
||||
DRW_transform_to_display(effects->source_buffer);
|
||||
|
||||
/* Debug : Ouput buffer to view. */
|
||||
if ((G.debug_value > 0) && (G.debug_value <= 5)) {
|
||||
switch (G.debug_value) {
|
||||
case 1:
|
||||
if (stl->g_data->minzbuffer) DRW_transform_to_display(stl->g_data->minzbuffer);
|
||||
break;
|
||||
case 2:
|
||||
if (stl->g_data->ssr_hit_output[0]) DRW_transform_to_display(stl->g_data->ssr_hit_output[0]);
|
||||
break;
|
||||
case 3:
|
||||
if (txl->ssr_normal_input) DRW_transform_to_display(txl->ssr_normal_input);
|
||||
break;
|
||||
case 4:
|
||||
if (txl->ssr_specrough_input) DRW_transform_to_display(txl->ssr_specrough_input);
|
||||
break;
|
||||
case 5:
|
||||
if (txl->color_double_buffer) DRW_transform_to_display(txl->color_double_buffer);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* If no post processes is enabled, buffers are still not swapped, do it now. */
|
||||
SWAP_DOUBLE_BUFFERS();
|
||||
|
||||
if (!stl->g_data->valid_double_buffer &&
|
||||
((effects->enabled_effects & EFFECT_DOUBLE_BUFFER) != 0) &&
|
||||
(DRW_state_is_image_render() == false))
|
||||
{
|
||||
/* If history buffer is not valid request another frame.
|
||||
* This fix black reflections on area resize. */
|
||||
DRW_viewport_request_redraw();
|
||||
}
|
||||
|
||||
/* Record pers matrix for the next frame. */
|
||||
DRW_viewport_matrix_get(stl->g_data->prev_persmat, DRW_MAT_PERS);
|
||||
|
||||
/* Update double buffer status if render mode. */
|
||||
if (DRW_state_is_image_render()) {
|
||||
stl->g_data->valid_double_buffer = (txl->color_double_buffer != NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void EEVEE_effects_free(void)
|
||||
{
|
||||
for (int i = 0; i < SSR_MAX_SHADER; ++i) {
|
||||
DRW_SHADER_FREE_SAFE(e_data.ssr_sh[i]);
|
||||
}
|
||||
DRW_SHADER_FREE_SAFE(e_data.downsample_sh);
|
||||
|
||||
DRW_SHADER_FREE_SAFE(e_data.volumetric_upsample_sh);
|
||||
|
||||
DRW_SHADER_FREE_SAFE(e_data.minmaxz_downlevel_sh);
|
||||
DRW_SHADER_FREE_SAFE(e_data.minmaxz_downdepth_sh);
|
||||
DRW_SHADER_FREE_SAFE(e_data.minmaxz_copydepth_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.minz_copydepth_sh);
|
||||
DRW_SHADER_FREE_SAFE(e_data.maxz_copydepth_sh);
|
||||
|
||||
DRW_SHADER_FREE_SAFE(e_data.motion_blur_sh);
|
||||
DRW_SHADER_FREE_SAFE(e_data.dof_downsample_sh);
|
||||
|
@@ -49,18 +49,19 @@ static void EEVEE_engine_init(void *ved)
|
||||
EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl;
|
||||
EEVEE_SceneLayerData *sldata = EEVEE_scene_layer_data_get();
|
||||
|
||||
DRWFboTexture tex = {&txl->color, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER};
|
||||
|
||||
const float *viewport_size = DRW_viewport_size_get();
|
||||
DRW_framebuffer_init(&fbl->main, &draw_engine_eevee_type,
|
||||
(int)viewport_size[0], (int)viewport_size[1],
|
||||
&tex, 1);
|
||||
|
||||
if (!stl->g_data) {
|
||||
/* Alloc transient pointers */
|
||||
stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__);
|
||||
}
|
||||
stl->g_data->background_alpha = 1.0f;
|
||||
stl->g_data->valid_double_buffer = (txl->color_double_buffer != NULL);
|
||||
|
||||
DRWFboTexture tex = {&txl->color, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER | DRW_TEX_MIPMAP};
|
||||
|
||||
const float *viewport_size = DRW_viewport_size_get();
|
||||
DRW_framebuffer_init(&fbl->main, &draw_engine_eevee_type,
|
||||
(int)viewport_size[0], (int)viewport_size[1],
|
||||
&tex, 1);
|
||||
|
||||
EEVEE_materials_init(stl);
|
||||
EEVEE_lights_init(sldata);
|
||||
@@ -133,44 +134,54 @@ static void EEVEE_draw_scene(void *vedata)
|
||||
/* Default framebuffer and texture */
|
||||
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
|
||||
|
||||
/* Refresh shadows */
|
||||
EEVEE_draw_shadows(sldata, psl);
|
||||
/* Number of iteration: needed for all temporal effect (SSR, TAA)
|
||||
* when using opengl render. */
|
||||
int loop_ct = DRW_state_is_image_render() ? 4 : 1;
|
||||
|
||||
/* Refresh Probes */
|
||||
EEVEE_lightprobes_refresh(sldata, vedata);
|
||||
while (loop_ct--) {
|
||||
/* Refresh shadows */
|
||||
EEVEE_draw_shadows(sldata, psl);
|
||||
|
||||
/* Attach depth to the hdr buffer and bind it */
|
||||
DRW_framebuffer_texture_detach(dtxl->depth);
|
||||
DRW_framebuffer_texture_attach(fbl->main, dtxl->depth, 0, 0);
|
||||
DRW_framebuffer_bind(fbl->main);
|
||||
DRW_framebuffer_clear(false, true, false, NULL, 1.0f);
|
||||
/* Refresh Probes */
|
||||
EEVEE_lightprobes_refresh(sldata, vedata);
|
||||
|
||||
DRW_draw_pass(psl->background_pass);
|
||||
/* Attach depth to the hdr buffer and bind it */
|
||||
DRW_framebuffer_texture_detach(dtxl->depth);
|
||||
DRW_framebuffer_texture_attach(fbl->main, dtxl->depth, 0, 0);
|
||||
DRW_framebuffer_bind(fbl->main);
|
||||
DRW_framebuffer_clear(false, true, false, NULL, 1.0f);
|
||||
|
||||
/* Depth prepass */
|
||||
DRW_draw_pass(psl->depth_pass);
|
||||
DRW_draw_pass(psl->depth_pass_cull);
|
||||
/* TODO move background after depth pass to cut some overdraw */
|
||||
DRW_draw_pass(psl->background_pass);
|
||||
|
||||
/* Create minmax texture */
|
||||
EEVEE_create_minmax_buffer(vedata, dtxl->depth);
|
||||
/* Depth prepass */
|
||||
DRW_draw_pass(psl->depth_pass);
|
||||
DRW_draw_pass(psl->depth_pass_cull);
|
||||
|
||||
/* Restore main FB */
|
||||
DRW_framebuffer_bind(fbl->main);
|
||||
/* Create minmax texture */
|
||||
EEVEE_create_minmax_buffer(vedata, dtxl->depth, -1);
|
||||
|
||||
/* Shading pass */
|
||||
DRW_draw_pass(psl->probe_display);
|
||||
EEVEE_draw_default_passes(psl);
|
||||
DRW_draw_pass(psl->material_pass);
|
||||
/* Restore main FB */
|
||||
DRW_framebuffer_bind(fbl->main);
|
||||
|
||||
/* Volumetrics */
|
||||
EEVEE_effects_do_volumetrics(sldata, vedata);
|
||||
/* Shading pass */
|
||||
DRW_draw_pass(psl->probe_display);
|
||||
EEVEE_draw_default_passes(psl);
|
||||
DRW_draw_pass(psl->material_pass);
|
||||
|
||||
/* Transparent */
|
||||
DRW_pass_sort_shgroup_z(psl->transparent_pass);
|
||||
DRW_draw_pass(psl->transparent_pass);
|
||||
/* Screen Space Reflections */
|
||||
EEVEE_effects_do_ssr(sldata, vedata);
|
||||
|
||||
/* Post Process */
|
||||
EEVEE_draw_effects(vedata);
|
||||
/* Volumetrics */
|
||||
EEVEE_effects_do_volumetrics(sldata, vedata);
|
||||
|
||||
/* Transparent */
|
||||
DRW_pass_sort_shgroup_z(psl->transparent_pass);
|
||||
DRW_draw_pass(psl->transparent_pass);
|
||||
|
||||
/* Post Process */
|
||||
EEVEE_draw_effects(vedata);
|
||||
}
|
||||
}
|
||||
|
||||
static void EEVEE_engine_free(void)
|
||||
@@ -196,6 +207,14 @@ static void EEVEE_scene_layer_settings_create(RenderEngine *UNUSED(engine), IDPr
|
||||
props->type == IDP_GROUP &&
|
||||
props->subtype == IDP_GROUP_SUB_ENGINE_RENDER);
|
||||
|
||||
BKE_collection_engine_property_add_bool(props, "ssr_enable", false);
|
||||
BKE_collection_engine_property_add_bool(props, "ssr_halfres", true);
|
||||
BKE_collection_engine_property_add_int(props, "ssr_ray_count", 1);
|
||||
BKE_collection_engine_property_add_int(props, "ssr_stride", 16);
|
||||
BKE_collection_engine_property_add_float(props, "ssr_thickness", 0.2f);
|
||||
BKE_collection_engine_property_add_float(props, "ssr_border_fade", 0.075f);
|
||||
BKE_collection_engine_property_add_float(props, "ssr_firefly_fac", 0.5f);
|
||||
|
||||
BKE_collection_engine_property_add_bool(props, "volumetric_enable", false);
|
||||
BKE_collection_engine_property_add_float(props, "volumetric_start", 0.1f);
|
||||
BKE_collection_engine_property_add_float(props, "volumetric_end", 100.0f);
|
||||
|
@@ -61,9 +61,10 @@ static struct {
|
||||
struct GPUShader *probe_cube_display_sh;
|
||||
|
||||
struct GPUTexture *hammersley;
|
||||
struct GPUTexture *planar_depth;
|
||||
struct GPUTexture *planar_minmaxz;
|
||||
struct GPUTexture *planar_pool_placeholder;
|
||||
struct GPUTexture *depth_placeholder;
|
||||
struct GPUTexture *depth_array_placeholder;
|
||||
struct GPUTexture *cube_face_depth;
|
||||
struct GPUTexture *cube_face_minmaxz;
|
||||
|
||||
@@ -147,11 +148,14 @@ static void planar_pool_ensure_alloc(EEVEE_Data *vedata, int num_planar_ref)
|
||||
if (!txl->planar_pool) {
|
||||
if (num_planar_ref > 0) {
|
||||
txl->planar_pool = DRW_texture_create_2D_array(width, height, max_ff(1, num_planar_ref),
|
||||
DRW_TEX_RGBA_16, DRW_TEX_FILTER | DRW_TEX_MIPMAP, NULL);
|
||||
DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER | DRW_TEX_MIPMAP, NULL);
|
||||
txl->planar_depth = DRW_texture_create_2D_array(width, height, max_ff(1, num_planar_ref),
|
||||
DRW_TEX_DEPTH_24, 0, NULL);
|
||||
}
|
||||
else if (num_planar_ref == 0) {
|
||||
/* Makes Opengl Happy : Create a placeholder texture that will never be sampled but still bound to shader. */
|
||||
txl->planar_pool = DRW_texture_create_2D_array(1, 1, 1, DRW_TEX_RGBA_8, DRW_TEX_FILTER | DRW_TEX_MIPMAP, NULL);
|
||||
txl->planar_depth = DRW_texture_create_2D_array(1, 1, 1, DRW_TEX_DEPTH_24, 0, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,11 +168,6 @@ static void planar_pool_ensure_alloc(EEVEE_Data *vedata, int num_planar_ref)
|
||||
DRWFboTexture tex_minmaxz = {&e_data.planar_minmaxz, DRW_TEX_RG_32, DRW_TEX_MIPMAP | DRW_TEX_TEMP};
|
||||
DRW_framebuffer_init(&fbl->planarref_fb, &draw_engine_eevee_type,
|
||||
width / 2, height / 2, &tex_minmaxz, 1);
|
||||
|
||||
/* Note: this is not the configuration used when rendering. */
|
||||
DRWFboTexture tex = {&e_data.planar_depth, DRW_TEX_DEPTH_24, DRW_TEX_TEMP};
|
||||
DRW_framebuffer_init(&fbl->planarref_fb, &draw_engine_eevee_type,
|
||||
width, height, &tex, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -303,14 +302,20 @@ void EEVEE_lightprobes_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *UNUSED(ved
|
||||
}
|
||||
|
||||
/* Minmaxz Pyramid */
|
||||
/* Highjacking the minmaxz_fb but that's ok because it's reconfigured before usage. */
|
||||
// DRWFboTexture tex_minmaxz = {&e_data.cube_face_minmaxz, DRW_TEX_RG_32, DRW_TEX_MIPMAP | DRW_TEX_TEMP};
|
||||
// DRW_framebuffer_init(&vedata->fbl->minmaxz_fb, &draw_engine_eevee_type, PROBE_RT_SIZE / 2, PROBE_RT_SIZE / 2, &tex_minmaxz, 1);
|
||||
// DRW_framebuffer_init(&vedata->fbl->downsample_fb, &draw_engine_eevee_type, PROBE_RT_SIZE / 2, PROBE_RT_SIZE / 2, &tex_minmaxz, 1);
|
||||
|
||||
/* Placeholder planar pool: used when rendering planar reflections (avoid dependency loop). */
|
||||
if (!e_data.planar_pool_placeholder) {
|
||||
e_data.planar_pool_placeholder = DRW_texture_create_2D_array(1, 1, 1, DRW_TEX_RGBA_8, DRW_TEX_FILTER, NULL);
|
||||
}
|
||||
|
||||
if (!e_data.depth_placeholder) {
|
||||
e_data.depth_placeholder = DRW_texture_create_2D(1, 1, DRW_TEX_DEPTH_24, 0, NULL);
|
||||
}
|
||||
if (!e_data.depth_array_placeholder) {
|
||||
e_data.depth_array_placeholder = DRW_texture_create_2D_array(1, 1, 1, DRW_TEX_DEPTH_24, 0, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void EEVEE_lightprobes_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata)
|
||||
@@ -724,6 +729,7 @@ void EEVEE_lightprobes_cache_finish(EEVEE_SceneLayerData *sldata, EEVEE_Data *ve
|
||||
|
||||
if (pinfo->num_planar != pinfo->cache_num_planar) {
|
||||
DRW_TEXTURE_FREE_SAFE(vedata->txl->planar_pool);
|
||||
DRW_TEXTURE_FREE_SAFE(vedata->txl->planar_depth);
|
||||
pinfo->cache_num_planar = pinfo->num_planar;
|
||||
}
|
||||
|
||||
@@ -972,9 +978,11 @@ static void render_scene_to_probe(
|
||||
/* Avoid using the texture attached to framebuffer when rendering. */
|
||||
/* XXX */
|
||||
GPUTexture *tmp_planar_pool = txl->planar_pool;
|
||||
GPUTexture *tmp_minmaxz = stl->g_data->minmaxz;
|
||||
GPUTexture *tmp_minz = stl->g_data->minzbuffer;
|
||||
GPUTexture *tmp_maxz = txl->maxzbuffer;
|
||||
txl->planar_pool = e_data.planar_pool_placeholder;
|
||||
// stl->g_data->minmaxz = e_data.cube_face_minmaxz;
|
||||
stl->g_data->minzbuffer = e_data.depth_placeholder;
|
||||
txl->maxzbuffer = e_data.depth_placeholder;
|
||||
|
||||
/* Detach to rebind the right cubeface. */
|
||||
DRW_framebuffer_bind(sldata->probe_fb);
|
||||
@@ -1030,7 +1038,8 @@ static void render_scene_to_probe(
|
||||
/* Restore */
|
||||
sldata->probes->specular_toggle = true;
|
||||
txl->planar_pool = tmp_planar_pool;
|
||||
stl->g_data->minmaxz = tmp_minmaxz;
|
||||
stl->g_data->minzbuffer = tmp_minz;
|
||||
txl->maxzbuffer = tmp_maxz;
|
||||
stl->effects->ao_dist = tmp_ao_dist;
|
||||
stl->effects->ao_samples = tmp_ao_samples;
|
||||
}
|
||||
@@ -1043,7 +1052,6 @@ static void render_scene_to_planar(
|
||||
EEVEE_FramebufferList *fbl = vedata->fbl;
|
||||
EEVEE_TextureList *txl = vedata->txl;
|
||||
EEVEE_PassList *psl = vedata->psl;
|
||||
EEVEE_StorageList *stl = vedata->stl;
|
||||
|
||||
float viewinv[4][4];
|
||||
float persinv[4][4];
|
||||
@@ -1052,7 +1060,7 @@ static void render_scene_to_planar(
|
||||
invert_m4_m4(persinv, persmat);
|
||||
|
||||
/* Attach depth here since it's a DRW_TEX_TEMP */
|
||||
DRW_framebuffer_texture_attach(fbl->planarref_fb, e_data.planar_depth, 0, 0);
|
||||
DRW_framebuffer_texture_layer_attach(fbl->planarref_fb, txl->planar_depth, 0, layer, 0);
|
||||
DRW_framebuffer_texture_layer_attach(fbl->planarref_fb, txl->planar_pool, 0, layer, 0);
|
||||
DRW_framebuffer_bind(fbl->planarref_fb);
|
||||
|
||||
@@ -1061,10 +1069,9 @@ static void render_scene_to_planar(
|
||||
/* Avoid using the texture attached to framebuffer when rendering. */
|
||||
/* XXX */
|
||||
GPUTexture *tmp_planar_pool = txl->planar_pool;
|
||||
GPUTexture *tmp_minmaxz = stl->g_data->minmaxz;
|
||||
GPUTexture *tmp_planar_depth = txl->planar_depth;
|
||||
txl->planar_pool = e_data.planar_pool_placeholder;
|
||||
stl->g_data->minmaxz = e_data.planar_minmaxz;
|
||||
stl->g_data->background_alpha = FLT_MAX; /* Alpha is distance for planar reflections. */
|
||||
txl->planar_depth = e_data.depth_array_placeholder;
|
||||
|
||||
DRW_viewport_matrix_override_set(persmat, DRW_MAT_PERS);
|
||||
DRW_viewport_matrix_override_set(persinv, DRW_MAT_PERSINV);
|
||||
@@ -1083,7 +1090,7 @@ static void render_scene_to_planar(
|
||||
DRW_draw_pass(psl->depth_pass_clip);
|
||||
DRW_draw_pass(psl->depth_pass_clip_cull);
|
||||
|
||||
EEVEE_create_minmax_buffer(vedata, e_data.planar_depth);
|
||||
EEVEE_create_minmax_buffer(vedata, tmp_planar_depth, layer);
|
||||
|
||||
/* Rebind Planar FB */
|
||||
DRW_framebuffer_bind(fbl->planarref_fb);
|
||||
@@ -1097,15 +1104,14 @@ static void render_scene_to_planar(
|
||||
|
||||
/* Restore */
|
||||
txl->planar_pool = tmp_planar_pool;
|
||||
stl->g_data->minmaxz = tmp_minmaxz;
|
||||
stl->g_data->background_alpha = 1.0;
|
||||
txl->planar_depth = tmp_planar_depth;
|
||||
DRW_viewport_matrix_override_unset(DRW_MAT_PERS);
|
||||
DRW_viewport_matrix_override_unset(DRW_MAT_PERSINV);
|
||||
DRW_viewport_matrix_override_unset(DRW_MAT_VIEW);
|
||||
DRW_viewport_matrix_override_unset(DRW_MAT_VIEWINV);
|
||||
|
||||
DRW_framebuffer_texture_detach(txl->planar_pool);
|
||||
DRW_framebuffer_texture_detach(e_data.planar_depth);
|
||||
DRW_framebuffer_texture_detach(txl->planar_depth);
|
||||
}
|
||||
|
||||
static void render_world_to_probe(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl)
|
||||
@@ -1257,6 +1263,9 @@ void EEVEE_lightprobes_refresh(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata)
|
||||
ped->need_update = false;
|
||||
}
|
||||
|
||||
printf("Updated Grid %d : cell %d / %d, bounce %d / %d\n",
|
||||
i, ped->updated_cells, ped->num_cell, pinfo->updated_bounce + 1, max_bounce);
|
||||
|
||||
/* Only do one probe per frame */
|
||||
DRW_viewport_request_redraw();
|
||||
goto update_planar;
|
||||
@@ -1294,6 +1303,8 @@ void EEVEE_lightprobes_refresh(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata)
|
||||
ped->ready_to_shade = true;
|
||||
}
|
||||
|
||||
printf("Update Cubemap %d\n", i);
|
||||
|
||||
DRW_viewport_request_redraw();
|
||||
|
||||
/* Only do one probe per frame */
|
||||
@@ -1325,7 +1336,7 @@ update_planar:
|
||||
/* If there is at least one planar probe */
|
||||
if (pinfo->num_planar > 0) {
|
||||
const int max_lod = 5;
|
||||
DRW_framebuffer_recursive_downsample(vedata->fbl->minmaxz_fb, txl->planar_pool, max_lod, &downsample_planar, vedata);
|
||||
DRW_framebuffer_recursive_downsample(vedata->fbl->downsample_fb, txl->planar_pool, max_lod, &downsample_planar, vedata);
|
||||
/* For shading, save max level of the planar map */
|
||||
pinfo->lod_planar_max = (float)(max_lod);
|
||||
}
|
||||
@@ -1342,4 +1353,6 @@ void EEVEE_lightprobes_free(void)
|
||||
DRW_SHADER_FREE_SAFE(e_data.probe_cube_display_sh);
|
||||
DRW_TEXTURE_FREE_SAFE(e_data.hammersley);
|
||||
DRW_TEXTURE_FREE_SAFE(e_data.planar_pool_placeholder);
|
||||
DRW_TEXTURE_FREE_SAFE(e_data.depth_placeholder);
|
||||
DRW_TEXTURE_FREE_SAFE(e_data.depth_array_placeholder);
|
||||
}
|
||||
|
@@ -253,8 +253,15 @@ static char *eevee_get_volume_defines(int options)
|
||||
return str;
|
||||
}
|
||||
|
||||
static void add_standard_uniforms(DRWShadingGroup *shgrp, EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata)
|
||||
/**
|
||||
* ssr_id can be null to disable ssr contribution.
|
||||
**/
|
||||
static void add_standard_uniforms(DRWShadingGroup *shgrp, EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata, int *ssr_id)
|
||||
{
|
||||
if (ssr_id == NULL) {
|
||||
static int no_ssr = -1.0f;
|
||||
ssr_id = &no_ssr;
|
||||
}
|
||||
DRW_shgroup_uniform_block(shgrp, "probe_block", sldata->probe_ubo);
|
||||
DRW_shgroup_uniform_block(shgrp, "grid_block", sldata->grid_ubo);
|
||||
DRW_shgroup_uniform_block(shgrp, "planar_block", sldata->planar_ubo);
|
||||
@@ -273,9 +280,10 @@ static void add_standard_uniforms(DRWShadingGroup *shgrp, EEVEE_SceneLayerData *
|
||||
DRW_shgroup_uniform_buffer(shgrp, "irradianceGrid", &sldata->irradiance_pool);
|
||||
DRW_shgroup_uniform_buffer(shgrp, "shadowCubes", &sldata->shadow_depth_cube_pool);
|
||||
DRW_shgroup_uniform_buffer(shgrp, "shadowCascades", &sldata->shadow_depth_cascade_pool);
|
||||
DRW_shgroup_uniform_int(shgrp, "outputSsrId", ssr_id, 1);
|
||||
if (vedata->stl->effects->use_ao) {
|
||||
DRW_shgroup_uniform_vec4(shgrp, "viewvecs[0]", (float *)&vedata->stl->g_data->viewvecs, 2);
|
||||
DRW_shgroup_uniform_buffer(shgrp, "minMaxDepthTex", &vedata->stl->g_data->minmaxz);
|
||||
DRW_shgroup_uniform_buffer(shgrp, "minMaxDepthTex", &vedata->txl->maxzbuffer);
|
||||
DRW_shgroup_uniform_vec3(shgrp, "aoParameters", &vedata->stl->effects->ao_dist, 1);
|
||||
}
|
||||
}
|
||||
@@ -583,8 +591,10 @@ struct GPUMaterial *EEVEE_material_hair_get(
|
||||
**/
|
||||
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)
|
||||
bool is_hair, bool is_flat_normal, bool use_ao, bool use_bent_normals, bool use_blend, bool use_ssr)
|
||||
{
|
||||
static int ssr_id;
|
||||
ssr_id = (use_ssr) ? 0 : -1;
|
||||
int options = VAR_MAT_MESH;
|
||||
|
||||
if (is_hair) options |= VAR_MAT_HAIR;
|
||||
@@ -598,7 +608,7 @@ static struct DRWShadingGroup *EEVEE_default_shading_group_create(
|
||||
}
|
||||
|
||||
DRWShadingGroup *shgrp = DRW_shgroup_create(e_data.default_lit[options], pass);
|
||||
add_standard_uniforms(shgrp, sldata, vedata);
|
||||
add_standard_uniforms(shgrp, sldata, vedata, &ssr_id);
|
||||
|
||||
return shgrp;
|
||||
}
|
||||
@@ -608,8 +618,10 @@ static struct DRWShadingGroup *EEVEE_default_shading_group_create(
|
||||
**/
|
||||
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)
|
||||
bool is_hair, bool is_flat_normal, bool use_ao, bool use_bent_normals, bool use_ssr)
|
||||
{
|
||||
static int ssr_id;
|
||||
ssr_id = (use_ssr) ? 0 : -1;
|
||||
int options = VAR_MAT_MESH;
|
||||
|
||||
if (is_hair) options |= VAR_MAT_HAIR;
|
||||
@@ -626,7 +638,7 @@ static struct DRWShadingGroup *EEVEE_default_shading_group_get(
|
||||
vedata->psl->default_pass[options] = DRW_pass_create("Default Lit Pass", state);
|
||||
|
||||
DRWShadingGroup *shgrp = DRW_shgroup_create(e_data.default_lit[options], vedata->psl->default_pass[options]);
|
||||
add_standard_uniforms(shgrp, sldata, vedata);
|
||||
add_standard_uniforms(shgrp, sldata, vedata, &ssr_id);
|
||||
}
|
||||
|
||||
return DRW_shgroup_create(e_data.default_lit[options], vedata->psl->default_pass[options]);
|
||||
@@ -638,12 +650,14 @@ void EEVEE_materials_cache_init(EEVEE_Data *vedata)
|
||||
EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl;
|
||||
|
||||
{
|
||||
/* Global AO Switch*/
|
||||
const DRWContextState *draw_ctx = DRW_context_state_get();
|
||||
SceneLayer *scene_layer = draw_ctx->scene_layer;
|
||||
IDProperty *props = BKE_scene_layer_engine_evaluated_get(scene_layer, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_EEVEE);
|
||||
/* Global AO Switch*/
|
||||
stl->effects->use_ao = BKE_collection_engine_property_value_get_bool(props, "gtao_enable");
|
||||
stl->effects->use_bent_normals = BKE_collection_engine_property_value_get_bool(props, "gtao_use_bent_normals");
|
||||
/* SSR switch */
|
||||
stl->effects->use_ssr = BKE_collection_engine_property_value_get_bool(props, "ssr_enable");
|
||||
}
|
||||
|
||||
/* Create Material Ghash */
|
||||
@@ -781,7 +795,9 @@ static void material_opaque(
|
||||
|
||||
*shgrp = DRW_shgroup_material_create(*gpumat, psl->material_pass);
|
||||
if (*shgrp) {
|
||||
add_standard_uniforms(*shgrp, sldata, vedata);
|
||||
static int ssr_id;
|
||||
ssr_id = (stl->effects->use_ssr) ? 0 : -1;
|
||||
add_standard_uniforms(*shgrp, sldata, vedata, &ssr_id);
|
||||
}
|
||||
else {
|
||||
/* Shader failed : pink color */
|
||||
@@ -813,7 +829,7 @@ static void material_opaque(
|
||||
/* Fallback to default shader */
|
||||
if (*shgrp == NULL) {
|
||||
*shgrp = EEVEE_default_shading_group_get(sldata, vedata, false, use_flat_nor,
|
||||
stl->effects->use_ao, stl->effects->use_bent_normals);
|
||||
stl->effects->use_ao, stl->effects->use_bent_normals, stl->effects->use_ssr);
|
||||
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);
|
||||
@@ -855,7 +871,8 @@ static void material_transparent(
|
||||
|
||||
*shgrp = DRW_shgroup_material_create(*gpumat, psl->transparent_pass);
|
||||
if (*shgrp) {
|
||||
add_standard_uniforms(*shgrp, sldata, vedata);
|
||||
static int ssr_id = -1; /* TODO transparent SSR */
|
||||
add_standard_uniforms(*shgrp, sldata, vedata, &ssr_id);
|
||||
}
|
||||
else {
|
||||
/* Shader failed : pink color */
|
||||
@@ -871,7 +888,7 @@ static void material_transparent(
|
||||
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);
|
||||
false, use_flat_nor, stl->effects->use_ao, stl->effects->use_bent_normals, true, false);
|
||||
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);
|
||||
@@ -1089,7 +1106,7 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_SceneLayerData *sl
|
||||
|
||||
shgrp = DRW_shgroup_material_create(gpumat, psl->material_pass);
|
||||
if (shgrp) {
|
||||
add_standard_uniforms(shgrp, sldata, vedata);
|
||||
add_standard_uniforms(shgrp, sldata, vedata, NULL);
|
||||
|
||||
BLI_ghash_insert(material_hash, ma, shgrp);
|
||||
|
||||
@@ -1108,7 +1125,7 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_SceneLayerData *sl
|
||||
/* Fallback to default shader */
|
||||
if (shgrp == NULL) {
|
||||
shgrp = EEVEE_default_shading_group_get(sldata, vedata, true, false,
|
||||
stl->effects->use_ao, stl->effects->use_bent_normals);
|
||||
stl->effects->use_ao, stl->effects->use_bent_normals, stl->effects->use_ssr);
|
||||
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);
|
||||
|
@@ -103,12 +103,22 @@ typedef struct EEVEE_PassList {
|
||||
struct DRWPass *dof_down;
|
||||
struct DRWPass *dof_scatter;
|
||||
struct DRWPass *dof_resolve;
|
||||
struct DRWPass *minmaxz_downlevel;
|
||||
struct DRWPass *minmaxz_downdepth;
|
||||
struct DRWPass *minmaxz_copydepth;
|
||||
struct DRWPass *volumetric_integrate_ps;
|
||||
struct DRWPass *volumetric_resolve_ps;
|
||||
struct DRWPass *volumetric_resolve_transmit_ps;
|
||||
struct DRWPass *ssr_raytrace;
|
||||
struct DRWPass *ssr_resolve;
|
||||
struct DRWPass *color_downsample_ps;
|
||||
|
||||
/* HiZ */
|
||||
struct DRWPass *minz_downlevel_ps;
|
||||
struct DRWPass *maxz_downlevel_ps;
|
||||
struct DRWPass *minz_downdepth_ps;
|
||||
struct DRWPass *maxz_downdepth_ps;
|
||||
struct DRWPass *minz_downdepth_layer_ps;
|
||||
struct DRWPass *maxz_downdepth_layer_ps;
|
||||
struct DRWPass *minz_copydepth_ps;
|
||||
struct DRWPass *maxz_copydepth_ps;
|
||||
|
||||
struct DRWPass *depth_pass;
|
||||
struct DRWPass *depth_pass_cull;
|
||||
@@ -122,7 +132,7 @@ typedef struct EEVEE_PassList {
|
||||
|
||||
typedef struct EEVEE_FramebufferList {
|
||||
/* Effects */
|
||||
struct GPUFrameBuffer *minmaxz_fb;
|
||||
struct GPUFrameBuffer *downsample_fb;
|
||||
struct GPUFrameBuffer *effect_fb;
|
||||
struct GPUFrameBuffer *bloom_blit_fb;
|
||||
struct GPUFrameBuffer *bloom_down_fb[MAX_BLOOM_STEP];
|
||||
@@ -131,10 +141,12 @@ typedef struct EEVEE_FramebufferList {
|
||||
struct GPUFrameBuffer *dof_scatter_far_fb;
|
||||
struct GPUFrameBuffer *dof_scatter_near_fb;
|
||||
struct GPUFrameBuffer *volumetric_fb;
|
||||
struct GPUFrameBuffer *screen_tracing_fb;
|
||||
|
||||
struct GPUFrameBuffer *planarref_fb;
|
||||
|
||||
struct GPUFrameBuffer *main;
|
||||
struct GPUFrameBuffer *double_buffer;
|
||||
} EEVEE_FramebufferList;
|
||||
|
||||
typedef struct EEVEE_TextureList {
|
||||
@@ -149,9 +161,16 @@ typedef struct EEVEE_TextureList {
|
||||
struct GPUTexture *bloom_downsample[MAX_BLOOM_STEP]; /* R16_G16_B16 */
|
||||
struct GPUTexture *bloom_upsample[MAX_BLOOM_STEP-1]; /* R16_G16_B16 */
|
||||
|
||||
struct GPUTexture *ssr_normal_input;
|
||||
struct GPUTexture *ssr_specrough_input;
|
||||
|
||||
struct GPUTexture *planar_pool;
|
||||
struct GPUTexture *planar_depth;
|
||||
|
||||
struct GPUTexture *maxzbuffer;
|
||||
|
||||
struct GPUTexture *color; /* R16_G16_B16 */
|
||||
struct GPUTexture *color_double_buffer;
|
||||
} EEVEE_TextureList;
|
||||
|
||||
typedef struct EEVEE_StorageList {
|
||||
@@ -300,6 +319,16 @@ enum {
|
||||
typedef struct EEVEE_EffectsInfo {
|
||||
int enabled_effects;
|
||||
|
||||
/* SSR */
|
||||
bool use_ssr;
|
||||
bool reflection_trace_full;
|
||||
bool ssr_use_normalization;
|
||||
int ssr_ray_count;
|
||||
float ssr_firefly_fac;
|
||||
float ssr_border_fac;
|
||||
float ssr_stride;
|
||||
float ssr_thickness;
|
||||
|
||||
/* Ambient Occlusion */
|
||||
bool use_ao, use_bent_normals;
|
||||
float ao_dist, ao_samples, ao_factor;
|
||||
@@ -339,6 +368,8 @@ enum {
|
||||
EFFECT_BLOOM = (1 << 1),
|
||||
EFFECT_DOF = (1 << 2),
|
||||
EFFECT_VOLUMETRIC = (1 << 3),
|
||||
EFFECT_SSR = (1 << 4),
|
||||
EFFECT_DOUBLE_BUFFER = (1 << 5), /* Not really an effect but a feature */
|
||||
};
|
||||
|
||||
/* ************** SCENE LAYER DATA ************** */
|
||||
@@ -428,13 +459,17 @@ typedef struct EEVEE_PrivateData {
|
||||
struct DRWShadingGroup *planar_downsample;
|
||||
struct GHash *material_hash;
|
||||
struct GHash *hair_material_hash;
|
||||
struct GPUTexture *minmaxz;
|
||||
struct GPUTexture *minzbuffer;
|
||||
struct GPUTexture *ssr_hit_output[4];
|
||||
struct GPUTexture *volumetric;
|
||||
struct GPUTexture *volumetric_transmit;
|
||||
float background_alpha; /* TODO find a better place for this. */
|
||||
float viewvecs[2][4];
|
||||
/* For planar probes */
|
||||
float texel_size[2];
|
||||
/* For double buffering */
|
||||
bool valid_double_buffer;
|
||||
float prev_persmat[4][4];
|
||||
} EEVEE_PrivateData; /* Transient data */
|
||||
|
||||
/* eevee_data.c */
|
||||
@@ -484,8 +519,10 @@ void EEVEE_lightprobes_free(void);
|
||||
/* eevee_effects.c */
|
||||
void EEVEE_effects_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata);
|
||||
void EEVEE_effects_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata);
|
||||
void EEVEE_create_minmax_buffer(EEVEE_Data *vedata, struct GPUTexture *depth_src);
|
||||
void EEVEE_create_minmax_buffer(EEVEE_Data *vedata, struct GPUTexture *depth_src, int layer);
|
||||
void EEVEE_downsample_buffer(EEVEE_Data *vedata, struct GPUFrameBuffer *fb_src, struct GPUTexture *texture_src, int level);
|
||||
void EEVEE_effects_do_volumetrics(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata);
|
||||
void EEVEE_effects_do_ssr(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata);
|
||||
void EEVEE_draw_effects(EEVEE_Data *vedata);
|
||||
void EEVEE_effects_free(void);
|
||||
|
||||
|
@@ -16,7 +16,7 @@ uniform vec3 aoParameters;
|
||||
|
||||
float get_max_horizon(vec2 co, vec3 x, float h, float lod)
|
||||
{
|
||||
float depth = textureLod(minMaxDepthTex, co, floor(lod)).g;
|
||||
float depth = textureLod(minMaxDepthTex, co, floor(lod)).r;
|
||||
|
||||
/* Background case */
|
||||
/* this is really slow and is only a problem
|
||||
|
@@ -28,82 +28,10 @@ flat in int shFace; /* Shadow layer we are rendering to. */
|
||||
|
||||
#define cameraForward normalize(ViewMatrixInverse[2].xyz)
|
||||
#define cameraPos ViewMatrixInverse[3].xyz
|
||||
|
||||
#define cameraVec ((ProjectionMatrix[3][3] == 0.0) ? normalize(cameraPos - worldPosition) : cameraForward)
|
||||
#define viewCameraVec ((ProjectionMatrix[3][3] == 0.0) ? normalize(-viewPosition) : vec3(0.0, 0.0, 1.0))
|
||||
|
||||
/* ------- Structures -------- */
|
||||
#ifdef VOLUMETRICS
|
||||
|
||||
struct Closure {
|
||||
vec3 absorption;
|
||||
vec3 scatter;
|
||||
vec3 emission;
|
||||
float anisotropy;
|
||||
};
|
||||
|
||||
#define CLOSURE_DEFAULT Closure(vec3(0.0), vec3(0.0), vec3(0.0), 0.0)
|
||||
|
||||
Closure closure_mix(Closure cl1, Closure cl2, float fac)
|
||||
{
|
||||
Closure cl;
|
||||
cl.absorption = mix(cl1.absorption, cl2.absorption, fac);
|
||||
cl.scatter = mix(cl1.scatter, cl2.scatter, fac);
|
||||
cl.emission = mix(cl1.emission, cl2.emission, fac);
|
||||
cl.anisotropy = mix(cl1.anisotropy, cl2.anisotropy, fac);
|
||||
return cl;
|
||||
}
|
||||
|
||||
Closure closure_add(Closure cl1, Closure cl2)
|
||||
{
|
||||
Closure cl;
|
||||
cl.absorption = cl1.absorption + cl2.absorption;
|
||||
cl.scatter = cl1.scatter + cl2.scatter;
|
||||
cl.emission = cl1.emission + cl2.emission;
|
||||
cl.anisotropy = (cl1.anisotropy + cl2.anisotropy) / 2.0; /* Average phase (no multi lobe) */
|
||||
return cl;
|
||||
}
|
||||
#else
|
||||
|
||||
struct Closure {
|
||||
vec3 radiance;
|
||||
float opacity;
|
||||
};
|
||||
|
||||
#define CLOSURE_DEFAULT Closure(vec3(0.0), 1.0)
|
||||
|
||||
Closure closure_mix(Closure cl1, Closure cl2, float fac)
|
||||
{
|
||||
Closure cl;
|
||||
cl.radiance = mix(cl1.radiance, cl2.radiance, fac);
|
||||
cl.opacity = mix(cl1.opacity, cl2.opacity, fac);
|
||||
return cl;
|
||||
}
|
||||
|
||||
Closure closure_add(Closure cl1, Closure cl2)
|
||||
{
|
||||
Closure cl;
|
||||
cl.radiance = cl1.radiance + cl2.radiance;
|
||||
cl.opacity = cl1.opacity + cl2.opacity;
|
||||
return cl;
|
||||
}
|
||||
|
||||
#endif /* VOLUMETRICS */
|
||||
|
||||
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 */
|
||||
vec4 color_spec; /* w : Spec Intensity */
|
||||
@@ -162,15 +90,18 @@ struct ShadowCascadeData {
|
||||
vec4 bias;
|
||||
};
|
||||
|
||||
#define cameraVec ((ProjectionMatrix[3][3] == 0.0) ? normalize(cameraPos - worldPosition) : cameraForward)
|
||||
|
||||
/* ------- Convenience functions --------- */
|
||||
|
||||
vec3 mul(mat3 m, vec3 v) { return m * v; }
|
||||
mat3 mul(mat3 m1, mat3 m2) { return m1 * m2; }
|
||||
vec3 transform_point(mat4 m, vec3 v) { return (m * vec4(v, 1.0)).xyz; }
|
||||
vec3 project_point(mat4 m, vec3 v) {
|
||||
vec4 tmp = m * vec4(v, 1.0);
|
||||
return tmp.xyz / tmp.w;
|
||||
}
|
||||
|
||||
float min_v3(vec3 v) { return min(v.x, min(v.y, v.z)); }
|
||||
float max_v2(vec2 v) { return max(v.x, v.y); }
|
||||
|
||||
float saturate(float a) { return clamp(a, 0.0, 1.0); }
|
||||
vec2 saturate(vec2 a) { return clamp(a, 0.0, 1.0); }
|
||||
@@ -199,6 +130,11 @@ float fast_acos(float x)
|
||||
return (x >= 0) ? res : M_PI - res;
|
||||
}
|
||||
|
||||
float point_plane_projection_dist(vec3 lineorigin, vec3 planeorigin, vec3 planenormal)
|
||||
{
|
||||
return dot(planenormal, planeorigin - lineorigin);
|
||||
}
|
||||
|
||||
float line_plane_intersect_dist(vec3 lineorigin, vec3 linedirection, vec3 planeorigin, vec3 planenormal)
|
||||
{
|
||||
return dot(planenormal, planeorigin - lineorigin) / dot(planenormal, linedirection);
|
||||
@@ -332,6 +268,11 @@ vec3 get_view_space_from_depth(vec2 uvcoords, float depth)
|
||||
}
|
||||
}
|
||||
|
||||
vec3 get_world_space_from_depth(vec2 uvcoords, float depth)
|
||||
{
|
||||
return (ViewMatrixInverse * vec4(get_view_space_from_depth(uvcoords, depth), 1.0)).xyz;
|
||||
}
|
||||
|
||||
vec3 get_specular_dominant_dir(vec3 N, vec3 V, float roughness)
|
||||
{
|
||||
vec3 R = -reflect(V, N);
|
||||
@@ -345,6 +286,26 @@ float specular_occlusion(float NV, float AO, float roughness)
|
||||
return saturate(pow(NV + AO, roughness) - 1.0 + AO);
|
||||
}
|
||||
|
||||
/* ---- Encode / Decode Normal buffer data ---- */
|
||||
/* From http://aras-p.info/texts/CompactNormalStorage.html
|
||||
* Using Method #4: Spheremap Transform */
|
||||
vec2 normal_encode(vec3 n, vec3 view)
|
||||
{
|
||||
float p = sqrt(n.z * 8.0 + 8.0);
|
||||
return n.xy / p + 0.5;
|
||||
}
|
||||
|
||||
vec3 normal_decode(vec2 enc, vec3 view)
|
||||
{
|
||||
vec2 fenc = enc * 4.0 - 2.0;
|
||||
float f = dot(fenc, fenc);
|
||||
float g = sqrt(1.0 - f / 4.0);
|
||||
vec3 n;
|
||||
n.xy = fenc*g;
|
||||
n.z = 1 - f / 2;
|
||||
return n;
|
||||
}
|
||||
|
||||
/* Fresnel */
|
||||
vec3 F_schlick(vec3 f0, float cos_theta)
|
||||
{
|
||||
@@ -411,4 +372,126 @@ float bsdf_ggx(vec3 N, vec3 L, vec3 V, float roughness)
|
||||
void accumulate_light(vec3 light, float fac, inout vec4 accum)
|
||||
{
|
||||
accum += vec4(light, 1.0) * min(fac, (1.0 - accum.a));
|
||||
}
|
||||
}
|
||||
|
||||
/* ----------- Cone Apperture Approximation --------- */
|
||||
|
||||
/* Return a fitted cone angle given the input roughness */
|
||||
float cone_cosine(float r)
|
||||
{
|
||||
/* Using phong gloss
|
||||
* roughness = sqrt(2/(gloss+2)) */
|
||||
float gloss = -2 + 2 / (r * r);
|
||||
/* Drobot 2014 in GPUPro5 */
|
||||
// return cos(2.0 * sqrt(2.0 / (gloss + 2)));
|
||||
/* Uludag 2014 in GPUPro5 */
|
||||
// return pow(0.244, 1 / (gloss + 1));
|
||||
/* Jimenez 2016 in Practical Realtime Strategies for Accurate Indirect Occlusion*/
|
||||
return exp2(-3.32193 * r * r);
|
||||
}
|
||||
|
||||
/* --------- Closure ---------- */
|
||||
#ifdef VOLUMETRICS
|
||||
|
||||
struct Closure {
|
||||
vec3 absorption;
|
||||
vec3 scatter;
|
||||
vec3 emission;
|
||||
float anisotropy;
|
||||
};
|
||||
|
||||
#define CLOSURE_DEFAULT Closure(vec3(0.0), vec3(0.0), vec3(0.0), 0.0)
|
||||
|
||||
Closure closure_mix(Closure cl1, Closure cl2, float fac)
|
||||
{
|
||||
Closure cl;
|
||||
cl.absorption = mix(cl1.absorption, cl2.absorption, fac);
|
||||
cl.scatter = mix(cl1.scatter, cl2.scatter, fac);
|
||||
cl.emission = mix(cl1.emission, cl2.emission, fac);
|
||||
cl.anisotropy = mix(cl1.anisotropy, cl2.anisotropy, fac);
|
||||
return cl;
|
||||
}
|
||||
|
||||
Closure closure_add(Closure cl1, Closure cl2)
|
||||
{
|
||||
Closure cl;
|
||||
cl.absorption = cl1.absorption + cl2.absorption;
|
||||
cl.scatter = cl1.scatter + cl2.scatter;
|
||||
cl.emission = cl1.emission + cl2.emission;
|
||||
cl.anisotropy = (cl1.anisotropy + cl2.anisotropy) / 2.0; /* Average phase (no multi lobe) */
|
||||
return cl;
|
||||
}
|
||||
#else
|
||||
|
||||
struct Closure {
|
||||
vec3 radiance;
|
||||
float opacity;
|
||||
vec4 ssr_data;
|
||||
vec2 ssr_normal;
|
||||
int ssr_id;
|
||||
};
|
||||
|
||||
#define CLOSURE_DEFAULT Closure(vec3(0.0), 1.0, vec4(0.0), vec2(0.0), -1)
|
||||
|
||||
uniform int outputSsrId;
|
||||
|
||||
Closure closure_mix(Closure cl1, Closure cl2, float fac)
|
||||
{
|
||||
Closure cl;
|
||||
if (cl1.ssr_id == outputSsrId) {
|
||||
cl.ssr_data = mix(cl1.ssr_data.xyzw, vec4(vec3(0.0), cl1.ssr_data.w), fac); /* do not blend roughness */
|
||||
cl.ssr_normal = cl1.ssr_normal;
|
||||
cl.ssr_id = cl1.ssr_id;
|
||||
}
|
||||
else {
|
||||
cl.ssr_data = mix(vec4(vec3(0.0), cl2.ssr_data.w), cl2.ssr_data.xyzw, fac); /* do not blend roughness */
|
||||
cl.ssr_normal = cl2.ssr_normal;
|
||||
cl.ssr_id = cl2.ssr_id;
|
||||
}
|
||||
cl.radiance = mix(cl1.radiance, cl2.radiance, fac);
|
||||
cl.opacity = mix(cl1.opacity, cl2.opacity, fac);
|
||||
return cl;
|
||||
}
|
||||
|
||||
Closure closure_add(Closure cl1, Closure cl2)
|
||||
{
|
||||
Closure cl = (cl1.ssr_id == outputSsrId) ? cl1 : cl2;
|
||||
cl.radiance = cl1.radiance + cl2.radiance;
|
||||
cl.opacity = cl1.opacity + cl2.opacity;
|
||||
return cl;
|
||||
}
|
||||
|
||||
#if defined(MESH_SHADER) && !defined(USE_ALPHA_HASH) && !defined(USE_ALPHA_CLIP) && !defined(SHADOW_SHADER)
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
layout(location = 1) out vec4 ssrNormals;
|
||||
layout(location = 2) out vec4 ssrData;
|
||||
|
||||
Closure nodetree_exec(void); /* Prototype */
|
||||
|
||||
#define NODETREE_EXEC
|
||||
void main()
|
||||
{
|
||||
Closure cl = nodetree_exec();
|
||||
fragColor = vec4(cl.radiance, cl.opacity);
|
||||
ssrNormals = cl.ssr_normal.xyyy;
|
||||
ssrData = cl.ssr_data;
|
||||
}
|
||||
|
||||
#endif /* MESH_SHADER && !SHADOW_SHADER */
|
||||
|
||||
#endif /* VOLUMETRICS */
|
||||
|
||||
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
|
@@ -6,11 +6,14 @@ uniform float invSampleCount;
|
||||
|
||||
vec2 jitternoise = vec2(0.0);
|
||||
|
||||
#ifdef NOISE_SIZE
|
||||
void setup_noise(void)
|
||||
{
|
||||
jitternoise = texture(texJitter, gl_FragCoord.xy / NOISE_SIZE).rg; /* Global variable */
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAMMERSLEY_SIZE
|
||||
vec3 hammersley_3d(float i, float invsamplenbr)
|
||||
{
|
||||
vec3 Xi; /* Theta, cos(Phi), sin(Phi) */
|
||||
@@ -29,6 +32,7 @@ vec3 hammersley_3d(float i)
|
||||
{
|
||||
return hammersley_3d(i, invSampleCount);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* -------------- BSDFS -------------- */
|
||||
|
||||
@@ -42,19 +46,30 @@ float pdf_hemisphere()
|
||||
return 0.5 * M_1_PI;
|
||||
}
|
||||
|
||||
vec3 sample_ggx(vec3 rand, float a2)
|
||||
{
|
||||
/* Theta is the aperture angle of the cone */
|
||||
float z = sqrt( (1.0 - rand.x) / ( 1.0 + a2 * rand.x - rand.x ) ); /* cos theta */
|
||||
float r = sqrt( 1.0 - z * z ); /* sin theta */
|
||||
float x = r * rand.y;
|
||||
float y = r * rand.z;
|
||||
|
||||
/* Microfacet Normal */
|
||||
return vec3(x, y, z);
|
||||
}
|
||||
|
||||
vec3 sample_ggx(vec3 rand, float a2, vec3 N, vec3 T, vec3 B, out float NH)
|
||||
{
|
||||
vec3 Ht = sample_ggx(rand, a2);
|
||||
NH = Ht.z;
|
||||
return tangent_to_world(Ht, N, T, B);
|
||||
}
|
||||
|
||||
#ifdef HAMMERSLEY_SIZE
|
||||
vec3 sample_ggx(float nsample, float a2, vec3 N, vec3 T, vec3 B)
|
||||
{
|
||||
vec3 Xi = hammersley_3d(nsample);
|
||||
|
||||
/* Theta is the aperture angle of the cone */
|
||||
float z = sqrt( (1.0 - Xi.x) / ( 1.0 + a2 * Xi.x - Xi.x ) ); /* cos theta */
|
||||
float r = sqrt( 1.0 - z * z ); /* sin theta */
|
||||
float x = r * Xi.y;
|
||||
float y = r * Xi.z;
|
||||
|
||||
/* Microfacet Normal */
|
||||
vec3 Ht = vec3(x, y, z);
|
||||
|
||||
vec3 Ht = sample_ggx(Xi, a2);
|
||||
return tangent_to_world(Ht, N, T, B);
|
||||
}
|
||||
|
||||
@@ -70,4 +85,5 @@ vec3 sample_hemisphere(float nsample, vec3 N, vec3 T, vec3 B)
|
||||
vec3 Ht = vec3(x, y, z);
|
||||
|
||||
return tangent_to_world(Ht, N, T, B);
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -4,17 +4,15 @@ uniform float metallic;
|
||||
uniform float specular;
|
||||
uniform float roughness;
|
||||
|
||||
out vec4 FragColor;
|
||||
|
||||
void main()
|
||||
Closure nodetree_exec(void)
|
||||
{
|
||||
vec3 dielectric = vec3(0.034) * specular * 2.0;
|
||||
vec3 diffuse = mix(basecol, vec3(0.0), metallic);
|
||||
vec3 f0 = mix(dielectric, basecol, metallic);
|
||||
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
|
||||
vec3 ssr_spec;
|
||||
vec3 radiance = eevee_surface_lit((gl_FrontFacing) ? worldNormal : -worldNormal, diffuse, f0, roughness, 1.0, 0, ssr_spec);
|
||||
|
||||
Closure result = Closure(radiance, 1.0, vec4(ssr_spec, roughness), normal_encode(normalize(viewNormal), viewCameraVec), 0);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@@ -48,13 +48,13 @@ out vec4 FragColor;
|
||||
|
||||
float brightness(vec3 c)
|
||||
{
|
||||
return max(max(c.r, c.g), c.b);
|
||||
return max(max(c.r, c.g), c.b);
|
||||
}
|
||||
|
||||
/* 3-tap median filter */
|
||||
vec3 median(vec3 a, vec3 b, vec3 c)
|
||||
{
|
||||
return a + b + c - min(min(a, b), c) - max(max(a, b), c);
|
||||
return a + b + c - min(min(a, b), c) - max(max(a, b), c);
|
||||
}
|
||||
|
||||
/* ------------- Filters ------------ */
|
||||
|
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* Simple downsample shader. Takes the average of the 4 texels of lower mip.
|
||||
**/
|
||||
|
||||
uniform sampler2D source;
|
||||
|
||||
out vec4 FragColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
/* Reconstructing Target uvs like this avoid missing pixels if NPO2 */
|
||||
vec2 uvs = gl_FragCoord.xy * 2.0 / vec2(textureSize(source, 0));
|
||||
|
||||
FragColor = texture(source, uvs);
|
||||
}
|
@@ -4,63 +4,61 @@
|
||||
* Adapted from http://rastergrid.com/blog/2010/10/hierarchical-z-map-based-occlusion-culling/
|
||||
**/
|
||||
|
||||
uniform sampler2D depthBuffer;
|
||||
|
||||
out vec4 FragMinMax;
|
||||
|
||||
vec2 sampleLowerMip(ivec2 texel)
|
||||
{
|
||||
#ifdef INPUT_DEPTH
|
||||
return texelFetch(depthBuffer, texel, 0).rr;
|
||||
#ifdef LAYERED
|
||||
uniform sampler2DArray depthBuffer;
|
||||
uniform int depthLayer;
|
||||
#else
|
||||
return texelFetch(depthBuffer, texel, 0).rg;
|
||||
uniform sampler2D depthBuffer;
|
||||
#endif
|
||||
|
||||
float sampleLowerMip(ivec2 texel)
|
||||
{
|
||||
#ifdef LAYERED
|
||||
return texelFetch(depthBuffer, ivec3(texel, depthLayer), 0).r;
|
||||
#else
|
||||
return texelFetch(depthBuffer, texel, 0).r;
|
||||
#endif
|
||||
}
|
||||
|
||||
void minmax(inout vec2 val[2])
|
||||
void minmax(inout float out_val, float in_val)
|
||||
{
|
||||
val[0].x = min(val[0].x, val[1].x);
|
||||
val[0].y = max(val[0].y, val[1].y);
|
||||
#ifdef MIN_PASS
|
||||
out_val = min(out_val, in_val);
|
||||
#else /* MAX_PASS */
|
||||
out_val = max(out_val, in_val);
|
||||
#endif
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
vec2 val[2];
|
||||
ivec2 texelPos = ivec2(gl_FragCoord.xy);
|
||||
ivec2 mipsize = textureSize(depthBuffer, 0);
|
||||
ivec2 mipsize = textureSize(depthBuffer, 0).xy;
|
||||
|
||||
#ifndef COPY_DEPTH
|
||||
texelPos *= 2;
|
||||
#endif
|
||||
|
||||
val[0] = sampleLowerMip(texelPos);
|
||||
float val = sampleLowerMip(texelPos);
|
||||
#ifndef COPY_DEPTH
|
||||
val[1] = sampleLowerMip(texelPos + ivec2(1, 0));
|
||||
minmax(val);
|
||||
val[1] = sampleLowerMip(texelPos + ivec2(1, 1));
|
||||
minmax(val);
|
||||
val[1] = sampleLowerMip(texelPos + ivec2(0, 1));
|
||||
minmax(val);
|
||||
minmax(val, sampleLowerMip(texelPos + ivec2(1, 0)));
|
||||
minmax(val, sampleLowerMip(texelPos + ivec2(1, 1)));
|
||||
minmax(val, sampleLowerMip(texelPos + ivec2(0, 1)));
|
||||
|
||||
/* if we are reducing an odd-width texture then fetch the edge texels */
|
||||
if (((mipsize.x & 1) != 0) && (int(gl_FragCoord.x) == mipsize.x-3)) {
|
||||
/* if both edges are odd, fetch the top-left corner texel */
|
||||
if (((mipsize.y & 1) != 0) && (int(gl_FragCoord.y) == mipsize.y-3)) {
|
||||
val[1] = sampleLowerMip(texelPos + ivec2(-1, -1));
|
||||
minmax(val);
|
||||
minmax(val, sampleLowerMip(texelPos + ivec2(-1, -1)));
|
||||
}
|
||||
val[1] = sampleLowerMip(texelPos + ivec2(0, -1));
|
||||
minmax(val);
|
||||
val[1] = sampleLowerMip(texelPos + ivec2(1, -1));
|
||||
minmax(val);
|
||||
minmax(val, sampleLowerMip(texelPos + ivec2(0, -1)));
|
||||
minmax(val, sampleLowerMip(texelPos + ivec2(1, -1)));
|
||||
}
|
||||
/* if we are reducing an odd-height texture then fetch the edge texels */
|
||||
else if (((mipsize.y & 1) != 0) && (int(gl_FragCoord.y) == mipsize.y-3)) {
|
||||
val[1] = sampleLowerMip(texelPos + ivec2(0, -1));
|
||||
minmax(val);
|
||||
val[1] = sampleLowerMip(texelPos + ivec2(1, -1));
|
||||
minmax(val);
|
||||
minmax(val, sampleLowerMip(texelPos + ivec2(0, -1)));
|
||||
minmax(val, sampleLowerMip(texelPos + ivec2(1, -1)));
|
||||
}
|
||||
#endif
|
||||
|
||||
FragMinMax = vec4(val[0], 0.0, 1.0);
|
||||
gl_FragDepth = val;
|
||||
}
|
357
source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl
Normal file
357
source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl
Normal file
@@ -0,0 +1,357 @@
|
||||
|
||||
/* Based on Stochastic Screen Space Reflections
|
||||
* https://www.ea.com/frostbite/news/stochastic-screen-space-reflections */
|
||||
|
||||
#ifndef UTIL_TEX
|
||||
#define UTIL_TEX
|
||||
uniform sampler2DArray utilTex;
|
||||
#endif /* UTIL_TEX */
|
||||
|
||||
uniform int rayCount;
|
||||
|
||||
#define BRDF_BIAS 0.7
|
||||
|
||||
vec3 generate_ray(vec3 V, vec3 N, float a2, vec3 rand, out float pdf)
|
||||
{
|
||||
float NH;
|
||||
vec3 T, B;
|
||||
make_orthonormal_basis(N, T, B); /* Generate tangent space */
|
||||
|
||||
/* Importance sampling bias */
|
||||
rand.x = mix(rand.x, 0.0, BRDF_BIAS);
|
||||
|
||||
/* TODO distribution of visible normals */
|
||||
vec3 H = sample_ggx(rand, a2, N, T, B, NH); /* Microfacet normal */
|
||||
pdf = min(1024e32, pdf_ggx_reflect(NH, a2)); /* Theoretical limit of 16bit float */
|
||||
return reflect(-V, H);
|
||||
}
|
||||
|
||||
#define MAX_MIP 9.0
|
||||
|
||||
#ifdef STEP_RAYTRACE
|
||||
|
||||
uniform sampler2D depthBuffer;
|
||||
uniform sampler2D normalBuffer;
|
||||
uniform sampler2D specroughBuffer;
|
||||
|
||||
uniform mat4 ViewProjectionMatrix;
|
||||
|
||||
layout(location = 0) out vec4 hitData0;
|
||||
layout(location = 1) out vec4 hitData1;
|
||||
layout(location = 2) out vec4 hitData2;
|
||||
layout(location = 3) out vec4 hitData3;
|
||||
|
||||
bool has_hit_backface(vec3 hit_pos, vec3 R, vec3 V)
|
||||
{
|
||||
vec2 hit_co = project_point(ProjectionMatrix, hit_pos).xy * 0.5 + 0.5;
|
||||
vec3 hit_N = normal_decode(textureLod(normalBuffer, hit_co, 0.0).rg, V);
|
||||
return (dot(-R, hit_N) < 0.0);
|
||||
}
|
||||
|
||||
vec4 do_ssr(sampler2D depthBuffer, vec3 V, vec3 N, vec3 viewPosition, float a2, vec3 rand)
|
||||
{
|
||||
float pdf;
|
||||
vec3 R = generate_ray(V, N, a2, rand, pdf);
|
||||
|
||||
float hit_dist = raycast(depthBuffer, viewPosition, R, rand.x);
|
||||
vec3 hit_pos = viewPosition + R * abs(hit_dist);
|
||||
|
||||
if (has_hit_backface(hit_pos, R, V) || (hit_dist <= 0.0)) {
|
||||
hit_pos.z *= -1.0;
|
||||
}
|
||||
|
||||
return vec4(hit_pos, pdf);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
#ifdef FULLRES
|
||||
ivec2 fullres_texel = ivec2(gl_FragCoord.xy);
|
||||
ivec2 halfres_texel = fullres_texel;
|
||||
#else
|
||||
ivec2 fullres_texel = ivec2(gl_FragCoord.xy) * 2;
|
||||
ivec2 halfres_texel = ivec2(gl_FragCoord.xy);
|
||||
#endif
|
||||
|
||||
float depth = texelFetch(depthBuffer, fullres_texel, 0).r;
|
||||
|
||||
/* Early out */
|
||||
if (depth == 1.0)
|
||||
discard;
|
||||
|
||||
vec2 uvs = gl_FragCoord.xy / vec2(textureSize(depthBuffer, 0));
|
||||
#ifndef FULLRES
|
||||
uvs *= 2.0;
|
||||
#endif
|
||||
|
||||
/* Using view space */
|
||||
vec3 viewPosition = get_view_space_from_depth(uvs, depth);
|
||||
vec3 V = viewCameraVec;
|
||||
vec3 N = normal_decode(texelFetch(normalBuffer, fullres_texel, 0).rg, V);
|
||||
|
||||
/* Retrieve pixel data */
|
||||
vec4 speccol_roughness = texelFetch(specroughBuffer, fullres_texel, 0).rgba;
|
||||
|
||||
/* Early out */
|
||||
if (dot(speccol_roughness.rgb, vec3(1.0)) == 0.0)
|
||||
discard;
|
||||
|
||||
float roughness = speccol_roughness.a;
|
||||
float roughnessSquared = max(1e-3, roughness * roughness);
|
||||
float a2 = roughnessSquared * roughnessSquared;
|
||||
|
||||
vec3 rand = texelFetch(utilTex, ivec3(halfres_texel % LUT_SIZE, 2), 0).rba;
|
||||
|
||||
/* TODO : Raytrace together if textureGather is supported. */
|
||||
hitData0 = do_ssr(depthBuffer, V, N, viewPosition, a2, rand);
|
||||
if (rayCount > 1) hitData1 = do_ssr(depthBuffer, V, N, viewPosition, a2, rand.xyz * vec3(1.0, -1.0, -1.0));
|
||||
if (rayCount > 2) hitData2 = do_ssr(depthBuffer, V, N, viewPosition, a2, rand.xzy * vec3(1.0, 1.0, -1.0));
|
||||
if (rayCount > 3) hitData3 = do_ssr(depthBuffer, V, N, viewPosition, a2, rand.xzy * vec3(1.0, -1.0, 1.0));
|
||||
}
|
||||
|
||||
#else /* STEP_RESOLVE */
|
||||
|
||||
uniform sampler2D colorBuffer; /* previous frame */
|
||||
uniform sampler2D depthBuffer;
|
||||
uniform sampler2D normalBuffer;
|
||||
uniform sampler2D specroughBuffer;
|
||||
|
||||
uniform sampler2D hitBuffer0;
|
||||
uniform sampler2D hitBuffer1;
|
||||
uniform sampler2D hitBuffer2;
|
||||
uniform sampler2D hitBuffer3;
|
||||
|
||||
uniform int probe_count;
|
||||
|
||||
uniform float borderFadeFactor;
|
||||
uniform float fireflyFactor;
|
||||
|
||||
uniform mat4 ViewProjectionMatrix;
|
||||
uniform mat4 PastViewProjectionMatrix;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
void fallback_cubemap(vec3 N, vec3 V, vec3 W, float roughness, float roughnessSquared, inout vec4 spec_accum)
|
||||
{
|
||||
/* Specular probes */
|
||||
vec3 spec_dir = get_specular_dominant_dir(N, V, roughnessSquared);
|
||||
|
||||
/* Starts at 1 because 0 is world probe */
|
||||
for (int i = 1; i < MAX_PROBE && i < probe_count && spec_accum.a < 0.999; ++i) {
|
||||
CubeData cd = probes_data[i];
|
||||
|
||||
float fade = probe_attenuation_cube(cd, W);
|
||||
|
||||
if (fade > 0.0) {
|
||||
vec3 spec = probe_evaluate_cube(float(i), cd, W, spec_dir, roughness);
|
||||
accumulate_light(spec, fade, spec_accum);
|
||||
}
|
||||
}
|
||||
|
||||
/* World Specular */
|
||||
if (spec_accum.a < 0.999) {
|
||||
vec3 spec = probe_evaluate_world_spec(spec_dir, roughness);
|
||||
accumulate_light(spec, 1.0, spec_accum);
|
||||
}
|
||||
}
|
||||
|
||||
#if 0 /* Finish reprojection with motion vectors */
|
||||
vec3 get_motion_vector(vec3 pos)
|
||||
{
|
||||
}
|
||||
|
||||
/* http://bitsquid.blogspot.fr/2017/06/reprojecting-reflections_22.html */
|
||||
vec3 find_reflection_incident_point(vec3 cam, vec3 hit, vec3 pos, vec3 N)
|
||||
{
|
||||
float d_cam = point_plane_projection_dist(cam, pos, N);
|
||||
float d_hit = point_plane_projection_dist(hit, pos, N);
|
||||
|
||||
if (d_hit < d_cam) {
|
||||
/* Swap */
|
||||
float tmp = d_cam;
|
||||
d_cam = d_hit;
|
||||
d_hit = tmp;
|
||||
}
|
||||
|
||||
vec3 proj_cam = cam - (N * d_cam);
|
||||
vec3 proj_hit = hit - (N * d_hit);
|
||||
|
||||
return (proj_hit - proj_cam) * d_cam / (d_cam + d_hit) + proj_cam;
|
||||
}
|
||||
#endif
|
||||
|
||||
float brightness(vec3 c)
|
||||
{
|
||||
return max(max(c.r, c.g), c.b);
|
||||
}
|
||||
|
||||
float screen_border_mask(vec2 past_hit_co, vec3 hit)
|
||||
{
|
||||
/* Fade on current and past screen edges */
|
||||
vec4 hit_co = ViewProjectionMatrix * vec4(hit, 1.0);
|
||||
hit_co.xy = (hit_co.xy / hit_co.w) * 0.5 + 0.5;
|
||||
hit_co.zw = past_hit_co;
|
||||
|
||||
const float margin = 0.003;
|
||||
float atten = borderFadeFactor + margin; /* Screen percentage */
|
||||
hit_co = smoothstep(margin, atten, hit_co) * (1 - smoothstep(1.0 - atten, 1.0 - margin, hit_co));
|
||||
vec2 atten_fac = min(hit_co.xy, hit_co.zw);
|
||||
|
||||
float screenfade = atten_fac.x * atten_fac.y;
|
||||
|
||||
return screenfade;
|
||||
}
|
||||
|
||||
float view_facing_mask(vec3 V, vec3 R)
|
||||
{
|
||||
/* Fade on viewing angle (strange deformations happens at R == V) */
|
||||
return smoothstep(0.95, 0.80, dot(V, R));
|
||||
}
|
||||
|
||||
vec2 get_reprojected_reflection(vec3 hit, vec3 pos, vec3 N)
|
||||
{
|
||||
/* TODO real reprojection with motion vectors, etc... */
|
||||
return project_point(PastViewProjectionMatrix, hit).xy * 0.5 + 0.5;
|
||||
}
|
||||
|
||||
vec4 get_ssr_sample(
|
||||
sampler2D hitBuffer, vec3 worldPosition, vec3 N, vec3 V, float roughnessSquared,
|
||||
float cone_tan, vec2 source_uvs, vec2 texture_size, ivec2 target_texel,
|
||||
inout float weight_acc)
|
||||
{
|
||||
vec4 hit_co_pdf = texelFetch(hitBuffer, target_texel, 0).rgba;
|
||||
bool has_hit = (hit_co_pdf.z < 0.0);
|
||||
hit_co_pdf.z = -abs(hit_co_pdf.z);
|
||||
|
||||
/* Hit position in world space. */
|
||||
vec3 hit_pos = (ViewMatrixInverse * vec4(hit_co_pdf.xyz, 1.0)).xyz;
|
||||
|
||||
/* Find hit position in previous frame. */
|
||||
vec2 ref_uvs = get_reprojected_reflection(hit_pos, worldPosition, N);
|
||||
|
||||
/* Estimate a cone footprint to sample a corresponding mipmap level. */
|
||||
/* Compute cone footprint Using UV distance because we are using screen space filtering. */
|
||||
float cone_footprint = 1.5 * cone_tan * distance(ref_uvs, source_uvs);
|
||||
float mip = BRDF_BIAS * clamp(log2(cone_footprint * max(texture_size.x, texture_size.y)), 0.0, MAX_MIP);
|
||||
|
||||
/* Slide 54 */
|
||||
vec3 L = normalize(hit_pos - worldPosition);
|
||||
float bsdf = bsdf_ggx(N, L, V, roughnessSquared);
|
||||
float weight = step(0.001, hit_co_pdf.w) * bsdf / hit_co_pdf.w;
|
||||
weight_acc += weight;
|
||||
|
||||
vec3 sample = textureLod(colorBuffer, ref_uvs, mip).rgb;
|
||||
|
||||
/* Do not add light if ray has failed. */
|
||||
sample *= float(has_hit);
|
||||
|
||||
/* Firefly removal */
|
||||
sample /= 1.0 + fireflyFactor * brightness(sample);
|
||||
|
||||
float mask = screen_border_mask(ref_uvs, hit_pos);
|
||||
mask *= view_facing_mask(V, N);
|
||||
mask *= float(has_hit);
|
||||
|
||||
return vec4(sample, mask) * weight;
|
||||
}
|
||||
|
||||
#define NUM_NEIGHBORS 9
|
||||
|
||||
void main()
|
||||
{
|
||||
ivec2 fullres_texel = ivec2(gl_FragCoord.xy);
|
||||
#ifdef FULLRES
|
||||
ivec2 halfres_texel = fullres_texel;
|
||||
#else
|
||||
ivec2 halfres_texel = ivec2(gl_FragCoord.xy / 2.0);
|
||||
#endif
|
||||
vec2 texture_size = vec2(textureSize(depthBuffer, 0));
|
||||
vec2 uvs = gl_FragCoord.xy / texture_size;
|
||||
vec3 rand = texelFetch(utilTex, ivec3(fullres_texel % LUT_SIZE, 2), 0).rba;
|
||||
|
||||
float depth = textureLod(depthBuffer, uvs, 0.0).r;
|
||||
|
||||
/* Early out */
|
||||
if (depth == 1.0)
|
||||
discard;
|
||||
|
||||
/* Using world space */
|
||||
vec3 viewPosition = get_view_space_from_depth(uvs, depth); /* Needed for viewCameraVec */
|
||||
vec3 worldPosition = transform_point(ViewMatrixInverse, viewPosition);
|
||||
vec3 V = cameraVec;
|
||||
vec3 N = mat3(ViewMatrixInverse) * normal_decode(texelFetch(normalBuffer, fullres_texel, 0).rg, viewCameraVec);
|
||||
vec4 speccol_roughness = texelFetch(specroughBuffer, fullres_texel, 0).rgba;
|
||||
|
||||
/* Early out */
|
||||
if (dot(speccol_roughness.rgb, vec3(1.0)) == 0.0)
|
||||
discard;
|
||||
|
||||
float roughness = speccol_roughness.a;
|
||||
float roughnessSquared = max(1e-3, roughness * roughness);
|
||||
|
||||
vec4 spec_accum = vec4(0.0);
|
||||
|
||||
/* Resolve SSR */
|
||||
float cone_cos = cone_cosine(roughnessSquared);
|
||||
float cone_tan = sqrt(1 - cone_cos * cone_cos) / cone_cos;
|
||||
cone_tan *= mix(saturate(dot(N, V) * 2.0), 1.0, roughness); /* Elongation fit */
|
||||
|
||||
vec2 source_uvs = project_point(PastViewProjectionMatrix, worldPosition).xy * 0.5 + 0.5;
|
||||
|
||||
vec4 ssr_accum = vec4(0.0);
|
||||
float weight_acc = 0.0;
|
||||
const ivec2 neighbors[9] = ivec2[9](
|
||||
ivec2(0, 0),
|
||||
|
||||
ivec2(0, 1),
|
||||
ivec2(-1, -1), ivec2(1, -1),
|
||||
|
||||
ivec2(-1, 1), ivec2(1, 1),
|
||||
ivec2(0, -1),
|
||||
|
||||
ivec2(-1, 0), ivec2(1, 0)
|
||||
);
|
||||
ivec2 invert_neighbor;
|
||||
invert_neighbor.x = ((fullres_texel.x & 0x1) == 0) ? 1 : -1;
|
||||
invert_neighbor.y = ((fullres_texel.y & 0x1) == 0) ? 1 : -1;
|
||||
|
||||
for (int i = 0; i < NUM_NEIGHBORS; i++) {
|
||||
ivec2 target_texel = halfres_texel + neighbors[i] * invert_neighbor;
|
||||
|
||||
ssr_accum += get_ssr_sample(hitBuffer0, worldPosition, N, V,
|
||||
roughnessSquared, cone_tan, source_uvs,
|
||||
texture_size, target_texel, weight_acc);
|
||||
if (rayCount > 1) {
|
||||
ssr_accum += get_ssr_sample(hitBuffer1, worldPosition, N, V,
|
||||
roughnessSquared, cone_tan, source_uvs,
|
||||
texture_size, target_texel, weight_acc);
|
||||
}
|
||||
if (rayCount > 2) {
|
||||
ssr_accum += get_ssr_sample(hitBuffer2, worldPosition, N, V,
|
||||
roughnessSquared, cone_tan, source_uvs,
|
||||
texture_size, target_texel, weight_acc);
|
||||
}
|
||||
if (rayCount > 3) {
|
||||
ssr_accum += get_ssr_sample(hitBuffer3, worldPosition, N, V,
|
||||
roughnessSquared, cone_tan, source_uvs,
|
||||
texture_size, target_texel, weight_acc);
|
||||
}
|
||||
}
|
||||
|
||||
/* Compute SSR contribution */
|
||||
if (weight_acc > 0.0) {
|
||||
ssr_accum /= weight_acc;
|
||||
/* fade between 0.5 and 1.0 roughness */
|
||||
ssr_accum.a *= saturate(2.0 - roughness * 2.0);
|
||||
accumulate_light(ssr_accum.rgb, ssr_accum.a, spec_accum);
|
||||
}
|
||||
|
||||
/* If SSR contribution is not 1.0, blend with cubemaps */
|
||||
if (spec_accum.a < 1.0) {
|
||||
fallback_cubemap(N, V, worldPosition, roughness, roughnessSquared, spec_accum);
|
||||
}
|
||||
|
||||
fragColor = vec4(spec_accum.rgb * speccol_roughness.rgb, 1.0);
|
||||
}
|
||||
|
||||
#endif
|
@@ -8,18 +8,6 @@ layout(std140) uniform shadow_block {
|
||||
ShadowCascadeData shadows_cascade_data[MAX_SHADOW_CASCADE];
|
||||
};
|
||||
|
||||
layout(std140) uniform probe_block {
|
||||
CubeData probes_data[MAX_PROBE];
|
||||
};
|
||||
|
||||
layout(std140) uniform grid_block {
|
||||
GridData grids_data[MAX_GRID];
|
||||
};
|
||||
|
||||
layout(std140) uniform planar_block {
|
||||
PlanarData planars_data[MAX_PLANAR];
|
||||
};
|
||||
|
||||
layout(std140) uniform light_block {
|
||||
LightData lights_data[MAX_LIGHT];
|
||||
};
|
||||
|
@@ -60,6 +60,28 @@ struct GridData {
|
||||
#define g_resolution resolution_offset.xyz
|
||||
#define g_offset resolution_offset.w
|
||||
|
||||
#ifndef MAX_PROBE
|
||||
#define MAX_PROBE 1
|
||||
#endif
|
||||
#ifndef MAX_GRID
|
||||
#define MAX_GRID 1
|
||||
#endif
|
||||
#ifndef MAX_PLANAR
|
||||
#define MAX_PLANAR 1
|
||||
#endif
|
||||
|
||||
layout(std140) uniform probe_block {
|
||||
CubeData probes_data[MAX_PROBE];
|
||||
};
|
||||
|
||||
layout(std140) uniform grid_block {
|
||||
GridData grids_data[MAX_GRID];
|
||||
};
|
||||
|
||||
layout(std140) uniform planar_block {
|
||||
PlanarData planars_data[MAX_PLANAR];
|
||||
};
|
||||
|
||||
/* ----------- Functions --------- */
|
||||
|
||||
float probe_attenuation_cube(CubeData pd, vec3 W)
|
||||
@@ -148,14 +170,13 @@ vec3 probe_evaluate_planar(
|
||||
/* Sample reflection depth. */
|
||||
vec4 refco = pd.reflectionmat * vec4(W, 1.0);
|
||||
refco.xy /= refco.w;
|
||||
float ref_depth = textureLod(probePlanars, vec3(refco.xy, id), 0.0).a;
|
||||
|
||||
/* Find view vector / reflection plane intersection. (dist_to_plane is negative) */
|
||||
float dist_to_plane = line_plane_intersect_dist(camera_pos, V, pd.pl_plane_eq);
|
||||
vec3 point_on_plane = camera_pos + V * dist_to_plane;
|
||||
|
||||
/* How far the pixel is from the plane. */
|
||||
ref_depth = ref_depth + dist_to_plane;
|
||||
float ref_depth = 1.0; /* TODO parameter */
|
||||
|
||||
/* Compute distorded reflection vector based on the distance to the reflected object.
|
||||
* In other words find intersection between reflection vector and the sphere center
|
||||
|
@@ -1,10 +1,6 @@
|
||||
|
||||
uniform int probeIdx;
|
||||
|
||||
layout(std140) uniform planar_block {
|
||||
PlanarData planars_data[MAX_PLANAR];
|
||||
};
|
||||
|
||||
in vec3 worldPosition;
|
||||
|
||||
out vec4 FragColor;
|
||||
|
@@ -24,7 +24,7 @@ in vec3 viewNormal;
|
||||
|
||||
/* ----------- default ----------- */
|
||||
|
||||
vec3 eevee_surface_lit(vec3 N, vec3 albedo, vec3 f0, float roughness, float ao)
|
||||
vec3 eevee_surface_lit(vec3 N, vec3 albedo, vec3 f0, float roughness, float ao, int ssr_id, out vec3 ssr_spec)
|
||||
{
|
||||
/* Zero length vectors cause issues, see: T51979. */
|
||||
#if 0
|
||||
@@ -89,37 +89,40 @@ vec3 eevee_surface_lit(vec3 N, vec3 albedo, vec3 f0, float roughness, float ao)
|
||||
/* Accumulate light from all sources until accumulator is full. Then apply Occlusion and BRDF. */
|
||||
vec4 spec_accum = vec4(0.0);
|
||||
|
||||
/* Planar Reflections */
|
||||
for (int i = 0; i < MAX_PLANAR && i < planar_count && spec_accum.a < 0.999; ++i) {
|
||||
PlanarData pd = planars_data[i];
|
||||
/* SSR lobe is applied later in a defered style */
|
||||
if (ssr_id != outputSsrId) {
|
||||
/* Planar Reflections */
|
||||
for (int i = 0; i < MAX_PLANAR && i < planar_count && spec_accum.a < 0.999; ++i) {
|
||||
PlanarData pd = planars_data[i];
|
||||
|
||||
float fade = probe_attenuation_planar(pd, worldPosition, N);
|
||||
float fade = probe_attenuation_planar(pd, worldPosition, N);
|
||||
|
||||
if (fade > 0.0) {
|
||||
vec3 spec = probe_evaluate_planar(float(i), pd, worldPosition, N, V, rand.r, cameraPos, roughness, fade);
|
||||
accumulate_light(spec, fade, spec_accum);
|
||||
if (fade > 0.0) {
|
||||
vec3 spec = probe_evaluate_planar(float(i), pd, worldPosition, N, V, rand.r, cameraPos, roughness, fade);
|
||||
accumulate_light(spec, fade, spec_accum);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Specular probes */
|
||||
vec3 spec_dir = get_specular_dominant_dir(N, V, roughnessSquared);
|
||||
/* Specular probes */
|
||||
vec3 spec_dir = get_specular_dominant_dir(N, V, roughnessSquared);
|
||||
|
||||
/* Starts at 1 because 0 is world probe */
|
||||
for (int i = 1; i < MAX_PROBE && i < probe_count && spec_accum.a < 0.999; ++i) {
|
||||
CubeData cd = probes_data[i];
|
||||
/* Starts at 1 because 0 is world probe */
|
||||
for (int i = 1; i < MAX_PROBE && i < probe_count && spec_accum.a < 0.999; ++i) {
|
||||
CubeData cd = probes_data[i];
|
||||
|
||||
float fade = probe_attenuation_cube(cd, worldPosition);
|
||||
float fade = probe_attenuation_cube(cd, worldPosition);
|
||||
|
||||
if (fade > 0.0) {
|
||||
vec3 spec = probe_evaluate_cube(float(i), cd, worldPosition, spec_dir, roughness);
|
||||
accumulate_light(spec, fade, spec_accum);
|
||||
if (fade > 0.0) {
|
||||
vec3 spec = probe_evaluate_cube(float(i), cd, worldPosition, spec_dir, roughness);
|
||||
accumulate_light(spec, fade, spec_accum);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* World Specular */
|
||||
if (spec_accum.a < 0.999) {
|
||||
vec3 spec = probe_evaluate_world_spec(spec_dir, roughness);
|
||||
accumulate_light(spec, 1.0, spec_accum);
|
||||
/* World Specular */
|
||||
if (spec_accum.a < 0.999) {
|
||||
vec3 spec = probe_evaluate_world_spec(spec_dir, roughness);
|
||||
accumulate_light(spec, 1.0, spec_accum);
|
||||
}
|
||||
}
|
||||
|
||||
/* Ambient Occlusion */
|
||||
@@ -130,7 +133,8 @@ vec3 eevee_surface_lit(vec3 N, vec3 albedo, vec3 f0, float roughness, float ao)
|
||||
vec2 uv = lut_coords(dot(N, V), roughness);
|
||||
vec2 brdf_lut = texture(utilTex, vec3(uv, 1.0)).rg;
|
||||
|
||||
out_light += spec_accum.rgb * F_ibl(f0, brdf_lut) * specular_occlusion(dot(N, V), final_ao, roughness) * float(specToggle);
|
||||
ssr_spec = F_ibl(f0, brdf_lut) * specular_occlusion(dot(N, V), final_ao, roughness);
|
||||
out_light += spec_accum.rgb * ssr_spec * float(specToggle);
|
||||
|
||||
/* ---------------- DIFFUSE ENVIRONMENT LIGHTING ----------------- */
|
||||
|
||||
@@ -166,7 +170,7 @@ vec3 eevee_surface_lit(vec3 N, vec3 albedo, vec3 f0, float roughness, float ao)
|
||||
vec3 eevee_surface_clearcoat_lit(
|
||||
vec3 N, vec3 albedo, vec3 f0, float roughness,
|
||||
vec3 C_N, float C_intensity, float C_roughness, /* Clearcoat params */
|
||||
float ao)
|
||||
float ao, int ssr_id, out vec3 ssr_spec)
|
||||
{
|
||||
roughness = clamp(roughness, 1e-8, 0.9999);
|
||||
float roughnessSquared = roughness * roughness;
|
||||
@@ -233,8 +237,10 @@ vec3 eevee_surface_clearcoat_lit(
|
||||
float fade = probe_attenuation_planar(pd, worldPosition, worldNormal);
|
||||
|
||||
if (fade > 0.0) {
|
||||
vec3 spec = probe_evaluate_planar(float(i), pd, worldPosition, N, V, rand.r, cameraPos, roughness, fade);
|
||||
accumulate_light(spec, fade, spec_accum);
|
||||
if (ssr_id != outputSsrId) {
|
||||
vec3 spec = probe_evaluate_planar(float(i), pd, worldPosition, N, V, rand.r, cameraPos, roughness, fade);
|
||||
accumulate_light(spec, fade, spec_accum);
|
||||
}
|
||||
|
||||
vec3 C_spec = probe_evaluate_planar(float(i), pd, worldPosition, C_N, V, rand.r, cameraPos, C_roughness, fade);
|
||||
accumulate_light(C_spec, fade, C_spec_accum);
|
||||
@@ -252,8 +258,10 @@ vec3 eevee_surface_clearcoat_lit(
|
||||
float fade = probe_attenuation_cube(cd, worldPosition);
|
||||
|
||||
if (fade > 0.0) {
|
||||
vec3 spec = probe_evaluate_cube(float(i), cd, worldPosition, spec_dir, roughness);
|
||||
accumulate_light(spec, fade, spec_accum);
|
||||
if (ssr_id != outputSsrId) {
|
||||
vec3 spec = probe_evaluate_cube(float(i), cd, worldPosition, spec_dir, roughness);
|
||||
accumulate_light(spec, fade, spec_accum);
|
||||
}
|
||||
|
||||
vec3 C_spec = probe_evaluate_cube(float(i), cd, worldPosition, C_spec_dir, C_roughness);
|
||||
accumulate_light(C_spec, fade, C_spec_accum);
|
||||
@@ -262,8 +270,10 @@ vec3 eevee_surface_clearcoat_lit(
|
||||
|
||||
/* World Specular */
|
||||
if (spec_accum.a < 0.999) {
|
||||
vec3 spec = probe_evaluate_world_spec(spec_dir, roughness);
|
||||
accumulate_light(spec, 1.0, spec_accum);
|
||||
if (ssr_id != outputSsrId) {
|
||||
vec3 spec = probe_evaluate_world_spec(spec_dir, roughness);
|
||||
accumulate_light(spec, 1.0, spec_accum);
|
||||
}
|
||||
|
||||
vec3 C_spec = probe_evaluate_world_spec(C_spec_dir, C_roughness);
|
||||
accumulate_light(C_spec, 1.0, C_spec_accum);
|
||||
@@ -277,7 +287,8 @@ vec3 eevee_surface_clearcoat_lit(
|
||||
vec2 uv = lut_coords(dot(N, V), roughness);
|
||||
vec2 brdf_lut = texture(utilTex, vec3(uv, 1.0)).rg;
|
||||
|
||||
out_light += spec_accum.rgb * F_ibl(f0, brdf_lut) * specular_occlusion(dot(N, V), final_ao, roughness) * float(specToggle);
|
||||
ssr_spec = F_ibl(f0, brdf_lut) * specular_occlusion(dot(N, V), final_ao, roughness);
|
||||
out_light += spec_accum.rgb * ssr_spec * float(specToggle);
|
||||
|
||||
uv = lut_coords(dot(C_N, V), C_roughness);
|
||||
brdf_lut = texture(utilTex, vec3(uv, 1.0)).rg;
|
||||
@@ -392,7 +403,7 @@ vec3 eevee_surface_diffuse_lit(vec3 N, vec3 albedo, float ao)
|
||||
|
||||
/* ----------- Glossy ----------- */
|
||||
|
||||
vec3 eevee_surface_glossy_lit(vec3 N, vec3 f0, float roughness, float ao)
|
||||
vec3 eevee_surface_glossy_lit(vec3 N, vec3 f0, float roughness, float ao, int ssr_id, out vec3 ssr_spec)
|
||||
{
|
||||
roughness = clamp(roughness, 1e-8, 0.9999);
|
||||
float roughnessSquared = roughness * roughness;
|
||||
@@ -442,37 +453,39 @@ vec3 eevee_surface_glossy_lit(vec3 N, vec3 f0, float roughness, float ao)
|
||||
/* Accumulate light from all sources until accumulator is full. Then apply Occlusion and BRDF. */
|
||||
vec4 spec_accum = vec4(0.0);
|
||||
|
||||
/* Planar Reflections */
|
||||
for (int i = 0; i < MAX_PLANAR && i < planar_count && spec_accum.a < 0.999; ++i) {
|
||||
PlanarData pd = planars_data[i];
|
||||
if (ssr_id != outputSsrId) {
|
||||
/* Planar Reflections */
|
||||
for (int i = 0; i < MAX_PLANAR && i < planar_count && spec_accum.a < 0.999; ++i) {
|
||||
PlanarData pd = planars_data[i];
|
||||
|
||||
float fade = probe_attenuation_planar(pd, worldPosition, N);
|
||||
float fade = probe_attenuation_planar(pd, worldPosition, N);
|
||||
|
||||
if (fade > 0.0) {
|
||||
vec3 spec = probe_evaluate_planar(float(i), pd, worldPosition, N, V, rand.r, cameraPos, roughness, fade);
|
||||
accumulate_light(spec, fade, spec_accum);
|
||||
if (fade > 0.0) {
|
||||
vec3 spec = probe_evaluate_planar(float(i), pd, worldPosition, N, V, rand.r, cameraPos, roughness, fade);
|
||||
accumulate_light(spec, fade, spec_accum);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Specular probes */
|
||||
vec3 spec_dir = get_specular_dominant_dir(N, V, roughnessSquared);
|
||||
/* Specular probes */
|
||||
vec3 spec_dir = get_specular_dominant_dir(N, V, roughnessSquared);
|
||||
|
||||
/* Starts at 1 because 0 is world probe */
|
||||
for (int i = 1; i < MAX_PROBE && i < probe_count && spec_accum.a < 0.999; ++i) {
|
||||
CubeData cd = probes_data[i];
|
||||
/* Starts at 1 because 0 is world probe */
|
||||
for (int i = 1; i < MAX_PROBE && i < probe_count && spec_accum.a < 0.999; ++i) {
|
||||
CubeData cd = probes_data[i];
|
||||
|
||||
float fade = probe_attenuation_cube(cd, worldPosition);
|
||||
float fade = probe_attenuation_cube(cd, worldPosition);
|
||||
|
||||
if (fade > 0.0) {
|
||||
vec3 spec = probe_evaluate_cube(float(i), cd, worldPosition, spec_dir, roughness);
|
||||
accumulate_light(spec, fade, spec_accum);
|
||||
if (fade > 0.0) {
|
||||
vec3 spec = probe_evaluate_cube(float(i), cd, worldPosition, spec_dir, roughness);
|
||||
accumulate_light(spec, fade, spec_accum);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* World Specular */
|
||||
if (spec_accum.a < 0.999) {
|
||||
vec3 spec = probe_evaluate_world_spec(spec_dir, roughness);
|
||||
accumulate_light(spec, 1.0, spec_accum);
|
||||
/* World Specular */
|
||||
if (spec_accum.a < 0.999) {
|
||||
vec3 spec = probe_evaluate_world_spec(spec_dir, roughness);
|
||||
accumulate_light(spec, 1.0, spec_accum);
|
||||
}
|
||||
}
|
||||
|
||||
/* Ambient Occlusion */
|
||||
@@ -483,7 +496,8 @@ vec3 eevee_surface_glossy_lit(vec3 N, vec3 f0, float roughness, float ao)
|
||||
vec2 uv = lut_coords(dot(N, V), roughness);
|
||||
vec2 brdf_lut = texture(utilTex, vec3(uv, 1.0)).rg;
|
||||
|
||||
out_light += spec_accum.rgb * F_ibl(f0, brdf_lut) * specular_occlusion(dot(N, V), final_ao, roughness) * float(specToggle);
|
||||
ssr_spec = F_ibl(f0, brdf_lut) * specular_occlusion(dot(N, V), final_ao, roughness);
|
||||
out_light += spec_accum.rgb * ssr_spec * float(specToggle);
|
||||
|
||||
return out_light;
|
||||
}
|
||||
|
177
source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl
Normal file
177
source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl
Normal file
@@ -0,0 +1,177 @@
|
||||
/* Based on work from Morgan McGuire and Michael Mara at Williams College 2014
|
||||
* Released as open source under the BSD 2-Clause License
|
||||
* http://opensource.org/licenses/BSD-2-Clause
|
||||
* http://casual-effects.blogspot.fr/2014/08/screen-space-ray-tracing.html */
|
||||
|
||||
#define MAX_STEP 256
|
||||
#define MAX_REFINE_STEP 32 /* Should be max allowed stride */
|
||||
|
||||
uniform mat4 PixelProjMatrix; /* View > NDC > Texel : maps view coords to texel coord */
|
||||
uniform vec2 ssrParameters;
|
||||
|
||||
#define ssrStride ssrParameters.x
|
||||
#define ssrThickness ssrParameters.y
|
||||
|
||||
void swapIfBigger(inout float a, inout float b)
|
||||
{
|
||||
if (a > b) {
|
||||
float temp = a;
|
||||
a = b;
|
||||
b = temp;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the length of the ray if there is a hit, and negate it if not hit occured */
|
||||
float raycast(sampler2D depth_texture, vec3 ray_origin, vec3 ray_dir, float ray_jitter)
|
||||
{
|
||||
float near = get_view_z_from_depth(0.0); /* TODO optimize */
|
||||
float far = get_view_z_from_depth(1.0); /* TODO optimize */
|
||||
|
||||
/* Clip ray to a near/far plane in 3D */
|
||||
float ray_length = 1e16;
|
||||
if ((ray_origin.z + ray_dir.z * ray_length) > near) {
|
||||
ray_length = (near - ray_origin.z) / ray_dir.z;
|
||||
}
|
||||
else {
|
||||
ray_length = (ray_origin.z - far) / -ray_dir.z;
|
||||
}
|
||||
|
||||
vec3 ray_end = ray_dir * ray_length + ray_origin;
|
||||
|
||||
/* Project into screen space */
|
||||
vec4 H0 = PixelProjMatrix * vec4(ray_origin, 1.0);
|
||||
vec4 H1 = PixelProjMatrix * vec4(ray_end, 1.0);
|
||||
|
||||
/* There are a lot of divisions by w that can be turned into multiplications
|
||||
* at some minor precision loss...and we need to interpolate these 1/w values
|
||||
* anyway. */
|
||||
float k0 = 1.0 / H0.w;
|
||||
float k1 = 1.0 / H1.w;
|
||||
|
||||
/* Switch the original points to values that interpolate linearly in 2D */
|
||||
vec3 Q0 = ray_origin * k0;
|
||||
vec3 Q1 = ray_end * k1;
|
||||
|
||||
/* Screen-space endpoints */
|
||||
vec2 P0 = H0.xy * k0;
|
||||
vec2 P1 = H1.xy * k1;
|
||||
|
||||
/* [Optional clipping to frustum sides here] */
|
||||
|
||||
/* If the line is degenerate, make it cover at least one pixel
|
||||
* to not have to handle zero-pixel extent as a special case later */
|
||||
P1 += vec2((distance_squared(P0, P1) < 0.0001) ? 0.01 : 0.0);
|
||||
|
||||
vec2 delta = P1 - P0;
|
||||
|
||||
/* Permute so that the primary iteration is in x to reduce large branches later.
|
||||
* After this, "x" is the primary iteration direction and "y" is the secondary one
|
||||
* If it is a more-vertical line, create a permutation that swaps x and y in the output
|
||||
* and directly swizzle the inputs. */
|
||||
bool permute = false;
|
||||
if (abs(delta.x) < abs(delta.y)) {
|
||||
permute = true;
|
||||
delta = delta.yx;
|
||||
P1 = P1.yx;
|
||||
P0 = P0.yx;
|
||||
}
|
||||
|
||||
/* Track the derivatives */
|
||||
float step_sign = sign(delta.x);
|
||||
float invdx = step_sign / delta.x;
|
||||
vec2 dP = vec2(step_sign, invdx * delta.y);
|
||||
vec3 dQ = (Q1 - Q0) * invdx;
|
||||
float dk = (k1 - k0) * invdx;
|
||||
|
||||
/* Slide each value from the start of the ray to the end */
|
||||
vec4 pqk = vec4(P0, Q0.z, k0);
|
||||
|
||||
/* Scale derivatives by the desired pixel stride */
|
||||
vec4 dPQK = vec4(dP, dQ.z, dk) * ssrStride;
|
||||
|
||||
/* We track the ray depth at +/- 1/2 pixel to treat pixels as clip-space solid
|
||||
* voxels. Because the depth at -1/2 for a given pixel will be the same as at
|
||||
* +1/2 for the previous iteration, we actually only have to compute one value
|
||||
* per iteration. */
|
||||
float prev_zmax = ray_origin.z;
|
||||
float zmax;
|
||||
|
||||
/* P1.x is never modified after this point, so pre-scale it by
|
||||
* the step direction for a signed comparison */
|
||||
float end = P1.x * step_sign;
|
||||
|
||||
/* Initial offset */
|
||||
pqk += dPQK * (0.01 + ray_jitter);
|
||||
|
||||
bool hit = false;
|
||||
float raw_depth;
|
||||
for (float hitstep = 0.0; hitstep < MAX_STEP && !hit; hitstep++) {
|
||||
/* Ray finished & no hit*/
|
||||
if ((pqk.x * step_sign) > end) break;
|
||||
|
||||
/* step through current cell */
|
||||
pqk += dPQK;
|
||||
|
||||
ivec2 hitpixel = ivec2(permute ? pqk.yx : pqk.xy);
|
||||
raw_depth = texelFetch(depth_texture, ivec2(hitpixel), 0).r;
|
||||
|
||||
float zmin = prev_zmax;
|
||||
zmax = (dPQK.z * 0.5 + pqk.z) / (dPQK.w * 0.5 + pqk.w);
|
||||
prev_zmax = zmax;
|
||||
swapIfBigger(zmin, zmax);
|
||||
|
||||
float vmax = get_view_z_from_depth(raw_depth);
|
||||
float vmin = vmax - ssrThickness;
|
||||
|
||||
/* Check if we are somewhere near the surface. */
|
||||
/* Note: we consider hitting the screen borders (raw_depth == 0.0)
|
||||
* as valid to check for occluder in the refine pass */
|
||||
if (!((zmin > vmax) || (zmax < vmin)) || (raw_depth == 0.0)) {
|
||||
/* Below surface, cannot trace further */
|
||||
hit = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (hit) {
|
||||
/* Rewind back a step. */
|
||||
pqk -= dPQK;
|
||||
|
||||
/* And do a finer trace over this segment. */
|
||||
dPQK /= ssrStride;
|
||||
|
||||
prev_zmax = (dPQK.z * -0.5 + pqk.z) / (dPQK.w * -0.5 + pqk.w);
|
||||
|
||||
for (float refinestep = 0.0; refinestep < (ssrStride * 2.0) && refinestep < (MAX_REFINE_STEP * 2.0); refinestep++) {
|
||||
/* step through current cell */
|
||||
pqk += dPQK;
|
||||
|
||||
ivec2 hitpixel = ivec2(permute ? pqk.yx : pqk.xy);
|
||||
raw_depth = texelFetch(depth_texture, hitpixel, 0).r;
|
||||
|
||||
float zmin = prev_zmax;
|
||||
zmax = (dPQK.z * 0.5 + pqk.z) / (dPQK.w * 0.5 + pqk.w);
|
||||
prev_zmax = zmax;
|
||||
swapIfBigger(zmin, zmax);
|
||||
|
||||
float vmax = get_view_z_from_depth(raw_depth);
|
||||
float vmin = vmax - ssrThickness;
|
||||
|
||||
/* Check if we are somewhere near the surface. */
|
||||
if (!((zmin > vmax) || (zmax < vmin)) || (raw_depth == 0.0)) {
|
||||
/* Below surface, cannot trace further */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If we did hit the background, get exact ray. */
|
||||
if (raw_depth == 1.0) {
|
||||
zmax = get_view_z_from_depth(1.0); /* TODO optimize */
|
||||
}
|
||||
|
||||
hit = hit && (raw_depth != 0.0);
|
||||
|
||||
/* Return length */
|
||||
float result = (zmax - ray_origin.z) / ray_dir.z;
|
||||
return (hit) ? result : -result;
|
||||
}
|
@@ -558,8 +558,14 @@ void GPU_framebuffer_recursive_downsample(
|
||||
attachment = GL_COLOR_ATTACHMENT0;
|
||||
|
||||
/* last bound prevails here, better allow explicit control here too */
|
||||
glDrawBuffer(GL_COLOR_ATTACHMENT0);
|
||||
glReadBuffer(GL_COLOR_ATTACHMENT0);
|
||||
if (GPU_texture_depth(tex)) {
|
||||
glDrawBuffer(GL_NONE);
|
||||
glReadBuffer(GL_NONE);
|
||||
}
|
||||
else {
|
||||
glDrawBuffer(GL_COLOR_ATTACHMENT0);
|
||||
glReadBuffer(GL_COLOR_ATTACHMENT0);
|
||||
}
|
||||
|
||||
for (int i=1; i < num_iter+1 && (current_dim[0] > 1 && current_dim[1] > 1); i++) {
|
||||
|
||||
|
@@ -2663,6 +2663,8 @@ void node_bsdf_diffuse(vec4 color, float roughness, vec3 N, out Closure result)
|
||||
{
|
||||
#ifdef EEVEE_ENGINE
|
||||
vec3 L = eevee_surface_diffuse_lit(N, vec3(1.0), 1.0);
|
||||
vec3 vN = normalize(mat3(ViewMatrix) * N);
|
||||
result = Closure(L * color.rgb, 1.0, vec4(0.0), normal_encode(N, viewCameraVec), -1);
|
||||
#else
|
||||
/* ambient light */
|
||||
vec3 L = vec3(0.2);
|
||||
@@ -2675,15 +2677,19 @@ void node_bsdf_diffuse(vec4 color, float roughness, vec3 N, out Closure result)
|
||||
float bsdf = max(dot(N, light_position), 0.0);
|
||||
L += light_diffuse * bsdf;
|
||||
}
|
||||
#endif
|
||||
|
||||
result = Closure(L * color.rgb, 1.0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void node_bsdf_glossy(vec4 color, float roughness, vec3 N, out Closure result)
|
||||
void node_bsdf_glossy(vec4 color, float roughness, vec3 N, float ssr_id, out Closure result)
|
||||
{
|
||||
#ifdef EEVEE_ENGINE
|
||||
vec3 L = eevee_surface_glossy_lit(N, vec3(1.0), roughness, 1.0);
|
||||
vec3 ssr_spec;
|
||||
roughness = sqrt(roughness);
|
||||
vec3 L = eevee_surface_glossy_lit(N, vec3(1.0), roughness, 1.0, int(ssr_id), ssr_spec);
|
||||
vec3 vN = normalize(mat3(ViewMatrix) * N);
|
||||
result = Closure(L * color.rgb, 1.0, vec4(ssr_spec * color.rgb, roughness), normal_encode(vN, viewCameraVec), int(ssr_id));
|
||||
#else
|
||||
/* ambient light */
|
||||
vec3 L = vec3(0.2);
|
||||
@@ -2702,9 +2708,9 @@ void node_bsdf_glossy(vec4 color, float roughness, vec3 N, out Closure result)
|
||||
bsdf += 0.5 * max(dot(N, light_position), 0.0);
|
||||
L += light_specular * bsdf;
|
||||
}
|
||||
#endif
|
||||
|
||||
result = Closure(L * color.rgb, 1.0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void node_bsdf_anisotropic(
|
||||
@@ -2724,6 +2730,7 @@ void node_bsdf_toon(vec4 color, float size, float tsmooth, vec3 N, out Closure r
|
||||
node_bsdf_diffuse(color, 0.0, N, result);
|
||||
}
|
||||
|
||||
#ifndef EEVEE_ENGINE
|
||||
void node_bsdf_principled(vec4 base_color, float subsurface, vec3 subsurface_radius, vec4 subsurface_color, float metallic, float specular,
|
||||
float specular_tint, float roughness, float anisotropic, float anisotropic_rotation, float sheen, float sheen_tint, float clearcoat,
|
||||
float clearcoat_roughness, float ior, float transmission, float transmission_roughness, vec3 N, vec3 CN, vec3 T, vec3 I, out Closure result)
|
||||
@@ -2821,16 +2828,19 @@ void node_bsdf_principled(vec4 base_color, float subsurface, vec3 subsurface_rad
|
||||
|
||||
result = Closure(L, 1.0);
|
||||
}
|
||||
#endif
|
||||
|
||||
void node_bsdf_principled_simple(vec4 base_color, float subsurface, vec3 subsurface_radius, vec4 subsurface_color, float metallic, float specular,
|
||||
float specular_tint, float roughness, float anisotropic, float anisotropic_rotation, float sheen, float sheen_tint, float clearcoat,
|
||||
float clearcoat_roughness, float ior, float transmission, float transmission_roughness, vec3 N, vec3 CN, vec3 T, vec3 I, out Closure result)
|
||||
float clearcoat_roughness, float ior, float transmission, float transmission_roughness, vec3 N, vec3 CN, vec3 T, vec3 I, float ssr_id, out Closure result)
|
||||
{
|
||||
#ifdef EEVEE_ENGINE
|
||||
vec3 diffuse, f0;
|
||||
vec3 diffuse, f0, ssr_spec;
|
||||
convert_metallic_to_specular_tinted(base_color.rgb, metallic, specular, specular_tint, diffuse, f0);
|
||||
|
||||
result = Closure(eevee_surface_lit(N, diffuse, f0, roughness, 1.0), 1.0);
|
||||
vec3 L = eevee_surface_lit(N, diffuse, f0, roughness, 1.0, int(ssr_id), ssr_spec);
|
||||
vec3 vN = normalize(mat3(ViewMatrix) * N);
|
||||
result = Closure(L, 1.0, vec4(ssr_spec, roughness), normal_encode(vN, viewCameraVec), int(ssr_id));
|
||||
#else
|
||||
node_bsdf_principled(base_color, subsurface, subsurface_radius, subsurface_color, metallic, specular,
|
||||
specular_tint, roughness, anisotropic, anisotropic_rotation, sheen, sheen_tint, clearcoat,
|
||||
@@ -2840,10 +2850,10 @@ void node_bsdf_principled_simple(vec4 base_color, float subsurface, vec3 subsurf
|
||||
|
||||
void node_bsdf_principled_clearcoat(vec4 base_color, float subsurface, vec3 subsurface_radius, vec4 subsurface_color, float metallic, float specular,
|
||||
float specular_tint, float roughness, float anisotropic, float anisotropic_rotation, float sheen, float sheen_tint, float clearcoat,
|
||||
float clearcoat_roughness, float ior, float transmission, float transmission_roughness, vec3 N, vec3 CN, vec3 T, vec3 I, out Closure result)
|
||||
float clearcoat_roughness, float ior, float transmission, float transmission_roughness, vec3 N, vec3 CN, vec3 T, vec3 I, float ssr_id, out Closure result)
|
||||
{
|
||||
#ifdef EEVEE_ENGINE
|
||||
vec3 diffuse, f0;
|
||||
vec3 diffuse, f0, ssr_spec;
|
||||
convert_metallic_to_specular_tinted(base_color.rgb, metallic, specular, specular_tint, diffuse, f0);
|
||||
|
||||
clearcoat *= 0.25;
|
||||
@@ -2865,13 +2875,16 @@ void node_bsdf_principled_clearcoat(vec4 base_color, float subsurface, vec3 subs
|
||||
N = tangent_to_world(Ht, N, Y, X);
|
||||
|
||||
if (dot(N, cameraVec) > 0) {
|
||||
surface_color.rgb += eevee_surface_clearcoat_lit(N, diffuse, f0, sqrt(min(ax, ay)), CN, clearcoat, clearcoat_roughness, 1.0);
|
||||
surface_color.rgb += eevee_surface_clearcoat_lit(N, diffuse, f0, sqrt(min(ax, ay)), CN, clearcoat, clearcoat_roughness, 1.0, ssr_id);
|
||||
surface_color.a += 1.0;
|
||||
}
|
||||
}
|
||||
result = Closure(surface_color.rgb / surface_color.a, 1.0);
|
||||
#else
|
||||
result = Closure(eevee_surface_clearcoat_lit(N, diffuse, f0, roughness, CN, clearcoat, clearcoat_roughness, 1.0), 1.0);
|
||||
|
||||
vec3 L = eevee_surface_clearcoat_lit(N, diffuse, f0, roughness, CN, clearcoat, clearcoat_roughness, 1.0, int(ssr_id), ssr_spec);
|
||||
vec3 vN = normalize(mat3(ViewMatrix) * N);
|
||||
result = Closure(L, 1.0, vec4(ssr_spec, roughness), normal_encode(vN, viewCameraVec), int(ssr_id));
|
||||
#endif
|
||||
|
||||
#else
|
||||
@@ -2905,6 +2918,8 @@ void node_subsurface_scattering(
|
||||
node_bsdf_diffuse(color, 0.0, N, result);
|
||||
}
|
||||
|
||||
/* Unsupported for now */
|
||||
#ifndef EEVEE_ENGINE
|
||||
void node_bsdf_hair(vec4 color, float offset, float roughnessu, float roughnessv, vec3 tangent, out Closure result)
|
||||
{
|
||||
result = Closure(color.rgb, color.a);
|
||||
@@ -2919,6 +2934,8 @@ void node_ambient_occlusion(vec4 color, out Closure result)
|
||||
{
|
||||
result = Closure(color.rgb, color.a);
|
||||
}
|
||||
#endif /* EEVEE_ENGINE */
|
||||
|
||||
#endif /* VOLUMETRICS */
|
||||
|
||||
/* emission */
|
||||
@@ -2927,7 +2944,11 @@ void node_emission(vec4 color, float strength, vec3 N, out Closure result)
|
||||
{
|
||||
#ifndef VOLUMETRICS
|
||||
color *= strength;
|
||||
#ifdef EEVEE_ENGINE
|
||||
result = Closure(color.rgb, color.a, vec4(0.0), normal_encode(N, viewCameraVec), -1);
|
||||
#else
|
||||
result = Closure(color.rgb, color.a);
|
||||
#endif
|
||||
#else
|
||||
result = Closure(vec3(0.0), vec3(0.0), color.rgb * strength, 0.0);
|
||||
#endif
|
||||
@@ -2952,7 +2973,11 @@ void node_background(vec4 color, float strength, out Closure result)
|
||||
{
|
||||
#ifndef VOLUMETRICS
|
||||
color *= strength;
|
||||
#ifdef EEVEE_ENGINE
|
||||
result = Closure(color.rgb, color.a, vec4(0.0), vec2(0.0), -1);
|
||||
#else
|
||||
result = Closure(color.rgb, color.a);
|
||||
#endif
|
||||
#else
|
||||
result = CLOSURE_DEFAULT;
|
||||
#endif
|
||||
@@ -3995,7 +4020,11 @@ uniform float backgroundAlpha;
|
||||
void node_output_world(Closure surface, Closure volume, out Closure result)
|
||||
{
|
||||
#ifndef VOLUMETRICS
|
||||
#ifdef EEVEE_ENGINE
|
||||
result = Closure(surface.radiance, backgroundAlpha, vec4(0.0), vec2(0.0), -1);
|
||||
#else
|
||||
result = Closure(surface.radiance, backgroundAlpha);
|
||||
#endif
|
||||
#else
|
||||
result = volume;
|
||||
#endif /* VOLUMETRICS */
|
||||
@@ -4013,29 +4042,31 @@ void world_normals_get(out vec3 N)
|
||||
void node_eevee_metallic(
|
||||
vec4 basecol, float metallic, float specular, float roughness, vec4 emissive, float transp, vec3 normal,
|
||||
float clearcoat, float clearcoat_roughness, vec3 clearcoat_normal,
|
||||
float occlusion, out Closure result)
|
||||
float occlusion, float ssr_id, out Closure result)
|
||||
{
|
||||
vec3 diffuse, f0;
|
||||
vec3 diffuse, f0, ssr_spec;
|
||||
convert_metallic_to_specular(basecol.rgb, metallic, specular, diffuse, f0);
|
||||
|
||||
result = Closure(eevee_surface_lit(normal, diffuse, f0, roughness, occlusion) + emissive.rgb, 1.0 - transp);
|
||||
vec3 L = eevee_surface_lit(normal, diffuse, f0, roughness, occlusion, int(ssr_id), ssr_spec);
|
||||
vec3 vN = normalize(mat3(ViewMatrix) * normal);
|
||||
result = Closure(L + emissive.rgb, 1.0 - transp, vec4(ssr_spec, roughness), normal_encode(vN, viewCameraVec), int(ssr_id));
|
||||
}
|
||||
|
||||
void node_eevee_specular(
|
||||
vec4 diffuse, vec4 specular, float roughness, vec4 emissive, float transp, vec3 normal,
|
||||
float clearcoat, float clearcoat_roughness, vec3 clearcoat_normal,
|
||||
float occlusion, out Closure result)
|
||||
float occlusion, float ssr_id, out Closure result)
|
||||
{
|
||||
result = Closure(eevee_surface_lit(normal, diffuse.rgb, specular.rgb, roughness, occlusion) + emissive.rgb, 1.0 - transp);
|
||||
vec3 ssr_spec;
|
||||
|
||||
vec3 L = eevee_surface_lit(normal, diffuse.rgb, specular.rgb, roughness, occlusion, int(ssr_id), ssr_spec);
|
||||
vec3 vN = normalize(mat3(ViewMatrix) * normal);
|
||||
result = Closure(L + emissive.rgb, 1.0 - transp, vec4(ssr_spec, roughness), normal_encode(vN, viewCameraVec), int(ssr_id));
|
||||
}
|
||||
|
||||
void node_output_eevee_material(Closure surface, out Closure result)
|
||||
{
|
||||
#if defined(USE_ALPHA_HASH) || defined(USE_ALPHA_CLIP) || defined(USE_ALPHA_BLEND)
|
||||
result = surface;
|
||||
#else
|
||||
result = Closure(surface.radiance, length(viewPosition));
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* EEVEE_ENGINE */
|
||||
|
@@ -214,8 +214,11 @@ typedef struct bNode {
|
||||
* and replacing all uses with per-instance data.
|
||||
*/
|
||||
short preview_xsize, preview_ysize; /* reserved size of the preview rect */
|
||||
int pad2;
|
||||
short pad2[2];
|
||||
struct uiBlock *block; /* runtime during drawing */
|
||||
|
||||
float ssr_id; /* XXX: eevee only, id of screen space reflection layer, needs to be a float to feed GPU_uniform. */
|
||||
float pad3;
|
||||
} bNode;
|
||||
|
||||
/* node->flag */
|
||||
|
@@ -2622,6 +2622,13 @@ RNA_LAYER_ENGINE_EEVEE_GET_SET_FLOAT(volumetric_light_clamp)
|
||||
RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(volumetric_shadows)
|
||||
RNA_LAYER_ENGINE_EEVEE_GET_SET_INT(volumetric_shadow_samples)
|
||||
RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(volumetric_colored_transmittance)
|
||||
RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(ssr_enable)
|
||||
RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(ssr_halfres)
|
||||
RNA_LAYER_ENGINE_EEVEE_GET_SET_INT(ssr_ray_count)
|
||||
RNA_LAYER_ENGINE_EEVEE_GET_SET_INT(ssr_stride)
|
||||
RNA_LAYER_ENGINE_EEVEE_GET_SET_FLOAT(ssr_thickness)
|
||||
RNA_LAYER_ENGINE_EEVEE_GET_SET_FLOAT(ssr_border_fade)
|
||||
RNA_LAYER_ENGINE_EEVEE_GET_SET_FLOAT(ssr_firefly_fac)
|
||||
|
||||
/* object engine */
|
||||
RNA_LAYER_MODE_OBJECT_GET_SET_BOOL(show_wire)
|
||||
@@ -6176,6 +6183,62 @@ static void rna_def_scene_layer_engine_settings_eevee(BlenderRNA *brna)
|
||||
|
||||
/* see RNA_LAYER_ENGINE_GET_SET macro */
|
||||
|
||||
/* Screen Space Reflection */
|
||||
prop = RNA_def_property(srna, "ssr_enable", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_Eevee_ssr_enable_get",
|
||||
"rna_LayerEngineSettings_Eevee_ssr_enable_set");
|
||||
RNA_def_property_ui_text(prop, "Screen Space Reflections", "Enable screen space reflection");
|
||||
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
|
||||
RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_SceneLayerEngineSettings_update");
|
||||
|
||||
prop = RNA_def_property(srna, "ssr_halfres", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_Eevee_ssr_halfres_get",
|
||||
"rna_LayerEngineSettings_Eevee_ssr_halfres_set");
|
||||
RNA_def_property_ui_text(prop, "Half Res Trace", "Raytrace at a lower resolution");
|
||||
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
|
||||
RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_SceneLayerEngineSettings_update");
|
||||
|
||||
prop = RNA_def_property(srna, "ssr_stride", PROP_INT, PROP_PIXEL);
|
||||
RNA_def_property_int_funcs(prop, "rna_LayerEngineSettings_Eevee_ssr_stride_get",
|
||||
"rna_LayerEngineSettings_Eevee_ssr_stride_set", NULL);
|
||||
RNA_def_property_ui_text(prop, "Stride", "Step size between two raymarching samples");
|
||||
RNA_def_property_range(prop, 1, 32);
|
||||
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
|
||||
RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_SceneLayerEngineSettings_update");
|
||||
|
||||
prop = RNA_def_property(srna, "ssr_ray_count", PROP_INT, PROP_NONE);
|
||||
RNA_def_property_int_funcs(prop, "rna_LayerEngineSettings_Eevee_ssr_ray_count_get",
|
||||
"rna_LayerEngineSettings_Eevee_ssr_ray_count_set", NULL);
|
||||
RNA_def_property_ui_text(prop, "Samples", "Number of rays to trace per pixels");
|
||||
RNA_def_property_range(prop, 1, 4);
|
||||
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
|
||||
RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_SceneLayerEngineSettings_update");
|
||||
|
||||
prop = RNA_def_property(srna, "ssr_thickness", PROP_FLOAT, PROP_DISTANCE);
|
||||
RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Eevee_ssr_thickness_get",
|
||||
"rna_LayerEngineSettings_Eevee_ssr_thickness_set", NULL);
|
||||
RNA_def_property_ui_text(prop, "Thickness", "Pixel thickness used to detect intersection");
|
||||
RNA_def_property_range(prop, 1e-6f, FLT_MAX);
|
||||
RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 5, 3);
|
||||
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
|
||||
RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_SceneLayerEngineSettings_update");
|
||||
|
||||
prop = RNA_def_property(srna, "ssr_border_fade", PROP_FLOAT, PROP_FACTOR);
|
||||
RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Eevee_ssr_border_fade_get",
|
||||
"rna_LayerEngineSettings_Eevee_ssr_border_fade_set", NULL);
|
||||
RNA_def_property_ui_text(prop, "Edge Fading", "Screen percentage used to fade the SSR");
|
||||
RNA_def_property_range(prop, 0.0f, 0.5f);
|
||||
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
|
||||
RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_SceneLayerEngineSettings_update");
|
||||
|
||||
prop = RNA_def_property(srna, "ssr_firefly_fac", PROP_FLOAT, PROP_FACTOR);
|
||||
RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Eevee_ssr_firefly_fac_get",
|
||||
"rna_LayerEngineSettings_Eevee_ssr_firefly_fac_set", NULL);
|
||||
RNA_def_property_ui_text(prop, "Clamp", "Smoothly clamp pixel intensity to remove noise");
|
||||
RNA_def_property_range(prop, 0.0f, 1.0f);
|
||||
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
|
||||
RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_SceneLayerEngineSettings_update");
|
||||
|
||||
/* Volumetrics */
|
||||
prop = RNA_def_property(srna, "volumetric_enable", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_Eevee_volumetric_enable_get",
|
||||
|
@@ -475,6 +475,48 @@ static void ntree_shader_relink_displacement(bNodeTree *ntree,
|
||||
ntreeUpdateTree(G.main, ntree);
|
||||
}
|
||||
|
||||
static bool ntree_tag_ssr_bsdf_cb(bNode *fromnode, bNode *UNUSED(tonode), void *userdata, const bool UNUSED(reversed))
|
||||
{
|
||||
switch (fromnode->type) {
|
||||
case SH_NODE_BSDF_ANISOTROPIC:
|
||||
case SH_NODE_EEVEE_METALLIC:
|
||||
case SH_NODE_EEVEE_SPECULAR:
|
||||
case SH_NODE_BSDF_PRINCIPLED:
|
||||
case SH_NODE_BSDF_GLOSSY:
|
||||
fromnode->ssr_id = (*(float *)userdata);
|
||||
(*(float *)userdata) += 1;
|
||||
break;
|
||||
default:
|
||||
/* We could return false here but since we (will)
|
||||
* allow the use of Closure as RGBA, we can have
|
||||
* Bsdf nodes linked to other Bsdf nodes. */
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* EEVEE: Scan the ntree to set the Screen Space Reflection
|
||||
* layer id of every specular node.
|
||||
*/
|
||||
static void ntree_shader_tag_ssr_node(bNodeTree *ntree, short compatibility)
|
||||
{
|
||||
if (compatibility != NODE_NEWER_SHADING) {
|
||||
/* We can only deal with new shading system here. */
|
||||
return;
|
||||
}
|
||||
|
||||
bNode *output_node = ntree_shader_output_node(ntree);
|
||||
if (output_node == NULL) {
|
||||
return;
|
||||
}
|
||||
/* Make sure sockets links pointers are correct. */
|
||||
ntreeUpdateTree(G.main, ntree);
|
||||
|
||||
int lobe_count = 0;
|
||||
nodeChainIter(ntree, output_node, ntree_tag_ssr_bsdf_cb, &lobe_count, true);
|
||||
}
|
||||
|
||||
void ntreeGPUMaterialNodes(bNodeTree *ntree, GPUMaterial *mat, short compatibility)
|
||||
{
|
||||
/* localize tree to create links for reroute and mute */
|
||||
@@ -486,6 +528,8 @@ void ntreeGPUMaterialNodes(bNodeTree *ntree, GPUMaterial *mat, short compatibili
|
||||
*/
|
||||
ntree_shader_relink_displacement(localtree, compatibility);
|
||||
|
||||
ntree_shader_tag_ssr_node(localtree, compatibility);
|
||||
|
||||
exec = ntreeShaderBeginExecTree(localtree);
|
||||
ntreeExecGPUNodes(exec, mat, 1, compatibility);
|
||||
ntreeShaderEndExecTree(exec);
|
||||
|
@@ -51,7 +51,7 @@ static int node_shader_gpu_bsdf_glossy(GPUMaterial *mat, bNode *node, bNodeExecD
|
||||
if (!in[2].link)
|
||||
GPU_link(mat, "world_normals_get", &in[2].link);
|
||||
|
||||
return GPU_stack_link(mat, node, "node_bsdf_glossy", in, out);
|
||||
return GPU_stack_link(mat, node, "node_bsdf_glossy", in, out, GPU_uniform(&node->ssr_id));
|
||||
}
|
||||
|
||||
/* node type definition */
|
||||
|
@@ -100,10 +100,10 @@ static int node_shader_gpu_bsdf_principled(GPUMaterial *mat, bNode *node, bNodeE
|
||||
|
||||
/* Only use complex versions when needed. */
|
||||
if (!in[12].link && (in[12].vec[0] == 0.0f)) {
|
||||
return GPU_stack_link(mat, node, "node_bsdf_principled_simple", in, out, GPU_builtin(GPU_VIEW_POSITION));
|
||||
return GPU_stack_link(mat, node, "node_bsdf_principled_simple", in, out, GPU_builtin(GPU_VIEW_POSITION), GPU_uniform(&node->ssr_id));
|
||||
}
|
||||
else {
|
||||
return GPU_stack_link(mat, node, "node_bsdf_principled_clearcoat", in, out, GPU_builtin(GPU_VIEW_POSITION));
|
||||
return GPU_stack_link(mat, node, "node_bsdf_principled_clearcoat", in, out, GPU_builtin(GPU_VIEW_POSITION), GPU_uniform(&node->ssr_id));
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -68,7 +68,7 @@ static int node_shader_gpu_eevee_metallic(GPUMaterial *mat, bNode *node, bNodeEx
|
||||
GPU_link(mat, "set_value", GPU_uniform(&one), &in[10].link);
|
||||
}
|
||||
|
||||
return GPU_stack_link(mat, node, "node_eevee_metallic", in, out);
|
||||
return GPU_stack_link(mat, node, "node_eevee_metallic", in, out, GPU_uniform(&node->ssr_id));
|
||||
}
|
||||
|
||||
|
||||
|
@@ -67,7 +67,7 @@ static int node_shader_gpu_eevee_specular(GPUMaterial *mat, bNode *node, bNodeEx
|
||||
GPU_link(mat, "set_value", GPU_uniform(&one), &in[9].link);
|
||||
}
|
||||
|
||||
return GPU_stack_link(mat, node, "node_eevee_specular", in, out);
|
||||
return GPU_stack_link(mat, node, "node_eevee_specular", in, out, GPU_uniform(&node->ssr_id));
|
||||
}
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user