Compare commits
17 Commits
temp-geome
...
eevee-prob
Author | SHA1 | Date | |
---|---|---|---|
074dc9b675 | |||
a9ac8d8871 | |||
9c2f459816 | |||
b1840d1bc5 | |||
8ba1acf826 | |||
b1d43d0f60 | |||
251ad8bf60 | |||
7ca2427ce2 | |||
744427b729 | |||
6eaeb6272e | |||
1d56589f14 | |||
f6cc14f86e | |||
1df2f7a713 | |||
bb05f6d335 | |||
36b066ee98 | |||
60b2e410a7 | |||
fe00859202 |
@@ -90,6 +90,7 @@ set(SRC
|
||||
engines/eevee/eevee_lights.c
|
||||
engines/eevee/eevee_lookdev.c
|
||||
engines/eevee/eevee_lut.c
|
||||
engines/eevee/eevee_lut_gen.c
|
||||
engines/eevee/eevee_materials.c
|
||||
engines/eevee/eevee_mist.c
|
||||
engines/eevee/eevee_motion_blur.c
|
||||
@@ -197,7 +198,6 @@ set(LIB
|
||||
|
||||
data_to_c_simple(engines/eevee/shaders/ambient_occlusion_lib.glsl SRC)
|
||||
data_to_c_simple(engines/eevee/shaders/background_vert.glsl SRC)
|
||||
data_to_c_simple(engines/eevee/shaders/closure_lib.glsl SRC)
|
||||
data_to_c_simple(engines/eevee/shaders/common_uniforms_lib.glsl SRC)
|
||||
data_to_c_simple(engines/eevee/shaders/common_utiltex_lib.glsl SRC)
|
||||
data_to_c_simple(engines/eevee/shaders/lights_lib.glsl SRC)
|
||||
@@ -215,7 +215,12 @@ data_to_c_simple(engines/eevee/shaders/lightprobe_grid_fill_frag.glsl SRC)
|
||||
data_to_c_simple(engines/eevee/shaders/lightprobe_planar_display_frag.glsl SRC)
|
||||
data_to_c_simple(engines/eevee/shaders/lightprobe_planar_display_vert.glsl SRC)
|
||||
data_to_c_simple(engines/eevee/shaders/lookdev_world_frag.glsl SRC)
|
||||
data_to_c_simple(engines/eevee/shaders/closure_lit_lib.glsl SRC)
|
||||
data_to_c_simple(engines/eevee/shaders/closure_eval_lib.glsl SRC)
|
||||
data_to_c_simple(engines/eevee/shaders/closure_eval_diffuse_lib.glsl SRC)
|
||||
data_to_c_simple(engines/eevee/shaders/closure_eval_glossy_lib.glsl SRC)
|
||||
data_to_c_simple(engines/eevee/shaders/closure_eval_refraction_lib.glsl SRC)
|
||||
data_to_c_simple(engines/eevee/shaders/closure_eval_translucent_lib.glsl SRC)
|
||||
data_to_c_simple(engines/eevee/shaders/closure_type_lib.glsl SRC)
|
||||
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_frag.glsl SRC)
|
||||
|
@@ -1040,8 +1040,10 @@ void EEVEE_lightbake_filter_glossy(EEVEE_ViewLayerData *sldata,
|
||||
pinfo->padding_size *= pinfo->texel_size;
|
||||
pinfo->layer = probe_idx * 6;
|
||||
pinfo->roughness = i / (float)maxlevel;
|
||||
pinfo->roughness *= pinfo->roughness; /* Disney Roughness */
|
||||
pinfo->roughness *= pinfo->roughness; /* Distribute Roughness accros lod more evenly */
|
||||
/* Disney Roughness */
|
||||
pinfo->roughness = square_f(pinfo->roughness);
|
||||
/* Distribute Roughness across lod more evenly */
|
||||
pinfo->roughness = square_f(square_f(pinfo->roughness));
|
||||
CLAMP(pinfo->roughness, 1e-8f, 0.99999f); /* Avoid artifacts */
|
||||
|
||||
#if 1 /* Variable Sample count and bias (fast) */
|
||||
|
@@ -33,139 +33,82 @@
|
||||
|
||||
#include "eevee_private.h"
|
||||
|
||||
static struct GPUTexture *create_ggx_lut_texture(int UNUSED(w), int UNUSED(h))
|
||||
float *EEVEE_lut_update_ggx_brdf(int lut_size)
|
||||
{
|
||||
struct GPUTexture *tex;
|
||||
struct GPUFrameBuffer *fb = NULL;
|
||||
static float samples_len = 8192.0f;
|
||||
static float inv_samples_len = 1.0f / 8192.0f;
|
||||
|
||||
DRWPass *pass = DRW_pass_create("LightProbe Filtering", DRW_STATE_WRITE_COLOR);
|
||||
DRWPass *pass = DRW_pass_create(__func__, DRW_STATE_WRITE_COLOR);
|
||||
DRWShadingGroup *grp = DRW_shgroup_create(EEVEE_shaders_ggx_lut_sh_get(), pass);
|
||||
DRW_shgroup_uniform_float(grp, "sampleCount", &samples_len, 1);
|
||||
DRW_shgroup_uniform_float(grp, "invSampleCount", &inv_samples_len, 1);
|
||||
DRW_shgroup_uniform_texture(grp, "texHammersley", e_data.hammersley);
|
||||
DRW_shgroup_uniform_texture(grp, "texJitter", e_data.jitter);
|
||||
|
||||
struct GPUBatch *geom = DRW_cache_fullscreen_quad_get();
|
||||
DRW_shgroup_call(grp, geom, NULL);
|
||||
|
||||
float *texels = MEM_mallocN(sizeof(float[2]) * w * h, "lut");
|
||||
|
||||
tex = DRW_texture_create_2d(w, h, GPU_RG16F, DRW_TEX_FILTER, (float *)texels);
|
||||
|
||||
DRWFboTexture tex_filter = {&tex, GPU_RG16F, DRW_TEX_FILTER};
|
||||
GPU_framebuffer_init(&fb, &draw_engine_eevee_type, w, h, &tex_filter, 1);
|
||||
DRW_shgroup_uniform_float_copy(grp, "sampleCount", 64.0f); /* Actual sample count is squared. */
|
||||
DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
|
||||
|
||||
GPUTexture *tex = DRW_texture_create_2d(lut_size, lut_size, GPU_RG16F, 0, NULL);
|
||||
GPUFrameBuffer *fb = NULL;
|
||||
GPU_framebuffer_ensure_config(&fb,
|
||||
{
|
||||
GPU_ATTACHMENT_NONE,
|
||||
GPU_ATTACHMENT_TEXTURE(tex),
|
||||
});
|
||||
GPU_framebuffer_bind(fb);
|
||||
DRW_draw_pass(pass);
|
||||
GPU_FRAMEBUFFER_FREE_SAFE(fb);
|
||||
|
||||
float *data = MEM_mallocN(sizeof(float[3]) * w * h, "lut");
|
||||
GPU_framebuffer_read_color(fb, 0, 0, w, h, 3, 0, GPU_DATA_FLOAT, data);
|
||||
|
||||
printf("{");
|
||||
for (int i = 0; i < w * h * 3; i += 3) {
|
||||
printf("%ff, %ff, ", data[i], data[i + 1]);
|
||||
i += 3;
|
||||
printf("%ff, %ff, ", data[i], data[i + 1]);
|
||||
i += 3;
|
||||
printf("%ff, %ff, ", data[i], data[i + 1]);
|
||||
i += 3;
|
||||
printf("%ff, %ff, \n", data[i], data[i + 1]);
|
||||
float *data = GPU_texture_read(tex, GPU_DATA_FLOAT, 0);
|
||||
GPU_texture_free(tex);
|
||||
#if 0
|
||||
FILE *f = BLI_fopen("brdf_split_sum_ggx.h", "w");
|
||||
fprintf(f, "static float brdf_split_sum_ggx[%d * %d * 2] = {\n", lut_size, lut_size);
|
||||
fprintf(f, "{");
|
||||
for (int i = 0; i < lut_size * lut_size * 2;) {
|
||||
for (int j = 0; j < 4; j++, i += 2) {
|
||||
fprintf(f, "%ff, %ff, ", data[i], data[i + 1]);
|
||||
}
|
||||
fprintf(f, "\n ");
|
||||
}
|
||||
printf("}");
|
||||
|
||||
MEM_freeN(texels);
|
||||
MEM_freeN(data);
|
||||
|
||||
return tex;
|
||||
}
|
||||
|
||||
static struct GPUTexture *create_ggx_refraction_lut_texture(int w, int h)
|
||||
{
|
||||
struct GPUTexture *tex;
|
||||
struct GPUTexture *hammersley = create_hammersley_sample_texture(8192);
|
||||
struct GPUFrameBuffer *fb = NULL;
|
||||
static float samples_len = 8192.0f;
|
||||
static float a2 = 0.0f;
|
||||
static float inv_samples_len = 1.0f / 8192.0f;
|
||||
|
||||
DRWPass *pass = DRW_pass_create("LightProbe Filtering", DRW_STATE_WRITE_COLOR);
|
||||
DRWShadingGroup *grp = DRW_shgroup_create(EEVEE_shaders_ggx_refraction_lut_sh_get(), pass);
|
||||
DRW_shgroup_uniform_float(grp, "a2", &a2, 1);
|
||||
DRW_shgroup_uniform_float(grp, "sampleCount", &samples_len, 1);
|
||||
DRW_shgroup_uniform_float(grp, "invSampleCount", &inv_samples_len, 1);
|
||||
DRW_shgroup_uniform_texture(grp, "texHammersley", hammersley);
|
||||
DRW_shgroup_uniform_texture(grp, "utilTex", e_data.util_tex);
|
||||
|
||||
struct GPUBatch *geom = DRW_cache_fullscreen_quad_get();
|
||||
DRW_shgroup_call(grp, geom, NULL);
|
||||
|
||||
float *texels = MEM_mallocN(sizeof(float[2]) * w * h, "lut");
|
||||
|
||||
tex = DRW_texture_create_2d(w, h, GPU_R16F, DRW_TEX_FILTER, (float *)texels);
|
||||
|
||||
DRWFboTexture tex_filter = {&tex, GPU_R16F, DRW_TEX_FILTER};
|
||||
GPU_framebuffer_init(&fb, &draw_engine_eevee_type, w, h, &tex_filter, 1);
|
||||
|
||||
GPU_framebuffer_bind(fb);
|
||||
|
||||
float *data = MEM_mallocN(sizeof(float[3]) * w * h, "lut");
|
||||
|
||||
float inc = 1.0f / 31.0f;
|
||||
float roughness = 1e-8f - inc;
|
||||
FILE *f = BLI_fopen("btdf_split_sum_ggx.h", "w");
|
||||
fprintf(f, "static float btdf_split_sum_ggx[32][64 * 64] = {\n");
|
||||
do {
|
||||
roughness += inc;
|
||||
CLAMP(roughness, 1e-4f, 1.0f);
|
||||
a2 = powf(roughness, 4.0f);
|
||||
DRW_draw_pass(pass);
|
||||
|
||||
GPU_framebuffer_read_data(0, 0, w, h, 3, 0, data);
|
||||
|
||||
#if 1
|
||||
fprintf(f, "\t{\n\t\t");
|
||||
for (int i = 0; i < w * h * 3; i += 3) {
|
||||
fprintf(f, "%ff,", data[i]);
|
||||
if (((i / 3) + 1) % 12 == 0) {
|
||||
fprintf(f, "\n\t\t");
|
||||
}
|
||||
else {
|
||||
fprintf(f, " ");
|
||||
}
|
||||
}
|
||||
fprintf(f, "\n\t},\n");
|
||||
#else
|
||||
for (int i = 0; i < w * h * 3; i += 3) {
|
||||
if (data[i] < 0.01) {
|
||||
printf(" ");
|
||||
}
|
||||
else if (data[i] < 0.3) {
|
||||
printf(".");
|
||||
}
|
||||
else if (data[i] < 0.6) {
|
||||
printf("+");
|
||||
}
|
||||
else if (data[i] < 0.9) {
|
||||
printf("%%");
|
||||
}
|
||||
else {
|
||||
printf("#");
|
||||
}
|
||||
if ((i / 3 + 1) % 64 == 0) {
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
fprintf(f, "}");
|
||||
fclose(f);
|
||||
#endif
|
||||
|
||||
} while (roughness < 1.0f);
|
||||
fprintf(f, "\n};\n");
|
||||
|
||||
fclose(f);
|
||||
|
||||
MEM_freeN(texels);
|
||||
MEM_freeN(data);
|
||||
|
||||
return tex;
|
||||
return data;
|
||||
}
|
||||
|
||||
float *EEVEE_lut_update_ggx_btdf(int lut_size, int lut_depth)
|
||||
{
|
||||
float roughness;
|
||||
DRWPass *pass = DRW_pass_create(__func__, DRW_STATE_WRITE_COLOR);
|
||||
DRWShadingGroup *grp = DRW_shgroup_create(EEVEE_shaders_ggx_refraction_lut_sh_get(), pass);
|
||||
DRW_shgroup_uniform_float_copy(grp, "sampleCount", 64.0f); /* Actual sample count is squared. */
|
||||
DRW_shgroup_uniform_float(grp, "z", &roughness, 1);
|
||||
DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
|
||||
|
||||
GPUTexture *tex = DRW_texture_create_2d_array(lut_size, lut_size, lut_depth, GPU_RG16F, 0, NULL);
|
||||
GPUFrameBuffer *fb = NULL;
|
||||
for (int i = 0; i < lut_depth; i++) {
|
||||
GPU_framebuffer_ensure_config(&fb,
|
||||
{
|
||||
GPU_ATTACHMENT_NONE,
|
||||
GPU_ATTACHMENT_TEXTURE_LAYER(tex, i),
|
||||
});
|
||||
GPU_framebuffer_bind(fb);
|
||||
roughness = i / (lut_depth - 1.0f);
|
||||
DRW_draw_pass(pass);
|
||||
}
|
||||
|
||||
GPU_FRAMEBUFFER_FREE_SAFE(fb);
|
||||
|
||||
float *data = GPU_texture_read(tex, GPU_DATA_FLOAT, 0);
|
||||
GPU_texture_free(tex);
|
||||
#if 0
|
||||
FILE *f = BLI_fopen("brdf_split_sum_ggx.h", "w");
|
||||
fprintf(f, "static float brdf_split_sum_ggx[%d * %d * 2] = {\n", lut_size, lut_size);
|
||||
fprintf(f, "{");
|
||||
for (int i = 0; i < lut_size * lut_size * 2;) {
|
||||
for (int j = 0; j < 4; j++, i += 2) {
|
||||
fprintf(f, "%ff, %ff, ", data[i], data[i + 1]);
|
||||
}
|
||||
fprintf(f, "\n ");
|
||||
}
|
||||
fprintf(f, "}");
|
||||
fclose(f);
|
||||
#endif
|
||||
|
||||
return data;
|
||||
}
|
||||
|
@@ -142,11 +142,20 @@ static void eevee_init_noise_texture(void)
|
||||
e_data.noise_tex = DRW_texture_create_2d(64, 64, GPU_RGBA16F, 0, (float *)blue_noise);
|
||||
}
|
||||
|
||||
#define RUNTIME_LUT_CREATION 1
|
||||
|
||||
static void eevee_init_util_texture(void)
|
||||
{
|
||||
const int layers = 4 + 16;
|
||||
float(*texels)[4] = MEM_mallocN(sizeof(float[4]) * 64 * 64 * layers, "utils texels");
|
||||
float(*texels_layer)[4] = texels;
|
||||
#if RUNTIME_LUT_CREATION
|
||||
float *bsdf_ggx_lut = EEVEE_lut_update_ggx_brdf(64);
|
||||
float(*btdf_ggx_lut)[64 * 64 * 2] = (float(*)[64 * 64 * 2]) EEVEE_lut_update_ggx_btdf(64, 16);
|
||||
#else
|
||||
const float *bsdf_ggx_lut = bsdf_split_sum_ggx;
|
||||
const float(*btdf_ggx_lut)[64 * 64 * 2] = btdf_split_sum_ggx;
|
||||
#endif
|
||||
|
||||
/* Copy ltc_mat_ggx into 1st layer */
|
||||
memcpy(texels_layer, ltc_mat_ggx, sizeof(float[4]) * 64 * 64);
|
||||
@@ -155,8 +164,8 @@ static void eevee_init_util_texture(void)
|
||||
/* Copy bsdf_split_sum_ggx into 2nd layer red and green channels.
|
||||
* Copy ltc_mag_ggx into 2nd layer blue and alpha channel. */
|
||||
for (int i = 0; i < 64 * 64; i++) {
|
||||
texels_layer[i][0] = bsdf_split_sum_ggx[i * 2 + 0];
|
||||
texels_layer[i][1] = bsdf_split_sum_ggx[i * 2 + 1];
|
||||
texels_layer[i][0] = bsdf_ggx_lut[i * 2 + 0];
|
||||
texels_layer[i][1] = bsdf_ggx_lut[i * 2 + 1];
|
||||
texels_layer[i][2] = ltc_mag_ggx[i * 2 + 0];
|
||||
texels_layer[i][3] = ltc_mag_ggx[i * 2 + 1];
|
||||
}
|
||||
@@ -183,8 +192,8 @@ static void eevee_init_util_texture(void)
|
||||
/* Copy Refraction GGX LUT in layer 5 - 21 */
|
||||
for (int j = 0; j < 16; j++) {
|
||||
for (int i = 0; i < 64 * 64; i++) {
|
||||
texels_layer[i][0] = btdf_split_sum_ggx[j * 2][i];
|
||||
texels_layer[i][1] = 0.0; /* UNUSED */
|
||||
texels_layer[i][0] = btdf_ggx_lut[j][i * 2 + 0];
|
||||
texels_layer[i][1] = btdf_ggx_lut[j][i * 2 + 1];
|
||||
texels_layer[i][2] = 0.0; /* UNUSED */
|
||||
texels_layer[i][3] = 0.0; /* UNUSED */
|
||||
}
|
||||
@@ -195,6 +204,10 @@ static void eevee_init_util_texture(void)
|
||||
64, 64, layers, GPU_RGBA16F, DRW_TEX_FILTER | DRW_TEX_WRAP, (float *)texels);
|
||||
|
||||
MEM_freeN(texels);
|
||||
#if RUNTIME_LUT_CREATION
|
||||
MEM_freeN(bsdf_ggx_lut);
|
||||
MEM_freeN(btdf_ggx_lut);
|
||||
#endif
|
||||
}
|
||||
|
||||
void EEVEE_update_noise(EEVEE_PassList *psl, EEVEE_FramebufferList *fbl, const double offsets[3])
|
||||
|
@@ -1422,6 +1422,10 @@ void EEVEE_lookdev_draw(EEVEE_Data *vedata);
|
||||
/** eevee_engine.c */
|
||||
void EEVEE_cache_populate(void *vedata, Object *ob);
|
||||
|
||||
/** eevee_lut_gen.c */
|
||||
float *EEVEE_lut_update_ggx_brdf(int lut_size);
|
||||
float *EEVEE_lut_update_ggx_btdf(int lut_size, int lut_depth);
|
||||
|
||||
/* Shadow Matrix */
|
||||
static const float texcomat[4][4] = {
|
||||
/* From NDC to TexCo */
|
||||
|
@@ -191,6 +191,12 @@ void EEVEE_screen_raytrace_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *v
|
||||
DRW_shgroup_uniform_texture_ref(grp, "hitBuffer", &effects->ssr_hit_output);
|
||||
DRW_shgroup_uniform_texture_ref(grp, "pdfBuffer", &effects->ssr_pdf_output);
|
||||
DRW_shgroup_uniform_texture_ref(grp, "prevColorBuffer", &txl->color_double_buffer);
|
||||
DRW_shgroup_uniform_texture_ref(grp, "maxzBuffer", &txl->maxzbuffer);
|
||||
DRW_shgroup_uniform_texture_ref(grp, "shadowCubeTexture", &sldata->shadow_cube_pool);
|
||||
DRW_shgroup_uniform_texture_ref(grp, "shadowCascadeTexture", &sldata->shadow_cascade_pool);
|
||||
DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex());
|
||||
DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo);
|
||||
DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo);
|
||||
DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo);
|
||||
DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo);
|
||||
DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo);
|
||||
@@ -198,7 +204,6 @@ void EEVEE_screen_raytrace_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *v
|
||||
DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined);
|
||||
DRW_shgroup_uniform_int(grp, "neighborOffset", &effects->ssr_neighbor_ofs, 1);
|
||||
if ((effects->enabled_effects & EFFECT_GTAO) != 0) {
|
||||
DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex());
|
||||
DRW_shgroup_uniform_texture_ref(grp, "horizonBuffer", &effects->gtao_horizons);
|
||||
}
|
||||
|
||||
|
@@ -142,7 +142,6 @@ static struct {
|
||||
struct GPUShader *volumetric_accum_sh;
|
||||
|
||||
/* Shader strings */
|
||||
char *closure_lit_lib;
|
||||
char *surface_lit_frag;
|
||||
char *surface_prepass_frag;
|
||||
char *surface_geom_barycentric;
|
||||
@@ -184,7 +183,7 @@ extern char datatoc_bsdf_common_lib_glsl[];
|
||||
extern char datatoc_bsdf_lut_frag_glsl[];
|
||||
extern char datatoc_bsdf_sampling_lib_glsl[];
|
||||
extern char datatoc_btdf_lut_frag_glsl[];
|
||||
extern char datatoc_closure_lib_glsl[];
|
||||
extern char datatoc_closure_type_lib_glsl[];
|
||||
extern char datatoc_common_uniforms_lib_glsl[];
|
||||
extern char datatoc_common_utiltex_lib_glsl[];
|
||||
extern char datatoc_cryptomatte_frag_glsl[];
|
||||
@@ -224,7 +223,11 @@ extern char datatoc_lightprobe_planar_downsample_geom_glsl[];
|
||||
extern char datatoc_lightprobe_planar_downsample_vert_glsl[];
|
||||
extern char datatoc_lightprobe_vert_glsl[];
|
||||
extern char datatoc_lights_lib_glsl[];
|
||||
extern char datatoc_closure_lit_lib_glsl[];
|
||||
extern char datatoc_closure_eval_lib_glsl[];
|
||||
extern char datatoc_closure_eval_diffuse_lib_glsl[];
|
||||
extern char datatoc_closure_eval_glossy_lib_glsl[];
|
||||
extern char datatoc_closure_eval_refraction_lib_glsl[];
|
||||
extern char datatoc_closure_eval_translucent_lib_glsl[];
|
||||
extern char datatoc_ltc_lib_glsl[];
|
||||
extern char datatoc_object_motion_frag_glsl[];
|
||||
extern char datatoc_object_motion_vert_glsl[];
|
||||
@@ -279,23 +282,13 @@ static void eevee_shader_library_ensure(void)
|
||||
DRW_SHADER_LIB_ADD(e_data.lib, lights_lib);
|
||||
DRW_SHADER_LIB_ADD(e_data.lib, surface_lib);
|
||||
DRW_SHADER_LIB_ADD(e_data.lib, volumetric_lib);
|
||||
DRW_SHADER_LIB_ADD(e_data.lib, closure_lib);
|
||||
DRW_SHADER_LIB_ADD(e_data.lib, ssr_lib);
|
||||
|
||||
/* Add one for each Closure */
|
||||
e_data.closure_lit_lib = BLI_string_joinN(datatoc_closure_lit_lib_glsl,
|
||||
datatoc_closure_lit_lib_glsl,
|
||||
datatoc_closure_lit_lib_glsl,
|
||||
datatoc_closure_lit_lib_glsl,
|
||||
datatoc_closure_lit_lib_glsl,
|
||||
datatoc_closure_lit_lib_glsl,
|
||||
datatoc_closure_lit_lib_glsl,
|
||||
datatoc_closure_lit_lib_glsl,
|
||||
datatoc_closure_lit_lib_glsl,
|
||||
datatoc_closure_lit_lib_glsl,
|
||||
datatoc_closure_lit_lib_glsl);
|
||||
|
||||
DRW_shader_library_add_file(e_data.lib, e_data.closure_lit_lib, "closure_lit_lib.glsl");
|
||||
DRW_SHADER_LIB_ADD(e_data.lib, closure_type_lib);
|
||||
DRW_SHADER_LIB_ADD(e_data.lib, closure_eval_lib);
|
||||
DRW_SHADER_LIB_ADD(e_data.lib, closure_eval_diffuse_lib);
|
||||
DRW_SHADER_LIB_ADD(e_data.lib, closure_eval_glossy_lib);
|
||||
DRW_SHADER_LIB_ADD(e_data.lib, closure_eval_translucent_lib);
|
||||
DRW_SHADER_LIB_ADD(e_data.lib, closure_eval_refraction_lib);
|
||||
|
||||
e_data.surface_lit_frag = DRW_shader_library_create_shader_string(e_data.lib,
|
||||
datatoc_surface_frag_glsl);
|
||||
@@ -556,11 +549,8 @@ GPUShader *EEVEE_shaders_effect_maxz_copydepth_sh_get(void)
|
||||
GPUShader *EEVEE_shaders_ggx_lut_sh_get(void)
|
||||
{
|
||||
if (e_data.ggx_lut_sh == NULL) {
|
||||
e_data.ggx_lut_sh = DRW_shader_create_with_shaderlib(datatoc_lightprobe_vert_glsl,
|
||||
datatoc_lightprobe_geom_glsl,
|
||||
datatoc_bsdf_lut_frag_glsl,
|
||||
e_data.lib,
|
||||
"#define HAMMERSLEY_SIZE 8192\n");
|
||||
e_data.ggx_lut_sh = DRW_shader_create_fullscreen_with_shaderlib(
|
||||
datatoc_bsdf_lut_frag_glsl, e_data.lib, NULL);
|
||||
}
|
||||
return e_data.ggx_lut_sh;
|
||||
}
|
||||
@@ -1403,7 +1393,6 @@ struct GPUMaterial *EEVEE_material_get(
|
||||
|
||||
void EEVEE_shaders_free(void)
|
||||
{
|
||||
MEM_SAFE_FREE(e_data.closure_lit_lib);
|
||||
MEM_SAFE_FREE(e_data.surface_prepass_frag);
|
||||
MEM_SAFE_FREE(e_data.surface_lit_frag);
|
||||
MEM_SAFE_FREE(e_data.surface_geom_barycentric);
|
||||
|
@@ -191,15 +191,15 @@ void gtao_deferred(
|
||||
dirs.xy = get_ao_dir(noise.x * 0.5);
|
||||
dirs.zw = get_ao_dir(noise.x * 0.5 + 0.5);
|
||||
|
||||
bent_normal = normal * 1e-8;
|
||||
visibility = 1e-8;
|
||||
bent_normal = vec3(0.0);
|
||||
visibility = 0.0;
|
||||
|
||||
horizons = unpack_horizons(horizons);
|
||||
|
||||
integrate_slice(normal, dirs.xy, horizons.xy, visibility, bent_normal);
|
||||
integrate_slice(normal, dirs.zw, horizons.zw, visibility, bent_normal);
|
||||
|
||||
bent_normal = normalize(bent_normal / visibility);
|
||||
bent_normal = safe_normalize(bent_normal);
|
||||
|
||||
visibility *= 0.5; /* We integrated 2 slices. */
|
||||
}
|
||||
@@ -240,13 +240,24 @@ float gtao_multibounce(float visibility, vec3 albedo)
|
||||
return max(x, ((x * a + b) * x + c) * x);
|
||||
}
|
||||
|
||||
float diffuse_occlusion(vec3 N, vec3 vis_cone_dir, float vis_cone_aperture_cos, vec3 albedo)
|
||||
{
|
||||
if ((int(aoSettings) & USE_AO) == 0) {
|
||||
return 1.0;
|
||||
}
|
||||
/* If the shading normal is orthogonal to the geometric normal, it should be half lit. */
|
||||
float horizon_fac = saturate(dot(N, vis_cone_dir) * 0.5 + 0.5);
|
||||
float ao = vis_cone_aperture_cos * horizon_fac;
|
||||
return gtao_multibounce(ao, albedo);
|
||||
}
|
||||
|
||||
float specular_occlusion(float NV, float AO, float roughness)
|
||||
{
|
||||
return saturate(pow(NV + AO, roughness) - 1.0 + AO);
|
||||
}
|
||||
|
||||
/* Use the right occlusion */
|
||||
float occlusion_compute(vec3 N, vec3 vpos, float user_occlusion, vec4 rand, out vec3 bent_normal)
|
||||
float occlusion_compute(vec3 N, vec3 vpos, vec4 rand, out vec3 bent_normal)
|
||||
{
|
||||
#ifndef USE_REFRACTION
|
||||
if ((int(aoSettings) & USE_AO) != 0) {
|
||||
@@ -263,10 +274,6 @@ float occlusion_compute(vec3 N, vec3 vpos, float user_occlusion, vec4 rand, out
|
||||
visibility = max(1e-3, visibility);
|
||||
|
||||
if ((int(aoSettings) & USE_BENT_NORMAL) != 0) {
|
||||
/* The bent normal will show the facet look of the mesh. Try to minimize this. */
|
||||
float mix_fac = visibility * visibility * visibility;
|
||||
bent_normal = normalize(mix(bent_normal, vnor, mix_fac));
|
||||
|
||||
bent_normal = transform_direction(ViewMatrixInverse, bent_normal);
|
||||
}
|
||||
else {
|
||||
@@ -276,10 +283,10 @@ float occlusion_compute(vec3 N, vec3 vpos, float user_occlusion, vec4 rand, out
|
||||
/* Scale by user factor */
|
||||
visibility = pow(visibility, aoFactor);
|
||||
|
||||
return min(visibility, user_occlusion);
|
||||
return visibility;
|
||||
}
|
||||
#endif
|
||||
|
||||
bent_normal = N;
|
||||
return user_occlusion;
|
||||
return 1.0;
|
||||
}
|
||||
|
@@ -1,6 +1,15 @@
|
||||
|
||||
#pragma BLENDER_REQUIRE(common_math_lib.glsl)
|
||||
|
||||
vec3 diffuse_dominant_dir(vec3 N, vec3 vis_cone_dir, float vis_cone_aperture_cos)
|
||||
{
|
||||
/* TODO(fclem) revisit this. bent too much towards vis_cone_dir. */
|
||||
vis_cone_aperture_cos *= sqr(vis_cone_aperture_cos);
|
||||
|
||||
N = mix(vis_cone_dir, N, vis_cone_aperture_cos);
|
||||
return normalize(N);
|
||||
}
|
||||
|
||||
vec3 specular_dominant_dir(vec3 N, vec3 V, float roughness)
|
||||
{
|
||||
vec3 R = -reflect(V, N);
|
||||
@@ -15,6 +24,7 @@ float ior_from_f0(float f0)
|
||||
return (-f - 1.0) / (f - 1.0);
|
||||
}
|
||||
|
||||
/* Simplified form of F_eta(eta, 1.0). */
|
||||
float f0_from_ior(float eta)
|
||||
{
|
||||
float A = (eta - 1.0) / (eta + 1.0);
|
||||
@@ -47,30 +57,21 @@ float F_eta(float eta, float cos_theta)
|
||||
* the refracted direction */
|
||||
float c = abs(cos_theta);
|
||||
float g = eta * eta - 1.0 + c * c;
|
||||
float result;
|
||||
|
||||
if (g > 0.0) {
|
||||
g = sqrt(g);
|
||||
vec2 g_c = vec2(g) + vec2(c, -c);
|
||||
float A = g_c.y / g_c.x;
|
||||
A *= A;
|
||||
g_c *= c;
|
||||
float B = (g_c.y - 1.0) / (g_c.x + 1.0);
|
||||
B *= B;
|
||||
result = 0.5 * A * (1.0 + B);
|
||||
float A = (g - c) / (g + c);
|
||||
float B = (c * (g + c) - 1.0) / (c * (g - c) + 1.0);
|
||||
return 0.5 * A * A * (1.0 + B * B);
|
||||
}
|
||||
else {
|
||||
result = 1.0; /* TIR (no refracted component) */
|
||||
}
|
||||
|
||||
return result;
|
||||
/* Total internal reflections. */
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
/* Fresnel color blend base on fresnel factor */
|
||||
vec3 F_color_blend(float eta, float fresnel, vec3 f0_color)
|
||||
{
|
||||
float f0 = F_eta(eta, 1.0);
|
||||
float fac = saturate((fresnel - f0) / max(1e-8, 1.0 - f0));
|
||||
float f0 = f0_from_ior(eta);
|
||||
float fac = saturate((fresnel - f0) / (1.0 - f0));
|
||||
return mix(f0_color, vec3(1.0), fac);
|
||||
}
|
||||
|
||||
@@ -79,7 +80,7 @@ vec3 F_brdf_single_scatter(vec3 f0, vec3 f90, vec2 lut)
|
||||
{
|
||||
/* Unreal specular matching : if specular color is below 2% intensity,
|
||||
* treat as shadowning */
|
||||
return saturate(50.0 * dot(f0, vec3(0.3, 0.6, 0.1))) * lut.y * abs(f90) + lut.x * f0;
|
||||
return lut.y * f90 + lut.x * f0;
|
||||
}
|
||||
|
||||
/* Multi-scattering brdf approximation from :
|
||||
@@ -87,11 +88,7 @@ vec3 F_brdf_single_scatter(vec3 f0, vec3 f90, vec2 lut)
|
||||
* by Carmelo J. Fdez-Agüera. */
|
||||
vec3 F_brdf_multi_scatter(vec3 f0, vec3 f90, vec2 lut)
|
||||
{
|
||||
vec3 FssEss = F_brdf_single_scatter(f0, f90, lut);
|
||||
/* Hack to avoid many more shader variations. */
|
||||
if (f90.g < 0.0) {
|
||||
return FssEss;
|
||||
}
|
||||
vec3 FssEss = lut.y * f90 + lut.x * f0;
|
||||
|
||||
float Ess = lut.x + lut.y;
|
||||
float Ems = 1.0 - Ess;
|
||||
@@ -102,8 +99,6 @@ vec3 F_brdf_multi_scatter(vec3 f0, vec3 f90, vec2 lut)
|
||||
return FssEss + Fms * Ems;
|
||||
}
|
||||
|
||||
#define F_brdf(f0, f90, lut) F_brdf_multi_scatter(f0, f90, lut)
|
||||
|
||||
/* GGX */
|
||||
float D_ggx_opti(float NH, float a2)
|
||||
{
|
||||
|
@@ -1,48 +1,57 @@
|
||||
#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(bsdf_sampling_lib.glsl)
|
||||
|
||||
out vec4 FragColor;
|
||||
uniform float sampleCount;
|
||||
|
||||
out vec2 FragColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec3 N, T, B, V;
|
||||
/* Make sure coordinates are covering the whole [0..1] range at texel center. */
|
||||
float y = floor(gl_FragCoord.y) / (LUT_SIZE - 1);
|
||||
float x = floor(gl_FragCoord.x) / (LUT_SIZE - 1);
|
||||
|
||||
float NV = (1.0 - (clamp(gl_FragCoord.y / LUT_SIZE, 1e-4, 0.9999)));
|
||||
float sqrtRoughness = clamp(gl_FragCoord.x / LUT_SIZE, 1e-4, 0.9999);
|
||||
float a = sqrtRoughness * sqrtRoughness;
|
||||
float a2 = a * a;
|
||||
float NV = clamp(1.0 - y * y, 1e-4, 0.9999);
|
||||
float a = x * x;
|
||||
float a2 = clamp(a * a, 1e-4, 0.9999);
|
||||
|
||||
N = vec3(0.0, 0.0, 1.0);
|
||||
T = vec3(1.0, 0.0, 0.0);
|
||||
B = vec3(0.0, 1.0, 0.0);
|
||||
V = vec3(sqrt(1.0 - NV * NV), 0.0, NV);
|
||||
|
||||
setup_noise();
|
||||
vec3 V = vec3(sqrt(1.0 - NV * NV), 0.0, NV);
|
||||
|
||||
/* Integrating BRDF */
|
||||
float brdf_accum = 0.0;
|
||||
float fresnel_accum = 0.0;
|
||||
for (float i = 0; i < sampleCount; i++) {
|
||||
vec3 H = sample_ggx(i, a2, N, T, B); /* Microfacet normal */
|
||||
vec3 L = -reflect(V, H);
|
||||
float NL = L.z;
|
||||
for (float j = 0.0; j < sampleCount; j++) {
|
||||
for (float i = 0.0; i < sampleCount; i++) {
|
||||
vec3 Xi = (vec3(i, j, 0.0) + 0.5) / sampleCount;
|
||||
Xi.yz = vec2(cos(Xi.y * M_2PI), sin(Xi.y * M_2PI));
|
||||
|
||||
if (NL > 0.0) {
|
||||
float NH = max(H.z, 0.0);
|
||||
float VH = max(dot(V, H), 0.0);
|
||||
vec3 H = sample_ggx(Xi, a2); /* Microfacet normal */
|
||||
vec3 L = -reflect(V, H);
|
||||
float NL = L.z;
|
||||
|
||||
float G1_v = G1_Smith_GGX(NV, a2);
|
||||
float G1_l = G1_Smith_GGX(NL, a2);
|
||||
float G_smith = 4.0 * NV * NL / (G1_v * G1_l); /* See G1_Smith_GGX for explanations. */
|
||||
if (NL > 0.0) {
|
||||
float NH = max(H.z, 0.0);
|
||||
float VH = max(dot(V, H), 0.0);
|
||||
|
||||
float brdf = (G_smith * VH) / (NH * NV);
|
||||
float Fc = pow(1.0 - VH, 5.0);
|
||||
float G1_v = G1_Smith_GGX(NV, a2);
|
||||
float G1_l = G1_Smith_GGX(NL, a2);
|
||||
float G_smith = 4.0 * NV * NL / (G1_v * G1_l); /* See G1_Smith_GGX for explanations. */
|
||||
|
||||
brdf_accum += (1.0 - Fc) * brdf;
|
||||
fresnel_accum += Fc * brdf;
|
||||
float brdf = (G_smith * VH) / (NH * NV);
|
||||
|
||||
/* Follow maximum specular value for principled bsdf. */
|
||||
const float specular = 1.0;
|
||||
const float eta = (2.0 / (1.0 - sqrt(0.08 * specular))) - 1.0;
|
||||
float fresnel = F_eta(eta, VH);
|
||||
float Fc = F_color_blend(eta, fresnel, vec3(0)).r;
|
||||
|
||||
brdf_accum += (1.0 - Fc) * brdf;
|
||||
fresnel_accum += Fc * brdf;
|
||||
}
|
||||
}
|
||||
}
|
||||
brdf_accum /= sampleCount;
|
||||
fresnel_accum /= sampleCount;
|
||||
brdf_accum /= sampleCount * sampleCount;
|
||||
fresnel_accum /= sampleCount * sampleCount;
|
||||
|
||||
FragColor = vec4(brdf_accum, fresnel_accum, 0.0, 1.0);
|
||||
FragColor = vec2(brdf_accum, fresnel_accum);
|
||||
}
|
||||
|
@@ -1,21 +1,7 @@
|
||||
|
||||
#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(bsdf_common_lib.glsl)
|
||||
|
||||
uniform sampler1D texHammersley;
|
||||
uniform float sampleCount;
|
||||
uniform float invSampleCount;
|
||||
|
||||
vec2 jitternoise = vec2(0.0);
|
||||
|
||||
#ifndef UTIL_TEX
|
||||
# define UTIL_TEX
|
||||
|
||||
#endif /* UTIL_TEX */
|
||||
|
||||
void setup_noise(void)
|
||||
{
|
||||
jitternoise = texelfetch_noise_tex(gl_FragCoord.xy).rg; /* Global variable */
|
||||
}
|
||||
|
||||
vec3 tangent_to_world(vec3 vector, vec3 N, vec3 T, vec3 B)
|
||||
{
|
||||
@@ -27,20 +13,11 @@ vec3 hammersley_3d(float i, float invsamplenbr)
|
||||
{
|
||||
vec3 Xi; /* Theta, cos(Phi), sin(Phi) */
|
||||
|
||||
Xi.x = i * invsamplenbr; /* i/samples */
|
||||
Xi.x = fract(Xi.x + jitternoise.x);
|
||||
|
||||
int u = int(mod(i + jitternoise.y * HAMMERSLEY_SIZE, HAMMERSLEY_SIZE));
|
||||
|
||||
Xi.yz = texelFetch(texHammersley, u, 0).rg;
|
||||
Xi.x = i * invsamplenbr;
|
||||
Xi.yz = texelFetch(texHammersley, int(i), 0).rg;
|
||||
|
||||
return Xi;
|
||||
}
|
||||
|
||||
vec3 hammersley_3d(float i)
|
||||
{
|
||||
return hammersley_3d(i, invSampleCount);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* -------------- BSDFS -------------- */
|
||||
@@ -75,16 +52,16 @@ vec3 sample_ggx(vec3 rand, float a2, vec3 N, vec3 T, vec3 B, out float NH)
|
||||
}
|
||||
|
||||
#ifdef HAMMERSLEY_SIZE
|
||||
vec3 sample_ggx(float nsample, float a2, vec3 N, vec3 T, vec3 B)
|
||||
vec3 sample_ggx(float nsample, float inv_sample_count, float a2, vec3 N, vec3 T, vec3 B)
|
||||
{
|
||||
vec3 Xi = hammersley_3d(nsample);
|
||||
vec3 Xi = hammersley_3d(nsample, inv_sample_count);
|
||||
vec3 Ht = sample_ggx(Xi, a2);
|
||||
return tangent_to_world(Ht, N, T, B);
|
||||
}
|
||||
|
||||
vec3 sample_hemisphere(float nsample, vec3 N, vec3 T, vec3 B)
|
||||
vec3 sample_hemisphere(float nsample, float inv_sample_count, vec3 N, vec3 T, vec3 B)
|
||||
{
|
||||
vec3 Xi = hammersley_3d(nsample);
|
||||
vec3 Xi = hammersley_3d(nsample, inv_sample_count);
|
||||
|
||||
float z = Xi.x; /* cos theta */
|
||||
float r = sqrt(max(0.0, 1.0f - z * z)); /* sin theta */
|
||||
@@ -96,9 +73,9 @@ vec3 sample_hemisphere(float nsample, vec3 N, vec3 T, vec3 B)
|
||||
return tangent_to_world(Ht, N, T, B);
|
||||
}
|
||||
|
||||
vec3 sample_cone(float nsample, float angle, vec3 N, vec3 T, vec3 B)
|
||||
vec3 sample_cone(float nsample, float inv_sample_count, float angle, vec3 N, vec3 T, vec3 B)
|
||||
{
|
||||
vec3 Xi = hammersley_3d(nsample);
|
||||
vec3 Xi = hammersley_3d(nsample, inv_sample_count);
|
||||
|
||||
float z = cos(angle * Xi.x); /* cos theta */
|
||||
float r = sqrt(max(0.0, 1.0f - z * z)); /* sin theta */
|
||||
|
@@ -1,62 +1,89 @@
|
||||
#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(bsdf_sampling_lib.glsl)
|
||||
|
||||
uniform float a2;
|
||||
uniform float sampleCount;
|
||||
uniform float z;
|
||||
|
||||
out vec4 FragColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec3 N, T, B, V;
|
||||
float x = floor(gl_FragCoord.x) / (LUT_SIZE - 1.0);
|
||||
float y = floor(gl_FragCoord.y) / (LUT_SIZE - 1.0);
|
||||
|
||||
float x = gl_FragCoord.x / LUT_SIZE;
|
||||
float y = gl_FragCoord.y / LUT_SIZE;
|
||||
/* There is little variation if ior > 1.0 so we
|
||||
* maximize LUT precision for ior < 1.0 */
|
||||
x = x * 1.1;
|
||||
float ior = (x > 1.0) ? ior_from_f0((x - 1.0) * 10.0) : sqrt(x);
|
||||
float NV = (1.0 - (clamp(y, 1e-4, 0.9999)));
|
||||
float ior = clamp(sqrt(x), 0.05, 0.999);
|
||||
/* ior is sin of critical angle. */
|
||||
float critical_cos = sqrt(1.0 - saturate(ior * ior));
|
||||
|
||||
N = vec3(0.0, 0.0, 1.0);
|
||||
T = vec3(1.0, 0.0, 0.0);
|
||||
B = vec3(0.0, 1.0, 0.0);
|
||||
V = vec3(sqrt(1.0 - NV * NV), 0.0, NV);
|
||||
y = y * 2.0 - 1.0;
|
||||
/* Maximize texture usage on both sides of the critical angle. */
|
||||
y *= (y > 0.0) ? (1.0 - critical_cos) : critical_cos;
|
||||
/* Center LUT around critical angle to avoid strange interpolation issues when the critical
|
||||
* angle is changing. */
|
||||
y += critical_cos;
|
||||
float NV = clamp(y, 1e-4, 0.9999);
|
||||
|
||||
setup_noise();
|
||||
float a = z * z;
|
||||
float a2 = clamp(a * a, 1e-8, 0.9999);
|
||||
|
||||
vec3 V = vec3(sqrt(1.0 - NV * NV), 0.0, NV);
|
||||
|
||||
/* Integrating BTDF */
|
||||
float btdf_accum = 0.0;
|
||||
for (float i = 0.0; i < sampleCount; i++) {
|
||||
vec3 H = sample_ggx(i, a2, N, T, B); /* Microfacet normal */
|
||||
float fresnel_accum = 0.0;
|
||||
for (float j = 0.0; j < sampleCount; j++) {
|
||||
for (float i = 0.0; i < sampleCount; i++) {
|
||||
vec3 Xi = (vec3(i, j, 0.0) + 0.5) / sampleCount;
|
||||
Xi.yz = vec2(cos(Xi.y * M_2PI), sin(Xi.y * M_2PI));
|
||||
|
||||
float VH = dot(V, H);
|
||||
/* Microfacet normal. */
|
||||
vec3 H = sample_ggx(Xi, a2);
|
||||
|
||||
/* Check if there is total internal reflections. */
|
||||
float c = abs(VH);
|
||||
float g = ior * ior - 1.0 + c * c;
|
||||
float VH = dot(V, H);
|
||||
|
||||
float eta = 1.0 / ior;
|
||||
if (dot(H, V) < 0.0) {
|
||||
H = -H;
|
||||
eta = ior;
|
||||
}
|
||||
/* Check if there is total internal reflections. */
|
||||
float fresnel = F_eta(ior, VH);
|
||||
|
||||
vec3 L = refract(-V, H, eta);
|
||||
float NL = -dot(N, L);
|
||||
fresnel_accum += fresnel;
|
||||
|
||||
if ((NL > 0.0) && (g > 0.0)) {
|
||||
float LH = dot(L, H);
|
||||
float eta = 1.0 / ior;
|
||||
if (dot(H, V) < 0.0) {
|
||||
H = -H;
|
||||
eta = ior;
|
||||
}
|
||||
|
||||
float G1_l = NL * 2.0 /
|
||||
G1_Smith_GGX(NL, a2); /* Balancing the adjustments made in G1_Smith */
|
||||
vec3 L = refract(-V, H, eta);
|
||||
float NL = -L.z;
|
||||
|
||||
/* btdf = abs(VH*LH) * (ior*ior) * D * G(V) * G(L) / (Ht2 * NV)
|
||||
* pdf = (VH * abs(LH)) * (ior*ior) * D * G(V) / (Ht2 * NV) */
|
||||
float btdf = G1_l * abs(VH * LH) / (VH * abs(LH));
|
||||
if ((NL > 0.0) && (fresnel < 0.999)) {
|
||||
float LH = dot(L, H);
|
||||
|
||||
btdf_accum += btdf;
|
||||
/* Balancing the adjustments made in G1_Smith. */
|
||||
float G1_l = NL * 2.0 / G1_Smith_GGX(NL, a2);
|
||||
|
||||
/* btdf = abs(VH*LH) * (ior*ior) * D * G(V) * G(L) / (Ht2 * NV)
|
||||
* pdf = (VH * abs(LH)) * (ior*ior) * D * G(V) / (Ht2 * NV) */
|
||||
float btdf = G1_l * abs(VH * LH) / (VH * abs(LH));
|
||||
|
||||
btdf_accum += btdf;
|
||||
}
|
||||
}
|
||||
}
|
||||
btdf_accum /= sampleCount;
|
||||
btdf_accum /= sampleCount * sampleCount;
|
||||
fresnel_accum /= sampleCount * sampleCount;
|
||||
|
||||
FragColor = vec4(btdf_accum, 0.0, 0.0, 1.0);
|
||||
if (z == 0.0) {
|
||||
/* Perfect mirror. Increased precision because the roughness is clamped. */
|
||||
fresnel_accum = F_eta(ior, NV);
|
||||
}
|
||||
|
||||
if (x == 0.0) {
|
||||
/* Special case. */
|
||||
fresnel_accum = 1.0;
|
||||
btdf_accum = 0.0;
|
||||
}
|
||||
|
||||
/* There is place to put multiscater result (which is a little bit different still)
|
||||
* and / or lobe fitting for better sampling of */
|
||||
FragColor = vec4(btdf_accum, fresnel_accum, 0.0, 1.0);
|
||||
}
|
||||
|
@@ -0,0 +1,85 @@
|
||||
#pragma BLENDER_REQUIRE(lights_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(lightprobe_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(ambient_occlusion_lib.glsl)
|
||||
|
||||
struct ClosureInputDiffuse {
|
||||
vec3 N; /** Shading normal. */
|
||||
vec3 albedo; /** Used for multibounce GTAO approximation. Not applied to final radiance. */
|
||||
};
|
||||
|
||||
#define CLOSURE_INPUT_Diffuse_DEFAULT ClosureInputDiffuse(vec3(0.0), vec3(0.0))
|
||||
|
||||
struct ClosureEvalDiffuse {
|
||||
vec3 probe_sampling_dir; /** Direction to sample probes from. */
|
||||
float ambient_occlusion; /** Final occlusion for distant lighting. */
|
||||
};
|
||||
|
||||
/* Stubs. */
|
||||
#define ClosureOutputDiffuse ClosureOutput
|
||||
#define closure_Diffuse_planar_eval(cl_in, cl_eval, cl_common, data, cl_out)
|
||||
#define closure_Diffuse_cubemap_eval(cl_in, cl_eval, cl_common, data, cl_out)
|
||||
|
||||
ClosureEvalDiffuse closure_Diffuse_eval_init(inout ClosureInputDiffuse cl_in,
|
||||
ClosureEvalCommon cl_common,
|
||||
out ClosureOutputDiffuse cl_out)
|
||||
{
|
||||
cl_in.N = safe_normalize(cl_in.N);
|
||||
cl_out.radiance = vec3(0.0);
|
||||
|
||||
ClosureEvalDiffuse cl_eval;
|
||||
cl_eval.ambient_occlusion = diffuse_occlusion(
|
||||
cl_in.N, cl_common.bent_normal, cl_common.occlusion, cl_in.albedo);
|
||||
cl_eval.probe_sampling_dir = diffuse_dominant_dir(
|
||||
cl_in.N, cl_common.bent_normal, cl_common.occlusion);
|
||||
return cl_eval;
|
||||
}
|
||||
|
||||
void closure_Diffuse_light_eval(ClosureInputDiffuse cl_in,
|
||||
ClosureEvalDiffuse cl_eval,
|
||||
ClosureEvalCommon cl_common,
|
||||
ClosureLightData light,
|
||||
inout ClosureOutputDiffuse cl_out)
|
||||
{
|
||||
float radiance = light_diffuse(light.data, cl_in.N, cl_common.V, light.L);
|
||||
/* TODO(fclem) We could try to shadow lights that are shadowless with the ambient_occlusion
|
||||
* factor here. */
|
||||
cl_out.radiance += light.data.l_color * (light.vis * light.contact_shadow * radiance);
|
||||
}
|
||||
|
||||
void closure_Diffuse_grid_eval(ClosureInputDiffuse cl_in,
|
||||
ClosureEvalDiffuse cl_eval,
|
||||
ClosureEvalCommon cl_common,
|
||||
ClosureGridData grid,
|
||||
inout ClosureOutputDiffuse cl_out)
|
||||
{
|
||||
vec3 probe_radiance = probe_evaluate_grid(
|
||||
grid.data, cl_common.P, cl_eval.probe_sampling_dir, grid.local_pos);
|
||||
cl_out.radiance += grid.attenuation * probe_radiance;
|
||||
}
|
||||
|
||||
void closure_Diffuse_indirect_end(ClosureInputDiffuse cl_in,
|
||||
ClosureEvalDiffuse cl_eval,
|
||||
ClosureEvalCommon cl_common,
|
||||
inout ClosureOutputDiffuse cl_out)
|
||||
{
|
||||
/* If not enough light has been accumulated from probes, use the world specular cubemap
|
||||
* to fill the remaining energy needed. */
|
||||
if (cl_common.diffuse_accum > 0.0) {
|
||||
vec3 probe_radiance = probe_evaluate_world_diff(cl_eval.probe_sampling_dir);
|
||||
cl_out.radiance += cl_common.diffuse_accum * probe_radiance;
|
||||
}
|
||||
/* Apply occlusion on radiance before the light loop. */
|
||||
cl_out.radiance *= cl_eval.ambient_occlusion;
|
||||
}
|
||||
|
||||
void closure_Diffuse_eval_end(ClosureInputDiffuse cl_in,
|
||||
ClosureEvalDiffuse cl_eval,
|
||||
ClosureEvalCommon cl_common,
|
||||
inout ClosureOutputDiffuse cl_out)
|
||||
{
|
||||
#if defined(DEPTH_SHADER) || defined(WORLD_BACKGROUND)
|
||||
/* This makes shader resources become unused and avoid issues with samplers. (see T59747) */
|
||||
cl_out.radiance = vec3(0.0);
|
||||
return;
|
||||
#endif
|
||||
}
|
@@ -0,0 +1,136 @@
|
||||
|
||||
#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(lights_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(lightprobe_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(ambient_occlusion_lib.glsl)
|
||||
|
||||
struct ClosureInputGlossy {
|
||||
vec3 N; /** Shading normal. */
|
||||
float roughness; /** Input roughness, not squared. */
|
||||
};
|
||||
|
||||
#define CLOSURE_INPUT_Glossy_DEFAULT ClosureInputGlossy(vec3(0.0), 0.0)
|
||||
|
||||
struct ClosureEvalGlossy {
|
||||
vec4 ltc_mat; /** LTC matrix values. */
|
||||
float ltc_brdf_scale; /** LTC BRDF scaling. */
|
||||
vec3 probe_sampling_dir; /** Direction to sample probes from. */
|
||||
float spec_occlusion; /** Specular Occlusion. */
|
||||
vec3 raytrace_radiance; /** Raytrace reflection to be accumulated after occlusion. */
|
||||
};
|
||||
|
||||
/* Stubs. */
|
||||
#define ClosureOutputGlossy ClosureOutput
|
||||
#define closure_Glossy_grid_eval(cl_in, cl_eval, cl_common, data, cl_out)
|
||||
|
||||
#ifdef STEP_RESOLVE /* SSR */
|
||||
/* Prototype. */
|
||||
void raytrace_resolve(ClosureInputGlossy cl_in,
|
||||
inout ClosureEvalGlossy cl_eval,
|
||||
inout ClosureEvalCommon cl_common,
|
||||
inout ClosureOutputGlossy cl_out);
|
||||
#endif
|
||||
|
||||
ClosureEvalGlossy closure_Glossy_eval_init(inout ClosureInputGlossy cl_in,
|
||||
inout ClosureEvalCommon cl_common,
|
||||
out ClosureOutputGlossy cl_out)
|
||||
{
|
||||
cl_in.N = safe_normalize(cl_in.N);
|
||||
cl_in.roughness = clamp(cl_in.roughness, 1e-8, 0.9999);
|
||||
cl_out.radiance = vec3(0.0);
|
||||
|
||||
float NV = dot(cl_in.N, cl_common.V);
|
||||
vec2 lut_uv = lut_coords(NV, cl_in.roughness);
|
||||
|
||||
ClosureEvalGlossy cl_eval;
|
||||
cl_eval.ltc_mat = texture(utilTex, vec3(lut_uv, LTC_MAT_LAYER));
|
||||
cl_eval.probe_sampling_dir = specular_dominant_dir(cl_in.N, cl_common.V, sqr(cl_in.roughness));
|
||||
cl_eval.spec_occlusion = specular_occlusion(NV, cl_common.occlusion, cl_in.roughness);
|
||||
cl_eval.raytrace_radiance = vec3(0.0);
|
||||
|
||||
#ifdef STEP_RESOLVE /* SSR */
|
||||
raytrace_resolve(cl_in, cl_eval, cl_common, cl_out);
|
||||
#endif
|
||||
|
||||
/* The brdf split sum LUT is applied after the radiance accumulation.
|
||||
* Correct the LTC so that its energy is constant. */
|
||||
/* TODO(fclem) Optimize this so that only one scale factor is stored. */
|
||||
vec4 ltc_brdf = texture(utilTex, vec3(lut_uv, LTC_BRDF_LAYER)).barg;
|
||||
vec2 split_sum_brdf = ltc_brdf.zw;
|
||||
cl_eval.ltc_brdf_scale = (ltc_brdf.x + ltc_brdf.y) / (split_sum_brdf.x + split_sum_brdf.y);
|
||||
return cl_eval;
|
||||
}
|
||||
|
||||
void closure_Glossy_light_eval(ClosureInputGlossy cl_in,
|
||||
ClosureEvalGlossy cl_eval,
|
||||
ClosureEvalCommon cl_common,
|
||||
ClosureLightData light,
|
||||
inout ClosureOutputGlossy cl_out)
|
||||
{
|
||||
float radiance = light_specular(light.data, cl_eval.ltc_mat, cl_in.N, cl_common.V, light.L);
|
||||
radiance *= cl_eval.ltc_brdf_scale;
|
||||
cl_out.radiance += light.data.l_color *
|
||||
(light.data.l_spec * light.vis * light.contact_shadow * radiance);
|
||||
}
|
||||
|
||||
void closure_Glossy_planar_eval(ClosureInputGlossy cl_in,
|
||||
ClosureEvalGlossy cl_eval,
|
||||
inout ClosureEvalCommon cl_common,
|
||||
ClosurePlanarData planar,
|
||||
inout ClosureOutputGlossy cl_out)
|
||||
{
|
||||
#ifndef STEP_RESOLVE /* SSR already evaluates planar reflections. */
|
||||
vec3 probe_radiance = probe_evaluate_planar(
|
||||
planar.id, planar.data, cl_common.P, cl_in.N, cl_common.V, cl_in.roughness);
|
||||
cl_out.radiance += planar.attenuation * probe_radiance;
|
||||
#else
|
||||
/* HACK: Fix an issue with planar reflections still being counted inside the specular
|
||||
* accumulator. This only works because we only use one Glossy closure in the resolve pass. */
|
||||
cl_common.specular_accum += planar.attenuation;
|
||||
#endif
|
||||
}
|
||||
|
||||
void closure_Glossy_cubemap_eval(ClosureInputGlossy cl_in,
|
||||
ClosureEvalGlossy cl_eval,
|
||||
ClosureEvalCommon cl_common,
|
||||
ClosureCubemapData cube,
|
||||
inout ClosureOutputGlossy cl_out)
|
||||
{
|
||||
vec3 probe_radiance = probe_evaluate_cube(
|
||||
cube.id, cl_common.P, cl_eval.probe_sampling_dir, cl_in.roughness);
|
||||
cl_out.radiance += cube.attenuation * probe_radiance;
|
||||
}
|
||||
|
||||
void closure_Glossy_indirect_end(ClosureInputGlossy cl_in,
|
||||
ClosureEvalGlossy cl_eval,
|
||||
ClosureEvalCommon cl_common,
|
||||
inout ClosureOutputGlossy cl_out)
|
||||
{
|
||||
/* If not enough light has been accumulated from probes, use the world specular cubemap
|
||||
* to fill the remaining energy needed. */
|
||||
if (specToggle && cl_common.specular_accum > 0.0) {
|
||||
vec3 probe_radiance = probe_evaluate_world_spec(cl_eval.probe_sampling_dir, cl_in.roughness);
|
||||
cl_out.radiance += cl_common.specular_accum * probe_radiance;
|
||||
}
|
||||
|
||||
/* Apply occlusion on distant lighting. */
|
||||
cl_out.radiance *= cl_eval.spec_occlusion;
|
||||
/* Apply Raytrace reflections after occlusion since they are direct, local reflections. */
|
||||
cl_out.radiance += cl_eval.raytrace_radiance;
|
||||
}
|
||||
|
||||
void closure_Glossy_eval_end(ClosureInputGlossy cl_in,
|
||||
ClosureEvalGlossy cl_eval,
|
||||
ClosureEvalCommon cl_common,
|
||||
inout ClosureOutputGlossy cl_out)
|
||||
{
|
||||
#if defined(DEPTH_SHADER) || defined(WORLD_BACKGROUND)
|
||||
/* This makes shader resources become unused and avoid issues with samplers. (see T59747) */
|
||||
cl_out.radiance = vec3(0.0);
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (!specToggle) {
|
||||
cl_out.radiance = vec3(0.0);
|
||||
}
|
||||
}
|
316
source/blender/draw/engines/eevee/shaders/closure_eval_lib.glsl
Normal file
316
source/blender/draw/engines/eevee/shaders/closure_eval_lib.glsl
Normal file
@@ -0,0 +1,316 @@
|
||||
|
||||
#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(lights_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(lightprobe_lib.glsl)
|
||||
|
||||
/**
|
||||
* Extensive use of Macros to be able to change the maximum amount of evaluated closure easily.
|
||||
* NOTE: GLSL does not support variadic macros.
|
||||
*
|
||||
* Example
|
||||
* // Declare the cl_eval function
|
||||
* CLOSURE_EVAL_FUNCTION_DECLARE_3(name, Diffuse, Glossy, Refraction);
|
||||
* // Declare the inputs & outputs
|
||||
* CLOSURE_VARS_DECLARE(Diffuse, Glossy, Refraction);
|
||||
* // Specify inputs
|
||||
* in_Diffuse_0.N = N;
|
||||
* ...
|
||||
* // Call the cl_eval function
|
||||
* CLOSURE_EVAL_FUNCTION_3(name, Diffuse, Glossy, Refraction);
|
||||
* // Get the cl_out
|
||||
* closure.radiance = out_Diffuse_0.radiance + out_Glossy_1.radiance + out_Refraction_2.radiance;
|
||||
**/
|
||||
|
||||
#define CLOSURE_VARS_DECLARE(t0, t1, t2, t3) \
|
||||
ClosureInputCommon in_common = CLOSURE_INPUT_COMMON_DEFAULT; \
|
||||
ClosureInput##t0 in_##t0##_0 = CLOSURE_INPUT_##t0##_DEFAULT; \
|
||||
ClosureInput##t1 in_##t1##_1 = CLOSURE_INPUT_##t1##_DEFAULT; \
|
||||
ClosureInput##t2 in_##t2##_2 = CLOSURE_INPUT_##t2##_DEFAULT; \
|
||||
ClosureInput##t3 in_##t3##_3 = CLOSURE_INPUT_##t3##_DEFAULT; \
|
||||
ClosureOutput##t0 out_##t0##_0; \
|
||||
ClosureOutput##t1 out_##t1##_1; \
|
||||
ClosureOutput##t2 out_##t2##_2; \
|
||||
ClosureOutput##t3 out_##t3##_3;
|
||||
|
||||
#define CLOSURE_EVAL_DECLARE(t0, t1, t2, t3) \
|
||||
ClosureEvalCommon cl_common = closure_Common_eval_init(in_common); \
|
||||
ClosureEval##t0 eval_##t0##_0 = closure_##t0##_eval_init(in_##t0##_0, cl_common, out_##t0##_0); \
|
||||
ClosureEval##t1 eval_##t1##_1 = closure_##t1##_eval_init(in_##t1##_1, cl_common, out_##t1##_1); \
|
||||
ClosureEval##t2 eval_##t2##_2 = closure_##t2##_eval_init(in_##t2##_2, cl_common, out_##t2##_2); \
|
||||
ClosureEval##t3 eval_##t3##_3 = closure_##t3##_eval_init(in_##t3##_3, cl_common, out_##t3##_3);
|
||||
|
||||
#define CLOSURE_META_SUBROUTINE(subroutine, t0, t1, t2, t3) \
|
||||
closure_##t0##_##subroutine(in_##t0##_0, eval_##t0##_0, cl_common, out_##t0##_0); \
|
||||
closure_##t1##_##subroutine(in_##t1##_1, eval_##t1##_1, cl_common, out_##t1##_1); \
|
||||
closure_##t2##_##subroutine(in_##t2##_2, eval_##t2##_2, cl_common, out_##t2##_2); \
|
||||
closure_##t3##_##subroutine(in_##t3##_3, eval_##t3##_3, cl_common, out_##t3##_3);
|
||||
|
||||
#define CLOSURE_META_SUBROUTINE_DATA(subroutine, sub_data, t0, t1, t2, t3) \
|
||||
closure_##t0##_##subroutine(in_##t0##_0, eval_##t0##_0, cl_common, sub_data, out_##t0##_0); \
|
||||
closure_##t1##_##subroutine(in_##t1##_1, eval_##t1##_1, cl_common, sub_data, out_##t1##_1); \
|
||||
closure_##t2##_##subroutine(in_##t2##_2, eval_##t2##_2, cl_common, sub_data, out_##t2##_2); \
|
||||
closure_##t3##_##subroutine(in_##t3##_3, eval_##t3##_3, cl_common, sub_data, out_##t3##_3);
|
||||
|
||||
/* Inputs are inout so that callers can get the final inputs used for evaluation. */
|
||||
#define CLOSURE_EVAL_FUNCTION_DECLARE(name, t0, t1, t2, t3) \
|
||||
void closure_##name##_eval(ClosureInputCommon in_common, \
|
||||
inout ClosureInput##t0 in_##t0##_0, \
|
||||
inout ClosureInput##t1 in_##t1##_1, \
|
||||
inout ClosureInput##t2 in_##t2##_2, \
|
||||
inout ClosureInput##t3 in_##t3##_3, \
|
||||
out ClosureOutput##t0 out_##t0##_0, \
|
||||
out ClosureOutput##t1 out_##t1##_1, \
|
||||
out ClosureOutput##t2 out_##t2##_2, \
|
||||
out ClosureOutput##t3 out_##t3##_3) \
|
||||
{ \
|
||||
CLOSURE_EVAL_DECLARE(t0, t1, t2, t3); \
|
||||
\
|
||||
for (int i = 0; cl_common.specular_accum > 0.0 && i < prbNumPlanar && i < MAX_PLANAR; i++) { \
|
||||
ClosurePlanarData planar = closure_planar_eval_init(i, cl_common); \
|
||||
if (planar.attenuation > 1e-8) { \
|
||||
CLOSURE_META_SUBROUTINE_DATA(planar_eval, planar, t0, t1, t2, t3); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
/* Starts at 1 because 0 is world cubemap. */ \
|
||||
for (int i = 1; cl_common.specular_accum > 0.0 && i < prbNumRenderCube && i < MAX_PROBE; \
|
||||
i++) { \
|
||||
ClosureCubemapData cube = closure_cubemap_eval_init(i, cl_common); \
|
||||
if (cube.attenuation > 1e-8) { \
|
||||
CLOSURE_META_SUBROUTINE_DATA(cubemap_eval, cube, t0, t1, t2, t3); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
/* Starts at 1 because 0 is world irradiance. */ \
|
||||
for (int i = 1; cl_common.diffuse_accum > 0.0 && i < prbNumRenderGrid && i < MAX_GRID; i++) { \
|
||||
ClosureGridData grid = closure_grid_eval_init(i, cl_common); \
|
||||
if (grid.attenuation > 1e-8) { \
|
||||
CLOSURE_META_SUBROUTINE_DATA(grid_eval, grid, t0, t1, t2, t3); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
CLOSURE_META_SUBROUTINE(indirect_end, t0, t1, t2, t3); \
|
||||
\
|
||||
for (int i = 0; i < laNumLight && i < MAX_LIGHT; i++) { \
|
||||
ClosureLightData light = closure_light_eval_init(cl_common, i); \
|
||||
if (light.vis > 1e-8) { \
|
||||
CLOSURE_META_SUBROUTINE_DATA(light_eval, light, t0, t1, t2, t3); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
CLOSURE_META_SUBROUTINE(eval_end, t0, t1, t2, t3); \
|
||||
}
|
||||
|
||||
#define CLOSURE_EVAL_FUNCTION(name, t0, t1, t2, t3) \
|
||||
closure_##name##_eval(in_common, \
|
||||
in_##t0##_0, \
|
||||
in_##t1##_1, \
|
||||
in_##t2##_2, \
|
||||
in_##t3##_3, \
|
||||
out_##t0##_0, \
|
||||
out_##t1##_1, \
|
||||
out_##t2##_2, \
|
||||
out_##t3##_3)
|
||||
|
||||
#define CLOSURE_EVAL_FUNCTION_DECLARE_1(name, t0) \
|
||||
CLOSURE_EVAL_FUNCTION_DECLARE(name, t0, Dummy, Dummy, Dummy)
|
||||
#define CLOSURE_EVAL_FUNCTION_DECLARE_2(name, t0, t1) \
|
||||
CLOSURE_EVAL_FUNCTION_DECLARE(name, t0, t1, Dummy, Dummy)
|
||||
#define CLOSURE_EVAL_FUNCTION_DECLARE_3(name, t0, t1, t2) \
|
||||
CLOSURE_EVAL_FUNCTION_DECLARE(name, t0, t1, t2, Dummy)
|
||||
#define CLOSURE_EVAL_FUNCTION_DECLARE_4(name, t0, t1, t2, t3) \
|
||||
CLOSURE_EVAL_FUNCTION_DECLARE(name, t0, t1, t2, t3)
|
||||
|
||||
#define CLOSURE_VARS_DECLARE_1(t0) CLOSURE_VARS_DECLARE(t0, Dummy, Dummy, Dummy)
|
||||
#define CLOSURE_VARS_DECLARE_2(t0, t1) CLOSURE_VARS_DECLARE(t0, t1, Dummy, Dummy)
|
||||
#define CLOSURE_VARS_DECLARE_3(t0, t1, t2) CLOSURE_VARS_DECLARE(t0, t1, t2, Dummy)
|
||||
#define CLOSURE_VARS_DECLARE_4(t0, t1, t2, t3) CLOSURE_VARS_DECLARE(t0, t1, t2, t3)
|
||||
|
||||
#define CLOSURE_EVAL_FUNCTION_1(name, t0) CLOSURE_EVAL_FUNCTION(name, t0, Dummy, Dummy, Dummy)
|
||||
#define CLOSURE_EVAL_FUNCTION_2(name, t0, t1) CLOSURE_EVAL_FUNCTION(name, t0, t1, Dummy, Dummy)
|
||||
#define CLOSURE_EVAL_FUNCTION_3(name, t0, t1, t2) CLOSURE_EVAL_FUNCTION(name, t0, t1, t2, Dummy)
|
||||
#define CLOSURE_EVAL_FUNCTION_4(name, t0, t1, t2, t3) CLOSURE_EVAL_FUNCTION(name, t0, t1, t2, t3)
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Dummy Closure
|
||||
*
|
||||
* Dummy closure type that will be optimized out by the compiler.
|
||||
* \{ */
|
||||
|
||||
#define ClosureInputDummy ClosureOutput
|
||||
#define ClosureOutputDummy ClosureOutput
|
||||
#define ClosureEvalDummy ClosureOutput
|
||||
#define CLOSURE_EVAL_DUMMY ClosureOutput(vec3(0))
|
||||
#define CLOSURE_INPUT_Dummy_DEFAULT CLOSURE_EVAL_DUMMY
|
||||
#define closure_Dummy_eval_init(cl_in, cl_common, cl_out) CLOSURE_EVAL_DUMMY
|
||||
#define closure_Dummy_planar_eval(cl_in, cl_eval, cl_common, data, cl_out)
|
||||
#define closure_Dummy_cubemap_eval(cl_in, cl_eval, cl_common, data, cl_out)
|
||||
#define closure_Dummy_grid_eval(cl_in, cl_eval, cl_common, data, cl_out)
|
||||
#define closure_Dummy_indirect_end(cl_in, cl_eval, cl_common, cl_out)
|
||||
#define closure_Dummy_light_eval(cl_in, cl_eval, cl_common, data, cl_out)
|
||||
#define closure_Dummy_eval_end(cl_in, cl_eval, cl_common, cl_out)
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Common cl_eval data
|
||||
*
|
||||
* Eval data not dependant on input parameters. All might not be used but unused ones
|
||||
* will be optimized out.
|
||||
* \{ */
|
||||
|
||||
struct ClosureInputCommon {
|
||||
/** Custom occlusion value set by the user. */
|
||||
float occlusion;
|
||||
};
|
||||
|
||||
#define CLOSURE_INPUT_COMMON_DEFAULT ClosureInputCommon(1.0)
|
||||
|
||||
struct ClosureEvalCommon {
|
||||
/** View vector. */
|
||||
vec3 V;
|
||||
/** Surface position. */
|
||||
vec3 P;
|
||||
/** Normal vector, always facing camera. */
|
||||
vec3 N;
|
||||
/** Normal vector, always facing camera. (viewspace) */
|
||||
vec3 vN;
|
||||
/** Surface position. (viewspace) */
|
||||
vec3 vP;
|
||||
/** Geometric normal, always facing camera. (viewspace) */
|
||||
vec3 vNg;
|
||||
/** Random numbers. 3 random sequences. zw is a random point on a circle. */
|
||||
vec4 rand;
|
||||
/** Final occlusion factor. Mix of the user occlusion and SSAO. */
|
||||
float occlusion;
|
||||
/** Least occluded direction in the hemisphere. */
|
||||
vec3 bent_normal;
|
||||
|
||||
/** Specular probe accumulator. Shared between planar and cubemap probe. */
|
||||
float specular_accum;
|
||||
/** Diffuse probe accumulator. */
|
||||
float diffuse_accum;
|
||||
/** Viewspace depth to start raytracing from. */
|
||||
float tracing_depth;
|
||||
};
|
||||
|
||||
/* Common cl_out struct used by most closures. */
|
||||
struct ClosureOutput {
|
||||
vec3 radiance;
|
||||
};
|
||||
|
||||
ClosureEvalCommon closure_Common_eval_init(ClosureInputCommon cl_in)
|
||||
{
|
||||
ClosureEvalCommon cl_eval;
|
||||
cl_eval.rand = texelfetch_noise_tex(gl_FragCoord.xy);
|
||||
cl_eval.V = cameraVec;
|
||||
cl_eval.P = worldPosition;
|
||||
cl_eval.N = safe_normalize(gl_FrontFacing ? worldNormal : -worldNormal);
|
||||
cl_eval.vN = safe_normalize(gl_FrontFacing ? viewNormal : -viewNormal);
|
||||
cl_eval.vP = viewPosition;
|
||||
cl_eval.vNg = safe_normalize(cross(dFdx(viewPosition), dFdy(viewPosition)));
|
||||
/* TODO(fclem) See if we can avoid this complicated setup. */
|
||||
cl_eval.tracing_depth = gl_FragCoord.z;
|
||||
/* Constant bias (due to depth buffer precision) */
|
||||
/* Magic numbers for 24bits of precision.
|
||||
* From http://terathon.com/gdc07_lengyel.pdf (slide 26) */
|
||||
cl_eval.tracing_depth -= mix(2.4e-7, 4.8e-7, gl_FragCoord.z);
|
||||
/* Convert to view Z. */
|
||||
cl_eval.tracing_depth = get_view_z_from_depth(cl_eval.tracing_depth);
|
||||
|
||||
/* TODO(fclem) Do occlusion evaluation per Closure using shading normal. */
|
||||
cl_eval.occlusion = min(
|
||||
cl_in.occlusion,
|
||||
occlusion_compute(cl_eval.N, cl_eval.vP, cl_eval.rand, cl_eval.bent_normal));
|
||||
|
||||
cl_eval.specular_accum = 1.0;
|
||||
cl_eval.diffuse_accum = 1.0;
|
||||
return cl_eval;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Loop data
|
||||
*
|
||||
* Loop datas are conveniently packed into struct to make it future proof.
|
||||
* \{ */
|
||||
|
||||
struct ClosureLightData {
|
||||
LightData data; /** Light Data. */
|
||||
vec4 L; /** Non-Normalized Light Vector (surface to light) with length in W component. */
|
||||
float vis; /** Light visibility. */
|
||||
float contact_shadow; /** Result of contact shadow tracing. */
|
||||
};
|
||||
|
||||
ClosureLightData closure_light_eval_init(ClosureEvalCommon cl_common, int light_id)
|
||||
{
|
||||
ClosureLightData light;
|
||||
light.data = lights_data[light_id];
|
||||
|
||||
light.L.xyz = light.data.l_position - cl_common.P;
|
||||
light.L.w = length(light.L.xyz);
|
||||
|
||||
light.vis = light_visibility(light.data, cl_common.P, light.L);
|
||||
light.contact_shadow = light_contact_shadows(light.data,
|
||||
cl_common.P,
|
||||
cl_common.vP,
|
||||
cl_common.tracing_depth,
|
||||
cl_common.vNg,
|
||||
cl_common.rand.x,
|
||||
light.vis);
|
||||
|
||||
return light;
|
||||
}
|
||||
|
||||
struct ClosureCubemapData {
|
||||
int id; /** Probe id. */
|
||||
float attenuation; /** Attenuation. */
|
||||
};
|
||||
|
||||
ClosureCubemapData closure_cubemap_eval_init(int cube_id, inout ClosureEvalCommon cl_common)
|
||||
{
|
||||
ClosureCubemapData cube;
|
||||
cube.id = cube_id;
|
||||
cube.attenuation = probe_attenuation_cube(cube_id, cl_common.P);
|
||||
cube.attenuation = min(cube.attenuation, cl_common.specular_accum);
|
||||
cl_common.specular_accum -= cube.attenuation;
|
||||
return cube;
|
||||
}
|
||||
|
||||
struct ClosurePlanarData {
|
||||
int id; /** Probe id. */
|
||||
PlanarData data; /** planars_data[id]. */
|
||||
float attenuation; /** Attenuation. */
|
||||
};
|
||||
|
||||
ClosurePlanarData closure_planar_eval_init(int planar_id, inout ClosureEvalCommon cl_common)
|
||||
{
|
||||
ClosurePlanarData planar;
|
||||
planar.id = planar_id;
|
||||
planar.data = planars_data[planar_id];
|
||||
planar.attenuation = probe_attenuation_planar(planar.data, cl_common.P, cl_common.N, 0.0);
|
||||
planar.attenuation = min(planar.attenuation, cl_common.specular_accum);
|
||||
cl_common.specular_accum -= planar.attenuation;
|
||||
return planar;
|
||||
}
|
||||
|
||||
struct ClosureGridData {
|
||||
int id; /** Grid id. */
|
||||
GridData data; /** grids_data[id] */
|
||||
float attenuation; /** Attenuation. */
|
||||
vec3 local_pos; /** Local position inside the grid. */
|
||||
};
|
||||
|
||||
ClosureGridData closure_grid_eval_init(int id, inout ClosureEvalCommon cl_common)
|
||||
{
|
||||
ClosureGridData grid;
|
||||
grid.id = id;
|
||||
grid.data = grids_data[id];
|
||||
grid.attenuation = probe_attenuation_grid(grid.data, cl_common.P, grid.local_pos);
|
||||
grid.attenuation = min(grid.attenuation, cl_common.diffuse_accum);
|
||||
cl_common.diffuse_accum -= grid.attenuation;
|
||||
return grid;
|
||||
}
|
||||
|
||||
/** \} */
|
@@ -0,0 +1,128 @@
|
||||
|
||||
#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(lights_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(lightprobe_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(ambient_occlusion_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(ssr_lib.glsl)
|
||||
|
||||
struct ClosureInputRefraction {
|
||||
vec3 N; /** Shading normal. */
|
||||
float roughness; /** Input roughness, not squared. */
|
||||
float ior; /** Index of refraction ratio. */
|
||||
};
|
||||
|
||||
#define CLOSURE_INPUT_Refraction_DEFAULT ClosureInputRefraction(vec3(0.0), 0.0, 0.0)
|
||||
|
||||
struct ClosureEvalRefraction {
|
||||
vec3 P; /** LTC matrix values. */
|
||||
vec3 ltc_brdf; /** LTC BRDF values. */
|
||||
vec3 probe_sampling_dir; /** Direction to sample probes from. */
|
||||
float probes_weight; /** Factor to apply to probe radiance. */
|
||||
};
|
||||
|
||||
/* Stubs. */
|
||||
#define ClosureOutputRefraction ClosureOutput
|
||||
#define closure_Refraction_grid_eval(cl_in, cl_eval, cl_common, data, cl_out)
|
||||
|
||||
ClosureEvalRefraction closure_Refraction_eval_init(inout ClosureInputRefraction cl_in,
|
||||
ClosureEvalCommon cl_common,
|
||||
out ClosureOutputRefraction cl_out)
|
||||
{
|
||||
cl_in.N = safe_normalize(cl_in.N);
|
||||
cl_in.roughness = clamp(cl_in.roughness, 1e-8, 0.9999);
|
||||
cl_in.ior = max(cl_in.ior, 1e-5);
|
||||
cl_out.radiance = vec3(0.0);
|
||||
|
||||
ClosureEvalRefraction cl_eval;
|
||||
vec3 cl_V;
|
||||
float eval_ior;
|
||||
/* Refract the view vector using the depth heuristic.
|
||||
* Then later Refract a second time the already refracted
|
||||
* ray using the inverse ior. */
|
||||
if (refractionDepth > 0.0) {
|
||||
eval_ior = 1.0 / cl_in.ior;
|
||||
cl_V = -refract(-cl_common.V, cl_in.N, eval_ior);
|
||||
vec3 plane_pos = cl_common.P - cl_in.N * refractionDepth;
|
||||
cl_eval.P = line_plane_intersect(cl_common.P, cl_V, plane_pos, cl_in.N);
|
||||
}
|
||||
else {
|
||||
eval_ior = cl_in.ior;
|
||||
cl_V = cl_common.V;
|
||||
cl_eval.P = cl_common.P;
|
||||
}
|
||||
|
||||
cl_eval.probe_sampling_dir = refraction_dominant_dir(cl_in.N, cl_V, cl_in.roughness, eval_ior);
|
||||
cl_eval.probes_weight = 1.0;
|
||||
|
||||
#ifdef USE_REFRACTION
|
||||
if (ssrefractToggle && cl_in.roughness < ssrMaxRoughness + 0.2) {
|
||||
/* Find approximated position of the 2nd refraction event. */
|
||||
vec3 vP = (refractionDepth > 0.0) ? transform_point(ViewMatrix, cl_eval.P) : cl_common.vP;
|
||||
vec4 ssr_output = screen_space_refraction(
|
||||
vP, cl_in.N, cl_V, eval_ior, sqr(cl_in.roughness), cl_common.rand);
|
||||
ssr_output.a *= smoothstep(ssrMaxRoughness + 0.2, ssrMaxRoughness, cl_in.roughness);
|
||||
cl_out.radiance += ssr_output.rgb * ssr_output.a;
|
||||
cl_eval.probes_weight -= ssr_output.a;
|
||||
}
|
||||
#endif
|
||||
return cl_eval;
|
||||
}
|
||||
|
||||
void closure_Refraction_light_eval(ClosureInputRefraction cl_in,
|
||||
ClosureEvalRefraction cl_eval,
|
||||
ClosureEvalCommon cl_common,
|
||||
ClosureLightData light,
|
||||
inout ClosureOutputRefraction cl_out)
|
||||
{
|
||||
/* Not implemented yet. */
|
||||
}
|
||||
|
||||
void closure_Refraction_planar_eval(ClosureInputRefraction cl_in,
|
||||
ClosureEvalRefraction cl_eval,
|
||||
ClosureEvalCommon cl_common,
|
||||
ClosurePlanarData planar,
|
||||
inout ClosureOutputRefraction cl_out)
|
||||
{
|
||||
/* Not implemented yet. */
|
||||
}
|
||||
|
||||
void closure_Refraction_cubemap_eval(ClosureInputRefraction cl_in,
|
||||
ClosureEvalRefraction cl_eval,
|
||||
ClosureEvalCommon cl_common,
|
||||
ClosureCubemapData cube,
|
||||
inout ClosureOutputRefraction cl_out)
|
||||
{
|
||||
vec3 probe_radiance = probe_evaluate_cube(
|
||||
cube.id, cl_eval.P, cl_eval.probe_sampling_dir, sqr(cl_in.roughness));
|
||||
cl_out.radiance += (cube.attenuation * cl_eval.probes_weight) * probe_radiance;
|
||||
}
|
||||
|
||||
void closure_Refraction_indirect_end(ClosureInputRefraction cl_in,
|
||||
ClosureEvalRefraction cl_eval,
|
||||
ClosureEvalCommon cl_common,
|
||||
inout ClosureOutputRefraction cl_out)
|
||||
{
|
||||
/* If not enough light has been accumulated from probes, use the world specular cubemap
|
||||
* to fill the remaining energy needed. */
|
||||
if (specToggle && cl_common.specular_accum > 0.0) {
|
||||
vec3 probe_radiance = probe_evaluate_world_spec(cl_eval.probe_sampling_dir,
|
||||
sqr(cl_in.roughness));
|
||||
cl_out.radiance += (cl_common.specular_accum * cl_eval.probes_weight) * probe_radiance;
|
||||
}
|
||||
}
|
||||
|
||||
void closure_Refraction_eval_end(ClosureInputRefraction cl_in,
|
||||
ClosureEvalRefraction cl_eval,
|
||||
ClosureEvalCommon cl_common,
|
||||
inout ClosureOutputRefraction cl_out)
|
||||
{
|
||||
#if defined(DEPTH_SHADER) || defined(WORLD_BACKGROUND)
|
||||
/* This makes shader resources become unused and avoid issues with samplers. (see T59747) */
|
||||
cl_out.radiance = vec3(0.0);
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (!specToggle) {
|
||||
cl_out.radiance = vec3(0.0);
|
||||
}
|
||||
}
|
@@ -0,0 +1,71 @@
|
||||
|
||||
#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(lights_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(lightprobe_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(ambient_occlusion_lib.glsl)
|
||||
|
||||
struct ClosureInputTranslucent {
|
||||
vec3 N; /** Shading normal. */
|
||||
};
|
||||
|
||||
#define CLOSURE_INPUT_Translucent_DEFAULT ClosureInputTranslucent(vec3(0.0))
|
||||
|
||||
/* Stubs. */
|
||||
#define ClosureEvalTranslucent ClosureEvalDummy
|
||||
#define ClosureOutputTranslucent ClosureOutput
|
||||
#define closure_Translucent_planar_eval(cl_in, cl_eval, cl_common, data, cl_out)
|
||||
#define closure_Translucent_cubemap_eval(cl_in, cl_eval, cl_common, data, cl_out)
|
||||
|
||||
ClosureEvalTranslucent closure_Translucent_eval_init(inout ClosureInputTranslucent cl_in,
|
||||
ClosureEvalCommon cl_common,
|
||||
out ClosureOutputTranslucent cl_out)
|
||||
{
|
||||
cl_in.N = safe_normalize(cl_in.N);
|
||||
cl_out.radiance = vec3(0.0);
|
||||
return CLOSURE_EVAL_DUMMY;
|
||||
}
|
||||
|
||||
void closure_Translucent_light_eval(ClosureInputTranslucent cl_in,
|
||||
ClosureEvalTranslucent cl_eval,
|
||||
ClosureEvalCommon cl_common,
|
||||
ClosureLightData light,
|
||||
inout ClosureOutputTranslucent cl_out)
|
||||
{
|
||||
float radiance = light_diffuse(light.data, cl_in.N, cl_common.V, light.L);
|
||||
cl_out.radiance += light.data.l_color * (light.vis * radiance);
|
||||
}
|
||||
|
||||
void closure_Translucent_grid_eval(ClosureInputTranslucent cl_in,
|
||||
ClosureEvalTranslucent cl_eval,
|
||||
ClosureEvalCommon cl_common,
|
||||
ClosureGridData grid,
|
||||
inout ClosureOutputTranslucent cl_out)
|
||||
{
|
||||
vec3 probe_radiance = probe_evaluate_grid(grid.data, cl_common.P, cl_in.N, grid.local_pos);
|
||||
cl_out.radiance += grid.attenuation * probe_radiance;
|
||||
}
|
||||
|
||||
void closure_Translucent_indirect_end(ClosureInputTranslucent cl_in,
|
||||
ClosureEvalTranslucent cl_eval,
|
||||
ClosureEvalCommon cl_common,
|
||||
inout ClosureOutputTranslucent cl_out)
|
||||
{
|
||||
/* If not enough light has been accumulated from probes, use the world specular cubemap
|
||||
* to fill the remaining energy needed. */
|
||||
if (cl_common.diffuse_accum > 0.0) {
|
||||
vec3 probe_radiance = probe_evaluate_world_diff(cl_in.N);
|
||||
cl_out.radiance += cl_common.diffuse_accum * probe_radiance;
|
||||
}
|
||||
}
|
||||
|
||||
void closure_Translucent_eval_end(ClosureInputTranslucent cl_in,
|
||||
ClosureEvalTranslucent cl_eval,
|
||||
ClosureEvalCommon cl_common,
|
||||
inout ClosureOutputTranslucent cl_out)
|
||||
{
|
||||
#if defined(DEPTH_SHADER) || defined(WORLD_BACKGROUND)
|
||||
/* This makes shader resources become unused and avoid issues with samplers. (see T59747) */
|
||||
cl_out.radiance = vec3(0.0);
|
||||
return;
|
||||
#endif
|
||||
}
|
@@ -1,545 +0,0 @@
|
||||
|
||||
#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(lightprobe_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(ambient_occlusion_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(ssr_lib.glsl)
|
||||
|
||||
/**
|
||||
* AUTO CONFIG
|
||||
* We include the file multiple times each time with a different configuration.
|
||||
* This leads to a lot of deadcode. Better idea would be to only generate the one needed.
|
||||
*/
|
||||
#if !defined(SURFACE_DEFAULT)
|
||||
# define SURFACE_DEFAULT
|
||||
# define CLOSURE_NAME eevee_closure_default
|
||||
# define CLOSURE_DIFFUSE
|
||||
# define CLOSURE_GLOSSY
|
||||
#endif /* SURFACE_DEFAULT */
|
||||
|
||||
#if !defined(SURFACE_DEFAULT_CLEARCOAT) && !defined(CLOSURE_NAME)
|
||||
# define SURFACE_DEFAULT_CLEARCOAT
|
||||
# define CLOSURE_NAME eevee_closure_default_clearcoat
|
||||
# define CLOSURE_DIFFUSE
|
||||
# define CLOSURE_GLOSSY
|
||||
# define CLOSURE_CLEARCOAT
|
||||
#endif /* SURFACE_DEFAULT_CLEARCOAT */
|
||||
|
||||
#if !defined(SURFACE_PRINCIPLED) && !defined(CLOSURE_NAME)
|
||||
# define SURFACE_PRINCIPLED
|
||||
# define CLOSURE_NAME eevee_closure_principled
|
||||
# define CLOSURE_DIFFUSE
|
||||
# define CLOSURE_GLOSSY
|
||||
# define CLOSURE_CLEARCOAT
|
||||
# define CLOSURE_REFRACTION
|
||||
# define CLOSURE_SUBSURFACE
|
||||
#endif /* SURFACE_PRINCIPLED */
|
||||
|
||||
#if !defined(SURFACE_CLEARCOAT) && !defined(CLOSURE_NAME)
|
||||
# define SURFACE_CLEARCOAT
|
||||
# define CLOSURE_NAME eevee_closure_clearcoat
|
||||
# define CLOSURE_GLOSSY
|
||||
# define CLOSURE_CLEARCOAT
|
||||
#endif /* SURFACE_CLEARCOAT */
|
||||
|
||||
#if !defined(SURFACE_DIFFUSE) && !defined(CLOSURE_NAME)
|
||||
# define SURFACE_DIFFUSE
|
||||
# define CLOSURE_NAME eevee_closure_diffuse
|
||||
# define CLOSURE_DIFFUSE
|
||||
#endif /* SURFACE_DIFFUSE */
|
||||
|
||||
#if !defined(SURFACE_SUBSURFACE) && !defined(CLOSURE_NAME)
|
||||
# define SURFACE_SUBSURFACE
|
||||
# define CLOSURE_NAME eevee_closure_subsurface
|
||||
# define CLOSURE_DIFFUSE
|
||||
# define CLOSURE_SUBSURFACE
|
||||
#endif /* SURFACE_SUBSURFACE */
|
||||
|
||||
#if !defined(SURFACE_SKIN) && !defined(CLOSURE_NAME)
|
||||
# define SURFACE_SKIN
|
||||
# define CLOSURE_NAME eevee_closure_skin
|
||||
# define CLOSURE_DIFFUSE
|
||||
# define CLOSURE_SUBSURFACE
|
||||
# define CLOSURE_GLOSSY
|
||||
#endif /* SURFACE_SKIN */
|
||||
|
||||
#if !defined(SURFACE_GLOSSY) && !defined(CLOSURE_NAME)
|
||||
# define SURFACE_GLOSSY
|
||||
# define CLOSURE_NAME eevee_closure_glossy
|
||||
# define CLOSURE_GLOSSY
|
||||
#endif /* SURFACE_GLOSSY */
|
||||
|
||||
#if !defined(SURFACE_REFRACT) && !defined(CLOSURE_NAME)
|
||||
# define SURFACE_REFRACT
|
||||
# define CLOSURE_NAME eevee_closure_refraction
|
||||
# define CLOSURE_REFRACTION
|
||||
#endif /* SURFACE_REFRACT */
|
||||
|
||||
#if !defined(SURFACE_GLASS) && !defined(CLOSURE_NAME)
|
||||
# define SURFACE_GLASS
|
||||
# define CLOSURE_NAME eevee_closure_glass
|
||||
# define CLOSURE_GLOSSY
|
||||
# define CLOSURE_REFRACTION
|
||||
#endif /* SURFACE_GLASS */
|
||||
|
||||
/* Safety : CLOSURE_CLEARCOAT implies CLOSURE_GLOSSY */
|
||||
#ifdef CLOSURE_CLEARCOAT
|
||||
# ifndef CLOSURE_GLOSSY
|
||||
# define CLOSURE_GLOSSY
|
||||
# endif
|
||||
#endif /* CLOSURE_CLEARCOAT */
|
||||
|
||||
void CLOSURE_NAME(vec3 N
|
||||
#ifdef CLOSURE_DIFFUSE
|
||||
,
|
||||
vec3 albedo
|
||||
#endif
|
||||
#ifdef CLOSURE_GLOSSY
|
||||
,
|
||||
vec3 f0,
|
||||
vec3 f90,
|
||||
int ssr_id
|
||||
#endif
|
||||
#if defined(CLOSURE_GLOSSY) || defined(CLOSURE_REFRACTION)
|
||||
,
|
||||
float roughness
|
||||
#endif
|
||||
#ifdef CLOSURE_CLEARCOAT
|
||||
,
|
||||
vec3 C_N,
|
||||
float C_intensity,
|
||||
float C_roughness
|
||||
#endif
|
||||
#if defined(CLOSURE_GLOSSY) || defined(CLOSURE_DIFFUSE)
|
||||
,
|
||||
float ao
|
||||
#endif
|
||||
#ifdef CLOSURE_SUBSURFACE
|
||||
,
|
||||
float sss_scale
|
||||
#endif
|
||||
#ifdef CLOSURE_REFRACTION
|
||||
,
|
||||
float ior
|
||||
#endif
|
||||
,
|
||||
const bool use_contact_shadows
|
||||
#ifdef CLOSURE_DIFFUSE
|
||||
,
|
||||
out vec3 out_diff
|
||||
#endif
|
||||
#ifdef CLOSURE_GLOSSY
|
||||
,
|
||||
out vec3 out_spec
|
||||
#endif
|
||||
#ifdef CLOSURE_REFRACTION
|
||||
,
|
||||
out vec3 out_refr
|
||||
#endif
|
||||
#ifdef CLOSURE_GLOSSY
|
||||
,
|
||||
out vec3 ssr_spec
|
||||
#endif
|
||||
)
|
||||
{
|
||||
#ifdef CLOSURE_DIFFUSE
|
||||
out_diff = vec3(0.0);
|
||||
#endif
|
||||
|
||||
#ifdef CLOSURE_GLOSSY
|
||||
out_spec = vec3(0.0);
|
||||
#endif
|
||||
|
||||
#ifdef CLOSURE_REFRACTION
|
||||
out_refr = vec3(0.0);
|
||||
#endif
|
||||
|
||||
#if defined(DEPTH_SHADER) || defined(WORLD_BACKGROUND)
|
||||
/* This makes shader resources become unused and avoid issues with samplers. (see T59747) */
|
||||
return;
|
||||
#else
|
||||
|
||||
/* Zero length vectors cause issues, see: T51979. */
|
||||
float len = length(N);
|
||||
if (isnan(len)) {
|
||||
return;
|
||||
}
|
||||
N /= len;
|
||||
|
||||
# ifdef CLOSURE_CLEARCOAT
|
||||
len = length(C_N);
|
||||
if (isnan(len)) {
|
||||
return;
|
||||
}
|
||||
C_N /= len;
|
||||
# endif
|
||||
|
||||
# if defined(CLOSURE_GLOSSY) || defined(CLOSURE_REFRACTION)
|
||||
roughness = clamp(roughness, 1e-8, 0.9999);
|
||||
float roughnessSquared = roughness * roughness;
|
||||
# endif
|
||||
|
||||
# ifdef CLOSURE_CLEARCOAT
|
||||
C_roughness = clamp(C_roughness, 1e-8, 0.9999);
|
||||
float C_roughnessSquared = C_roughness * C_roughness;
|
||||
# endif
|
||||
|
||||
vec3 V = cameraVec;
|
||||
|
||||
vec4 rand = texelfetch_noise_tex(gl_FragCoord.xy);
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* -------------------- SCENE LIGHTS LIGHTING --------------------- */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
# ifdef CLOSURE_GLOSSY
|
||||
vec2 lut_uv = lut_coords_ltc(dot(N, V), roughness);
|
||||
vec4 ltc_mat = texture(utilTex, vec3(lut_uv, 0.0)).rgba;
|
||||
# endif
|
||||
|
||||
# ifdef CLOSURE_CLEARCOAT
|
||||
vec2 lut_uv_clear = lut_coords_ltc(dot(C_N, V), C_roughness);
|
||||
vec4 ltc_mat_clear = texture(utilTex, vec3(lut_uv_clear, 0.0)).rgba;
|
||||
vec3 out_spec_clear = vec3(0.0);
|
||||
# endif
|
||||
|
||||
float tracing_depth = gl_FragCoord.z;
|
||||
/* Constant bias (due to depth buffer precision) */
|
||||
/* Magic numbers for 24bits of precision.
|
||||
* From http://terathon.com/gdc07_lengyel.pdf (slide 26) */
|
||||
tracing_depth -= mix(2.4e-7, 4.8e-7, gl_FragCoord.z);
|
||||
/* Convert to view Z. */
|
||||
tracing_depth = get_view_z_from_depth(tracing_depth);
|
||||
|
||||
vec3 true_normal = normalize(cross(dFdx(viewPosition), dFdy(viewPosition)));
|
||||
|
||||
for (int i = 0; i < MAX_LIGHT && i < laNumLight; i++) {
|
||||
LightData ld = lights_data[i];
|
||||
|
||||
vec4 l_vector; /* Non-Normalized Light Vector with length in last component. */
|
||||
l_vector.xyz = ld.l_position - worldPosition;
|
||||
l_vector.w = length(l_vector.xyz);
|
||||
|
||||
float l_vis = light_visibility(ld,
|
||||
worldPosition,
|
||||
viewPosition,
|
||||
tracing_depth,
|
||||
true_normal,
|
||||
rand.x,
|
||||
use_contact_shadows,
|
||||
l_vector);
|
||||
|
||||
if (l_vis < 1e-8) {
|
||||
continue;
|
||||
}
|
||||
|
||||
vec3 l_color_vis = ld.l_color * l_vis;
|
||||
|
||||
# ifdef CLOSURE_DIFFUSE
|
||||
out_diff += l_color_vis * light_diffuse(ld, N, V, l_vector);
|
||||
# endif
|
||||
|
||||
# ifdef CLOSURE_GLOSSY
|
||||
out_spec += l_color_vis * light_specular(ld, ltc_mat, N, V, l_vector) * ld.l_spec;
|
||||
# endif
|
||||
|
||||
# ifdef CLOSURE_CLEARCOAT
|
||||
out_spec_clear += l_color_vis * light_specular(ld, ltc_mat_clear, C_N, V, l_vector) *
|
||||
ld.l_spec;
|
||||
# endif
|
||||
}
|
||||
|
||||
# ifdef CLOSURE_GLOSSY
|
||||
vec2 brdf_lut_lights = texture(utilTex, vec3(lut_uv, 1.0)).ba;
|
||||
out_spec *= F_brdf(f0, f90, brdf_lut_lights.xy);
|
||||
# endif
|
||||
|
||||
# ifdef CLOSURE_CLEARCOAT
|
||||
vec2 brdf_lut_lights_clear = texture(utilTex, vec3(lut_uv_clear, 1.0)).ba;
|
||||
out_spec_clear *= F_brdf(vec3(0.04), vec3(1.0), brdf_lut_lights_clear.xy);
|
||||
out_spec += out_spec_clear * C_intensity;
|
||||
# endif
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* ---------------- SPECULAR ENVIRONMENT LIGHTING ----------------- */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
/* Accumulate incoming light from all sources until accumulator is full. Then apply Occlusion and
|
||||
* BRDF. */
|
||||
# ifdef CLOSURE_GLOSSY
|
||||
vec4 spec_accum = vec4(0.0);
|
||||
# endif
|
||||
|
||||
# ifdef CLOSURE_CLEARCOAT
|
||||
vec4 C_spec_accum = vec4(0.0);
|
||||
# endif
|
||||
|
||||
# ifdef CLOSURE_REFRACTION
|
||||
vec4 refr_accum = vec4(0.0);
|
||||
# endif
|
||||
|
||||
# ifdef CLOSURE_GLOSSY
|
||||
/* ---------------------------- */
|
||||
/* Planar Reflections */
|
||||
/* ---------------------------- */
|
||||
|
||||
for (int i = 0; i < MAX_PLANAR && i < prbNumPlanar && spec_accum.a < 0.999; i++) {
|
||||
PlanarData pd = planars_data[i];
|
||||
|
||||
/* Fade on geometric normal. */
|
||||
float fade = probe_attenuation_planar(
|
||||
pd, worldPosition, (gl_FrontFacing) ? worldNormal : -worldNormal, roughness);
|
||||
|
||||
if (fade > 0.0) {
|
||||
if (!(ssrToggle && ssr_id == outputSsrId)) {
|
||||
vec3 spec = probe_evaluate_planar(float(i), pd, worldPosition, N, V, roughness, fade);
|
||||
accumulate_light(spec, fade, spec_accum);
|
||||
}
|
||||
|
||||
# ifdef CLOSURE_CLEARCOAT
|
||||
vec3 C_spec = probe_evaluate_planar(float(i), pd, worldPosition, C_N, V, C_roughness, fade);
|
||||
accumulate_light(C_spec, fade, C_spec_accum);
|
||||
# endif
|
||||
}
|
||||
}
|
||||
# endif
|
||||
|
||||
# ifdef CLOSURE_GLOSSY
|
||||
vec3 spec_dir = specular_dominant_dir(N, V, roughnessSquared);
|
||||
# endif
|
||||
|
||||
# ifdef CLOSURE_CLEARCOAT
|
||||
vec3 C_spec_dir = specular_dominant_dir(C_N, V, C_roughnessSquared);
|
||||
# endif
|
||||
|
||||
# ifdef CLOSURE_REFRACTION
|
||||
/* Refract the view vector using the depth heuristic.
|
||||
* Then later Refract a second time the already refracted
|
||||
* ray using the inverse ior. */
|
||||
float final_ior = (refractionDepth > 0.0) ? 1.0 / ior : ior;
|
||||
vec3 refr_V = (refractionDepth > 0.0) ? -refract(-V, N, final_ior) : V;
|
||||
vec3 refr_pos = (refractionDepth > 0.0) ?
|
||||
line_plane_intersect(
|
||||
worldPosition, refr_V, worldPosition - N * refractionDepth, N) :
|
||||
worldPosition;
|
||||
vec3 refr_dir = refraction_dominant_dir(N, refr_V, roughness, final_ior);
|
||||
# endif
|
||||
|
||||
# ifdef CLOSURE_REFRACTION
|
||||
/* ---------------------------- */
|
||||
/* Screen Space Refraction */
|
||||
/* ---------------------------- */
|
||||
# ifdef USE_REFRACTION
|
||||
if (ssrefractToggle && roughness < ssrMaxRoughness + 0.2) {
|
||||
/* Find approximated position of the 2nd refraction event. */
|
||||
vec3 refr_vpos = (refractionDepth > 0.0) ? transform_point(ViewMatrix, refr_pos) :
|
||||
viewPosition;
|
||||
vec4 trans = screen_space_refraction(refr_vpos, N, refr_V, final_ior, roughnessSquared, rand);
|
||||
trans.a *= smoothstep(ssrMaxRoughness + 0.2, ssrMaxRoughness, roughness);
|
||||
accumulate_light(trans.rgb, trans.a, refr_accum);
|
||||
}
|
||||
# endif
|
||||
|
||||
# endif
|
||||
|
||||
/* ---------------------------- */
|
||||
/* Specular probes */
|
||||
/* ---------------------------- */
|
||||
# if defined(CLOSURE_GLOSSY) || defined(CLOSURE_REFRACTION)
|
||||
|
||||
# if defined(CLOSURE_GLOSSY) && defined(CLOSURE_REFRACTION)
|
||||
# define GLASS_ACCUM 1
|
||||
# define ACCUM min(refr_accum.a, spec_accum.a)
|
||||
# elif defined(CLOSURE_REFRACTION)
|
||||
# define GLASS_ACCUM 0
|
||||
# define ACCUM refr_accum.a
|
||||
# else
|
||||
# define GLASS_ACCUM 0
|
||||
# define ACCUM spec_accum.a
|
||||
# endif
|
||||
|
||||
/* Starts at 1 because 0 is world probe */
|
||||
for (int i = 1; ACCUM < 0.999 && i < prbNumRenderCube && i < MAX_PROBE; i++) {
|
||||
float fade = probe_attenuation_cube(i, worldPosition);
|
||||
|
||||
if (fade > 0.0) {
|
||||
|
||||
# if GLASS_ACCUM
|
||||
if (spec_accum.a < 0.999) {
|
||||
# endif
|
||||
# ifdef CLOSURE_GLOSSY
|
||||
if (!(ssrToggle && ssr_id == outputSsrId)) {
|
||||
vec3 spec = probe_evaluate_cube(i, worldPosition, spec_dir, roughness);
|
||||
accumulate_light(spec, fade, spec_accum);
|
||||
}
|
||||
# endif
|
||||
|
||||
# ifdef CLOSURE_CLEARCOAT
|
||||
vec3 C_spec = probe_evaluate_cube(i, worldPosition, C_spec_dir, C_roughness);
|
||||
accumulate_light(C_spec, fade, C_spec_accum);
|
||||
# endif
|
||||
# if GLASS_ACCUM
|
||||
}
|
||||
# endif
|
||||
|
||||
# if GLASS_ACCUM
|
||||
if (refr_accum.a < 0.999) {
|
||||
# endif
|
||||
# ifdef CLOSURE_REFRACTION
|
||||
vec3 trans = probe_evaluate_cube(i, refr_pos, refr_dir, roughnessSquared);
|
||||
accumulate_light(trans, fade, refr_accum);
|
||||
# endif
|
||||
# if GLASS_ACCUM
|
||||
}
|
||||
# endif
|
||||
}
|
||||
}
|
||||
|
||||
# undef GLASS_ACCUM
|
||||
# undef ACCUM
|
||||
|
||||
/* ---------------------------- */
|
||||
/* World Probe */
|
||||
/* ---------------------------- */
|
||||
# ifdef CLOSURE_GLOSSY
|
||||
if (spec_accum.a < 0.999) {
|
||||
if (!(ssrToggle && ssr_id == outputSsrId)) {
|
||||
vec3 spec = probe_evaluate_world_spec(spec_dir, roughness);
|
||||
accumulate_light(spec, 1.0, spec_accum);
|
||||
}
|
||||
|
||||
# ifdef CLOSURE_CLEARCOAT
|
||||
vec3 C_spec = probe_evaluate_world_spec(C_spec_dir, C_roughness);
|
||||
accumulate_light(C_spec, 1.0, C_spec_accum);
|
||||
# endif
|
||||
}
|
||||
# endif
|
||||
|
||||
# ifdef CLOSURE_REFRACTION
|
||||
if (refr_accum.a < 0.999) {
|
||||
vec3 trans = probe_evaluate_world_spec(refr_dir, roughnessSquared);
|
||||
accumulate_light(trans, 1.0, refr_accum);
|
||||
}
|
||||
# endif
|
||||
# endif /* Specular probes */
|
||||
|
||||
/* ---------------------------- */
|
||||
/* Ambient Occlusion */
|
||||
/* ---------------------------- */
|
||||
# if defined(CLOSURE_GLOSSY) || defined(CLOSURE_DIFFUSE)
|
||||
if (!use_contact_shadows) {
|
||||
/* HACK: Fix for translucent BSDF. (see T65631) */
|
||||
N = -N;
|
||||
}
|
||||
vec3 bent_normal;
|
||||
float final_ao = occlusion_compute(N, viewPosition, ao, rand, bent_normal);
|
||||
if (!use_contact_shadows) {
|
||||
N = -N;
|
||||
/* Bypass bent normal. */
|
||||
bent_normal = N;
|
||||
}
|
||||
# endif
|
||||
|
||||
/* ---------------------------- */
|
||||
/* Specular Output */
|
||||
/* ---------------------------- */
|
||||
float NV = dot(N, V);
|
||||
# ifdef CLOSURE_GLOSSY
|
||||
vec2 uv = lut_coords(NV, roughness);
|
||||
vec2 brdf_lut = texture(utilTex, vec3(uv, 1.0)).rg;
|
||||
|
||||
/* This factor is outputted to be used by SSR in order
|
||||
* to match the intensity of the regular reflections. */
|
||||
ssr_spec = F_brdf(f0, f90, brdf_lut);
|
||||
float spec_occlu = specular_occlusion(NV, final_ao, roughness);
|
||||
|
||||
/* The SSR pass recompute the occlusion to not apply it to the SSR */
|
||||
if (ssrToggle && ssr_id == outputSsrId) {
|
||||
spec_occlu = 1.0;
|
||||
}
|
||||
|
||||
out_spec += spec_accum.rgb * ssr_spec * spec_occlu;
|
||||
# endif
|
||||
|
||||
# ifdef CLOSURE_REFRACTION
|
||||
float btdf = get_btdf_lut(NV, roughness, ior);
|
||||
|
||||
out_refr += refr_accum.rgb * btdf;
|
||||
|
||||
/* Global toggle for lightprobe baking. */
|
||||
out_refr *= float(specToggle);
|
||||
# endif
|
||||
|
||||
# ifdef CLOSURE_CLEARCOAT
|
||||
NV = dot(C_N, V);
|
||||
vec2 C_uv = lut_coords(NV, C_roughness);
|
||||
vec2 C_brdf_lut = texture(utilTex, vec3(C_uv, 1.0)).rg;
|
||||
vec3 C_fresnel = F_brdf(vec3(0.04), vec3(1.0), C_brdf_lut) *
|
||||
specular_occlusion(NV, final_ao, C_roughness);
|
||||
|
||||
out_spec += C_spec_accum.rgb * C_fresnel * C_intensity;
|
||||
# endif
|
||||
|
||||
# ifdef CLOSURE_GLOSSY
|
||||
/* Global toggle for lightprobe baking. */
|
||||
out_spec *= float(specToggle);
|
||||
# endif
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* ---------------- DIFFUSE ENVIRONMENT LIGHTING ------------------ */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
/* Accumulate light from all sources until accumulator is full. Then apply Occlusion and BRDF. */
|
||||
# ifdef CLOSURE_DIFFUSE
|
||||
vec4 diff_accum = vec4(0.0);
|
||||
|
||||
/* ---------------------------- */
|
||||
/* Irradiance Grids */
|
||||
/* ---------------------------- */
|
||||
/* Start at 1 because 0 is world irradiance */
|
||||
for (int i = 1; i < MAX_GRID && i < prbNumRenderGrid && diff_accum.a < 0.999; i++) {
|
||||
GridData gd = grids_data[i];
|
||||
|
||||
vec3 localpos;
|
||||
float fade = probe_attenuation_grid(gd, grids_data[i].localmat, worldPosition, localpos);
|
||||
|
||||
if (fade > 0.0) {
|
||||
vec3 diff = probe_evaluate_grid(gd, worldPosition, bent_normal, localpos);
|
||||
accumulate_light(diff, fade, diff_accum);
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------------------------- */
|
||||
/* World Diffuse */
|
||||
/* ---------------------------- */
|
||||
if (diff_accum.a < 0.999 && prbNumRenderGrid > 0) {
|
||||
vec3 diff = probe_evaluate_world_diff(bent_normal);
|
||||
accumulate_light(diff, 1.0, diff_accum);
|
||||
}
|
||||
|
||||
out_diff += diff_accum.rgb * gtao_multibounce(final_ao, albedo);
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Cleanup for next configuration */
|
||||
#undef CLOSURE_NAME
|
||||
|
||||
#ifdef CLOSURE_DIFFUSE
|
||||
# undef CLOSURE_DIFFUSE
|
||||
#endif
|
||||
|
||||
#ifdef CLOSURE_GLOSSY
|
||||
# undef CLOSURE_GLOSSY
|
||||
#endif
|
||||
|
||||
#ifdef CLOSURE_CLEARCOAT
|
||||
# undef CLOSURE_CLEARCOAT
|
||||
#endif
|
||||
|
||||
#ifdef CLOSURE_REFRACTION
|
||||
# undef CLOSURE_REFRACTION
|
||||
#endif
|
||||
|
||||
#ifdef CLOSURE_SUBSURFACE
|
||||
# undef CLOSURE_SUBSURFACE
|
||||
#endif
|
@@ -147,17 +147,27 @@ Closure closure_emission(vec3 rgb)
|
||||
|
||||
#ifndef VOLUMETRICS
|
||||
|
||||
/* Let radiance passthrough or replace it to get the BRDF and color
|
||||
* to applied to the SSR result. */
|
||||
vec3 closure_mask_ssr_radiance(vec3 radiance, float ssr_id)
|
||||
{
|
||||
return (ssrToggle && int(ssr_id) == outputSsrId) ? vec3(1.0) : radiance;
|
||||
}
|
||||
|
||||
void closure_load_ssr_data(
|
||||
vec3 ssr_spec, float roughness, vec3 N, vec3 viewVec, int ssr_id, inout Closure cl)
|
||||
vec3 ssr_radiance, float roughness, vec3 N, float ssr_id, inout Closure cl)
|
||||
{
|
||||
/* Still encode to avoid artifacts in the SSR pass. */
|
||||
vec3 vN = normalize(mat3(ViewMatrix) * N);
|
||||
cl.ssr_normal = normal_encode(vN, viewVec);
|
||||
cl.ssr_normal = normal_encode(vN, viewCameraVec);
|
||||
|
||||
if (ssr_id == outputSsrId) {
|
||||
cl.ssr_data = vec4(ssr_spec, roughness);
|
||||
if (ssrToggle && int(ssr_id) == outputSsrId) {
|
||||
cl.ssr_data = vec4(ssr_radiance, roughness);
|
||||
cl.flag |= CLOSURE_SSR_FLAG;
|
||||
}
|
||||
else {
|
||||
cl.radiance += ssr_radiance;
|
||||
}
|
||||
}
|
||||
|
||||
void closure_load_sss_data(
|
||||
@@ -169,13 +179,11 @@ void closure_load_sss_data(
|
||||
cl.sss_radius = radius;
|
||||
cl.sss_albedo = sss_albedo;
|
||||
cl.flag |= CLOSURE_SSS_FLAG;
|
||||
cl.radiance += render_pass_diffuse_mask(sss_albedo, vec3(0));
|
||||
/* Irradiance will be convolved by SSSS pass. Do not add to radiance. */
|
||||
sss_irradiance = vec3(0);
|
||||
}
|
||||
else
|
||||
# endif
|
||||
{
|
||||
cl.radiance += render_pass_diffuse_mask(sss_albedo, sss_irradiance * sss_albedo);
|
||||
}
|
||||
cl.radiance += render_pass_diffuse_mask(vec3(1), sss_irradiance) * sss_albedo;
|
||||
}
|
||||
|
||||
#endif
|
@@ -12,52 +12,91 @@ uniform sampler2DArray utilTex;
|
||||
|
||||
#define LUT_SIZE 64
|
||||
|
||||
#define texelfetch_noise_tex(coord) texelFetch(utilTex, ivec3(ivec2(coord) % LUT_SIZE, 2.0), 0)
|
||||
#define LTC_MAT_LAYER 0
|
||||
#define LTC_BRDF_LAYER 1
|
||||
#define BRDF_LUT_LAYER 1
|
||||
#define NOISE_LAYER 2
|
||||
#define LTC_DISK_LAYER 3 /* UNUSED */
|
||||
|
||||
/* Return texture coordinates to sample Surface LUT */
|
||||
vec2 lut_coords(float cosTheta, float roughness)
|
||||
/* Layers 4 to 20 are for BTDF Lut. */
|
||||
const float lut_btdf_layer_first = 4.0;
|
||||
const float lut_btdf_layer_count = 16.0;
|
||||
|
||||
#define texelfetch_noise_tex(coord) \
|
||||
texelFetch(utilTex, ivec3(ivec2(coord) % LUT_SIZE, NOISE_LAYER), 0)
|
||||
|
||||
/* Return texture coordinates to sample Surface LUT. */
|
||||
vec2 lut_coords(float cos_theta, float roughness)
|
||||
{
|
||||
float theta = acos(cosTheta);
|
||||
vec2 coords = vec2(roughness, theta / M_PI_2);
|
||||
vec2 coords = vec2(roughness, sqrt(1.0 - cos_theta));
|
||||
|
||||
/* scale and bias coordinates, for correct filtered lookup */
|
||||
return coords * (LUT_SIZE - 1.0) / LUT_SIZE + 0.5 / LUT_SIZE;
|
||||
}
|
||||
|
||||
vec2 lut_coords_ltc(float cosTheta, float roughness)
|
||||
/* Returns the GGX split-sum precomputed in LUT. */
|
||||
vec2 brdf_lut(float cos_theta, float roughness)
|
||||
{
|
||||
vec2 coords = vec2(roughness, sqrt(1.0 - cosTheta));
|
||||
|
||||
/* scale and bias coordinates, for correct filtered lookup */
|
||||
return coords * (LUT_SIZE - 1.0) / LUT_SIZE + 0.5 / LUT_SIZE;
|
||||
return textureLod(utilTex, vec3(lut_coords(cos_theta, roughness), BRDF_LUT_LAYER), 0.0).rg;
|
||||
}
|
||||
|
||||
float get_btdf_lut(float NV, float roughness, float ior)
|
||||
/* Return texture coordinates to sample Surface LUT. */
|
||||
vec3 lut_coords_btdf(float cos_theta, float roughness, float ior)
|
||||
{
|
||||
const vec3 lut_scale_bias_texel_size = vec3((LUT_SIZE - 1.0), 0.5, 1.5) / LUT_SIZE;
|
||||
/* ior is sin of critical angle. */
|
||||
float critical_cos = sqrt(1.0 - ior * ior);
|
||||
|
||||
vec3 coords;
|
||||
/* Try to compensate for the low resolution and interpolation error. */
|
||||
coords.x = (ior > 1.0) ? (0.9 + lut_scale_bias_texel_size.z) +
|
||||
(0.1 - lut_scale_bias_texel_size.z) * f0_from_ior(ior) :
|
||||
(0.9 + lut_scale_bias_texel_size.z) * ior * ior;
|
||||
coords.y = 1.0 - saturate(NV);
|
||||
coords.xy *= lut_scale_bias_texel_size.x;
|
||||
coords.xy += lut_scale_bias_texel_size.y;
|
||||
coords.x = sqr(ior);
|
||||
coords.y = cos_theta;
|
||||
coords.y -= critical_cos;
|
||||
coords.y /= (coords.y > 0.0) ? (1.0 - critical_cos) : critical_cos;
|
||||
coords.y = coords.y * 0.5 + 0.5;
|
||||
coords.z = roughness;
|
||||
|
||||
const float lut_lvl_ofs = 4.0; /* First texture lvl of roughness. */
|
||||
const float lut_lvl_scale = 16.0; /* How many lvl of roughness in the lut. */
|
||||
coords = saturate(coords);
|
||||
|
||||
float mip = roughness * lut_lvl_scale;
|
||||
float mip_floor = floor(mip);
|
||||
/* scale and bias coordinates, for correct filtered lookup */
|
||||
coords.xy = coords.xy * (LUT_SIZE - 1.0) / LUT_SIZE + 0.5 / LUT_SIZE;
|
||||
|
||||
coords.z = lut_lvl_ofs + mip_floor + 1.0;
|
||||
float btdf_high = textureLod(utilTex, coords, 0.0).r;
|
||||
return coords;
|
||||
}
|
||||
|
||||
coords.z -= 1.0;
|
||||
float btdf_low = textureLod(utilTex, coords, 0.0).r;
|
||||
/* Returns GGX BTDF in first component and fresnel in second. */
|
||||
vec2 btdf_lut(float cos_theta, float roughness, float ior)
|
||||
{
|
||||
if (ior <= 1e-5) {
|
||||
return vec2(0.0);
|
||||
}
|
||||
|
||||
float btdf = (ior == 1.0) ? 1.0 : mix(btdf_low, btdf_high, mip - coords.z);
|
||||
if (ior >= 1.0) {
|
||||
vec2 split_sum = brdf_lut(cos_theta, roughness);
|
||||
float f0 = f0_from_ior(ior);
|
||||
/* Baked IOR for GGX BRDF. */
|
||||
const float specular = 1.0;
|
||||
const float eta_brdf = (2.0 / (1.0 - sqrt(0.08 * specular))) - 1.0;
|
||||
/* Avoid harsh transition comming from ior == 1. */
|
||||
float f90 = fast_sqrt(saturate(f0 / (f0_from_ior(eta_brdf) * 0.25)));
|
||||
float fresnel = F_brdf_single_scatter(vec3(f0), vec3(f90), split_sum).r;
|
||||
/* Setting the BTDF to one is not really important since it is only used for multiscatter
|
||||
* and it's already quite close to ground truth. */
|
||||
float btdf = 1.0;
|
||||
return vec2(btdf, fresnel);
|
||||
}
|
||||
|
||||
vec3 coords = lut_coords_btdf(cos_theta, roughness, ior);
|
||||
|
||||
float layer = coords.z * lut_btdf_layer_count;
|
||||
float layer_floored = floor(layer);
|
||||
|
||||
coords.z = lut_btdf_layer_first + layer_floored;
|
||||
vec2 btdf_low = textureLod(utilTex, coords, 0.0).rg;
|
||||
|
||||
coords.z += 1.0;
|
||||
vec2 btdf_high = textureLod(utilTex, coords, 0.0).rg;
|
||||
|
||||
/* Manual trilinear interpolation. */
|
||||
vec2 btdf = mix(btdf_low, btdf_high, layer - layer_floored);
|
||||
|
||||
return btdf;
|
||||
}
|
||||
|
@@ -2,6 +2,8 @@
|
||||
#pragma BLENDER_REQUIRE(common_math_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(common_math_geom_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(closure_eval_glossy_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(closure_eval_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(raytrace_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(lightprobe_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(ssr_lib.glsl)
|
||||
@@ -170,7 +172,7 @@ void main()
|
||||
/* Importance sampling bias */
|
||||
rand.x = mix(rand.x, 0.0, ssrBrdfBias);
|
||||
|
||||
vec3 worldPosition = transform_point(ViewMatrixInverse, viewPosition);
|
||||
vec3 W = transform_point(ViewMatrixInverse, viewPosition);
|
||||
vec3 wN = transform_direction(ViewMatrixInverse, N);
|
||||
|
||||
vec3 T, B;
|
||||
@@ -180,12 +182,12 @@ void main()
|
||||
for (int i = 0; i < MAX_PLANAR && i < prbNumPlanar; i++) {
|
||||
PlanarData pd = planars_data[i];
|
||||
|
||||
float fade = probe_attenuation_planar(pd, worldPosition, wN, 0.0);
|
||||
float fade = probe_attenuation_planar(pd, W, wN, 0.0);
|
||||
|
||||
if (fade > 0.5) {
|
||||
/* Find view vector / reflection plane intersection. */
|
||||
/* TODO optimize, use view space for all. */
|
||||
vec3 tracePosition = line_plane_intersect(worldPosition, cameraVec, pd.pl_plane_eq);
|
||||
vec3 tracePosition = line_plane_intersect(W, cameraVec, pd.pl_plane_eq);
|
||||
tracePosition = transform_point(ViewMatrix, tracePosition);
|
||||
vec3 planeNormal = transform_direction(ViewMatrix, pd.pl_normal);
|
||||
|
||||
@@ -213,6 +215,8 @@ uniform sampler2D pdfBuffer;
|
||||
|
||||
uniform int neighborOffset;
|
||||
|
||||
in vec4 uvcoordsvar;
|
||||
|
||||
const ivec2 neighbors[32] = ivec2[32](ivec2(0, 0),
|
||||
ivec2(1, 1),
|
||||
ivec2(-2, 0),
|
||||
@@ -298,7 +302,7 @@ float get_sample_depth(vec2 hit_co, bool is_planar, float planar_index)
|
||||
|
||||
vec3 get_hit_vector(vec3 hit_pos,
|
||||
PlanarData pd,
|
||||
vec3 worldPosition,
|
||||
vec3 P,
|
||||
vec3 N,
|
||||
vec3 V,
|
||||
bool is_planar,
|
||||
@@ -309,7 +313,7 @@ vec3 get_hit_vector(vec3 hit_pos,
|
||||
|
||||
if (is_planar) {
|
||||
/* Reflect back the hit position to have it in non-reflected world space */
|
||||
vec3 trace_pos = line_plane_intersect(worldPosition, V, pd.pl_plane_eq);
|
||||
vec3 trace_pos = line_plane_intersect(P, V, pd.pl_plane_eq);
|
||||
hit_vec = hit_pos - trace_pos;
|
||||
hit_vec = reflect(hit_vec, pd.pl_normal);
|
||||
/* Modify here so mip texel alignment is correct. */
|
||||
@@ -317,8 +321,8 @@ vec3 get_hit_vector(vec3 hit_pos,
|
||||
}
|
||||
else {
|
||||
/* Find hit position in previous frame. */
|
||||
hit_co = get_reprojected_reflection(hit_pos, worldPosition, N);
|
||||
hit_vec = hit_pos - worldPosition;
|
||||
hit_co = get_reprojected_reflection(hit_pos, P, N);
|
||||
hit_vec = hit_pos - P;
|
||||
}
|
||||
|
||||
mask = screen_border_mask(hit_co);
|
||||
@@ -339,7 +343,7 @@ vec4 get_ssr_samples(vec4 hit_pdf,
|
||||
ivec4 hit_data[2],
|
||||
PlanarData pd,
|
||||
float planar_index,
|
||||
vec3 worldPosition,
|
||||
vec3 P,
|
||||
vec3 N,
|
||||
vec3 V,
|
||||
float roughnessSquared,
|
||||
@@ -379,14 +383,10 @@ vec4 get_ssr_samples(vec4 hit_pdf,
|
||||
|
||||
/* Get actual hit vector and hit coordinate (from last frame). */
|
||||
vec4 mask = vec4(1.0);
|
||||
hit_pos[0] = get_hit_vector(
|
||||
hit_pos[0], pd, worldPosition, N, V, is_planar.x, hit_co[0].xy, mask.x);
|
||||
hit_pos[1] = get_hit_vector(
|
||||
hit_pos[1], pd, worldPosition, N, V, is_planar.y, hit_co[0].zw, mask.y);
|
||||
hit_pos[2] = get_hit_vector(
|
||||
hit_pos[2], pd, worldPosition, N, V, is_planar.z, hit_co[1].xy, mask.z);
|
||||
hit_pos[3] = get_hit_vector(
|
||||
hit_pos[3], pd, worldPosition, N, V, is_planar.w, hit_co[1].zw, mask.w);
|
||||
hit_pos[0] = get_hit_vector(hit_pos[0], pd, P, N, V, is_planar.x, hit_co[0].xy, mask.x);
|
||||
hit_pos[1] = get_hit_vector(hit_pos[1], pd, P, N, V, is_planar.y, hit_co[0].zw, mask.y);
|
||||
hit_pos[2] = get_hit_vector(hit_pos[2], pd, P, N, V, is_planar.z, hit_co[1].xy, mask.z);
|
||||
hit_pos[3] = get_hit_vector(hit_pos[3], pd, P, N, V, is_planar.w, hit_co[1].zw, mask.w);
|
||||
|
||||
vec4 hit_dist;
|
||||
hit_dist.x = length(hit_pos[0]);
|
||||
@@ -476,47 +476,30 @@ vec4 get_ssr_samples(vec4 hit_pdf,
|
||||
return accum;
|
||||
}
|
||||
|
||||
void main()
|
||||
void raytrace_resolve(ClosureInputGlossy cl_in,
|
||||
inout ClosureEvalGlossy cl_eval,
|
||||
inout ClosureEvalCommon cl_common,
|
||||
inout ClosureOutputGlossy cl_out)
|
||||
{
|
||||
ivec2 fullres_texel = ivec2(gl_FragCoord.xy);
|
||||
# ifdef FULLRES
|
||||
ivec2 halfres_texel = fullres_texel;
|
||||
ivec2 texel = ivec2(gl_FragCoord.xy);
|
||||
# else
|
||||
ivec2 halfres_texel = ivec2(gl_FragCoord.xy / 2.0);
|
||||
ivec2 texel = ivec2(gl_FragCoord.xy / 2.0);
|
||||
# endif
|
||||
vec2 uvs = gl_FragCoord.xy / vec2(textureSize(depthBuffer, 0));
|
||||
|
||||
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 vN = normal_decode(texelFetch(normalBuffer, fullres_texel, 0).rg, viewCameraVec);
|
||||
vec3 N = transform_direction(ViewMatrixInverse, vN);
|
||||
vec4 speccol_roughness = texelFetch(specroughBuffer, fullres_texel, 0).rgba;
|
||||
vec3 V = cl_common.V;
|
||||
vec3 N = cl_in.N;
|
||||
vec3 P = cl_common.P;
|
||||
|
||||
/* 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);
|
||||
float roughness = cl_in.roughness;
|
||||
float roughnessSquared = max(1e-3, sqr(roughness));
|
||||
|
||||
/* 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;
|
||||
vec2 source_uvs = project_point(pastViewProjectionMatrix, P).xy * 0.5 + 0.5;
|
||||
|
||||
vec4 ssr_accum = vec4(0.0);
|
||||
float weight_acc = 0.0;
|
||||
@@ -525,16 +508,16 @@ void main()
|
||||
/* TODO optimize with textureGather */
|
||||
/* Doing these fetches early to hide latency. */
|
||||
vec4 hit_pdf;
|
||||
hit_pdf.x = texelFetch(pdfBuffer, halfres_texel + neighbors[0 + neighborOffset], 0).r;
|
||||
hit_pdf.y = texelFetch(pdfBuffer, halfres_texel + neighbors[1 + neighborOffset], 0).r;
|
||||
hit_pdf.z = texelFetch(pdfBuffer, halfres_texel + neighbors[2 + neighborOffset], 0).r;
|
||||
hit_pdf.w = texelFetch(pdfBuffer, halfres_texel + neighbors[3 + neighborOffset], 0).r;
|
||||
hit_pdf.x = texelFetch(pdfBuffer, texel + neighbors[0 + neighborOffset], 0).r;
|
||||
hit_pdf.y = texelFetch(pdfBuffer, texel + neighbors[1 + neighborOffset], 0).r;
|
||||
hit_pdf.z = texelFetch(pdfBuffer, texel + neighbors[2 + neighborOffset], 0).r;
|
||||
hit_pdf.w = texelFetch(pdfBuffer, texel + neighbors[3 + neighborOffset], 0).r;
|
||||
|
||||
ivec4 hit_data[2];
|
||||
hit_data[0].xy = texelFetch(hitBuffer, halfres_texel + neighbors[0 + neighborOffset], 0).rg;
|
||||
hit_data[0].zw = texelFetch(hitBuffer, halfres_texel + neighbors[1 + neighborOffset], 0).rg;
|
||||
hit_data[1].xy = texelFetch(hitBuffer, halfres_texel + neighbors[2 + neighborOffset], 0).rg;
|
||||
hit_data[1].zw = texelFetch(hitBuffer, halfres_texel + neighbors[3 + neighborOffset], 0).rg;
|
||||
hit_data[0].xy = texelFetch(hitBuffer, texel + neighbors[0 + neighborOffset], 0).rg;
|
||||
hit_data[0].zw = texelFetch(hitBuffer, texel + neighbors[1 + neighborOffset], 0).rg;
|
||||
hit_data[1].xy = texelFetch(hitBuffer, texel + neighbors[2 + neighborOffset], 0).rg;
|
||||
hit_data[1].zw = texelFetch(hitBuffer, texel + neighbors[3 + neighborOffset], 0).rg;
|
||||
|
||||
/* Find Planar Reflections affecting this pixel */
|
||||
PlanarData pd;
|
||||
@@ -542,7 +525,7 @@ void main()
|
||||
for (int i = 0; i < MAX_PLANAR && i < prbNumPlanar; i++) {
|
||||
pd = planars_data[i];
|
||||
|
||||
float fade = probe_attenuation_planar(pd, worldPosition, N, 0.0);
|
||||
float fade = probe_attenuation_planar(pd, P, N, 0.0);
|
||||
|
||||
if (fade > 0.5) {
|
||||
planar_index = float(i);
|
||||
@@ -554,7 +537,7 @@ void main()
|
||||
hit_data,
|
||||
pd,
|
||||
planar_index,
|
||||
worldPosition,
|
||||
P,
|
||||
N,
|
||||
V,
|
||||
roughnessSquared,
|
||||
@@ -564,19 +547,51 @@ void main()
|
||||
}
|
||||
|
||||
/* Compute SSR contribution */
|
||||
if (weight_acc > 0.0) {
|
||||
ssr_accum /= weight_acc;
|
||||
/* fade between 0.5 and 1.0 roughness */
|
||||
ssr_accum.a *= smoothstep(ssrMaxRoughness + 0.2, ssrMaxRoughness, roughness);
|
||||
accumulate_light(ssr_accum.rgb, ssr_accum.a, spec_accum);
|
||||
ssr_accum *= (weight_acc == 0.0) ? 0.0 : (1.0 / weight_acc);
|
||||
/* fade between 0.5 and 1.0 roughness */
|
||||
ssr_accum.a *= smoothstep(ssrMaxRoughness + 0.2, ssrMaxRoughness, roughness);
|
||||
|
||||
cl_eval.raytrace_radiance = ssr_accum.rgb * ssr_accum.a;
|
||||
cl_common.specular_accum -= ssr_accum.a;
|
||||
}
|
||||
|
||||
CLOSURE_EVAL_FUNCTION_DECLARE_1(ssr_resolve, Glossy)
|
||||
|
||||
void main()
|
||||
{
|
||||
ivec2 texel = ivec2(gl_FragCoord.xy);
|
||||
float depth = texelFetch(depthBuffer, texel, 0).r;
|
||||
|
||||
if (depth == 1.0) {
|
||||
discard;
|
||||
}
|
||||
|
||||
/* If SSR contribution is not 1.0, blend with cubemaps */
|
||||
if (spec_accum.a < 1.0) {
|
||||
fallback_cubemap(N, V, worldPosition, viewPosition, roughness, roughnessSquared, spec_accum);
|
||||
vec4 speccol_roughness = texelFetch(specroughBuffer, texel, 0).rgba;
|
||||
vec3 brdf = speccol_roughness.rgb;
|
||||
float roughness = speccol_roughness.a;
|
||||
|
||||
if (max_v3(brdf) <= 0.0) {
|
||||
discard;
|
||||
}
|
||||
|
||||
fragColor = vec4(spec_accum.rgb * speccol_roughness.rgb, 1.0);
|
||||
viewPosition = get_view_space_from_depth(uvcoordsvar.xy, depth);
|
||||
worldPosition = transform_point(ViewMatrixInverse, viewPosition);
|
||||
|
||||
vec2 normal_encoded = texelFetch(normalBuffer, texel, 0).rg;
|
||||
viewNormal = normal_decode(normal_encoded, viewCameraVec);
|
||||
worldNormal = transform_direction(ViewMatrixInverse, viewNormal);
|
||||
|
||||
CLOSURE_VARS_DECLARE_1(Glossy);
|
||||
|
||||
in_Glossy_0.N = worldNormal;
|
||||
in_Glossy_0.roughness = roughness;
|
||||
|
||||
/* Do a full deferred evaluation of the glossy BSDF. The only difference is that we inject the
|
||||
* SSR resolve before the cubemap iter. BRDF term is already computed during main pass and is
|
||||
* passed as specular color. */
|
||||
CLOSURE_EVAL_FUNCTION_1(ssr_resolve, Glossy);
|
||||
|
||||
fragColor = vec4(out_Glossy_0.radiance * brdf, 1.0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -9,6 +9,9 @@ uniform float lodFactor;
|
||||
uniform float lodMax;
|
||||
uniform float intensityFac;
|
||||
|
||||
uniform float sampleCount;
|
||||
uniform float invSampleCount;
|
||||
|
||||
in vec3 worldPosition;
|
||||
|
||||
out vec4 FragColor;
|
||||
@@ -144,7 +147,7 @@ void main()
|
||||
float weight = 0.0;
|
||||
vec3 out_radiance = vec3(0.0);
|
||||
for (float i = 0; i < sampleCount; i++) {
|
||||
vec3 L = sample_hemisphere(i, N, T, B); /* Microfacet normal */
|
||||
vec3 L = sample_hemisphere(i, invSampleCount, N, T, B); /* Microfacet normal */
|
||||
float NL = dot(N, L);
|
||||
|
||||
if (NL > 0.0) {
|
||||
|
@@ -11,6 +11,9 @@ uniform float paddingSize;
|
||||
uniform float intensityFac;
|
||||
uniform float fireflyFactor;
|
||||
|
||||
uniform float sampleCount;
|
||||
uniform float invSampleCount;
|
||||
|
||||
in vec3 worldPosition;
|
||||
|
||||
out vec4 FragColor;
|
||||
@@ -45,15 +48,11 @@ void main()
|
||||
|
||||
make_orthonormal_basis(N, T, B); /* Generate tangent space */
|
||||
|
||||
/* Noise to dither the samples */
|
||||
/* Note : ghosting is better looking than noise. */
|
||||
// setup_noise();
|
||||
|
||||
/* Integrating Envmap */
|
||||
float weight = 0.0;
|
||||
vec3 out_radiance = vec3(0.0);
|
||||
for (float i = 0; i < sampleCount; i++) {
|
||||
vec3 H = sample_ggx(i, roughnessSquared, N, T, B); /* Microfacet normal */
|
||||
vec3 H = sample_ggx(i, invSampleCount, roughnessSquared, N, T, B); /* Microfacet normal */
|
||||
vec3 L = -reflect(V, H);
|
||||
float NL = dot(N, L);
|
||||
|
||||
|
@@ -13,6 +13,9 @@ uniform float farClip;
|
||||
uniform float visibilityRange;
|
||||
uniform float visibilityBlur;
|
||||
|
||||
uniform float sampleCount;
|
||||
uniform float invSampleCount;
|
||||
|
||||
out vec4 FragColor;
|
||||
|
||||
vec3 octahedral_to_cubemap_proj(vec2 co)
|
||||
@@ -77,7 +80,7 @@ void main()
|
||||
vec2 accum = vec2(0.0);
|
||||
|
||||
for (float i = 0; i < sampleCount; i++) {
|
||||
vec3 sample = sample_cone(i, M_PI_2 * visibilityBlur, cos, T, B);
|
||||
vec3 sample = sample_cone(i, invSampleCount, M_PI_2 * visibilityBlur, cos, T, B);
|
||||
float depth = texture(probeDepth, sample).r;
|
||||
depth = get_world_distance(depth, sample);
|
||||
accum += vec2(depth, depth * depth);
|
||||
|
@@ -137,9 +137,9 @@ float probe_attenuation_planar(PlanarData pd, vec3 W, vec3 N, float roughness)
|
||||
return fac;
|
||||
}
|
||||
|
||||
float probe_attenuation_grid(GridData gd, mat4 localmat, vec3 W, out vec3 localpos)
|
||||
float probe_attenuation_grid(GridData gd, vec3 W, out vec3 localpos)
|
||||
{
|
||||
localpos = transform_point(localmat, W);
|
||||
localpos = transform_point(gd.localmat, W);
|
||||
vec3 pos_to_edge = max(vec3(0.0), abs(localpos) - 1.0);
|
||||
float fade = length(pos_to_edge);
|
||||
return saturate(-fade * gd.g_atten_scale + gd.g_atten_bias);
|
||||
@@ -167,7 +167,7 @@ vec3 probe_evaluate_cube(int pd_id, vec3 W, vec3 R, float roughness)
|
||||
* http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf
|
||||
*/
|
||||
float original_roughness = roughness;
|
||||
float linear_roughness = sqrt(roughness);
|
||||
float linear_roughness = fast_sqrt(roughness);
|
||||
float distance_roughness = saturate(dist * linear_roughness / length(intersection));
|
||||
linear_roughness = mix(distance_roughness, linear_roughness, linear_roughness);
|
||||
roughness = linear_roughness * linear_roughness;
|
||||
@@ -175,16 +175,17 @@ vec3 probe_evaluate_cube(int pd_id, vec3 W, vec3 R, float roughness)
|
||||
float fac = saturate(original_roughness * 2.0 - 1.0);
|
||||
R = mix(intersection, R, fac * fac);
|
||||
|
||||
return textureLod_cubemapArray(probeCubes, vec4(R, float(pd_id)), roughness * prbLodCubeMax).rgb;
|
||||
float lod = linear_roughness * prbLodCubeMax;
|
||||
return textureLod_cubemapArray(probeCubes, vec4(R, float(pd_id)), lod).rgb;
|
||||
}
|
||||
|
||||
vec3 probe_evaluate_world_spec(vec3 R, float roughness)
|
||||
{
|
||||
return textureLod_cubemapArray(probeCubes, vec4(R, 0.0), roughness * prbLodCubeMax).rgb;
|
||||
float lod = fast_sqrt(roughness) * prbLodCubeMax;
|
||||
return textureLod_cubemapArray(probeCubes, vec4(R, 0.0), lod).rgb;
|
||||
}
|
||||
|
||||
vec3 probe_evaluate_planar(
|
||||
float id, PlanarData pd, vec3 W, vec3 N, vec3 V, float roughness, inout float fade)
|
||||
vec3 probe_evaluate_planar(int id, PlanarData pd, vec3 W, vec3 N, vec3 V, float roughness)
|
||||
{
|
||||
/* Find view vector / reflection plane intersection. */
|
||||
vec3 point_on_plane = line_plane_intersect(W, V, pd.pl_plane_eq);
|
||||
@@ -226,7 +227,7 @@ void fallback_cubemap(vec3 N,
|
||||
#ifdef SSR_AO
|
||||
vec4 rand = texelfetch_noise_tex(gl_FragCoord.xy);
|
||||
vec3 bent_normal;
|
||||
float final_ao = occlusion_compute(N, viewPosition, 1.0, rand, bent_normal);
|
||||
float final_ao = occlusion_compute(N, viewPosition, rand, bent_normal);
|
||||
final_ao = specular_occlusion(dot(N, V), final_ao, roughness);
|
||||
#else
|
||||
const float final_ao = 1.0;
|
||||
|
@@ -252,32 +252,29 @@ float light_attenuation(LightData ld, vec4 l_vector)
|
||||
return vis;
|
||||
}
|
||||
|
||||
float light_shadowing(LightData ld,
|
||||
vec3 W,
|
||||
#ifndef VOLUMETRICS
|
||||
vec3 viewPosition,
|
||||
float tracing_depth,
|
||||
vec3 true_normal,
|
||||
float rand_x,
|
||||
const bool use_contact_shadows,
|
||||
#endif
|
||||
float vis)
|
||||
float light_shadowing(LightData ld, vec3 W, float vis)
|
||||
{
|
||||
#if !defined(VOLUMETRICS) || defined(VOLUME_SHADOW)
|
||||
/* shadowing */
|
||||
if (ld.l_shadowid >= 0.0 && vis > 0.001) {
|
||||
|
||||
if (ld.l_type == SUN) {
|
||||
vis *= sample_cascade_shadow(int(ld.l_shadowid), W);
|
||||
}
|
||||
else {
|
||||
vis *= sample_cube_shadow(int(ld.l_shadowid), W);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return vis;
|
||||
}
|
||||
|
||||
# ifndef VOLUMETRICS
|
||||
#ifndef VOLUMETRICS
|
||||
float light_contact_shadows(
|
||||
LightData ld, vec3 P, vec3 vP, float tracing_depth, vec3 vNg, float rand_x, float vis)
|
||||
{
|
||||
if (ld.l_shadowid >= 0.0 && vis > 0.001) {
|
||||
ShadowData sd = shadows_data[int(ld.l_shadowid)];
|
||||
/* Only compute if not already in shadow. */
|
||||
if (use_contact_shadows && sd.sh_contact_dist > 0.0 && vis > 1e-8) {
|
||||
if (sd.sh_contact_dist > 0.0) {
|
||||
/* Contact Shadows. */
|
||||
vec3 ray_ori, ray_dir;
|
||||
float trace_distance;
|
||||
@@ -287,54 +284,34 @@ float light_shadowing(LightData ld,
|
||||
ray_dir = shadows_cascade_data[int(sd.sh_data_index)].sh_shadow_vec * trace_distance;
|
||||
}
|
||||
else {
|
||||
ray_dir = shadows_cube_data[int(sd.sh_data_index)].position.xyz - W;
|
||||
ray_dir = shadows_cube_data[int(sd.sh_data_index)].position.xyz - P;
|
||||
float len = length(ray_dir);
|
||||
trace_distance = min(sd.sh_contact_dist, len);
|
||||
ray_dir *= trace_distance / len;
|
||||
}
|
||||
|
||||
ray_dir = transform_direction(ViewMatrix, ray_dir);
|
||||
ray_ori = vec3(viewPosition.xy, tracing_depth) + true_normal * sd.sh_contact_offset;
|
||||
ray_ori = vec3(vP.xy, tracing_depth) + vNg * sd.sh_contact_offset;
|
||||
|
||||
vec3 hit_pos = raycast(
|
||||
-1, ray_ori, ray_dir, sd.sh_contact_thickness, rand_x, 0.1, 0.001, false);
|
||||
|
||||
if (hit_pos.z > 0.0) {
|
||||
hit_pos = get_view_space_from_depth(hit_pos.xy, hit_pos.z);
|
||||
float hit_dist = distance(viewPosition, hit_pos);
|
||||
float hit_dist = distance(vP, hit_pos);
|
||||
float dist_ratio = hit_dist / trace_distance;
|
||||
return vis * saturate(dist_ratio * 3.0 - 2.0);
|
||||
return saturate(dist_ratio * 3.0 - 2.0);
|
||||
}
|
||||
}
|
||||
# endif /* VOLUMETRICS */
|
||||
}
|
||||
#endif
|
||||
|
||||
return vis;
|
||||
return 1.0;
|
||||
}
|
||||
#endif /* VOLUMETRICS */
|
||||
|
||||
float light_visibility(LightData ld,
|
||||
vec3 W,
|
||||
#ifndef VOLUMETRICS
|
||||
vec3 viewPosition,
|
||||
float tracing_depth,
|
||||
vec3 true_normal,
|
||||
float rand_x,
|
||||
const bool use_contact_shadows,
|
||||
#endif
|
||||
vec4 l_vector)
|
||||
float light_visibility(LightData ld, vec3 W, vec4 l_vector)
|
||||
{
|
||||
float l_atten = light_attenuation(ld, l_vector);
|
||||
return light_shadowing(ld,
|
||||
W,
|
||||
#ifndef VOLUMETRICS
|
||||
viewPosition,
|
||||
tracing_depth,
|
||||
true_normal,
|
||||
rand_x,
|
||||
use_contact_shadows,
|
||||
#endif
|
||||
l_atten);
|
||||
return light_shadowing(ld, W, l_atten);
|
||||
}
|
||||
|
||||
float light_diffuse(LightData ld, vec3 N, vec3 V, vec4 l_vector)
|
||||
|
@@ -5,8 +5,12 @@
|
||||
|
||||
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(common_uniforms_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(closure_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(closure_lit_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(closure_type_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(closure_eval_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(closure_eval_diffuse_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(closure_eval_glossy_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(closure_eval_translucent_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(closure_eval_refraction_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(surface_lib.glsl)
|
||||
|
||||
#ifdef USE_ALPHA_HASH
|
||||
|
@@ -39,7 +39,7 @@ void main()
|
||||
vec3 viewPosition = get_view_space_from_depth(uvs, depth);
|
||||
vec3 worldPosition = transform_point(ViewMatrixInverse, viewPosition);
|
||||
|
||||
vec3 true_normal = normalize(cross(dFdx(viewPosition), dFdy(viewPosition)));
|
||||
vec3 true_normal = safe_normalize(cross(dFdx(viewPosition), dFdy(viewPosition)));
|
||||
|
||||
for (int i = 0; i < MAX_LIGHT && i < laNumLight; i++) {
|
||||
LightData ld = lights_data[i];
|
||||
@@ -48,8 +48,10 @@ void main()
|
||||
l_vector.xyz = ld.l_position - worldPosition;
|
||||
l_vector.w = length(l_vector.xyz);
|
||||
|
||||
float l_vis = light_shadowing(
|
||||
ld, worldPosition, viewPosition, tracing_depth, true_normal, rand.x, true, 1.0);
|
||||
float l_vis = light_shadowing(ld, worldPosition, 1.0);
|
||||
|
||||
l_vis *= light_contact_shadows(
|
||||
ld, worldPosition, viewPosition, tracing_depth, true_normal, rand.x, 1.0);
|
||||
|
||||
accum_light += l_vis;
|
||||
}
|
||||
|
@@ -3,8 +3,13 @@
|
||||
#pragma BLENDER_REQUIRE(common_hair_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl)
|
||||
|
||||
#pragma BLENDER_REQUIRE(closure_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(closure_lit_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(closure_type_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(closure_eval_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(closure_eval_diffuse_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(closure_eval_glossy_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(closure_eval_translucent_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(closure_eval_refraction_lib.glsl)
|
||||
|
||||
#pragma BLENDER_REQUIRE(surface_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(volumetric_lib.glsl)
|
||||
|
||||
|
@@ -13,7 +13,15 @@ uniform float refractionDepth;
|
||||
vec3 worldNormal; \
|
||||
vec3 viewNormal;
|
||||
|
||||
#ifdef GPU_GEOMETRY_SHADER
|
||||
#if defined(STEP_RESOLVE) || defined(STEP_RAYTRACE)
|
||||
/* SSR will set these global variables itself.
|
||||
* Also make false positive compiler warnings disapear by setting values. */
|
||||
vec3 worldPosition = vec3(0);
|
||||
vec3 viewPosition = vec3(0);
|
||||
vec3 worldNormal = vec3(0);
|
||||
vec3 viewNormal = vec3(0);
|
||||
|
||||
#elif defined(GPU_GEOMETRY_SHADER)
|
||||
in ShaderStageInterface{SURFACE_INTERFACE} dataIn[];
|
||||
|
||||
out ShaderStageInterface{SURFACE_INTERFACE} dataOut;
|
||||
@@ -24,7 +32,7 @@ out ShaderStageInterface{SURFACE_INTERFACE} dataOut;
|
||||
dataOut.worldNormal = dataIn[vert].worldNormal; \
|
||||
dataOut.viewNormal = dataIn[vert].viewNormal;
|
||||
|
||||
#else
|
||||
#else /* GPU_VERTEX_SHADER || GPU_FRAGMENT_SHADER*/
|
||||
|
||||
IN_OUT ShaderStageInterface{SURFACE_INTERFACE};
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
|
||||
#pragma BLENDER_REQUIRE(volumetric_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(closure_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(closure_type_lib.glsl)
|
||||
|
||||
/* Based on Frosbite Unified Volumetric.
|
||||
* https://www.ea.com/frostbite/news/physically-based-unified-volumetric-rendering-in-frostbite */
|
||||
|
@@ -72,6 +72,9 @@ float sum(vec4 v) { return dot(vec4(1.0), v); }
|
||||
float avg(vec2 v) { return dot(vec2(1.0 / 2.0), v); }
|
||||
float avg(vec3 v) { return dot(vec3(1.0 / 3.0), v); }
|
||||
float avg(vec4 v) { return dot(vec4(1.0 / 4.0), v); }
|
||||
|
||||
float sqr(float v) { return v * v; }
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
#define saturate(a) clamp(a, 0.0, 1.0)
|
||||
@@ -93,6 +96,15 @@ float len_squared(vec3 a)
|
||||
return dot(a, a);
|
||||
}
|
||||
|
||||
vec3 safe_normalize(vec3 v)
|
||||
{
|
||||
float len = length(v);
|
||||
if (isnan(len) || len == 0.0) {
|
||||
return vec3(1.0, 0.0, 0.0);
|
||||
}
|
||||
return v / len;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
@@ -755,6 +755,10 @@ static void gpu_parse_material_library(GHash *hash, GPUMaterialLibrary *library)
|
||||
|
||||
/* get parameters */
|
||||
while (*code && *code != ')') {
|
||||
if (BLI_str_startswith(code, "const ")) {
|
||||
code = gpu_str_skip_token(code, NULL, 0);
|
||||
}
|
||||
|
||||
/* test if it's an input or output */
|
||||
qual = FUNCTION_QUAL_IN;
|
||||
if (BLI_str_startswith(code, "out ")) {
|
||||
|
@@ -4,7 +4,7 @@ void node_ambient_occlusion(
|
||||
{
|
||||
vec3 bent_normal;
|
||||
vec4 rand = texelfetch_noise_tex(gl_FragCoord.xy);
|
||||
result_ao = occlusion_compute(normalize(normal), viewPosition, 1.0, rand, bent_normal);
|
||||
result_ao = occlusion_compute(normalize(normal), viewPosition, rand, bent_normal);
|
||||
result_color = result_ao * color;
|
||||
}
|
||||
#else
|
||||
|
@@ -1,12 +1,27 @@
|
||||
#ifndef VOLUMETRICS
|
||||
|
||||
CLOSURE_EVAL_FUNCTION_DECLARE_1(node_bsdf_diffuse, Diffuse)
|
||||
|
||||
void node_bsdf_diffuse(vec4 color, float roughness, vec3 N, out Closure result)
|
||||
{
|
||||
N = normalize(N);
|
||||
CLOSURE_VARS_DECLARE_1(Diffuse);
|
||||
|
||||
in_Diffuse_0.N = N; /* Normalized during eval. */
|
||||
in_Diffuse_0.albedo = color.rgb;
|
||||
|
||||
CLOSURE_EVAL_FUNCTION_1(node_bsdf_diffuse, Diffuse);
|
||||
|
||||
result = CLOSURE_DEFAULT;
|
||||
eevee_closure_diffuse(N, color.rgb, 1.0, true, result.radiance);
|
||||
result.radiance = render_pass_diffuse_mask(color.rgb, result.radiance * color.rgb);
|
||||
closure_load_ssr_data(vec3(0.0), 0.0, N, viewCameraVec, -1, result);
|
||||
|
||||
out_Diffuse_0.radiance = render_pass_diffuse_mask(vec3(1.0), out_Diffuse_0.radiance);
|
||||
out_Diffuse_0.radiance *= color.rgb;
|
||||
|
||||
result.radiance = out_Diffuse_0.radiance;
|
||||
|
||||
/* TODO(fclem) Try to not use this. */
|
||||
closure_load_ssr_data(vec3(0.0), 0.0, in_Diffuse_0.N, -1, result);
|
||||
}
|
||||
|
||||
#else
|
||||
/* Stub diffuse because it is not compatible with volumetrics. */
|
||||
# define node_bsdf_diffuse(a, b, c, d) (d = CLOSURE_DEFAULT)
|
||||
|
@@ -1,4 +1,7 @@
|
||||
#ifndef VOLUMETRICS
|
||||
|
||||
CLOSURE_EVAL_FUNCTION_DECLARE_3(node_eevee_specular, Diffuse, Glossy, Glossy)
|
||||
|
||||
void node_eevee_specular(vec4 diffuse,
|
||||
vec4 specular,
|
||||
float roughness,
|
||||
@@ -12,34 +15,63 @@ void node_eevee_specular(vec4 diffuse,
|
||||
float ssr_id,
|
||||
out Closure result)
|
||||
{
|
||||
normal = normalize(normal);
|
||||
CLOSURE_VARS_DECLARE_3(Diffuse, Glossy, Glossy);
|
||||
|
||||
vec3 out_diff, out_spec, ssr_spec;
|
||||
eevee_closure_default_clearcoat(normal,
|
||||
diffuse.rgb,
|
||||
specular.rgb,
|
||||
vec3(1.0),
|
||||
int(ssr_id),
|
||||
roughness,
|
||||
clearcoat_normal,
|
||||
clearcoat * 0.25,
|
||||
clearcoat_roughness,
|
||||
occlusion,
|
||||
true,
|
||||
out_diff,
|
||||
out_spec,
|
||||
ssr_spec);
|
||||
in_common.occlusion = occlusion;
|
||||
|
||||
in_Diffuse_0.N = normal; /* Normalized during eval. */
|
||||
in_Diffuse_0.albedo = diffuse.rgb;
|
||||
|
||||
in_Glossy_1.N = normal; /* Normalized during eval. */
|
||||
in_Glossy_1.roughness = roughness;
|
||||
|
||||
in_Glossy_2.N = clearcoat_normal; /* Normalized during eval. */
|
||||
in_Glossy_2.roughness = clearcoat_roughness;
|
||||
|
||||
CLOSURE_EVAL_FUNCTION_3(node_eevee_specular, Diffuse, Glossy, Glossy);
|
||||
|
||||
float alpha = 1.0 - transp;
|
||||
result = CLOSURE_DEFAULT;
|
||||
result.radiance = render_pass_diffuse_mask(diffuse.rgb, out_diff * diffuse.rgb);
|
||||
result.radiance += render_pass_glossy_mask(vec3(1.0), out_spec);
|
||||
result.radiance += render_pass_emission_mask(emissive.rgb);
|
||||
result.radiance *= alpha;
|
||||
result.transmittance = vec3(transp);
|
||||
|
||||
closure_load_ssr_data(ssr_spec * alpha, roughness, normal, viewCameraVec, int(ssr_id), result);
|
||||
{
|
||||
/* Diffuse. */
|
||||
out_Diffuse_0.radiance = render_pass_diffuse_mask(vec3(1), out_Diffuse_0.radiance);
|
||||
out_Diffuse_0.radiance *= in_Diffuse_0.albedo;
|
||||
result += out_Diffuse_0.radiance;
|
||||
}
|
||||
{
|
||||
/* Glossy. */
|
||||
float NV = dot(in_Glossy_1.N, cameraVec);
|
||||
vec2 split_sum = brdf_lut(NV, in_Glossy_1.roughness);
|
||||
vec3 brdf = F_brdf_single_scatter(specular.rgb, vec3(1.0), split_sum);
|
||||
|
||||
out_Glossy_1.radiance = closure_mask_ssr_radiance(out_Glossy_1.radiance, ssr_id);
|
||||
out_Glossy_1.radiance *= brdf;
|
||||
out_Glossy_1.radiance = render_pass_glossy_mask(spec_color, out_Glossy_1.radiance);
|
||||
closure_load_ssr_data(
|
||||
out_Glossy_1.radiance, in_Glossy_1.roughness, in_Glossy_1.N, ssr_id, result);
|
||||
}
|
||||
{
|
||||
/* Clearcoat. */
|
||||
float NV = dot(in_Glossy_2.N, cameraVec);
|
||||
vec2 split_sum = brdf_lut(NV, in_Glossy_2.roughness);
|
||||
vec3 brdf = F_brdf_single_scatter(vec3(0.04), vec3(1.0), split_sum);
|
||||
|
||||
out_Glossy_2.radiance *= brdf * clearcoat * 0.25;
|
||||
out_Glossy_2.radiance = render_pass_glossy_mask(vec3(1), out_Glossy_2.radiance);
|
||||
result.radiance += out_Glossy_2.radiance;
|
||||
}
|
||||
{
|
||||
/* Emission. */
|
||||
vec3 out_emission_radiance = render_pass_emission_mask(emission.rgb);
|
||||
result.radiance += out_emission_radiance;
|
||||
}
|
||||
|
||||
float trans = 1.0 - trans;
|
||||
result.transmittance = vec3(trans);
|
||||
result.radiance *= alpha;
|
||||
result.ssr_data.rgb *= alpha;
|
||||
}
|
||||
|
||||
#else
|
||||
/* Stub specular because it is not compatible with volumetrics. */
|
||||
# define node_eevee_specular(a, b, c, d, e, f, g, h, i, j, k, result) (result = CLOSURE_DEFAULT)
|
||||
|
@@ -1,38 +1,55 @@
|
||||
#ifndef VOLUMETRICS
|
||||
|
||||
CLOSURE_EVAL_FUNCTION_DECLARE_2(node_bsdf_glass, Glossy, Refraction)
|
||||
|
||||
void node_bsdf_glass(vec4 color,
|
||||
float roughness,
|
||||
float ior,
|
||||
vec3 N,
|
||||
float use_multiscatter,
|
||||
float ssr_id,
|
||||
const float do_multiscatter,
|
||||
const float ssr_id,
|
||||
out Closure result)
|
||||
{
|
||||
N = normalize(N);
|
||||
vec3 out_spec, out_refr, ssr_spec;
|
||||
vec3 refr_color = (refractionDepth > 0.0) ? color.rgb * color.rgb :
|
||||
color.rgb; /* Simulate 2 transmission event */
|
||||
eevee_closure_glass(N,
|
||||
vec3(1.0),
|
||||
/* HACK: Pass the multiscatter flag as the sign to not add closure
|
||||
* variations or increase register usage. */
|
||||
(use_multiscatter != 0.0) ? vec3(1.0) : -vec3(1.0),
|
||||
int(ssr_id),
|
||||
roughness,
|
||||
1.0,
|
||||
ior,
|
||||
true,
|
||||
out_spec,
|
||||
out_refr,
|
||||
ssr_spec);
|
||||
float fresnel = F_eta(ior, dot(N, cameraVec));
|
||||
vec3 vN = mat3(ViewMatrix) * N;
|
||||
result = CLOSURE_DEFAULT;
|
||||
result.radiance = render_pass_glossy_mask(refr_color, out_refr * refr_color) * (1.0 - fresnel);
|
||||
result.radiance += render_pass_glossy_mask(color.rgb, out_spec * color.rgb) * fresnel;
|
||||
CLOSURE_VARS_DECLARE_2(Glossy, Refraction);
|
||||
|
||||
in_Glossy_0.N = N; /* Normalized during eval. */
|
||||
in_Glossy_0.roughness = roughness;
|
||||
|
||||
in_Refraction_1.N = N; /* Normalized during eval. */
|
||||
in_Refraction_1.roughness = roughness;
|
||||
in_Refraction_1.ior = ior;
|
||||
|
||||
CLOSURE_EVAL_FUNCTION_2(node_bsdf_glass, Glossy, Refraction);
|
||||
|
||||
result = CLOSURE_DEFAULT;
|
||||
|
||||
float NV = dot(in_Refraction_1.N, cameraVec);
|
||||
|
||||
float fresnel = (do_multiscatter != 0.0) ?
|
||||
btdf_lut(NV, in_Refraction_1.roughness, in_Refraction_1.ior).y :
|
||||
F_eta(in_Refraction_1.ior, NV);
|
||||
|
||||
vec2 split_sum = brdf_lut(NV, in_Glossy_0.roughness);
|
||||
vec3 brdf = (do_multiscatter != 0.0) ? F_brdf_multi_scatter(vec3(1.0), vec3(1.0), split_sum) :
|
||||
F_brdf_single_scatter(vec3(1.0), vec3(1.0), split_sum);
|
||||
out_Glossy_0.radiance = closure_mask_ssr_radiance(out_Glossy_0.radiance, ssr_id);
|
||||
out_Glossy_0.radiance *= brdf;
|
||||
out_Glossy_0.radiance = render_pass_glossy_mask(vec3(1.0), out_Glossy_0.radiance);
|
||||
out_Glossy_0.radiance *= color.rgb * fresnel;
|
||||
closure_load_ssr_data(
|
||||
ssr_spec * color.rgb * fresnel, roughness, N, viewCameraVec, int(ssr_id), result);
|
||||
out_Glossy_0.radiance, in_Glossy_0.roughness, in_Glossy_0.N, ssr_id, result);
|
||||
|
||||
float btdf = (do_multiscatter != 0.0) ?
|
||||
1.0 :
|
||||
btdf_lut(NV, in_Refraction_1.roughness, in_Refraction_1.ior).x;
|
||||
out_Refraction_1.radiance *= btdf;
|
||||
out_Refraction_1.radiance = render_pass_glossy_mask(vec3(1.0), out_Refraction_1.radiance);
|
||||
out_Refraction_1.radiance *= color.rgb * (1.0 - fresnel);
|
||||
/* Simulate 2nd absorption event. */
|
||||
out_Refraction_1.radiance *= (refractionDepth > 0.0) ? color.rgb : vec3(1.0);
|
||||
result.radiance += out_Refraction_1.radiance;
|
||||
}
|
||||
|
||||
#else
|
||||
/* Stub glass because it is not compatible with volumetrics. */
|
||||
# define node_bsdf_glass(a, b, c, d, e, f, result) (result = CLOSURE_DEFAULT)
|
||||
|
@@ -1,23 +1,32 @@
|
||||
#ifndef VOLUMETRICS
|
||||
|
||||
CLOSURE_EVAL_FUNCTION_DECLARE_1(node_bsdf_glossy, Glossy)
|
||||
|
||||
void node_bsdf_glossy(
|
||||
vec4 color, float roughness, vec3 N, float use_multiscatter, float ssr_id, out Closure result)
|
||||
{
|
||||
N = normalize(N);
|
||||
vec3 out_spec, ssr_spec;
|
||||
eevee_closure_glossy(N,
|
||||
vec3(1.0),
|
||||
use_multiscatter != 0.0 ? vec3(1.0) : vec3(-1.0), /* HACK */
|
||||
int(ssr_id),
|
||||
roughness,
|
||||
1.0,
|
||||
true,
|
||||
out_spec,
|
||||
ssr_spec);
|
||||
vec3 vN = mat3(ViewMatrix) * N;
|
||||
bool do_ssr = (ssrToggle && int(ssr_id) == outputSsrId);
|
||||
|
||||
CLOSURE_VARS_DECLARE_1(Glossy);
|
||||
|
||||
in_Glossy_0.N = N; /* Normalized during eval. */
|
||||
in_Glossy_0.roughness = roughness;
|
||||
|
||||
CLOSURE_EVAL_FUNCTION_1(node_bsdf_glossy, Glossy);
|
||||
|
||||
result = CLOSURE_DEFAULT;
|
||||
result.radiance = render_pass_glossy_mask(vec3(1.0), out_spec) * color.rgb;
|
||||
closure_load_ssr_data(ssr_spec * color.rgb, roughness, N, viewCameraVec, int(ssr_id), result);
|
||||
|
||||
vec2 split_sum = brdf_lut(dot(in_Glossy_0.N, cameraVec), in_Glossy_0.roughness);
|
||||
vec3 brdf = (use_multiscatter != 0.0) ? F_brdf_multi_scatter(vec3(1.0), vec3(1.0), split_sum) :
|
||||
F_brdf_single_scatter(vec3(1.0), vec3(1.0), split_sum);
|
||||
out_Glossy_0.radiance = closure_mask_ssr_radiance(out_Glossy_0.radiance, ssr_id);
|
||||
out_Glossy_0.radiance *= brdf;
|
||||
out_Glossy_0.radiance = render_pass_glossy_mask(vec3(1.0), out_Glossy_0.radiance);
|
||||
out_Glossy_0.radiance *= color.rgb;
|
||||
closure_load_ssr_data(
|
||||
out_Glossy_0.radiance, in_Glossy_0.roughness, in_Glossy_0.N, ssr_id, result);
|
||||
}
|
||||
|
||||
#else
|
||||
/* Stub glossy because it is not compatible with volumetrics. */
|
||||
# define node_bsdf_glossy(a, b, c, d, e, result) (result = CLOSURE_DEFAULT)
|
||||
|
@@ -1,41 +1,20 @@
|
||||
#ifndef VOLUMETRICS
|
||||
vec3 tint_from_color(vec3 color)
|
||||
{
|
||||
float lum = dot(color, vec3(0.3, 0.6, 0.1)); /* luminance approx. */
|
||||
return (lum > 0) ? color / lum : vec3(1.0); /* normalize lum. to isolate hue+sat */
|
||||
float lum = dot(color, vec3(0.3, 0.6, 0.1)); /* luminance approx. */
|
||||
return (lum > 0.0) ? color / lum : vec3(0.0); /* normalize lum. to isolate hue+sat */
|
||||
}
|
||||
|
||||
void convert_metallic_to_specular_tinted(vec3 basecol,
|
||||
vec3 basecol_tint,
|
||||
float metallic,
|
||||
float specular_fac,
|
||||
float specular_tint,
|
||||
out vec3 diffuse,
|
||||
out vec3 f0)
|
||||
{
|
||||
vec3 tmp_col = mix(vec3(1.0), basecol_tint, specular_tint);
|
||||
f0 = mix((0.08 * specular_fac) * tmp_col, basecol, metallic);
|
||||
diffuse = basecol * (1.0 - metallic);
|
||||
}
|
||||
|
||||
/* Output sheen is to be multiplied by sheen_color. */
|
||||
void principled_sheen(float NV,
|
||||
vec3 basecol_tint,
|
||||
float sheen,
|
||||
float sheen_tint,
|
||||
out float out_sheen,
|
||||
out vec3 sheen_color)
|
||||
float principled_sheen(float NV)
|
||||
{
|
||||
float f = 1.0 - NV;
|
||||
/* Temporary fix for T59784. Normal map seems to contain NaNs for tangent space normal maps,
|
||||
* therefore we need to clamp value. */
|
||||
f = clamp(f, 0.0, 1.0);
|
||||
/* Empirical approximation (manual curve fitting). Can be refined. */
|
||||
out_sheen = f * f * f * 0.077 + f * 0.01 + 0.00026;
|
||||
|
||||
sheen_color = sheen * mix(vec3(1.0), basecol_tint, sheen_tint);
|
||||
float sheen = f * f * f * 0.077 + f * 0.01 + 0.00026;
|
||||
return sheen;
|
||||
}
|
||||
|
||||
CLOSURE_EVAL_FUNCTION_DECLARE_4(node_bsdf_principled, Diffuse, Glossy, Glossy, Refraction)
|
||||
|
||||
void node_bsdf_principled(vec4 base_color,
|
||||
float subsurface,
|
||||
vec3 subsurface_radius,
|
||||
@@ -59,434 +38,166 @@ void node_bsdf_principled(vec4 base_color,
|
||||
vec3 N,
|
||||
vec3 CN,
|
||||
vec3 T,
|
||||
vec3 I,
|
||||
float use_multiscatter,
|
||||
const float do_diffuse,
|
||||
const float do_clearcoat,
|
||||
const float do_refraction,
|
||||
const float do_multiscatter,
|
||||
float ssr_id,
|
||||
float sss_id,
|
||||
vec3 sss_scale,
|
||||
out Closure result)
|
||||
{
|
||||
N = normalize(N);
|
||||
ior = max(ior, 1e-5);
|
||||
/* Match cycles. */
|
||||
metallic = saturate(metallic);
|
||||
transmission = saturate(transmission);
|
||||
float m_transmission = 1.0 - transmission;
|
||||
float diffuse_weight = (1.0 - transmission) * (1.0 - metallic);
|
||||
transmission *= (1.0 - metallic);
|
||||
float specular_weight = (1.0 - transmission);
|
||||
clearcoat = max(clearcoat, 0.0);
|
||||
transmission_roughness = 1.0 - (1.0 - roughness) * (1.0 - transmission_roughness);
|
||||
|
||||
float dielectric = 1.0 - metallic;
|
||||
transmission *= dielectric;
|
||||
sheen *= dielectric;
|
||||
subsurface_color *= dielectric;
|
||||
CLOSURE_VARS_DECLARE_4(Diffuse, Glossy, Glossy, Refraction);
|
||||
|
||||
vec3 diffuse, f0, out_diff, out_spec, out_refr, ssr_spec, sheen_color;
|
||||
float out_sheen;
|
||||
vec3 ctint = tint_from_color(base_color.rgb);
|
||||
convert_metallic_to_specular_tinted(
|
||||
base_color.rgb, ctint, metallic, specular, specular_tint, diffuse, f0);
|
||||
in_Diffuse_0.N = N; /* Normalized during eval. */
|
||||
in_Diffuse_0.albedo = mix(base_color.rgb, subsurface_color.rgb, subsurface);
|
||||
|
||||
float NV = dot(N, cameraVec);
|
||||
principled_sheen(NV, ctint, sheen, sheen_tint, out_sheen, sheen_color);
|
||||
in_Glossy_1.N = N; /* Normalized during eval. */
|
||||
in_Glossy_1.roughness = roughness;
|
||||
|
||||
vec3 f90 = mix(vec3(1.0), f0, (1.0 - specular) * metallic);
|
||||
in_Glossy_2.N = CN; /* Normalized during eval. */
|
||||
in_Glossy_2.roughness = clearcoat_roughness;
|
||||
|
||||
/* Far from being accurate, but 2 glossy evaluation is too expensive.
|
||||
* Most noticeable difference is at grazing angles since the bsdf lut
|
||||
* f0 color interpolation is done on top of this interpolation. */
|
||||
vec3 f0_glass = mix(vec3(1.0), base_color.rgb, specular_tint);
|
||||
float fresnel = F_eta(ior, NV);
|
||||
vec3 spec_col = F_color_blend(ior, fresnel, f0_glass) * fresnel;
|
||||
f0 = mix(f0, spec_col, transmission);
|
||||
f90 = mix(f90, spec_col, transmission);
|
||||
in_Refraction_3.N = N; /* Normalized during eval. */
|
||||
in_Refraction_3.roughness = do_multiscatter != 0.0 ? roughness : transmission_roughness;
|
||||
in_Refraction_3.ior = ior;
|
||||
|
||||
/* Really poor approximation but needed to workaround issues with renderpasses. */
|
||||
spec_col = mix(vec3(1.0), spec_col, transmission);
|
||||
/* Match cycles. */
|
||||
spec_col += float(clearcoat > 1e-5);
|
||||
|
||||
vec3 mixed_ss_base_color = mix(diffuse, subsurface_color.rgb, subsurface);
|
||||
|
||||
float sss_scalef = avg(sss_scale) * subsurface;
|
||||
eevee_closure_principled(N,
|
||||
mixed_ss_base_color,
|
||||
f0,
|
||||
/* HACK: Pass the multiscatter flag as the sign to not add closure
|
||||
* variations or increase register usage. */
|
||||
(use_multiscatter != 0.0) ? f90 : -f90,
|
||||
int(ssr_id),
|
||||
roughness,
|
||||
CN,
|
||||
clearcoat * 0.25,
|
||||
clearcoat_roughness,
|
||||
1.0,
|
||||
sss_scalef,
|
||||
ior,
|
||||
true,
|
||||
out_diff,
|
||||
out_spec,
|
||||
out_refr,
|
||||
ssr_spec);
|
||||
|
||||
vec3 refr_color = base_color.rgb;
|
||||
refr_color *= (refractionDepth > 0.0) ? refr_color :
|
||||
vec3(1.0); /* Simulate 2 transmission event */
|
||||
refr_color *= saturate(1.0 - fresnel) * transmission;
|
||||
|
||||
sheen_color *= m_transmission;
|
||||
mixed_ss_base_color *= m_transmission;
|
||||
CLOSURE_EVAL_FUNCTION_4(node_bsdf_principled, Diffuse, Glossy, Glossy, Refraction);
|
||||
|
||||
result = CLOSURE_DEFAULT;
|
||||
result.radiance = render_pass_glossy_mask(refr_color, out_refr * refr_color);
|
||||
result.radiance += render_pass_glossy_mask(spec_col, out_spec);
|
||||
/* Coarse approx. */
|
||||
result.radiance += render_pass_diffuse_mask(sheen_color, out_diff * out_sheen * sheen_color);
|
||||
result.radiance += render_pass_emission_mask(emission.rgb * emission_strength);
|
||||
result.radiance *= alpha;
|
||||
closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
|
||||
|
||||
mixed_ss_base_color *= alpha;
|
||||
closure_load_sss_data(sss_scalef, out_diff, mixed_ss_base_color, int(sss_id), result);
|
||||
result.transmittance = vec3(1.0 - alpha);
|
||||
}
|
||||
/* This will tag the whole eval for optimisation. */
|
||||
if (do_diffuse == 0.0) {
|
||||
out_Diffuse_0.radiance = vec3(0);
|
||||
}
|
||||
if (do_clearcoat == 0.0) {
|
||||
out_Glossy_2.radiance = vec3(0);
|
||||
}
|
||||
if (do_refraction == 0.0) {
|
||||
out_Refraction_3.radiance = vec3(0);
|
||||
}
|
||||
|
||||
void node_bsdf_principled_dielectric(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,
|
||||
vec4 emission,
|
||||
float emission_strength,
|
||||
float alpha,
|
||||
vec3 N,
|
||||
vec3 CN,
|
||||
vec3 T,
|
||||
vec3 I,
|
||||
float use_multiscatter,
|
||||
float ssr_id,
|
||||
float sss_id,
|
||||
vec3 sss_scale,
|
||||
out Closure result)
|
||||
{
|
||||
N = normalize(N);
|
||||
metallic = saturate(metallic);
|
||||
float dielectric = 1.0 - metallic;
|
||||
/* Glossy_1 will always be evaluated. */
|
||||
float NV = dot(in_Glossy_1.N, cameraVec);
|
||||
|
||||
vec3 diffuse, f0, out_diff, out_spec, ssr_spec, sheen_color;
|
||||
float out_sheen;
|
||||
vec3 ctint = tint_from_color(base_color.rgb);
|
||||
convert_metallic_to_specular_tinted(
|
||||
base_color.rgb, ctint, metallic, specular, specular_tint, diffuse, f0);
|
||||
vec3 base_color_tint = tint_from_color(base_color.rgb);
|
||||
|
||||
vec3 f90 = mix(vec3(1.0), f0, (1.0 - specular) * metallic);
|
||||
float fresnel = (do_multiscatter != 0.0) ?
|
||||
btdf_lut(NV, in_Glossy_1.roughness, in_Refraction_3.ior).y :
|
||||
F_eta(in_Refraction_3.ior, NV);
|
||||
|
||||
float NV = dot(N, cameraVec);
|
||||
principled_sheen(NV, ctint, sheen, sheen_tint, out_sheen, sheen_color);
|
||||
{
|
||||
/* Glossy reflections.
|
||||
* Separate Glass reflections and main specular reflections to match Cycles renderpasses. */
|
||||
out_Glossy_1.radiance = closure_mask_ssr_radiance(out_Glossy_1.radiance, ssr_id);
|
||||
|
||||
eevee_closure_default(N,
|
||||
diffuse,
|
||||
f0,
|
||||
/* HACK: Pass the multiscatter flag as the sign to not add closure
|
||||
* variations or increase register usage. */
|
||||
(use_multiscatter != 0.0) ? f90 : -f90,
|
||||
int(ssr_id),
|
||||
roughness,
|
||||
1.0,
|
||||
true,
|
||||
out_diff,
|
||||
out_spec,
|
||||
ssr_spec);
|
||||
vec2 split_sum = brdf_lut(NV, roughness);
|
||||
|
||||
result = CLOSURE_DEFAULT;
|
||||
result.radiance = render_pass_glossy_mask(vec3(1.0), out_spec);
|
||||
result.radiance += render_pass_diffuse_mask(sheen_color, out_diff * out_sheen * sheen_color);
|
||||
result.radiance += render_pass_diffuse_mask(diffuse, out_diff * diffuse);
|
||||
result.radiance += render_pass_emission_mask(emission.rgb * emission_strength);
|
||||
result.radiance *= alpha;
|
||||
closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
|
||||
vec3 glossy_radiance_final = vec3(0.0);
|
||||
if (transmission > 1e-5) {
|
||||
/* Glass Reflection: Reuse radiance from Glossy1. */
|
||||
vec3 out_glass_refl_radiance = out_Glossy_1.radiance;
|
||||
|
||||
/* Poor approximation since we baked the LUT using a fixed IOR. */
|
||||
vec3 f0 = mix(vec3(1.0), base_color.rgb, specular_tint);
|
||||
vec3 f90 = vec3(1);
|
||||
|
||||
vec3 brdf = (do_multiscatter != 0.0) ? F_brdf_multi_scatter(f0, f90, split_sum) :
|
||||
F_brdf_single_scatter(f0, f90, split_sum);
|
||||
|
||||
out_glass_refl_radiance *= brdf;
|
||||
out_glass_refl_radiance = render_pass_glossy_mask(vec3(1), out_glass_refl_radiance);
|
||||
out_glass_refl_radiance *= fresnel * transmission;
|
||||
glossy_radiance_final += out_glass_refl_radiance;
|
||||
}
|
||||
if (specular_weight > 1e-5) {
|
||||
vec3 dielectric_f0_color = mix(vec3(1.0), base_color_tint, specular_tint);
|
||||
vec3 metallic_f0_color = base_color.rgb;
|
||||
vec3 f0 = mix((0.08 * specular) * dielectric_f0_color, metallic_f0_color, metallic);
|
||||
/* Cycles does this blending using the microfacet fresnel factor. However, our fresnel
|
||||
* is already baked inside the split sum LUT. We approximate using by modifying the
|
||||
* changing the f90 color directly in a non linear fashion. */
|
||||
vec3 f90 = mix(f0, vec3(1), fast_sqrt(specular));
|
||||
|
||||
vec3 brdf = (do_multiscatter != 0.0) ? F_brdf_multi_scatter(f0, f90, split_sum) :
|
||||
F_brdf_single_scatter(f0, f90, split_sum);
|
||||
|
||||
out_Glossy_1.radiance *= brdf;
|
||||
out_Glossy_1.radiance = render_pass_glossy_mask(vec3(1), out_Glossy_1.radiance);
|
||||
out_Glossy_1.radiance *= specular_weight;
|
||||
glossy_radiance_final += out_Glossy_1.radiance;
|
||||
}
|
||||
|
||||
closure_load_ssr_data(
|
||||
glossy_radiance_final, in_Glossy_1.roughness, in_Glossy_1.N, ssr_id, result);
|
||||
}
|
||||
|
||||
if (diffuse_weight > 1e-5) {
|
||||
/* Mask over all diffuse radiance. */
|
||||
out_Diffuse_0.radiance *= diffuse_weight;
|
||||
|
||||
/* Sheen Coarse approximation: We reuse the diffuse radiance and just scale it. */
|
||||
vec3 sheen_color = mix(vec3(1), base_color_tint, sheen_tint);
|
||||
vec3 out_sheen_radiance = out_Diffuse_0.radiance * principled_sheen(NV);
|
||||
out_sheen_radiance = render_pass_diffuse_mask(vec3(1), out_sheen_radiance);
|
||||
out_sheen_radiance *= sheen * sheen_color;
|
||||
result.radiance += out_sheen_radiance;
|
||||
|
||||
/* Diffuse / Subsurface. */
|
||||
float scale = avg(sss_scale) * subsurface;
|
||||
closure_load_sss_data(scale, out_Diffuse_0.radiance, in_Diffuse_0.albedo, int(sss_id), result);
|
||||
}
|
||||
|
||||
if (transmission > 1e-5) {
|
||||
float btdf = (do_multiscatter != 0.0) ?
|
||||
1.0 :
|
||||
btdf_lut(NV, in_Refraction_3.roughness, in_Refraction_3.ior).x;
|
||||
/* TODO(fclem) This could be going to a transmission render pass instead. */
|
||||
out_Refraction_3.radiance *= btdf;
|
||||
out_Refraction_3.radiance = render_pass_glossy_mask(vec3(1), out_Refraction_3.radiance);
|
||||
out_Refraction_3.radiance *= base_color.rgb;
|
||||
/* Simulate 2nd transmission event. */
|
||||
out_Refraction_3.radiance *= (refractionDepth > 0.0) ? base_color.rgb : vec3(1);
|
||||
out_Refraction_3.radiance *= (1.0 - fresnel) * transmission;
|
||||
result.radiance += out_Refraction_3.radiance;
|
||||
}
|
||||
|
||||
if (clearcoat > 1e-5) {
|
||||
float NV = dot(in_Glossy_2.N, cameraVec);
|
||||
vec2 split_sum = brdf_lut(NV, in_Glossy_2.roughness);
|
||||
vec3 brdf = F_brdf_single_scatter(vec3(0.04), vec3(1.0), split_sum);
|
||||
|
||||
out_Glossy_2.radiance *= brdf * clearcoat * 0.25;
|
||||
out_Glossy_2.radiance = render_pass_glossy_mask(vec3(1), out_Glossy_2.radiance);
|
||||
result.radiance += out_Glossy_2.radiance;
|
||||
}
|
||||
|
||||
{
|
||||
vec3 out_emission_radiance = render_pass_emission_mask(emission.rgb);
|
||||
out_emission_radiance *= emission_strength;
|
||||
result.radiance += out_emission_radiance;
|
||||
}
|
||||
|
||||
result.transmittance = vec3(1.0 - alpha);
|
||||
}
|
||||
|
||||
void node_bsdf_principled_metallic(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,
|
||||
vec4 emission,
|
||||
float emission_strength,
|
||||
float alpha,
|
||||
vec3 N,
|
||||
vec3 CN,
|
||||
vec3 T,
|
||||
vec3 I,
|
||||
float use_multiscatter,
|
||||
float ssr_id,
|
||||
float sss_id,
|
||||
vec3 sss_scale,
|
||||
out Closure result)
|
||||
{
|
||||
N = normalize(N);
|
||||
vec3 out_spec, ssr_spec;
|
||||
|
||||
vec3 f90 = mix(vec3(1.0), base_color.rgb, (1.0 - specular) * metallic);
|
||||
|
||||
eevee_closure_glossy(N,
|
||||
base_color.rgb,
|
||||
/* HACK: Pass the multiscatter flag as the sign to not add closure
|
||||
* variations or increase register usage. */
|
||||
(use_multiscatter != 0.0) ? f90 : -f90,
|
||||
int(ssr_id),
|
||||
roughness,
|
||||
1.0,
|
||||
true,
|
||||
out_spec,
|
||||
ssr_spec);
|
||||
|
||||
result = CLOSURE_DEFAULT;
|
||||
result.radiance = render_pass_glossy_mask(vec3(1.0), out_spec);
|
||||
result.radiance += render_pass_emission_mask(emission.rgb * emission_strength);
|
||||
result.radiance *= alpha;
|
||||
closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
|
||||
|
||||
result.transmittance = vec3(1.0 - alpha);
|
||||
result.ssr_data.rgb *= alpha;
|
||||
# ifdef USE_SSS
|
||||
result.sss_irradiance *= alpha;
|
||||
# endif
|
||||
}
|
||||
|
||||
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,
|
||||
vec4 emission,
|
||||
float emission_strength,
|
||||
float alpha,
|
||||
vec3 N,
|
||||
vec3 CN,
|
||||
vec3 T,
|
||||
vec3 I,
|
||||
float use_multiscatter,
|
||||
float ssr_id,
|
||||
float sss_id,
|
||||
vec3 sss_scale,
|
||||
out Closure result)
|
||||
{
|
||||
vec3 out_spec, ssr_spec;
|
||||
N = normalize(N);
|
||||
|
||||
vec3 f90 = mix(vec3(1.0), base_color.rgb, (1.0 - specular) * metallic);
|
||||
|
||||
eevee_closure_clearcoat(N,
|
||||
base_color.rgb,
|
||||
/* HACK: Pass the multiscatter flag as the sign to not add closure
|
||||
* variations or increase register usage. */
|
||||
(use_multiscatter != 0.0) ? f90 : -f90,
|
||||
int(ssr_id),
|
||||
roughness,
|
||||
CN,
|
||||
clearcoat * 0.25,
|
||||
clearcoat_roughness,
|
||||
1.0,
|
||||
true,
|
||||
out_spec,
|
||||
ssr_spec);
|
||||
/* Match cycles. */
|
||||
float spec_col = 1.0 + float(clearcoat > 1e-5);
|
||||
|
||||
result = CLOSURE_DEFAULT;
|
||||
result.radiance = render_pass_glossy_mask(vec3(spec_col), out_spec);
|
||||
result.radiance += render_pass_emission_mask(emission.rgb * emission_strength);
|
||||
result.radiance *= alpha;
|
||||
|
||||
closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
|
||||
|
||||
result.transmittance = vec3(1.0 - alpha);
|
||||
}
|
||||
|
||||
void node_bsdf_principled_subsurface(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,
|
||||
vec4 emission,
|
||||
float emission_strength,
|
||||
float alpha,
|
||||
vec3 N,
|
||||
vec3 CN,
|
||||
vec3 T,
|
||||
vec3 I,
|
||||
float use_multiscatter,
|
||||
float ssr_id,
|
||||
float sss_id,
|
||||
vec3 sss_scale,
|
||||
out Closure result)
|
||||
{
|
||||
metallic = saturate(metallic);
|
||||
N = normalize(N);
|
||||
|
||||
vec3 diffuse, f0, out_diff, out_spec, ssr_spec, sheen_color;
|
||||
float out_sheen;
|
||||
vec3 ctint = tint_from_color(base_color.rgb);
|
||||
convert_metallic_to_specular_tinted(
|
||||
base_color.rgb, ctint, metallic, specular, specular_tint, diffuse, f0);
|
||||
|
||||
subsurface_color = subsurface_color * (1.0 - metallic);
|
||||
vec3 mixed_ss_base_color = mix(diffuse, subsurface_color.rgb, subsurface);
|
||||
float sss_scalef = avg(sss_scale) * subsurface;
|
||||
|
||||
float NV = dot(N, cameraVec);
|
||||
principled_sheen(NV, ctint, sheen, sheen_tint, out_sheen, sheen_color);
|
||||
|
||||
vec3 f90 = mix(vec3(1.0), base_color.rgb, (1.0 - specular) * metallic);
|
||||
|
||||
eevee_closure_skin(N,
|
||||
mixed_ss_base_color,
|
||||
f0,
|
||||
/* HACK: Pass the multiscatter flag as the sign to not add closure variations
|
||||
* or increase register usage. */
|
||||
(use_multiscatter != 0.0) ? f90 : -f90,
|
||||
int(ssr_id),
|
||||
roughness,
|
||||
1.0,
|
||||
sss_scalef,
|
||||
true,
|
||||
out_diff,
|
||||
out_spec,
|
||||
ssr_spec);
|
||||
|
||||
result = CLOSURE_DEFAULT;
|
||||
result.radiance = render_pass_glossy_mask(vec3(1.0), out_spec);
|
||||
result.radiance += render_pass_diffuse_mask(sheen_color, out_diff * out_sheen * sheen_color);
|
||||
result.radiance += render_pass_emission_mask(emission.rgb * emission_strength);
|
||||
result.radiance *= alpha;
|
||||
|
||||
closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
|
||||
|
||||
mixed_ss_base_color *= alpha;
|
||||
closure_load_sss_data(sss_scalef, out_diff, mixed_ss_base_color, int(sss_id), result);
|
||||
|
||||
result.transmittance = vec3(1.0 - alpha);
|
||||
}
|
||||
|
||||
void node_bsdf_principled_glass(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,
|
||||
vec4 emission,
|
||||
float emission_strength,
|
||||
float alpha,
|
||||
vec3 N,
|
||||
vec3 CN,
|
||||
vec3 T,
|
||||
vec3 I,
|
||||
float use_multiscatter,
|
||||
float ssr_id,
|
||||
float sss_id,
|
||||
vec3 sss_scale,
|
||||
out Closure result)
|
||||
{
|
||||
ior = max(ior, 1e-5);
|
||||
N = normalize(N);
|
||||
|
||||
vec3 f0, out_spec, out_refr, ssr_spec;
|
||||
f0 = mix(vec3(1.0), base_color.rgb, specular_tint);
|
||||
|
||||
eevee_closure_glass(N,
|
||||
vec3(1.0),
|
||||
vec3((use_multiscatter != 0.0) ? 1.0 : -1.0),
|
||||
int(ssr_id),
|
||||
roughness,
|
||||
1.0,
|
||||
ior,
|
||||
true,
|
||||
out_spec,
|
||||
out_refr,
|
||||
ssr_spec);
|
||||
|
||||
vec3 refr_color = base_color.rgb;
|
||||
refr_color *= (refractionDepth > 0.0) ? refr_color :
|
||||
vec3(1.0); /* Simulate 2 transmission events */
|
||||
|
||||
float fresnel = F_eta(ior, dot(N, cameraVec));
|
||||
vec3 spec_col = F_color_blend(ior, fresnel, f0);
|
||||
spec_col *= fresnel;
|
||||
refr_color *= (1.0 - fresnel);
|
||||
|
||||
ssr_spec *= spec_col;
|
||||
|
||||
result = CLOSURE_DEFAULT;
|
||||
result.radiance = render_pass_glossy_mask(refr_color, out_refr * refr_color);
|
||||
result.radiance += render_pass_glossy_mask(spec_col, out_spec * spec_col);
|
||||
result.radiance += render_pass_emission_mask(emission.rgb * emission_strength);
|
||||
result.radiance *= alpha;
|
||||
closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
|
||||
result.transmittance = vec3(1.0 - alpha);
|
||||
}
|
||||
#else
|
||||
/* clang-format off */
|
||||
/* Stub principled because it is not compatible with volumetrics. */
|
||||
# define node_bsdf_principled(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, aa, bb, result) (result = CLOSURE_DEFAULT)
|
||||
# define node_bsdf_principled_dielectric(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, aa, bb, result) (result = CLOSURE_DEFAULT)
|
||||
# define node_bsdf_principled_metallic(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, aa, bb, result) (result = CLOSURE_DEFAULT)
|
||||
# define node_bsdf_principled_clearcoat(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, aa, bb, result) (result = CLOSURE_DEFAULT)
|
||||
# define node_bsdf_principled_subsurface(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, aa, bb, result) (result = CLOSURE_DEFAULT)
|
||||
# define node_bsdf_principled_glass(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, aa, bb, result) (result = CLOSURE_DEFAULT)
|
||||
# define node_bsdf_principled(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, aa, bb, cc, dd, result) (result = CLOSURE_DEFAULT)
|
||||
/* clang-format on */
|
||||
#endif
|
||||
|
@@ -1,15 +1,30 @@
|
||||
#ifndef VOLUMETRICS
|
||||
|
||||
CLOSURE_EVAL_FUNCTION_DECLARE_1(node_bsdf_refraction, Refraction)
|
||||
|
||||
void node_bsdf_refraction(vec4 color, float roughness, float ior, vec3 N, out Closure result)
|
||||
{
|
||||
N = normalize(N);
|
||||
vec3 out_refr;
|
||||
color.rgb *= (refractionDepth > 0.0) ? color.rgb : vec3(1.0); /* Simulate 2 absorption event. */
|
||||
eevee_closure_refraction(N, roughness, ior, true, out_refr);
|
||||
vec3 vN = mat3(ViewMatrix) * N;
|
||||
CLOSURE_VARS_DECLARE_1(Refraction);
|
||||
|
||||
in_Refraction_0.N = N; /* Normalized during eval. */
|
||||
in_Refraction_0.roughness = roughness;
|
||||
in_Refraction_0.ior = ior;
|
||||
|
||||
CLOSURE_EVAL_FUNCTION_1(node_bsdf_refraction, Refraction);
|
||||
|
||||
result = CLOSURE_DEFAULT;
|
||||
result.ssr_normal = normal_encode(vN, viewCameraVec);
|
||||
result.radiance = render_pass_glossy_mask(color.rgb, out_refr * color.rgb);
|
||||
|
||||
out_Refraction_0.radiance = render_pass_glossy_mask(vec3(1.0), out_Refraction_0.radiance);
|
||||
out_Refraction_0.radiance *= color.rgb;
|
||||
/* Simulate 2nd absorption event. */
|
||||
out_Refraction_0.radiance *= (refractionDepth > 0.0) ? color.rgb : vec3(1.0);
|
||||
|
||||
result.radiance = out_Refraction_0.radiance;
|
||||
|
||||
/* TODO(fclem) Try to not use this. */
|
||||
result.ssr_normal = normal_encode(mat3(ViewMatrix) * in_Refraction_0.N, viewCameraVec);
|
||||
}
|
||||
|
||||
#else
|
||||
/* Stub refraction because it is not compatible with volumetrics. */
|
||||
# define node_bsdf_refraction(a, b, c, d, e) (e = CLOSURE_DEFAULT)
|
||||
|
@@ -1,4 +1,7 @@
|
||||
#ifndef VOLUMETRICS
|
||||
|
||||
CLOSURE_EVAL_FUNCTION_DECLARE_1(node_subsurface_scattering, Diffuse)
|
||||
|
||||
void node_subsurface_scattering(vec4 color,
|
||||
float scale,
|
||||
vec3 radius,
|
||||
@@ -8,20 +11,29 @@ void node_subsurface_scattering(vec4 color,
|
||||
float sss_id,
|
||||
out Closure result)
|
||||
{
|
||||
N = normalize(N);
|
||||
vec3 out_diff;
|
||||
vec3 vN = mat3(ViewMatrix) * N;
|
||||
CLOSURE_VARS_DECLARE_1(Diffuse);
|
||||
|
||||
in_Diffuse_0.N = N; /* Normalized during eval. */
|
||||
in_Diffuse_0.albedo = color.rgb;
|
||||
|
||||
CLOSURE_EVAL_FUNCTION_1(node_subsurface_scattering, Diffuse);
|
||||
|
||||
result = CLOSURE_DEFAULT;
|
||||
closure_load_ssr_data(vec3(0.0), 0.0, N, viewCameraVec, -1, result);
|
||||
|
||||
eevee_closure_subsurface(N, color.rgb, 1.0, scale, true, out_diff);
|
||||
/* Not perfect for texture_blur values between 0.0 and 1.0.
|
||||
* Interpolate between separated color and color applied on irradiance. */
|
||||
float one_minus_texture_blur = 1.0 - texture_blur;
|
||||
vec3 sss_albedo = color.rgb * texture_blur + one_minus_texture_blur;
|
||||
vec3 radiance_tint = color.rgb * one_minus_texture_blur + texture_blur;
|
||||
/* Consider output radiance as irradiance. */
|
||||
out_Diffuse_0.radiance *= radiance_tint;
|
||||
|
||||
/* Not perfect for texture_blur not exactly equal to 0.0 or 1.0. */
|
||||
vec3 sss_albedo = mix(color.rgb, vec3(1.0), texture_blur);
|
||||
out_diff *= mix(vec3(1.0), color.rgb, texture_blur);
|
||||
result.radiance = render_pass_sss_mask(sss_albedo);
|
||||
closure_load_sss_data(scale, out_diff, sss_albedo, int(sss_id), result);
|
||||
closure_load_sss_data(scale, out_Diffuse_0.radiance, sss_albedo, int(sss_id), result);
|
||||
|
||||
/* TODO(fclem) Try to not use this. */
|
||||
closure_load_ssr_data(vec3(0.0), 0.0, in_Diffuse_0.N, -1, result);
|
||||
}
|
||||
|
||||
#else
|
||||
/* Stub subsurface scattering because it is not compatible with volumetrics. */
|
||||
# define node_subsurface_scattering(a, b, c, d, e, f, g, h) (h = CLOSURE_DEFAULT)
|
||||
|
@@ -1,12 +1,20 @@
|
||||
#ifndef VOLUMETRICS
|
||||
|
||||
CLOSURE_EVAL_FUNCTION_DECLARE_1(node_bsdf_translucent, Translucent)
|
||||
|
||||
void node_bsdf_translucent(vec4 color, vec3 N, out Closure result)
|
||||
{
|
||||
N = normalize(N);
|
||||
CLOSURE_VARS_DECLARE_1(Translucent);
|
||||
|
||||
in_Translucent_0.N = -N; /* Normalized during eval. */
|
||||
|
||||
CLOSURE_EVAL_FUNCTION_1(node_bsdf_translucent, Translucent);
|
||||
|
||||
result = CLOSURE_DEFAULT;
|
||||
eevee_closure_diffuse(-N, color.rgb, 1.0, false, result.radiance);
|
||||
closure_load_ssr_data(vec3(0.0), 0.0, N, viewCameraVec, -1, result);
|
||||
result.radiance = render_pass_diffuse_mask(color.rgb, result.radiance * color.rgb);
|
||||
closure_load_ssr_data(vec3(0.0), 0.0, -in_Translucent_0.N, -1, result);
|
||||
result.radiance = render_pass_diffuse_mask(color.rgb, out_Translucent_0.radiance * color.rgb);
|
||||
}
|
||||
|
||||
#else
|
||||
/* Stub translucent because it is not compatible with volumetrics. */
|
||||
# define node_bsdf_translucent(a, b, c) (c = CLOSURE_DEFAULT)
|
||||
|
@@ -185,7 +185,7 @@ typedef struct LightCache {
|
||||
} LightCache;
|
||||
|
||||
/* Bump the version number for lightcache data structure changes. */
|
||||
#define LIGHTCACHE_STATIC_VERSION 1
|
||||
#define LIGHTCACHE_STATIC_VERSION 2
|
||||
|
||||
/* LightCache->type */
|
||||
enum {
|
||||
|
@@ -134,54 +134,32 @@ static int node_shader_gpu_bsdf_principled(GPUMaterial *mat,
|
||||
GPU_link(mat, "set_rgb_one", &sss_scale);
|
||||
}
|
||||
|
||||
/* Due to the manual effort done per config, we only optimize the most common permutations. */
|
||||
char *node_name;
|
||||
uint flag = 0;
|
||||
if (!use_subsurf && use_diffuse && !use_refract && !use_clear) {
|
||||
static char name[] = "node_bsdf_principled_dielectric";
|
||||
node_name = name;
|
||||
flag = GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_GLOSSY;
|
||||
uint flag = GPU_MATFLAG_GLOSSY;
|
||||
if (use_diffuse) {
|
||||
flag |= GPU_MATFLAG_DIFFUSE;
|
||||
}
|
||||
else if (!use_subsurf && !use_diffuse && !use_refract && !use_clear) {
|
||||
static char name[] = "node_bsdf_principled_metallic";
|
||||
node_name = name;
|
||||
flag = GPU_MATFLAG_GLOSSY;
|
||||
if (use_refract) {
|
||||
flag |= GPU_MATFLAG_REFRACT;
|
||||
}
|
||||
else if (!use_subsurf && !use_diffuse && !use_refract && use_clear) {
|
||||
static char name[] = "node_bsdf_principled_clearcoat";
|
||||
node_name = name;
|
||||
flag = GPU_MATFLAG_GLOSSY;
|
||||
}
|
||||
else if (use_subsurf && use_diffuse && !use_refract && !use_clear) {
|
||||
static char name[] = "node_bsdf_principled_subsurface";
|
||||
node_name = name;
|
||||
flag = GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_GLOSSY;
|
||||
}
|
||||
else if (!use_subsurf && !use_diffuse && use_refract && !use_clear && !socket_not_zero(4)) {
|
||||
static char name[] = "node_bsdf_principled_glass";
|
||||
node_name = name;
|
||||
flag = GPU_MATFLAG_GLOSSY | GPU_MATFLAG_REFRACT;
|
||||
}
|
||||
else {
|
||||
static char name[] = "node_bsdf_principled";
|
||||
node_name = name;
|
||||
flag = GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_GLOSSY | GPU_MATFLAG_REFRACT;
|
||||
}
|
||||
|
||||
if (use_subsurf) {
|
||||
flag |= GPU_MATFLAG_SSS;
|
||||
}
|
||||
|
||||
float f_use_diffuse = use_diffuse ? 1.0f : 0.0f;
|
||||
float f_use_clearcoat = use_clear ? 1.0f : 0.0f;
|
||||
float f_use_refraction = use_refract ? 1.0f : 0.0f;
|
||||
float use_multi_scatter = (node->custom1 == SHD_GLOSSY_MULTI_GGX) ? 1.0f : 0.0f;
|
||||
|
||||
GPU_material_flag_set(mat, flag);
|
||||
|
||||
return GPU_stack_link(mat,
|
||||
node,
|
||||
node_name,
|
||||
"node_bsdf_principled",
|
||||
in,
|
||||
out,
|
||||
GPU_builtin(GPU_VIEW_POSITION),
|
||||
GPU_constant(&f_use_diffuse),
|
||||
GPU_constant(&f_use_clearcoat),
|
||||
GPU_constant(&f_use_refraction),
|
||||
GPU_constant(&use_multi_scatter),
|
||||
GPU_constant(&node->ssr_id),
|
||||
GPU_constant(&node->sss_id),
|
||||
|
Reference in New Issue
Block a user