diff --git a/source/blender/draw/engines/eevee_next/eevee_defines.hh b/source/blender/draw/engines/eevee_next/eevee_defines.hh index f8c5a36c0cf..baf2cb390b6 100644 --- a/source/blender/draw/engines/eevee_next/eevee_defines.hh +++ b/source/blender/draw/engines/eevee_next/eevee_defines.hh @@ -144,6 +144,7 @@ #define RBUFS_CRYPTOMATTE_SLOT 2 #define GBUF_CLOSURE_SLOT 3 #define GBUF_COLOR_SLOT 4 +#define GBUF_HEADER_SLOT 5 /* Volume properties pass do not write to `rbufs`. Reuse the same bind points. */ #define VOLUME_PROP_SCATTERING_IMG_SLOT 0 #define VOLUME_PROP_EXTINCTION_IMG_SLOT 1 diff --git a/source/blender/draw/engines/eevee_next/eevee_gbuffer.hh b/source/blender/draw/engines/eevee_next/eevee_gbuffer.hh index df8ecde7296..b89c1e71060 100644 --- a/source/blender/draw/engines/eevee_next/eevee_gbuffer.hh +++ b/source/blender/draw/engines/eevee_next/eevee_gbuffer.hh @@ -68,7 +68,8 @@ class Instance; * Color degradation is expected to happen in this case. */ struct GBuffer { - /* TODO(fclem): Use texture from pool once they support texture array. */ + /* TODO(fclem): Use texture from pool once they support texture array and layer views. */ + Texture header_tx = {"GbufferHeader"}; Texture closure_tx = {"GbufferClosure"}; Texture color_tx = {"GbufferColor"}; @@ -76,6 +77,7 @@ struct GBuffer { { const bool use_sss = (closure_bits_ & CLOSURE_SSS) != 0; eGPUTextureUsage usage = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_SHADER_WRITE; + header_tx.ensure_2d(GPU_R8UI, extent, usage); closure_tx.ensure_2d_array(GPU_RGBA16, extent, use_sss ? 3 : 2, usage); color_tx.ensure_2d_array(GPU_RGB10_A2, extent, 2, usage); } @@ -83,9 +85,17 @@ struct GBuffer { void release() { /* TODO(fclem): Use texture from pool once they support texture array. */ + // header_tx.release(); // closure_tx.release(); // color_tx.release(); } + + template void bind_resources(draw::detail::PassBase *pass) + { + pass->bind_texture("gbuf_header_tx", &header_tx); + pass->bind_texture("gbuf_closure_tx", &closure_tx); + pass->bind_texture("gbuf_color_tx", &color_tx); + } }; } // namespace blender::eevee diff --git a/source/blender/draw/engines/eevee_next/eevee_pipeline.cc b/source/blender/draw/engines/eevee_next/eevee_pipeline.cc index 0e20979b4f4..aae894e6eae 100644 --- a/source/blender/draw/engines/eevee_next/eevee_pipeline.cc +++ b/source/blender/draw/engines/eevee_next/eevee_pipeline.cc @@ -392,6 +392,7 @@ void DeferredLayer::begin_sync() /* G-buffer. */ gbuffer_ps_.bind_image(GBUF_CLOSURE_SLOT, &inst_.gbuffer.closure_tx); gbuffer_ps_.bind_image(GBUF_COLOR_SLOT, &inst_.gbuffer.color_tx); + gbuffer_ps_.bind_image(GBUF_HEADER_SLOT, &inst_.gbuffer.header_tx); /* RenderPasses & AOVs. */ gbuffer_ps_.bind_image(RBUFS_COLOR_SLOT, &inst_.render_buffers.rp_color_tx); gbuffer_ps_.bind_image(RBUFS_VALUE_SLOT, &inst_.render_buffers.rp_value_tx); @@ -424,44 +425,48 @@ void DeferredLayer::end_sync() { eClosureBits evaluated_closures = CLOSURE_DIFFUSE | CLOSURE_REFLECTION | CLOSURE_REFRACTION; if (closure_bits_ & evaluated_closures) { - eval_light_ps_.init(); - /* Use stencil test to reject pixel not written by this layer. */ - eval_light_ps_.state_set(DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL); - eval_light_ps_.state_stencil(0x00u, 0x00u, evaluated_closures); - eval_light_ps_.shader_set(inst_.shaders.static_shader_get(DEFERRED_LIGHT)); - eval_light_ps_.bind_image("direct_diffuse_img", &direct_diffuse_tx_); - eval_light_ps_.bind_image("direct_reflect_img", &direct_reflect_tx_); - eval_light_ps_.bind_image("direct_refract_img", &direct_refract_tx_); - eval_light_ps_.bind_texture("gbuffer_closure_tx", &inst_.gbuffer.closure_tx); - eval_light_ps_.bind_texture(RBUFS_UTILITY_TEX_SLOT, inst_.pipelines.utility_tx); - eval_light_ps_.bind_image(RBUFS_COLOR_SLOT, &inst_.render_buffers.rp_color_tx); - eval_light_ps_.bind_image(RBUFS_VALUE_SLOT, &inst_.render_buffers.rp_value_tx); - inst_.bind_uniform_data(&eval_light_ps_); - inst_.lights.bind_resources(&eval_light_ps_); - inst_.shadows.bind_resources(&eval_light_ps_); - inst_.sampling.bind_resources(&eval_light_ps_); - inst_.hiz_buffer.bind_resources(&eval_light_ps_); - eval_light_ps_.barrier(GPU_BARRIER_TEXTURE_FETCH | GPU_BARRIER_SHADER_IMAGE_ACCESS); - eval_light_ps_.draw_procedural(GPU_PRIM_TRIS, 1, 3); - - combine_ps_.init(); - /* Use stencil test to reject pixel not written by this layer. */ - combine_ps_.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_STENCIL_NEQUAL | DRW_STATE_BLEND_ADD); - combine_ps_.state_stencil(0x00u, 0x00u, evaluated_closures); - combine_ps_.shader_set(inst_.shaders.static_shader_get(DEFERRED_COMBINE)); - combine_ps_.bind_image("direct_diffuse_img", &direct_diffuse_tx_); - combine_ps_.bind_image("direct_reflect_img", &direct_reflect_tx_); - combine_ps_.bind_image("direct_refract_img", &direct_refract_tx_); - combine_ps_.bind_image("indirect_diffuse_img", &indirect_diffuse_tx_); - combine_ps_.bind_image("indirect_reflect_img", &indirect_reflect_tx_); - combine_ps_.bind_image("indirect_refract_img", &indirect_refract_tx_); - combine_ps_.bind_texture("gbuffer_closure_tx", &inst_.gbuffer.closure_tx); - combine_ps_.bind_texture("gbuffer_color_tx", &inst_.gbuffer.color_tx); - combine_ps_.bind_image(RBUFS_COLOR_SLOT, &inst_.render_buffers.rp_color_tx); - combine_ps_.bind_image(RBUFS_VALUE_SLOT, &inst_.render_buffers.rp_value_tx); - inst_.bind_uniform_data(&combine_ps_); - combine_ps_.barrier(GPU_BARRIER_TEXTURE_FETCH | GPU_BARRIER_SHADER_IMAGE_ACCESS); - combine_ps_.draw_procedural(GPU_PRIM_TRIS, 1, 3); + { + PassSimple &pass = eval_light_ps_; + pass.init(); + /* Use stencil test to reject pixel not written by this layer. */ + pass.state_set(DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL); + pass.state_stencil(0x00u, 0x00u, evaluated_closures); + pass.shader_set(inst_.shaders.static_shader_get(DEFERRED_LIGHT)); + pass.bind_image("direct_diffuse_img", &direct_diffuse_tx_); + pass.bind_image("direct_reflect_img", &direct_reflect_tx_); + pass.bind_image("direct_refract_img", &direct_refract_tx_); + pass.bind_texture(RBUFS_UTILITY_TEX_SLOT, inst_.pipelines.utility_tx); + pass.bind_image(RBUFS_COLOR_SLOT, &inst_.render_buffers.rp_color_tx); + pass.bind_image(RBUFS_VALUE_SLOT, &inst_.render_buffers.rp_value_tx); + inst_.bind_uniform_data(&pass); + inst_.gbuffer.bind_resources(&pass); + inst_.lights.bind_resources(&pass); + inst_.shadows.bind_resources(&pass); + inst_.sampling.bind_resources(&pass); + inst_.hiz_buffer.bind_resources(&pass); + pass.barrier(GPU_BARRIER_TEXTURE_FETCH | GPU_BARRIER_SHADER_IMAGE_ACCESS); + pass.draw_procedural(GPU_PRIM_TRIS, 1, 3); + } + { + PassSimple &pass = combine_ps_; + pass.init(); + /* Use stencil test to reject pixel not written by this layer. */ + pass.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_STENCIL_NEQUAL | DRW_STATE_BLEND_ADD_FULL); + pass.state_stencil(0x00u, 0x00u, evaluated_closures); + pass.shader_set(inst_.shaders.static_shader_get(DEFERRED_COMBINE)); + pass.bind_image("direct_diffuse_img", &direct_diffuse_tx_); + pass.bind_image("direct_reflect_img", &direct_reflect_tx_); + pass.bind_image("direct_refract_img", &direct_refract_tx_); + pass.bind_image("indirect_diffuse_img", &indirect_diffuse_tx_); + pass.bind_image("indirect_reflect_img", &indirect_reflect_tx_); + pass.bind_image("indirect_refract_img", &indirect_refract_tx_); + pass.bind_image(RBUFS_COLOR_SLOT, &inst_.render_buffers.rp_color_tx); + pass.bind_image(RBUFS_VALUE_SLOT, &inst_.render_buffers.rp_value_tx); + inst_.gbuffer.bind_resources(&pass); + inst_.bind_uniform_data(&pass); + pass.barrier(GPU_BARRIER_TEXTURE_FETCH | GPU_BARRIER_SHADER_IMAGE_ACCESS); + pass.draw_procedural(GPU_PRIM_TRIS, 1, 3); + } } } @@ -550,6 +555,9 @@ void DeferredLayer::render(View &main_view, } } + /* TODO(fclem): Clear in pass when Gbuffer will render with framebuffer. */ + inst_.gbuffer.header_tx.clear(uint4(0)); + GPU_framebuffer_bind(combined_fb); inst_.manager->submit(gbuffer_ps_, render_view); @@ -748,6 +756,7 @@ void DeferredProbeLayer::begin_sync() /* G-buffer. */ gbuffer_ps_.bind_image(GBUF_CLOSURE_SLOT, &inst_.gbuffer.closure_tx); gbuffer_ps_.bind_image(GBUF_COLOR_SLOT, &inst_.gbuffer.color_tx); + gbuffer_ps_.bind_image(GBUF_HEADER_SLOT, &inst_.gbuffer.header_tx); /* RenderPasses & AOVs. */ gbuffer_ps_.bind_image(RBUFS_COLOR_SLOT, &inst_.render_buffers.rp_color_tx); gbuffer_ps_.bind_image(RBUFS_VALUE_SLOT, &inst_.render_buffers.rp_value_tx); @@ -783,31 +792,25 @@ void DeferredProbeLayer::begin_sync() void DeferredProbeLayer::end_sync() { if (closure_bits_ & (CLOSURE_DIFFUSE | CLOSURE_REFLECTION)) { - const bool is_last_eval_pass = !(closure_bits_ & CLOSURE_SSS); - - eval_light_ps_.init(); + PassSimple &pass = eval_light_ps_; + pass.init(); /* Use stencil test to reject pixel not written by this layer. */ - eval_light_ps_.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_STENCIL_NEQUAL | - DRW_STATE_BLEND_CUSTOM); - eval_light_ps_.state_stencil(0x00u, 0x00u, (CLOSURE_DIFFUSE | CLOSURE_REFLECTION)); - eval_light_ps_.shader_set(inst_.shaders.static_shader_get(DEFERRED_CAPTURE_EVAL)); - eval_light_ps_.bind_texture("gbuffer_closure_tx", &inst_.gbuffer.closure_tx); - eval_light_ps_.bind_texture("gbuffer_color_tx", &inst_.gbuffer.color_tx); - eval_light_ps_.push_constant("is_last_eval_pass", is_last_eval_pass); - eval_light_ps_.bind_image(RBUFS_COLOR_SLOT, &inst_.render_buffers.rp_color_tx); - eval_light_ps_.bind_image(RBUFS_VALUE_SLOT, &inst_.render_buffers.rp_value_tx); - eval_light_ps_.bind_texture(RBUFS_UTILITY_TEX_SLOT, inst_.pipelines.utility_tx); - - inst_.bind_uniform_data(&eval_light_ps_); - inst_.lights.bind_resources(&eval_light_ps_); - inst_.shadows.bind_resources(&eval_light_ps_); - inst_.sampling.bind_resources(&eval_light_ps_); - inst_.hiz_buffer.bind_resources(&eval_light_ps_); - inst_.reflection_probes.bind_resources(&eval_light_ps_); - inst_.irradiance_cache.bind_resources(&eval_light_ps_); - - eval_light_ps_.barrier(GPU_BARRIER_TEXTURE_FETCH | GPU_BARRIER_SHADER_IMAGE_ACCESS); - eval_light_ps_.draw_procedural(GPU_PRIM_TRIS, 1, 3); + pass.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_STENCIL_NEQUAL); + pass.state_stencil(0x00u, 0x00u, (CLOSURE_DIFFUSE | CLOSURE_REFLECTION)); + pass.shader_set(inst_.shaders.static_shader_get(DEFERRED_CAPTURE_EVAL)); + pass.bind_image(RBUFS_COLOR_SLOT, &inst_.render_buffers.rp_color_tx); + pass.bind_image(RBUFS_VALUE_SLOT, &inst_.render_buffers.rp_value_tx); + pass.bind_texture(RBUFS_UTILITY_TEX_SLOT, inst_.pipelines.utility_tx); + inst_.bind_uniform_data(&pass); + inst_.gbuffer.bind_resources(&pass); + inst_.lights.bind_resources(&pass); + inst_.shadows.bind_resources(&pass); + inst_.sampling.bind_resources(&pass); + inst_.hiz_buffer.bind_resources(&pass); + inst_.reflection_probes.bind_resources(&pass); + inst_.irradiance_cache.bind_resources(&pass); + pass.barrier(GPU_BARRIER_TEXTURE_FETCH | GPU_BARRIER_SHADER_IMAGE_ACCESS); + pass.draw_procedural(GPU_PRIM_TRIS, 1, 3); } } diff --git a/source/blender/draw/engines/eevee_next/eevee_raytrace.cc b/source/blender/draw/engines/eevee_next/eevee_raytrace.cc index 291fabbd8c4..c3230442b1a 100644 --- a/source/blender/draw/engines/eevee_next/eevee_raytrace.cc +++ b/source/blender/draw/engines/eevee_next/eevee_raytrace.cc @@ -46,12 +46,11 @@ void RayTraceModule::sync() PassSimple &pass = tile_classify_ps_; pass.init(); pass.shader_set(inst_.shaders.static_shader_get(RAY_TILE_CLASSIFY)); - pass.bind_texture("gbuffer_closure_tx", &inst_.gbuffer.closure_tx); - pass.bind_texture("stencil_tx", &renderbuf_stencil_view_); pass.bind_image("tile_mask_img", &tile_mask_tx_); pass.bind_ssbo("ray_dispatch_buf", &ray_dispatch_buf_); pass.bind_ssbo("denoise_dispatch_buf", &denoise_dispatch_buf_); inst_.bind_uniform_data(&pass); + inst_.gbuffer.bind_resources(&pass); pass.dispatch(&tile_classify_dispatch_size_); pass.barrier(GPU_BARRIER_SHADER_IMAGE_ACCESS | GPU_BARRIER_SHADER_STORAGE); } @@ -74,12 +73,10 @@ void RayTraceModule::sync() pass.shader_set(inst_.shaders.static_shader_get((type == 0) ? RAY_GENERATE_REFLECT : RAY_GENERATE_REFRACT)); pass.bind_texture(RBUFS_UTILITY_TEX_SLOT, inst_.pipelines.utility_tx); - pass.bind_texture("stencil_tx", &renderbuf_stencil_view_); - pass.bind_texture("gbuffer_closure_tx", &inst_.gbuffer.closure_tx); - pass.bind_texture("gbuffer_color_tx", &inst_.gbuffer.color_tx); pass.bind_image("out_ray_data_img", &ray_data_tx_); pass.bind_ssbo("tiles_coord_buf", &ray_tiles_buf_); inst_.sampling.bind_resources(&pass); + inst_.gbuffer.bind_resources(&pass); pass.dispatch(ray_dispatch_buf_); pass.barrier(GPU_BARRIER_SHADER_STORAGE | GPU_BARRIER_TEXTURE_FETCH | GPU_BARRIER_SHADER_IMAGE_ACCESS); @@ -125,8 +122,6 @@ void RayTraceModule::sync() RAY_DENOISE_SPATIAL_REFRACT)); pass.bind_ssbo("tiles_coord_buf", &denoise_tiles_buf_); pass.bind_texture(RBUFS_UTILITY_TEX_SLOT, inst_.pipelines.utility_tx); - pass.bind_texture("gbuffer_closure_tx", &inst_.gbuffer.closure_tx); - pass.bind_texture("stencil_tx", &renderbuf_stencil_view_); pass.bind_texture("depth_tx", &depth_tx); pass.bind_image("ray_data_img", &ray_data_tx_); pass.bind_image("ray_time_img", &ray_time_tx_); @@ -137,6 +132,7 @@ void RayTraceModule::sync() pass.bind_image("tile_mask_img", &tile_mask_tx_); inst_.bind_uniform_data(&pass); inst_.sampling.bind_resources(&pass); + inst_.gbuffer.bind_resources(&pass); pass.dispatch(denoise_dispatch_buf_); pass.barrier(GPU_BARRIER_SHADER_IMAGE_ACCESS); } @@ -164,7 +160,6 @@ void RayTraceModule::sync() pass.init(); pass.shader_set(inst_.shaders.static_shader_get((type == 0) ? RAY_DENOISE_BILATERAL_REFLECT : RAY_DENOISE_BILATERAL_REFRACT)); - pass.bind_texture("gbuffer_closure_tx", &inst_.gbuffer.closure_tx); pass.bind_texture("depth_tx", &depth_tx); pass.bind_image("in_radiance_img", &denoised_temporal_tx_); pass.bind_image("out_radiance_img", &denoised_bilateral_tx_); @@ -173,6 +168,7 @@ void RayTraceModule::sync() pass.bind_ssbo("tiles_coord_buf", &denoise_tiles_buf_); inst_.bind_uniform_data(&pass); inst_.sampling.bind_resources(&pass); + inst_.gbuffer.bind_resources(&pass); pass.dispatch(denoise_dispatch_buf_); pass.barrier(GPU_BARRIER_SHADER_IMAGE_ACCESS); } diff --git a/source/blender/draw/engines/eevee_next/eevee_subsurface.cc b/source/blender/draw/engines/eevee_next/eevee_subsurface.cc index 619459f9e91..28a92d85f73 100644 --- a/source/blender/draw/engines/eevee_next/eevee_subsurface.cc +++ b/source/blender/draw/engines/eevee_next/eevee_subsurface.cc @@ -36,9 +36,8 @@ void SubsurfaceModule::end_sync() subsurface_ps_.shader_set(inst_.shaders.static_shader_get(SUBSURFACE_EVAL)); inst_.bind_uniform_data(&subsurface_ps_); inst_.hiz_buffer.bind_resources(&subsurface_ps_); + inst_.gbuffer.bind_resources(&subsurface_ps_); subsurface_ps_.bind_texture("radiance_tx", &diffuse_light_tx_); - subsurface_ps_.bind_texture("gbuffer_closure_tx", &inst_.gbuffer.closure_tx); - subsurface_ps_.bind_texture("gbuffer_color_tx", &inst_.gbuffer.color_tx); subsurface_ps_.bind_image(RBUFS_COLOR_SLOT, &inst_.render_buffers.rp_color_tx); /** NOTE: Not used in the shader, but we bind it to avoid debug warnings. */ subsurface_ps_.bind_image(RBUFS_VALUE_SLOT, &inst_.render_buffers.rp_value_tx); diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_deferred_capture_frag.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_deferred_capture_frag.glsl index 91168753891..813d2f13dcc 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_deferred_capture_frag.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_deferred_capture_frag.glsl @@ -21,61 +21,27 @@ void main() vec3 V = cameraVec(P); float vP_z = dot(cameraForward, P) - dot(cameraForward, cameraPos); - vec4 gbuffer_0_packed = texelFetch(gbuffer_closure_tx, ivec3(texel, 0), 0); - vec4 gbuffer_1_packed = texelFetch(gbuffer_closure_tx, ivec3(texel, 1), 0); + GBufferData gbuf = gbuffer_read(gbuf_header_tx, gbuf_closure_tx, gbuf_color_tx, texel); - ClosureReflection reflection_data; - reflection_data.N = gbuffer_normal_unpack(gbuffer_0_packed.xy); - reflection_data.roughness = gbuffer_0_packed.z; - - ClosureDiffuse diffuse_data; - diffuse_data.N = gbuffer_normal_unpack(gbuffer_1_packed.xy); - /* These are only set for SSS case. */ - diffuse_data.sss_radius = vec3(0.0); - diffuse_data.sss_id = 0u; - float thickness = 0.0; - - ClosureRefraction refraction_data; - refraction_data.N = diffuse_data.N; - refraction_data.roughness = gbuffer_1_packed.z; - refraction_data.ior = 0.0; /* Not needed. */ - - bool is_refraction = gbuffer_is_refraction(gbuffer_1_packed); - if (is_refraction) { - /* Still evaluate the diffuse light so that dithered SSS / Refraction combination still - * produces a complete diffuse light buffer that will be correctly convolved by the SSSS. - * The refraction pixels will just set the diffuse radiance to 0. */ - } - else if (textureSize(gbuffer_closure_tx, 0).z >= 3) { - vec4 gbuffer_2_packed = texelFetch(gbuffer_closure_tx, ivec3(texel, 2), 0); - diffuse_data.sss_radius = gbuffer_sss_radii_unpack(gbuffer_2_packed.xyz); - diffuse_data.sss_id = gbuffer_object_id_unorm16_unpack(gbuffer_2_packed.w); - thickness = gbuffer_thickness_unpack(gbuffer_1_packed.z); - } - - vec3 Ng = diffuse_data.N; + vec3 Ng = gbuf.diffuse.N; vec3 diffuse_light = vec3(0.0); vec3 unused_reflection_light = vec3(0.0); vec3 unused_refraction_light = vec3(0.0); float unused_shadow = 1.0; - light_eval(diffuse_data, - reflection_data, + light_eval(gbuf.diffuse, + gbuf.reflection, P, Ng, V, vP_z, - thickness, + gbuf.thickness, diffuse_light, unused_reflection_light, unused_shadow); - /* Apply color and output lighting to render-passes. */ - vec4 color_0_packed = texelFetch(gbuffer_color_tx, ivec3(texel, 0), 0); - vec4 color_1_packed = texelFetch(gbuffer_color_tx, ivec3(texel, 1), 0); + vec3 albedo = gbuf.diffuse.color + gbuf.reflection.color + gbuf.refraction.color; - vec3 albedo_color = gbuffer_color_unpack(color_0_packed) + gbuffer_color_unpack(color_1_packed); - - out_radiance = vec4(diffuse_light * albedo_color, 0.0); + out_radiance = vec4(diffuse_light * albedo, 0.0); } diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_deferred_combine_frag.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_deferred_combine_frag.glsl index 65b43cd7324..24be6ede092 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_deferred_combine_frag.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_deferred_combine_frag.glsl @@ -21,24 +21,18 @@ void main() vec3 refract_light = imageLoad(direct_refract_img, texel).rgb + imageLoad(indirect_refract_img, texel).rgb; - /* Apply color and output lighting to render-passes. */ - vec4 gbuffer_1_packed = texelFetch(gbuffer_closure_tx, ivec3(texel, 1), 0); - bool is_refraction = gbuffer_is_refraction(gbuffer_1_packed); - - vec4 color_0_packed = texelFetch(gbuffer_color_tx, ivec3(texel, 0), 0); - vec4 color_1_packed = texelFetch(gbuffer_color_tx, ivec3(texel, 1), 0); - - vec3 reflection_color = gbuffer_color_unpack(color_0_packed); - vec3 refraction_color = is_refraction ? gbuffer_color_unpack(color_1_packed) : vec3(0.0); - vec3 diffuse_color = is_refraction ? vec3(0.0) : gbuffer_color_unpack(color_1_packed); - + GBufferData gbuf = gbuffer_read(gbuf_header_tx, gbuf_closure_tx, gbuf_color_tx, texel); + /* Mask invalid radiance. */ + diffuse_light = gbuf.has_diffuse ? diffuse_light : vec3(0.0); + reflect_light = gbuf.has_reflection ? reflect_light : vec3(0.0); + refract_light = gbuf.has_refraction ? refract_light : vec3(0.0); /* Light passes. */ vec3 specular_light = reflect_light + refract_light; - render_pass_color_out(uniform_buf.render_pass.diffuse_light_id, diffuse_light); - render_pass_color_out(uniform_buf.render_pass.specular_light_id, specular_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_light * diffuse_color; - out_combined.xyz += reflect_light * reflection_color; - out_combined.xyz += refract_light * refraction_color; + out_combined.xyz += diffuse_light * gbuf.diffuse.color; + out_combined.xyz += reflect_light * gbuf.reflection.color; + out_combined.xyz += refract_light * gbuf.refraction.color; } diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_deferred_light_frag.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_deferred_light_frag.glsl index 5594f12e192..06dc34280a2 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_deferred_light_frag.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_deferred_light_frag.glsl @@ -26,59 +26,29 @@ void main() vec3 V = cameraVec(P); float vP_z = dot(cameraForward, P) - dot(cameraForward, cameraPos); - vec4 gbuffer_0_packed = texelFetch(gbuffer_closure_tx, ivec3(texel, 0), 0); - vec4 gbuffer_1_packed = texelFetch(gbuffer_closure_tx, ivec3(texel, 1), 0); - - ClosureReflection reflection_data; - reflection_data.N = gbuffer_normal_unpack(gbuffer_0_packed.xy); - reflection_data.roughness = gbuffer_0_packed.z; - - ClosureDiffuse diffuse_data; - diffuse_data.N = gbuffer_normal_unpack(gbuffer_1_packed.xy); - /* These are only set for SSS case. */ - diffuse_data.sss_radius = vec3(0.0); - diffuse_data.sss_id = 0u; - float thickness = 0.0; - - ClosureRefraction refraction_data; - refraction_data.N = diffuse_data.N; - refraction_data.roughness = gbuffer_1_packed.z; - refraction_data.ior = 0.0; /* Not needed. */ - - bool is_refraction = gbuffer_is_refraction(gbuffer_1_packed); - if (is_refraction) { - /* Still evaluate the diffuse light so that dithered SSS / Refraction combination still - * produces a complete diffuse light buffer that will be correctly convolved by the SSSS. - * The refraction pixels will just set the diffuse radiance to 0. */ - } - else if (textureSize(gbuffer_closure_tx, 0).z >= 3) { - vec4 gbuffer_2_packed = texelFetch(gbuffer_closure_tx, ivec3(texel, 2), 0); - diffuse_data.sss_radius = gbuffer_sss_radii_unpack(gbuffer_2_packed.xyz); - diffuse_data.sss_id = gbuffer_object_id_unorm16_unpack(gbuffer_2_packed.w); - thickness = gbuffer_thickness_unpack(gbuffer_1_packed.z); - } + GBufferData gbuf = gbuffer_read(gbuf_header_tx, gbuf_closure_tx, gbuf_color_tx, texel); vec3 diffuse_light = vec3(0.0); vec3 reflection_light = vec3(0.0); vec3 refraction_light = vec3(0.0); float shadow = 1.0; - light_eval(diffuse_data, - reflection_data, + light_eval(gbuf.diffuse, + gbuf.reflection, P, Ng, V, vP_z, - thickness, + gbuf.thickness, diffuse_light, reflection_light, shadow); - render_pass_value_out(uniform_buf.render_pass.shadow_id, shadow); + output_renderpass_value(uniform_buf.render_pass.shadow_id, shadow); /* Store lighting for next deferred pass. */ /* Output object ID for sub-surface screen space processing. */ - float f_sss_id = gbuffer_object_id_f16_pack(diffuse_data.sss_id); + float f_sss_id = gbuffer_object_id_f16_pack(gbuf.diffuse.sss_id); imageStore(direct_diffuse_img, texel, vec4(diffuse_light, f_sss_id)); imageStore(direct_reflect_img, texel, vec4(reflection_light, 1.0)); diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_gbuffer_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_gbuffer_lib.glsl index e4f45b6bbcf..f5546da7338 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_gbuffer_lib.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_gbuffer_lib.glsl @@ -9,6 +9,8 @@ */ #pragma BLENDER_REQUIRE(gpu_shader_math_vector_lib.glsl) +#pragma BLENDER_REQUIRE(gpu_shader_utildefines_lib.glsl) +#pragma BLENDER_REQUIRE(gpu_shader_codegen_lib.glsl) vec2 gbuffer_normal_pack(vec3 N) { @@ -110,3 +112,85 @@ bool gbuffer_is_refraction(vec4 gbuffer) { return gbuffer.w < 1.0; } + +struct GBufferData { + ClosureDiffuse diffuse; + ClosureReflection reflection; + ClosureRefraction refraction; + float thickness; + bool has_diffuse; + bool has_reflection; + bool has_refraction; +}; + +GBufferData gbuffer_read(usampler2D header_tx, + sampler2DArray closure_tx, + sampler2DArray color_tx, + ivec2 texel) +{ + GBufferData gbuf; + + uint header = texelFetch(header_tx, texel, 0).r; + + gbuf.thickness = 0.0; + gbuf.has_diffuse = flag_test(header, CLOSURE_DIFFUSE); + gbuf.has_reflection = flag_test(header, CLOSURE_REFLECTION); + gbuf.has_refraction = flag_test(header, CLOSURE_REFRACTION); + + if (gbuf.has_reflection) { + int layer = 0; + vec4 closure_packed = texelFetch(closure_tx, ivec3(texel, layer), 0); + gbuf.reflection.N = gbuffer_normal_unpack(closure_packed.xy); + gbuf.reflection.roughness = closure_packed.z; + + vec4 color_packed = texelFetch(color_tx, ivec3(texel, layer), 0); + gbuf.reflection.color = gbuffer_color_unpack(color_packed); + } + else { + gbuf.reflection.N = vec3(0.0, 0.0, 1.0); + gbuf.reflection.roughness = 0.0; + gbuf.reflection.color = vec3(0.0); + } + + if (gbuf.has_diffuse) { + int layer = 1; + vec4 closure_packed = texelFetch(closure_tx, ivec3(texel, layer), 0); + gbuf.diffuse.N = gbuffer_normal_unpack(closure_packed.xy); + gbuf.diffuse.sss_id = 0u; + gbuf.thickness = gbuffer_thickness_unpack(closure_packed.z); + + vec4 color_packed = texelFetch(color_tx, ivec3(texel, layer), 0); + gbuf.diffuse.color = gbuffer_color_unpack(color_packed); + + if (flag_test(header, CLOSURE_SSS)) { + int layer = 2; + vec4 closure_packed = texelFetch(closure_tx, ivec3(texel, layer), 0); + gbuf.diffuse.sss_radius = gbuffer_sss_radii_unpack(closure_packed.xyz); + gbuf.diffuse.sss_id = gbuffer_object_id_unorm16_unpack(closure_packed.w); + } + } + else { + gbuf.diffuse.N = vec3(0.0, 0.0, 1.0); + gbuf.diffuse.sss_id = 0u; + gbuf.diffuse.color = vec3(0.0); + } + + if (gbuf.has_refraction) { + int layer = 1; + vec4 closure_packed = texelFetch(closure_tx, ivec3(texel, layer), 0); + gbuf.refraction.N = gbuffer_normal_unpack(closure_packed.xy); + gbuf.refraction.roughness = closure_packed.z; + gbuf.refraction.ior = gbuffer_ior_unpack(closure_packed.w); + + vec4 color_packed = texelFetch(color_tx, ivec3(texel, layer), 0); + gbuf.refraction.color = gbuffer_color_unpack(color_packed); + } + else { + gbuf.refraction.N = vec3(0.0, 0.0, 1.0); + gbuf.refraction.ior = 1.1; + gbuf.refraction.roughness = 0.0; + gbuf.refraction.color = vec3(0.0); + } + + return gbuf; +} diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl index 99c882990ff..36607db1b51 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl @@ -367,60 +367,6 @@ vec2 bsdf_lut(float cos_theta, float roughness, float ior, float do_multiscatter #endif } -void output_renderpass_color(int id, vec4 color) -{ -#if defined(MAT_RENDER_PASS_SUPPORT) && defined(GPU_FRAGMENT_SHADER) - if (id >= 0) { - ivec2 texel = ivec2(gl_FragCoord.xy); - imageStore(rp_color_img, ivec3(texel, id), color); - } -#endif -} - -void output_renderpass_value(int id, float value) -{ -#if defined(MAT_RENDER_PASS_SUPPORT) && defined(GPU_FRAGMENT_SHADER) - if (id >= 0) { - ivec2 texel = ivec2(gl_FragCoord.xy); - imageStore(rp_value_img, ivec3(texel, id), vec4(value)); - } -#endif -} - -void clear_aovs() -{ -#if defined(MAT_RENDER_PASS_SUPPORT) && defined(GPU_FRAGMENT_SHADER) - for (int i = 0; i < AOV_MAX && i < uniform_buf.render_pass.aovs.color_len; i++) { - output_renderpass_color(uniform_buf.render_pass.color_len + i, vec4(0)); - } - for (int i = 0; i < AOV_MAX && i < uniform_buf.render_pass.aovs.value_len; i++) { - output_renderpass_value(uniform_buf.render_pass.value_len + i, 0.0); - } -#endif -} - -void output_aov(vec4 color, float value, uint hash) -{ -#if defined(MAT_RENDER_PASS_SUPPORT) && defined(GPU_FRAGMENT_SHADER) - for (int i = 0; i < AOV_MAX && i < uniform_buf.render_pass.aovs.color_len; i++) { - if (uniform_buf.render_pass.aovs.hash_color[i].x == hash) { - imageStore(rp_color_img, - ivec3(ivec2(gl_FragCoord.xy), uniform_buf.render_pass.color_len + i), - color); - return; - } - } - for (int i = 0; i < AOV_MAX && i < uniform_buf.render_pass.aovs.value_len; i++) { - if (uniform_buf.render_pass.aovs.hash_value[i].x == hash) { - imageStore(rp_value_img, - ivec3(ivec2(gl_FragCoord.xy), uniform_buf.render_pass.value_len + i), - vec4(value)); - return; - } - } -#endif -} - #ifdef EEVEE_MATERIAL_STUBS # define attrib_load() # define nodetree_displacement() vec3(0.0) diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_ray_denoise_bilateral_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_ray_denoise_bilateral_comp.glsl index 3b376bf0af6..6c556f60697 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_ray_denoise_bilateral_comp.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_ray_denoise_bilateral_comp.glsl @@ -61,20 +61,20 @@ vec3 from_accumulation_space(vec3 color) return color / (1.0 - dot(color, vec3(1.0))); } -void gbuffer_load_closure_data(sampler2DArray gbuffer_closure_tx, +void gbuffer_load_closure_data(sampler2DArray gbuf_closure_tx, ivec2 texel, out ClosureDiffuse closure) { - vec4 data_in = texelFetch(gbuffer_closure_tx, ivec3(texel, 1), 0); + vec4 data_in = texelFetch(gbuf_closure_tx, ivec3(texel, 1), 0); closure.N = gbuffer_normal_unpack(data_in.xy); } -void gbuffer_load_closure_data(sampler2DArray gbuffer_closure_tx, +void gbuffer_load_closure_data(sampler2DArray gbuf_closure_tx, ivec2 texel, out ClosureRefraction closure) { - vec4 data_in = texelFetch(gbuffer_closure_tx, ivec3(texel, 1), 0); + vec4 data_in = texelFetch(gbuf_closure_tx, ivec3(texel, 1), 0); closure.N = gbuffer_normal_unpack(data_in.xy); if (gbuffer_is_refraction(data_in)) { @@ -87,11 +87,11 @@ void gbuffer_load_closure_data(sampler2DArray gbuffer_closure_tx, } } -void gbuffer_load_closure_data(sampler2DArray gbuffer_closure_tx, +void gbuffer_load_closure_data(sampler2DArray gbuf_closure_tx, ivec2 texel, out ClosureReflection closure) { - vec4 data_in = texelFetch(gbuffer_closure_tx, ivec3(texel, 0), 0); + vec4 data_in = texelFetch(gbuf_closure_tx, ivec3(texel, 0), 0); closure.N = gbuffer_normal_unpack(data_in.xy); closure.roughness = data_in.z; @@ -116,7 +116,7 @@ void main() #else # error #endif - gbuffer_load_closure_data(gbuffer_closure_tx, texel_fullres, center_closure); + gbuffer_load_closure_data(gbuf_closure_tx, texel_fullres, center_closure); float roughness = center_closure.roughness; @@ -168,7 +168,7 @@ void main() continue; } - gbuffer_load_closure_data(gbuffer_closure_tx, sample_texel, sample_closure); + gbuffer_load_closure_data(gbuf_closure_tx, sample_texel, sample_closure); float depth_weight = bilateral_depth_weight(center_closure.N, center_P, sample_P); float spatial_weight = bilateral_spatial_weight(filter_size, vec2(offset)); diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_ray_denoise_spatial_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_ray_denoise_spatial_comp.glsl index f3a6e4f02e5..4417ec9a3ca 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_ray_denoise_spatial_comp.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_ray_denoise_spatial_comp.glsl @@ -22,40 +22,22 @@ #pragma BLENDER_REQUIRE(eevee_bxdf_lib.glsl) #pragma BLENDER_REQUIRE(common_view_lib.glsl) -void gbuffer_load_closure_data(sampler2DArray gbuffer_closure_tx, +void gbuffer_load_closure_data(sampler2DArray gbuf_closure_tx, ivec2 texel, out ClosureDiffuse closure) { - vec4 data_in = texelFetch(gbuffer_closure_tx, ivec3(texel, 1), 0); - - closure.N = gbuffer_normal_unpack(data_in.xy); } -void gbuffer_load_closure_data(sampler2DArray gbuffer_closure_tx, +void gbuffer_load_closure_data(sampler2DArray gbuf_closure_tx, ivec2 texel, out ClosureRefraction closure) { - vec4 data_in = texelFetch(gbuffer_closure_tx, ivec3(texel, 1), 0); - - closure.N = gbuffer_normal_unpack(data_in.xy); - if (gbuffer_is_refraction(data_in)) { - closure.roughness = data_in.z; - closure.ior = gbuffer_ior_unpack(data_in.w); - } - else { - closure.roughness = 1.0; - closure.ior = 1.1; - } } -void gbuffer_load_closure_data(sampler2DArray gbuffer_closure_tx, +void gbuffer_load_closure_data(sampler2DArray gbuf_closure_tx, ivec2 texel, out ClosureReflection closure) { - vec4 data_in = texelFetch(gbuffer_closure_tx, ivec3(texel, 0), 0); - - closure.N = gbuffer_normal_unpack(data_in.xy); - closure.roughness = data_in.z; } float bxdf_eval(ClosureDiffuse closure, vec3 L, vec3 V) @@ -88,19 +70,6 @@ bool neighbor_tile_mask_bit_get(uint tile_mask, ivec2 offset) return flag_test(tile_mask, 1u << shift); } -#if defined(RAYTRACE_DIFFUSE) -# define ClosureT ClosureDiffuse -# define CLOSURE_ACTIVE eClosureBits(CLOSURE_DIFFUSE) -#elif defined(RAYTRACE_REFRACT) -# define ClosureT ClosureRefraction -# define CLOSURE_ACTIVE eClosureBits(CLOSURE_REFRACTION) -#elif defined(RAYTRACE_REFLECT) -# define ClosureT ClosureReflection -# define CLOSURE_ACTIVE eClosureBits(CLOSURE_REFLECTION) -#else -# error -#endif - void main() { const uint tile_size = RAYTRACE_GROUP_SIZE; @@ -143,8 +112,8 @@ void main() } } - bool valid_texel = in_texture_range(texel_fullres, stencil_tx); - uint closure_bits = (!valid_texel) ? 0u : texelFetch(stencil_tx, texel_fullres, 0).r; + bool valid_texel = in_texture_range(texel_fullres, gbuf_header_tx); + uint closure_bits = (!valid_texel) ? 0u : texelFetch(gbuf_header_tx, texel_fullres, 0).r; if (!flag_test(closure_bits, CLOSURE_ACTIVE)) { imageStore(out_radiance_img, texel_fullres, vec4(FLT_11_11_10_MAX, 0.0)); imageStore(out_variance_img, texel_fullres, vec4(0.0)); @@ -155,8 +124,17 @@ void main() vec2 uv = (vec2(texel_fullres) + 0.5) * uniform_buf.raytrace.full_resolution_inv; vec3 V = transform_direction(ViewMatrixInverse, get_view_vector_from_screen_uv(uv)); - ClosureT closure; - gbuffer_load_closure_data(gbuffer_closure_tx, texel_fullres, closure); + GBufferData gbuf = gbuffer_read(gbuf_header_tx, gbuf_closure_tx, gbuf_color_tx, texel_fullres); + +#if defined(RAYTRACE_DIFFUSE) + ClosureDiffuse closure = gbuf.diffuse; +#elif defined(RAYTRACE_REFRACT) + ClosureRefraction closure = gbuf.refraction; +#elif defined(RAYTRACE_REFLECT) + ClosureReflection closure = gbuf.reflection; +#else +# error +#endif uint sample_count = 16u; float filter_size = 9.0; diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_ray_generate_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_ray_generate_comp.glsl index 03b2ebeef5c..c0b28e5de5d 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_ray_generate_comp.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_ray_generate_comp.glsl @@ -22,58 +22,32 @@ void main() ivec2 texel_fullres = texel * uniform_buf.raytrace.resolution_scale + uniform_buf.raytrace.resolution_bias; - bool valid_texel = in_texture_range(texel_fullres, stencil_tx); - uint closure_bits = (!valid_texel) ? 0u : texelFetch(stencil_tx, texel_fullres, 0).r; + GBufferData gbuf = gbuffer_read(gbuf_header_tx, gbuf_closure_tx, gbuf_color_tx, texel_fullres); #if defined(RAYTRACE_REFLECT) - ClosureReflection closure; - eClosureBits closure_active = CLOSURE_REFLECTION; - const int gbuf_layer = 0; + bool valid_pixel = gbuf.has_reflection; #elif defined(RAYTRACE_REFRACT) - ClosureRefraction closure; - eClosureBits closure_active = CLOSURE_REFRACTION; - const int gbuf_layer = 1; + bool valid_pixel = gbuf.has_refraction; #endif - if (!flag_test(closure_bits, closure_active)) { + if (!valid_pixel) { imageStore(out_ray_data_img, texel, vec4(0.0)); return; } - vec2 uv = (vec2(texel_fullres) + 0.5) / vec2(textureSize(stencil_tx, 0).xy); + vec2 uv = (vec2(texel_fullres) + 0.5) / vec2(textureSize(gbuf_header_tx, 0).xy); vec3 V = transform_direction(ViewMatrixInverse, get_view_vector_from_screen_uv(uv)); vec2 noise = utility_tx_fetch(utility_tx, vec2(texel), UTIL_BLUE_NOISE_LAYER).rg; - /* Load GBuffer data. */ - vec4 gbuffer_packed = texelFetch(gbuffer_closure_tx, ivec3(texel_fullres, gbuf_layer), 0); - - closure.N = gbuffer_normal_unpack(gbuffer_packed.xy); - #if defined(RAYTRACE_REFLECT) - closure.roughness = gbuffer_packed.z; - + ClosureReflection closure = gbuf.reflection; #elif defined(RAYTRACE_REFRACT) - if (gbuffer_is_refraction(gbuffer_packed)) { - closure.roughness = gbuffer_packed.z; - closure.ior = gbuffer_ior_unpack(gbuffer_packed.w); - } - else { - /* Avoid producing incorrect ray directions. */ - closure.ior = 1.1; - closure.roughness = 0.0; - } + ClosureRefraction closure = gbuf.refraction; #endif float pdf; vec3 ray_direction = ray_generate_direction(noise.xy, closure, V, pdf); -#if defined(RAYTRACE_REFRACT) - if (gbuffer_is_refraction(gbuffer_packed) && closure_active != CLOSURE_REFRACTION) { - /* Discard incorrect rays. */ - pdf = 0.0; - } -#endif - /* Store inverse pdf to speedup denoising. * Limit to the smallest non-0 value that the format can encode. * Strangely it does not correspond to the IEEE spec. */ diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_ray_tile_classify_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_ray_tile_classify_comp.glsl index 4e90cf032dd..b8523b010e1 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_ray_tile_classify_comp.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_ray_tile_classify_comp.glsl @@ -40,15 +40,17 @@ void main() barrier(); - ivec2 texel = min(ivec2(gl_GlobalInvocationID.xy), textureSize(stencil_tx, 0) - 1); + ivec2 texel = ivec2(gl_GlobalInvocationID.xy); - eClosureBits closure_bits = eClosureBits(texelFetch(stencil_tx, texel, 0).r); + bool valid_texel = in_texture_range(texel, gbuf_header_tx); + uint closure_bits = (!valid_texel) ? 0u : texelFetch(gbuf_header_tx, texel, 0).r; if (flag_test(closure_bits, uniform_buf.raytrace.closure_active)) { - int gbuffer_layer = uniform_buf.raytrace.closure_active == CLOSURE_REFRACTION ? 1 : 0; + GBufferData gbuf = gbuffer_read(gbuf_header_tx, gbuf_closure_tx, gbuf_color_tx, texel); - vec4 gbuffer_packed = texelFetch(gbuffer_closure_tx, ivec3(texel, gbuffer_layer), 0); - float roughness = gbuffer_packed.z; + float roughness = (uniform_buf.raytrace.closure_active == CLOSURE_REFRACTION) ? + gbuf.refraction.roughness : + gbuf.reflection.roughness; if (ray_glossy_factor(roughness) > 0.0) { /* We don't care about race condition here. */ diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_renderpass_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_renderpass_lib.glsl index 078154bfbce..9495c7172c9 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_renderpass_lib.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_renderpass_lib.glsl @@ -2,16 +2,56 @@ * * SPDX-License-Identifier: GPL-2.0-or-later */ -void render_pass_color_out(int pass_index, vec3 color) +void output_renderpass_color(int id, vec4 color) { - if (pass_index >= 0) { - imageStore(rp_color_img, ivec3(ivec2(gl_FragCoord.xy), pass_index), vec4(color, 0.0)); +#if defined(MAT_RENDER_PASS_SUPPORT) && defined(GPU_FRAGMENT_SHADER) + if (id >= 0) { + ivec2 texel = ivec2(gl_FragCoord.xy); + imageStore(rp_color_img, ivec3(texel, id), color); } +#endif } -void render_pass_value_out(int pass_index, float value) +void output_renderpass_value(int id, float value) { - if (pass_index >= 0) { - imageStore(rp_value_img, ivec3(ivec2(gl_FragCoord.xy), pass_index), vec4(value)); +#if defined(MAT_RENDER_PASS_SUPPORT) && defined(GPU_FRAGMENT_SHADER) + if (id >= 0) { + ivec2 texel = ivec2(gl_FragCoord.xy); + imageStore(rp_value_img, ivec3(texel, id), vec4(value)); } +#endif +} + +void clear_aovs() +{ +#if defined(MAT_RENDER_PASS_SUPPORT) && defined(GPU_FRAGMENT_SHADER) + for (int i = 0; i < AOV_MAX && i < uniform_buf.render_pass.aovs.color_len; i++) { + output_renderpass_color(uniform_buf.render_pass.color_len + i, vec4(0)); + } + for (int i = 0; i < AOV_MAX && i < uniform_buf.render_pass.aovs.value_len; i++) { + output_renderpass_value(uniform_buf.render_pass.value_len + i, 0.0); + } +#endif +} + +void output_aov(vec4 color, float value, uint hash) +{ +#if defined(MAT_RENDER_PASS_SUPPORT) && defined(GPU_FRAGMENT_SHADER) + for (int i = 0; i < AOV_MAX && i < uniform_buf.render_pass.aovs.color_len; i++) { + if (uniform_buf.render_pass.aovs.hash_color[i].x == hash) { + imageStore(rp_color_img, + ivec3(ivec2(gl_FragCoord.xy), uniform_buf.render_pass.color_len + i), + color); + return; + } + } + for (int i = 0; i < AOV_MAX && i < uniform_buf.render_pass.aovs.value_len; i++) { + if (uniform_buf.render_pass.aovs.hash_value[i].x == hash) { + imageStore(rp_value_img, + ivec3(ivec2(gl_FragCoord.xy), uniform_buf.render_pass.value_len + i), + vec4(value)); + return; + } + } +#endif } \ No newline at end of file diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_subsurface_eval_frag.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_subsurface_eval_frag.glsl index c0833c8733d..4609678dff3 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_subsurface_eval_frag.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_subsurface_eval_frag.glsl @@ -28,22 +28,16 @@ void main(void) float gbuffer_depth = texelFetch(hiz_tx, texel, 0).r; vec3 vP = get_view_space_from_depth(center_uv, gbuffer_depth); - vec4 color_1_packed = texelFetch(gbuffer_color_tx, ivec3(texel, 1), 0); - vec4 gbuffer_2_packed = texelFetch(gbuffer_closure_tx, ivec3(texel, 2), 0); + GBufferData gbuf = gbuffer_read(gbuf_header_tx, gbuf_closure_tx, gbuf_color_tx, texel); - ClosureDiffuse diffuse; - diffuse.sss_radius = gbuffer_sss_radii_unpack(gbuffer_2_packed.xyz); - diffuse.sss_id = gbuffer_object_id_unorm16_unpack(gbuffer_2_packed.w); - diffuse.color = gbuffer_color_unpack(color_1_packed); - - if (diffuse.sss_id == 0u) { + if (gbuf.diffuse.sss_id == 0u) { /* Normal diffuse is already in combined pass. */ /* Refraction also go into this case. */ out_combined = vec4(0.0); return; } - float max_radius = max_v3(diffuse.sss_radius); + float max_radius = max_v3(gbuf.diffuse.sss_radius); float homcoord = ProjectionMatrix[2][3] * vP.z + ProjectionMatrix[3][3]; vec2 sample_scale = vec2(ProjectionMatrix[0][0], ProjectionMatrix[1][1]) * @@ -56,10 +50,11 @@ void main(void) return; } - diffuse.sss_radius = max(vec3(1e-4), diffuse.sss_radius / max_radius) * max_radius; + /* Avoid too small radii that have float imprecision. */ + vec3 clamped_sss_radius = max(vec3(1e-4), gbuf.diffuse.sss_radius / max_radius) * max_radius; /* Scale albedo because we can have HDR value caused by BSDF sampling. */ - vec3 albedo = diffuse.color / max(1e-6, max_v3(diffuse.color)); - vec3 d = burley_setup(diffuse.sss_radius, albedo); + vec3 albedo = gbuf.diffuse.color / max(1e-6, max_v3(gbuf.diffuse.color)); + vec3 d = burley_setup(clamped_sss_radius, albedo); /* Do not rotate too much to avoid too much cache misses. */ float golden_angle = M_PI * (3.0 - sqrt(5.0)); @@ -87,7 +82,7 @@ void main(void) vec3 sample_radiance = sample_data.rgb; uint sample_sss_id = uint(sample_data.a); - if (sample_sss_id != diffuse.sss_id) { + if (sample_sss_id != gbuf.diffuse.sss_id) { continue; } @@ -116,7 +111,7 @@ void main(void) accum -= texelFetch(radiance_tx, texel, 0).rgb; /* Apply surface color on final radiance. */ - accum *= diffuse.color; + accum *= gbuf.diffuse.color; /* Debug, detect NaNs. */ if (any(isnan(accum))) { diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_surf_deferred_frag.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_deferred_frag.glsl index 24e77fd55f6..15c9b413523 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_surf_deferred_frag.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_deferred_frag.glsl @@ -16,6 +16,7 @@ #pragma BLENDER_REQUIRE(eevee_ambient_occlusion_lib.glsl) #pragma BLENDER_REQUIRE(eevee_surf_lib.glsl) #pragma BLENDER_REQUIRE(eevee_nodetree_lib.glsl) +#pragma BLENDER_REQUIRE(eevee_renderpass_lib.glsl) #pragma BLENDER_REQUIRE(eevee_sampling_lib.glsl) vec4 closure_to_rgba(Closure cl) @@ -86,56 +87,62 @@ void main() /* ----- GBuffer output ----- */ - if (true) { + uint header = 0u; + + if (g_reflection_data.weight > 0.0) { /* Reflection. */ - vec4 out_reflect = vec4(gbuffer_normal_pack(g_reflection_data.N), - g_reflection_data.roughness, - g_reflection_data.roughness); - imageStore(out_gbuff_closure_img, ivec3(out_texel, 0), out_reflect); + vec4 closure; + closure.xy = gbuffer_normal_pack(g_reflection_data.N); + closure.z = g_reflection_data.roughness; + closure.w = 0.0; + imageStore(out_gbuf_closure_img, ivec3(out_texel, 0), closure); vec4 color = gbuffer_color_pack(g_reflection_data.color); - imageStore(out_gbuff_color_img, ivec3(out_texel, 0), color); + imageStore(out_gbuf_color_img, ivec3(out_texel, 0), color); + header |= CLOSURE_REFLECTION; } - /* TODO(fclem) other RNG. */ - float refract_rand = fract(g_closure_rand * 6.1803398875); float combined_weight = g_refraction_data.weight + g_diffuse_data.weight; - bool output_refraction = combined_weight > 0.0 && - (refract_rand * combined_weight) < g_refraction_data.weight; - if (output_refraction) { - /* Refraction. */ - vec4 closure; - closure.xy = gbuffer_normal_pack(g_refraction_data.N); - closure.z = g_refraction_data.roughness; - closure.w = gbuffer_ior_pack(g_refraction_data.ior); - /* Clamp to just bellow 1 to be able to distinguish between refraction and diffuse. - * Ceiling value is chosen by the storage format (16bit UNORM). */ - closure.w = min(closure.w, float(0xFFFFu - 1u) / float(0xFFFFu)); - imageStore(out_gbuff_closure_img, ivec3(out_texel, 1), closure); + if (combined_weight > 0.0) { + /* TODO(fclem) other RNG. */ + float refract_rand = fract(g_closure_rand * 6.1803398875); + bool output_refraction = (refract_rand * combined_weight) < g_refraction_data.weight; + if (output_refraction) { + /* Refraction. */ + vec4 closure; + closure.xy = gbuffer_normal_pack(g_refraction_data.N); + closure.z = g_refraction_data.roughness; + closure.w = gbuffer_ior_pack(g_refraction_data.ior); + imageStore(out_gbuf_closure_img, ivec3(out_texel, 1), closure); - vec4 color = gbuffer_color_pack(g_refraction_data.color); - imageStore(out_gbuff_color_img, ivec3(out_texel, 1), color); - } - else { - /* Diffuse. */ - vec4 closure; - closure.xy = gbuffer_normal_pack(g_diffuse_data.N); - closure.z = gbuffer_thickness_pack(thickness); - /* Used to detect the refraction case. Could be used for roughness. */ - closure.w = 1.0; - imageStore(out_gbuff_closure_img, ivec3(out_texel, 1), closure); + vec4 color = gbuffer_color_pack(g_refraction_data.color); + imageStore(out_gbuf_color_img, ivec3(out_texel, 1), color); + header |= CLOSURE_REFRACTION; + } + else { + /* Diffuse. */ + vec4 closure; + closure.xy = gbuffer_normal_pack(g_diffuse_data.N); + closure.z = gbuffer_thickness_pack(thickness); + closure.w = 0.0; /* Unused. */ + imageStore(out_gbuf_closure_img, ivec3(out_texel, 1), closure); - vec4 color = gbuffer_color_pack(g_diffuse_data.color); - imageStore(out_gbuff_color_img, ivec3(out_texel, 1), color); + vec4 color = gbuffer_color_pack(g_diffuse_data.color); + imageStore(out_gbuf_color_img, ivec3(out_texel, 1), color); + header |= CLOSURE_DIFFUSE; + } + + if (g_diffuse_data.sss_id > 0) { + /* SubSurface Scattering. */ + vec4 closure; + closure.xyz = gbuffer_sss_radii_pack(g_diffuse_data.sss_radius); + closure.w = gbuffer_object_id_unorm16_pack(uint(resource_id)); + imageStore(out_gbuf_closure_img, ivec3(out_texel, 2), closure); + header |= CLOSURE_SSS; + } } - if (true) { - /* SubSurface Scattering. */ - vec4 closure; - closure.xyz = gbuffer_sss_radii_pack(g_diffuse_data.sss_radius); - closure.w = gbuffer_object_id_unorm16_pack(g_diffuse_data.sss_id > 0 ? uint(resource_id) : 0); - imageStore(out_gbuff_closure_img, ivec3(out_texel, 2), closure); - } + imageStore(out_gbuf_header_img, out_texel, uvec4(header)); /* ----- Radiance output ----- */ diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_surf_forward_frag.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_forward_frag.glsl index 153963976bd..893aec25ac4 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_surf_forward_frag.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_forward_frag.glsl @@ -16,6 +16,7 @@ #pragma BLENDER_REQUIRE(eevee_nodetree_lib.glsl) #pragma BLENDER_REQUIRE(eevee_sampling_lib.glsl) #pragma BLENDER_REQUIRE(eevee_surf_lib.glsl) +#pragma BLENDER_REQUIRE(eevee_renderpass_lib.glsl) #pragma BLENDER_REQUIRE(eevee_volume_lib.glsl) vec4 closure_to_rgba(Closure cl) diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_surf_world_frag.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_world_frag.glsl index 35a97c3eb8c..2a889aef48b 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_surf_world_frag.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_world_frag.glsl @@ -13,6 +13,7 @@ #pragma BLENDER_REQUIRE(eevee_attributes_lib.glsl) #pragma BLENDER_REQUIRE(eevee_surf_lib.glsl) #pragma BLENDER_REQUIRE(eevee_nodetree_lib.glsl) +#pragma BLENDER_REQUIRE(eevee_renderpass_lib.glsl) void main() { diff --git a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_deferred_info.hh b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_deferred_info.hh index a419d94a8d9..0056a7515ff 100644 --- a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_deferred_info.hh +++ b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_deferred_info.hh @@ -10,12 +10,15 @@ #define image_in(slot, format, name) \ image(slot, format, Qualifier::READ, ImageType::FLOAT_2D, name, Frequency::PASS) +GPU_SHADER_CREATE_INFO(eevee_gbuffer_data) + .sampler(7, ImageType::UINT_2D, "gbuf_header_tx") + .sampler(8, ImageType::FLOAT_2D_ARRAY, "gbuf_closure_tx") + .sampler(9, ImageType::FLOAT_2D_ARRAY, "gbuf_color_tx"); + GPU_SHADER_CREATE_INFO(eevee_deferred_light) .fragment_source("eevee_deferred_light_frag.glsl") /* Early fragment test is needed to avoid processing fragments without correct GBuffer data. */ .early_fragment_test(true) - /* Inputs. */ - .sampler(0, ImageType::FLOAT_2D_ARRAY, "gbuffer_closure_tx") /* Chaining to next pass. */ /* TODO(@fclem): These could use the sub-pass feature. */ .image_out(2, GPU_RGBA16F, "direct_diffuse_img") @@ -23,6 +26,7 @@ GPU_SHADER_CREATE_INFO(eevee_deferred_light) .image_out(4, GPU_RGBA16F, "direct_refract_img") .define("SSS_TRANSMITTANCE") .additional_info("eevee_shared", + "eevee_gbuffer_data", "eevee_utility_texture", "eevee_sampling_data", "eevee_light_data", @@ -43,10 +47,11 @@ GPU_SHADER_CREATE_INFO(eevee_deferred_combine) .image_in(5, RAYTRACE_RADIANCE_FORMAT, "indirect_diffuse_img") .image_in(6, RAYTRACE_RADIANCE_FORMAT, "indirect_reflect_img") .image_in(7, RAYTRACE_RADIANCE_FORMAT, "indirect_refract_img") - .sampler(0, ImageType::FLOAT_2D_ARRAY, "gbuffer_closure_tx") - .sampler(1, ImageType::FLOAT_2D_ARRAY, "gbuffer_color_tx") .fragment_out(0, Type::VEC4, "out_combined") - .additional_info("eevee_shared", "eevee_render_pass_out", "draw_fullscreen") + .additional_info("eevee_shared", + "eevee_gbuffer_data", + "eevee_render_pass_out", + "draw_fullscreen") .fragment_source("eevee_deferred_combine_frag.glsl") .do_static_compilation(true); @@ -54,11 +59,10 @@ GPU_SHADER_CREATE_INFO(eevee_deferred_capture_eval) /* Early fragment test is needed to avoid processing fragments without correct GBuffer data. */ .early_fragment_test(true) /* Inputs. */ - .sampler(0, ImageType::FLOAT_2D_ARRAY, "gbuffer_closure_tx") - .sampler(1, ImageType::FLOAT_2D_ARRAY, "gbuffer_color_tx") .fragment_out(0, Type::VEC4, "out_radiance") .define("SSS_TRANSMITTANCE") .additional_info("eevee_shared", + "eevee_gbuffer_data", "eevee_utility_texture", "eevee_sampling_data", "eevee_light_data", diff --git a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh index 82fe048a237..57b14ba47e1 100644 --- a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh +++ b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh @@ -127,8 +127,9 @@ GPU_SHADER_CREATE_INFO(eevee_surf_deferred) .fragment_out(0, Type::VEC4, "out_transmittance", DualBlend::SRC_1) /* Everything is stored inside a two layered target, one for each format. This is to fit the * limitation of the number of images we can bind on a single shader. */ - .image_array_out(GBUF_CLOSURE_SLOT, Qualifier::WRITE, GPU_RGBA16, "out_gbuff_closure_img") - .image_array_out(GBUF_COLOR_SLOT, Qualifier::WRITE, GPU_RGB10_A2, "out_gbuff_color_img") + .image_array_out(GBUF_CLOSURE_SLOT, Qualifier::WRITE, GPU_RGBA16, "out_gbuf_closure_img") + .image_array_out(GBUF_COLOR_SLOT, Qualifier::WRITE, GPU_RGB10_A2, "out_gbuf_color_img") + .image(GBUF_HEADER_SLOT, GPU_R8UI, Qualifier::WRITE, ImageType::UINT_2D, "out_gbuf_header_img") .fragment_source("eevee_surf_deferred_frag.glsl") .additional_info("eevee_global_ubo", "eevee_utility_texture", diff --git a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_subsurface_info.hh b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_subsurface_info.hh index 5130711fc63..fafdb3791b7 100644 --- a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_subsurface_info.hh +++ b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_subsurface_info.hh @@ -7,9 +7,10 @@ GPU_SHADER_CREATE_INFO(eevee_subsurface_eval) .do_static_compilation(true) - .additional_info("eevee_shared", "eevee_global_ubo", "eevee_render_pass_out") - .sampler(0, ImageType::FLOAT_2D_ARRAY, "gbuffer_closure_tx") - .sampler(1, ImageType::FLOAT_2D_ARRAY, "gbuffer_color_tx") + .additional_info("eevee_shared", + "eevee_gbuffer_data", + "eevee_global_ubo", + "eevee_render_pass_out") .sampler(2, ImageType::FLOAT_2D, "radiance_tx") .early_fragment_test(true) .fragment_out(0, Type::VEC4, "out_combined") diff --git a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_tracing_info.hh b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_tracing_info.hh index f358c3d9681..10c089d9c71 100644 --- a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_tracing_info.hh +++ b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_tracing_info.hh @@ -9,10 +9,12 @@ GPU_SHADER_CREATE_INFO(name##_reflect) \ .do_static_compilation(true) \ .define("RAYTRACE_REFLECT") \ + .define("CLOSURE_ACTIVE", "eClosureBits(CLOSURE_REFLECTION)") \ .additional_info(#name); \ GPU_SHADER_CREATE_INFO(name##_refract) \ .do_static_compilation(true) \ .define("RAYTRACE_REFRACT") \ + .define("CLOSURE_ACTIVE", "eClosureBits(CLOSURE_REFRACTION)") \ .additional_info(#name); /* -------------------------------------------------------------------- */ @@ -22,10 +24,8 @@ GPU_SHADER_CREATE_INFO(eevee_ray_tile_classify) .do_static_compilation(true) .local_group_size(RAYTRACE_GROUP_SIZE, RAYTRACE_GROUP_SIZE) - .additional_info("eevee_shared", "eevee_global_ubo") + .additional_info("eevee_shared", "eevee_gbuffer_data", "eevee_global_ubo") .typedef_source("draw_shader_shared.h") - .sampler(0, ImageType::FLOAT_2D_ARRAY, "gbuffer_closure_tx") - .sampler(1, ImageType::UINT_2D, "stencil_tx") .image(0, RAYTRACE_TILEMASK_FORMAT, Qualifier::WRITE, ImageType::UINT_2D, "tile_mask_img") .storage_buf(0, Qualifier::WRITE, "DispatchCommand", "ray_dispatch_buf") .storage_buf(1, Qualifier::WRITE, "DispatchCommand", "denoise_dispatch_buf") @@ -46,12 +46,11 @@ GPU_SHADER_CREATE_INFO(eevee_ray_tile_compact) GPU_SHADER_CREATE_INFO(eevee_ray_generate) .local_group_size(RAYTRACE_GROUP_SIZE, RAYTRACE_GROUP_SIZE) .additional_info("eevee_shared", + "eevee_gbuffer_data", "eevee_global_ubo", "eevee_sampling_data", "draw_view", "eevee_utility_texture") - .sampler(0, ImageType::UINT_2D, "stencil_tx") - .sampler(1, ImageType::FLOAT_2D_ARRAY, "gbuffer_closure_tx") .image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "out_ray_data_img") .storage_buf(4, Qualifier::READ, "uint", "tiles_coord_buf[]") .compute_source("eevee_ray_generate_comp.glsl"); @@ -93,12 +92,11 @@ EEVEE_RAYTRACE_CLOSURE_VARIATION(eevee_ray_trace_screen) GPU_SHADER_CREATE_INFO(eevee_ray_denoise_spatial) .local_group_size(RAYTRACE_GROUP_SIZE, RAYTRACE_GROUP_SIZE) .additional_info("eevee_shared", + "eevee_gbuffer_data", "eevee_global_ubo", "eevee_sampling_data", "draw_view", "eevee_utility_texture") - .sampler(0, ImageType::FLOAT_2D_ARRAY, "gbuffer_closure_tx") - .sampler(1, ImageType::UINT_2D, "stencil_tx") .sampler(3, ImageType::DEPTH_2D, "depth_tx") .image(0, GPU_RGBA16F, Qualifier::READ, ImageType::FLOAT_2D, "ray_data_img") .image(1, GPU_RGBA16F, Qualifier::READ, ImageType::FLOAT_2D, "ray_time_img") @@ -130,8 +128,11 @@ GPU_SHADER_CREATE_INFO(eevee_ray_denoise_temporal) GPU_SHADER_CREATE_INFO(eevee_ray_denoise_bilateral) .local_group_size(RAYTRACE_GROUP_SIZE, RAYTRACE_GROUP_SIZE) - .additional_info("eevee_shared", "eevee_global_ubo", "eevee_sampling_data", "draw_view") - .sampler(0, ImageType::FLOAT_2D_ARRAY, "gbuffer_closure_tx") + .additional_info("eevee_shared", + "eevee_gbuffer_data", + "eevee_global_ubo", + "eevee_sampling_data", + "draw_view") .sampler(1, ImageType::DEPTH_2D, "depth_tx") .image(1, RAYTRACE_RADIANCE_FORMAT, Qualifier::READ, ImageType::FLOAT_2D, "in_radiance_img") .image(2, RAYTRACE_RADIANCE_FORMAT, Qualifier::WRITE, ImageType::FLOAT_2D, "out_radiance_img")