EEVEE-Next: Gbuffer Read optimizations

This modify most shader using the GBuffer to use the
`ClosureUndetermined`. This in turn reduces the amount
of duplicated data in the `GBufferReader` structure.

The most important part is the usage of fixed array
indices to access the `GBufferReader.closures[]`.
This avoid the struct to be moved from local register
to device memory and remove a huge performance penalty.

Pull Request: https://projects.blender.org/blender/blender/pulls/116772
This commit is contained in:
Clément Foucault
2024-01-07 04:46:25 +01:00
committed by Clément Foucault
parent 6f51d7332b
commit f2b3403145
21 changed files with 363 additions and 301 deletions

View File

@@ -18,19 +18,34 @@ void main()
GBufferReader gbuf = gbuffer_read(gbuf_header_tx, gbuf_closure_tx, gbuf_normal_tx, texel);
if (gbuf.header == 0u) {
if (gbuf.closure_count == 0) {
discard;
return;
}
float shade = saturate(drw_normal_world_to_view(gbuf.data.surface_N).z);
float shade = saturate(drw_normal_world_to_view(gbuf.surface_N).z);
uvec4 closure_types = (uvec4(gbuf.header) >> uvec4(0u, 4u, 8u, 12u)) & 15u;
uint header = texelFetch(gbuf_header_tx, texel, 0).x;
uvec4 closure_types = (uvec4(header) >> uvec4(0u, 4u, 8u, 12u)) & 15u;
float storage_cost = reduce_add(vec4(not(equal(closure_types, uvec4(0u)))));
float eval_cost = reduce_add(vec4(equal(closure_types, uvec4(GBUF_REFLECTION)))) * 1.0 +
reduce_add(vec4(equal(closure_types, uvec4(GBUF_REFRACTION)))) * 1.0 +
reduce_add(vec4(equal(closure_types, uvec4(GBUF_DIFFUSE)))) * 1.0 +
reduce_add(vec4(equal(closure_types, uvec4(GBUF_SUBSURFACE)))) * 1.0;
float eval_cost = 0.0;
for (int i = 0; i < GBUFFER_LAYER_MAX && i < gbuf.closure_count; i++) {
switch (gbuffer_closure_get(gbuf, i).type) {
case CLOSURE_BSDF_DIFFUSE_ID:
case CLOSURE_BSDF_TRANSLUCENT_ID:
case CLOSURE_BSDF_MICROFACET_GGX_REFLECTION_ID:
case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
eval_cost += 1.0;
break;
case CLOSURE_BSSRDF_BURLEY_ID:
eval_cost += 2.0;
break;
case CLOSURE_NONE_ID:
/* TODO(fclem): Assert. */
break;
}
}
switch (eDebugMode(debug_mode)) {
default:

View File

@@ -19,30 +19,54 @@ void main()
GBufferReader gbuf = gbuffer_read(gbuf_header_tx, gbuf_closure_tx, gbuf_normal_tx, texel);
if (!gbuf.has_any_surface) {
if (gbuf.closure_count == 0) {
return;
}
ClosureLightStack stack;
stack.cl[0].N = gbuf.data.surface_N;
stack.cl[0].N = gbuf.surface_N;
stack.cl[0].ltc_mat = LTC_LAMBERT_MAT;
stack.cl[0].type = LIGHT_DIFFUSE;
stack.cl[1].N = -gbuf.surface_N;
stack.cl[1].ltc_mat = LTC_LAMBERT_MAT;
stack.cl[1].type = LIGHT_DIFFUSE;
vec3 P = drw_point_screen_to_world(vec3(uvcoordsvar.xy, depth));
vec3 Ng = stack.cl[0].N;
vec3 Ng = gbuf.surface_N;
vec3 V = drw_world_incident_vector(P);
float vPz = dot(drw_view_forward(), P) - dot(drw_view_forward(), drw_view_position());
/* Direct light. */
light_eval(stack, P, Ng, V, vPz, gbuf.data.thickness);
light_eval(stack, P, Ng, V, vPz, gbuf.thickness);
/* Indirect light. */
/* Can only load irradiance to avoid dependency loop with the reflection probe. */
SphericalHarmonicL1 sh = lightprobe_irradiance_sample(P, V, Ng);
vec3 radiance = stack.cl[0].light_shadowed + spherical_harmonics_evaluate_lambert(Ng, sh);
vec3 radiance_front = stack.cl[0].light_shadowed + spherical_harmonics_evaluate_lambert(Ng, sh);
vec3 radiance_back = stack.cl[1].light_shadowed + spherical_harmonics_evaluate_lambert(-Ng, sh);
vec3 albedo = gbuf.data.diffuse.color + gbuf.data.reflection.color + gbuf.data.refraction.color +
gbuf.data.translucent.color;
vec3 albedo_front = vec3(0.0);
vec3 albedo_back = vec3(0.0);
out_radiance = vec4(radiance * albedo, 0.0);
for (int i = 0; i < GBUFFER_LAYER_MAX && i < gbuf.closure_count; i++) {
ClosureUndetermined cl = gbuffer_closure_get(gbuf, i);
switch (cl.type) {
case CLOSURE_BSSRDF_BURLEY_ID:
case CLOSURE_BSDF_DIFFUSE_ID:
case CLOSURE_BSDF_MICROFACET_GGX_REFLECTION_ID:
albedo_front += cl.color;
break;
case CLOSURE_BSDF_TRANSLUCENT_ID:
case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
albedo_back += cl.color;
break;
case CLOSURE_NONE_ID:
/* TODO(fclem): Assert. */
break;
}
}
out_radiance = vec4(radiance_front * albedo_front + radiance_back * albedo_back, 0.0);
}

View File

@@ -68,10 +68,11 @@ void main()
closure_light += load_radiance_indirect(texel, i);
}
closure_light *= gbuf.closures[i].color;
ClosureUndetermined cl = gbuffer_closure_get(gbuf, i);
closure_light *= cl.color;
out_combined.rgb += closure_light;
switch (gbuf.closures[i].type) {
switch (cl.type) {
case CLOSURE_BSDF_TRANSLUCENT_ID:
case CLOSURE_BSSRDF_BURLEY_ID:
case CLOSURE_BSDF_DIFFUSE_ID:

View File

@@ -54,23 +54,24 @@ void main()
}
vec3 P = drw_point_screen_to_world(vec3(uvcoordsvar.xy, depth));
vec3 Ng = gbuf.data.surface_N;
vec3 Ng = gbuf.surface_N;
vec3 V = drw_world_incident_vector(P);
float vPz = dot(drw_view_forward(), P) - dot(drw_view_forward(), drw_view_position());
ClosureLightStack stack;
for (int i = 0; i < LIGHT_CLOSURE_EVAL_COUNT && i < gbuf.closure_count; i++) {
stack.cl[i] = closure_light_new(gbuf.closures[i], V);
stack.cl[i] = closure_light_new(gbuffer_closure_get(gbuf, i), V);
}
/* TODO(fclem): Split thickness computation. */
float thickness = (gbuf.has_translucent) ? gbuf.data.thickness : 0.0;
float thickness = gbuf.thickness;
#ifdef MAT_SUBSURFACE
if (gbuf.has_sss) {
/* NOTE: BSSRDF is supposed to always be the first closure. */
bool has_sss = gbuffer_closure_get(gbuf, 0).type == CLOSURE_BSSRDF_BURLEY_ID;
if (has_sss) {
float shadow_thickness = thickness_from_shadow(P, Ng, vPz);
thickness = (shadow_thickness != THICKNESS_NO_VALUE) ?
max(shadow_thickness, gbuf.data.thickness) :
gbuf.data.thickness;
thickness = (shadow_thickness != THICKNESS_NO_VALUE) ? max(shadow_thickness, gbuf.thickness) :
gbuf.thickness;
/* Add one translucent closure for all SSS closure. Reuse the same lighting. */
ClosureLight cl_light;
@@ -84,12 +85,11 @@ void main()
light_eval(stack, P, Ng, V, vPz, thickness);
#ifdef MAT_SUBSURFACE
/* NOTE: BSSRDF is supposed to always be the first closure. */
if (gbuf.closures[0].type == CLOSURE_BSSRDF_BURLEY_ID) {
if (has_sss) {
/* Add to diffuse light for processing inside the Screen Space SSS pass.
* The tranlucent light is not outputed as a separate quantity because
* it is over the closure_count. */
vec3 sss_profile = subsurface_transmission(gbuf.closures[0].data.rgb, thickness);
vec3 sss_profile = subsurface_transmission(gbuffer_closure_get(gbuf, 0).data.rgb, thickness);
stack.cl[0].light_shadowed += stack.cl[gbuf.closure_count].light_shadowed * sss_profile;
stack.cl[0].light_unshadowed += stack.cl[gbuf.closure_count].light_unshadowed * sss_profile;
}
@@ -116,25 +116,26 @@ void main()
LightProbeSample samp = lightprobe_load(P, Ng, V);
for (int i = 0; i < LIGHT_CLOSURE_EVAL_COUNT && i < gbuf.closure_count; i++) {
switch (gbuf.closures[i].type) {
ClosureUndetermined cl = gbuffer_closure_get(gbuf, i);
switch (cl.type) {
case CLOSURE_BSDF_TRANSLUCENT_ID:
/* TODO: Support in ray tracing first. Otherwise we have a discrepancy. */
stack.cl[i].light_shadowed += lightprobe_eval(
samp, to_closure_translucent(gbuf.closures[i]), P, V, noise_probe);
samp, to_closure_translucent(cl), P, V, noise_probe);
break;
case CLOSURE_BSSRDF_BURLEY_ID:
/* TODO: Support translucency in ray tracing first. Otherwise we have a discrepancy. */
case CLOSURE_BSDF_DIFFUSE_ID:
stack.cl[i].light_shadowed += lightprobe_eval(
samp, to_closure_diffuse(gbuf.closures[i]), P, V, noise_probe);
samp, to_closure_diffuse(cl), P, V, noise_probe);
break;
case CLOSURE_BSDF_MICROFACET_GGX_REFLECTION_ID:
stack.cl[i].light_shadowed += lightprobe_eval(
samp, to_closure_reflection(gbuf.closures[i]), P, V, noise_probe);
samp, to_closure_reflection(cl), P, V, noise_probe);
break;
case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
stack.cl[i].light_shadowed += lightprobe_eval(
samp, to_closure_refraction(gbuf.closures[i]), P, V, noise_probe);
samp, to_closure_refraction(cl), P, V, noise_probe);
break;
case CLOSURE_NONE_ID:
/* TODO(fclem): Assert. */

View File

@@ -20,32 +20,47 @@ void main()
GBufferReader gbuf = gbuffer_read(gbuf_header_tx, gbuf_closure_tx, gbuf_normal_tx, texel);
vec3 P = drw_point_screen_to_world(vec3(uvcoordsvar.xy, depth));
vec3 Ng = gbuf.data.diffuse.N;
vec3 Ng = gbuf.surface_N;
vec3 V = drw_world_incident_vector(P);
float vPz = dot(drw_view_forward(), P) - dot(drw_view_forward(), drw_view_position());
ClosureLightStack stack;
stack.cl[0].N = gbuf.data.diffuse.N;
stack.cl[0].N = gbuf.surface_N;
stack.cl[0].ltc_mat = LTC_LAMBERT_MAT;
stack.cl[0].type = LIGHT_DIFFUSE;
stack.cl[1].N = gbuf.data.reflection.N;
stack.cl[1].ltc_mat = LTC_GGX_MAT(dot(gbuf.data.reflection.N, V),
gbuf.data.reflection.roughness);
stack.cl[1].type = LIGHT_SPECULAR;
stack.cl[1].N = -gbuf.surface_N;
stack.cl[1].ltc_mat = LTC_LAMBERT_MAT;
stack.cl[1].type = LIGHT_DIFFUSE;
/* Direct light. */
light_eval(stack, P, Ng, V, vPz, gbuf.data.thickness);
light_eval(stack, P, Ng, V, vPz, gbuf.thickness);
/* Indirect light. */
LightProbeSample samp = lightprobe_load(P, Ng, V);
SphericalHarmonicL1 sh = lightprobe_irradiance_sample(P, V, Ng);
vec3 radiance = vec3(0.0);
radiance += (stack.cl[0].light_shadowed +
lightprobe_eval(samp, gbuf.data.diffuse, P, V, vec2(0.0))) *
gbuf.data.diffuse.color;
radiance += (stack.cl[1].light_shadowed +
lightprobe_eval(samp, gbuf.data.reflection, P, V, vec2(0.0))) *
gbuf.data.reflection.color;
vec3 radiance_front = stack.cl[0].light_shadowed + spherical_harmonics_evaluate_lambert(Ng, sh);
vec3 radiance_back = stack.cl[1].light_shadowed + spherical_harmonics_evaluate_lambert(-Ng, sh);
out_radiance = vec4(radiance, 0.0);
vec3 albedo_front = vec3(0.0);
vec3 albedo_back = vec3(0.0);
for (int i = 0; i < GBUFFER_LAYER_MAX && i < gbuf.closure_count; i++) {
ClosureUndetermined cl = gbuffer_closure_get(gbuf, i);
switch (cl.type) {
case CLOSURE_BSSRDF_BURLEY_ID:
case CLOSURE_BSDF_DIFFUSE_ID:
case CLOSURE_BSDF_MICROFACET_GGX_REFLECTION_ID:
albedo_front += cl.color;
break;
case CLOSURE_BSDF_TRANSLUCENT_ID:
case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
albedo_back += cl.color;
break;
case CLOSURE_NONE_ID:
/* TODO(fclem): Assert. */
break;
}
}
out_radiance = vec4(radiance_front * albedo_front + radiance_back * albedo_back, 0.0);
}

View File

@@ -18,22 +18,18 @@ void main()
ivec2 tile_co = texel >> closure_tile_size_shift;
GBufferReader gbuf = gbuffer_read_header(in_gbuffer_header);
uint closure_count = gbuffer_closure_count(in_gbuffer_header);
if (gbuf.has_diffuse) {
if (closure_count > 0) {
imageStore(tile_mask_img, ivec3(tile_co, 0), uvec4(1u));
}
if (gbuf.has_reflection) {
if (closure_count > 1) {
imageStore(tile_mask_img, ivec3(tile_co, 1), uvec4(1u));
}
if (gbuf.has_refraction) {
if (closure_count > 2) {
imageStore(tile_mask_img, ivec3(tile_co, 2), uvec4(1u));
}
if (gbuf.has_translucent) {
imageStore(tile_mask_img, ivec3(tile_co, 3), uvec4(1u));
}
/* TODO(fclem): For now, override SSS if we have translucency. */
else if (gbuf.has_sss) {
if (closure_count > 3) {
imageStore(tile_mask_img, ivec3(tile_co, 3), uvec4(1u));
}
}

View File

@@ -31,18 +31,14 @@ void main()
uint closure_count = texelFetch(tile_mask_tx, ivec3(tile_coord, 0), 0).r +
texelFetch(tile_mask_tx, ivec3(tile_coord, 1), 0).r +
// texelFetch(tile_mask_tx, ivec3(tile_coord, 2), 0).r + /* TODO: refract */
texelFetch(tile_mask_tx, ivec3(tile_coord, 2), 0).r +
texelFetch(tile_mask_tx, ivec3(tile_coord, 3), 0).r;
/* TODO(fclem): This is waiting for fully flexible evaluation pipeline. We need to refactor the
* raytracing pipeline first. */
bool has_reflection = texelFetch(tile_mask_tx, ivec3(tile_coord, 1), 0).r != 0u;
bool has_sss = texelFetch(tile_mask_tx, ivec3(tile_coord, 3), 0).r != 0u;
if (closure_count == 3 || has_sss) {
if (closure_count == 3) {
uint tile_index = atomicAdd(closure_triple_draw_buf.vertex_len, 6u) / 6u;
closure_triple_tile_buf[tile_index] = packUvec2x16(uvec2(tile_coord));
}
else if (closure_count == 2 || has_reflection) {
else if (closure_count == 2) {
uint tile_index = atomicAdd(closure_double_draw_buf.vertex_len, 6u) / 6u;
closure_double_tile_buf[tile_index] = packUvec2x16(uvec2(tile_coord));
}

View File

@@ -17,7 +17,7 @@
*
* \{ */
#define GBUFFER_LAYER_MAX 4
#define GBUFFER_LAYER_MAX 3
#define GBUFFER_NORMAL_MAX GBUFFER_LAYER_MAX
#define GBUFFER_DATA_MAX (GBUFFER_LAYER_MAX * 2)
@@ -64,17 +64,14 @@ struct GBufferWriter {
/* Result of loading the GBuffer. */
struct GBufferReader {
GBufferData data;
ClosureUndetermined closures[GBUFFER_LAYER_MAX];
/* First world normal stored in the gbuffer. Only valid if `has_any_surface` is true. */
vec3 surface_N;
/* Additional object information if any closure needs it. */
float thickness;
uint object_id;
bool has_diffuse;
bool has_translucent;
bool has_reflection;
bool has_refraction;
bool has_sss;
bool has_any_surface;
uint header;
/* Number of valid closure encoded in the gbuffer. */
int closure_count;
/* Only used for book-keeping when reading. */
int layer_data;
@@ -297,51 +294,81 @@ void gbuffer_append_closure(inout GBufferWriter gbuf, GBufferMode closure_type)
gbuf.header |= gbuffer_header_pack(closure_type, gbuf.closure_count);
gbuf.closure_count++;
}
void gbuffer_register_closure(inout GBufferReader gbuf, ClosureUndetermined cl)
void gbuffer_register_closure(inout GBufferReader gbuf, ClosureUndetermined cl, int slot)
{
gbuf.closures[gbuf.closure_count] = cl;
gbuf.closure_count++;
switch (cl.type) {
case CLOSURE_NONE_ID:
/* TODO(fclem): Assert. */
switch (slot) {
#if GBUFFER_LAYER_MAX > 0
case 0:
gbuf.closures[0] = cl;
break;
case CLOSURE_BSSRDF_BURLEY_ID:
/* TODO(fclem): BSSSRDF closure. */
gbuf.data.diffuse.N = cl.N;
gbuf.data.diffuse.color = cl.color;
gbuf.data.diffuse.sss_radius = cl.data.xyz;
gbuf.has_diffuse = true;
gbuf.has_sss = true;
#endif
#if GBUFFER_LAYER_MAX > 1
case 1:
gbuf.closures[1] = cl;
break;
case CLOSURE_BSDF_DIFFUSE_ID:
gbuf.data.diffuse.N = cl.N;
gbuf.data.diffuse.color = cl.color;
gbuf.has_diffuse = true;
break;
case CLOSURE_BSDF_TRANSLUCENT_ID:
gbuf.data.translucent.N = cl.N;
gbuf.data.translucent.color = cl.color;
gbuf.has_translucent = true;
break;
case CLOSURE_BSDF_MICROFACET_GGX_REFLECTION_ID:
gbuf.data.reflection.N = cl.N;
gbuf.data.reflection.color = cl.color;
gbuf.data.reflection.roughness = cl.data.x;
gbuf.has_reflection = true;
break;
case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
gbuf.data.refraction.N = cl.N;
gbuf.data.refraction.color = cl.color;
gbuf.data.refraction.roughness = cl.data.x;
gbuf.data.refraction.ior = cl.data.y;
gbuf.has_refraction = true;
#endif
#if GBUFFER_LAYER_MAX > 2
case 2:
gbuf.closures[2] = cl;
break;
#endif
}
}
ClosureUndetermined gbuffer_closure_get(GBufferReader gbuf, int i)
{
switch (i) {
#if GBUFFER_LAYER_MAX > 0
case 0:
return gbuf.closures[0];
#endif
#if GBUFFER_LAYER_MAX > 1
case 1:
return gbuf.closures[1];
#endif
#if GBUFFER_LAYER_MAX > 2
case 2:
return gbuf.closures[2];
#endif
default:
return closure_new(CLOSURE_NONE_ID);
}
}
void gbuffer_append_data(inout GBufferWriter gbuf, vec4 data)
{
gbuf.data[gbuf.layer_data] = data;
switch (gbuf.layer_data) {
#if GBUFFER_DATA_MAX > 0
case 0:
gbuf.data[0] = data;
break;
#endif
#if GBUFFER_DATA_MAX > 1
case 1:
gbuf.data[1] = data;
break;
#endif
#if GBUFFER_DATA_MAX > 2
case 2:
gbuf.data[2] = data;
break;
#endif
#if GBUFFER_DATA_MAX > 3
case 3:
gbuf.data[3] = data;
break;
#endif
#if GBUFFER_DATA_MAX > 4
case 4:
gbuf.data[4] = data;
break;
#endif
#if GBUFFER_DATA_MAX > 5
case 5:
gbuf.data[5] = data;
break;
#endif
}
gbuf.layer_data++;
}
vec4 gbuffer_pop_first_data(inout GBufferReader gbuf, samplerGBufferClosure closure_tx)
@@ -353,7 +380,24 @@ vec4 gbuffer_pop_first_data(inout GBufferReader gbuf, samplerGBufferClosure clos
void gbuffer_append_normal(inout GBufferWriter gbuf, vec3 normal)
{
gbuf.N[gbuf.layer_normal] = gbuffer_normal_pack(normal);
vec2 packed_N = gbuffer_normal_pack(normal);
switch (gbuf.layer_normal) {
#if GBUFFER_NORMAL_MAX > 0
case 0:
gbuf.N[0] = packed_N;
break;
#endif
#if GBUFFER_NORMAL_MAX > 1
case 1:
gbuf.N[1] = packed_N;
break;
#endif
#if GBUFFER_NORMAL_MAX > 2
case 2:
gbuf.N[2] = packed_N;
break;
#endif
}
gbuf.layer_normal++;
}
vec3 gbuffer_pop_first_normal(inout GBufferReader gbuf, samplerGBufferNormal normal_tx)
@@ -374,8 +418,8 @@ void gbuffer_additional_info_load(inout GBufferReader gbuf, samplerGBufferNormal
{
vec2 data_packed = fetchGBuffer(normal_tx, gbuf.texel, gbuf.layer_normal).rg;
gbuf.layer_normal++;
gbuf.data.thickness = gbuffer_thickness_unpack(data_packed.x);
gbuf.data.object_id = gbuffer_object_id_unorm16_unpack(data_packed.y);
gbuf.thickness = gbuffer_thickness_unpack(data_packed.x);
gbuf.object_id = gbuffer_object_id_unorm16_unpack(data_packed.y);
}
/** \} */
@@ -393,6 +437,7 @@ void gbuffer_closure_diffuse_pack(inout GBufferWriter gbuf, ClosureUndetermined
}
void gbuffer_closure_diffuse_load(inout GBufferReader gbuf,
int layer,
samplerGBufferClosure closure_tx,
samplerGBufferNormal normal_tx)
{
@@ -402,7 +447,7 @@ void gbuffer_closure_diffuse_load(inout GBufferReader gbuf,
cl.color = gbuffer_closure_color_unpack(data0);
cl.N = gbuffer_pop_first_normal(gbuf, normal_tx);
gbuffer_register_closure(gbuf, cl);
gbuffer_register_closure(gbuf, cl, layer);
}
void gbuffer_closure_translucent_pack(inout GBufferWriter gbuf, ClosureUndetermined cl)
@@ -413,6 +458,7 @@ void gbuffer_closure_translucent_pack(inout GBufferWriter gbuf, ClosureUndetermi
}
void gbuffer_closure_translucent_load(inout GBufferReader gbuf,
int layer,
samplerGBufferClosure closure_tx,
samplerGBufferNormal normal_tx)
{
@@ -422,7 +468,7 @@ void gbuffer_closure_translucent_load(inout GBufferReader gbuf,
cl.color = gbuffer_closure_color_unpack(data0);
cl.N = gbuffer_pop_first_normal(gbuf, normal_tx);
gbuffer_register_closure(gbuf, cl);
gbuffer_register_closure(gbuf, cl, layer);
}
void gbuffer_closure_subsurface_pack(inout GBufferWriter gbuf, ClosureUndetermined cl)
@@ -434,6 +480,7 @@ void gbuffer_closure_subsurface_pack(inout GBufferWriter gbuf, ClosureUndetermin
}
void gbuffer_closure_subsurface_load(inout GBufferReader gbuf,
int layer,
samplerGBufferClosure closure_tx,
samplerGBufferNormal normal_tx)
{
@@ -445,7 +492,7 @@ void gbuffer_closure_subsurface_load(inout GBufferReader gbuf,
cl.data.rgb = gbuffer_sss_radii_unpack(data1);
cl.N = gbuffer_pop_first_normal(gbuf, normal_tx);
gbuffer_register_closure(gbuf, cl);
gbuffer_register_closure(gbuf, cl, layer);
}
void gbuffer_closure_reflection_pack(inout GBufferWriter gbuf, ClosureUndetermined cl)
@@ -457,6 +504,7 @@ void gbuffer_closure_reflection_pack(inout GBufferWriter gbuf, ClosureUndetermin
}
void gbuffer_closure_reflection_load(inout GBufferReader gbuf,
int layer,
samplerGBufferClosure closure_tx,
samplerGBufferNormal normal_tx)
{
@@ -468,7 +516,7 @@ void gbuffer_closure_reflection_load(inout GBufferReader gbuf,
cl.data.x = data1.x;
cl.N = gbuffer_pop_first_normal(gbuf, normal_tx);
gbuffer_register_closure(gbuf, cl);
gbuffer_register_closure(gbuf, cl, layer);
}
void gbuffer_closure_refraction_pack(inout GBufferWriter gbuf, ClosureUndetermined cl)
@@ -480,6 +528,7 @@ void gbuffer_closure_refraction_pack(inout GBufferWriter gbuf, ClosureUndetermin
}
void gbuffer_closure_refraction_load(inout GBufferReader gbuf,
int layer,
samplerGBufferClosure closure_tx,
samplerGBufferNormal normal_tx)
{
@@ -492,7 +541,7 @@ void gbuffer_closure_refraction_load(inout GBufferReader gbuf,
cl.data.y = gbuffer_ior_unpack(data1.y);
cl.N = gbuffer_pop_first_normal(gbuf, normal_tx);
gbuffer_register_closure(gbuf, cl);
gbuffer_register_closure(gbuf, cl, layer);
}
/** \} */
@@ -512,6 +561,7 @@ void gbuffer_closure_reflection_colorless_pack(inout GBufferWriter gbuf, Closure
}
void gbuffer_closure_reflection_colorless_load(inout GBufferReader gbuf,
int layer,
samplerGBufferClosure closure_tx,
samplerGBufferNormal normal_tx)
{
@@ -523,7 +573,7 @@ void gbuffer_closure_reflection_colorless_load(inout GBufferReader gbuf,
cl.N = gbuffer_pop_first_normal(gbuf, normal_tx);
gbuffer_register_closure(gbuf, cl);
gbuffer_register_closure(gbuf, cl, layer);
}
void gbuffer_closure_refraction_colorless_pack(inout GBufferWriter gbuf, ClosureUndetermined cl)
@@ -535,6 +585,7 @@ void gbuffer_closure_refraction_colorless_pack(inout GBufferWriter gbuf, Closure
}
void gbuffer_closure_refraction_colorless_load(inout GBufferReader gbuf,
int layer,
samplerGBufferClosure closure_tx,
samplerGBufferNormal normal_tx)
{
@@ -547,7 +598,7 @@ void gbuffer_closure_refraction_colorless_load(inout GBufferReader gbuf,
cl.N = gbuffer_pop_first_normal(gbuf, normal_tx);
gbuffer_register_closure(gbuf, cl);
gbuffer_register_closure(gbuf, cl, layer);
}
/** \} */
@@ -586,8 +637,8 @@ void gbuffer_closure_metal_clear_coat_load(inout GBufferReader gbuf,
coat.N = bottom.N = gbuffer_pop_first_normal(gbuf, normal_tx);
gbuffer_register_closure(gbuf, bottom);
gbuffer_register_closure(gbuf, coat);
gbuffer_register_closure(gbuf, bottom, 0);
gbuffer_register_closure(gbuf, coat, 1);
}
/** \} */
@@ -641,7 +692,8 @@ GBufferWriter gbuffer_pack(GBufferDataUndetermined data_in)
}
}
if (has_translucent) {
/* TODO(fclem): Allow misxing of translucent and refraction. */
if (has_translucent && !has_refraction) {
gbuffer_closure_translucent_pack(gbuf, data_in.translucent);
}
@@ -658,92 +710,53 @@ GBufferWriter gbuffer_pack(GBufferDataUndetermined data_in)
return gbuf;
}
/* Populate the GBufferReader only based on the header. The rest of the data is undefined. */
GBufferReader gbuffer_read_header(uint header)
/* Return the number of closure as encoded in the give header value. */
uint gbuffer_closure_count(uint header)
{
GBufferReader gbuf;
gbuf.header = header;
gbuf.has_any_surface = (header != 0u);
gbuf.has_diffuse = false;
gbuf.has_reflection = false;
gbuf.has_refraction = false;
gbuf.has_translucent = false;
gbuf.has_sss = false;
gbuf.closure_count = 0;
uvec4 closure_types = (uvec4(header) >> uvec4(0u, 4u, 8u, 12u)) & 15u;
for (int layer = 0; layer < 4; layer++) {
GBufferMode mode = gbuffer_header_unpack(gbuf.header, layer);
switch (mode) {
case GBUF_NONE:
break;
case GBUF_DIFFUSE:
gbuf.has_diffuse = true;
break;
case GBUF_TRANSLUCENT:
gbuf.has_translucent = true;
break;
case GBUF_SUBSURFACE:
gbuf.has_diffuse = true;
gbuf.has_sss = true;
break;
case GBUF_METAL_CLEARCOAT:
case GBUF_REFLECTION_COLORLESS:
case GBUF_REFLECTION:
gbuf.has_reflection = true;
break;
case GBUF_REFRACTION_COLORLESS:
case GBUF_REFRACTION:
gbuf.has_refraction = true;
break;
}
if (closure_types.x == GBUF_METAL_CLEARCOAT) {
return 2u;
}
return gbuf;
return reduce_add(vec4(not(equal(closure_types, uvec4(0u)))));
}
GBufferReader gbuffer_read_header_closure_types(uint header)
{
GBufferReader gbuf;
gbuf.header = header;
gbuf.has_any_surface = (header != 0u);
gbuf.closure_count = 0;
for (int layer = 0; layer < 4; layer++) {
GBufferMode mode = gbuffer_header_unpack(gbuf.header, layer);
for (int layer = 0; layer < GBUFFER_LAYER_MAX; layer++) {
GBufferMode mode = gbuffer_header_unpack(header, layer);
int closure_type = CLOSURE_NONE_ID;
switch (mode) {
case GBUF_NONE:
break;
case GBUF_DIFFUSE:
gbuf.closures[gbuf.closure_count].type = CLOSURE_BSDF_DIFFUSE_ID;
gbuf.closure_count += 1;
closure_type = CLOSURE_BSDF_DIFFUSE_ID;
gbuf.closure_count++;
break;
case GBUF_TRANSLUCENT:
gbuf.closures[gbuf.closure_count].type = CLOSURE_BSDF_TRANSLUCENT_ID;
gbuf.closure_count += 1;
closure_type = CLOSURE_BSDF_TRANSLUCENT_ID;
gbuf.closure_count++;
break;
case GBUF_SUBSURFACE:
gbuf.closures[gbuf.closure_count].type = CLOSURE_BSSRDF_BURLEY_ID;
gbuf.closure_count += 1;
break;
case GBUF_METAL_CLEARCOAT:
gbuf.closures[gbuf.closure_count].type = CLOSURE_BSDF_MICROFACET_GGX_REFLECTION_ID;
gbuf.closure_count += 1;
gbuf.closures[gbuf.closure_count].type = CLOSURE_BSDF_MICROFACET_GGX_REFLECTION_ID;
gbuf.closure_count += 1;
closure_type = CLOSURE_BSSRDF_BURLEY_ID;
gbuf.closure_count++;
break;
case GBUF_REFLECTION_COLORLESS:
case GBUF_REFLECTION:
gbuf.closures[gbuf.closure_count].type = CLOSURE_BSDF_MICROFACET_GGX_REFLECTION_ID;
gbuf.closure_count += 1;
closure_type = CLOSURE_BSDF_MICROFACET_GGX_REFLECTION_ID;
gbuf.closure_count++;
break;
case GBUF_REFRACTION_COLORLESS:
case GBUF_REFRACTION:
gbuf.closures[gbuf.closure_count].type = CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID;
gbuf.closure_count += 1;
closure_type = CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID;
gbuf.closure_count++;
break;
default:
break;
}
gbuffer_register_closure(gbuf, closure_new(closure_type), layer);
}
return gbuf;
}
@@ -754,82 +767,66 @@ GBufferReader gbuffer_read(samplerGBufferHeader header_tx,
{
GBufferReader gbuf;
gbuf.texel = texel;
gbuf.header = fetchGBuffer(header_tx, texel);
gbuf.has_any_surface = (gbuf.header != 0u);
gbuf.has_diffuse = false;
gbuf.has_reflection = false;
gbuf.has_refraction = false;
gbuf.has_translucent = false;
gbuf.has_sss = false;
gbuf.data.thickness = 0.0;
gbuf.thickness = 0.0;
gbuf.closure_count = 0;
gbuf.object_id = 0u;
gbuf.layer_data = 0;
gbuf.layer_normal = 0;
gbuf.surface_N = vec3(0.0);
if (!gbuf.has_any_surface) {
uint header = fetchGBuffer(header_tx, texel);
if (header == 0u) {
for (int layer = 0; layer < GBUFFER_LAYER_MAX; layer++) {
gbuffer_register_closure(gbuf, closure_new(CLOSURE_NONE_ID), layer);
}
return gbuf;
}
/* First closure is always written. */
gbuf.data.surface_N = gbuffer_normal_unpack(fetchGBuffer(normal_tx, texel, 0).xy);
/* Default values. */
gbuf.data.refraction.color = vec3(0.0);
gbuf.data.refraction.N = vec3(0.0, 0.0, 1.0);
gbuf.data.refraction.roughness = 0.0;
gbuf.data.refraction.ior = 1.1; /* Avoid NaN in some places. */
gbuf.data.reflection.color = vec3(0.0);
gbuf.data.reflection.N = vec3(0.0, 0.0, 1.0);
gbuf.data.reflection.roughness = 0.0;
gbuf.data.diffuse.color = vec3(0.0);
gbuf.data.diffuse.N = vec3(0.0, 0.0, 1.0);
gbuf.data.diffuse.sss_radius = vec3(0.0, 0.0, 0.0);
gbuf.data.diffuse.sss_id = 0u;
gbuf.data.translucent.color = vec3(0.0);
gbuf.data.translucent.N = vec3(0.0, 0.0, 1.0);
gbuf.data.thickness = 0.0;
gbuf.surface_N = gbuffer_normal_unpack(fetchGBuffer(normal_tx, texel, 0).xy);
bool has_additional_data = false;
for (int layer = 0; layer < GBUFFER_LAYER_MAX; layer++) {
gbuf.closures[layer].type = CLOSURE_NONE_ID;
}
for (int layer = 0; layer < GBUFFER_LAYER_MAX; layer++) {
GBufferMode mode = gbuffer_header_unpack(gbuf.header, layer);
GBufferMode mode = gbuffer_header_unpack(header, layer);
switch (mode) {
default:
case GBUF_NONE:
gbuffer_register_closure(gbuf, closure_new(CLOSURE_NONE_ID), layer);
break;
case GBUF_DIFFUSE:
gbuffer_closure_diffuse_load(gbuf, closure_tx, normal_tx);
gbuffer_closure_diffuse_load(gbuf, layer, closure_tx, normal_tx);
gbuf.closure_count++;
break;
case GBUF_TRANSLUCENT:
gbuffer_closure_translucent_load(gbuf, closure_tx, normal_tx);
gbuffer_closure_translucent_load(gbuf, layer, closure_tx, normal_tx);
gbuf.closure_count++;
has_additional_data = true;
break;
case GBUF_SUBSURFACE:
gbuffer_closure_subsurface_load(gbuf, closure_tx, normal_tx);
gbuffer_closure_subsurface_load(gbuf, layer, closure_tx, normal_tx);
gbuf.closure_count++;
has_additional_data = true;
break;
case GBUF_REFLECTION:
gbuffer_closure_reflection_load(gbuf, closure_tx, normal_tx);
gbuffer_closure_reflection_load(gbuf, layer, closure_tx, normal_tx);
gbuf.closure_count++;
break;
case GBUF_REFRACTION:
gbuffer_closure_refraction_load(gbuf, closure_tx, normal_tx);
gbuffer_closure_refraction_load(gbuf, layer, closure_tx, normal_tx);
gbuf.closure_count++;
break;
case GBUF_REFLECTION_COLORLESS:
gbuffer_closure_reflection_colorless_load(gbuf, closure_tx, normal_tx);
gbuffer_closure_reflection_colorless_load(gbuf, layer, closure_tx, normal_tx);
gbuf.closure_count++;
break;
case GBUF_REFRACTION_COLORLESS:
gbuffer_closure_refraction_colorless_load(gbuf, closure_tx, normal_tx);
break;
case GBUF_METAL_CLEARCOAT:
gbuffer_closure_metal_clear_coat_load(gbuf, closure_tx, normal_tx);
gbuffer_closure_refraction_colorless_load(gbuf, layer, closure_tx, normal_tx);
gbuf.closure_count++;
break;
}
}
if (gbuf.has_sss || gbuf.has_translucent) {
if (has_additional_data) {
gbuffer_additional_info_load(gbuf, normal_tx);
}

View File

@@ -46,12 +46,13 @@ void main()
EXPECT_EQ(g_data_packed.layer_data, 1);
EXPECT_EQ(data_out.closure_count, 1);
EXPECT_TRUE(data_out.has_any_surface);
EXPECT_TRUE(data_out.has_diffuse);
ClosureUndetermined out_diffuse = gbuffer_closure_get(data_out, 0);
EXPECT_EQ(out_diffuse.type, CLOSURE_BSDF_DIFFUSE_ID);
EXPECT_EQ(data_in.diffuse.type, CLOSURE_BSDF_DIFFUSE_ID);
EXPECT_NEAR(data_in.diffuse.color, data_out.data.diffuse.color, 1e-5);
EXPECT_NEAR(data_in.diffuse.N, data_out.data.diffuse.N, 1e-5);
EXPECT_NEAR(data_in.diffuse.color, out_diffuse.color, 1e-5);
EXPECT_NEAR(data_in.diffuse.N, out_diffuse.N, 1e-5);
}
TEST(eevee_gbuffer, ClosureSubsurface)
@@ -68,14 +69,14 @@ void main()
EXPECT_EQ(g_data_packed.layer_data, 2);
EXPECT_EQ(data_out.closure_count, 1);
EXPECT_TRUE(data_out.has_any_surface);
EXPECT_TRUE(data_out.has_diffuse);
EXPECT_TRUE(data_out.has_sss);
ClosureUndetermined out_sss_burley = gbuffer_closure_get(data_out, 0);
EXPECT_EQ(out_sss_burley.type, CLOSURE_BSSRDF_BURLEY_ID);
EXPECT_EQ(data_in.diffuse.type, CLOSURE_BSSRDF_BURLEY_ID);
EXPECT_NEAR(data_in.diffuse.color, data_out.data.diffuse.color, 1e-5);
EXPECT_NEAR(data_in.diffuse.N, data_out.data.diffuse.N, 1e-5);
EXPECT_NEAR(data_in.diffuse.data.rgb, data_out.data.diffuse.sss_radius, 1e-5);
EXPECT_NEAR(data_in.diffuse.color, out_sss_burley.color, 1e-5);
EXPECT_NEAR(data_in.diffuse.N, out_sss_burley.N, 1e-5);
EXPECT_NEAR(data_in.diffuse.data.rgb, to_closure_diffuse(out_sss_burley).sss_radius, 1e-5);
}
TEST(eevee_gbuffer, ClosureTranslucent)
@@ -91,12 +92,13 @@ void main()
EXPECT_EQ(g_data_packed.layer_data, 1);
EXPECT_EQ(data_out.closure_count, 1);
EXPECT_TRUE(data_out.has_any_surface);
EXPECT_TRUE(data_out.has_translucent);
ClosureUndetermined out_translucent = gbuffer_closure_get(data_out, 0);
EXPECT_EQ(out_translucent.type, CLOSURE_BSDF_TRANSLUCENT_ID);
EXPECT_EQ(data_in.translucent.type, CLOSURE_BSDF_TRANSLUCENT_ID);
EXPECT_NEAR(data_in.translucent.color, data_out.data.translucent.color, 1e-5);
EXPECT_NEAR(data_in.translucent.N, data_out.data.translucent.N, 1e-5);
EXPECT_NEAR(data_in.translucent.color, out_translucent.color, 1e-5);
EXPECT_NEAR(data_in.translucent.N, out_translucent.N, 1e-5);
}
TEST(eevee_gbuffer, ClosureReflection)
@@ -113,13 +115,14 @@ void main()
EXPECT_EQ(g_data_packed.layer_data, 2);
EXPECT_EQ(data_out.closure_count, 1);
EXPECT_TRUE(data_out.has_any_surface);
EXPECT_TRUE(data_out.has_reflection);
ClosureUndetermined out_reflection = gbuffer_closure_get(data_out, 0);
EXPECT_EQ(out_reflection.type, CLOSURE_BSDF_MICROFACET_GGX_REFLECTION_ID);
EXPECT_EQ(data_in.reflection.type, CLOSURE_BSDF_MICROFACET_GGX_REFLECTION_ID);
EXPECT_NEAR(data_in.reflection.color, data_out.data.reflection.color, 1e-5);
EXPECT_NEAR(data_in.reflection.N, data_out.data.reflection.N, 1e-5);
EXPECT_NEAR(data_in.reflection.data.r, data_out.data.reflection.roughness, 1e-5);
EXPECT_NEAR(data_in.reflection.color, out_reflection.color, 1e-5);
EXPECT_NEAR(data_in.reflection.N, out_reflection.N, 1e-5);
EXPECT_NEAR(data_in.reflection.data.r, out_reflection.data.r, 1e-5);
}
TEST(eevee_gbuffer, ClosureRefraction)
@@ -137,14 +140,15 @@ void main()
EXPECT_EQ(g_data_packed.layer_data, 2);
EXPECT_EQ(data_out.closure_count, 1);
EXPECT_TRUE(data_out.has_any_surface);
EXPECT_TRUE(data_out.has_refraction);
ClosureUndetermined out_refraction = gbuffer_closure_get(data_out, 0);
EXPECT_EQ(out_refraction.type, CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID);
EXPECT_EQ(data_in.refraction.type, CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID);
EXPECT_NEAR(data_in.refraction.color, data_out.data.refraction.color, 1e-5);
EXPECT_NEAR(data_in.refraction.N, data_out.data.refraction.N, 1e-5);
EXPECT_NEAR(data_in.refraction.data.r, data_out.data.refraction.roughness, 1e-5);
EXPECT_NEAR(data_in.refraction.data.g, data_out.data.refraction.ior, 1e-5);
EXPECT_NEAR(data_in.refraction.color, out_refraction.color, 1e-5);
EXPECT_NEAR(data_in.refraction.N, out_refraction.N, 1e-5);
EXPECT_NEAR(data_in.refraction.data.r, out_refraction.data.r, 1e-5);
EXPECT_NEAR(data_in.refraction.data.g, out_refraction.data.g, 1e-5);
}
TEST(eevee_gbuffer, ClosureCombination)
@@ -170,20 +174,22 @@ void main()
data_out = gbuffer_read(header_tx, closure_tx, normal_tx, ivec2(0));
EXPECT_EQ(data_out.closure_count, 2);
EXPECT_TRUE(data_out.has_any_surface);
EXPECT_TRUE(data_out.has_refraction);
EXPECT_TRUE(data_out.has_reflection);
ClosureUndetermined out_reflection = gbuffer_closure_get(data_out, 1);
ClosureUndetermined out_refraction = gbuffer_closure_get(data_out, 0);
EXPECT_EQ(out_refraction.type, CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID);
EXPECT_EQ(data_in.refraction.type, CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID);
EXPECT_NEAR(data_in.refraction.color, data_out.data.refraction.color, 1e-5);
EXPECT_NEAR(data_in.refraction.N, data_out.data.refraction.N, 1e-5);
EXPECT_NEAR(data_in.refraction.data.r, data_out.data.refraction.roughness, 1e-5);
EXPECT_NEAR(data_in.refraction.data.g, data_out.data.refraction.ior, 1e-5);
EXPECT_NEAR(data_in.refraction.color, out_refraction.color, 1e-5);
EXPECT_NEAR(data_in.refraction.N, out_refraction.N, 1e-5);
EXPECT_NEAR(data_in.refraction.data.r, out_refraction.data.r, 1e-5);
EXPECT_NEAR(data_in.refraction.data.g, out_refraction.data.g, 1e-5);
EXPECT_EQ(out_reflection.type, CLOSURE_BSDF_MICROFACET_GGX_REFLECTION_ID);
EXPECT_EQ(data_in.reflection.type, CLOSURE_BSDF_MICROFACET_GGX_REFLECTION_ID);
EXPECT_NEAR(data_in.reflection.color, data_out.data.reflection.color, 1e-5);
EXPECT_NEAR(data_in.reflection.N, data_out.data.reflection.N, 1e-5);
EXPECT_NEAR(data_in.reflection.data.r, data_out.data.reflection.roughness, 1e-5);
EXPECT_NEAR(data_in.reflection.color, out_reflection.color, 1e-5);
EXPECT_NEAR(data_in.reflection.N, out_reflection.N, 1e-5);
EXPECT_NEAR(data_in.reflection.data.r, out_reflection.data.r, 1e-5);
}
TEST(eevee_gbuffer, ClosureColorless)
@@ -209,19 +215,21 @@ void main()
data_out = gbuffer_read(header_tx, closure_tx, normal_tx, ivec2(0));
EXPECT_EQ(data_out.closure_count, 2);
EXPECT_TRUE(data_out.has_any_surface);
EXPECT_TRUE(data_out.has_refraction);
EXPECT_TRUE(data_out.has_reflection);
ClosureUndetermined out_reflection = gbuffer_closure_get(data_out, 1);
ClosureUndetermined out_refraction = gbuffer_closure_get(data_out, 0);
EXPECT_EQ(out_refraction.type, CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID);
EXPECT_EQ(data_in.refraction.type, CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID);
EXPECT_NEAR(data_in.refraction.color, data_out.data.refraction.color, 1e-5);
EXPECT_NEAR(data_in.refraction.N, data_out.data.refraction.N, 1e-5);
EXPECT_NEAR(data_in.refraction.data.r, data_out.data.refraction.roughness, 1e-5);
EXPECT_NEAR(data_in.refraction.data.g, data_out.data.refraction.ior, 1e-5);
EXPECT_NEAR(data_in.refraction.color, out_refraction.color, 1e-5);
EXPECT_NEAR(data_in.refraction.N, out_refraction.N, 1e-5);
EXPECT_NEAR(data_in.refraction.data.r, out_refraction.data.r, 1e-5);
EXPECT_NEAR(data_in.refraction.data.g, out_refraction.data.g, 1e-5);
EXPECT_EQ(out_reflection.type, CLOSURE_BSDF_MICROFACET_GGX_REFLECTION_ID);
EXPECT_EQ(data_in.reflection.type, CLOSURE_BSDF_MICROFACET_GGX_REFLECTION_ID);
EXPECT_NEAR(data_in.reflection.color, data_out.data.reflection.color, 1e-5);
EXPECT_NEAR(data_in.reflection.N, data_out.data.reflection.N, 1e-5);
EXPECT_NEAR(data_in.reflection.data.r, data_out.data.reflection.roughness, 1e-5);
EXPECT_NEAR(data_in.reflection.color, out_reflection.color, 1e-5);
EXPECT_NEAR(data_in.reflection.N, out_reflection.N, 1e-5);
EXPECT_NEAR(data_in.reflection.data.r, out_reflection.data.r, 1e-5);
}
}

View File

@@ -56,7 +56,7 @@ vec3 from_accumulation_space(vec3 color)
vec3 load_normal(ivec2 texel)
{
return gbuffer_read(gbuf_header_tx, gbuf_closure_tx, gbuf_normal_tx, texel).data.surface_N;
return gbuffer_read(gbuf_header_tx, gbuf_closure_tx, gbuf_normal_tx, texel).surface_N;
}
void main()
@@ -93,7 +93,7 @@ void main()
return;
}
ClosureUndetermined closure_center = gbuf.closures[closure_index];
ClosureUndetermined closure_center = gbuffer_closure_get(gbuf, closure_index);
vec3 center_N = closure_center.N;
float roughness = closure_apparent_roughness_get(closure_center);

View File

@@ -47,7 +47,7 @@ void main()
}
HorizonScanContext ctx;
ctx.closure = gbuf.closures[closure_index];
ctx.closure = gbuffer_closure_get(gbuf, closure_index);
ctx.closure.N = drw_normal_world_to_view(ctx.closure.N);
vec3 vP = drw_point_screen_to_view(vec3(uv, depth));

View File

@@ -23,7 +23,7 @@ void main()
gbuf_header_tx, gbuf_closure_tx, gbuf_normal_tx, texel_fullres);
/* Export normal. */
vec3 N = gbuf.data.surface_N;
vec3 N = gbuf.surface_N;
if (is_zero(N)) {
/* Avoid NaN. But should be fixed in any case. */
N = vec3(1.0, 0.0, 0.0);

View File

@@ -85,7 +85,7 @@ void main()
return;
}
ClosureUndetermined center_closure = gbuf.closures[closure_index];
ClosureUndetermined center_closure = gbuffer_closure_get(gbuf, closure_index);
float roughness = closure_apparent_roughness_get(center_closure);
float variance = imageLoad(in_variance_img, texel_fullres).r;
@@ -149,7 +149,7 @@ void main()
continue;
}
ClosureUndetermined sample_closure = sample_gbuf.closures[closure_index];
ClosureUndetermined sample_closure = gbuffer_closure_get(sample_gbuf, closure_index);
float depth_weight = bilateral_depth_weight(center_closure.N, center_P, sample_P);
float spatial_weight = bilateral_spatial_weight(filter_size, vec2(offset));

View File

@@ -126,7 +126,7 @@ void main()
vec3 P = drw_point_screen_to_world(vec3(uv, 0.5));
vec3 V = drw_world_incident_vector(P);
ClosureUndetermined closure = gbuf.closures[closure_index];
ClosureUndetermined closure = gbuffer_closure_get(gbuf, closure_index);
/* Compute filter size and needed sample count */
float apparent_roughness = closure_apparent_roughness_get(closure);

View File

@@ -35,7 +35,7 @@ void main()
vec3 V = drw_world_incident_vector(P);
vec2 noise = utility_tx_fetch(utility_tx, vec2(texel), UTIL_BLUE_NOISE_LAYER).rg;
BsdfSample samp = ray_generate_direction(noise.xy, gbuf.closures[closure_index], V);
BsdfSample samp = ray_generate_direction(noise.xy, gbuffer_closure_get(gbuf, closure_index), V);
/* Store inverse pdf to speedup denoising.
* Limit to the smallest non-0 value that the format can encode.

View File

@@ -13,8 +13,8 @@
#pragma BLENDER_REQUIRE(eevee_gbuffer_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_closure_lib.glsl)
shared uint tile_contains_ray_tracing[3];
shared uint tile_contains_horizon_scan[3];
shared uint tile_contains_ray_tracing[GBUFFER_LAYER_MAX];
shared uint tile_contains_horizon_scan[GBUFFER_LAYER_MAX];
/* Returns a blend factor between different tracing method. */
float ray_roughness_factor(RayTraceData raytrace, float roughness)
@@ -26,7 +26,7 @@ void main()
{
if (gl_LocalInvocationIndex == 0u) {
/* Init shared variables. */
for (int i = 0; i < 3; i++) {
for (int i = 0; i < GBUFFER_LAYER_MAX; i++) {
tile_contains_ray_tracing[i] = 0;
tile_contains_horizon_scan[i] = 0;
}
@@ -41,8 +41,12 @@ void main()
if (valid_texel) {
GBufferReader gbuf = gbuffer_read(gbuf_header_tx, gbuf_closure_tx, gbuf_normal_tx, texel);
for (int i = 0; i < 3 && i < gbuf.closure_count; i++) {
float roughness = closure_apparent_roughness_get(gbuf.closures[i]);
for (int i = 0; i < GBUFFER_LAYER_MAX; i++) {
ClosureUndetermined cl = gbuffer_closure_get(gbuf, i);
if (cl.type == CLOSURE_NONE_ID) {
break;
}
float roughness = closure_apparent_roughness_get(cl);
float ray_roughness_fac = ray_roughness_factor(uniform_buf.raytrace, roughness);
/* We don't care about race condition here. */
@@ -61,7 +65,7 @@ void main()
ivec2 denoise_tile_co = ivec2(gl_WorkGroupID.xy);
ivec2 tracing_tile_co = denoise_tile_co / uniform_buf.raytrace.resolution_scale;
for (int i = 0; i < 3; i++) {
for (int i = 0; i < GBUFFER_LAYER_MAX; i++) {
if (tile_contains_ray_tracing[i] > 0) {
imageStore(tile_raytrace_denoise_img, ivec3(denoise_tile_co, i), uvec4(1));
imageStore(tile_raytrace_tracing_img, ivec3(tracing_tile_co, i), uvec4(1));

View File

@@ -42,7 +42,7 @@ void main()
uint gbuf_header = texelFetch(gbuf_header_tx, texel_fullres, 0).r;
GBufferReader gbuf = gbuffer_read_header_closure_types(gbuf_header);
uint closure_type = gbuf.closures[closure_index].type;
uint closure_type = gbuffer_closure_get(gbuf, closure_index).type;
if ((closure_type == CLOSURE_BSDF_TRANSLUCENT_ID) ||
(closure_type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID))

View File

@@ -44,7 +44,7 @@ void main()
uint gbuf_header = texelFetch(gbuf_header_tx, texel_fullres, 0).r;
GBufferReader gbuf = gbuffer_read_header_closure_types(gbuf_header);
uint closure_type = gbuf.closures[closure_index].type;
uint closure_type = gbuffer_closure_get(gbuf, closure_index).type;
bool is_reflection = true;
if ((closure_type == CLOSURE_BSDF_TRANSLUCENT_ID) ||

View File

@@ -93,12 +93,14 @@ void main(void)
vec3 vP = drw_point_screen_to_view(vec3(center_uv, depth));
GBufferReader gbuf = gbuffer_read(gbuf_header_tx, gbuf_closure_tx, gbuf_normal_tx, texel);
if (!gbuf.has_sss) {
if (gbuffer_closure_get(gbuf, 0).type != CLOSURE_BSSRDF_BURLEY_ID) {
return;
}
float max_radius = reduce_max(gbuf.data.diffuse.sss_radius);
/* TODO SSS closure. */
ClosureDiffuse closure = to_closure_diffuse(gbuffer_closure_get(gbuf, 0));
float max_radius = reduce_max(closure.sss_radius);
float homcoord = ProjectionMatrix[2][3] * vP.z + ProjectionMatrix[3][3];
vec2 sample_scale = vec2(ProjectionMatrix[0][0], ProjectionMatrix[1][1]) *
@@ -111,10 +113,9 @@ void main(void)
}
/* Avoid too small radii that have float imprecision. */
vec3 clamped_sss_radius = max(vec3(1e-4), gbuf.data.diffuse.sss_radius / max_radius) *
max_radius;
vec3 clamped_sss_radius = max(vec3(1e-4), closure.sss_radius / max_radius) * max_radius;
/* Scale albedo because we can have HDR value caused by BSDF sampling. */
vec3 albedo = gbuf.data.diffuse.color / max(1e-6, reduce_max(gbuf.data.diffuse.color));
vec3 albedo = closure.color / max(1e-6, reduce_max(closure.color));
vec3 d = burley_setup(clamped_sss_radius, albedo);
/* Do not rotate too much to avoid too much cache misses. */
@@ -132,7 +133,7 @@ void main(void)
SubSurfaceSample samp = sample_neighborhood(sample_uv);
/* Reject radiance from other surfaces. Avoids light leak between objects. */
if (samp.sss_id != gbuf.data.object_id) {
if (samp.sss_id != gbuf.object_id) {
continue;
}
/* Slide 34. */

View File

@@ -25,14 +25,17 @@ void main(void)
GBufferReader gbuf = gbuffer_read(gbuf_header_tx, gbuf_closure_tx, gbuf_normal_tx, texel);
if (gbuf.has_sss) {
if (gbuffer_closure_get(gbuf, 0).type == CLOSURE_BSSRDF_BURLEY_ID) {
/* TODO SSS closure. */
vec3 radiance = imageLoad(direct_light_img, texel).rgb +
imageLoad(indirect_light_img, texel).rgb;
float max_radius = reduce_max(gbuf.data.diffuse.sss_radius);
ClosureDiffuse closure = to_closure_diffuse(gbuffer_closure_get(gbuf, 0));
float max_radius = reduce_max(closure.sss_radius);
imageStore(radiance_img, texel, vec4(radiance, 0.0));
imageStore(object_id_img, texel, uvec4(gbuf.data.object_id));
imageStore(object_id_img, texel, uvec4(gbuf.object_id));
vec2 center_uv = (vec2(texel) + 0.5) / vec2(textureSize(gbuf_header_tx, 0));
float depth = texelFetch(depth_tx, texel, 0).r;

View File

@@ -127,6 +127,7 @@ GPU_SHADER_CREATE_INFO(eevee_deferred_capture_eval)
/* Inputs. */
.fragment_out(0, Type::VEC4, "out_radiance")
.define("SHADOW_SUBSURFACE")
.define("LIGHT_CLOSURE_EVAL_COUNT", "2")
.additional_info("eevee_shared",
"eevee_gbuffer_data",
"eevee_utility_texture",