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:
committed by
Clément Foucault
parent
6f51d7332b
commit
f2b3403145
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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) ||
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user