Blender V4.3
overlay_next_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
9#pragma once
10
11#include "DNA_fluid_types.h"
12#include "DNA_modifier_types.h"
13
14#include "BKE_modifier.hh"
15
17
18namespace blender::draw::overlay {
19
20class Fluids {
21 private:
22 const SelectionType selection_type_;
23
24 PassSimple fluid_ps_ = {"fluid_ps_"};
25 PassSimple::Sub *velocity_needle_ps_ = nullptr;
26 PassSimple::Sub *velocity_mac_ps_ = nullptr;
27 PassSimple::Sub *velocity_streamline_ps_ = nullptr;
28 PassSimple::Sub *grid_lines_flags_ps_ = nullptr;
29 PassSimple::Sub *grid_lines_flat_ps_ = nullptr;
30 PassSimple::Sub *grid_lines_range_ps_ = nullptr;
31
32 ShapeInstanceBuf<ExtraInstanceData> cube_buf_ = {selection_type_, "cube_buf_"};
33
34 int dominant_axis = -1;
35
36 public:
37 Fluids(const SelectionType selection_type) : selection_type_(selection_type){};
38
39 void begin_sync(Resources &res, const State &state)
40 {
41 /* Against design. Should not sync depending on view. */
42 float3 camera_direction = View("WorkaroundView", DRW_view_default_get()).viewinv().z_axis();
43 dominant_axis = math::dominant_axis(camera_direction);
44
45 {
46 auto &pass = fluid_ps_;
47 pass.init();
49 state.clipping_plane_count);
50 res.select_bind(pass);
51
52 /* TODO(fclem): Use either specialization constants or push constants to reduce the amount of
53 * shader variants. */
54 velocity_needle_ps_ = &fluid_ps_.sub("Velocity Needles");
55 velocity_needle_ps_->shader_set(res.shaders.fluid_velocity_needle.get());
56
57 velocity_mac_ps_ = &fluid_ps_.sub("Velocity Mac");
58 velocity_mac_ps_->shader_set(res.shaders.fluid_velocity_mac.get());
59
60 velocity_streamline_ps_ = &fluid_ps_.sub("Velocity Line");
61 velocity_streamline_ps_->shader_set(res.shaders.fluid_velocity_streamline.get());
62
63 grid_lines_flags_ps_ = &fluid_ps_.sub("Velocity Mac");
64 grid_lines_flags_ps_->shader_set(res.shaders.fluid_grid_lines_flags.get());
65
66 grid_lines_flat_ps_ = &fluid_ps_.sub("Velocity Needles");
67 grid_lines_flat_ps_->shader_set(res.shaders.fluid_grid_lines_flat.get());
68
69 grid_lines_range_ps_ = &fluid_ps_.sub("Velocity Line");
70 grid_lines_range_ps_->shader_set(res.shaders.fluid_grid_lines_range.get());
71 }
72
73 cube_buf_.clear();
74 }
75
76 void object_sync(Manager &manager, const ObjectRef &ob_ref, Resources &res, const State &state)
77 {
78 Object *ob = ob_ref.object;
79
80 /* Do not show for dupli objects as the fluid is baked for the original object. */
82 return;
83 }
84
85 /* NOTE: There can only be one fluid modifier per object. */
87
88 if (md == nullptr) {
89 return;
90 }
91
93 FluidDomainSettings *fds = fmd->domain;
94
95 if (fds == nullptr) {
96 return;
97 }
98
99 const bool is_active_frame_after_cache_start = state.scene->r.cfra >= fds->cache_frame_start;
100 const bool is_active_frame_before_cache_end = state.scene->r.cfra >= fds->cache_frame_start;
101 const bool is_active_frame_in_cache_range = is_active_frame_after_cache_start &&
102 is_active_frame_before_cache_end;
103 if (!is_active_frame_in_cache_range) {
104 return;
105 }
106
107 ResourceHandle res_handle = manager.unique_handle(ob_ref);
108 select::ID sel_id = res.select_id(ob_ref);
109
110 /* Small cube showing voxel size. */
111 {
112 float3 min = float3(fds->p0) + float3(fds->cell_size) * float3(int3(fds->res_min));
113 float4x4 voxel_cube_mat = math::from_loc_scale<float4x4>(min, float3(fds->cell_size) / 2.0f);
114 /* Move small cube into the domain, otherwise its centered on corner of domain object. */
115 voxel_cube_mat = math::translate(voxel_cube_mat, float3(1.0f));
116 voxel_cube_mat = ob->object_to_world() * voxel_cube_mat;
117
118 const float4 &color = res.object_wire_color(ob_ref, state);
119 cube_buf_.append({voxel_cube_mat, color, 1.0f}, sel_id);
120 }
121
122 /* No volume data to display. */
123 if (fds->fluid == nullptr) {
124 return;
125 }
126
127 int slice_axis = slide_axis_get(*fds);
128
129 const bool draw_velocity = (fds->draw_velocity && is_active_frame_after_cache_start);
130 if (draw_velocity) {
131 int lines_per_voxel = -1;
132 PassSimple::Sub *sub_pass = nullptr;
133 switch (fds->vector_draw_type) {
134 default:
136 sub_pass = velocity_streamline_ps_;
137 lines_per_voxel = 1;
138 break;
140 sub_pass = velocity_needle_ps_;
141 lines_per_voxel = 6;
142 break;
143 case VECTOR_DRAW_MAC:
144 sub_pass = velocity_mac_ps_;
145 lines_per_voxel = 3;
146 break;
147 }
148
149 int total_lines = lines_per_voxel * math::reduce_mul(int3(fds->res));
150 if (slice_axis != -1) {
151 /* Remove the sliced dimension. */
152 total_lines /= fds->res[slice_axis];
153 }
154
156
157 PassSimple::Sub &sub = *sub_pass;
158 sub.bind_texture("velocityX", fds->tex_velocity_x);
159 sub.bind_texture("velocityY", fds->tex_velocity_y);
160 sub.bind_texture("velocityZ", fds->tex_velocity_z);
161 sub.push_constant("displaySize", fds->vector_scale);
162 sub.push_constant("slicePosition", fds->slice_depth);
163 sub.push_constant("cellSize", float3(fds->cell_size));
164 sub.push_constant("domainOriginOffset", float3(fds->p0));
165 sub.push_constant("adaptiveCellOffset", int3(fds->res_min));
166 sub.push_constant("sliceAxis", slice_axis);
167 sub.push_constant("scaleWithMagnitude", bool(fds->vector_scale_with_magnitude));
168 sub.push_constant("isCellCentered", (fds->vector_field == FLUID_DOMAIN_VECTOR_FIELD_FORCE));
169 if (fds->vector_draw_type == VECTOR_DRAW_MAC) {
173 }
174 sub.push_constant("in_select_id", int(sel_id.get()));
175 sub.draw_procedural(GPU_PRIM_LINES, 1, total_lines * 2, -1, res_handle);
176 }
177
178 /* Show gridlines only for slices with no interpolation. */
179 const bool show_gridlines = fds->show_gridlines &&
183 if (show_gridlines) {
184 PassSimple::Sub *sub_pass = nullptr;
185 switch (fds->gridlines_color_field) {
186 default:
189
190 sub_pass = grid_lines_flags_ps_;
191 sub_pass->bind_texture("flagTexture", fds->tex_flags);
192 break;
194 if (fds->use_coba && (fds->coba_field != FLUID_DOMAIN_FIELD_FLAGS)) {
197
198 sub_pass = grid_lines_range_ps_;
199 sub_pass->bind_texture("flagTexture", fds->tex_flags);
200 sub_pass->bind_texture("fieldTexture", fds->tex_range_field);
201 sub_pass->push_constant("lowerBound", fds->gridlines_lower_bound);
202 sub_pass->push_constant("upperBound", fds->gridlines_upper_bound);
203 sub_pass->push_constant("rangeColor", float4(fds->gridlines_range_color));
204 sub_pass->push_constant("cellFilter", int(fds->gridlines_cell_filter));
205 break;
206 }
207 /* Otherwise, fallback to none color type. */
210 sub_pass = grid_lines_flat_ps_;
211 break;
212 }
213
214 PassSimple::Sub &sub = *sub_pass;
215 sub.push_constant("volumeSize", int3(fds->res));
216 sub.push_constant("slicePosition", fds->slice_depth);
217 sub.push_constant("cellSize", float3(fds->cell_size));
218 sub.push_constant("domainOriginOffset", float3(fds->p0));
219 sub.push_constant("adaptiveCellOffset", int3(fds->res_min));
220 sub.push_constant("sliceAxis", slice_axis);
221 sub.push_constant("in_select_id", int(sel_id.get()));
222
223 BLI_assert(slice_axis != -1);
224 int lines_per_voxel = 4;
225 int total_lines = lines_per_voxel * math::reduce_mul(int3(fds->res)) / fds->res[slice_axis];
226 sub.draw_procedural(GPU_PRIM_LINES, 1, total_lines * 2, -1, res_handle);
227 }
228 }
229
230 void end_sync(Resources &res, ShapeCache &shapes, const State & /*state*/)
231 {
232 fluid_ps_.shader_set(res.shaders.extra_shape.get());
233 fluid_ps_.bind_ubo("globalsBlock", &res.globals_buf);
234
235 cube_buf_.end_sync(fluid_ps_, shapes.cube.get());
236 }
237
238 void draw(Framebuffer &framebuffer, Manager &manager, View &view)
239 {
240 GPU_framebuffer_bind(framebuffer);
241 manager.submit(fluid_ps_, view);
242 }
243
244 private:
245 /* Return axis index or -1 if no slice. */
246 int slide_axis_get(FluidDomainSettings &fluid_domain_settings) const
247 {
248 if (fluid_domain_settings.axis_slice_method != AXIS_SLICE_SINGLE) {
249 return -1;
250 }
251 if (fluid_domain_settings.slice_axis == SLICE_AXIS_AUTO) {
252 return dominant_axis;
253 }
254 return fluid_domain_settings.slice_axis - 1;
255 }
256};
257
258} // namespace blender::draw::overlay
ModifierData * BKE_modifiers_findby_type(const Object *ob, ModifierType type)
#define BLI_assert(a)
Definition BLI_assert.h:50
#define ATTR_FALLTHROUGH
@ AXIS_SLICE_SINGLE
@ FLUID_DOMAIN_FIELD_FLAGS
@ VECTOR_DRAW_MAC_X
@ VECTOR_DRAW_MAC_Y
@ VECTOR_DRAW_MAC_Z
@ FLUID_DISPLAY_INTERP_CLOSEST
@ SLICE_AXIS_AUTO
@ VECTOR_DRAW_NEEDLE
@ VECTOR_DRAW_STREAMLINE
@ VECTOR_DRAW_MAC
@ FLUID_GRIDLINE_COLOR_TYPE_FLAGS
@ FLUID_GRIDLINE_COLOR_TYPE_RANGE
@ FLUID_GRIDLINE_COLOR_TYPE_NONE
@ FLUID_DOMAIN_VECTOR_FIELD_FORCE
@ BASE_FROM_DUPLI
@ BASE_FROM_SET
@ eModifierType_Fluid
static void View(GHOST_IWindow *window, bool stereo, int eye=0)
void GPU_framebuffer_bind(GPUFrameBuffer *framebuffer)
@ GPU_PRIM_LINES
ResourceHandle unique_handle(const ObjectRef &ref)
void submit(PassSimple &pass, View &view)
void bind_texture(const char *name, GPUTexture *texture, GPUSamplerState state=sampler_auto)
void draw_procedural(GPUPrimType primitive, uint instance_len, uint vertex_len, uint vertex_first=-1, ResourceHandle handle={0}, uint custom_id=0)
Definition draw_pass.hh:833
PassBase< DrawCommandBufType > & sub(const char *name)
Definition draw_pass.hh:616
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
void object_sync(Manager &manager, const ObjectRef &ob_ref, Resources &res, const State &state)
void draw(Framebuffer &framebuffer, Manager &manager, View &view)
Fluids(const SelectionType selection_type)
void end_sync(Resources &res, ShapeCache &shapes, const State &)
void begin_sync(Resources &res, const State &state)
void DRW_fluid_ensure_flags(FluidModifierData *fmd)
void DRW_fluid_ensure_range_field(FluidModifierData *fmd)
void DRW_smoke_ensure_velocity(FluidModifierData *fmd)
const DRWView * DRW_view_default_get()
@ 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]
MatT from_loc_scale(const typename MatT::loc_type &location, const VecBase< typename MatT::base_type, ScaleDim > &scale)
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)
VecBase< float, 4 > float4
VecBase< int32_t, 3 > int3
VecBase< float, 3 > float3
#define min(a, b)
Definition sort.c:32
struct GPUTexture * tex_range_field
struct GPUTexture * tex_velocity_x
struct GPUTexture * tex_velocity_y
struct GPUTexture * tex_velocity_z
struct GPUTexture * tex_flags
struct FluidDomainSettings * domain
short base_flag
const float4 & object_wire_color(const ObjectRef &ob_ref, ThemeColorID theme_id) const
void end_sync(PassSimple::Sub &pass, gpu::Batch *shape)
void append(const InstanceDataT &data, select::ID select_id)
void select_bind(PassSimple &pass)
const ID select_id(const ObjectRef &ob_ref, uint sub_object_id=0)