Blender V4.5
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(GPU_RGBA32F, int3(1), usage, zero);
75 dummy_one.ensure_3d(GPU_RGBA32F, int3(1), usage, one);
78 }
79
80 GPUTexture *grid_default_texture(eGPUDefaultValue default_value)
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 GPUTexture *grid_tex = (drw_grid) ? drw_grid->texture :
160 (volume_grid) ? module.dummy_zero :
161 module.grid_default_texture(attr->default_value);
162 /* TODO(@pragma37): bind_texture const support ? */
163 sub->bind_texture(attr->input_name, (GPUTexture *)grid_tex);
164
165 volume_infos.grids_xform[grid_id++] = drw_grid ? float4x4(drw_grid->object_to_texture) :
167 }
168
169 volume_infos.push_update();
170
171 sub->bind_ubo("drw_volume", volume_infos);
172
173 return sub;
174}
175
176template<typename PassType>
178 Scene *scene,
179 Object *ob,
181{
183 VolumeInfosBuf &volume_infos = *module.ubo_pool.alloc();
184
185 ModifierData *md = nullptr;
186
187 volume_infos.density_scale = 1.0f;
188 volume_infos.color_mul = float4(1.0f);
189 volume_infos.temperature_mul = 1.0f;
190 volume_infos.temperature_bias = 0.0f;
191
192 bool has_fluid_modifier = (md = BKE_modifiers_findby_type(ob, eModifierType_Fluid)) &&
194 ((FluidModifierData *)md)->domain != nullptr;
195 FluidModifierData *fmd = has_fluid_modifier ? (FluidModifierData *)md : nullptr;
196 FluidDomainSettings *fds = has_fluid_modifier ? fmd->domain : nullptr;
197
198 PassType *sub = nullptr;
199
200 if (!has_fluid_modifier || (fds->type != FLUID_DOMAIN_TYPE_GAS)) {
201 /* No volume attributes or fluid domain. */
202 sub = &ps.sub("Volume Mesh SubPass");
203 int grid_id = 0;
204 for (const GPUMaterialAttribute *attr : attrs) {
205 sub->bind_texture(attr->input_name, module.grid_default_texture(attr->default_value));
206 volume_infos.grids_xform[grid_id++] = float4x4::identity();
207 }
208 }
209 else if (fds->fluid) {
210 /* Smoke Simulation. */
212
213 sub = &ps.sub("Volume Modifier SubPass");
214
215 float3 location, scale;
217 float3 orco_mul = math::safe_rcp(scale * 2.0);
218 float3 orco_add = (location - scale) * -orco_mul;
219 /* Replace OrcoTexCoFactors with a matrix multiplication. */
220 float4x4 orco_mat = math::from_scale<float4x4>(orco_mul);
221 orco_mat.location() = orco_add;
222
223 int grid_id = 0;
224 for (const GPUMaterialAttribute *attr : attrs) {
225 if (STREQ(attr->name, "density")) {
226 sub->bind_texture(attr->input_name,
227 fds->tex_density ? &fds->tex_density : &module.dummy_one);
228 }
229 else if (STREQ(attr->name, "color")) {
230 sub->bind_texture(attr->input_name, fds->tex_color ? &fds->tex_color : &module.dummy_one);
231 }
232 else if (STR_ELEM(attr->name, "flame", "temperature")) {
233 sub->bind_texture(attr->input_name, fds->tex_flame ? &fds->tex_flame : &module.dummy_zero);
234 }
235 else {
236 sub->bind_texture(attr->input_name, module.grid_default_texture(attr->default_value));
237 }
238 volume_infos.grids_xform[grid_id++] = orco_mat;
239 }
240
241 bool use_constant_color = ((fds->active_fields & FLUID_DOMAIN_ACTIVE_COLORS) == 0 &&
243 if (use_constant_color) {
244 volume_infos.color_mul = float4(UNPACK3(fds->active_color), 1.0f);
245 }
246
247 /* Output is such that 0..1 maps to 0..1000K. */
248 volume_infos.temperature_mul = fds->flame_max_temp - fds->flame_ignition;
249 volume_infos.temperature_bias = fds->flame_ignition;
250 }
251
252 if (sub) {
253 volume_infos.push_update();
254 sub->bind_ubo("drw_volume", volume_infos);
255 }
256
257 return sub;
258}
259
260template<typename PassType>
262 Scene *scene,
263 Object *ob,
264 GPUMaterial *gpu_material)
265{
266 ListBase attr_list = GPU_material_attributes(gpu_material);
268 if (ob == nullptr) {
269 return volume_world_grids_init(ps, attrs);
270 }
271 if (ob->type == OB_VOLUME) {
272 return volume_object_grids_init(ps, ob, attrs);
273 }
274 return drw_volume_object_mesh_init(ps, scene, ob, attrs);
275}
276
278 Scene *scene,
279 Object *ob,
280 GPUMaterial *gpu_material)
281{
282 return volume_sub_pass_implementation(ps, scene, ob, gpu_material);
283}
284
286 Scene *scene,
287 Object *ob,
288 GPUMaterial *gpu_material)
289{
290 return volume_sub_pass_implementation(ps, scene, ob, gpu_material);
291}
292
294
295} // 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:656
unsigned int uint
#define UNPACK3(a)
#define STREQ(a, b)
@ FLUID_DOMAIN_USE_NOISE
@ FLUID_DOMAIN_TYPE_GAS
@ FLUID_DOMAIN_ACTIVE_COLORS
@ FLUID_DOMAIN_ACTIVE_COLOR_SET
@ eModifierMode_Realtime
@ eModifierType_Fluid
@ OB_VOLUME
eGPUDefaultValue
@ GPU_DEFAULT_1
@ GPU_DEFAULT_0
ListBase GPU_material_attributes(const GPUMaterial *material)
void GPU_texture_extend_mode(GPUTexture *texture, GPUSamplerExtendMode extend_mode)
eGPUTextureUsage
@ GPU_TEXTURE_USAGE_SHADER_READ
@ GPU_SAMPLER_EXTEND_MODE_REPEAT
@ GPU_RGBA32F
detail::PassBase< command::DrawMultiBuf > Sub
Definition draw_pass.hh:490
void DRW_smoke_ensure(FluidModifierData *fmd, int highres)
Mesh & DRW_object_get_data_for_drawing(const Object &object)
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 GPUTexture * tex_density
struct GPUTexture * tex_color
struct GPUTexture * tex_flame
struct FluidDomainSettings * domain
ustring name
Definition graph/node.h:177
float4x4 grids_xform[DRW_GRID_PER_VOLUME_MAX]
GPUTexture * grid_default_texture(eGPUDefaultValue default_value)
VolumeUniformBufPool ubo_pool
Vector< VolumeInfosBuf * > ubos