From 90806591ce1ecdda6709b8ce5493a28166d9d424 Mon Sep 17 00:00:00 2001 From: Miguel Pozo Date: Fri, 24 Feb 2023 19:40:43 +0100 Subject: [PATCH 01/10] Port draw_volume to the new Draw Manager --- source/blender/draw/CMakeLists.txt | 1 + source/blender/draw/intern/draw_common.hh | 24 ++++ source/blender/draw/intern/draw_volume.cc | 160 ++++++++++++++++++++++ 3 files changed, 185 insertions(+) create mode 100644 source/blender/draw/intern/draw_common.hh diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index c6f8dcf335f..5058fb5f0fc 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -233,6 +233,7 @@ set(SRC intern/draw_color_management.h intern/draw_command.hh intern/draw_common.h + intern/draw_common.hh intern/draw_common_shader_shared.h intern/draw_curves_private.hh intern/draw_debug.h diff --git a/source/blender/draw/intern/draw_common.hh b/source/blender/draw/intern/draw_common.hh new file mode 100644 index 00000000000..ff2c77a89cb --- /dev/null +++ b/source/blender/draw/intern/draw_common.hh @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2016 Blender Foundation. */ + +/** \file + * \ingroup draw + */ + +#pragma once + +#include "draw_common.h" +#include "draw_manager.hh" +#include "draw_pass.hh" + +namespace blender::draw { + +struct VolumeAttribute { + StringRefNull input_name; + StringRefNull name; + eGPUDefaultValue default_value; +}; + +bool volume_sub_pass(PassMain::Sub &ps, Scene *scene, Object *ob, Span attrs); + +} // namespace blender::draw diff --git a/source/blender/draw/intern/draw_volume.cc b/source/blender/draw/intern/draw_volume.cc index 34c54b63230..be05b1adfb9 100644 --- a/source/blender/draw/intern/draw_volume.cc +++ b/source/blender/draw/intern/draw_volume.cc @@ -25,6 +25,8 @@ #include "draw_common.h" #include "draw_manager.h" +#include "draw_common.hh" + using namespace blender; using namespace blender::draw; using VolumeInfosBuf = blender::draw::UniformBuffer; @@ -273,3 +275,161 @@ DRWShadingGroup *DRW_shgroup_volume_create_sub(Scene *scene, } return drw_volume_object_mesh_init(scene, ob, &attrs, shgrp); } + +/* Temporary port to Draw Manager Next */ + +namespace blender::draw { + +static bool volume_world_grids_init(PassMain::Sub &ps, Span attrs) +{ + for (const VolumeAttribute &attr : attrs) { + ps.bind_texture(attr.input_name.c_str(), grid_default_texture(attr.default_value)); + } + + return true; +} + +static bool volume_object_grids_init(PassMain::Sub &ps, Object *ob, Span attrs) +{ + VolumeUniformBufPool *pool = (VolumeUniformBufPool *)DST.vmempool->volume_grids_ubos; + VolumeInfosBuf &volume_infos = *pool->alloc(); + + Volume *volume = (Volume *)ob->data; + BKE_volume_load(volume, G.main); + + volume_infos.density_scale = BKE_volume_density_scale(volume, ob->object_to_world); + volume_infos.color_mul = float4(1.0f); + volume_infos.temperature_mul = 1.0f; + volume_infos.temperature_bias = 0.0f; + + bool has_grids = false; + for (const VolumeAttribute &attr : attrs) { + if (BKE_volume_grid_find_for_read(volume, attr.name.c_str()) != nullptr) { + has_grids = true; + break; + } + } + /* Render nothing if there is no attribute for the shader to render. + * This also avoids an assert caused by the bounding box being zero in size. */ + if (!has_grids) { + return false; + } + + /* Bind volume grid textures. */ + int grid_id = 0, grids_len = 0; + for (const VolumeAttribute &attr : attrs) { + const VolumeGrid *volume_grid = BKE_volume_grid_find_for_read(volume, attr.name.c_str()); + const DRWVolumeGrid *drw_grid = (volume_grid) ? + DRW_volume_batch_cache_get_grid(volume, volume_grid) : + nullptr; + /* Handle 3 cases here: + * - Grid exists and texture was loaded -> use texture. + * - Grid exists but has zero size or failed to load -> use zero. + * - Grid does not exist -> use default value. */ + const GPUTexture *grid_tex = (drw_grid) ? drw_grid->texture : + (volume_grid) ? g_data.dummy_zero : + grid_default_texture(attr.default_value); + /* TODO (Miguel Pozo): bind_texture const support ? */ + ps.bind_texture(attr.input_name.c_str(), (GPUTexture *)grid_tex); + + volume_infos.grids_xform[grid_id++] = float4x4(drw_grid ? drw_grid->object_to_texture : + g_data.dummy_grid_mat); + } + + volume_infos.push_update(); + + ps.bind_ubo("drw_volume", volume_infos); + + return true; +} + +static bool drw_volume_object_mesh_init(PassMain::Sub &ps, + Scene *scene, + Object *ob, + Span attrs) +{ + VolumeUniformBufPool *pool = (VolumeUniformBufPool *)DST.vmempool->volume_grids_ubos; + VolumeInfosBuf &volume_infos = *pool->alloc(); + + ModifierData *md = nullptr; + + volume_infos.density_scale = 1.0f; + volume_infos.color_mul = float4(1.0f); + volume_infos.temperature_mul = 1.0f; + volume_infos.temperature_bias = 0.0f; + + /* Smoke Simulation */ + if ((md = BKE_modifiers_findby_type(ob, eModifierType_Fluid)) && + BKE_modifier_is_enabled(scene, md, eModifierMode_Realtime) && + ((FluidModifierData *)md)->domain != nullptr) { + FluidModifierData *fmd = (FluidModifierData *)md; + FluidDomainSettings *fds = fmd->domain; + + /* Don't try to show liquid domains here. */ + if (!fds->fluid || !(fds->type == FLUID_DOMAIN_TYPE_GAS)) { + return false; + } + + if (fds->fluid && (fds->type == FLUID_DOMAIN_TYPE_GAS)) { + DRW_smoke_ensure(fmd, fds->flags & FLUID_DOMAIN_USE_NOISE); + } + + int grid_id = 0; + for (const VolumeAttribute &attr : attrs) { + if (STREQ(attr.name.c_str(), "density")) { + ps.bind_texture(attr.input_name.c_str(), + fds->tex_density ? &fds->tex_density : &g_data.dummy_one); + } + else if (STREQ(attr.name.c_str(), "color")) { + ps.bind_texture(attr.input_name.c_str(), + fds->tex_color ? &fds->tex_color : &g_data.dummy_one); + } + else if (STR_ELEM(attr.name.c_str(), "flame", "temperature")) { + ps.bind_texture(attr.input_name.c_str(), + fds->tex_flame ? &fds->tex_flame : &g_data.dummy_zero); + } + else { + ps.bind_texture(attr.input_name.c_str(), grid_default_texture(attr.default_value)); + } + volume_infos.grids_xform[grid_id++] = float4x4(g_data.dummy_grid_mat); + } + + bool use_constant_color = ((fds->active_fields & FLUID_DOMAIN_ACTIVE_COLORS) == 0 && + (fds->active_fields & FLUID_DOMAIN_ACTIVE_COLOR_SET) != 0); + if (use_constant_color) { + volume_infos.color_mul = float4(UNPACK3(fds->active_color), 1.0f); + } + + /* Output is such that 0..1 maps to 0..1000K */ + volume_infos.temperature_mul = fds->flame_max_temp - fds->flame_ignition; + volume_infos.temperature_bias = fds->flame_ignition; + } + else { + int grid_id = 0; + for (const VolumeAttribute &attr : attrs) { + ps.bind_texture(attr.input_name.c_str(), grid_default_texture(attr.default_value)); + volume_infos.grids_xform[grid_id++] = float4x4(g_data.dummy_grid_mat); + } + } + + volume_infos.push_update(); + + ps.bind_ubo("drw_volume", volume_infos); + + return true; +} + +bool volume_sub_pass(PassMain::Sub &ps, Scene *scene, Object *ob, Span attrs) +{ + if (ob == nullptr) { + return volume_world_grids_init(ps, attrs); + } + else if (ob->type == OB_VOLUME) { + return volume_object_grids_init(ps, ob, attrs); + } + else { + return drw_volume_object_mesh_init(ps, scene, ob, attrs); + } +} + +} // namespace blender::draw -- 2.30.2 From 78861a003570a4bdb548aa8112494332800ad81d Mon Sep 17 00:00:00 2001 From: Miguel Pozo Date: Wed, 1 Mar 2023 20:01:16 +0100 Subject: [PATCH 02/10] Volume Objects --- .../shaders/infos/workbench_volume_info.hh | 37 ++- .../engines/workbench/workbench_engine.cc | 228 +++++++++++++++--- source/blender/draw/intern/draw_volume.cc | 1 + .../draw/intern/shaders/draw_view_info.hh | 3 + 4 files changed, 229 insertions(+), 40 deletions(-) diff --git a/source/blender/draw/engines/workbench/shaders/infos/workbench_volume_info.hh b/source/blender/draw/engines/workbench/shaders/infos/workbench_volume_info.hh index 698c7d1a8b7..e461e6ee077 100644 --- a/source/blender/draw/engines/workbench/shaders/infos/workbench_volume_info.hh +++ b/source/blender/draw/engines/workbench/shaders/infos/workbench_volume_info.hh @@ -6,7 +6,7 @@ /** \name Volume shader base * \{ */ -GPU_SHADER_CREATE_INFO(workbench_volume) +GPU_SHADER_CREATE_INFO(workbench_volume_common) .vertex_in(0, Type::VEC3, "pos") .fragment_out(0, Type::VEC4, "fragColor") .sampler(0, ImageType::DEPTH_2D, "depthBuffer") @@ -16,27 +16,44 @@ GPU_SHADER_CREATE_INFO(workbench_volume) .push_constant(Type::FLOAT, "stepLength") .push_constant(Type::FLOAT, "densityScale") .vertex_source("workbench_volume_vert.glsl") - .fragment_source("workbench_volume_frag.glsl") - .additional_info("draw_object_infos"); + .fragment_source("workbench_volume_frag.glsl"); +GPU_SHADER_CREATE_INFO(workbench_volume) + .additional_info("workbench_volume_common", "draw_object_infos"); + +GPU_SHADER_CREATE_INFO(workbench_next_volume) + .define("WORKBENCH_NEXT") + .additional_info("workbench_volume_common", "draw_object_infos_new", "draw_view"); /** \} */ /* -------------------------------------------------------------------- */ /** \name Smoke variation * \{ */ -GPU_SHADER_CREATE_INFO(workbench_volume_smoke) +GPU_SHADER_CREATE_INFO(workbench_volume_smoke_common) .define("VOLUME_SMOKE") .sampler(2, ImageType::FLOAT_3D, "flameTexture") .sampler(3, ImageType::FLOAT_1D, "flameColorTexture") - .additional_info("draw_mesh", "draw_resource_id_varying"); + .additional_info("draw_resource_id_varying"); -GPU_SHADER_CREATE_INFO(workbench_volume_object) +GPU_SHADER_CREATE_INFO(workbench_volume_object_common) .define("VOLUME_OBJECT") .push_constant(Type::MAT4, "volumeTextureToObject") /* FIXME(fclem): This overflow the push_constant limit. */ .push_constant(Type::MAT4, "volumeObjectToTexture") - .additional_info("draw_volume", "draw_resource_id_varying"); + .additional_info("draw_resource_id_varying"); + +GPU_SHADER_CREATE_INFO(workbench_volume_smoke) + .additional_info("workbench_volume_smoke_common", "draw_mesh"); + +GPU_SHADER_CREATE_INFO(workbench_volume_object) + .additional_info("workbench_volume_object_common", "draw_volume"); + +GPU_SHADER_CREATE_INFO(workbench_next_volume_smoke) + .additional_info("workbench_volume_smoke_common", "draw_modelmat_new"); + +GPU_SHADER_CREATE_INFO(workbench_next_volume_object) + .additional_info("workbench_volume_object_common", "draw_volume_new"); /** \} */ @@ -111,4 +128,10 @@ GPU_SHADER_CREATE_INFO(workbench_volume_slice) WORKBENCH_VOLUME_SMOKE_VARIATIONS(workbench_volume, "workbench_volume") +#define WORKBENCH_NEXT_VOLUME_SMOKE_VARIATIONS(prefix, ...) \ + WORKBENCH_VOLUME_INTERP_VARIATIONS(prefix##_smoke, "workbench_next_volume_smoke", __VA_ARGS__) \ + WORKBENCH_VOLUME_INTERP_VARIATIONS(prefix##_object, "workbench_next_volume_object", __VA_ARGS__) + +WORKBENCH_NEXT_VOLUME_SMOKE_VARIATIONS(workbench_next_volume, "workbench_next_volume") + /** \} */ diff --git a/source/blender/draw/engines/workbench/workbench_engine.cc b/source/blender/draw/engines/workbench/workbench_engine.cc index d93106a3cca..e66e181e938 100644 --- a/source/blender/draw/engines/workbench/workbench_engine.cc +++ b/source/blender/draw/engines/workbench/workbench_engine.cc @@ -13,14 +13,178 @@ #include "ED_view3d.h" #include "GPU_capabilities.h" +#include "draw_common.hh" + #include "workbench_private.hh" +#include "BKE_volume.h" +#include "BKE_volume_render.h" +#include "BLI_rand.h" + #include "workbench_engine.h" /* Own include. */ namespace blender::workbench { using namespace draw; +class VolumePass { + PassMain ps_ = {"Volume Ps"}; + Framebuffer fb_ = {"Volume Fb"}; + bool active_ = true; + Texture dummy_shadow_tx = {"Dummy Shadow"}; + + GPUShader *shaders[2][2][3][2]; + + GPUShader *get_shader(bool slice, bool coba, VolumeDisplayInterpMethod interpolation, bool smoke) + { + GPUShader *&shader = shaders[slice][coba][interpolation][smoke]; + + if (shader == nullptr) { + std::string create_info_name = "workbench_next_volume"; + create_info_name += (smoke) ? "_smoke" : "_object"; + switch (interpolation) { + case VOLUME_DISPLAY_INTERP_LINEAR: + create_info_name += "_linear"; + break; + case VOLUME_DISPLAY_INTERP_CUBIC: + create_info_name += "_linear"; + break; + case VOLUME_DISPLAY_INTERP_CLOSEST: + create_info_name += "_linear"; + break; + default: + BLI_assert_unreachable(); + } + create_info_name += (coba) ? "_coba" : "_no_coba"; + create_info_name += (slice) ? "_slice" : "_no_slice"; + shader = GPU_shader_create_from_info_name(create_info_name.c_str()); + } + return shader; + } + + public: + void sync(SceneResources &resources) + { + active_ = false; + ps_.init(); + ps_.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL | DRW_STATE_CULL_FRONT); + ps_.bind_ubo(WB_WORLD_SLOT, resources.world_buf); + + dummy_shadow_tx.ensure_3d(GPU_RGBA8, int3(1), GPU_TEXTURE_USAGE_SHADER_READ, float4(1)); + } + + void object_sync_volume(Manager &manager, + SceneResources &resources, + const SceneState &scene_state, + ObjectRef &ob_ref, + float3 color) + { + Object *ob = ob_ref.object; + /* Create 3D textures. */ + Volume *volume = static_cast(ob->data); + BKE_volume_load(volume, G.main); + const VolumeGrid *volume_grid = BKE_volume_grid_active_get_for_read(volume); + if (volume_grid == nullptr) { + return; + } + +#if 0 + /* TODO (Miguel Pozo): Use common API? */ + Vector attrs = { + {"densityTexture", BKE_volume_grid_name(volume_grid), eGPUDefaultValue::GPU_DEFAULT_1}}; + PassMain::Sub &sub_ps = ps_.sub(ob->id.name); + if (!volume_sub_pass(ps_, nullptr, nullptr, attrs)) { + return; + } +#endif + + DRWVolumeGrid *grid = DRW_volume_batch_cache_get_grid(volume, volume_grid); + if (grid == nullptr) { + return; + } + + active_ = true; + + PassMain::Sub &sub_ps = ps_.sub(ob->id.name); + + const bool use_slice = (volume->display.axis_slice_method == AXIS_SLICE_SINGLE); + VolumeDisplayInterpMethod interpolation = static_cast( + volume->display.interpolation_method); + + sub_ps.shader_set(get_shader(use_slice, false, interpolation, false)); + + if (use_slice) { + float4x4 view_mat_inv; + DRW_view_viewmat_get(nullptr, view_mat_inv.ptr(), true); + + const int axis = (volume->display.slice_axis == SLICE_AXIS_AUTO) ? + axis_dominant_v3_single(view_mat_inv[2]) : + volume->display.slice_axis - 1; + + float3 dim; + BKE_object_dimensions_get(ob, dim); + /* 0.05f to achieve somewhat the same opacity as the full view. */ + float step_length = max_ff(1e-16f, dim[axis] * 0.05f); + + const float slice_position = volume->display.slice_depth; + + /*TODO (Miguel Pozo): Does this override or replace the parent pass state ? */ + sub_ps.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL | + ~DRW_STATE_CULL_FRONT); + sub_ps.push_constant("slicePosition", slice_position); + sub_ps.push_constant("sliceAxis", axis); + sub_ps.push_constant("stepLength", step_length); + } + else { + /* Compute world space dimensions for step size. */ + float4x4 texture_to_world = float4x4(ob->object_to_world) * + float4x4(grid->texture_to_object); + float3 world_size; + math::normalize_and_get_size(float3x3(texture_to_world), world_size); + + /* Compute step parameters. */ + double noise_offset; + BLI_halton_1d(3, 0.0, scene_state.sample, &noise_offset); + int3 resolution; + GPU_texture_get_mipmap_size(grid->texture, 0, resolution); + + float3 slice_count = math::max(float3(0.01f), float3(resolution)) * 5.0f; + int max_slice = std::max({UNPACK3(slice_count)}); + float step_length = math::length((1.0f / slice_count) * world_size); + + sub_ps.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL | + DRW_STATE_CULL_FRONT); + sub_ps.push_constant("samplesLen", max_slice); + sub_ps.push_constant("stepLength", step_length); + sub_ps.push_constant("noiseOfs", float(noise_offset)); + } + + const float density_scale = volume->display.density * + BKE_volume_density_scale(volume, ob->object_to_world); + + sub_ps.bind_texture("depthBuffer", &resources.depth_tx); + sub_ps.bind_texture("densityTexture", grid->texture); + /* TODO: implement shadow texture, see manta_smoke_calc_transparency. */ + sub_ps.bind_texture("shadowTexture", dummy_shadow_tx); + sub_ps.push_constant("activeColor", color); + sub_ps.push_constant("densityScale", density_scale); + sub_ps.push_constant("volumeObjectToTexture", float4x4(grid->object_to_texture)); + sub_ps.push_constant("volumeTextureToObject", float4x4(grid->texture_to_object)); + + sub_ps.draw(DRW_cache_cube_get(), manager.resource_handle(ob_ref)); + } + + void draw(Manager &manager, View &view, SceneResources &resources) + { + if (!active_) { + return; + } + fb_.ensure(GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(resources.color_tx)); + fb_.bind(); + manager.submit(ps_, view); + } +}; + class Instance { public: View view = {"DefaultView"}; @@ -34,6 +198,7 @@ class Instance { TransparentDepthPass transparent_depth_ps; ShadowPass shadow_ps; + VolumePass volume_ps; OutlinePass outline_ps; DofPass dof_ps; AntiAliasingPass anti_aliasing_ps; @@ -75,6 +240,7 @@ class Instance { transparent_depth_ps.sync(scene_state, resources); shadow_ps.sync(); + volume_ps.sync(resources); outline_ps.sync(resources); dof_ps.sync(resources); anti_aliasing_ps.sync(resources, scene_state.resolution); @@ -85,6 +251,26 @@ class Instance { resources.material_buf.push_update(); } + Material get_material(ObjectRef ob_ref, eV3DShadingColorType color_type, int slot = 0) + { + switch (color_type) { + case V3D_SHADING_OBJECT_COLOR: + return Material(*ob_ref.object); + case V3D_SHADING_RANDOM_COLOR: + return Material(*ob_ref.object, true); + case V3D_SHADING_SINGLE_COLOR: + return scene_state.material_override; + case V3D_SHADING_VERTEX_COLOR: + return scene_state.material_attribute_color; + case V3D_SHADING_MATERIAL_COLOR: + if (::Material *_mat = BKE_object_material_get_eval(ob_ref.object, slot + 1)) { + return Material(*_mat); + } + default: + return Material(*BKE_material_default_empty()); + } + } + void object_sync(Manager &manager, ObjectRef &ob_ref) { if (scene_state.render_finished) { @@ -163,14 +349,16 @@ class Instance { #if 0 /* TODO(@pragma37): */ DRWShadingGroup *grp = workbench_material_hair_setup( wpd, ob, CURVES_MATERIAL_NR, object_state.color_type); - DRW_shgroup_curves_create_sub(ob, grp, NULL); + DRW_shgroup_curves_create_sub(ob, grp, nullptr); #endif } else if (ob->type == OB_VOLUME) { if (scene_state.shading.type != OB_WIRE) { -#if 0 /* TODO(@pragma37): */ - workbench_volume_cache_populate(vedata, wpd->scene, ob, NULL, object_state.color_type); -#endif + volume_ps.object_sync_volume(manager, + resources, + scene_state, + ob_ref, + get_material(ob_ref, object_state.color_type).base_color); } } } @@ -204,15 +392,7 @@ class Instance { continue; } - Material mat; - - if (::Material *_mat = BKE_object_material_get_eval(ob_ref.object, i + 1)) { - mat = Material(*_mat); - } - else { - mat = Material(*BKE_material_default_empty()); - } - + Material mat = get_material(ob_ref, object_state.color_type, i); has_transparent_material = has_transparent_material || mat.is_transparent(); ::Image *image = nullptr; @@ -244,24 +424,7 @@ class Instance { } if (batch) { - Material mat; - - if (object_state.color_type == V3D_SHADING_OBJECT_COLOR) { - mat = Material(*ob_ref.object); - } - else if (object_state.color_type == V3D_SHADING_RANDOM_COLOR) { - mat = Material(*ob_ref.object, true); - } - else if (object_state.color_type == V3D_SHADING_SINGLE_COLOR) { - mat = scene_state.material_override; - } - else if (object_state.color_type == V3D_SHADING_VERTEX_COLOR) { - mat = scene_state.material_attribute_color; - } - else { - mat = Material(*BKE_material_default_empty()); - } - + Material mat = get_material(ob_ref, object_state.color_type); has_transparent_material = has_transparent_material || mat.is_transparent(); draw_mesh(ob_ref, @@ -370,8 +533,7 @@ class Instance { transparent_ps.draw(manager, view, resources, resolution); transparent_depth_ps.draw(manager, view, resources); - // volume_ps.draw_prepass(manager, view, resources.depth_tx); - + volume_ps.draw(manager, view, resources); outline_ps.draw(manager, resources); dof_ps.draw(manager, view, resources, resolution); anti_aliasing_ps.draw(manager, view, resources, resolution, depth_tx, color_tx); diff --git a/source/blender/draw/intern/draw_volume.cc b/source/blender/draw/intern/draw_volume.cc index be05b1adfb9..207678c07f4 100644 --- a/source/blender/draw/intern/draw_volume.cc +++ b/source/blender/draw/intern/draw_volume.cc @@ -297,6 +297,7 @@ static bool volume_object_grids_init(PassMain::Sub &ps, Object *ob, Spandata; BKE_volume_load(volume, G.main); + /* TODO (Miguel Pozo): Should have *= volume->display.density ? */ volume_infos.density_scale = BKE_volume_density_scale(volume, ob->object_to_world); volume_infos.color_mul = float4(1.0f); volume_infos.temperature_mul = 1.0f; diff --git a/source/blender/draw/intern/shaders/draw_view_info.hh b/source/blender/draw/intern/shaders/draw_view_info.hh index 5f61dec7a00..0341e9d90be 100644 --- a/source/blender/draw/intern/shaders/draw_view_info.hh +++ b/source/blender/draw/intern/shaders/draw_view_info.hh @@ -126,6 +126,9 @@ GPU_SHADER_CREATE_INFO(draw_pointcloud) GPU_SHADER_CREATE_INFO(draw_volume).additional_info("draw_modelmat", "draw_resource_id_uniform"); +GPU_SHADER_CREATE_INFO(draw_volume_new) + .additional_info("draw_modelmat_new", "draw_resource_handle_new"); + GPU_SHADER_CREATE_INFO(draw_gpencil) .typedef_source("gpencil_shader_shared.h") .define("DRW_GPENCIL_INFO") -- 2.30.2 From ea3117540b78847b44c23d31325331b1d6afd8f4 Mon Sep 17 00:00:00 2001 From: Miguel Pozo Date: Thu, 2 Mar 2023 17:50:58 +0100 Subject: [PATCH 03/10] Volume Modifier --- .../engines/workbench/workbench_engine.cc | 225 +++++++++++++----- 1 file changed, 166 insertions(+), 59 deletions(-) diff --git a/source/blender/draw/engines/workbench/workbench_engine.cc b/source/blender/draw/engines/workbench/workbench_engine.cc index e66e181e938..5bcd28c5a27 100644 --- a/source/blender/draw/engines/workbench/workbench_engine.cc +++ b/source/blender/draw/engines/workbench/workbench_engine.cc @@ -28,16 +28,20 @@ namespace blender::workbench { using namespace draw; class VolumePass { + bool active_ = true; + PassMain ps_ = {"Volume Ps"}; Framebuffer fb_ = {"Volume Fb"}; - bool active_ = true; - Texture dummy_shadow_tx = {"Dummy Shadow"}; - GPUShader *shaders[2][2][3][2]; + Texture dummy_shadow_tx_ = {"Dummy Shadow"}; + Texture dummy_volume_tx_ = {"Dummy Volume"}; + Texture dummy_coba_tx_ = {"Dummy Coba"}; - GPUShader *get_shader(bool slice, bool coba, VolumeDisplayInterpMethod interpolation, bool smoke) + GPUShader *shaders_[2][2][3][2]; + + GPUShader *get_shader(bool slice, bool coba, int interpolation, bool smoke) { - GPUShader *&shader = shaders[slice][coba][interpolation][smoke]; + GPUShader *&shader = shaders_[slice][coba][interpolation][smoke]; if (shader == nullptr) { std::string create_info_name = "workbench_next_volume"; @@ -62,6 +66,43 @@ class VolumePass { return shader; } + void setup_slice_ps(PassMain::Sub &ps, Object *ob, int slice_axis_enum, float slice_depth) + { + float4x4 view_mat_inv; + DRW_view_viewmat_get(nullptr, view_mat_inv.ptr(), true); + + const int axis = (slice_axis_enum == SLICE_AXIS_AUTO) ? + axis_dominant_v3_single(view_mat_inv[2]) : + slice_axis_enum - 1; + + float3 dimensions; + BKE_object_dimensions_get(ob, dimensions); + /* 0.05f to achieve somewhat the same opacity as the full view. */ + float step_length = max_ff(1e-16f, dimensions[axis] * 0.05f); + + /*TODO (Miguel Pozo): Does this override or replace the parent pass state ? */ + ps.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL | ~DRW_STATE_CULL_FRONT); + ps.push_constant("slicePosition", slice_depth); + ps.push_constant("sliceAxis", axis); + ps.push_constant("stepLength", step_length); + } + + void setup_non_slice_ps( + PassMain::Sub &ps, Object *ob, int taa_sample, float3 slice_count, float3 world_size) + { + double noise_offset; + BLI_halton_1d(3, 0.0, taa_sample, &noise_offset); + + int max_slice = std::max({UNPACK3(slice_count)}); + float step_length = math::length((1.0f / slice_count) * world_size); + + /*TODO (Miguel Pozo): Does this override or replace the parent pass state ? */ + ps.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL | DRW_STATE_CULL_FRONT); + ps.push_constant("samplesLen", max_slice); + ps.push_constant("stepLength", step_length); + ps.push_constant("noiseOfs", float(noise_offset)); + } + public: void sync(SceneResources &resources) { @@ -70,7 +111,9 @@ class VolumePass { ps_.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL | DRW_STATE_CULL_FRONT); ps_.bind_ubo(WB_WORLD_SLOT, resources.world_buf); - dummy_shadow_tx.ensure_3d(GPU_RGBA8, int3(1), GPU_TEXTURE_USAGE_SHADER_READ, float4(1)); + dummy_shadow_tx_.ensure_3d(GPU_RGBA8, int3(1), GPU_TEXTURE_USAGE_SHADER_READ, float4(1)); + dummy_volume_tx_.ensure_3d(GPU_RGBA8, int3(1), GPU_TEXTURE_USAGE_SHADER_READ, float4(0)); + dummy_coba_tx_.ensure_1d(GPU_RGBA8, 1, GPU_TEXTURE_USAGE_SHADER_READ, float4(0)); } void object_sync_volume(Manager &manager, @@ -108,56 +151,8 @@ class VolumePass { PassMain::Sub &sub_ps = ps_.sub(ob->id.name); const bool use_slice = (volume->display.axis_slice_method == AXIS_SLICE_SINGLE); - VolumeDisplayInterpMethod interpolation = static_cast( - volume->display.interpolation_method); - sub_ps.shader_set(get_shader(use_slice, false, interpolation, false)); - - if (use_slice) { - float4x4 view_mat_inv; - DRW_view_viewmat_get(nullptr, view_mat_inv.ptr(), true); - - const int axis = (volume->display.slice_axis == SLICE_AXIS_AUTO) ? - axis_dominant_v3_single(view_mat_inv[2]) : - volume->display.slice_axis - 1; - - float3 dim; - BKE_object_dimensions_get(ob, dim); - /* 0.05f to achieve somewhat the same opacity as the full view. */ - float step_length = max_ff(1e-16f, dim[axis] * 0.05f); - - const float slice_position = volume->display.slice_depth; - - /*TODO (Miguel Pozo): Does this override or replace the parent pass state ? */ - sub_ps.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL | - ~DRW_STATE_CULL_FRONT); - sub_ps.push_constant("slicePosition", slice_position); - sub_ps.push_constant("sliceAxis", axis); - sub_ps.push_constant("stepLength", step_length); - } - else { - /* Compute world space dimensions for step size. */ - float4x4 texture_to_world = float4x4(ob->object_to_world) * - float4x4(grid->texture_to_object); - float3 world_size; - math::normalize_and_get_size(float3x3(texture_to_world), world_size); - - /* Compute step parameters. */ - double noise_offset; - BLI_halton_1d(3, 0.0, scene_state.sample, &noise_offset); - int3 resolution; - GPU_texture_get_mipmap_size(grid->texture, 0, resolution); - - float3 slice_count = math::max(float3(0.01f), float3(resolution)) * 5.0f; - int max_slice = std::max({UNPACK3(slice_count)}); - float step_length = math::length((1.0f / slice_count) * world_size); - - sub_ps.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL | - DRW_STATE_CULL_FRONT); - sub_ps.push_constant("samplesLen", max_slice); - sub_ps.push_constant("stepLength", step_length); - sub_ps.push_constant("noiseOfs", float(noise_offset)); - } + sub_ps.shader_set(get_shader(use_slice, false, volume->display.interpolation_method, false)); const float density_scale = volume->display.density * BKE_volume_density_scale(volume, ob->object_to_world); @@ -165,15 +160,128 @@ class VolumePass { sub_ps.bind_texture("depthBuffer", &resources.depth_tx); sub_ps.bind_texture("densityTexture", grid->texture); /* TODO: implement shadow texture, see manta_smoke_calc_transparency. */ - sub_ps.bind_texture("shadowTexture", dummy_shadow_tx); + sub_ps.bind_texture("shadowTexture", dummy_shadow_tx_); sub_ps.push_constant("activeColor", color); sub_ps.push_constant("densityScale", density_scale); sub_ps.push_constant("volumeObjectToTexture", float4x4(grid->object_to_texture)); sub_ps.push_constant("volumeTextureToObject", float4x4(grid->texture_to_object)); + if (use_slice) { + setup_slice_ps(sub_ps, ob, volume->display.slice_axis, volume->display.slice_depth); + } + else { + float3 world_size; + float4x4 texture_to_world = float4x4(ob->object_to_world) * + float4x4(grid->texture_to_object); + math::normalize_and_get_size(float3x3(texture_to_world), world_size); + + int3 resolution; + GPU_texture_get_mipmap_size(grid->texture, 0, resolution); + float3 slice_count = float3(resolution) * 5.0f; + + setup_non_slice_ps(sub_ps, ob, scene_state.sample, slice_count, world_size); + } + sub_ps.draw(DRW_cache_cube_get(), manager.resource_handle(ob_ref)); } + void object_sync_modifier(Manager &manager, + SceneResources &resources, + const SceneState &scene_state, + ObjectRef &ob_ref, + ModifierData *md) + { + Object *ob = ob_ref.object; + + FluidModifierData *modifier = reinterpret_cast(md); + FluidDomainSettings &settings = *modifier->domain; + + if (!settings.fluid) { + return; + } + + bool can_load = false; + if (settings.use_coba) { + DRW_smoke_ensure_coba_field(modifier); + can_load = settings.tex_field != nullptr; + } + else if (settings.type == FLUID_DOMAIN_TYPE_GAS) { + DRW_smoke_ensure(modifier, settings.flags & FLUID_DOMAIN_USE_NOISE); + can_load = settings.tex_density != nullptr || settings.tex_color != nullptr; + } + + if (!can_load) { + return; + } + + active_ = true; + + PassMain::Sub &sub_ps = ps_.sub(ob->id.name); + + const bool use_slice = settings.axis_slice_method == AXIS_SLICE_SINGLE; + + sub_ps.shader_set(get_shader(use_slice, settings.use_coba, settings.interp_method, true)); + + if (settings.use_coba) { + const bool show_flags = settings.coba_field == FLUID_DOMAIN_FIELD_FLAGS; + const bool show_pressure = settings.coba_field == FLUID_DOMAIN_FIELD_PRESSURE; + const bool show_phi = ELEM(settings.coba_field, + FLUID_DOMAIN_FIELD_PHI, + FLUID_DOMAIN_FIELD_PHI_IN, + FLUID_DOMAIN_FIELD_PHI_OUT, + FLUID_DOMAIN_FIELD_PHI_OBSTACLE); + + sub_ps.push_constant("showFlags", show_flags); + sub_ps.push_constant("showPressure", show_pressure); + sub_ps.push_constant("showPhi", show_phi); + sub_ps.push_constant("gridScale", settings.grid_scale); + + if (show_flags) { + sub_ps.bind_texture("flagTexture", settings.tex_field); + } + else { + sub_ps.bind_texture("densityTexture", settings.tex_field); + } + + if (!show_flags && !show_pressure && !show_phi) { + sub_ps.bind_texture("transferTexture", settings.tex_coba); + } + } + else { + bool use_constant_color = ((settings.active_fields & FLUID_DOMAIN_ACTIVE_COLORS) == 0 && + (settings.active_fields & FLUID_DOMAIN_ACTIVE_COLOR_SET) != 0); + + sub_ps.push_constant("activeColor", + use_constant_color ? float3(settings.active_color) : float3(1)); + + sub_ps.bind_texture("densityTexture", + settings.tex_color ? settings.tex_color : settings.tex_density); + sub_ps.bind_texture("flameTexture", + settings.tex_flame ? settings.tex_flame : dummy_volume_tx_); + sub_ps.bind_texture("flameColorTexture", + settings.tex_flame ? settings.tex_flame_coba : dummy_coba_tx_); + sub_ps.bind_texture("shadowTexture", settings.tex_shadow); + } + + sub_ps.push_constant("densityScale", 10.0f * settings.display_thickness); + sub_ps.bind_texture("depthBuffer", &resources.depth_tx); + + if (use_slice) { + setup_slice_ps(sub_ps, ob, settings.slice_axis, settings.slice_depth); + /* TODO (Miguel Pozo): Why is a quad used here, but not in volume? */ + sub_ps.draw(DRW_cache_quad_get(), manager.resource_handle(ob_ref)); + } + else { + float3 world_size; + BKE_object_dimensions_get(ob, world_size); + + float3 slice_count = float3(settings.res) * std::max(0.001f, settings.slice_per_voxel); + + setup_non_slice_ps(sub_ps, ob, scene_state.sample, slice_count, world_size); + sub_ps.draw(DRW_cache_cube_get(), manager.resource_handle(ob_ref)); + } + } + void draw(Manager &manager, View &view, SceneResources &resources) { if (!active_) { @@ -324,9 +432,8 @@ class Instance { if (md && BKE_modifier_is_enabled(scene_state.scene, md, eModifierMode_Realtime)) { FluidModifierData *fmd = (FluidModifierData *)md; if (fmd->domain) { -#if 0 /* TODO(@pragma37): */ - workbench_volume_cache_populate(vedata, wpd->scene, ob, md, V3D_SHADING_SINGLE_COLOR); -#endif + volume_ps.object_sync_modifier(manager, resources, scene_state, ob_ref, md); + if (fmd->domain->type == FLUID_DOMAIN_TYPE_GAS) { return; /* Do not draw solid in this case. */ } -- 2.30.2 From fe3b4dee6d63db03b3822f81189674fea85e40a1 Mon Sep 17 00:00:00 2001 From: Miguel Pozo Date: Thu, 2 Mar 2023 19:02:35 +0100 Subject: [PATCH 04/10] fixes --- source/blender/draw/engines/workbench/workbench_engine.cc | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/source/blender/draw/engines/workbench/workbench_engine.cc b/source/blender/draw/engines/workbench/workbench_engine.cc index 5bcd28c5a27..9e996b9ce0a 100644 --- a/source/blender/draw/engines/workbench/workbench_engine.cc +++ b/source/blender/draw/engines/workbench/workbench_engine.cc @@ -51,10 +51,10 @@ class VolumePass { create_info_name += "_linear"; break; case VOLUME_DISPLAY_INTERP_CUBIC: - create_info_name += "_linear"; + create_info_name += "_cubic"; break; case VOLUME_DISPLAY_INTERP_CLOSEST: - create_info_name += "_linear"; + create_info_name += "_closest"; break; default: BLI_assert_unreachable(); @@ -80,8 +80,7 @@ class VolumePass { /* 0.05f to achieve somewhat the same opacity as the full view. */ float step_length = max_ff(1e-16f, dimensions[axis] * 0.05f); - /*TODO (Miguel Pozo): Does this override or replace the parent pass state ? */ - ps.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL | ~DRW_STATE_CULL_FRONT); + ps.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL); ps.push_constant("slicePosition", slice_depth); ps.push_constant("sliceAxis", axis); ps.push_constant("stepLength", step_length); @@ -108,7 +107,6 @@ class VolumePass { { active_ = false; ps_.init(); - ps_.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL | DRW_STATE_CULL_FRONT); ps_.bind_ubo(WB_WORLD_SLOT, resources.world_buf); dummy_shadow_tx_.ensure_3d(GPU_RGBA8, int3(1), GPU_TEXTURE_USAGE_SHADER_READ, float4(1)); -- 2.30.2 From 7e2eb98ca0c63d974ca51b34eefecc74f420db76 Mon Sep 17 00:00:00 2001 From: Miguel Pozo Date: Thu, 2 Mar 2023 19:32:55 +0100 Subject: [PATCH 05/10] Remove the port of draw_volume to the new Draw Manager There are too many missing features that Workbench would need. --- source/blender/draw/CMakeLists.txt | 1 - .../engines/workbench/workbench_engine.cc | 12 -- source/blender/draw/intern/draw_common.hh | 24 --- source/blender/draw/intern/draw_volume.cc | 161 ------------------ 4 files changed, 198 deletions(-) delete mode 100644 source/blender/draw/intern/draw_common.hh diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 5058fb5f0fc..c6f8dcf335f 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -233,7 +233,6 @@ set(SRC intern/draw_color_management.h intern/draw_command.hh intern/draw_common.h - intern/draw_common.hh intern/draw_common_shader_shared.h intern/draw_curves_private.hh intern/draw_debug.h diff --git a/source/blender/draw/engines/workbench/workbench_engine.cc b/source/blender/draw/engines/workbench/workbench_engine.cc index 9e996b9ce0a..f7e0b0b1127 100644 --- a/source/blender/draw/engines/workbench/workbench_engine.cc +++ b/source/blender/draw/engines/workbench/workbench_engine.cc @@ -13,8 +13,6 @@ #include "ED_view3d.h" #include "GPU_capabilities.h" -#include "draw_common.hh" - #include "workbench_private.hh" #include "BKE_volume.h" @@ -129,16 +127,6 @@ class VolumePass { return; } -#if 0 - /* TODO (Miguel Pozo): Use common API? */ - Vector attrs = { - {"densityTexture", BKE_volume_grid_name(volume_grid), eGPUDefaultValue::GPU_DEFAULT_1}}; - PassMain::Sub &sub_ps = ps_.sub(ob->id.name); - if (!volume_sub_pass(ps_, nullptr, nullptr, attrs)) { - return; - } -#endif - DRWVolumeGrid *grid = DRW_volume_batch_cache_get_grid(volume, volume_grid); if (grid == nullptr) { return; diff --git a/source/blender/draw/intern/draw_common.hh b/source/blender/draw/intern/draw_common.hh deleted file mode 100644 index ff2c77a89cb..00000000000 --- a/source/blender/draw/intern/draw_common.hh +++ /dev/null @@ -1,24 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later - * Copyright 2016 Blender Foundation. */ - -/** \file - * \ingroup draw - */ - -#pragma once - -#include "draw_common.h" -#include "draw_manager.hh" -#include "draw_pass.hh" - -namespace blender::draw { - -struct VolumeAttribute { - StringRefNull input_name; - StringRefNull name; - eGPUDefaultValue default_value; -}; - -bool volume_sub_pass(PassMain::Sub &ps, Scene *scene, Object *ob, Span attrs); - -} // namespace blender::draw diff --git a/source/blender/draw/intern/draw_volume.cc b/source/blender/draw/intern/draw_volume.cc index 207678c07f4..34c54b63230 100644 --- a/source/blender/draw/intern/draw_volume.cc +++ b/source/blender/draw/intern/draw_volume.cc @@ -25,8 +25,6 @@ #include "draw_common.h" #include "draw_manager.h" -#include "draw_common.hh" - using namespace blender; using namespace blender::draw; using VolumeInfosBuf = blender::draw::UniformBuffer; @@ -275,162 +273,3 @@ DRWShadingGroup *DRW_shgroup_volume_create_sub(Scene *scene, } return drw_volume_object_mesh_init(scene, ob, &attrs, shgrp); } - -/* Temporary port to Draw Manager Next */ - -namespace blender::draw { - -static bool volume_world_grids_init(PassMain::Sub &ps, Span attrs) -{ - for (const VolumeAttribute &attr : attrs) { - ps.bind_texture(attr.input_name.c_str(), grid_default_texture(attr.default_value)); - } - - return true; -} - -static bool volume_object_grids_init(PassMain::Sub &ps, Object *ob, Span attrs) -{ - VolumeUniformBufPool *pool = (VolumeUniformBufPool *)DST.vmempool->volume_grids_ubos; - VolumeInfosBuf &volume_infos = *pool->alloc(); - - Volume *volume = (Volume *)ob->data; - BKE_volume_load(volume, G.main); - - /* TODO (Miguel Pozo): Should have *= volume->display.density ? */ - volume_infos.density_scale = BKE_volume_density_scale(volume, ob->object_to_world); - volume_infos.color_mul = float4(1.0f); - volume_infos.temperature_mul = 1.0f; - volume_infos.temperature_bias = 0.0f; - - bool has_grids = false; - for (const VolumeAttribute &attr : attrs) { - if (BKE_volume_grid_find_for_read(volume, attr.name.c_str()) != nullptr) { - has_grids = true; - break; - } - } - /* Render nothing if there is no attribute for the shader to render. - * This also avoids an assert caused by the bounding box being zero in size. */ - if (!has_grids) { - return false; - } - - /* Bind volume grid textures. */ - int grid_id = 0, grids_len = 0; - for (const VolumeAttribute &attr : attrs) { - const VolumeGrid *volume_grid = BKE_volume_grid_find_for_read(volume, attr.name.c_str()); - const DRWVolumeGrid *drw_grid = (volume_grid) ? - DRW_volume_batch_cache_get_grid(volume, volume_grid) : - nullptr; - /* Handle 3 cases here: - * - Grid exists and texture was loaded -> use texture. - * - Grid exists but has zero size or failed to load -> use zero. - * - Grid does not exist -> use default value. */ - const GPUTexture *grid_tex = (drw_grid) ? drw_grid->texture : - (volume_grid) ? g_data.dummy_zero : - grid_default_texture(attr.default_value); - /* TODO (Miguel Pozo): bind_texture const support ? */ - ps.bind_texture(attr.input_name.c_str(), (GPUTexture *)grid_tex); - - volume_infos.grids_xform[grid_id++] = float4x4(drw_grid ? drw_grid->object_to_texture : - g_data.dummy_grid_mat); - } - - volume_infos.push_update(); - - ps.bind_ubo("drw_volume", volume_infos); - - return true; -} - -static bool drw_volume_object_mesh_init(PassMain::Sub &ps, - Scene *scene, - Object *ob, - Span attrs) -{ - VolumeUniformBufPool *pool = (VolumeUniformBufPool *)DST.vmempool->volume_grids_ubos; - VolumeInfosBuf &volume_infos = *pool->alloc(); - - ModifierData *md = nullptr; - - volume_infos.density_scale = 1.0f; - volume_infos.color_mul = float4(1.0f); - volume_infos.temperature_mul = 1.0f; - volume_infos.temperature_bias = 0.0f; - - /* Smoke Simulation */ - if ((md = BKE_modifiers_findby_type(ob, eModifierType_Fluid)) && - BKE_modifier_is_enabled(scene, md, eModifierMode_Realtime) && - ((FluidModifierData *)md)->domain != nullptr) { - FluidModifierData *fmd = (FluidModifierData *)md; - FluidDomainSettings *fds = fmd->domain; - - /* Don't try to show liquid domains here. */ - if (!fds->fluid || !(fds->type == FLUID_DOMAIN_TYPE_GAS)) { - return false; - } - - if (fds->fluid && (fds->type == FLUID_DOMAIN_TYPE_GAS)) { - DRW_smoke_ensure(fmd, fds->flags & FLUID_DOMAIN_USE_NOISE); - } - - int grid_id = 0; - for (const VolumeAttribute &attr : attrs) { - if (STREQ(attr.name.c_str(), "density")) { - ps.bind_texture(attr.input_name.c_str(), - fds->tex_density ? &fds->tex_density : &g_data.dummy_one); - } - else if (STREQ(attr.name.c_str(), "color")) { - ps.bind_texture(attr.input_name.c_str(), - fds->tex_color ? &fds->tex_color : &g_data.dummy_one); - } - else if (STR_ELEM(attr.name.c_str(), "flame", "temperature")) { - ps.bind_texture(attr.input_name.c_str(), - fds->tex_flame ? &fds->tex_flame : &g_data.dummy_zero); - } - else { - ps.bind_texture(attr.input_name.c_str(), grid_default_texture(attr.default_value)); - } - volume_infos.grids_xform[grid_id++] = float4x4(g_data.dummy_grid_mat); - } - - bool use_constant_color = ((fds->active_fields & FLUID_DOMAIN_ACTIVE_COLORS) == 0 && - (fds->active_fields & FLUID_DOMAIN_ACTIVE_COLOR_SET) != 0); - if (use_constant_color) { - volume_infos.color_mul = float4(UNPACK3(fds->active_color), 1.0f); - } - - /* Output is such that 0..1 maps to 0..1000K */ - volume_infos.temperature_mul = fds->flame_max_temp - fds->flame_ignition; - volume_infos.temperature_bias = fds->flame_ignition; - } - else { - int grid_id = 0; - for (const VolumeAttribute &attr : attrs) { - ps.bind_texture(attr.input_name.c_str(), grid_default_texture(attr.default_value)); - volume_infos.grids_xform[grid_id++] = float4x4(g_data.dummy_grid_mat); - } - } - - volume_infos.push_update(); - - ps.bind_ubo("drw_volume", volume_infos); - - return true; -} - -bool volume_sub_pass(PassMain::Sub &ps, Scene *scene, Object *ob, Span attrs) -{ - if (ob == nullptr) { - return volume_world_grids_init(ps, attrs); - } - else if (ob->type == OB_VOLUME) { - return volume_object_grids_init(ps, ob, attrs); - } - else { - return drw_volume_object_mesh_init(ps, scene, ob, attrs); - } -} - -} // namespace blender::draw -- 2.30.2 From e7cadb3045ea4ac4f61cb004e89fa4b4f69de63d Mon Sep 17 00:00:00 2001 From: Miguel Pozo Date: Fri, 3 Mar 2023 16:30:31 +0100 Subject: [PATCH 06/10] Early out if the volume is opaque already --- .../engines/workbench/shaders/workbench_volume_frag.glsl | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl index 80190ede5c9..8224f76c420 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl @@ -209,6 +209,12 @@ vec4 volume_integration(vec3 ray_ori, vec3 ray_dir, float ray_inc, float ray_max /* accumulate and also take into account the transmittance from previous steps */ final_scattering += final_transmittance * Lscat; final_transmittance *= Tr; + + if (final_transmittance <= 0.01) { + /* Early out */ + final_transmittance = 0; + break; + } } return vec4(final_scattering, final_transmittance); -- 2.30.2 From d6191e4d1d737bf984af7048b1b0a3333fa99442 Mon Sep 17 00:00:00 2001 From: Miguel Pozo Date: Mon, 6 Mar 2023 16:23:50 +0100 Subject: [PATCH 07/10] Move implementation to its own file --- source/blender/draw/CMakeLists.txt | 1 + .../engines/workbench/workbench_engine.cc | 258 ------------------ .../engines/workbench/workbench_private.hh | 36 +++ .../workbench/workbench_volume_next.cc | 255 +++++++++++++++++ 4 files changed, 292 insertions(+), 258 deletions(-) create mode 100644 source/blender/draw/engines/workbench/workbench_volume_next.cc diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index c6f8dcf335f..f7aab78b23b 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -180,6 +180,7 @@ set(SRC engines/workbench/workbench_state.cc engines/workbench/workbench_transparent.c engines/workbench/workbench_volume.c + engines/workbench/workbench_volume_next.cc engines/external/external_engine.c engines/gpencil/gpencil_antialiasing.c engines/gpencil/gpencil_cache_utils.c diff --git a/source/blender/draw/engines/workbench/workbench_engine.cc b/source/blender/draw/engines/workbench/workbench_engine.cc index f7e0b0b1127..ec897394067 100644 --- a/source/blender/draw/engines/workbench/workbench_engine.cc +++ b/source/blender/draw/engines/workbench/workbench_engine.cc @@ -15,270 +15,12 @@ #include "workbench_private.hh" -#include "BKE_volume.h" -#include "BKE_volume_render.h" -#include "BLI_rand.h" - #include "workbench_engine.h" /* Own include. */ namespace blender::workbench { using namespace draw; -class VolumePass { - bool active_ = true; - - PassMain ps_ = {"Volume Ps"}; - Framebuffer fb_ = {"Volume Fb"}; - - Texture dummy_shadow_tx_ = {"Dummy Shadow"}; - Texture dummy_volume_tx_ = {"Dummy Volume"}; - Texture dummy_coba_tx_ = {"Dummy Coba"}; - - GPUShader *shaders_[2][2][3][2]; - - GPUShader *get_shader(bool slice, bool coba, int interpolation, bool smoke) - { - GPUShader *&shader = shaders_[slice][coba][interpolation][smoke]; - - if (shader == nullptr) { - std::string create_info_name = "workbench_next_volume"; - create_info_name += (smoke) ? "_smoke" : "_object"; - switch (interpolation) { - case VOLUME_DISPLAY_INTERP_LINEAR: - create_info_name += "_linear"; - break; - case VOLUME_DISPLAY_INTERP_CUBIC: - create_info_name += "_cubic"; - break; - case VOLUME_DISPLAY_INTERP_CLOSEST: - create_info_name += "_closest"; - break; - default: - BLI_assert_unreachable(); - } - create_info_name += (coba) ? "_coba" : "_no_coba"; - create_info_name += (slice) ? "_slice" : "_no_slice"; - shader = GPU_shader_create_from_info_name(create_info_name.c_str()); - } - return shader; - } - - void setup_slice_ps(PassMain::Sub &ps, Object *ob, int slice_axis_enum, float slice_depth) - { - float4x4 view_mat_inv; - DRW_view_viewmat_get(nullptr, view_mat_inv.ptr(), true); - - const int axis = (slice_axis_enum == SLICE_AXIS_AUTO) ? - axis_dominant_v3_single(view_mat_inv[2]) : - slice_axis_enum - 1; - - float3 dimensions; - BKE_object_dimensions_get(ob, dimensions); - /* 0.05f to achieve somewhat the same opacity as the full view. */ - float step_length = max_ff(1e-16f, dimensions[axis] * 0.05f); - - ps.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL); - ps.push_constant("slicePosition", slice_depth); - ps.push_constant("sliceAxis", axis); - ps.push_constant("stepLength", step_length); - } - - void setup_non_slice_ps( - PassMain::Sub &ps, Object *ob, int taa_sample, float3 slice_count, float3 world_size) - { - double noise_offset; - BLI_halton_1d(3, 0.0, taa_sample, &noise_offset); - - int max_slice = std::max({UNPACK3(slice_count)}); - float step_length = math::length((1.0f / slice_count) * world_size); - - /*TODO (Miguel Pozo): Does this override or replace the parent pass state ? */ - ps.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL | DRW_STATE_CULL_FRONT); - ps.push_constant("samplesLen", max_slice); - ps.push_constant("stepLength", step_length); - ps.push_constant("noiseOfs", float(noise_offset)); - } - - public: - void sync(SceneResources &resources) - { - active_ = false; - ps_.init(); - ps_.bind_ubo(WB_WORLD_SLOT, resources.world_buf); - - dummy_shadow_tx_.ensure_3d(GPU_RGBA8, int3(1), GPU_TEXTURE_USAGE_SHADER_READ, float4(1)); - dummy_volume_tx_.ensure_3d(GPU_RGBA8, int3(1), GPU_TEXTURE_USAGE_SHADER_READ, float4(0)); - dummy_coba_tx_.ensure_1d(GPU_RGBA8, 1, GPU_TEXTURE_USAGE_SHADER_READ, float4(0)); - } - - void object_sync_volume(Manager &manager, - SceneResources &resources, - const SceneState &scene_state, - ObjectRef &ob_ref, - float3 color) - { - Object *ob = ob_ref.object; - /* Create 3D textures. */ - Volume *volume = static_cast(ob->data); - BKE_volume_load(volume, G.main); - const VolumeGrid *volume_grid = BKE_volume_grid_active_get_for_read(volume); - if (volume_grid == nullptr) { - return; - } - - DRWVolumeGrid *grid = DRW_volume_batch_cache_get_grid(volume, volume_grid); - if (grid == nullptr) { - return; - } - - active_ = true; - - PassMain::Sub &sub_ps = ps_.sub(ob->id.name); - - const bool use_slice = (volume->display.axis_slice_method == AXIS_SLICE_SINGLE); - - sub_ps.shader_set(get_shader(use_slice, false, volume->display.interpolation_method, false)); - - const float density_scale = volume->display.density * - BKE_volume_density_scale(volume, ob->object_to_world); - - sub_ps.bind_texture("depthBuffer", &resources.depth_tx); - sub_ps.bind_texture("densityTexture", grid->texture); - /* TODO: implement shadow texture, see manta_smoke_calc_transparency. */ - sub_ps.bind_texture("shadowTexture", dummy_shadow_tx_); - sub_ps.push_constant("activeColor", color); - sub_ps.push_constant("densityScale", density_scale); - sub_ps.push_constant("volumeObjectToTexture", float4x4(grid->object_to_texture)); - sub_ps.push_constant("volumeTextureToObject", float4x4(grid->texture_to_object)); - - if (use_slice) { - setup_slice_ps(sub_ps, ob, volume->display.slice_axis, volume->display.slice_depth); - } - else { - float3 world_size; - float4x4 texture_to_world = float4x4(ob->object_to_world) * - float4x4(grid->texture_to_object); - math::normalize_and_get_size(float3x3(texture_to_world), world_size); - - int3 resolution; - GPU_texture_get_mipmap_size(grid->texture, 0, resolution); - float3 slice_count = float3(resolution) * 5.0f; - - setup_non_slice_ps(sub_ps, ob, scene_state.sample, slice_count, world_size); - } - - sub_ps.draw(DRW_cache_cube_get(), manager.resource_handle(ob_ref)); - } - - void object_sync_modifier(Manager &manager, - SceneResources &resources, - const SceneState &scene_state, - ObjectRef &ob_ref, - ModifierData *md) - { - Object *ob = ob_ref.object; - - FluidModifierData *modifier = reinterpret_cast(md); - FluidDomainSettings &settings = *modifier->domain; - - if (!settings.fluid) { - return; - } - - bool can_load = false; - if (settings.use_coba) { - DRW_smoke_ensure_coba_field(modifier); - can_load = settings.tex_field != nullptr; - } - else if (settings.type == FLUID_DOMAIN_TYPE_GAS) { - DRW_smoke_ensure(modifier, settings.flags & FLUID_DOMAIN_USE_NOISE); - can_load = settings.tex_density != nullptr || settings.tex_color != nullptr; - } - - if (!can_load) { - return; - } - - active_ = true; - - PassMain::Sub &sub_ps = ps_.sub(ob->id.name); - - const bool use_slice = settings.axis_slice_method == AXIS_SLICE_SINGLE; - - sub_ps.shader_set(get_shader(use_slice, settings.use_coba, settings.interp_method, true)); - - if (settings.use_coba) { - const bool show_flags = settings.coba_field == FLUID_DOMAIN_FIELD_FLAGS; - const bool show_pressure = settings.coba_field == FLUID_DOMAIN_FIELD_PRESSURE; - const bool show_phi = ELEM(settings.coba_field, - FLUID_DOMAIN_FIELD_PHI, - FLUID_DOMAIN_FIELD_PHI_IN, - FLUID_DOMAIN_FIELD_PHI_OUT, - FLUID_DOMAIN_FIELD_PHI_OBSTACLE); - - sub_ps.push_constant("showFlags", show_flags); - sub_ps.push_constant("showPressure", show_pressure); - sub_ps.push_constant("showPhi", show_phi); - sub_ps.push_constant("gridScale", settings.grid_scale); - - if (show_flags) { - sub_ps.bind_texture("flagTexture", settings.tex_field); - } - else { - sub_ps.bind_texture("densityTexture", settings.tex_field); - } - - if (!show_flags && !show_pressure && !show_phi) { - sub_ps.bind_texture("transferTexture", settings.tex_coba); - } - } - else { - bool use_constant_color = ((settings.active_fields & FLUID_DOMAIN_ACTIVE_COLORS) == 0 && - (settings.active_fields & FLUID_DOMAIN_ACTIVE_COLOR_SET) != 0); - - sub_ps.push_constant("activeColor", - use_constant_color ? float3(settings.active_color) : float3(1)); - - sub_ps.bind_texture("densityTexture", - settings.tex_color ? settings.tex_color : settings.tex_density); - sub_ps.bind_texture("flameTexture", - settings.tex_flame ? settings.tex_flame : dummy_volume_tx_); - sub_ps.bind_texture("flameColorTexture", - settings.tex_flame ? settings.tex_flame_coba : dummy_coba_tx_); - sub_ps.bind_texture("shadowTexture", settings.tex_shadow); - } - - sub_ps.push_constant("densityScale", 10.0f * settings.display_thickness); - sub_ps.bind_texture("depthBuffer", &resources.depth_tx); - - if (use_slice) { - setup_slice_ps(sub_ps, ob, settings.slice_axis, settings.slice_depth); - /* TODO (Miguel Pozo): Why is a quad used here, but not in volume? */ - sub_ps.draw(DRW_cache_quad_get(), manager.resource_handle(ob_ref)); - } - else { - float3 world_size; - BKE_object_dimensions_get(ob, world_size); - - float3 slice_count = float3(settings.res) * std::max(0.001f, settings.slice_per_voxel); - - setup_non_slice_ps(sub_ps, ob, scene_state.sample, slice_count, world_size); - sub_ps.draw(DRW_cache_cube_get(), manager.resource_handle(ob_ref)); - } - } - - void draw(Manager &manager, View &view, SceneResources &resources) - { - if (!active_) { - return; - } - fb_.ensure(GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(resources.color_tx)); - fb_.bind(); - manager.submit(ps_, view); - } -}; - class Instance { public: View view = {"DefaultView"}; diff --git a/source/blender/draw/engines/workbench/workbench_private.hh b/source/blender/draw/engines/workbench/workbench_private.hh index 832e5ac5f23..dedc9941ebb 100644 --- a/source/blender/draw/engines/workbench/workbench_private.hh +++ b/source/blender/draw/engines/workbench/workbench_private.hh @@ -324,6 +324,42 @@ class ShadowPass { bool force_fail_method); }; +class VolumePass { + bool active_ = true; + + PassMain ps_ = {"Volume"}; + Framebuffer fb_ = {"Volume"}; + + Texture dummy_shadow_tx_ = {"Volume.Dummy Shadow Tx"}; + Texture dummy_volume_tx_ = {"Volume.Dummy Volume Tx"}; + Texture dummy_coba_tx_ = {"Volume.Dummy Coba Tx"}; + + GPUShader *shaders_[2][2][3][2]; + GPUShader *get_shader(bool slice, bool coba, int interpolation, bool smoke); + + void setup_slice_ps(PassMain::Sub &ps, Object *ob, int slice_axis_enum, float slice_depth); + + void setup_non_slice_ps( + PassMain::Sub &ps, Object *ob, int taa_sample, float3 slice_count, float3 world_size); + + public: + void sync(SceneResources &resources); + + void object_sync_volume(Manager &manager, + SceneResources &resources, + const SceneState &scene_state, + ObjectRef &ob_ref, + float3 color); + + void object_sync_modifier(Manager &manager, + SceneResources &resources, + const SceneState &scene_state, + ObjectRef &ob_ref, + ModifierData *md); + + void draw(Manager &manager, View &view, SceneResources &resources); +}; + class OutlinePass { private: bool enabled_ = false; diff --git a/source/blender/draw/engines/workbench/workbench_volume_next.cc b/source/blender/draw/engines/workbench/workbench_volume_next.cc new file mode 100644 index 00000000000..affcfd7c694 --- /dev/null +++ b/source/blender/draw/engines/workbench/workbench_volume_next.cc @@ -0,0 +1,255 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "workbench_private.hh" + +#include "BKE_volume.h" +#include "BKE_volume_render.h" +#include "BLI_rand.h" +#include "DNA_fluid_types.h" +#include "DNA_modifier_types.h" + +namespace blender::workbench { + +GPUShader *VolumePass::get_shader(bool slice, bool coba, int interpolation, bool smoke) +{ + GPUShader *&shader = shaders_[slice][coba][interpolation][smoke]; + + if (shader == nullptr) { + std::string create_info_name = "workbench_next_volume"; + create_info_name += (smoke) ? "_smoke" : "_object"; + switch (interpolation) { + case VOLUME_DISPLAY_INTERP_LINEAR: + create_info_name += "_linear"; + break; + case VOLUME_DISPLAY_INTERP_CUBIC: + create_info_name += "_cubic"; + break; + case VOLUME_DISPLAY_INTERP_CLOSEST: + create_info_name += "_closest"; + break; + default: + BLI_assert_unreachable(); + } + create_info_name += (coba) ? "_coba" : "_no_coba"; + create_info_name += (slice) ? "_slice" : "_no_slice"; + shader = GPU_shader_create_from_info_name(create_info_name.c_str()); + } + return shader; +} + +void VolumePass::setup_slice_ps(PassMain::Sub &ps, + Object *ob, + int slice_axis_enum, + float slice_depth) +{ + float4x4 view_mat_inv; + DRW_view_viewmat_get(nullptr, view_mat_inv.ptr(), true); + + const int axis = (slice_axis_enum == SLICE_AXIS_AUTO) ? + axis_dominant_v3_single(view_mat_inv[2]) : + slice_axis_enum - 1; + + float3 dimensions; + BKE_object_dimensions_get(ob, dimensions); + /* 0.05f to achieve somewhat the same opacity as the full view. */ + float step_length = max_ff(1e-16f, dimensions[axis] * 0.05f); + + ps.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL); + ps.push_constant("slicePosition", slice_depth); + ps.push_constant("sliceAxis", axis); + ps.push_constant("stepLength", step_length); +} + +void VolumePass::setup_non_slice_ps( + PassMain::Sub &ps, Object *ob, int taa_sample, float3 slice_count, float3 world_size) +{ + double noise_offset; + BLI_halton_1d(3, 0.0, taa_sample, &noise_offset); + + int max_slice = std::max({UNPACK3(slice_count)}); + float step_length = math::length((1.0f / slice_count) * world_size); + + /*TODO (Miguel Pozo): Does this override or replace the parent pass state ? */ + ps.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL | DRW_STATE_CULL_FRONT); + ps.push_constant("samplesLen", max_slice); + ps.push_constant("stepLength", step_length); + ps.push_constant("noiseOfs", float(noise_offset)); +} + +void VolumePass::sync(SceneResources &resources) +{ + active_ = false; + ps_.init(); + ps_.bind_ubo(WB_WORLD_SLOT, resources.world_buf); + + dummy_shadow_tx_.ensure_3d(GPU_RGBA8, int3(1), GPU_TEXTURE_USAGE_SHADER_READ, float4(1)); + dummy_volume_tx_.ensure_3d(GPU_RGBA8, int3(1), GPU_TEXTURE_USAGE_SHADER_READ, float4(0)); + dummy_coba_tx_.ensure_1d(GPU_RGBA8, 1, GPU_TEXTURE_USAGE_SHADER_READ, float4(0)); +} + +void VolumePass::object_sync_volume(Manager &manager, + SceneResources &resources, + const SceneState &scene_state, + ObjectRef &ob_ref, + float3 color) +{ + Object *ob = ob_ref.object; + /* Create 3D textures. */ + Volume *volume = static_cast(ob->data); + BKE_volume_load(volume, G.main); + const VolumeGrid *volume_grid = BKE_volume_grid_active_get_for_read(volume); + if (volume_grid == nullptr) { + return; + } + + DRWVolumeGrid *grid = DRW_volume_batch_cache_get_grid(volume, volume_grid); + if (grid == nullptr) { + return; + } + + active_ = true; + + PassMain::Sub &sub_ps = ps_.sub(ob->id.name); + + const bool use_slice = (volume->display.axis_slice_method == AXIS_SLICE_SINGLE); + + sub_ps.shader_set(get_shader(use_slice, false, volume->display.interpolation_method, false)); + + const float density_scale = volume->display.density * + BKE_volume_density_scale(volume, ob->object_to_world); + + sub_ps.bind_texture("depthBuffer", &resources.depth_tx); + sub_ps.bind_texture("densityTexture", grid->texture); + /* TODO: implement shadow texture, see manta_smoke_calc_transparency. */ + sub_ps.bind_texture("shadowTexture", dummy_shadow_tx_); + sub_ps.push_constant("activeColor", color); + sub_ps.push_constant("densityScale", density_scale); + sub_ps.push_constant("volumeObjectToTexture", float4x4(grid->object_to_texture)); + sub_ps.push_constant("volumeTextureToObject", float4x4(grid->texture_to_object)); + + if (use_slice) { + setup_slice_ps(sub_ps, ob, volume->display.slice_axis, volume->display.slice_depth); + } + else { + float3 world_size; + float4x4 texture_to_world = float4x4(ob->object_to_world) * float4x4(grid->texture_to_object); + math::normalize_and_get_size(float3x3(texture_to_world), world_size); + + int3 resolution; + GPU_texture_get_mipmap_size(grid->texture, 0, resolution); + float3 slice_count = float3(resolution) * 5.0f; + + setup_non_slice_ps(sub_ps, ob, scene_state.sample, slice_count, world_size); + } + + sub_ps.draw(DRW_cache_cube_get(), manager.resource_handle(ob_ref)); +} + +void VolumePass::object_sync_modifier(Manager &manager, + SceneResources &resources, + const SceneState &scene_state, + ObjectRef &ob_ref, + ModifierData *md) +{ + Object *ob = ob_ref.object; + + FluidModifierData *modifier = reinterpret_cast(md); + FluidDomainSettings &settings = *modifier->domain; + + if (!settings.fluid) { + return; + } + + bool can_load = false; + if (settings.use_coba) { + DRW_smoke_ensure_coba_field(modifier); + can_load = settings.tex_field != nullptr; + } + else if (settings.type == FLUID_DOMAIN_TYPE_GAS) { + DRW_smoke_ensure(modifier, settings.flags & FLUID_DOMAIN_USE_NOISE); + can_load = settings.tex_density != nullptr || settings.tex_color != nullptr; + } + + if (!can_load) { + return; + } + + active_ = true; + + PassMain::Sub &sub_ps = ps_.sub(ob->id.name); + + const bool use_slice = settings.axis_slice_method == AXIS_SLICE_SINGLE; + + sub_ps.shader_set(get_shader(use_slice, settings.use_coba, settings.interp_method, true)); + + if (settings.use_coba) { + const bool show_flags = settings.coba_field == FLUID_DOMAIN_FIELD_FLAGS; + const bool show_pressure = settings.coba_field == FLUID_DOMAIN_FIELD_PRESSURE; + const bool show_phi = ELEM(settings.coba_field, + FLUID_DOMAIN_FIELD_PHI, + FLUID_DOMAIN_FIELD_PHI_IN, + FLUID_DOMAIN_FIELD_PHI_OUT, + FLUID_DOMAIN_FIELD_PHI_OBSTACLE); + + sub_ps.push_constant("showFlags", show_flags); + sub_ps.push_constant("showPressure", show_pressure); + sub_ps.push_constant("showPhi", show_phi); + sub_ps.push_constant("gridScale", settings.grid_scale); + + if (show_flags) { + sub_ps.bind_texture("flagTexture", settings.tex_field); + } + else { + sub_ps.bind_texture("densityTexture", settings.tex_field); + } + + if (!show_flags && !show_pressure && !show_phi) { + sub_ps.bind_texture("transferTexture", settings.tex_coba); + } + } + else { + bool use_constant_color = ((settings.active_fields & FLUID_DOMAIN_ACTIVE_COLORS) == 0 && + (settings.active_fields & FLUID_DOMAIN_ACTIVE_COLOR_SET) != 0); + + sub_ps.push_constant("activeColor", + use_constant_color ? float3(settings.active_color) : float3(1)); + + sub_ps.bind_texture("densityTexture", + settings.tex_color ? settings.tex_color : settings.tex_density); + sub_ps.bind_texture("flameTexture", + settings.tex_flame ? settings.tex_flame : dummy_volume_tx_); + sub_ps.bind_texture("flameColorTexture", + settings.tex_flame ? settings.tex_flame_coba : dummy_coba_tx_); + sub_ps.bind_texture("shadowTexture", settings.tex_shadow); + } + + sub_ps.push_constant("densityScale", 10.0f * settings.display_thickness); + sub_ps.bind_texture("depthBuffer", &resources.depth_tx); + + if (use_slice) { + setup_slice_ps(sub_ps, ob, settings.slice_axis, settings.slice_depth); + /* TODO (Miguel Pozo): Why is a quad used here, but not in volume? */ + sub_ps.draw(DRW_cache_quad_get(), manager.resource_handle(ob_ref)); + } + else { + float3 world_size; + BKE_object_dimensions_get(ob, world_size); + + float3 slice_count = float3(settings.res) * std::max(0.001f, settings.slice_per_voxel); + + setup_non_slice_ps(sub_ps, ob, scene_state.sample, slice_count, world_size); + sub_ps.draw(DRW_cache_cube_get(), manager.resource_handle(ob_ref)); + } +} + +void VolumePass::draw(Manager &manager, View &view, SceneResources &resources) +{ + if (!active_) { + return; + } + fb_.ensure(GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(resources.color_tx)); + fb_.bind(); + manager.submit(ps_, view); +} + +} // namespace blender::workbench -- 2.30.2 From 327d87ef3d5612c1306df45d38b84e5fa2f3c882 Mon Sep 17 00:00:00 2001 From: Miguel Pozo Date: Mon, 6 Mar 2023 17:42:02 +0100 Subject: [PATCH 08/10] cleanup --- .../engines/workbench/workbench_private.hh | 14 +++++-- .../workbench/workbench_volume_next.cc | 37 ++++++++++--------- 2 files changed, 30 insertions(+), 21 deletions(-) diff --git a/source/blender/draw/engines/workbench/workbench_private.hh b/source/blender/draw/engines/workbench/workbench_private.hh index dedc9941ebb..e098db26b06 100644 --- a/source/blender/draw/engines/workbench/workbench_private.hh +++ b/source/blender/draw/engines/workbench/workbench_private.hh @@ -337,10 +337,18 @@ class VolumePass { GPUShader *shaders_[2][2][3][2]; GPUShader *get_shader(bool slice, bool coba, int interpolation, bool smoke); - void setup_slice_ps(PassMain::Sub &ps, Object *ob, int slice_axis_enum, float slice_depth); + void draw_slice_ps(Manager &manager, + PassMain::Sub &ps, + ObjectRef &ob_ref, + int slice_axis_enum, + float slice_depth); - void setup_non_slice_ps( - PassMain::Sub &ps, Object *ob, int taa_sample, float3 slice_count, float3 world_size); + void draw_volume_ps(Manager &manager, + PassMain::Sub &ps, + ObjectRef &ob_ref, + int taa_sample, + float3 slice_count, + float3 world_size); public: void sync(SceneResources &resources); diff --git a/source/blender/draw/engines/workbench/workbench_volume_next.cc b/source/blender/draw/engines/workbench/workbench_volume_next.cc index affcfd7c694..8aa9c725892 100644 --- a/source/blender/draw/engines/workbench/workbench_volume_next.cc +++ b/source/blender/draw/engines/workbench/workbench_volume_next.cc @@ -37,10 +37,8 @@ GPUShader *VolumePass::get_shader(bool slice, bool coba, int interpolation, bool return shader; } -void VolumePass::setup_slice_ps(PassMain::Sub &ps, - Object *ob, - int slice_axis_enum, - float slice_depth) +void VolumePass::draw_slice_ps( + Manager &manager, PassMain::Sub &ps, ObjectRef &ob_ref, int slice_axis_enum, float slice_depth) { float4x4 view_mat_inv; DRW_view_viewmat_get(nullptr, view_mat_inv.ptr(), true); @@ -50,18 +48,24 @@ void VolumePass::setup_slice_ps(PassMain::Sub &ps, slice_axis_enum - 1; float3 dimensions; - BKE_object_dimensions_get(ob, dimensions); + BKE_object_dimensions_get(ob_ref.object, dimensions); /* 0.05f to achieve somewhat the same opacity as the full view. */ - float step_length = max_ff(1e-16f, dimensions[axis] * 0.05f); + float step_length = std::max(1e-16f, dimensions[axis] * 0.05f); ps.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL); ps.push_constant("slicePosition", slice_depth); ps.push_constant("sliceAxis", axis); ps.push_constant("stepLength", step_length); + + ps.draw(DRW_cache_quad_get(), manager.resource_handle(ob_ref)); } -void VolumePass::setup_non_slice_ps( - PassMain::Sub &ps, Object *ob, int taa_sample, float3 slice_count, float3 world_size) +void VolumePass::draw_volume_ps(Manager &manager, + PassMain::Sub &ps, + ObjectRef &ob_ref, + int taa_sample, + float3 slice_count, + float3 world_size) { double noise_offset; BLI_halton_1d(3, 0.0, taa_sample, &noise_offset); @@ -69,11 +73,12 @@ void VolumePass::setup_non_slice_ps( int max_slice = std::max({UNPACK3(slice_count)}); float step_length = math::length((1.0f / slice_count) * world_size); - /*TODO (Miguel Pozo): Does this override or replace the parent pass state ? */ ps.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL | DRW_STATE_CULL_FRONT); ps.push_constant("samplesLen", max_slice); ps.push_constant("stepLength", step_length); ps.push_constant("noiseOfs", float(noise_offset)); + + ps.draw(DRW_cache_cube_get(), manager.resource_handle(ob_ref)); } void VolumePass::sync(SceneResources &resources) @@ -128,7 +133,8 @@ void VolumePass::object_sync_volume(Manager &manager, sub_ps.push_constant("volumeTextureToObject", float4x4(grid->texture_to_object)); if (use_slice) { - setup_slice_ps(sub_ps, ob, volume->display.slice_axis, volume->display.slice_depth); + draw_slice_ps( + manager, sub_ps, ob_ref, volume->display.slice_axis, volume->display.slice_depth); } else { float3 world_size; @@ -139,10 +145,8 @@ void VolumePass::object_sync_volume(Manager &manager, GPU_texture_get_mipmap_size(grid->texture, 0, resolution); float3 slice_count = float3(resolution) * 5.0f; - setup_non_slice_ps(sub_ps, ob, scene_state.sample, slice_count, world_size); + draw_volume_ps(manager, sub_ps, ob_ref, scene_state.sample, slice_count, world_size); } - - sub_ps.draw(DRW_cache_cube_get(), manager.resource_handle(ob_ref)); } void VolumePass::object_sync_modifier(Manager &manager, @@ -227,9 +231,7 @@ void VolumePass::object_sync_modifier(Manager &manager, sub_ps.bind_texture("depthBuffer", &resources.depth_tx); if (use_slice) { - setup_slice_ps(sub_ps, ob, settings.slice_axis, settings.slice_depth); - /* TODO (Miguel Pozo): Why is a quad used here, but not in volume? */ - sub_ps.draw(DRW_cache_quad_get(), manager.resource_handle(ob_ref)); + draw_slice_ps(manager, sub_ps, ob_ref, settings.slice_axis, settings.slice_depth); } else { float3 world_size; @@ -237,8 +239,7 @@ void VolumePass::object_sync_modifier(Manager &manager, float3 slice_count = float3(settings.res) * std::max(0.001f, settings.slice_per_voxel); - setup_non_slice_ps(sub_ps, ob, scene_state.sample, slice_count, world_size); - sub_ps.draw(DRW_cache_cube_get(), manager.resource_handle(ob_ref)); + draw_volume_ps(manager, sub_ps, ob_ref, scene_state.sample, slice_count, world_size); } } -- 2.30.2 From 5eba5d9cd22115e3bfbb0c5ad9368f0392c91532 Mon Sep 17 00:00:00 2001 From: Miguel Pozo Date: Tue, 16 May 2023 15:20:03 +0200 Subject: [PATCH 09/10] Remove implicit casting --- .../draw/engines/workbench/shaders/workbench_volume_frag.glsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl index 8224f76c420..8d2bd08cf30 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl @@ -212,7 +212,7 @@ vec4 volume_integration(vec3 ray_ori, vec3 ray_dir, float ray_inc, float ray_max if (final_transmittance <= 0.01) { /* Early out */ - final_transmittance = 0; + final_transmittance = 0.0; break; } } -- 2.30.2 From 60f5e72f1faa1c40750c8308fe162b1ed27077da Mon Sep 17 00:00:00 2001 From: Miguel Pozo Date: Tue, 16 May 2023 15:21:04 +0200 Subject: [PATCH 10/10] Reorder class layout --- .../engines/workbench/workbench_private.hh | 32 ++-- .../workbench/workbench_volume_next.cc | 142 +++++++++--------- 2 files changed, 88 insertions(+), 86 deletions(-) diff --git a/source/blender/draw/engines/workbench/workbench_private.hh b/source/blender/draw/engines/workbench/workbench_private.hh index e098db26b06..5366314d073 100644 --- a/source/blender/draw/engines/workbench/workbench_private.hh +++ b/source/blender/draw/engines/workbench/workbench_private.hh @@ -334,21 +334,7 @@ class VolumePass { Texture dummy_volume_tx_ = {"Volume.Dummy Volume Tx"}; Texture dummy_coba_tx_ = {"Volume.Dummy Coba Tx"}; - GPUShader *shaders_[2][2][3][2]; - GPUShader *get_shader(bool slice, bool coba, int interpolation, bool smoke); - - void draw_slice_ps(Manager &manager, - PassMain::Sub &ps, - ObjectRef &ob_ref, - int slice_axis_enum, - float slice_depth); - - void draw_volume_ps(Manager &manager, - PassMain::Sub &ps, - ObjectRef &ob_ref, - int taa_sample, - float3 slice_count, - float3 world_size); + GPUShader *shaders_[2 /*slice*/][2 /*coba*/][3 /*interpolation*/][2 /*smoke*/]; public: void sync(SceneResources &resources); @@ -366,6 +352,22 @@ class VolumePass { ModifierData *md); void draw(Manager &manager, View &view, SceneResources &resources); + + private: + GPUShader *get_shader(bool slice, bool coba, int interpolation, bool smoke); + + void draw_slice_ps(Manager &manager, + PassMain::Sub &ps, + ObjectRef &ob_ref, + int slice_axis_enum, + float slice_depth); + + void draw_volume_ps(Manager &manager, + PassMain::Sub &ps, + ObjectRef &ob_ref, + int taa_sample, + float3 slice_count, + float3 world_size); }; class OutlinePass { diff --git a/source/blender/draw/engines/workbench/workbench_volume_next.cc b/source/blender/draw/engines/workbench/workbench_volume_next.cc index 8aa9c725892..3307aa21a13 100644 --- a/source/blender/draw/engines/workbench/workbench_volume_next.cc +++ b/source/blender/draw/engines/workbench/workbench_volume_next.cc @@ -10,77 +10,6 @@ namespace blender::workbench { -GPUShader *VolumePass::get_shader(bool slice, bool coba, int interpolation, bool smoke) -{ - GPUShader *&shader = shaders_[slice][coba][interpolation][smoke]; - - if (shader == nullptr) { - std::string create_info_name = "workbench_next_volume"; - create_info_name += (smoke) ? "_smoke" : "_object"; - switch (interpolation) { - case VOLUME_DISPLAY_INTERP_LINEAR: - create_info_name += "_linear"; - break; - case VOLUME_DISPLAY_INTERP_CUBIC: - create_info_name += "_cubic"; - break; - case VOLUME_DISPLAY_INTERP_CLOSEST: - create_info_name += "_closest"; - break; - default: - BLI_assert_unreachable(); - } - create_info_name += (coba) ? "_coba" : "_no_coba"; - create_info_name += (slice) ? "_slice" : "_no_slice"; - shader = GPU_shader_create_from_info_name(create_info_name.c_str()); - } - return shader; -} - -void VolumePass::draw_slice_ps( - Manager &manager, PassMain::Sub &ps, ObjectRef &ob_ref, int slice_axis_enum, float slice_depth) -{ - float4x4 view_mat_inv; - DRW_view_viewmat_get(nullptr, view_mat_inv.ptr(), true); - - const int axis = (slice_axis_enum == SLICE_AXIS_AUTO) ? - axis_dominant_v3_single(view_mat_inv[2]) : - slice_axis_enum - 1; - - float3 dimensions; - BKE_object_dimensions_get(ob_ref.object, dimensions); - /* 0.05f to achieve somewhat the same opacity as the full view. */ - float step_length = std::max(1e-16f, dimensions[axis] * 0.05f); - - ps.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL); - ps.push_constant("slicePosition", slice_depth); - ps.push_constant("sliceAxis", axis); - ps.push_constant("stepLength", step_length); - - ps.draw(DRW_cache_quad_get(), manager.resource_handle(ob_ref)); -} - -void VolumePass::draw_volume_ps(Manager &manager, - PassMain::Sub &ps, - ObjectRef &ob_ref, - int taa_sample, - float3 slice_count, - float3 world_size) -{ - double noise_offset; - BLI_halton_1d(3, 0.0, taa_sample, &noise_offset); - - int max_slice = std::max({UNPACK3(slice_count)}); - float step_length = math::length((1.0f / slice_count) * world_size); - - ps.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL | DRW_STATE_CULL_FRONT); - ps.push_constant("samplesLen", max_slice); - ps.push_constant("stepLength", step_length); - ps.push_constant("noiseOfs", float(noise_offset)); - - ps.draw(DRW_cache_cube_get(), manager.resource_handle(ob_ref)); -} - void VolumePass::sync(SceneResources &resources) { active_ = false; @@ -253,4 +182,75 @@ void VolumePass::draw(Manager &manager, View &view, SceneResources &resources) manager.submit(ps_, view); } +GPUShader *VolumePass::get_shader(bool slice, bool coba, int interpolation, bool smoke) +{ + GPUShader *&shader = shaders_[slice][coba][interpolation][smoke]; + + if (shader == nullptr) { + std::string create_info_name = "workbench_next_volume"; + create_info_name += (smoke) ? "_smoke" : "_object"; + switch (interpolation) { + case VOLUME_DISPLAY_INTERP_LINEAR: + create_info_name += "_linear"; + break; + case VOLUME_DISPLAY_INTERP_CUBIC: + create_info_name += "_cubic"; + break; + case VOLUME_DISPLAY_INTERP_CLOSEST: + create_info_name += "_closest"; + break; + default: + BLI_assert_unreachable(); + } + create_info_name += (coba) ? "_coba" : "_no_coba"; + create_info_name += (slice) ? "_slice" : "_no_slice"; + shader = GPU_shader_create_from_info_name(create_info_name.c_str()); + } + return shader; +} + +void VolumePass::draw_slice_ps( + Manager &manager, PassMain::Sub &ps, ObjectRef &ob_ref, int slice_axis_enum, float slice_depth) +{ + float4x4 view_mat_inv; + DRW_view_viewmat_get(nullptr, view_mat_inv.ptr(), true); + + const int axis = (slice_axis_enum == SLICE_AXIS_AUTO) ? + axis_dominant_v3_single(view_mat_inv[2]) : + slice_axis_enum - 1; + + float3 dimensions; + BKE_object_dimensions_get(ob_ref.object, dimensions); + /* 0.05f to achieve somewhat the same opacity as the full view. */ + float step_length = std::max(1e-16f, dimensions[axis] * 0.05f); + + ps.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL); + ps.push_constant("slicePosition", slice_depth); + ps.push_constant("sliceAxis", axis); + ps.push_constant("stepLength", step_length); + + ps.draw(DRW_cache_quad_get(), manager.resource_handle(ob_ref)); +} + +void VolumePass::draw_volume_ps(Manager &manager, + PassMain::Sub &ps, + ObjectRef &ob_ref, + int taa_sample, + float3 slice_count, + float3 world_size) +{ + double noise_offset; + BLI_halton_1d(3, 0.0, taa_sample, &noise_offset); + + int max_slice = std::max({UNPACK3(slice_count)}); + float step_length = math::length((1.0f / slice_count) * world_size); + + ps.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL | DRW_STATE_CULL_FRONT); + ps.push_constant("samplesLen", max_slice); + ps.push_constant("stepLength", step_length); + ps.push_constant("noiseOfs", float(noise_offset)); + + ps.draw(DRW_cache_cube_get(), manager.resource_handle(ob_ref)); +} + } // namespace blender::workbench -- 2.30.2