Blender V5.0
draw_volume.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2022 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
10
11#include "DRW_gpu_wrapper.hh"
12#include "DRW_render.hh"
13
14#include "DNA_fluid_types.h"
15#include "DNA_volume_types.h"
16
17#include "BLI_string.h"
18
19#include "BKE_global.hh"
20#include "BKE_mesh.hh"
21#include "BKE_modifier.hh"
22#include "BKE_volume.hh"
23#include "BKE_volume_render.hh"
24
25#include "GPU_material.hh"
26
27#include "draw_cache.hh"
28#include "draw_common_c.hh"
30
31#include "draw_common.hh"
32
33namespace blender::draw {
34
36
40
42 {
43 for (VolumeInfosBuf *ubo : ubos) {
44 delete ubo;
45 }
46 }
47
48 void reset()
49 {
50 used = 0;
51 }
52
54 {
55 if (used >= ubos.size()) {
56 VolumeInfosBuf *buf = new VolumeInfosBuf();
57 ubos.append(buf);
58 }
59 return ubos[used++];
60 }
61};
62
65
68
70 {
71 const float zero[4] = {0.0f, 0.0f, 0.0f, 0.0f};
72 const float one[4] = {1.0f, 1.0f, 1.0f, 1.0f};
74 dummy_zero.ensure_3d(blender::gpu::TextureFormat::SFLOAT_32_32_32_32, int3(1), usage, zero);
75 dummy_one.ensure_3d(blender::gpu::TextureFormat::SFLOAT_32_32_32_32, int3(1), usage, one);
78 }
79
81 {
82 switch (default_value) {
83 case GPU_DEFAULT_0:
84 return dummy_zero;
85 case GPU_DEFAULT_1:
86 return dummy_one;
87 }
88 return dummy_zero;
89 }
90};
91
92void DRW_volume_init(DRWData *drw_data)
93{
94 if (drw_data == nullptr) {
95 drw_data = drw_get().data;
96 }
97 if (drw_data->volume_module == nullptr) {
98 drw_data->volume_module = MEM_new<VolumeModule>("VolumeModule");
99 }
100 drw_data->volume_module->ubo_pool.reset();
101}
102
104{
105 MEM_delete(module);
106}
107
108/* -------------------------------------------------------------------- */
111
112template<typename PassType>
114{
116
117 PassType *sub = &ps.sub("World Volume");
118 for (const GPUMaterialAttribute *attr : attrs) {
119 sub->bind_texture(attr->input_name, module.grid_default_texture(attr->default_value));
120 }
121
122 return sub;
123}
124
125template<typename PassType>
127 Object *ob,
129{
131 BKE_volume_load(&volume, G.main);
132
133 /* Render nothing if there is no attribute. */
134 if (BKE_volume_num_grids(&volume) == 0) {
135 return nullptr;
136 }
137
139 VolumeInfosBuf &volume_infos = *module.ubo_pool.alloc();
140
141 volume_infos.density_scale = BKE_volume_density_scale(&volume, ob->object_to_world().ptr());
142 volume_infos.color_mul = float4(1.0f);
143 volume_infos.temperature_mul = 1.0f;
144 volume_infos.temperature_bias = 0.0f;
145
146 PassType *sub = &ps.sub("Volume Object SubPass");
147
148 /* Bind volume grid textures. */
149 int grid_id = 0;
150 for (const GPUMaterialAttribute *attr : attrs) {
151 const bke::VolumeGridData *volume_grid = BKE_volume_grid_find(&volume, attr->name);
152 const DRWVolumeGrid *drw_grid = (volume_grid) ?
153 DRW_volume_batch_cache_get_grid(&volume, volume_grid) :
154 nullptr;
155 /* Handle 3 cases here:
156 * - Grid exists and texture was loaded -> use texture.
157 * - Grid exists but has zero size or failed to load -> use zero.
158 * - Grid does not exist -> use default value. */
159 const gpu::Texture *grid_tex = (drw_grid) ? drw_grid->texture :
160 (volume_grid) ?
161 module.dummy_zero :
162 module.grid_default_texture(attr->default_value);
163 /* TODO(@pragma37): bind_texture const support ? */
164 sub->bind_texture(attr->input_name, (gpu::Texture *)grid_tex);
165
166 volume_infos.grids_xform[grid_id++] = drw_grid ? float4x4(drw_grid->object_to_texture) :
168 }
169
170 volume_infos.push_update();
171
172 sub->bind_ubo("drw_volume", volume_infos);
173
174 return sub;
175}
176
177template<typename PassType>
179 Scene *scene,
180 Object *ob,
182{
184 VolumeInfosBuf &volume_infos = *module.ubo_pool.alloc();
185
186 ModifierData *md = nullptr;
187
188 volume_infos.density_scale = 1.0f;
189 volume_infos.color_mul = float4(1.0f);
190 volume_infos.temperature_mul = 1.0f;
191 volume_infos.temperature_bias = 0.0f;
192
193 bool has_fluid_modifier = (md = BKE_modifiers_findby_type(ob, eModifierType_Fluid)) &&
195 ((FluidModifierData *)md)->domain != nullptr;
196 FluidModifierData *fmd = has_fluid_modifier ? (FluidModifierData *)md : nullptr;
197 FluidDomainSettings *fds = has_fluid_modifier ? fmd->domain : nullptr;
198
199 PassType *sub = nullptr;
200
201 if (!has_fluid_modifier || (fds->type != FLUID_DOMAIN_TYPE_GAS)) {
202 /* No volume attributes or fluid domain. */
203 sub = &ps.sub("Volume Mesh SubPass");
204 int grid_id = 0;
205 for (const GPUMaterialAttribute *attr : attrs) {
206 sub->bind_texture(attr->input_name, module.grid_default_texture(attr->default_value));
207 volume_infos.grids_xform[grid_id++] = float4x4::identity();
208 }
209 }
210 else if (fds->fluid) {
211 /* Smoke Simulation. */
213
214 sub = &ps.sub("Volume Modifier SubPass");
215
216 float3 location, scale;
218 float3 orco_mul = math::safe_rcp(scale * 2.0);
219 float3 orco_add = (location - scale) * -orco_mul;
220 /* Replace OrcoTexCoFactors with a matrix multiplication. */
221 float4x4 orco_mat = math::from_scale<float4x4>(orco_mul);
222 orco_mat.location() = orco_add;
223
224 int grid_id = 0;
225 for (const GPUMaterialAttribute *attr : attrs) {
226 if (STREQ(attr->name, "density")) {
227 sub->bind_texture(attr->input_name,
228 fds->tex_density ? &fds->tex_density : &module.dummy_one);
229 }
230 else if (STREQ(attr->name, "color")) {
231 sub->bind_texture(attr->input_name, fds->tex_color ? &fds->tex_color : &module.dummy_one);
232 }
233 else if (STR_ELEM(attr->name, "flame", "temperature")) {
234 sub->bind_texture(attr->input_name, fds->tex_flame ? &fds->tex_flame : &module.dummy_zero);
235 }
236 else {
237 sub->bind_texture(attr->input_name, module.grid_default_texture(attr->default_value));
238 }
239 volume_infos.grids_xform[grid_id++] = orco_mat;
240 }
241
242 bool use_constant_color = ((fds->active_fields & FLUID_DOMAIN_ACTIVE_COLORS) == 0 &&
244 if (use_constant_color) {
245 volume_infos.color_mul = float4(UNPACK3(fds->active_color), 1.0f);
246 }
247
248 /* Output is such that 0..1 maps to 0..1000K. */
249 volume_infos.temperature_mul = fds->flame_max_temp - fds->flame_ignition;
250 volume_infos.temperature_bias = fds->flame_ignition;
251 }
252
253 if (sub) {
254 volume_infos.push_update();
255 sub->bind_ubo("drw_volume", volume_infos);
256 }
257
258 return sub;
259}
260
261template<typename PassType>
263 Scene *scene,
264 Object *ob,
265 GPUMaterial *gpu_material)
266{
267 ListBase attr_list = GPU_material_attributes(gpu_material);
269 if (ob == nullptr) {
270 return volume_world_grids_init(ps, attrs);
271 }
272 if (ob->type == OB_VOLUME) {
273 return volume_object_grids_init(ps, ob, attrs);
274 }
275 return drw_volume_object_mesh_init(ps, scene, ob, attrs);
276}
277
279 Scene *scene,
280 Object *ob,
281 GPUMaterial *gpu_material)
282{
283 return volume_sub_pass_implementation(ps, scene, ob, gpu_material);
284}
285
287 Scene *scene,
288 Object *ob,
289 GPUMaterial *gpu_material)
290{
291 return volume_sub_pass_implementation(ps, scene, ob, gpu_material);
292}
293
295
296} // namespace blender::draw
void BKE_mesh_texspace_get(Mesh *mesh, float r_texspace_location[3], float r_texspace_size[3])
bool BKE_modifier_is_enabled(const Scene *scene, ModifierData *md, int required_mode)
ModifierData * BKE_modifiers_findby_type(const Object *ob, ModifierType type)
Volume data-block.
int BKE_volume_num_grids(const Volume *volume)
bool BKE_volume_load(const Volume *volume, const Main *bmain)
const blender::bke::VolumeGridData * BKE_volume_grid_find(const Volume *volume, blender::StringRef name)
Volume data-block rendering and viewport drawing utilities.
float BKE_volume_density_scale(const Volume *volume, const float matrix[4][4])
#define STR_ELEM(...)
Definition BLI_string.h:661
unsigned int uint
#define UNPACK3(a)
#define STREQ(a, b)
@ FLUID_DOMAIN_TYPE_GAS
@ FLUID_DOMAIN_ACTIVE_COLORS
@ FLUID_DOMAIN_ACTIVE_COLOR_SET
@ FLUID_DOMAIN_USE_NOISE
@ eModifierMode_Realtime
@ eModifierType_Fluid
@ OB_VOLUME
T & DRW_object_get_data_for_drawing(const Object &object)
GPUDefaultValue
@ GPU_DEFAULT_1
@ GPU_DEFAULT_0
ListBase GPU_material_attributes(const GPUMaterial *material)
void GPU_texture_extend_mode(blender::gpu::Texture *texture, GPUSamplerExtendMode extend_mode)
eGPUTextureUsage
@ GPU_TEXTURE_USAGE_SHADER_READ
@ GPU_SAMPLER_EXTEND_MODE_REPEAT
detail::PassBase< command::DrawMultiBuf > Sub
Definition draw_pass.hh:499
void DRW_smoke_ensure(FluidModifierData *fmd, int highres)
DRWContext & drw_get()
PassType
#define G(x, y, z)
PassMain::Sub * volume_sub_pass(PassMain::Sub &ps, Scene *scene, Object *ob, GPUMaterial *gpu_material)
PassType * volume_object_grids_init(PassType &ps, Object *ob, ListBaseWrapper< GPUMaterialAttribute > &attrs)
blender::draw::UniformBuffer< VolumeInfos > VolumeInfosBuf
PassType * volume_world_grids_init(PassType &ps, ListBaseWrapper< GPUMaterialAttribute > &attrs)
PassType * volume_sub_pass_implementation(PassType &ps, Scene *scene, Object *ob, GPUMaterial *gpu_material)
void DRW_volume_init(DRWData *drw_data=nullptr)
PassType * drw_volume_object_mesh_init(PassType &ps, Scene *scene, Object *ob, ListBaseWrapper< GPUMaterialAttribute > &attrs)
DRWVolumeGrid * DRW_volume_batch_cache_get_grid(Volume *volume, const bke::VolumeGridData *volume_grid)
void DRW_volume_module_free(draw::VolumeModule *module)
T safe_rcp(const T &a)
MatBase< T, NumCol, NumRow > scale(const MatBase< T, NumCol, NumRow > &mat, const VectorT &scale)
MatT from_scale(const VecBase< typename MatT::base_type, ScaleDim > &scale)
MatBase< float, 4, 4 > float4x4
VecBase< float, 4 > float4
VecBase< int32_t, 3 > int3
ListBaseWrapperTemplate< ListBase, T > ListBaseWrapper
VecBase< float, 3 > float3
static struct PyModuleDef module
Definition python.cpp:796
DRWData * data
blender::draw::VolumeModule * volume_module
struct FluidDomainSettings * domain
ustring name
Definition graph/node.h:177
float4x4 grids_xform[DRW_GRID_PER_VOLUME_MAX]
gpu::Texture * grid_default_texture(GPUDefaultValue default_value)
VolumeUniformBufPool ubo_pool
Vector< VolumeInfosBuf * > ubos