Blender V4.5
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
5#include "draw_cache.hh"
6#include "draw_common_c.hh"
7
9
10#include "BKE_volume.hh"
11#include "BKE_volume_render.hh"
12#include "BLI_math_geom.h"
13#include "BLI_rand.h"
14#include "DNA_fluid_types.h"
15#include "DNA_modifier_types.h"
16
17namespace blender::workbench {
18
20{
21 active_ = false;
22 ps_.init();
23 ps_.bind_ubo(WB_WORLD_SLOT, resources.world_buf);
24
25 dummy_shadow_tx_.ensure_3d(GPU_RGBA8, int3(1), GPU_TEXTURE_USAGE_SHADER_READ, float4(1));
26 dummy_volume_tx_.ensure_3d(GPU_RGBA8, int3(1), GPU_TEXTURE_USAGE_SHADER_READ, float4(0));
27 dummy_coba_tx_.ensure_1d(GPU_RGBA8, 1, GPU_TEXTURE_USAGE_SHADER_READ, float4(0));
28}
29
31 SceneResources &resources,
32 const SceneState &scene_state,
33 ObjectRef &ob_ref,
35{
36 Object *ob = ob_ref.object;
37 /* Create 3D textures. */
39 BKE_volume_load(&volume, G.main);
40 const bke::VolumeGridData *volume_grid = BKE_volume_grid_active_get_for_read(&volume);
41 if (volume_grid == nullptr) {
42 return;
43 }
44
45 DRWVolumeGrid *grid = DRW_volume_batch_cache_get_grid(&volume, volume_grid);
46 if (grid == nullptr) {
47 return;
48 }
49
50 active_ = true;
51
52 PassMain::Sub &sub_ps = ps_.sub("Volume Object SubPass");
53
54 const bool use_slice = (volume.display.axis_slice_method == AXIS_SLICE_SINGLE);
55
56 sub_ps.shader_set(
57 ShaderCache::get().volume_get(false, volume.display.interpolation_method, false, use_slice));
58 sub_ps.push_constant("do_depth_test", scene_state.shading.type >= OB_SOLID);
59
60 const float density_fac = volume.display.density *
61 BKE_volume_density_scale(&volume, ob->object_to_world().ptr());
62
63 sub_ps.bind_texture("depth_buffer", &resources.depth_tx);
64 sub_ps.bind_texture("stencil_tx", &stencil_tx_);
65 sub_ps.bind_texture("density_tx", grid->texture);
66 /* TODO: implement shadow texture, see manta_smoke_calc_transparency. */
67 sub_ps.bind_texture("shadow_tx", dummy_shadow_tx_);
68 sub_ps.push_constant("active_color", color);
69 sub_ps.push_constant("density_fac", density_fac);
70 sub_ps.push_constant("volume_object_to_texture", float4x4(grid->object_to_texture));
71 sub_ps.push_constant("volume_texture_to_object", float4x4(grid->texture_to_object));
72
73 if (use_slice) {
74 draw_slice_ps(
75 manager, resources, sub_ps, ob_ref, volume.display.slice_axis, volume.display.slice_depth);
76 }
77 else {
78 float4x4 texture_to_world = ob->object_to_world() * float4x4(grid->texture_to_object);
79 float3 world_size = math::to_scale(texture_to_world);
80
81 int3 resolution;
82 GPU_texture_get_mipmap_size(grid->texture, 0, resolution);
83 float3 slice_count = float3(resolution) * 5.0f;
84
85 draw_volume_ps(
86 manager, resources, sub_ps, ob_ref, scene_state.sample, slice_count, world_size);
87 }
88}
89
91 SceneResources &resources,
92 const SceneState &scene_state,
93 ObjectRef &ob_ref,
94 ModifierData *md)
95{
96 Object *ob = ob_ref.object;
97
98 FluidModifierData *modifier = reinterpret_cast<FluidModifierData *>(md);
99 FluidDomainSettings &settings = *modifier->domain;
100
101 if (!settings.fluid) {
102 return;
103 }
104
105 bool can_load = false;
106 if (settings.use_coba) {
108 can_load = settings.tex_field != nullptr;
109 }
110 else if (settings.type == FLUID_DOMAIN_TYPE_GAS) {
112 can_load = settings.tex_density != nullptr || settings.tex_color != nullptr;
113 }
114
115 if (!can_load) {
116 return;
117 }
118
119 active_ = true;
120
121 PassMain::Sub &sub_ps = ps_.sub("Volume Modifier SubPass");
122
123 const bool use_slice = settings.axis_slice_method == AXIS_SLICE_SINGLE;
124
125 sub_ps.shader_set(
126 ShaderCache::get().volume_get(true, settings.interp_method, settings.use_coba, use_slice));
127 sub_ps.push_constant("do_depth_test", scene_state.shading.type >= OB_SOLID);
128
129 if (settings.use_coba) {
130 const bool show_flags = settings.coba_field == FLUID_DOMAIN_FIELD_FLAGS;
131 const bool show_pressure = settings.coba_field == FLUID_DOMAIN_FIELD_PRESSURE;
132 const bool show_phi = ELEM(settings.coba_field,
137
138 sub_ps.push_constant("show_flags", show_flags);
139 sub_ps.push_constant("show_pressure", show_pressure);
140 sub_ps.push_constant("show_phi", show_phi);
141 sub_ps.push_constant("grid_scale", settings.grid_scale);
142
143 if (show_flags) {
144 sub_ps.bind_texture("flag_tx", settings.tex_field);
145 }
146 else {
147 sub_ps.bind_texture("density_tx", settings.tex_field);
148 }
149
150 if (!show_flags && !show_pressure && !show_phi) {
151 sub_ps.bind_texture("transfer_tx", settings.tex_coba);
152 }
153 }
154 else {
155 bool use_constant_color = ((settings.active_fields & FLUID_DOMAIN_ACTIVE_COLORS) == 0 &&
157
158 sub_ps.push_constant("active_color",
159 use_constant_color ? float3(settings.active_color) : float3(1));
160
161 sub_ps.bind_texture("density_tx",
162 settings.tex_color ? settings.tex_color : settings.tex_density);
163 sub_ps.bind_texture("flame_tx", settings.tex_flame ? settings.tex_flame : dummy_volume_tx_);
164 sub_ps.bind_texture("flame_color_tx",
165 settings.tex_flame ? settings.tex_flame_coba : dummy_coba_tx_);
166 sub_ps.bind_texture("shadow_tx", settings.tex_shadow);
167 }
168
169 sub_ps.push_constant("density_fac", 10.0f * settings.display_thickness);
170 sub_ps.bind_texture("depth_buffer", &resources.depth_tx);
171 sub_ps.bind_texture("stencil_tx", &stencil_tx_);
172
173 if (use_slice) {
174 draw_slice_ps(manager, resources, sub_ps, ob_ref, settings.slice_axis, settings.slice_depth);
175 }
176 else {
177 float3 world_size;
178 BKE_object_dimensions_get(ob, world_size);
179
180 float3 slice_count = float3(settings.res) * std::max(0.001f, settings.slice_per_voxel);
181
182 draw_volume_ps(
183 manager, resources, sub_ps, ob_ref, scene_state.sample, slice_count, world_size);
184 }
185}
186
187void VolumePass::draw(Manager &manager, View &view, SceneResources &resources)
188{
189 if (!active_) {
190 return;
191 }
192
193 stencil_tx_ = resources.depth_tx.ptr()->stencil_view();
194
196 fb_.bind();
197 manager.submit(ps_, view);
198}
199
200void VolumePass::draw_slice_ps(Manager &manager,
201 SceneResources &resources,
202 PassMain::Sub &ps,
203 ObjectRef &ob_ref,
204 int slice_axis_enum,
205 float slice_depth)
206{
208
209 const int axis = (slice_axis_enum == SLICE_AXIS_AUTO) ?
210 axis_dominant_v3_single(view_mat_inv[2]) :
211 slice_axis_enum - 1;
212
213 float3 dimensions;
214 BKE_object_dimensions_get(ob_ref.object, dimensions);
215 /* 0.05f to achieve somewhat the same opacity as the full view. */
216 float step_length = std::max(1e-16f, dimensions[axis] * 0.05f);
217
219 ps.push_constant("slice_position", slice_depth);
220 ps.push_constant("slice_axis", axis);
221 ps.push_constant("step_length", step_length);
222
223 ps.draw(resources.volume_cube_batch, manager.resource_handle(ob_ref));
224}
225
226void VolumePass::draw_volume_ps(Manager &manager,
227 SceneResources &resources,
228 PassMain::Sub &ps,
229 ObjectRef &ob_ref,
230 int taa_sample,
231 float3 slice_count,
232 float3 world_size)
233{
234 double noise_offset;
235 BLI_halton_1d(3, 0.0, taa_sample, &noise_offset);
236
237 int max_slice = std::max({UNPACK3(slice_count)});
238 float step_length = math::length((1.0f / slice_count) * world_size);
239
241 ps.push_constant("samples_len", max_slice);
242 ps.push_constant("step_length", step_length);
243 ps.push_constant("noise_ofs", float(noise_offset));
244
245 ps.draw(resources.volume_cube_batch, manager.resource_handle(ob_ref));
246}
247
248} // namespace blender::workbench
void BKE_object_dimensions_get(const 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:226
#define UNPACK3(a)
#define ELEM(...)
@ FLUID_DOMAIN_USE_NOISE
@ FLUID_DOMAIN_TYPE_GAS
@ 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_ACTIVE_COLORS
@ FLUID_DOMAIN_ACTIVE_COLOR_SET
@ SLICE_AXIS_AUTO
@ OB_SOLID
static AppView * view
#define GPU_ATTACHMENT_TEXTURE(_texture)
#define GPU_ATTACHMENT_NONE
@ GPU_TEXTURE_USAGE_SHADER_READ
@ GPU_RGBA8
void GPU_texture_get_mipmap_size(GPUTexture *texture, int mip_level, int *r_size)
void submit(PassSimple &pass, View &view)
ResourceHandleRange resource_handle(const ObjectRef &ref, float inflate_bounds=0.0f)
GPUTexture * stencil_view(bool cube_as_array=false)
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, GPUTexture *texture, GPUSamplerState state=sampler_auto)
void draw(gpu::Batch *batch, uint instance_len=-1, uint vertex_len=-1, uint vertex_first=-1, ResourceHandleRange handle={0}, uint custom_id=0)
Definition draw_pass.hh:884
void state_set(DRWState state, int clip_plane_count=0)
void push_constant(const char *name, const float &data)
void shader_set(GPUShader *shader)
detail::PassBase< command::DrawMultiBuf > Sub
Definition draw_pass.hh:490
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)
void DRW_smoke_ensure_coba_field(FluidModifierData *fmd)
void DRW_smoke_ensure(FluidModifierData *fmd, int highres)
Mesh & DRW_object_get_data_for_drawing(const Object &object)
@ 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
#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
struct GPUTexture * tex_density
struct GPUTexture * tex_color
struct GPUTexture * tex_field
struct GPUTexture * tex_shadow
struct GPUTexture * tex_coba
struct GPUTexture * tex_flame
struct GPUTexture * tex_flame_coba
VolumeDisplay display
UniformBuffer< WorldData > world_buf
#define WB_WORLD_SLOT