Blender V4.3
draw_cache_impl_volume.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2017 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
10
11#include <cstring>
12
13#include "MEM_guardedalloc.h"
14
15#include "BLI_listbase.h"
16#include "BLI_math_base.h"
17#include "BLI_math_matrix.hh"
18#include "BLI_math_vector.h"
19#include "BLI_utildefines.h"
20
21#include "DNA_object_types.h"
22#include "DNA_volume_types.h"
23
24#include "BKE_global.hh"
25#include "BKE_volume.hh"
27#include "BKE_volume_render.hh"
28
29#include "GPU_batch.hh"
30#include "GPU_capabilities.hh"
31#include "GPU_texture.hh"
32
34
35#include "DRW_render.hh"
36
37#include "draw_cache.hh" /* own include */
38#include "draw_cache_impl.hh" /* own include */
39
40namespace blender::draw {
41
42static void volume_batch_cache_clear(Volume *volume);
43
44/* ---------------------------------------------------------------------- */
45/* Volume gpu::Batch Cache */
46
48 /* 3D textures */
50
51 /* Wireframe */
52 struct {
54 gpu::Batch *batch;
56
57 /* Surface for selection */
58 gpu::Batch *selection_surface;
59
60 /* settings to determine if cache is invalid */
62};
63
64/* gpu::Batch cache management. */
65
66static bool volume_batch_cache_valid(Volume *volume)
67{
68 VolumeBatchCache *cache = static_cast<VolumeBatchCache *>(volume->batch_cache);
69 return (cache && cache->is_dirty == false);
70}
71
72static void volume_batch_cache_init(Volume *volume)
73{
74 VolumeBatchCache *cache = static_cast<VolumeBatchCache *>(volume->batch_cache);
75
76 if (!cache) {
77 volume->batch_cache = cache = MEM_cnew<VolumeBatchCache>(__func__);
78 }
79 else {
80 memset(cache, 0, sizeof(*cache));
81 }
82
83 cache->is_dirty = false;
84}
85
87{
88 if (!volume_batch_cache_valid(volume)) {
91 }
92}
93
95{
97 return static_cast<VolumeBatchCache *>(volume->batch_cache);
98}
99
101{
102 VolumeBatchCache *cache = static_cast<VolumeBatchCache *>(volume->batch_cache);
103 if (cache == nullptr) {
104 return;
105 }
106 switch (mode) {
108 cache->is_dirty = true;
109 break;
110 default:
111 BLI_assert(0);
112 }
113}
114
116{
117 VolumeBatchCache *cache = static_cast<VolumeBatchCache *>(volume->batch_cache);
118 if (!cache) {
119 return;
120 }
121
122 LISTBASE_FOREACH (DRWVolumeGrid *, grid, &cache->grids) {
123 MEM_SAFE_FREE(grid->name);
124 DRW_TEXTURE_FREE_SAFE(grid->texture);
125 }
126 BLI_freelistN(&cache->grids);
127
131}
132
142
144 void *userdata, const float (*verts)[3], const int (*edges)[2], int totvert, int totedge)
145{
146 VolumeWireframeUserData *data = static_cast<VolumeWireframeUserData *>(userdata);
147 Scene *scene = data->scene;
148 Volume *volume = data->volume;
149 VolumeBatchCache *cache = static_cast<VolumeBatchCache *>(volume->batch_cache);
150 const bool do_hq_normals = (scene->r.perf_flag & SCE_PERF_HQ_NORMALS) != 0 ||
152
153 /* Create vertex buffer. */
154 static GPUVertFormat format = {0};
155 static GPUVertFormat format_hq = {0};
156 static struct {
157 uint pos_id, nor_id;
158 uint pos_hq_id, nor_hq_id;
159 } attr_id;
160
161 if (format.attr_len == 0) {
165 attr_id.pos_id = GPU_vertformat_attr_add(&format_hq, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
167 &format_hq, "nor", GPU_COMP_I16, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
168 }
169
170 static float normal[3] = {1.0f, 0.0f, 0.0f};
171 GPUNormal packed_normal;
172 GPU_normal_convert_v3(&packed_normal, normal, do_hq_normals);
173 uint pos_id = do_hq_normals ? attr_id.pos_hq_id : attr_id.pos_id;
174 uint nor_id = do_hq_normals ? attr_id.nor_hq_id : attr_id.nor_id;
175
176 cache->face_wire.pos_nor_in_order = GPU_vertbuf_create_with_format(do_hq_normals ? format_hq :
177 format);
180 GPU_vertbuf_attr_fill_stride(cache->face_wire.pos_nor_in_order, nor_id, 0, &packed_normal);
181
182 /* Create wiredata. */
183 gpu::VertBuf *vbo_wiredata = GPU_vertbuf_calloc();
184 DRW_vertbuf_create_wiredata(vbo_wiredata, totvert);
185
187 /* Create batch. */
190 }
191 else {
192 /* Create edge index buffer. */
194 GPU_indexbuf_init(&elb, GPU_PRIM_LINES, totedge, totvert);
195 for (int i = 0; i < totedge; i++) {
196 GPU_indexbuf_add_line_verts(&elb, edges[i][0], edges[i][1]);
197 }
199
200 /* Create batch. */
203 }
204
205 GPU_batch_vertbuf_add(cache->face_wire.batch, vbo_wiredata, true);
206}
207
209{
211 return nullptr;
212 }
213
215
216 if (cache->face_wire.batch == nullptr) {
217 const bke::VolumeGridData *volume_grid = BKE_volume_grid_active_get_for_read(volume);
218 if (volume_grid == nullptr) {
219 return nullptr;
220 }
221
222 /* Create wireframe from OpenVDB tree. */
223 const DRWContextState *draw_ctx = DRW_context_state_get();
225 userdata.volume = volume;
226 userdata.scene = draw_ctx->scene;
227 BKE_volume_grid_wireframe(volume, volume_grid, drw_volume_wireframe_cb, &userdata);
228 }
229
230 return cache->face_wire.batch;
231}
232
234 void *userdata, float (*verts)[3], int (*tris)[3], int totvert, int tottris)
235{
236 Volume *volume = static_cast<Volume *>(userdata);
237 VolumeBatchCache *cache = static_cast<VolumeBatchCache *>(volume->batch_cache);
238
239 static GPUVertFormat format = {0};
240 static uint pos_id;
241 if (format.attr_len == 0) {
243 }
244
245 /* Create vertex buffer. */
247 GPU_vertbuf_data_alloc(*vbo_surface, totvert);
248 GPU_vertbuf_attr_fill(vbo_surface, pos_id, verts);
249
250 /* Create index buffer. */
252 GPU_indexbuf_init(&elb, GPU_PRIM_TRIS, tottris, totvert);
253 for (int i = 0; i < tottris; i++) {
254 GPU_indexbuf_add_tri_verts(&elb, UNPACK3(tris[i]));
255 }
256 gpu::IndexBuf *ibo_surface = GPU_indexbuf_build(&elb);
257
259 GPU_PRIM_TRIS, vbo_surface, ibo_surface, GPU_BATCH_OWNS_VBO | GPU_BATCH_OWNS_INDEX);
260}
261
263{
265 if (cache->selection_surface == nullptr) {
266 const bke::VolumeGridData *volume_grid = BKE_volume_grid_active_get_for_read(volume);
267 if (volume_grid == nullptr) {
268 return nullptr;
269 }
271 volume, volume_grid, drw_volume_selection_surface_cb, volume);
272 }
273 return cache->selection_surface;
274}
275
277 const bke::VolumeGridData *grid,
278 VolumeBatchCache *cache)
279{
280 const std::string name = bke::volume_grid::get_name(*grid);
281
282 /* Return cached grid. */
283 LISTBASE_FOREACH (DRWVolumeGrid *, cache_grid, &cache->grids) {
284 if (cache_grid->name == name) {
285 return cache_grid;
286 }
287 }
288
289 /* Allocate new grid. */
290 DRWVolumeGrid *cache_grid = MEM_cnew<DRWVolumeGrid>(__func__);
291 cache_grid->name = BLI_strdup(name.c_str());
292 BLI_addtail(&cache->grids, cache_grid);
293
294 /* TODO: can we load this earlier, avoid accessing the global and take
295 * advantage of dependency graph multi-threading? */
296 BKE_volume_load(volume, G.main);
297
298 /* Test if we support textures with the number of channels. */
300 if (!ELEM(channels, 1, 3)) {
301 return cache_grid;
302 }
303
304 DenseFloatVolumeGrid dense_grid;
305 if (BKE_volume_grid_dense_floats(volume, grid, &dense_grid)) {
306 cache_grid->texture_to_object = float4x4(dense_grid.texture_to_object);
307 cache_grid->object_to_texture = math::invert(cache_grid->texture_to_object);
308
309 /* Create GPU texture. */
311 cache_grid->texture = GPU_texture_create_3d("volume_grid",
312 UNPACK3(dense_grid.resolution),
313 1,
314 format,
316 dense_grid.voxels);
317 /* The texture can be null if the resolution along one axis is larger than
318 * GL_MAX_3D_TEXTURE_SIZE. */
319 if (cache_grid->texture != nullptr) {
320 GPU_texture_swizzle_set(cache_grid->texture, (channels == 3) ? "rgb1" : "rrr1");
323 }
324 else {
325 MEM_freeN(dense_grid.voxels);
326 printf("Error: Could not allocate 3D texture for volume.\n");
327 }
328 }
329
330 return cache_grid;
331}
332
334 const bke::VolumeGridData *volume_grid)
335{
337 DRWVolumeGrid *grid = volume_grid_cache_get(volume, volume_grid, cache);
338 return (grid->texture != nullptr) ? grid : nullptr;
339}
340
342{
343 return max_ii(1, volume->totcol);
344}
345
346} // namespace blender::draw
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)
@ BKE_VOLUME_BATCH_DIRTY_ALL
Definition BKE_volume.hh:57
Volume data-block rendering and viewport drawing utilities.
void BKE_volume_dense_float_grid_clear(DenseFloatVolumeGrid *dense_grid)
void BKE_volume_grid_selection_surface(const Volume *volume, const blender::bke::VolumeGridData *volume_grid, BKE_volume_selection_surface_cb cb, void *cb_userdata)
bool BKE_volume_grid_dense_floats(const Volume *volume, const blender::bke::VolumeGridData *volume_grid, DenseFloatVolumeGrid *r_dense_grid)
void BKE_volume_grid_wireframe(const Volume *volume, const blender::bke::VolumeGridData *volume_grid, BKE_volume_wireframe_cb cb, void *cb_userdata)
#define BLI_assert(a)
Definition BLI_assert.h:50
#define LISTBASE_FOREACH(type, var, list)
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:496
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
MINLINE int max_ii(int a, int b)
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC
Definition string.c:40
unsigned int uint
#define UNPACK3(a)
#define ELEM(...)
Object is a sort of wrapper for general info.
@ SCE_PERF_HQ_NORMALS
@ VOLUME_WIREFRAME_NONE
@ VOLUME_WIREFRAME_POINTS
struct Volume Volume
#define DRW_TEXTURE_FREE_SAFE(tex)
blender::gpu::Batch * GPU_batch_create_ex(GPUPrimType primitive_type, blender::gpu::VertBuf *vertex_buf, blender::gpu::IndexBuf *index_buf, eGPUBatchFlag owns_flag)
Definition gpu_batch.cc:56
#define GPU_batch_create(primitive_type, vertex_buf, index_buf)
Definition GPU_batch.hh:149
int GPU_batch_vertbuf_add(blender::gpu::Batch *batch, blender::gpu::VertBuf *vertex_buf, bool own_vbo)
#define GPU_BATCH_DISCARD_SAFE(batch)
Definition GPU_batch.hh:205
@ GPU_BATCH_OWNS_INDEX
Definition GPU_batch.hh:51
@ GPU_BATCH_OWNS_VBO
Definition GPU_batch.hh:42
bool GPU_use_hq_normals_workaround()
void GPU_indexbuf_init(GPUIndexBufBuilder *, GPUPrimType, uint prim_len, uint vertex_len)
blender::gpu::IndexBuf * GPU_indexbuf_build(GPUIndexBufBuilder *)
void GPU_indexbuf_add_line_verts(GPUIndexBufBuilder *, uint v1, uint v2)
void GPU_indexbuf_add_tri_verts(GPUIndexBufBuilder *, uint v1, uint v2, uint v3)
@ GPU_PRIM_LINES
@ GPU_PRIM_POINTS
@ GPU_PRIM_TRIS
void GPU_texture_extend_mode(GPUTexture *texture, GPUSamplerExtendMode extend_mode)
@ GPU_TEXTURE_USAGE_SHADER_READ
@ GPU_SAMPLER_EXTEND_MODE_CLAMP_TO_BORDER
GPUTexture * GPU_texture_create_3d(const char *name, int width, int height, int depth, int mip_len, eGPUTextureFormat format, eGPUTextureUsage usage, const void *data)
eGPUTextureFormat
@ GPU_RGB16F
void GPU_texture_swizzle_set(GPUTexture *texture, const char swizzle[4])
void GPU_vertbuf_attr_fill_stride(blender::gpu::VertBuf *, uint a_idx, uint stride, const void *data)
#define GPU_vertbuf_create_with_format(format)
void GPU_vertbuf_attr_fill(blender::gpu::VertBuf *, uint a_idx, const void *data)
#define GPU_VERTBUF_DISCARD_SAFE(verts)
blender::gpu::VertBuf * GPU_vertbuf_calloc()
void GPU_vertbuf_data_alloc(blender::gpu::VertBuf &verts, uint v_len)
@ GPU_FETCH_FLOAT
@ GPU_FETCH_INT_TO_FLOAT_UNIT
uint GPU_vertformat_attr_add(GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
BLI_INLINE void GPU_normal_convert_v3(GPUNormal *gpu_normal, const float data[3], const bool do_hq_normals)
@ GPU_COMP_I10
@ GPU_COMP_F32
@ GPU_COMP_I16
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Brightness Control the brightness and contrast of the input color Vector Map input vector components with curves Camera Retrieve information about the camera and how it relates to the current shading point s position Clamp a value between a minimum and a maximum Vector Perform vector math operation Invert Invert a producing a negative Combine Generate a color from its and blue channels(Deprecated)") DefNode(ShaderNode
#define printf
const DRWContextState * DRW_context_state_get()
static float verts[][3]
struct @157336070235062372277311340362362342103123126032::@132215023242101136103363133227133264017254024241 attr_id
format
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
#define G(x, y, z)
std::string get_name(const VolumeGridData &grid)
int get_channels_num(VolumeGridType type)
VolumeGridType get_type(const VolumeGridData &grid)
blender::gpu::Batch * DRW_volume_batch_cache_get_selection_surface(Volume *volume)
static void volume_batch_cache_clear(Volume *volume)
static void volume_batch_cache_init(Volume *volume)
void DRW_volume_batch_cache_free(Volume *volume)
void DRW_volume_batch_cache_validate(Volume *volume)
void DRW_volume_batch_cache_dirty_tag(Volume *volume, int mode)
blender::gpu::Batch * DRW_volume_batch_cache_get_wireframes_face(Volume *volume)
static bool volume_batch_cache_valid(Volume *volume)
static DRWVolumeGrid * volume_grid_cache_get(const Volume *volume, const bke::VolumeGridData *grid, VolumeBatchCache *cache)
void DRW_vertbuf_create_wiredata(blender::gpu::VertBuf *vbo, const int vert_len)
static VolumeBatchCache * volume_batch_cache_get(Volume *volume)
static void drw_volume_selection_surface_cb(void *userdata, float(*verts)[3], int(*tris)[3], int totvert, int tottris)
DRWVolumeGrid * DRW_volume_batch_cache_get_grid(Volume *volume, const bke::VolumeGridData *volume_grid)
int DRW_volume_material_count_get(const Volume *volume)
static void drw_volume_wireframe_cb(void *userdata, const float(*verts)[3], const int(*edges)[2], int totvert, int totedge)
CartesianBasis invert(const CartesianBasis &basis)
MatBase< float, 4, 4 > float4x4
blender::float4x4 object_to_texture
GPUTexture * texture
blender::float4x4 texture_to_object
struct RenderData r
void * batch_cache
VolumeDisplay display
struct blender::draw::VolumeBatchCache::@046100156230137045271141270111342117350362306271 face_wire