1
1

Compare commits

...

30 Commits

Author SHA1 Message Date
678c5e3752 Eevee: SSR: Refactor multiple rays. Plus other changes...
-Allow a maximum of 4 rays per trace pixel.
-Removes parameter Normalize: use normalization all the time now.
-Add firefly clamp slider.
2017-07-24 11:18:11 +02:00
e0eb879562 Eevee: Make MinmaxZ compatible with textureArray 2017-07-23 20:33:29 +02:00
601b4ddfc0 Eevee: Planar Reflection: Remove distance approximation.
This commit separate the depth texture into another texture array.
This remove the need to output radial depth into alpha.
Unfortunatly it's difficult to recover position from the non linear depth buffer when applying reflection without adding a bunch of stuff.
This is in preparation of SSR planar reflections.
2017-07-23 14:03:27 +02:00
455aeb1495 Eevee: SSR: Add two hit option.
This option add another raytrace per pixel, clearing some noise.
But multiplying the raytrace cost.
2017-07-23 00:03:45 +02:00
f359db1977 Eevee: SSR: Fix Opengl Render.
Add a constant number of 4 drawing loop to accumulate 4 "bounce" of light in SSRs.
2017-07-22 20:36:34 +02:00
647f9c2325 Eevee: SSR: Fixed problem with un-initialized texture.
Also add another debug buffer and cleanup in effect_ssr_frag.glsl
2017-07-22 16:22:01 +02:00
03c0525b4c Eevee: SSR: Small fixes
- Encode normals for other opaque bsdf so they are not rejected by the normal facing test.
- Early out non reflective surfaces.
- Add small offset to raytrace to avoid self intersection.
- Fix fallback probes not appearing.
2017-07-22 14:46:54 +02:00
d2131b8f16 Eevee: SSR: Add Weight Normalization option. 2017-07-22 14:41:34 +02:00
47044f7061 Eevee: SSR: Add View Facing fadeout.
Also make hit boolean depends on hit coord not on pdf.
2017-07-22 14:39:35 +02:00
ada51744b6 Eevee: SSR: Add fullscreen raytrace option and Screen border factor. 2017-07-22 01:13:33 +02:00
b3472b67ea Eevee: SSR: Use noise to dither the stride banding. 2017-07-22 00:22:39 +02:00
e785648f2e Eevee: SSR: Add stride and thickness parameters.
Also polished the raytracing algorithm.
2017-07-21 23:48:48 +02:00
c02f8eb749 Eevee: SSR: Add fullscreen raytrace. 2017-07-21 15:06:29 +02:00
3272640d6e Eevee: HiZ buffer: Split into two 24bit depth buffer
This way we don't have float precision issue we had before and we save some bandwidth.
2017-07-21 14:27:16 +02:00
33d76061b6 Eevee: SSR: Add firefly filter and refine noise reduction.
Push to 9 resolve sample.
Add an normalization as an option since it gives harsh limits.
2017-07-21 00:24:16 +02:00
79d4180c41 Eevee: Codestyle. 2017-07-21 00:20:05 +02:00
d8e2e4d490 Eevee: SSR: Do the SSR pass only for probes if there is no valid double buffer.
This prevent black reflection when initializing SSR.
2017-07-21 00:19:23 +02:00
e4c43b377d Eevee: SSR: Add mipmap filtering and bias to reduce noise.
Also fix the roughness factors.
2017-07-20 18:40:23 +02:00
3c9b318b7e Eevee: Fix glossy node roughness. 2017-07-20 16:54:57 +02:00
b8c8e27586 Eevee: SSR: Don't block the ray if tracing behind object.
This requires to check for backface after a hit.
2017-07-19 23:40:14 +02:00
9857ee6cf1 Eevee: SSR: Add per pixel resolve of multiple rays. 2017-07-19 19:21:16 +02:00
ab0d7492e6 Eevee: SSR: Add roughness random rays. 2017-07-19 15:39:37 +02:00
e1d4bb91d7 Eevee: SSR: Add double buffer so we can read previous frame color.
Also add simple reprojection and screen fade to the SSR resolve pass.
2017-07-19 14:22:03 +02:00
f3fdc1f4e2 Eevee: SSR: Make raymarch step bigger. 2017-07-19 14:19:03 +02:00
644522da01 Eevee: Fix Shader compilation. 2017-07-18 16:48:45 +02:00
f3e8cd97fa Eevee: SSR: Add simple raytracing.
Still imprecise.
2017-07-18 16:48:24 +02:00
93134fc578 Eevee: Fix clip/hashed alpha prepass/shadow crash. 2017-07-18 10:12:51 +02:00
76c323ff30 Eevee: SSR: Encode Normal in buffer and add cubemap fallback.
Normals can point away from the camera so we cannot just put XY in the buffer and reconstruct Z later as we would not know the sign of Z.
2017-07-18 10:12:51 +02:00
37653aaf58 Eevee: SSR: Output ssr datas to buffers.
Output in 2 buffers Normals, Specular Color and roughness.
This way we can raytrace in a defered fashion and blend the exact contribution of the specular lobe on top of the opaque pass.
2017-07-18 10:12:50 +02:00
471709176c Eevee: Ssr: Add ssr id to glossy nodes.
An id is given to each glossy node in order to determine which specular lobe is using ssr.
2017-07-18 10:12:50 +02:00
30 changed files with 1736 additions and 353 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View 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

View File

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

View File

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

View File

@@ -1,10 +1,6 @@
uniform int probeIdx;
layout(std140) uniform planar_block {
PlanarData planars_data[MAX_PLANAR];
};
in vec3 worldPosition;
out vec4 FragColor;

View File

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

View 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;
}

View File

@@ -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++) {

View File

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

View File

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

View File

@@ -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",

View File

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

View File

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

View File

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

View File

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

View File

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