EEVEE-Next: Raytrace: Add Diffuse Ray
This implement the diffuse tracing as simple screen-space ray trace. This is extremely inefficient and should only be used for reference purpose. The real screen space diffuse implementation will be done in another PR. Depends on #112507 ![image](/attachments/a2c0a9d9-3206-4dc7-acf8-0c37851ad10b) Pull Request: https://projects.blender.org/blender/blender/pulls/112539
This commit is contained in:
parent
2638f30983
commit
89da0cf07d
|
@ -78,6 +78,8 @@
|
|||
#define RAYTRACE_GROUP_SIZE 8
|
||||
/* Keep this as a define to avoid shader variations. */
|
||||
#define RAYTRACE_RADIANCE_FORMAT GPU_R11F_G11F_B10F
|
||||
#define RAYTRACE_RAYTIME_FORMAT GPU_R32F
|
||||
#define RAYTRACE_HORIZON_FORMAT GPU_R32UI
|
||||
#define RAYTRACE_VARIANCE_FORMAT GPU_R16F
|
||||
#define RAYTRACE_TILEMASK_FORMAT GPU_R8UI
|
||||
|
||||
|
|
|
@ -593,10 +593,13 @@ void DeferredLayer::render(View &main_view,
|
|||
inst_.subsurface.render(render_view, combined_fb, direct_diffuse_tx_);
|
||||
}
|
||||
|
||||
TextureFromPool dummy_diffuse_indirect;
|
||||
dummy_diffuse_indirect.acquire(int2(1), RAYTRACE_RADIANCE_FORMAT);
|
||||
dummy_diffuse_indirect.clear(float4(0));
|
||||
RayTraceResult diffuse_result = {dummy_diffuse_indirect};
|
||||
RayTraceResult diffuse_result = inst_.raytracing.trace(rt_buffer,
|
||||
radiance_feedback_tx_,
|
||||
radiance_feedback_persmat_,
|
||||
closure_bits_,
|
||||
CLOSURE_DIFFUSE,
|
||||
main_view,
|
||||
render_view);
|
||||
|
||||
RayTraceResult reflect_result = inst_.raytracing.trace(rt_buffer,
|
||||
radiance_feedback_tx_,
|
||||
|
|
|
@ -41,6 +41,16 @@ void RayTraceModule::sync()
|
|||
{
|
||||
Texture &depth_tx = inst_.render_buffers.depth_tx;
|
||||
|
||||
#define SHADER_VARIATION(_shader_name, _index) \
|
||||
((_index == 0) ? _shader_name##REFLECT : \
|
||||
(_index == 1) ? _shader_name##REFRACT : \
|
||||
_shader_name##DIFFUSE)
|
||||
|
||||
#define PASS_VARIATION(_pass_name, _index, _suffix) \
|
||||
((_index == 0) ? _pass_name##reflect##_suffix : \
|
||||
(_index == 1) ? _pass_name##refract##_suffix : \
|
||||
_pass_name##diffuse##_suffix)
|
||||
|
||||
/* Setup. */
|
||||
{
|
||||
PassSimple &pass = tile_classify_ps_;
|
||||
|
@ -67,11 +77,10 @@ void RayTraceModule::sync()
|
|||
pass.dispatch(&tile_compact_dispatch_size_);
|
||||
pass.barrier(GPU_BARRIER_SHADER_STORAGE);
|
||||
}
|
||||
for (auto type : IndexRange(2)) {
|
||||
PassSimple &pass = (type == 0) ? generate_reflect_ps_ : generate_refract_ps_;
|
||||
for (auto type : IndexRange(3)) {
|
||||
PassSimple &pass = PASS_VARIATION(generate_, type, _ps_);
|
||||
pass.init();
|
||||
pass.shader_set(inst_.shaders.static_shader_get((type == 0) ? RAY_GENERATE_REFLECT :
|
||||
RAY_GENERATE_REFRACT));
|
||||
pass.shader_set(inst_.shaders.static_shader_get(SHADER_VARIATION(RAY_GENERATE_, type)));
|
||||
pass.bind_texture(RBUFS_UTILITY_TEX_SLOT, inst_.pipelines.utility_tx);
|
||||
pass.bind_image("out_ray_data_img", &ray_data_tx_);
|
||||
pass.bind_ssbo("tiles_coord_buf", &ray_tiles_buf_);
|
||||
|
@ -82,11 +91,10 @@ void RayTraceModule::sync()
|
|||
GPU_BARRIER_SHADER_IMAGE_ACCESS);
|
||||
}
|
||||
/* Tracing. */
|
||||
for (auto type : IndexRange(2)) {
|
||||
PassSimple &pass = (type == 0) ? trace_reflect_ps_ : trace_refract_ps_;
|
||||
for (auto type : IndexRange(3)) {
|
||||
PassSimple &pass = PASS_VARIATION(trace_, type, _ps_);
|
||||
pass.init();
|
||||
pass.shader_set(inst_.shaders.static_shader_get((type == 0) ? RAY_TRACE_SCREEN_REFLECT :
|
||||
RAY_TRACE_SCREEN_REFRACT));
|
||||
pass.shader_set(inst_.shaders.static_shader_get(SHADER_VARIATION(RAY_TRACE_SCREEN_, type)));
|
||||
pass.bind_ssbo("tiles_coord_buf", &ray_tiles_buf_);
|
||||
pass.bind_image("ray_data_img", &ray_data_tx_);
|
||||
pass.bind_image("ray_time_img", &ray_time_tx_);
|
||||
|
@ -115,11 +123,10 @@ void RayTraceModule::sync()
|
|||
pass.barrier(GPU_BARRIER_SHADER_IMAGE_ACCESS);
|
||||
}
|
||||
/* Denoise. */
|
||||
for (auto type : IndexRange(2)) {
|
||||
PassSimple &pass = (type == 0) ? denoise_spatial_reflect_ps_ : denoise_spatial_refract_ps_;
|
||||
for (auto type : IndexRange(3)) {
|
||||
PassSimple &pass = PASS_VARIATION(denoise_spatial_, type, _ps_);
|
||||
pass.init();
|
||||
pass.shader_set(inst_.shaders.static_shader_get((type == 0) ? RAY_DENOISE_SPATIAL_REFLECT :
|
||||
RAY_DENOISE_SPATIAL_REFRACT));
|
||||
pass.shader_set(inst_.shaders.static_shader_get(SHADER_VARIATION(RAY_DENOISE_SPATIAL_, type)));
|
||||
pass.bind_ssbo("tiles_coord_buf", &denoise_tiles_buf_);
|
||||
pass.bind_texture(RBUFS_UTILITY_TEX_SLOT, inst_.pipelines.utility_tx);
|
||||
pass.bind_texture("depth_tx", &depth_tx);
|
||||
|
@ -155,11 +162,11 @@ void RayTraceModule::sync()
|
|||
pass.dispatch(denoise_dispatch_buf_);
|
||||
pass.barrier(GPU_BARRIER_SHADER_IMAGE_ACCESS);
|
||||
}
|
||||
for (auto type : IndexRange(2)) {
|
||||
PassSimple &pass = (type == 0) ? denoise_bilateral_reflect_ps_ : denoise_bilateral_refract_ps_;
|
||||
for (auto type : IndexRange(3)) {
|
||||
PassSimple &pass = PASS_VARIATION(denoise_bilateral_, type, _ps_);
|
||||
pass.init();
|
||||
pass.shader_set(inst_.shaders.static_shader_get((type == 0) ? RAY_DENOISE_BILATERAL_REFLECT :
|
||||
RAY_DENOISE_BILATERAL_REFRACT));
|
||||
pass.shader_set(
|
||||
inst_.shaders.static_shader_get(SHADER_VARIATION(RAY_DENOISE_BILATERAL_, type)));
|
||||
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_);
|
||||
|
@ -172,6 +179,9 @@ void RayTraceModule::sync()
|
|||
pass.dispatch(denoise_dispatch_buf_);
|
||||
pass.barrier(GPU_BARRIER_SHADER_IMAGE_ACCESS);
|
||||
}
|
||||
|
||||
#undef SHADER_VARIATION
|
||||
#undef PASS_VARIATION
|
||||
}
|
||||
|
||||
void RayTraceModule::debug_pass_sync() {}
|
||||
|
@ -190,8 +200,8 @@ RayTraceResult RayTraceModule::trace(RayTraceBuffer &rt_buffer,
|
|||
{
|
||||
BLI_assert_msg(count_bits_i(raytrace_closure) == 1,
|
||||
"Only one closure type can be raytraced at a time.");
|
||||
BLI_assert_msg(raytrace_closure ==
|
||||
(raytrace_closure & (CLOSURE_REFLECTION | CLOSURE_REFRACTION)),
|
||||
BLI_assert_msg(raytrace_closure == (raytrace_closure &
|
||||
(CLOSURE_REFLECTION | CLOSURE_REFRACTION | CLOSURE_DIFFUSE)),
|
||||
"Only reflection and refraction are implemented.");
|
||||
|
||||
if (tracing_method_ == RAYTRACE_EEVEE_METHOD_NONE) {
|
||||
|
@ -207,7 +217,15 @@ RayTraceResult RayTraceModule::trace(RayTraceBuffer &rt_buffer,
|
|||
PassSimple *denoise_bilateral_ps = nullptr;
|
||||
RayTraceBuffer::DenoiseBuffer *denoise_buf = nullptr;
|
||||
|
||||
if (raytrace_closure == CLOSURE_REFLECTION) {
|
||||
if (raytrace_closure == CLOSURE_DIFFUSE) {
|
||||
options = reflection_options_;
|
||||
generate_ray_ps = &generate_diffuse_ps_;
|
||||
trace_ray_ps = force_no_tracing ? &trace_diffuse_ps_ : &trace_diffuse_ps_;
|
||||
denoise_spatial_ps = &denoise_spatial_diffuse_ps_;
|
||||
denoise_bilateral_ps = &denoise_bilateral_diffuse_ps_;
|
||||
denoise_buf = &rt_buffer.diffuse;
|
||||
}
|
||||
else if (raytrace_closure == CLOSURE_REFLECTION) {
|
||||
options = reflection_options_;
|
||||
generate_ray_ps = &generate_reflect_ps_;
|
||||
trace_ray_ps = force_no_tracing ? &trace_fallback_ps_ : &trace_reflect_ps_;
|
||||
|
@ -286,7 +304,7 @@ RayTraceResult RayTraceModule::trace(RayTraceBuffer &rt_buffer,
|
|||
{
|
||||
/* Tracing rays. */
|
||||
ray_data_tx_.acquire(tracing_res, GPU_RGBA16F);
|
||||
ray_time_tx_.acquire(tracing_res, GPU_R32F);
|
||||
ray_time_tx_.acquire(tracing_res, RAYTRACE_RAYTIME_FORMAT);
|
||||
ray_radiance_tx_.acquire(tracing_res, RAYTRACE_RADIANCE_FORMAT);
|
||||
|
||||
inst_.manager->submit(*generate_ray_ps, render_view);
|
||||
|
|
|
@ -54,7 +54,7 @@ struct RayTraceBuffer {
|
|||
* One for each closure type. Not to be mistaken with deferred layer type.
|
||||
* For instance the opaque deferred layer will only used the reflection history buffer.
|
||||
*/
|
||||
DenoiseBuffer reflection, refraction;
|
||||
DenoiseBuffer reflection, refraction, diffuse;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -103,14 +103,18 @@ class RayTraceModule {
|
|||
|
||||
draw::PassSimple tile_classify_ps_ = {"TileClassify"};
|
||||
draw::PassSimple tile_compact_ps_ = {"TileCompact"};
|
||||
draw::PassSimple generate_diffuse_ps_ = {"RayGenerate.Diffuse"};
|
||||
draw::PassSimple generate_reflect_ps_ = {"RayGenerate.Reflection"};
|
||||
draw::PassSimple generate_refract_ps_ = {"RayGenerate.Refraction"};
|
||||
draw::PassSimple trace_diffuse_ps_ = {"Trace.Diffuse"};
|
||||
draw::PassSimple trace_reflect_ps_ = {"Trace.Reflection"};
|
||||
draw::PassSimple trace_refract_ps_ = {"Trace.Refraction"};
|
||||
draw::PassSimple trace_fallback_ps_ = {"Trace.Fallback"};
|
||||
draw::PassSimple denoise_spatial_diffuse_ps_ = {"DenoiseSpatial.Diffuse"};
|
||||
draw::PassSimple denoise_spatial_reflect_ps_ = {"DenoiseSpatial.Reflection"};
|
||||
draw::PassSimple denoise_spatial_refract_ps_ = {"DenoiseSpatial.Refraction"};
|
||||
draw::PassSimple denoise_temporal_ps_ = {"DenoiseTemporal"};
|
||||
draw::PassSimple denoise_bilateral_diffuse_ps_ = {"DenoiseBilateral.Diffuse"};
|
||||
draw::PassSimple denoise_bilateral_reflect_ps_ = {"DenoiseBilateral.Reflection"};
|
||||
draw::PassSimple denoise_bilateral_refract_ps_ = {"DenoiseBilateral.Refraction"};
|
||||
|
||||
|
|
|
@ -156,22 +156,30 @@ const char *ShaderModule::static_shader_create_info_name_get(eShaderType shader_
|
|||
return "eevee_light_culling_tile";
|
||||
case LIGHT_CULLING_ZBIN:
|
||||
return "eevee_light_culling_zbin";
|
||||
case RAY_DENOISE_SPATIAL_DIFFUSE:
|
||||
return "eevee_ray_denoise_spatial_diffuse";
|
||||
case RAY_DENOISE_SPATIAL_REFLECT:
|
||||
return "eevee_ray_denoise_spatial_reflect";
|
||||
case RAY_DENOISE_SPATIAL_REFRACT:
|
||||
return "eevee_ray_denoise_spatial_refract";
|
||||
case RAY_DENOISE_TEMPORAL:
|
||||
return "eevee_ray_denoise_temporal";
|
||||
case RAY_DENOISE_BILATERAL_DIFFUSE:
|
||||
return "eevee_ray_denoise_bilateral_diffuse";
|
||||
case RAY_DENOISE_BILATERAL_REFLECT:
|
||||
return "eevee_ray_denoise_bilateral_reflect";
|
||||
case RAY_DENOISE_BILATERAL_REFRACT:
|
||||
return "eevee_ray_denoise_bilateral_refract";
|
||||
case RAY_GENERATE_DIFFUSE:
|
||||
return "eevee_ray_generate_diffuse";
|
||||
case RAY_GENERATE_REFLECT:
|
||||
return "eevee_ray_generate_reflect";
|
||||
case RAY_GENERATE_REFRACT:
|
||||
return "eevee_ray_generate_refract";
|
||||
case RAY_TRACE_FALLBACK:
|
||||
return "eevee_ray_trace_fallback";
|
||||
case RAY_TRACE_SCREEN_DIFFUSE:
|
||||
return "eevee_ray_trace_screen_diffuse";
|
||||
case RAY_TRACE_SCREEN_REFLECT:
|
||||
return "eevee_ray_trace_screen_reflect";
|
||||
case RAY_TRACE_SCREEN_REFRACT:
|
||||
|
|
|
@ -78,16 +78,20 @@ enum eShaderType {
|
|||
MOTION_BLUR_TILE_FLATTEN_RGBA,
|
||||
MOTION_BLUR_TILE_FLATTEN_RG,
|
||||
|
||||
RAY_DENOISE_BILATERAL_DIFFUSE,
|
||||
RAY_DENOISE_BILATERAL_REFLECT,
|
||||
RAY_DENOISE_BILATERAL_REFRACT,
|
||||
RAY_DENOISE_SPATIAL_DIFFUSE,
|
||||
RAY_DENOISE_SPATIAL_REFLECT,
|
||||
RAY_DENOISE_SPATIAL_REFRACT,
|
||||
RAY_DENOISE_TEMPORAL,
|
||||
RAY_GENERATE_DIFFUSE,
|
||||
RAY_GENERATE_REFLECT,
|
||||
RAY_GENERATE_REFRACT,
|
||||
RAY_TILE_CLASSIFY,
|
||||
RAY_TILE_COMPACT,
|
||||
RAY_TRACE_FALLBACK,
|
||||
RAY_TRACE_SCREEN_DIFFUSE,
|
||||
RAY_TRACE_SCREEN_REFLECT,
|
||||
RAY_TRACE_SCREEN_REFRACT,
|
||||
|
||||
|
|
|
@ -173,7 +173,7 @@ vec3 sample_uniform_hemisphere(vec3 rand, vec3 N, vec3 T, vec3 B, out float pdf)
|
|||
{
|
||||
vec3 tH = sample_uniform_hemisphere(rand);
|
||||
pdf = sample_pdf_uniform_hemisphere();
|
||||
return tH * mat3(N, T, B);
|
||||
return mat3(T, B, N) * tH;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
@ -200,7 +200,7 @@ vec3 sample_cosine_hemisphere(vec3 rand, vec3 N, vec3 T, vec3 B, out float pdf)
|
|||
{
|
||||
vec3 tH = sample_cosine_hemisphere(rand);
|
||||
pdf = sample_pdf_cosine_hemisphere(tH.z);
|
||||
return tH * mat3(N, T, B);
|
||||
return mat3(T, B, N) * tH;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -5,8 +5,7 @@
|
|||
/**
|
||||
* Compute light objects lighting contribution using Gbuffer data.
|
||||
*
|
||||
* Output light either directly to the radiance buffers or to temporary radiance accumulation
|
||||
* buffer that will be processed by other deferred lighting passes.
|
||||
* Output light .
|
||||
*/
|
||||
|
||||
#pragma BLENDER_REQUIRE(eevee_gbuffer_lib.glsl)
|
||||
|
@ -42,6 +41,8 @@ void main()
|
|||
gbuf.thickness,
|
||||
diffuse_light,
|
||||
reflection_light,
|
||||
/* TODO(fclem): Implement refraction light. */
|
||||
// refraction_light,
|
||||
shadow);
|
||||
|
||||
output_renderpass_value(uniform_buf.render_pass.shadow_id, shadow);
|
||||
|
|
|
@ -118,7 +118,11 @@ void main()
|
|||
#endif
|
||||
gbuffer_load_closure_data(gbuf_closure_tx, texel_fullres, center_closure);
|
||||
|
||||
#if defined(RAYTRACE_DIFFUSE)
|
||||
float roughness = 1.0;
|
||||
#else
|
||||
float roughness = center_closure.roughness;
|
||||
#endif
|
||||
|
||||
float variance = imageLoad(in_variance_img, texel_fullres).r;
|
||||
vec3 in_radiance = imageLoad(in_radiance_img, texel_fullres).rgb;
|
||||
|
|
|
@ -24,7 +24,9 @@ void main()
|
|||
|
||||
GBufferData gbuf = gbuffer_read(gbuf_header_tx, gbuf_closure_tx, gbuf_color_tx, texel_fullres);
|
||||
|
||||
#if defined(RAYTRACE_REFLECT)
|
||||
#if defined(RAYTRACE_DIFFUSE)
|
||||
bool valid_pixel = gbuf.has_diffuse;
|
||||
#elif defined(RAYTRACE_REFLECT)
|
||||
bool valid_pixel = gbuf.has_reflection;
|
||||
#elif defined(RAYTRACE_REFRACT)
|
||||
bool valid_pixel = gbuf.has_refraction;
|
||||
|
@ -39,7 +41,9 @@ void main()
|
|||
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;
|
||||
|
||||
#if defined(RAYTRACE_REFLECT)
|
||||
#if defined(RAYTRACE_DIFFUSE)
|
||||
ClosureDiffuse closure = gbuf.diffuse;
|
||||
#elif defined(RAYTRACE_REFLECT)
|
||||
ClosureReflection closure = gbuf.reflection;
|
||||
#elif defined(RAYTRACE_REFRACT)
|
||||
ClosureRefraction closure = gbuf.refraction;
|
||||
|
|
|
@ -45,7 +45,7 @@ void main()
|
|||
float noise_offset = sampling_rng_1D_get(SAMPLING_RAYTRACE_W);
|
||||
float rand_trace = interlieved_gradient_noise(vec2(texel), 5.0, noise_offset);
|
||||
|
||||
#if defined(RAYTRACE_REFLECT)
|
||||
#if defined(RAYTRACE_REFLECT) || defined(RAYTRACE_DIFFUSE)
|
||||
const bool discard_backface = true;
|
||||
const bool allow_self_intersection = false;
|
||||
#elif defined(RAYTRACE_REFRACT)
|
||||
|
|
|
@ -6,6 +6,11 @@
|
|||
#include "gpu_shader_create_info.hh"
|
||||
|
||||
#define EEVEE_RAYTRACE_CLOSURE_VARIATION(name, ...) \
|
||||
GPU_SHADER_CREATE_INFO(name##_diffuse) \
|
||||
.do_static_compilation(true) \
|
||||
.define("RAYTRACE_DIFFUSE") \
|
||||
.define("CLOSURE_ACTIVE", "eClosureBits(CLOSURE_DIFFUSE)") \
|
||||
.additional_info(#name); \
|
||||
GPU_SHADER_CREATE_INFO(name##_reflect) \
|
||||
.do_static_compilation(true) \
|
||||
.define("RAYTRACE_REFLECT") \
|
||||
|
@ -65,7 +70,7 @@ GPU_SHADER_CREATE_INFO(eevee_ray_trace_fallback)
|
|||
"draw_view",
|
||||
"eevee_reflection_probe_data")
|
||||
.image(0, GPU_RGBA16F, Qualifier::READ, ImageType::FLOAT_2D, "ray_data_img")
|
||||
.image(1, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "ray_time_img")
|
||||
.image(1, RAYTRACE_RAYTIME_FORMAT, Qualifier::WRITE, ImageType::FLOAT_2D, "ray_time_img")
|
||||
.image(2, RAYTRACE_RADIANCE_FORMAT, Qualifier::WRITE, ImageType::FLOAT_2D, "ray_radiance_img")
|
||||
.sampler(1, ImageType::DEPTH_2D, "depth_tx")
|
||||
.storage_buf(4, Qualifier::READ, "uint", "tiles_coord_buf[]")
|
||||
|
@ -80,7 +85,7 @@ GPU_SHADER_CREATE_INFO(eevee_ray_trace_screen)
|
|||
"eevee_hiz_data",
|
||||
"eevee_reflection_probe_data")
|
||||
.image(0, GPU_RGBA16F, Qualifier::READ, ImageType::FLOAT_2D, "ray_data_img")
|
||||
.image(1, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "ray_time_img")
|
||||
.image(1, RAYTRACE_RAYTIME_FORMAT, Qualifier::WRITE, ImageType::FLOAT_2D, "ray_time_img")
|
||||
.image(2, RAYTRACE_RADIANCE_FORMAT, Qualifier::WRITE, ImageType::FLOAT_2D, "ray_radiance_img")
|
||||
.sampler(0, ImageType::FLOAT_2D, "screen_radiance_tx")
|
||||
.sampler(1, ImageType::DEPTH_2D, "depth_tx")
|
||||
|
@ -99,7 +104,7 @@ GPU_SHADER_CREATE_INFO(eevee_ray_denoise_spatial)
|
|||
"eevee_utility_texture")
|
||||
.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")
|
||||
.image(1, RAYTRACE_RAYTIME_FORMAT, Qualifier::READ, ImageType::FLOAT_2D, "ray_time_img")
|
||||
.image(2, RAYTRACE_RADIANCE_FORMAT, Qualifier::READ, ImageType::FLOAT_2D, "ray_radiance_img")
|
||||
.image(3, RAYTRACE_RADIANCE_FORMAT, Qualifier::WRITE, ImageType::FLOAT_2D, "out_radiance_img")
|
||||
.image(4, RAYTRACE_VARIANCE_FORMAT, Qualifier::WRITE, ImageType::FLOAT_2D, "out_variance_img")
|
||||
|
|
Loading…
Reference in New Issue