EEVEE Next: Volumes #107176

Merged
Miguel Pozo merged 126 commits from pragma37/blender:pull-eevee-next-volumes into main 2023-08-04 16:47:22 +02:00
4 changed files with 49 additions and 70 deletions
Showing only changes of commit ca7a7c6e0c - Show all commits

View File

@ -507,7 +507,7 @@ set(GLSL_SRC
engines/eevee_next/shaders/eevee_volume_material_frag.glsl
engines/eevee_next/shaders/eevee_volume_material_vert.glsl
engines/eevee_next/shaders/eevee_volume_resolve_frag.glsl
engines/eevee_next/shaders/eevee_volume_scatter_frag.glsl
engines/eevee_next/shaders/eevee_volume_scatter_comp.glsl
engines/eevee_next/shaders/eevee_volume_vert.glsl
engines/eevee_next/eevee_defines.hh

View File

@ -291,16 +291,19 @@ void Volumes::end_sync()
transparent_pass_transmit_tx_ = integrated_transmit_tx_;
scatter_ps_.init();
scatter_ps_.state_set(DRW_STATE_WRITE_COLOR);
scatter_ps_.shader_set(inst_.shaders.static_shader_get(
data_.use_lights ? VOLUME_SCATTER_WITH_LIGHTS : VOLUME_SCATTER));
bind_volume_pass_resources(scatter_ps_);
scatter_ps_.bind_texture("volumeScattering", &prop_scattering_tx_);
scatter_ps_.bind_texture("volumeExtinction", &prop_extinction_tx_);
scatter_ps_.bind_texture("volumeEmission", &prop_emission_tx_);
scatter_ps_.bind_texture("volumePhase", &prop_phase_tx_);
scatter_ps_.draw_procedural(GPU_PRIM_TRIS, 1, data_.tex_size.z * 3);
scatter_ps_.bind_texture("scattering_tx", &prop_scattering_tx_);
scatter_ps_.bind_texture("extinction_tx", &prop_extinction_tx_);
scatter_ps_.bind_texture("emission_tx", &prop_emission_tx_);
scatter_ps_.bind_texture("phase_tx", &prop_phase_tx_);
scatter_ps_.bind_image("out_scattering", &scatter_tx_);
scatter_ps_.bind_image("out_transmittance", &transmit_tx_);
scatter_ps_.dispatch(math::divide_ceil(data_.tex_size, int3(VOLUME_GROUP_SIZE)));
scatter_ps_.barrier(GPU_BARRIER_TEXTURE_FETCH | GPU_BARRIER_SHADER_IMAGE_ACCESS);
integration_ps_.init();
integration_ps_.state_set(DRW_STATE_WRITE_COLOR);
@ -328,13 +331,13 @@ void Volumes::draw_compute(View &view)
DRW_stats_group_start("Volumes");
inst_.manager->submit(world_ps_, view);
volumetric_fb_.ensure(GPU_ATTACHMENT_NONE,
GPU_ATTACHMENT_TEXTURE(prop_scattering_tx_),
GPU_ATTACHMENT_TEXTURE(prop_extinction_tx_),
GPU_ATTACHMENT_TEXTURE(prop_emission_tx_),
GPU_ATTACHMENT_TEXTURE(prop_phase_tx_));
inst_.manager->submit(world_ps_, view);
volumetric_fb_.bind();
inst_.pipelines.volume.render(view);

View File

@ -37,7 +37,7 @@ vec3 volume_scatter_light_eval(vec3 P, vec3 V, uint l_idx, float s_anisotropy)
return vec3(0);
}
vec3 Li = light_volume(ld, l_vector) * light_volume_shadow(ld, P, l_vector, volumeExtinction);
vec3 Li = light_volume(ld, l_vector) * light_volume_shadow(ld, P, l_vector, extinction_tx);
return Li * vis * phase_function(-V, l_vector.xyz / l_vector.w, s_anisotropy);
}
@ -46,42 +46,52 @@ vec3 volume_scatter_light_eval(vec3 P, vec3 V, uint l_idx, float s_anisotropy)
void main()
{
ivec3 volume_cell = ivec3(ivec2(gl_FragCoord.xy), volume_geom_iface.slice);
ivec3 froxel = ivec3(gl_GlobalInvocationID);
if (any(greaterThanEqual(froxel, volumes_buf.tex_size))) {
return;
}
/* Emission */
outScattering = texelFetch(volumeEmission, volume_cell, 0);
outTransmittance = texelFetch(volumeExtinction, volume_cell, 0);
vec3 s_scattering = texelFetch(volumeScattering, volume_cell, 0).rgb;
vec3 volume_ndc = volume_to_ndc((vec3(volume_cell) + volumes_buf.jitter) *
volumes_buf.inv_tex_size);
vec3 scattering = texelFetch(emission_tx, froxel, 0).rgb;
vec3 transmittance = texelFetch(extinction_tx, froxel, 0).rgb;
vec3 s_scattering = texelFetch(scattering_tx, froxel, 0).rgb;
vec3 volume_ndc = volume_to_ndc((vec3(froxel) + volumes_buf.jitter) * volumes_buf.inv_tex_size);
vec3 vP = get_view_space_from_depth(volume_ndc.xy, volume_ndc.z);
vec3 P = point_view_to_world(vP);
vec3 V = cameraVec(P);
vec2 phase = texelFetch(volumePhase, volume_cell, 0).rg;
vec2 phase = texelFetch(phase_tx, froxel, 0).rg;
float s_anisotropy = phase.x / max(1.0, phase.y);
fclem marked this conversation as resolved Outdated

This need a comment explaining why we divide by 2nd component.

This need a comment explaining why we divide by 2nd component.

To be honest I have no idea. Currently, only the first channel is ever written to.
It was like this in the current implementation so I left it there.
I assumed the second channel was intended to be used eventually.

To be honest I have no idea. Currently, only the first channel is ever written to. It was like this in the current implementation so I left it there. I assumed the second channel was intended to be used eventually.

It is used to store the number or phase that were written to it. This way we take the mean phase still using addive blending.

It is used to store the number or phase that were written to it. This way we take the mean phase still using addive blending.

Oops! This should be solved now.

Oops! This should be solved now.
/* Environment : Average color. */
fclem marked this conversation as resolved Outdated

This comment is obsolete.

This comment is obsolete.
outScattering.rgb += irradiance_volumetric(P) * s_scattering * phase_function_isotropic();
scattering += irradiance_volumetric(P) * s_scattering * phase_function_isotropic();
#ifdef VOLUME_LIGHTING
LIGHT_FOREACH_BEGIN_DIRECTIONAL (light_cull_buf, l_idx) {
outScattering.rgb += volume_scatter_light_eval(P, V, l_idx, s_anisotropy) * s_scattering;
scattering += volume_scatter_light_eval(P, V, l_idx, s_anisotropy) * s_scattering;
}
LIGHT_FOREACH_END
LIGHT_FOREACH_BEGIN_LOCAL (
light_cull_buf, light_zbin_buf, light_tile_buf, gl_FragCoord.xy, vP.z, l_idx) {
outScattering.rgb += volume_scatter_light_eval(P, V, l_idx, s_anisotropy) * s_scattering;
/* TODO (Miguel Pozo): Simplify computation. Fix coord_scale first. */
vec2 pixel = (vec2(froxel.xy) + vec2(0.5)) / vec2(volumes_buf.tex_size.xy) /
volumes_buf.viewport_size_inv;
LIGHT_FOREACH_BEGIN_LOCAL (light_cull_buf, light_zbin_buf, light_tile_buf, pixel, vP.z, l_idx) {
scattering += volume_scatter_light_eval(P, V, l_idx, s_anisotropy) * s_scattering;
}
LIGHT_FOREACH_END
#endif
/* Catch NaNs */
if (any(isnan(outScattering)) || any(isnan(outTransmittance))) {
outScattering = vec4(0.0);
outTransmittance = vec4(1.0);
if (any(isnan(scattering)) || any(isnan(transmittance))) {
scattering = vec3(0.0);
transmittance = vec3(1.0);
}
imageStore(out_scattering, froxel, vec4(scattering, 1.0));
imageStore(out_transmittance, froxel, vec4(transmittance, 1.0));
}

View File

@ -32,11 +32,6 @@ GPU_SHADER_CREATE_INFO(eevee_volume_base)
.fragment_out(2, Type::VEC4, "volumeEmissive")
.fragment_out(3, Type::VEC4, "volumePhase");
GPU_SHADER_CREATE_INFO(eevee_volume_base_comp)
.additional_info("eevee_volume_lib")
.define("STANDALONE")
.define("VOLUMETRICS");
GPU_SHADER_CREATE_INFO(eevee_volume_clear)
.additional_info("eevee_shared")
.uniform_buf(VOLUMES_BUF_SLOT, "VolumesData", "volumes_buf")
@ -48,57 +43,28 @@ GPU_SHADER_CREATE_INFO(eevee_volume_clear)
.image(3, GPU_RG16F, Qualifier::WRITE, ImageType::FLOAT_2D, "out_phase")
.do_static_compilation(true);
GPU_SHADER_CREATE_INFO(eevee_volume_scatter_common)
.define("STANDALONE")
.define("VOLUMETRICS")
.define("VOLUME_SHADOW")
GPU_SHADER_CREATE_INFO(eevee_volume_scatter)
.additional_info("draw_resource_id_varying")
.additional_info("eevee_volume_lib")
.compute_source("eevee_volume_scatter_comp.glsl")
.local_group_size(VOLUME_GROUP_SIZE, VOLUME_GROUP_SIZE, VOLUME_GROUP_SIZE)
.define("VOLUME_SHADOW")
/* NOTE: Unique sampler IDs assigned for consistency between library includes,
* and to avoid unique assignment collision validation error.
* However, resources will be auto assigned locations within shader usage. */
.sampler(17, ImageType::FLOAT_3D, "volumeScattering")
.sampler(18, ImageType::FLOAT_3D, "volumeExtinction")
.sampler(19, ImageType::FLOAT_3D, "volumeEmission")
.sampler(20, ImageType::FLOAT_3D, "volumePhase")
.fragment_out(0, Type::VEC4, "outScattering")
.fragment_out(1, Type::VEC4, "outTransmittance")
.vertex_source("eevee_volume_vert.glsl")
.fragment_source("eevee_volume_scatter_frag.glsl")
.vertex_out(eevee_volume_vert_geom_iface);
GPU_SHADER_CREATE_INFO(eevee_volume_scatter)
.additional_info("eevee_volume_scatter_common")
.geometry_source("eevee_volume_geom.glsl")
.geometry_out(eevee_volume_geom_frag_iface)
.geometry_layout(PrimitiveIn::TRIANGLES, PrimitiveOut::TRIANGLE_STRIP, 3)
.sampler(17, ImageType::FLOAT_3D, "scattering_tx")
.sampler(18, ImageType::FLOAT_3D, "extinction_tx")
.sampler(19, ImageType::FLOAT_3D, "emission_tx")
.sampler(20, ImageType::FLOAT_3D, "phase_tx")
.image(0, GPU_R11F_G11F_B10F, Qualifier::WRITE, ImageType::FLOAT_3D, "out_scattering")
.image(1, GPU_R11F_G11F_B10F, Qualifier::WRITE, ImageType::FLOAT_3D, "out_transmittance")
pragma37 marked this conversation as resolved Outdated

Doesnt seems to be necessary. Merge with eevee_volume_resolve.

Doesnt seems to be necessary. Merge with eevee_volume_resolve.
.do_static_compilation(true);
#ifdef WITH_METAL_BACKEND
GPU_SHADER_CREATE_INFO(eevee_volume_scatter_no_geom)
.additional_info("eevee_volume_scatter_common")
.vertex_out(eevee_volume_geom_frag_iface)
.metal_backend_only(true)
.do_static_compilation(true)
.auto_resource_location(true);
#endif
GPU_SHADER_CREATE_INFO(eevee_volume_scatter_with_lights_common).define("VOLUME_LIGHTING");
GPU_SHADER_CREATE_INFO(eevee_volume_scatter_with_lights)
.additional_info("eevee_volume_scatter_with_lights_common")
.additional_info("eevee_volume_scatter")
.define("VOLUME_LIGHTING")
.do_static_compilation(true);
#ifdef WITH_METAL_BACKEND
GPU_SHADER_CREATE_INFO(eevee_volume_scatter_with_lights_no_geom)
.additional_info("eevee_volume_scatter_with_lights_common")
.additional_info("eevee_volume_scatter_no_geom")
.metal_backend_only(true)
.do_static_compilation(true)
.auto_resource_location(true);
#endif
GPU_SHADER_CREATE_INFO(eevee_volume_integration_common)
pragma37 marked this conversation as resolved Outdated

This should also output to the volume renderpasses.

This should also output to the volume renderpasses.

I think we should actually get final (f12) rendering working first before looking into this?

I think we should actually get final (f12) rendering working first before looking into this?

Ok but then add a TODO here.

Ok but then add a TODO here.
.define("STANDALONE")
.additional_info("eevee_volume_lib")