EEVEE-Next: Remove Light eval hard coded closures
Related to #115966 Allows for multiple evaluation of the same closure (i.e: metal + clearcoat). Pull Request: https://projects.blender.org/blender/blender/pulls/116478
This commit is contained in:
committed by
Clément Foucault
parent
df91fb329e
commit
dc155e2ae4
@@ -11,48 +11,77 @@
|
||||
#pragma BLENDER_REQUIRE(eevee_renderpass_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_colorspace_lib.glsl)
|
||||
|
||||
vec3 load_radiance_direct(ivec2 texel, int i)
|
||||
{
|
||||
/* TODO(fclem): Layered texture. */
|
||||
switch (i) {
|
||||
case 0:
|
||||
return imageLoad(direct_radiance_1_img, texel).rgb;
|
||||
case 1:
|
||||
return imageLoad(direct_radiance_2_img, texel).rgb;
|
||||
case 2:
|
||||
return imageLoad(direct_radiance_3_img, texel).rgb;
|
||||
default:
|
||||
return vec3(0);
|
||||
}
|
||||
return vec3(0);
|
||||
}
|
||||
|
||||
vec3 load_radiance_indirect(ivec2 texel, ClosureType closure_type)
|
||||
{
|
||||
/* TODO(fclem): Layered texture. */
|
||||
switch (closure_type) {
|
||||
case CLOSURE_BSSRDF_BURLEY_ID:
|
||||
case CLOSURE_BSDF_DIFFUSE_ID:
|
||||
return imageLoad(indirect_diffuse_img, texel).rgb;
|
||||
case CLOSURE_BSDF_MICROFACET_GGX_REFLECTION_ID:
|
||||
return imageLoad(indirect_reflect_img, texel).rgb;
|
||||
case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
|
||||
return imageLoad(indirect_refract_img, texel).rgb;
|
||||
default:
|
||||
return vec3(0);
|
||||
}
|
||||
return vec3(0);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
ivec2 texel = ivec2(gl_FragCoord.xy);
|
||||
|
||||
GBufferReader gbuf = gbuffer_read(gbuf_header_tx, gbuf_closure_tx, gbuf_normal_tx, texel);
|
||||
|
||||
vec3 glossy_reflect_light = vec3(0.0);
|
||||
vec3 glossy_refract_light = vec3(0.0);
|
||||
vec3 diffuse_reflect_light = vec3(0.0);
|
||||
vec3 diffuse_refract_light = vec3(0.0);
|
||||
out_combined = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
vec3 out_diffuse = vec3(0.0);
|
||||
vec3 out_specular = vec3(0.0);
|
||||
|
||||
if (gbuf.has_diffuse) {
|
||||
diffuse_reflect_light = imageLoad(direct_radiance_1_img, texel).rgb +
|
||||
imageLoad(indirect_diffuse_img, texel).rgb;
|
||||
}
|
||||
|
||||
if (gbuf.has_reflection) {
|
||||
glossy_reflect_light = imageLoad(direct_radiance_2_img, texel).rgb +
|
||||
imageLoad(indirect_reflect_img, texel).rgb;
|
||||
}
|
||||
|
||||
if (gbuf.has_translucent) {
|
||||
/* Indirect radiance not implemented yet. */
|
||||
diffuse_refract_light = imageLoad(direct_radiance_3_img, texel).rgb;
|
||||
}
|
||||
|
||||
if (gbuf.has_refraction) {
|
||||
/* Direct radiance not implemented yet. */
|
||||
glossy_refract_light = imageLoad(indirect_refract_img, texel).rgb;
|
||||
for (int i = 0; i < GBUFFER_LAYER_MAX && i < gbuf.closure_count; i++) {
|
||||
vec3 closure_light = load_radiance_direct(texel, i) +
|
||||
load_radiance_indirect(texel, gbuf.closures[i].type);
|
||||
|
||||
closure_light *= gbuf.closures[i].color;
|
||||
out_combined.rgb += closure_light;
|
||||
|
||||
switch (gbuf.closures[i].type) {
|
||||
case CLOSURE_BSDF_TRANSLUCENT_ID:
|
||||
case CLOSURE_BSSRDF_BURLEY_ID:
|
||||
case CLOSURE_BSDF_DIFFUSE_ID:
|
||||
out_diffuse += closure_light;
|
||||
break;
|
||||
case CLOSURE_BSDF_MICROFACET_GGX_REFLECTION_ID:
|
||||
case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
|
||||
out_specular += closure_light;
|
||||
break;
|
||||
case CLOSURE_NONE_ID:
|
||||
/* TODO(fclem): Assert. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#if 1 /* TODO(fclem): Only if needed. */
|
||||
/* Light passes. */
|
||||
vec3 diffuse_light = diffuse_reflect_light + diffuse_refract_light;
|
||||
vec3 specular_light = glossy_reflect_light + glossy_refract_light;
|
||||
output_renderpass_color(uniform_buf.render_pass.diffuse_light_id, vec4(diffuse_light, 1.0));
|
||||
output_renderpass_color(uniform_buf.render_pass.specular_light_id, vec4(specular_light, 1.0));
|
||||
/* Combine. */
|
||||
out_combined = vec4(0.0);
|
||||
out_combined.xyz += diffuse_reflect_light * gbuf.data.diffuse.color;
|
||||
out_combined.xyz += diffuse_refract_light * gbuf.data.translucent.color;
|
||||
out_combined.xyz += glossy_reflect_light * gbuf.data.reflection.color;
|
||||
out_combined.xyz += glossy_refract_light * gbuf.data.refraction.color;
|
||||
output_renderpass_color(uniform_buf.render_pass.diffuse_light_id, vec4(out_diffuse, 1.0));
|
||||
output_renderpass_color(uniform_buf.render_pass.specular_light_id, vec4(out_specular, 1.0));
|
||||
#endif
|
||||
|
||||
if (any(isnan(out_combined))) {
|
||||
out_combined = vec4(1.0, 0.0, 1.0, 0.0);
|
||||
|
||||
@@ -13,6 +13,33 @@
|
||||
#pragma BLENDER_REQUIRE(eevee_thickness_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_subsurface_lib.glsl)
|
||||
|
||||
ClosureLight closure_light_new(ClosureUndetermined cl, vec3 V)
|
||||
{
|
||||
ClosureLight cl_light;
|
||||
cl_light.N = cl.N;
|
||||
cl_light.ltc_mat = LTC_LAMBERT_MAT;
|
||||
cl_light.type = LIGHT_DIFFUSE;
|
||||
switch (cl.type) {
|
||||
case CLOSURE_BSDF_TRANSLUCENT_ID:
|
||||
cl_light.N = -cl.N;
|
||||
break;
|
||||
case CLOSURE_BSSRDF_BURLEY_ID:
|
||||
case CLOSURE_BSDF_DIFFUSE_ID:
|
||||
break;
|
||||
case CLOSURE_BSDF_MICROFACET_GGX_REFLECTION_ID:
|
||||
cl_light.ltc_mat = LTC_GGX_MAT(dot(cl.N, V), cl.data.x);
|
||||
cl_light.type = LIGHT_SPECULAR;
|
||||
break;
|
||||
case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
|
||||
cl_light.type = LIGHT_SPECULAR;
|
||||
break;
|
||||
case CLOSURE_NONE_ID:
|
||||
/* TODO(fclem): Assert. */
|
||||
break;
|
||||
}
|
||||
return cl_light;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
ivec2 texel = ivec2(gl_FragCoord.xy);
|
||||
@@ -25,46 +52,16 @@ void main()
|
||||
}
|
||||
|
||||
vec3 P = drw_point_screen_to_world(vec3(uvcoordsvar.xy, depth));
|
||||
/* Assume reflection closure normal is always somewhat representative of the geometric normal.
|
||||
* Ng is only used for shadow biases and subsurface check in this case. */
|
||||
vec3 Ng = gbuf.data.surface_N;
|
||||
vec3 V = drw_world_incident_vector(P);
|
||||
float vPz = dot(drw_view_forward(), P) - dot(drw_view_forward(), drw_view_position());
|
||||
|
||||
ClosureLight cl_diff;
|
||||
cl_diff.N = gbuf.data.diffuse.N;
|
||||
cl_diff.ltc_mat = LTC_LAMBERT_MAT;
|
||||
cl_diff.type = LIGHT_DIFFUSE;
|
||||
|
||||
ClosureLight cl_refl;
|
||||
cl_refl.N = gbuf.data.reflection.N;
|
||||
cl_refl.ltc_mat = LTC_GGX_MAT(dot(gbuf.data.reflection.N, V), gbuf.data.reflection.roughness);
|
||||
cl_refl.type = LIGHT_SPECULAR;
|
||||
|
||||
ClosureLight cl_sss;
|
||||
cl_sss.N = -gbuf.data.diffuse.N;
|
||||
cl_sss.ltc_mat = LTC_LAMBERT_MAT;
|
||||
cl_sss.type = LIGHT_DIFFUSE;
|
||||
|
||||
ClosureLight cl_translucent;
|
||||
cl_translucent.N = -gbuf.data.translucent.N;
|
||||
cl_translucent.ltc_mat = LTC_LAMBERT_MAT;
|
||||
cl_translucent.type = LIGHT_DIFFUSE;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/* TODO(fclem): This is waiting for fully flexible evaluation pipeline. We need to refactor the
|
||||
* raytracing pipeline first. */
|
||||
stack.cl[0] = (gbuf.has_diffuse) ? cl_diff : cl_refl;
|
||||
|
||||
#if LIGHT_CLOSURE_EVAL_COUNT > 1
|
||||
stack.cl[1] = cl_refl;
|
||||
#endif
|
||||
|
||||
#if LIGHT_CLOSURE_EVAL_COUNT > 2
|
||||
stack.cl[2] = (gbuf.has_translucent) ? cl_translucent : cl_sss;
|
||||
#endif
|
||||
|
||||
/* TODO(fclem): Split thickness computation. */
|
||||
float thickness = (gbuf.has_translucent) ? gbuf.data.thickness : 0.0;
|
||||
#ifdef MAT_SUBSURFACE
|
||||
if (gbuf.has_sss) {
|
||||
@@ -72,57 +69,57 @@ void main()
|
||||
thickness = (shadow_thickness != THICKNESS_NO_VALUE) ?
|
||||
max(shadow_thickness, gbuf.data.thickness) :
|
||||
gbuf.data.thickness;
|
||||
|
||||
/* Add one translucent closure for all SSS closure. Reuse the same lighting. */
|
||||
ClosureLight cl_light;
|
||||
cl_light.N = -Ng;
|
||||
cl_light.ltc_mat = LTC_LAMBERT_MAT;
|
||||
cl_light.type = LIGHT_DIFFUSE;
|
||||
stack.cl[gbuf.closure_count] = cl_light;
|
||||
}
|
||||
#endif
|
||||
|
||||
light_eval(stack, P, Ng, V, vPz, thickness);
|
||||
|
||||
vec3 radiance_shadowed = stack.cl[0].light_shadowed;
|
||||
vec3 radiance_unshadowed = stack.cl[0].light_unshadowed;
|
||||
#if LIGHT_CLOSURE_EVAL_COUNT > 1
|
||||
radiance_shadowed += stack.cl[1].light_shadowed;
|
||||
radiance_unshadowed += stack.cl[1].light_unshadowed;
|
||||
#endif
|
||||
#if LIGHT_CLOSURE_EVAL_COUNT > 2
|
||||
radiance_shadowed += stack.cl[2].light_shadowed;
|
||||
radiance_unshadowed += stack.cl[2].light_unshadowed;
|
||||
#endif
|
||||
|
||||
#ifdef MAT_SUBSURFACE
|
||||
if (gbuf.has_sss) {
|
||||
vec3 sss_profile = subsurface_transmission(gbuf.data.diffuse.sss_radius, thickness);
|
||||
stack.cl[2].light_shadowed *= sss_profile;
|
||||
stack.cl[2].light_unshadowed *= sss_profile;
|
||||
/* Add to diffuse light for processing inside the Screen Space SSS pass. */
|
||||
stack.cl[0].light_shadowed += stack.cl[2].light_shadowed;
|
||||
stack.cl[0].light_unshadowed += stack.cl[2].light_unshadowed;
|
||||
for (int i = 0; i < LIGHT_CLOSURE_EVAL_COUNT && i < gbuf.closure_count; i++) {
|
||||
/* 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. */
|
||||
if (gbuf.closures[i].type == CLOSURE_BSSRDF_BURLEY_ID) {
|
||||
/* Apply absorption per closure. */
|
||||
vec3 sss_profile = subsurface_transmission(gbuf.closures[i].data.rgb, thickness);
|
||||
stack.cl[i].light_shadowed += stack.cl[gbuf.closure_count].light_shadowed * sss_profile;
|
||||
stack.cl[i].light_unshadowed += stack.cl[gbuf.closure_count].light_unshadowed *
|
||||
sss_profile;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 1 /* TODO(fclem): Limit to when shadow pass is needed. */
|
||||
vec3 radiance_shadowed = vec3(0);
|
||||
vec3 radiance_unshadowed = vec3(0);
|
||||
for (int i = 0; i < LIGHT_CLOSURE_EVAL_COUNT && i < gbuf.closure_count; i++) {
|
||||
radiance_shadowed += stack.cl[i].light_shadowed;
|
||||
radiance_unshadowed += stack.cl[i].light_unshadowed;
|
||||
}
|
||||
/* TODO(fclem): Change shadow pass to be colored. */
|
||||
vec3 shadows = radiance_shadowed * safe_rcp(radiance_unshadowed);
|
||||
output_renderpass_value(uniform_buf.render_pass.shadow_id, average(shadows));
|
||||
|
||||
if (gbuf.closure_count > 0) {
|
||||
/* TODO(fclem): This is waiting for fully flexible evaluation pipeline. We need to refactor the
|
||||
* raytracing pipeline first. */
|
||||
if (gbuf.has_diffuse) {
|
||||
imageStore(direct_radiance_1_img, texel, vec4(stack.cl[0].light_shadowed, 1.0));
|
||||
}
|
||||
else {
|
||||
imageStore(direct_radiance_2_img, texel, vec4(stack.cl[0].light_shadowed, 1.0));
|
||||
}
|
||||
}
|
||||
|
||||
#if LIGHT_CLOSURE_EVAL_COUNT > 1
|
||||
if (gbuf.closure_count > 1) {
|
||||
imageStore(direct_radiance_2_img, texel, vec4(stack.cl[1].light_shadowed, 1.0));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if LIGHT_CLOSURE_EVAL_COUNT > 2
|
||||
if (gbuf.closure_count > 2 || gbuf.has_translucent) {
|
||||
imageStore(direct_radiance_3_img, texel, vec4(stack.cl[2].light_shadowed, 1.0));
|
||||
for (int i = 0; i < LIGHT_CLOSURE_EVAL_COUNT && i < gbuf.closure_count; i++) {
|
||||
/* TODO(fclem): Layered texture. */
|
||||
if (i == 0) {
|
||||
imageStore(direct_radiance_1_img, texel, vec4(stack.cl[i].light_shadowed, 1.0));
|
||||
}
|
||||
else if (i == 1) {
|
||||
imageStore(direct_radiance_2_img, texel, vec4(stack.cl[i].light_shadowed, 1.0));
|
||||
}
|
||||
else if (i == 2) {
|
||||
imageStore(direct_radiance_3_img, texel, vec4(stack.cl[i].light_shadowed, 1.0));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -17,8 +17,9 @@
|
||||
*
|
||||
* \{ */
|
||||
|
||||
#define GBUFFER_LAYER_MAX 8
|
||||
#define GBUFFER_NORMAL_MAX 4
|
||||
#define GBUFFER_LAYER_MAX 4
|
||||
#define GBUFFER_NORMAL_MAX GBUFFER_LAYER_MAX
|
||||
#define GBUFFER_DATA_MAX (GBUFFER_LAYER_MAX * 2)
|
||||
|
||||
/* Structure used as input and output of the packing & read functions. */
|
||||
struct GBufferData {
|
||||
@@ -52,7 +53,7 @@ struct GBufferDataUndetermined {
|
||||
struct GBufferWriter {
|
||||
uint header;
|
||||
/* TODO(fclem): Better packing. */
|
||||
vec4 data[GBUFFER_LAYER_MAX];
|
||||
vec4 data[GBUFFER_DATA_MAX];
|
||||
vec2 N[GBUFFER_NORMAL_MAX];
|
||||
|
||||
/* Only used for book-keeping. Not actually written. Can be derived from header. */
|
||||
@@ -65,6 +66,8 @@ struct GBufferWriter {
|
||||
struct GBufferReader {
|
||||
GBufferData data;
|
||||
|
||||
ClosureUndetermined closures[GBUFFER_LAYER_MAX];
|
||||
|
||||
bool has_diffuse;
|
||||
bool has_translucent;
|
||||
bool has_reflection;
|
||||
@@ -72,7 +75,7 @@ struct GBufferReader {
|
||||
bool has_sss;
|
||||
bool has_any_surface;
|
||||
uint header;
|
||||
uint closure_count;
|
||||
int closure_count;
|
||||
/* Only used for book-keeping when reading. */
|
||||
int layer_data;
|
||||
int layer_normal;
|
||||
@@ -297,6 +300,8 @@ void gbuffer_append_closure(inout GBufferWriter gbuf, GBufferMode closure_type)
|
||||
}
|
||||
void gbuffer_register_closure(inout GBufferReader gbuf, ClosureUndetermined cl)
|
||||
{
|
||||
gbuf.closures[gbuf.closure_count] = cl;
|
||||
gbuf.closure_count++;
|
||||
switch (cl.type) {
|
||||
case CLOSURE_NONE_ID:
|
||||
/* TODO(fclem): Assert. */
|
||||
@@ -333,7 +338,6 @@ void gbuffer_register_closure(inout GBufferReader gbuf, ClosureUndetermined cl)
|
||||
gbuf.has_refraction = true;
|
||||
break;
|
||||
}
|
||||
gbuf.closure_count++;
|
||||
}
|
||||
|
||||
void gbuffer_append_data(inout GBufferWriter gbuf, vec4 data)
|
||||
@@ -666,7 +670,7 @@ GBufferReader gbuffer_read_header(uint header)
|
||||
gbuf.has_refraction = false;
|
||||
gbuf.has_translucent = false;
|
||||
gbuf.has_sss = false;
|
||||
gbuf.closure_count = 0u;
|
||||
gbuf.closure_count = 0;
|
||||
|
||||
for (int layer = 0; layer < 4; layer++) {
|
||||
GBufferMode mode = gbuffer_header_unpack(gbuf.header, layer);
|
||||
@@ -744,7 +748,11 @@ GBufferReader gbuffer_read(samplerGBufferHeader header_tx,
|
||||
|
||||
gbuf.data.thickness = 0.0;
|
||||
|
||||
for (int layer = 0; layer < 4; layer++) {
|
||||
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);
|
||||
switch (mode) {
|
||||
case GBUF_NONE:
|
||||
|
||||
@@ -101,7 +101,7 @@ void main()
|
||||
|
||||
/* Output remaining closures using image store. */
|
||||
/* NOTE: The image view start at layer 2 so all destination layer is `layer - 2`. */
|
||||
for (int layer = 2; layer < GBUFFER_LAYER_MAX && layer < gbuf.layer_data; layer++) {
|
||||
for (int layer = 2; layer < GBUFFER_DATA_MAX && layer < gbuf.layer_data; layer++) {
|
||||
imageStore(out_gbuf_closure_img, ivec3(out_texel, layer - 2), gbuf.data[layer]);
|
||||
}
|
||||
/* NOTE: The image view start at layer 1 so all destination layer is `layer - 1`. */
|
||||
|
||||
@@ -104,7 +104,7 @@ void main()
|
||||
|
||||
/* Output remaining closures using image store. */
|
||||
/* NOTE: The image view start at layer 2 so all destination layer is `layer - 2`. */
|
||||
for (int layer = 2; layer < GBUFFER_LAYER_MAX && layer < gbuf.layer_data; layer++) {
|
||||
for (int layer = 2; layer < GBUFFER_DATA_MAX && layer < gbuf.layer_data; layer++) {
|
||||
imageStore(out_gbuf_closure_img, ivec3(out_texel, layer - 2), gbuf.data[layer]);
|
||||
}
|
||||
/* NOTE: The image view start at layer 1 so all destination layer is `layer - 1`. */
|
||||
|
||||
Reference in New Issue
Block a user