Blender V5.0
overlay_fluid.hh
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2024 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#pragma once
10
11#include "DNA_fluid_types.h"
12#include "DNA_modifier_types.h"
13
14#include "BKE_modifier.hh"
15
16#include "overlay_base.hh"
17
18namespace blender::draw::overlay {
19
23class Fluids : Overlay {
24 private:
25 const SelectionType selection_type_;
26
27 PassSimple fluid_ps_ = {"fluid_ps_"};
28 PassSimple::Sub *velocity_needle_ps_ = nullptr;
29 PassSimple::Sub *velocity_mac_ps_ = nullptr;
30 PassSimple::Sub *velocity_streamline_ps_ = nullptr;
31 PassSimple::Sub *grid_lines_flags_ps_ = nullptr;
32 PassSimple::Sub *grid_lines_flat_ps_ = nullptr;
33 PassSimple::Sub *grid_lines_range_ps_ = nullptr;
34
35 ShapeInstanceBuf<ExtraInstanceData> cube_buf_ = {selection_type_, "cube_buf_"};
36
37 int dominant_axis = -1;
38
39 public:
40 Fluids(const SelectionType selection_type) : selection_type_(selection_type) {};
41
42 void begin_sync(Resources &res, const State &state) final
43 {
44 /* Against design. Should not sync depending on view. */
46 dominant_axis = math::dominant_axis(camera_direction);
47
48 {
49 auto &pass = fluid_ps_;
50 pass.init();
52 state.clipping_plane_count);
53 res.select_bind(pass);
54
55 /* TODO(fclem): Use either specialization constants or push constants to reduce the amount of
56 * shader variants. */
57 velocity_needle_ps_ = &fluid_ps_.sub("Velocity Needles");
58 velocity_needle_ps_->shader_set(res.shaders->fluid_velocity_needle.get());
59
60 velocity_mac_ps_ = &fluid_ps_.sub("Velocity Mac");
61 velocity_mac_ps_->shader_set(res.shaders->fluid_velocity_mac.get());
62
63 velocity_streamline_ps_ = &fluid_ps_.sub("Velocity Line");
64 velocity_streamline_ps_->shader_set(res.shaders->fluid_velocity_streamline.get());
65
66 grid_lines_flags_ps_ = &fluid_ps_.sub("Velocity Mac");
67 grid_lines_flags_ps_->shader_set(res.shaders->fluid_grid_lines_flags.get());
68
69 grid_lines_flat_ps_ = &fluid_ps_.sub("Velocity Needles");
70 grid_lines_flat_ps_->shader_set(res.shaders->fluid_grid_lines_flat.get());
71
72 grid_lines_range_ps_ = &fluid_ps_.sub("Velocity Line");
73 grid_lines_range_ps_->shader_set(res.shaders->fluid_grid_lines_range.get());
74 }
75
76 cube_buf_.clear();
77 }
78
79 void object_sync(Manager &manager,
80 const ObjectRef &ob_ref,
81 Resources &res,
82 const State &state) final
83 {
84 Object *ob = ob_ref.object;
85
86 /* Do not show for dupli objects as the fluid is baked for the original object. */
87 if (is_from_dupli_or_set(ob)) {
88 return;
89 }
90
91 /* NOTE: There can only be one fluid modifier per object. */
93
94 if (md == nullptr) {
95 return;
96 }
97
99 FluidDomainSettings *fds = fmd->domain;
100
101 if (fds == nullptr) {
102 return;
103 }
104
105 const bool is_active_frame_after_cache_start = state.scene->r.cfra >= fds->cache_frame_start;
106 const bool is_active_frame_before_cache_end = state.scene->r.cfra <= fds->cache_frame_end;
107 const bool is_active_frame_in_cache_range = is_active_frame_after_cache_start &&
108 is_active_frame_before_cache_end;
109 if (!is_active_frame_in_cache_range) {
110 return;
111 }
112
113 ResourceHandleRange res_handle = manager.unique_handle(ob_ref);
114 select::ID sel_id = res.select_id(ob_ref);
115
116 /* Small cube showing voxel size. */
117 {
118 float3 min = float3(fds->p0) + float3(fds->cell_size) * float3(int3(fds->res_min));
119 float4x4 voxel_cube_mat = math::from_loc_scale<float4x4>(min, float3(fds->cell_size) / 2.0f);
120 /* Move small cube into the domain, otherwise its centered on corner of domain object. */
121 voxel_cube_mat = math::translate(voxel_cube_mat, float3(1.0f));
122 voxel_cube_mat = ob->object_to_world() * voxel_cube_mat;
123
124 const float4 &color = res.object_wire_color(ob_ref, state);
125 cube_buf_.append({voxel_cube_mat, color, 1.0f}, sel_id);
126 }
127
128 /* No volume data to display. */
129 if (fds->fluid == nullptr) {
130 return;
131 }
132
133 int slice_axis = slide_axis_get(*fds);
134
135 if (fds->draw_velocity) {
136 int lines_per_voxel = -1;
137 PassSimple::Sub *sub_pass = nullptr;
138 switch (fds->vector_draw_type) {
139 default:
141 sub_pass = velocity_streamline_ps_;
142 lines_per_voxel = 1;
143 break;
145 sub_pass = velocity_needle_ps_;
146 lines_per_voxel = 6;
147 break;
148 case VECTOR_DRAW_MAC:
149 sub_pass = velocity_mac_ps_;
150 lines_per_voxel = 3;
151 break;
152 }
153
154 int total_lines = lines_per_voxel * math::reduce_mul(int3(fds->res));
155 if (slice_axis != -1) {
156 /* Remove the sliced dimension. */
157 total_lines /= fds->res[slice_axis];
158 }
159
161
162 PassSimple::Sub &sub = *sub_pass;
163 sub.bind_texture("velocity_x", fds->tex_velocity_x);
164 sub.bind_texture("velocity_y", fds->tex_velocity_y);
165 sub.bind_texture("velocity_z", fds->tex_velocity_z);
166 sub.push_constant("display_size", fds->vector_scale);
167 sub.push_constant("slice_position", fds->slice_depth);
168 sub.push_constant("cell_size", float3(fds->cell_size));
169 sub.push_constant("domain_origin_offset", float3(fds->p0));
170 sub.push_constant("adaptive_cell_offset", int3(fds->res_min));
171 sub.push_constant("slice_axis", slice_axis);
172 sub.push_constant("scale_with_magnitude", bool(fds->vector_scale_with_magnitude));
173 sub.push_constant("is_cell_centered",
175 if (fds->vector_draw_type == VECTOR_DRAW_MAC) {
179 }
180 sub.push_constant("in_select_id", int(sel_id.get()));
181 sub.draw_procedural(GPU_PRIM_LINES, 1, total_lines * 2, -1, res_handle);
182 }
183
184 /* Show gridlines only for slices with no interpolation. */
185 const bool show_gridlines = fds->show_gridlines &&
189 if (show_gridlines) {
190 PassSimple::Sub *sub_pass = nullptr;
191 switch (fds->gridlines_color_field) {
192 default:
195
196 sub_pass = grid_lines_flags_ps_;
197 sub_pass->bind_texture("flag_tx", fds->tex_flags);
198 break;
200 if (fds->use_coba && (fds->coba_field != FLUID_DOMAIN_FIELD_FLAGS)) {
203
204 sub_pass = grid_lines_range_ps_;
205 sub_pass->bind_texture("flag_tx", fds->tex_flags);
206 sub_pass->bind_texture("field_tx", fds->tex_range_field);
207 sub_pass->push_constant("lower_bound", fds->gridlines_lower_bound);
208 sub_pass->push_constant("upper_bound", fds->gridlines_upper_bound);
209 sub_pass->push_constant("range_color", float4(fds->gridlines_range_color));
210 sub_pass->push_constant("cell_filter", int(fds->gridlines_cell_filter));
211 break;
212 }
213 /* Otherwise, fall back to none color type. */
216 sub_pass = grid_lines_flat_ps_;
217 break;
218 }
219
220 PassSimple::Sub &sub = *sub_pass;
221 sub.push_constant("volume_size", int3(fds->res));
222 sub.push_constant("slice_position", fds->slice_depth);
223 sub.push_constant("cell_size", float3(fds->cell_size));
224 sub.push_constant("domain_origin_offset", float3(fds->p0));
225 sub.push_constant("adaptive_cell_offset", int3(fds->res_min));
226 sub.push_constant("slice_axis", slice_axis);
227 sub.push_constant("in_select_id", int(sel_id.get()));
228
229 BLI_assert(slice_axis != -1);
230 int lines_per_voxel = 4;
231 int total_lines = lines_per_voxel * math::reduce_mul(int3(fds->res)) / fds->res[slice_axis];
232 sub.draw_procedural(GPU_PRIM_LINES, 1, total_lines * 2, -1, res_handle);
233 }
234 }
235
236 void end_sync(Resources &res, const State & /*state*/) final
237 {
238 fluid_ps_.shader_set(res.shaders->extra_shape.get());
239 fluid_ps_.bind_ubo(OVERLAY_GLOBALS_SLOT, &res.globals_buf);
240 fluid_ps_.bind_ubo(DRW_CLIPPING_UBO_SLOT, &res.clip_planes_buf);
241
242 cube_buf_.end_sync(fluid_ps_, res.shapes.cube.get());
243 }
244
245 void draw_line(Framebuffer &framebuffer, Manager &manager, View &view) final
246 {
247 GPU_framebuffer_bind(framebuffer);
248 manager.submit(fluid_ps_, view);
249 }
250
251 private:
252 /* Return axis index or -1 if no slice. */
253 int slide_axis_get(FluidDomainSettings &fluid_domain_settings) const
254 {
255 if (fluid_domain_settings.axis_slice_method != AXIS_SLICE_SINGLE) {
256 return -1;
257 }
258 if (fluid_domain_settings.slice_axis == SLICE_AXIS_AUTO) {
259 return dominant_axis;
260 }
261 return fluid_domain_settings.slice_axis - 1;
262 }
263};
264
265} // namespace blender::draw::overlay
ModifierData * BKE_modifiers_findby_type(const Object *ob, ModifierType type)
#define BLI_assert(a)
Definition BLI_assert.h:46
#define ATTR_FALLTHROUGH
@ FLUID_GRIDLINE_COLOR_TYPE_FLAGS
@ FLUID_GRIDLINE_COLOR_TYPE_RANGE
@ FLUID_GRIDLINE_COLOR_TYPE_NONE
@ FLUID_DOMAIN_FIELD_FLAGS
@ VECTOR_DRAW_NEEDLE
@ VECTOR_DRAW_STREAMLINE
@ VECTOR_DRAW_MAC
@ FLUID_DISPLAY_INTERP_CLOSEST
@ VECTOR_DRAW_MAC_X
@ VECTOR_DRAW_MAC_Y
@ VECTOR_DRAW_MAC_Z
@ SLICE_AXIS_AUTO
@ FLUID_DOMAIN_VECTOR_FIELD_FORCE
@ AXIS_SLICE_SINGLE
@ eModifierType_Fluid
static AppView * view
void GPU_framebuffer_bind(blender::gpu::FrameBuffer *fb)
@ GPU_PRIM_LINES
static View & default_get()
Definition draw_view.cc:317
const float4x4 & viewinv(int view_id=0) const
Definition draw_view.hh:142
void bind_texture(const char *name, gpu::Texture *texture, GPUSamplerState state=sampler_auto)
void draw_procedural(GPUPrimType primitive, uint instance_len, uint vertex_len, uint vertex_first=-1, ResourceIndexRange res_index={}, uint custom_id=0)
Definition draw_pass.hh:964
void push_constant(const char *name, const float &data)
detail::PassBase< command::DrawCommandBuf > Sub
Definition draw_pass.hh:499
void begin_sync(Resources &res, const State &state) final
Fluids(const SelectionType selection_type)
void object_sync(Manager &manager, const ObjectRef &ob_ref, Resources &res, const State &state) final
void end_sync(Resources &res, const State &) final
void draw_line(Framebuffer &framebuffer, Manager &manager, View &view) final
void DRW_fluid_ensure_flags(FluidModifierData *fmd)
void DRW_fluid_ensure_range_field(FluidModifierData *fmd)
void DRW_smoke_ensure_velocity(FluidModifierData *fmd)
#define DRW_CLIPPING_UBO_SLOT
#define OVERLAY_GLOBALS_SLOT
@ DRW_STATE_WRITE_DEPTH
Definition draw_state.hh:29
@ DRW_STATE_WRITE_COLOR
Definition draw_state.hh:30
@ DRW_STATE_DEPTH_LESS_EQUAL
Definition draw_state.hh:38
static ulong state[N]
select::SelectionType SelectionType
static bool is_from_dupli_or_set(const Object *ob)
detail::Pass< command::DrawCommandBuf > PassSimple
MatT from_loc_scale(const typename MatT::loc_type &location, const VecBase< typename MatT::base_type, ScaleDim > &scale)
T min(const T &a, const T &b)
MatBase< T, NumCol, NumRow > translate(const MatBase< T, NumCol, NumRow > &mat, const VectorT &translation)
T reduce_mul(const VecBase< T, Size > &a)
int dominant_axis(const VecBase< T, 3 > &a)
MatBase< float, 4, 4 > float4x4
VecBase< float, 4 > float4
VecBase< int32_t, 3 > int3
VecBase< float, 3 > float3
GPUTexture * tex_velocity_z
GPUTexture * tex_velocity_y
GPUTexture * tex_range_field
GPUTexture * tex_velocity_x
struct FluidDomainSettings * domain