Blender V4.3
workbench_volume.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
6
7#include "BKE_volume.hh"
9#include "BLI_rand.h"
10#include "DNA_fluid_types.h"
11#include "DNA_modifier_types.h"
12
13namespace blender::workbench {
14
16{
17 active_ = false;
18 ps_.init();
19 ps_.bind_ubo(WB_WORLD_SLOT, resources.world_buf);
20
24}
25
27 SceneResources &resources,
28 const SceneState &scene_state,
29 ObjectRef &ob_ref,
30 float3 color)
31{
32 Object *ob = ob_ref.object;
33 /* Create 3D textures. */
34 Volume *volume = static_cast<Volume *>(ob->data);
35 BKE_volume_load(volume, G.main);
36 const bke::VolumeGridData *volume_grid = BKE_volume_grid_active_get_for_read(volume);
37 if (volume_grid == nullptr) {
38 return;
39 }
40
41 DRWVolumeGrid *grid = DRW_volume_batch_cache_get_grid(volume, volume_grid);
42 if (grid == nullptr) {
43 return;
44 }
45
46 active_ = true;
47
48 PassMain::Sub &sub_ps = ps_.sub("Volume Object SubPass");
49
50 const bool use_slice = (volume->display.axis_slice_method == AXIS_SLICE_SINGLE);
51
53 false, volume->display.interpolation_method, false, use_slice));
54 sub_ps.push_constant("do_depth_test", scene_state.shading.type >= OB_SOLID);
55
56 const float density_scale = volume->display.density *
57 BKE_volume_density_scale(volume, ob->object_to_world().ptr());
58
59 sub_ps.bind_texture("depthBuffer", &resources.depth_tx);
60 sub_ps.bind_texture("stencil_tx", &stencil_tx_);
61 sub_ps.bind_texture("densityTexture", grid->texture);
62 /* TODO: implement shadow texture, see manta_smoke_calc_transparency. */
63 sub_ps.bind_texture("shadowTexture", dummy_shadow_tx_);
64 sub_ps.push_constant("activeColor", color);
65 sub_ps.push_constant("densityScale", density_scale);
66 sub_ps.push_constant("volumeObjectToTexture", float4x4(grid->object_to_texture));
67 sub_ps.push_constant("volumeTextureToObject", float4x4(grid->texture_to_object));
68
69 if (use_slice) {
70 draw_slice_ps(
71 manager, sub_ps, ob_ref, volume->display.slice_axis, volume->display.slice_depth);
72 }
73 else {
74 float4x4 texture_to_world = ob->object_to_world() * float4x4(grid->texture_to_object);
75 float3 world_size = math::to_scale(texture_to_world);
76
77 int3 resolution;
78 GPU_texture_get_mipmap_size(grid->texture, 0, resolution);
79 float3 slice_count = float3(resolution) * 5.0f;
80
81 draw_volume_ps(manager, sub_ps, ob_ref, scene_state.sample, slice_count, world_size);
82 }
83}
84
86 SceneResources &resources,
87 const SceneState &scene_state,
88 ObjectRef &ob_ref,
89 ModifierData *md)
90{
91 Object *ob = ob_ref.object;
92
93 FluidModifierData *modifier = reinterpret_cast<FluidModifierData *>(md);
94 FluidDomainSettings &settings = *modifier->domain;
95
96 if (!settings.fluid) {
97 return;
98 }
99
100 bool can_load = false;
101 if (settings.use_coba) {
103 can_load = settings.tex_field != nullptr;
104 }
105 else if (settings.type == FLUID_DOMAIN_TYPE_GAS) {
106 DRW_smoke_ensure(modifier, settings.flags & FLUID_DOMAIN_USE_NOISE);
107 can_load = settings.tex_density != nullptr || settings.tex_color != nullptr;
108 }
109
110 if (!can_load) {
111 return;
112 }
113
114 active_ = true;
115
116 PassMain::Sub &sub_ps = ps_.sub("Volume Modifier SubPass");
117
118 const bool use_slice = settings.axis_slice_method == AXIS_SLICE_SINGLE;
119
120 sub_ps.shader_set(
121 ShaderCache::get().volume_get(true, settings.interp_method, settings.use_coba, use_slice));
122 sub_ps.push_constant("do_depth_test", scene_state.shading.type >= OB_SOLID);
123
124 if (settings.use_coba) {
125 const bool show_flags = settings.coba_field == FLUID_DOMAIN_FIELD_FLAGS;
126 const bool show_pressure = settings.coba_field == FLUID_DOMAIN_FIELD_PRESSURE;
127 const bool show_phi = ELEM(settings.coba_field,
132
133 sub_ps.push_constant("showFlags", show_flags);
134 sub_ps.push_constant("showPressure", show_pressure);
135 sub_ps.push_constant("showPhi", show_phi);
136 sub_ps.push_constant("gridScale", settings.grid_scale);
137
138 if (show_flags) {
139 sub_ps.bind_texture("flagTexture", settings.tex_field);
140 }
141 else {
142 sub_ps.bind_texture("densityTexture", settings.tex_field);
143 }
144
145 if (!show_flags && !show_pressure && !show_phi) {
146 sub_ps.bind_texture("transferTexture", settings.tex_coba);
147 }
148 }
149 else {
150 bool use_constant_color = ((settings.active_fields & FLUID_DOMAIN_ACTIVE_COLORS) == 0 &&
151 (settings.active_fields & FLUID_DOMAIN_ACTIVE_COLOR_SET) != 0);
152
153 sub_ps.push_constant("activeColor",
154 use_constant_color ? float3(settings.active_color) : float3(1));
155
156 sub_ps.bind_texture("densityTexture",
157 settings.tex_color ? settings.tex_color : settings.tex_density);
158 sub_ps.bind_texture("flameTexture",
159 settings.tex_flame ? settings.tex_flame : dummy_volume_tx_);
160 sub_ps.bind_texture("flameColorTexture",
161 settings.tex_flame ? settings.tex_flame_coba : dummy_coba_tx_);
162 sub_ps.bind_texture("shadowTexture", settings.tex_shadow);
163 }
164
165 sub_ps.push_constant("densityScale", 10.0f * settings.display_thickness);
166 sub_ps.bind_texture("depthBuffer", &resources.depth_tx);
167 sub_ps.bind_texture("stencil_tx", &stencil_tx_);
168
169 if (use_slice) {
170 draw_slice_ps(manager, sub_ps, ob_ref, settings.slice_axis, settings.slice_depth);
171 }
172 else {
173 float3 world_size;
174 BKE_object_dimensions_get(ob, world_size);
175
176 float3 slice_count = float3(settings.res) * std::max(0.001f, settings.slice_per_voxel);
177
178 draw_volume_ps(manager, sub_ps, ob_ref, scene_state.sample, slice_count, world_size);
179 }
180}
181
182void VolumePass::draw(Manager &manager, View &view, SceneResources &resources)
183{
184 if (!active_) {
185 return;
186 }
187
188 stencil_tx_ = resources.stencil_view.extract(manager, resources.depth_tx);
189
191 fb_.bind();
192 manager.submit(ps_, view);
193}
194
195void VolumePass::draw_slice_ps(
196 Manager &manager, PassMain::Sub &ps, ObjectRef &ob_ref, int slice_axis_enum, float slice_depth)
197{
198 float4x4 view_mat_inv;
199 DRW_view_viewmat_get(nullptr, view_mat_inv.ptr(), true);
200
201 const int axis = (slice_axis_enum == SLICE_AXIS_AUTO) ?
202 axis_dominant_v3_single(view_mat_inv[2]) :
203 slice_axis_enum - 1;
204
205 float3 dimensions;
206 BKE_object_dimensions_get(ob_ref.object, dimensions);
207 /* 0.05f to achieve somewhat the same opacity as the full view. */
208 float step_length = std::max(1e-16f, dimensions[axis] * 0.05f);
209
211 ps.push_constant("slicePosition", slice_depth);
212 ps.push_constant("sliceAxis", axis);
213 ps.push_constant("stepLength", step_length);
214
215 ps.draw(DRW_cache_quad_get(), manager.resource_handle(ob_ref));
216}
217
218void VolumePass::draw_volume_ps(Manager &manager,
219 PassMain::Sub &ps,
220 ObjectRef &ob_ref,
221 int taa_sample,
222 float3 slice_count,
223 float3 world_size)
224{
225 double noise_offset;
226 BLI_halton_1d(3, 0.0, taa_sample, &noise_offset);
227
228 int max_slice = std::max({UNPACK3(slice_count)});
229 float step_length = math::length((1.0f / slice_count) * world_size);
230
232 ps.push_constant("samplesLen", max_slice);
233 ps.push_constant("stepLength", step_length);
234 ps.push_constant("noiseOfs", float(noise_offset));
235
236 ps.draw(DRW_cache_cube_get(), manager.resource_handle(ob_ref));
237}
238
239} // namespace blender::workbench
void BKE_object_dimensions_get(Object *ob, float r_vec[3])
Volume data-block.
const blender::bke::VolumeGridData * BKE_volume_grid_active_get_for_read(const Volume *volume)
bool BKE_volume_load(const Volume *volume, const Main *bmain)
Volume data-block rendering and viewport drawing utilities.
float BKE_volume_density_scale(const Volume *volume, const float matrix[4][4])
MINLINE int axis_dominant_v3_single(const float vec[3])
Random number functions.
void BLI_halton_1d(unsigned int prime, double offset, int n, double *r)
Definition rand.cc:284
#define UNPACK3(a)
#define ELEM(...)
@ AXIS_SLICE_SINGLE
@ FLUID_DOMAIN_FIELD_PHI_OUT
@ FLUID_DOMAIN_FIELD_PHI_OBSTACLE
@ FLUID_DOMAIN_FIELD_FLAGS
@ FLUID_DOMAIN_FIELD_PHI
@ FLUID_DOMAIN_FIELD_PRESSURE
@ FLUID_DOMAIN_FIELD_PHI_IN
@ FLUID_DOMAIN_TYPE_GAS
@ FLUID_DOMAIN_ACTIVE_COLORS
@ FLUID_DOMAIN_ACTIVE_COLOR_SET
@ SLICE_AXIS_AUTO
@ FLUID_DOMAIN_USE_NOISE
@ OB_SOLID
#define GPU_ATTACHMENT_TEXTURE(_texture)
#define GPU_ATTACHMENT_NONE
@ GPU_TEXTURE_USAGE_SHADER_READ
void GPU_texture_get_mipmap_size(GPUTexture *texture, int mip_level, int *r_size)
void ensure(GPUAttachment depth=GPU_ATTACHMENT_NONE, GPUAttachment color1=GPU_ATTACHMENT_NONE, GPUAttachment color2=GPU_ATTACHMENT_NONE, GPUAttachment color3=GPU_ATTACHMENT_NONE, GPUAttachment color4=GPU_ATTACHMENT_NONE, GPUAttachment color5=GPU_ATTACHMENT_NONE, GPUAttachment color6=GPU_ATTACHMENT_NONE, GPUAttachment color7=GPU_ATTACHMENT_NONE, GPUAttachment color8=GPU_ATTACHMENT_NONE)
void submit(PassSimple &pass, View &view)
ResourceHandle resource_handle(const ObjectRef &ref, float inflate_bounds=0.0f)
bool ensure_1d(eGPUTextureFormat format, int extent, eGPUTextureUsage usage=GPU_TEXTURE_USAGE_GENERAL, const float *data=nullptr, int mip_len=1)
bool ensure_3d(eGPUTextureFormat format, int3 extent, eGPUTextureUsage usage=GPU_TEXTURE_USAGE_GENERAL, const float *data=nullptr, int mip_len=1)
void draw(gpu::Batch *batch, uint instance_len=-1, uint vertex_len=-1, uint vertex_first=-1, ResourceHandle handle={0}, uint custom_id=0)
Definition draw_pass.hh:760
PassBase< DrawCommandBufType > & sub(const char *name)
Definition draw_pass.hh:616
void state_set(DRWState state, int clip_plane_count=0)
Definition draw_pass.hh:954
void bind_ubo(const char *name, GPUUniformBuf *buffer)
void push_constant(const char *name, const float &data)
void shader_set(GPUShader *shader)
Definition draw_pass.hh:971
detail::PassBase< command::DrawMultiBuf > Sub
Definition draw_pass.hh:462
GPUShader * volume_get(bool smoke, int interpolation, bool coba, bool slice)
GPUTexture * extract(Manager &manager, Texture &stencil_src)
void sync(SceneResources &resources)
void object_sync_volume(Manager &manager, SceneResources &resources, const SceneState &scene_state, ObjectRef &ob_ref, float3 color)
void draw(Manager &manager, View &view, SceneResources &resources)
void object_sync_modifier(Manager &manager, SceneResources &resources, const SceneState &scene_state, ObjectRef &ob_ref, ModifierData *md)
blender::gpu::Batch * DRW_cache_quad_get()
blender::gpu::Batch * DRW_cache_cube_get()
void DRW_smoke_ensure_coba_field(FluidModifierData *fmd)
void DRW_smoke_ensure(FluidModifierData *fmd, int highres)
void DRW_view_viewmat_get(const DRWView *view, float mat[4][4], bool inverse)
@ DRW_STATE_CULL_FRONT
Definition draw_state.hh:44
@ DRW_STATE_WRITE_COLOR
Definition draw_state.hh:30
@ DRW_STATE_BLEND_ALPHA_PREMUL
Definition draw_state.hh:57
RAYTRACE_GROUP_SIZE additional_info("eevee_shared", "eevee_gbuffer_data", "eevee_global_ubo", "eevee_sampling_data", "eevee_utility_texture", "eevee_hiz_data", "draw_view") .specialization_constant(Type RAYTRACE_GROUP_SIZE in_sh_0_tx in_sh_2_tx screen_normal_tx GPU_RGBA8
#define G(x, y, z)
DRWVolumeGrid * DRW_volume_batch_cache_get_grid(Volume *volume, const bke::VolumeGridData *volume_grid)
T length(const VecBase< T, Size > &a)
VecBase< T, 3 > to_scale(const MatBase< T, NumCol, NumRow > &mat)
MatBase< float, 4, 4 > float4x4
VecBase< float, 4 > float4
VecBase< int32_t, 3 > int3
VecBase< float, 3 > float3
const c_style_mat & ptr() const
UniformBuffer< WorldData > world_buf
#define WB_WORLD_SLOT