Blender  V2.93
workbench_volume.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * Copyright 2018, Blender Foundation.
17  */
18 
23 #include "workbench_private.h"
24 
25 #include "DNA_fluid_types.h"
26 #include "DNA_modifier_types.h"
27 #include "DNA_object_force_types.h"
28 #include "DNA_volume_types.h"
29 
30 #include "BLI_dynstr.h"
31 #include "BLI_listbase.h"
32 #include "BLI_rand.h"
33 #include "BLI_string_utils.h"
34 
35 #include "BKE_fluid.h"
36 #include "BKE_global.h"
37 #include "BKE_object.h"
38 #include "BKE_volume.h"
39 #include "BKE_volume_render.h"
40 
42 {
43  WORKBENCH_TextureList *txl = vedata->txl;
44 
45  if (txl->dummy_volume_tx == NULL) {
46  const float zero[4] = {0.0f, 0.0f, 0.0f, 0.0f};
47  const float one[4] = {1.0f, 1.0f, 1.0f, 1.0f};
49  "dummy_volume", 1, 1, 1, 1, GPU_RGBA8, GPU_DATA_FLOAT, zero);
51  "dummy_shadow", 1, 1, 1, 1, GPU_RGBA8, GPU_DATA_FLOAT, one);
52  txl->dummy_coba_tx = GPU_texture_create_1d("dummy_coba", 1, 1, GPU_RGBA8, zero);
53  }
54 }
55 
57 {
58  vedata->psl->volume_ps = DRW_pass_create(
60 
61  vedata->stl->wpd->volumes_do = false;
62 }
63 
65  Object *ob,
66  ModifierData *md)
67 {
69  FluidDomainSettings *fds = fmd->domain;
70  WORKBENCH_PrivateData *wpd = vedata->stl->wpd;
71  WORKBENCH_TextureList *txl = vedata->txl;
73  DRWShadingGroup *grp = NULL;
74 
75  if (!fds->fluid) {
76  return;
77  }
78 
79  wpd->volumes_do = true;
80  if (fds->use_coba) {
82  }
83  else if (fds->type == FLUID_DOMAIN_TYPE_GAS) {
85  }
86  else {
87  return;
88  }
89 
90  if ((!fds->use_coba && (fds->tex_density == NULL && fds->tex_color == NULL)) ||
91  (fds->use_coba && fds->tex_field == NULL)) {
92  return;
93  }
94 
95  const bool use_slice = (fds->axis_slice_method == AXIS_SLICE_SINGLE);
96  const bool show_phi = ELEM(fds->coba_field,
101  const bool show_flags = (fds->coba_field == FLUID_DOMAIN_FIELD_FLAGS);
102  const bool show_pressure = (fds->coba_field == FLUID_DOMAIN_FIELD_PRESSURE);
104 
107  interp_type = WORKBENCH_VOLUME_INTERP_LINEAR;
108  break;
110  interp_type = WORKBENCH_VOLUME_INTERP_CUBIC;
111  break;
113  interp_type = WORKBENCH_VOLUME_INTERP_CLOSEST;
114  break;
115  }
116 
117  GPUShader *sh = workbench_shader_volume_get(use_slice, fds->use_coba, interp_type, true);
118 
119  if (use_slice) {
120  float invviewmat[4][4];
121  DRW_view_viewmat_get(NULL, invviewmat, true);
122 
123  const int axis = (fds->slice_axis == SLICE_AXIS_AUTO) ?
124  axis_dominant_v3_single(invviewmat[2]) :
125  fds->slice_axis - 1;
126  float dim[3];
127  BKE_object_dimensions_get(ob, dim);
128  /* 0.05f to achieve somewhat the same opacity as the full view. */
129  float step_length = max_ff(1e-16f, dim[axis] * 0.05f);
130 
131  grp = DRW_shgroup_create(sh, vedata->psl->volume_ps);
132  DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo);
133  DRW_shgroup_uniform_float_copy(grp, "slicePosition", fds->slice_depth);
134  DRW_shgroup_uniform_int_copy(grp, "sliceAxis", axis);
135  DRW_shgroup_uniform_float_copy(grp, "stepLength", step_length);
137  }
138  else {
139  double noise_ofs;
140  BLI_halton_1d(3, 0.0, wpd->taa_sample, &noise_ofs);
141  float dim[3], step_length, max_slice;
142  float slice_ct[3] = {fds->res[0], fds->res[1], fds->res[2]};
143  mul_v3_fl(slice_ct, max_ff(0.001f, fds->slice_per_voxel));
144  max_slice = max_fff(slice_ct[0], slice_ct[1], slice_ct[2]);
145  BKE_object_dimensions_get(ob, dim);
146  invert_v3(slice_ct);
147  mul_v3_v3(dim, slice_ct);
148  step_length = len_v3(dim);
149 
150  grp = DRW_shgroup_create(sh, vedata->psl->volume_ps);
151  DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo);
152  DRW_shgroup_uniform_int_copy(grp, "samplesLen", max_slice);
153  DRW_shgroup_uniform_float_copy(grp, "stepLength", step_length);
154  DRW_shgroup_uniform_float_copy(grp, "noiseOfs", noise_ofs);
156  }
157 
158  if (fds->use_coba) {
159  if (show_flags) {
160  DRW_shgroup_uniform_texture(grp, "flagTexture", fds->tex_field);
161  }
162  else {
163  DRW_shgroup_uniform_texture(grp, "densityTexture", fds->tex_field);
164  }
165  if (!show_phi && !show_flags && !show_pressure) {
166  DRW_shgroup_uniform_texture(grp, "transferTexture", fds->tex_coba);
167  }
168  DRW_shgroup_uniform_float_copy(grp, "gridScale", fds->grid_scale);
169  DRW_shgroup_uniform_bool_copy(grp, "showPhi", show_phi);
170  DRW_shgroup_uniform_bool_copy(grp, "showFlags", show_flags);
171  DRW_shgroup_uniform_bool_copy(grp, "showPressure", show_pressure);
172  }
173  else {
174  static float white[3] = {1.0f, 1.0f, 1.0f};
175  bool use_constant_color = ((fds->active_fields & FLUID_DOMAIN_ACTIVE_COLORS) == 0 &&
178  grp, "densityTexture", (fds->tex_color) ? fds->tex_color : fds->tex_density);
179  DRW_shgroup_uniform_texture(grp, "shadowTexture", fds->tex_shadow);
181  grp, "flameTexture", (fds->tex_flame) ? fds->tex_flame : txl->dummy_volume_tx);
183  grp, "flameColorTexture", (fds->tex_flame) ? fds->tex_flame_coba : txl->dummy_coba_tx);
185  grp, "activeColor", (use_constant_color) ? fds->active_color : white, 1);
186  }
187  DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth);
188  DRW_shgroup_uniform_float_copy(grp, "densityScale", 10.0f * fds->display_thickness);
189 
190  if (use_slice) {
192  }
193  else {
195  }
196 
198 }
199 
201  Object *ob,
202  eV3DShadingColorType color_type,
203  float color[3])
204 {
206  WORKBENCH_UBO_Material ubo_data;
207  workbench_material_ubo_data(wpd, ob, ma, &ubo_data, color_type);
208  copy_v3_v3(color, ubo_data.base_color);
209 }
210 
212  Object *ob,
213  eV3DShadingColorType color_type)
214 {
215  /* Create 3D textures. */
216  Volume *volume = ob->data;
217  BKE_volume_load(volume, G.main);
218  const VolumeGrid *volume_grid = BKE_volume_grid_active_get_for_read(volume);
219  if (volume_grid == NULL) {
220  return;
221  }
222  DRWVolumeGrid *grid = DRW_volume_batch_cache_get_grid(volume, volume_grid);
223  if (grid == NULL) {
224  return;
225  }
226 
227  WORKBENCH_PrivateData *wpd = vedata->stl->wpd;
228  WORKBENCH_TextureList *txl = vedata->txl;
230  DRWShadingGroup *grp = NULL;
231 
232  wpd->volumes_do = true;
233  const bool use_slice = (volume->display.axis_slice_method == AXIS_SLICE_SINGLE);
235 
238  interp_type = WORKBENCH_VOLUME_INTERP_LINEAR;
239  break;
241  interp_type = WORKBENCH_VOLUME_INTERP_CUBIC;
242  break;
244  interp_type = WORKBENCH_VOLUME_INTERP_CLOSEST;
245  break;
246  }
247 
248  /* Create shader. */
249  GPUShader *sh = workbench_shader_volume_get(use_slice, false, interp_type, false);
250 
251  /* Compute color. */
252  float color[3];
253  workbench_volume_material_color(wpd, ob, color_type, color);
254 
255  /* Combined texture to object, and object to world transform. */
256  float texture_to_world[4][4];
257  mul_m4_m4m4(texture_to_world, ob->obmat, grid->texture_to_object);
258 
259  if (use_slice) {
260  float invviewmat[4][4];
261  DRW_view_viewmat_get(NULL, invviewmat, true);
262 
263  const int axis = (volume->display.slice_axis == SLICE_AXIS_AUTO) ?
264  axis_dominant_v3_single(invviewmat[2]) :
265  volume->display.slice_axis - 1;
266 
267  float dim[3];
268  BKE_object_dimensions_get(ob, dim);
269  /* 0.05f to achieve somewhat the same opacity as the full view. */
270  float step_length = max_ff(1e-16f, dim[axis] * 0.05f);
271 
272  const float slice_position = volume->display.slice_depth;
273 
274  grp = DRW_shgroup_create(sh, vedata->psl->volume_ps);
275  DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo);
276  DRW_shgroup_uniform_float_copy(grp, "slicePosition", slice_position);
277  DRW_shgroup_uniform_int_copy(grp, "sliceAxis", axis);
278  DRW_shgroup_uniform_float_copy(grp, "stepLength", step_length);
280  }
281  else {
282  /* Compute world space dimensions for step size. */
283  float world_size[3];
284  mat4_to_size(world_size, texture_to_world);
285  abs_v3(world_size);
286 
287  /* Compute step parameters. */
288  double noise_ofs;
289  BLI_halton_1d(3, 0.0, wpd->taa_sample, &noise_ofs);
290  float step_length, max_slice;
291  int resolution[3];
292  GPU_texture_get_mipmap_size(grid->texture, 0, resolution);
293  float slice_ct[3] = {resolution[0], resolution[1], resolution[2]};
294  mul_v3_fl(slice_ct, max_ff(0.001f, 5.0f));
295  max_slice = max_fff(slice_ct[0], slice_ct[1], slice_ct[2]);
296  invert_v3(slice_ct);
297  mul_v3_v3(slice_ct, world_size);
298  step_length = len_v3(slice_ct);
299 
300  /* Set uniforms. */
301  grp = DRW_shgroup_create(sh, vedata->psl->volume_ps);
302  DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo);
303  DRW_shgroup_uniform_int_copy(grp, "samplesLen", max_slice);
304  DRW_shgroup_uniform_float_copy(grp, "stepLength", step_length);
305  DRW_shgroup_uniform_float_copy(grp, "noiseOfs", noise_ofs);
307  }
308 
309  /* Compute density scale. */
310  const float density_scale = volume->display.density *
311  BKE_volume_density_scale(volume, ob->obmat);
312 
313  DRW_shgroup_uniform_texture(grp, "densityTexture", grid->texture);
314  /* TODO: implement shadow texture, see manta_smoke_calc_transparency. */
315  DRW_shgroup_uniform_texture(grp, "shadowTexture", txl->dummy_shadow_tx);
316  DRW_shgroup_uniform_vec3_copy(grp, "activeColor", color);
317 
318  DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth);
319  DRW_shgroup_uniform_float_copy(grp, "densityScale", density_scale);
320 
321  DRW_shgroup_uniform_mat4(grp, "volumeObjectToTexture", grid->object_to_texture);
322  DRW_shgroup_uniform_mat4(grp, "volumeTextureToObject", grid->texture_to_object);
323 
325 }
326 
328  Scene *UNUSED(scene),
329  Object *ob,
330  ModifierData *md,
331  eV3DShadingColorType color_type)
332 {
333  if (md == NULL) {
334  workbench_volume_object_cache_populate(vedata, ob, color_type);
335  }
336  else {
338  }
339 }
340 
342 {
343  WORKBENCH_PassList *psl = vedata->psl;
344  WORKBENCH_PrivateData *wpd = vedata->stl->wpd;
346 
347  if (wpd->volumes_do) {
349  DRW_draw_pass(psl->volume_ps);
350  }
351 }
352 
354 {
355  WORKBENCH_PrivateData *wpd = vedata->stl->wpd;
356 
357  /* Free Smoke Textures after rendering */
358  /* XXX This is a waste of processing and GPU bandwidth if nothing
359  * is updated. But the problem is since Textures are stored in the
360  * modifier we don't want them to take precious VRAM if the
361  * modifier is not used for display. We should share them for
362  * all viewport in a redraw at least. */
363  LISTBASE_FOREACH (LinkData *, link, &wpd->smoke_domains) {
364  FluidModifierData *fmd = (FluidModifierData *)link->data;
365  DRW_smoke_free(fmd);
366  }
368 }
struct Material * BKE_object_material_get(struct Object *ob, short act)
Definition: material.c:697
General operations, lookup, etc. for blender objects.
void BKE_object_dimensions_get(struct Object *ob, float r_vec[3])
Definition: object.c:3901
Volume datablock.
const VolumeGrid * BKE_volume_grid_active_get_for_read(const struct Volume *volume)
bool BKE_volume_load(const struct Volume *volume, const struct Main *bmain)
Volume data-block rendering and viewport drawing utilities.
float BKE_volume_density_scale(const struct Volume *volume, const float matrix[4][4])
A dynamically sized string ADT.
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:172
struct LinkData * BLI_genericNodeN(void *data)
Definition: listbase.c:923
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition: listbase.c:547
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:110
MINLINE float max_fff(float a, float b, float c)
MINLINE float max_ff(float a, float b)
MINLINE int axis_dominant_v3_single(const float vec[3])
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
Definition: math_matrix.c:262
void mat4_to_size(float size[3], const float M[4][4])
Definition: math_matrix.c:2145
MINLINE void mul_v3_v3(float r[3], const float a[3])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void abs_v3(float r[3])
MINLINE void invert_v3(float r[3])
MINLINE float len_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT
Random number functions.
void BLI_halton_1d(unsigned int prime, double offset, int n, double *r)
Definition: rand.cc:299
#define UNUSED(x)
#define ELEM(...)
@ AXIS_SLICE_SINGLE
@ SLICE_AXIS_AUTO
@ 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_DisplayInterpolationMethod
@ FLUID_DISPLAY_INTERP_CLOSEST
@ FLUID_DISPLAY_INTERP_CUBIC
@ FLUID_DISPLAY_INTERP_LINEAR
@ FLUID_DOMAIN_USE_NOISE
@ FLUID_DOMAIN_ACTIVE_COLORS
@ FLUID_DOMAIN_ACTIVE_COLOR_SET
@ FLUID_DOMAIN_TYPE_GAS
eV3DShadingColorType
VolumeDisplayInterpMethod
@ VOLUME_DISPLAY_INTERP_CLOSEST
@ VOLUME_DISPLAY_INTERP_LINEAR
@ VOLUME_DISPLAY_INTERP_CUBIC
#define VOLUME_MATERIAL_NR
@ DRW_STATE_CULL_FRONT
Definition: DRW_render.h:329
@ DRW_STATE_WRITE_COLOR
Definition: DRW_render.h:315
@ DRW_STATE_BLEND_ALPHA_PREMUL
Definition: DRW_render.h:342
#define DRW_shgroup_call(shgroup, geom, ob)
Definition: DRW_render.h:420
void GPU_framebuffer_bind(GPUFrameBuffer *fb)
struct GPUShader GPUShader
Definition: GPU_shader.h:33
GPUTexture * GPU_texture_create_1d(const char *name, int w, int mip_len, eGPUTextureFormat format, const float *data)
Definition: gpu_texture.cc:237
@ GPU_DATA_FLOAT
Definition: GPU_texture.h:172
void GPU_texture_get_mipmap_size(GPUTexture *tex, int lvl, int *size)
Definition: gpu_texture.cc:590
@ GPU_RGBA8
Definition: GPU_texture.h:88
GPUTexture * GPU_texture_create_3d(const char *name, int w, int h, int d, int mip_len, eGPUTextureFormat texture_format, eGPUDataFormat data_format, const void *data)
Definition: gpu_texture.cc:263
Scene scene
GPUBatch * DRW_cache_quad_get(void)
Definition: draw_cache.c:392
GPUBatch * DRW_cache_cube_get(void)
Definition: draw_cache.c:700
DRWVolumeGrid * DRW_volume_batch_cache_get_grid(struct Volume *volume, const struct VolumeGrid *grid)
void DRW_smoke_free(struct FluidModifierData *fmd)
Definition: draw_fluid.c:438
void DRW_smoke_ensure_coba_field(struct FluidModifierData *fmd)
Definition: draw_fluid.c:478
void DRW_smoke_ensure(struct FluidModifierData *fmd, int highres)
Definition: draw_fluid.c:502
DefaultFramebufferList * DRW_viewport_framebuffer_list_get(void)
Definition: draw_manager.c:697
DefaultTextureList * DRW_viewport_texture_list_get(void)
Definition: draw_manager.c:702
void DRW_shgroup_uniform_float_copy(DRWShadingGroup *shgroup, const char *name, const float value)
void DRW_shgroup_uniform_block(DRWShadingGroup *shgroup, const char *name, const GPUUniformBuf *ubo)
void DRW_shgroup_state_disable(DRWShadingGroup *shgroup, DRWState state)
void DRW_shgroup_uniform_texture(DRWShadingGroup *shgroup, const char *name, const GPUTexture *tex)
void DRW_shgroup_state_enable(DRWShadingGroup *shgroup, DRWState state)
void DRW_shgroup_uniform_vec3_copy(DRWShadingGroup *shgroup, const char *name, const float *value)
void DRW_shgroup_uniform_vec3(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize)
void DRW_shgroup_uniform_int_copy(DRWShadingGroup *shgroup, const char *name, const int value)
DRWShadingGroup * DRW_shgroup_create(struct GPUShader *shader, DRWPass *pass)
void DRW_shgroup_uniform_texture_ref(DRWShadingGroup *shgroup, const char *name, GPUTexture **tex)
DRWPass * DRW_pass_create(const char *name, DRWState state)
void DRW_shgroup_uniform_bool_copy(DRWShadingGroup *shgroup, const char *name, const bool value)
void DRW_shgroup_uniform_mat4(DRWShadingGroup *shgroup, const char *name, const float(*value)[4])
void DRW_view_viewmat_get(const DRWView *view, float mat[4][4], bool inverse)
void DRW_draw_pass(DRWPass *pass)
float texture_to_object[4][4]
Definition: draw_cache.h:239
struct GPUTexture * texture
Definition: draw_cache.h:236
float object_to_texture[4][4]
Definition: draw_cache.h:240
struct GPUFrameBuffer * color_only_fb
struct GPUTexture * depth
struct GPUTexture * tex_density
struct GPUTexture * tex_color
struct GPUTexture * tex_field
struct MANTA * fluid
struct GPUTexture * tex_shadow
struct GPUTexture * tex_coba
struct GPUTexture * tex_flame
struct GPUTexture * tex_flame_coba
struct FluidDomainSettings * domain
float obmat[4][4]
void * data
VolumeDisplay display
WORKBENCH_PassList * psl
WORKBENCH_StorageList * stl
WORKBENCH_TextureList * txl
struct DRWPass * volume_ps
struct GPUUniformBuf * world_ubo
struct WORKBENCH_PrivateData * wpd
struct GPUTexture * dummy_coba_tx
struct GPUTexture * dummy_volume_tx
struct GPUTexture * dummy_shadow_tx
#define G(x, y, z)
void workbench_material_ubo_data(WORKBENCH_PrivateData *wpd, Object *ob, Material *mat, WORKBENCH_UBO_Material *data, eV3DShadingColorType color_type)
eWORKBENCH_VolumeInterpType
@ WORKBENCH_VOLUME_INTERP_CUBIC
@ WORKBENCH_VOLUME_INTERP_LINEAR
@ WORKBENCH_VOLUME_INTERP_CLOSEST
GPUShader * workbench_shader_volume_get(bool slice, bool coba, eWORKBENCH_VolumeInterpType interp_type, bool smoke)
void workbench_volume_cache_init(WORKBENCH_Data *vedata)
void workbench_volume_draw_pass(WORKBENCH_Data *vedata)
void workbench_volume_draw_finish(WORKBENCH_Data *vedata)
static void workbench_volume_modifier_cache_populate(WORKBENCH_Data *vedata, Object *ob, ModifierData *md)
void workbench_volume_cache_populate(WORKBENCH_Data *vedata, Scene *UNUSED(scene), Object *ob, ModifierData *md, eV3DShadingColorType color_type)
static void workbench_volume_material_color(WORKBENCH_PrivateData *wpd, Object *ob, eV3DShadingColorType color_type, float color[3])
static void workbench_volume_object_cache_populate(WORKBENCH_Data *vedata, Object *ob, eV3DShadingColorType color_type)
void workbench_volume_engine_init(WORKBENCH_Data *vedata)