Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/blender/blenkernel/BKE_volume_render.h10
-rw-r--r--source/blender/blenkernel/intern/volume_render.cc452
-rw-r--r--source/blender/draw/CMakeLists.txt1
-rw-r--r--source/blender/draw/engines/overlay/overlay_engine.c6
-rw-r--r--source/blender/draw/engines/overlay/overlay_outline.c16
-rw-r--r--source/blender/draw/engines/overlay/overlay_private.h6
-rw-r--r--source/blender/draw/engines/overlay/overlay_volume.c67
-rw-r--r--source/blender/draw/intern/draw_cache.c6
-rw-r--r--source/blender/draw/intern/draw_cache.h1
-rw-r--r--source/blender/draw/intern/draw_cache_impl.h1
-rw-r--r--source/blender/draw/intern/draw_cache_impl_volume.c47
11 files changed, 455 insertions, 158 deletions
diff --git a/source/blender/blenkernel/BKE_volume_render.h b/source/blender/blenkernel/BKE_volume_render.h
index a42f24a5312..593f296135c 100644
--- a/source/blender/blenkernel/BKE_volume_render.h
+++ b/source/blender/blenkernel/BKE_volume_render.h
@@ -58,6 +58,16 @@ void BKE_volume_grid_wireframe(const struct Volume *volume,
BKE_volume_wireframe_cb cb,
void *cb_userdata);
+/* Selection Surface */
+
+typedef void (*BKE_volume_selection_surface_cb)(
+ void *userdata, float (*verts)[3], int (*tris)[3], int totvert, int tottris);
+
+void BKE_volume_grid_selection_surface(const struct Volume *volume,
+ struct VolumeGrid *volume_grid,
+ BKE_volume_selection_surface_cb cb,
+ void *cb_userdata);
+
/* Render */
float BKE_volume_density_scale(const struct Volume *volume, const float matrix[4][4]);
diff --git a/source/blender/blenkernel/intern/volume_render.cc b/source/blender/blenkernel/intern/volume_render.cc
index 98d3617c822..b773452b6a8 100644
--- a/source/blender/blenkernel/intern/volume_render.cc
+++ b/source/blender/blenkernel/intern/volume_render.cc
@@ -20,8 +20,11 @@
#include "MEM_guardedalloc.h"
+#include "BLI_array.hh"
+#include "BLI_float3.hh"
#include "BLI_math_matrix.h"
#include "BLI_math_vector.h"
+#include "BLI_vector.hh"
#include "DNA_volume_types.h"
@@ -166,107 +169,223 @@ void BKE_volume_grid_dense_voxels(const Volume *volume,
/* Wireframe */
#ifdef WITH_OPENVDB
-struct VolumeWireframe {
- std::vector<openvdb::Vec3f> verts;
- std::vector<openvdb::Vec2I> edges;
-
- template<typename GridType>
- void add_grid(openvdb::GridBase::ConstPtr gridbase, const bool points, const bool coarse)
- {
- using TreeType = typename GridType::TreeType;
- using Depth2Type = typename TreeType::RootNodeType::ChildNodeType::ChildNodeType;
- using NodeCIter = typename TreeType::NodeCIter;
- using GridConstPtr = typename GridType::ConstPtr;
-
- GridConstPtr grid = openvdb::gridConstPtrCast<GridType>(gridbase);
- const openvdb::math::Transform &transform = grid->transform();
- const int depth = (coarse) ? 2 : 3;
-
- NodeCIter iter = grid->tree().cbeginNode();
- iter.setMaxDepth(depth);
-
- for (; iter; ++iter) {
- if (iter.getDepth() == depth) {
- openvdb::CoordBBox coordbbox;
-
- if (depth == 2) {
- /* Internal node at depth 2. */
- const Depth2Type *node = nullptr;
- iter.getNode(node);
- if (node) {
- node->evalActiveBoundingBox(coordbbox, false);
- }
- else {
- continue;
- }
- }
- else {
- /* Leaf node. */
- if (!iter.getBoundingBox(coordbbox)) {
- continue;
- }
- }
-
- /* +1 to convert from exclusive to include bounds. */
- coordbbox.max() = coordbbox.max().offsetBy(1);
- openvdb::BBoxd bbox = transform.indexToWorld(coordbbox);
-
- if (points) {
- add_point(bbox);
- }
- else {
- add_box(bbox);
- }
+
+/** Returns bounding boxes that approximate the shape of the volume stored in the grid. */
+template<typename GridType>
+static blender::Vector<openvdb::CoordBBox> get_bounding_boxes(openvdb::GridBase::ConstPtr gridbase,
+ const bool coarse)
+{
+ using TreeType = typename GridType::TreeType;
+ using Depth2Type = typename TreeType::RootNodeType::ChildNodeType::ChildNodeType;
+ using NodeCIter = typename TreeType::NodeCIter;
+ using GridConstPtr = typename GridType::ConstPtr;
+
+ GridConstPtr grid = openvdb::gridConstPtrCast<GridType>(gridbase);
+ blender::Vector<openvdb::CoordBBox> boxes;
+ const int depth = coarse ? 2 : 3;
+
+ NodeCIter iter = grid->tree().cbeginNode();
+ iter.setMaxDepth(depth);
+
+ for (; iter; ++iter) {
+ if (iter.getDepth() != depth) {
+ continue;
+ }
+
+ openvdb::CoordBBox box;
+ if (depth == 2) {
+ /* Internal node at depth 2. */
+ const Depth2Type *node = nullptr;
+ iter.getNode(node);
+ if (node) {
+ node->evalActiveBoundingBox(box, false);
}
+ else {
+ continue;
+ }
+ }
+ else {
+ /* Leaf node. */
+ if (!iter.getBoundingBox(box)) {
+ continue;
+ }
+ }
+
+ /* +1 to convert from exclusive to inclusive bounds. */
+ box.max() = box.max().offsetBy(1);
+
+ boxes.append(box);
+ }
+
+ return boxes;
+}
+
+static blender::Vector<openvdb::CoordBBox> get_bounding_boxes(VolumeGridType grid_type,
+ openvdb::GridBase::ConstPtr grid,
+ const bool coarse)
+{
+ switch (grid_type) {
+ case VOLUME_GRID_BOOLEAN: {
+ return get_bounding_boxes<openvdb::BoolGrid>(grid, coarse);
+ break;
+ }
+ case VOLUME_GRID_FLOAT: {
+ return get_bounding_boxes<openvdb::FloatGrid>(grid, coarse);
+ break;
+ }
+ case VOLUME_GRID_DOUBLE: {
+ return get_bounding_boxes<openvdb::DoubleGrid>(grid, coarse);
+ break;
+ }
+ case VOLUME_GRID_INT: {
+ return get_bounding_boxes<openvdb::Int32Grid>(grid, coarse);
+ break;
+ }
+ case VOLUME_GRID_INT64: {
+ return get_bounding_boxes<openvdb::Int64Grid>(grid, coarse);
+ break;
+ }
+ case VOLUME_GRID_MASK: {
+ return get_bounding_boxes<openvdb::MaskGrid>(grid, coarse);
+ break;
+ }
+ case VOLUME_GRID_VECTOR_FLOAT: {
+ return get_bounding_boxes<openvdb::Vec3fGrid>(grid, coarse);
+ break;
+ }
+ case VOLUME_GRID_VECTOR_DOUBLE: {
+ return get_bounding_boxes<openvdb::Vec3dGrid>(grid, coarse);
+ break;
+ }
+ case VOLUME_GRID_VECTOR_INT: {
+ return get_bounding_boxes<openvdb::Vec3IGrid>(grid, coarse);
+ break;
+ }
+ case VOLUME_GRID_STRING: {
+ return get_bounding_boxes<openvdb::StringGrid>(grid, coarse);
+ break;
+ }
+ case VOLUME_GRID_POINTS:
+ case VOLUME_GRID_UNKNOWN: {
+ break;
+ }
+ }
+ return {};
+}
+
+static void boxes_to_center_points(blender::Span<openvdb::CoordBBox> boxes,
+ const openvdb::math::Transform &transform,
+ blender::MutableSpan<blender::float3> r_verts)
+{
+ BLI_assert(boxes.size() == r_verts.size());
+ for (const int i : boxes.index_range()) {
+ openvdb::Vec3d center = transform.indexToWorld(boxes[i].getCenter());
+ r_verts[i] = blender::float3(center[0], center[1], center[2]);
+ }
+}
+
+static void boxes_to_corner_points(blender::Span<openvdb::CoordBBox> boxes,
+ const openvdb::math::Transform &transform,
+ blender::MutableSpan<blender::float3> r_verts)
+{
+ BLI_assert(boxes.size() * 8 == r_verts.size());
+ for (const int i : boxes.index_range()) {
+ const openvdb::CoordBBox &box = boxes[i];
+
+ /* The ordering of the corner points is lexicographic. */
+ std::array<openvdb::Coord, 8> corners;
+ box.getCornerPoints(corners.data());
+
+ for (int j = 0; j < 8; j++) {
+ openvdb::Coord corner_i = corners[j];
+ openvdb::Vec3d corner_d = transform.indexToWorld(corner_i);
+ r_verts[8 * i + j] = blender::float3(corner_d[0], corner_d[1], corner_d[2]);
}
}
+}
- void add_point(const openvdb::BBoxd &bbox)
- {
- verts.push_back(bbox.getCenter());
+static void boxes_to_edge_mesh(blender::Span<openvdb::CoordBBox> boxes,
+ const openvdb::math::Transform &transform,
+ blender::Vector<blender::float3> &r_verts,
+ blender::Vector<std::array<int, 2>> &r_edges)
+{
+ /* TODO: Deduplicate edges, hide flat edges? */
+
+ const int box_edges[12][2] = {
+ {0, 1},
+ {0, 2},
+ {0, 4},
+ {1, 3},
+ {1, 5},
+ {2, 3},
+ {2, 6},
+ {3, 7},
+ {4, 5},
+ {4, 6},
+ {5, 7},
+ {6, 7},
+ };
+
+ int vert_offset = r_verts.size();
+ int edge_offset = r_edges.size();
+
+ const int vert_amount = 8 * boxes.size();
+ const int edge_amount = 12 * boxes.size();
+
+ r_verts.resize(r_verts.size() + vert_amount);
+ r_edges.resize(r_edges.size() + edge_amount);
+ boxes_to_corner_points(boxes, transform, r_verts.as_mutable_span().take_back(vert_amount));
+
+ for (int i = 0; i < boxes.size(); i++) {
+ for (int j = 0; j < 12; j++) {
+ r_edges[edge_offset + j] = {vert_offset + box_edges[j][0], vert_offset + box_edges[j][1]};
+ }
+ vert_offset += 8;
+ edge_offset += 12;
}
+}
- void add_box(const openvdb::BBoxd &bbox)
- {
- /* TODO: deduplicate edges, hide flat edges? */
- openvdb::Vec3f min = bbox.min();
- openvdb::Vec3f max = bbox.max();
-
- const int vert_offset = verts.size();
- const int edge_offset = edges.size();
-
- /* Create vertices. */
- verts.resize(vert_offset + 8);
- verts[vert_offset + 0] = openvdb::Vec3f(min[0], min[1], min[2]);
- verts[vert_offset + 1] = openvdb::Vec3f(max[0], min[1], min[2]);
- verts[vert_offset + 2] = openvdb::Vec3f(max[0], max[1], min[2]);
- verts[vert_offset + 3] = openvdb::Vec3f(min[0], max[1], min[2]);
- verts[vert_offset + 4] = openvdb::Vec3f(min[0], min[1], max[2]);
- verts[vert_offset + 5] = openvdb::Vec3f(max[0], min[1], max[2]);
- verts[vert_offset + 6] = openvdb::Vec3f(max[0], max[1], max[2]);
- verts[vert_offset + 7] = openvdb::Vec3f(min[0], max[1], max[2]);
-
- /* Create edges. */
- const int box_edges[12][2] = {{0, 1},
- {1, 2},
- {2, 3},
- {3, 0},
- {4, 5},
- {5, 6},
- {6, 7},
- {7, 4},
- {0, 4},
- {1, 5},
- {2, 6},
- {3, 7}};
-
- edges.resize(edge_offset + 12);
- for (int i = 0; i < 12; i++) {
- edges[edge_offset + i] = openvdb::Vec2I(vert_offset + box_edges[i][0],
- vert_offset + box_edges[i][1]);
+static void boxes_to_cube_mesh(blender::Span<openvdb::CoordBBox> boxes,
+ const openvdb::math::Transform &transform,
+ blender::Vector<blender::float3> &r_verts,
+ blender::Vector<std::array<int, 3>> &r_tris)
+{
+ const int box_tris[12][3] = {
+ {0, 1, 4},
+ {4, 1, 5},
+ {0, 2, 1},
+ {1, 2, 3},
+ {1, 3, 5},
+ {5, 3, 7},
+ {6, 4, 5},
+ {7, 5, 6},
+ {2, 0, 4},
+ {2, 4, 6},
+ {3, 7, 2},
+ {6, 2, 7},
+ };
+
+ int vert_offset = r_verts.size();
+ int tri_offset = r_tris.size();
+
+ const int vert_amount = 8 * boxes.size();
+ const int tri_amount = 12 * boxes.size();
+
+ r_verts.resize(r_verts.size() + vert_amount);
+ r_tris.resize(r_tris.size() + tri_amount);
+ boxes_to_corner_points(boxes, transform, r_verts.as_mutable_span().take_back(vert_amount));
+
+ for (int i = 0; i < boxes.size(); i++) {
+ for (int j = 0; j < 12; j++) {
+ r_tris[tri_offset + j] = {vert_offset + box_tris[j][0],
+ vert_offset + box_tris[j][1],
+ vert_offset + box_tris[j][2]};
}
+ vert_offset += 8;
+ tri_offset += 12;
}
-};
+}
+
#endif
void BKE_volume_grid_wireframe(const Volume *volume,
@@ -274,79 +393,96 @@ void BKE_volume_grid_wireframe(const Volume *volume,
BKE_volume_wireframe_cb cb,
void *cb_userdata)
{
-#ifdef WITH_OPENVDB
- VolumeWireframe wireframe;
-
if (volume->display.wireframe_type == VOLUME_WIREFRAME_NONE) {
- /* Nothing. */
+ cb(cb_userdata, NULL, NULL, 0, 0);
+ return;
}
- else if (volume->display.wireframe_type == VOLUME_WIREFRAME_BOUNDS) {
- /* Bounding box. */
- float min[3], max[3];
- BKE_volume_grid_bounds(volume_grid, min, max);
- openvdb::BBoxd bbox(min, max);
- wireframe.add_box(bbox);
+#ifdef WITH_OPENVDB
+ openvdb::GridBase::ConstPtr grid = BKE_volume_grid_openvdb_for_read(volume, volume_grid);
+
+ if (volume->display.wireframe_type == VOLUME_WIREFRAME_BOUNDS) {
+ /* Bounding box. */
+ openvdb::CoordBBox box;
+ blender::Vector<blender::float3> verts;
+ blender::Vector<std::array<int, 2>> edges;
+ if (grid->baseTree().evalLeafBoundingBox(box)) {
+ boxes_to_edge_mesh({box}, grid->transform(), verts, edges);
+ }
+ cb(cb_userdata,
+ (float(*)[3])verts.data(),
+ (int(*)[2])edges.data(),
+ verts.size(),
+ edges.size());
}
else {
- /* Tree nodes. */
- openvdb::GridBase::ConstPtr grid = BKE_volume_grid_openvdb_for_read(volume, volume_grid);
- const bool points = (volume->display.wireframe_type == VOLUME_WIREFRAME_POINTS);
- const bool coarse = (volume->display.wireframe_detail == VOLUME_WIREFRAME_COARSE);
-
- switch (BKE_volume_grid_type(volume_grid)) {
- case VOLUME_GRID_BOOLEAN: {
- wireframe.add_grid<openvdb::BoolGrid>(grid, points, coarse);
- break;
- }
- case VOLUME_GRID_FLOAT: {
- wireframe.add_grid<openvdb::FloatGrid>(grid, points, coarse);
- break;
- }
- case VOLUME_GRID_DOUBLE: {
- wireframe.add_grid<openvdb::DoubleGrid>(grid, points, coarse);
- break;
- }
- case VOLUME_GRID_INT: {
- wireframe.add_grid<openvdb::Int32Grid>(grid, points, coarse);
- break;
- }
- case VOLUME_GRID_INT64: {
- wireframe.add_grid<openvdb::Int64Grid>(grid, points, coarse);
- break;
- }
- case VOLUME_GRID_MASK: {
- wireframe.add_grid<openvdb::MaskGrid>(grid, points, coarse);
- break;
- }
- case VOLUME_GRID_VECTOR_FLOAT: {
- wireframe.add_grid<openvdb::Vec3fGrid>(grid, points, coarse);
- break;
- }
- case VOLUME_GRID_VECTOR_DOUBLE: {
- wireframe.add_grid<openvdb::Vec3dGrid>(grid, points, coarse);
- break;
- }
- case VOLUME_GRID_VECTOR_INT: {
- wireframe.add_grid<openvdb::Vec3IGrid>(grid, points, coarse);
- break;
- }
- case VOLUME_GRID_STRING: {
- wireframe.add_grid<openvdb::StringGrid>(grid, points, coarse);
- break;
- }
- case VOLUME_GRID_POINTS:
- case VOLUME_GRID_UNKNOWN: {
- break;
- }
+ blender::Vector<openvdb::CoordBBox> boxes = get_bounding_boxes(
+ BKE_volume_grid_type(volume_grid),
+ grid,
+ volume->display.wireframe_detail == VOLUME_WIREFRAME_COARSE);
+
+ blender::Vector<blender::float3> verts;
+ blender::Vector<std::array<int, 2>> edges;
+
+ if (volume->display.wireframe_type == VOLUME_WIREFRAME_POINTS) {
+ verts.resize(boxes.size());
+ boxes_to_center_points(boxes, grid->transform(), verts);
}
+ else {
+ boxes_to_edge_mesh(boxes, grid->transform(), verts, edges);
+ }
+
+ cb(cb_userdata,
+ (float(*)[3])verts.data(),
+ (int(*)[2])edges.data(),
+ verts.size(),
+ edges.size());
+ }
+
+#else
+ UNUSED_VARS(volume, volume_grid);
+ cb(cb_userdata, NULL, NULL, 0, 0);
+#endif
+}
+
+static void grow_triangles(blender::MutableSpan<blender::float3> verts,
+ blender::Span<std::array<int, 3>> tris,
+ const float factor)
+{
+ /* Compute the offset for every vertex based on the connected edges.
+ * This formula simply tries increases the length of all edges. */
+ blender::Array<blender::float3> offsets(verts.size(), {0, 0, 0});
+ for (const std::array<int, 3> &tri : tris) {
+ offsets[tri[0]] += factor * (2 * verts[tri[0]] - verts[tri[1]] - verts[tri[2]]);
+ offsets[tri[1]] += factor * (2 * verts[tri[1]] - verts[tri[0]] - verts[tri[2]]);
+ offsets[tri[2]] += factor * (2 * verts[tri[2]] - verts[tri[0]] - verts[tri[1]]);
+ }
+ /* Apply the computed offsets. */
+ for (const int i : verts.index_range()) {
+ verts[i] += offsets[i];
}
+}
+
+void BKE_volume_grid_selection_surface(const Volume *volume,
+ VolumeGrid *volume_grid,
+ BKE_volume_selection_surface_cb cb,
+ void *cb_userdata)
+{
+#ifdef WITH_OPENVDB
+ openvdb::GridBase::ConstPtr grid = BKE_volume_grid_openvdb_for_read(volume, volume_grid);
+ blender::Vector<openvdb::CoordBBox> boxes = get_bounding_boxes(
+ BKE_volume_grid_type(volume_grid), grid, true);
+
+ blender::Vector<blender::float3> verts;
+ blender::Vector<std::array<int, 3>> tris;
+ boxes_to_cube_mesh(boxes, grid->transform(), verts, tris);
+
+ /* By slightly scaling the individual boxes up, we can avoid some artifacts when drawing the
+ * selection outline. */
+ const float offset_factor = 0.01f;
+ grow_triangles(verts, tris, offset_factor);
- cb(cb_userdata,
- (float(*)[3])wireframe.verts.data(),
- (int(*)[2])wireframe.edges.data(),
- wireframe.verts.size(),
- wireframe.edges.size());
+ cb(cb_userdata, (float(*)[3])verts.data(), (int(*)[3])tris.data(), verts.size(), tris.size());
#else
UNUSED_VARS(volume, volume_grid);
cb(cb_userdata, NULL, NULL, 0, 0);
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index 11aea544c65..4e72e89ae99 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -146,6 +146,7 @@ set(SRC
engines/overlay/overlay_particle.c
engines/overlay/overlay_sculpt.c
engines/overlay/overlay_shader.c
+ engines/overlay/overlay_volume.c
engines/overlay/overlay_wireframe.c
DRW_engine.h
diff --git a/source/blender/draw/engines/overlay/overlay_engine.c b/source/blender/draw/engines/overlay/overlay_engine.c
index fb235a1ff57..5a87af7238e 100644
--- a/source/blender/draw/engines/overlay/overlay_engine.c
+++ b/source/blender/draw/engines/overlay/overlay_engine.c
@@ -207,6 +207,7 @@ static void OVERLAY_cache_init(void *vedata)
OVERLAY_outline_cache_init(vedata);
OVERLAY_particle_cache_init(vedata);
OVERLAY_wireframe_cache_init(vedata);
+ OVERLAY_volume_cache_init(vedata);
}
BLI_INLINE OVERLAY_DupliData *OVERLAY_duplidata_get(Object *ob, void *vedata, bool *do_init)
@@ -355,6 +356,10 @@ static void OVERLAY_cache_populate(void *vedata, Object *ob)
OVERLAY_pose_cache_populate(vedata, ob);
}
+ if (ob->type == OB_VOLUME) {
+ OVERLAY_volume_cache_populate(vedata, ob);
+ }
+
if (in_edit_mode && !pd->hide_overlays) {
switch (ob->type) {
case OB_MESH:
@@ -551,6 +556,7 @@ static void OVERLAY_draw_scene(void *vedata)
OVERLAY_particle_draw(vedata);
OVERLAY_metaball_draw(vedata);
OVERLAY_gpencil_draw(vedata);
+ OVERLAY_volume_draw(vedata);
OVERLAY_extra_draw(vedata);
if (DRW_state_is_fbo()) {
diff --git a/source/blender/draw/engines/overlay/overlay_outline.c b/source/blender/draw/engines/overlay/overlay_outline.c
index e904066248f..f1467ff9794 100644
--- a/source/blender/draw/engines/overlay/overlay_outline.c
+++ b/source/blender/draw/engines/overlay/overlay_outline.c
@@ -272,6 +272,17 @@ static void OVERLAY_outline_gpencil(OVERLAY_PrivateData *pd, Object *ob)
pd->cfra);
}
+static void OVERLAY_outline_volume(OVERLAY_PrivateData *pd, Object *ob)
+{
+ struct GPUBatch *geom = DRW_cache_volume_selection_surface_get(ob);
+ if (geom == NULL) {
+ return;
+ }
+
+ DRWShadingGroup *shgroup = pd->outlines_grp;
+ DRW_shgroup_call(shgroup, geom, ob);
+}
+
void OVERLAY_outline_cache_populate(OVERLAY_Data *vedata,
Object *ob,
OVERLAY_DupliData *dupli,
@@ -293,6 +304,11 @@ void OVERLAY_outline_cache_populate(OVERLAY_Data *vedata,
return;
}
+ if (ob->type == OB_VOLUME) {
+ OVERLAY_outline_volume(pd, ob);
+ return;
+ }
+
if (ob->type == OB_POINTCLOUD && pd->wireframe_mode) {
/* Looks bad in this case. Could be relaxed if we draw a
* wireframe of some sort in the future. */
diff --git a/source/blender/draw/engines/overlay/overlay_private.h b/source/blender/draw/engines/overlay/overlay_private.h
index 2cf2ca34801..ada2c2c8d1f 100644
--- a/source/blender/draw/engines/overlay/overlay_private.h
+++ b/source/blender/draw/engines/overlay/overlay_private.h
@@ -119,6 +119,7 @@ typedef struct OVERLAY_PassList {
DRWPass *particle_ps;
DRWPass *pointcloud_ps;
DRWPass *sculpt_mask_ps;
+ DRWPass *volume_ps;
DRWPass *wireframe_ps;
DRWPass *wireframe_xray_ps;
DRWPass *xray_fade_ps;
@@ -285,6 +286,7 @@ typedef struct OVERLAY_PrivateData {
DRWShadingGroup *particle_shapes_grp;
DRWShadingGroup *pointcloud_dots_grp;
DRWShadingGroup *sculpt_mask_grp;
+ DRWShadingGroup *volume_selection_surface_grp;
DRWShadingGroup *wires_grp[2][2]; /* With and without coloring. */
DRWShadingGroup *wires_all_grp[2][2]; /* With and without coloring. */
DRWShadingGroup *wires_hair_grp[2][2]; /* With and without coloring. */
@@ -511,6 +513,10 @@ void OVERLAY_edit_text_cache_init(OVERLAY_Data *vedata);
void OVERLAY_edit_text_cache_populate(OVERLAY_Data *vedata, Object *ob);
void OVERLAY_edit_text_draw(OVERLAY_Data *vedata);
+void OVERLAY_volume_cache_init(OVERLAY_Data *vedata);
+void OVERLAY_volume_cache_populate(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_volume_draw(OVERLAY_Data *vedata);
+
void OVERLAY_edit_mesh_init(OVERLAY_Data *vedata);
void OVERLAY_edit_mesh_cache_init(OVERLAY_Data *vedata);
void OVERLAY_edit_mesh_cache_populate(OVERLAY_Data *vedata, Object *ob);
diff --git a/source/blender/draw/engines/overlay/overlay_volume.c b/source/blender/draw/engines/overlay/overlay_volume.c
new file mode 100644
index 00000000000..ffa664c90d5
--- /dev/null
+++ b/source/blender/draw/engines/overlay/overlay_volume.c
@@ -0,0 +1,67 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DNA_volume_types.h"
+
+#include "DRW_render.h"
+#include "GPU_shader.h"
+
+#include "overlay_private.h"
+
+void OVERLAY_volume_cache_init(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ const bool is_select = DRW_state_is_select();
+
+ if (is_select) {
+ DRWState state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
+ DRW_PASS_CREATE(psl->volume_ps, state | pd->clipping_state);
+ GPUShader *sh = OVERLAY_shader_depth_only();
+ DRWShadingGroup *grp = DRW_shgroup_create(sh, psl->volume_ps);
+ pd->volume_selection_surface_grp = grp;
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ }
+}
+
+void OVERLAY_volume_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ const bool is_select = DRW_state_is_select();
+
+ if (is_select) {
+ struct GPUBatch *geom = DRW_cache_volume_selection_surface_get(ob);
+ if (geom != NULL) {
+ DRW_shgroup_call(pd->volume_selection_surface_grp, geom, ob);
+ }
+ }
+}
+
+void OVERLAY_volume_draw(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+ OVERLAY_FramebufferList *fbl = vedata->fbl;
+
+ if (DRW_state_is_fbo()) {
+ GPU_framebuffer_bind(fbl->overlay_default_fb);
+ }
+
+ DRW_draw_pass(psl->volume_ps);
+}
diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c
index 0fbc9e2ed82..52e7e91a995 100644
--- a/source/blender/draw/intern/draw_cache.c
+++ b/source/blender/draw/intern/draw_cache.c
@@ -3279,6 +3279,12 @@ GPUBatch *DRW_cache_volume_face_wireframe_get(Object *ob)
return DRW_volume_batch_cache_get_wireframes_face(ob->data);
}
+GPUBatch *DRW_cache_volume_selection_surface_get(Object *ob)
+{
+ BLI_assert(ob->type == OB_VOLUME);
+ return DRW_volume_batch_cache_get_selection_surface(ob->data);
+}
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/draw/intern/draw_cache.h b/source/blender/draw/intern/draw_cache.h
index 7164a477d8a..5da9f4b7964 100644
--- a/source/blender/draw/intern/draw_cache.h
+++ b/source/blender/draw/intern/draw_cache.h
@@ -236,6 +236,7 @@ typedef struct DRWVolumeGrid {
DRWVolumeGrid *DRW_volume_batch_cache_get_grid(struct Volume *volume, struct VolumeGrid *grid);
struct GPUBatch *DRW_cache_volume_face_wireframe_get(struct Object *ob);
+struct GPUBatch *DRW_cache_volume_selection_surface_get(struct Object *ob);
/* GPencil */
struct GPUBatch *DRW_cache_gpencil_strokes_get(struct Object *ob, int cfra);
diff --git a/source/blender/draw/intern/draw_cache_impl.h b/source/blender/draw/intern/draw_cache_impl.h
index 9e7a2e2916c..e5cc18f6e09 100644
--- a/source/blender/draw/intern/draw_cache_impl.h
+++ b/source/blender/draw/intern/draw_cache_impl.h
@@ -152,6 +152,7 @@ struct GPUBatch **DRW_cache_pointcloud_surface_shaded_get(struct Object *ob,
int DRW_volume_material_count_get(struct Volume *volume);
struct GPUBatch *DRW_volume_batch_cache_get_wireframes_face(struct Volume *volume);
+struct GPUBatch *DRW_volume_batch_cache_get_selection_surface(struct Volume *volume);
/* Mesh */
void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
diff --git a/source/blender/draw/intern/draw_cache_impl_volume.c b/source/blender/draw/intern/draw_cache_impl_volume.c
index e39c4976e38..7b03070e32b 100644
--- a/source/blender/draw/intern/draw_cache_impl_volume.c
+++ b/source/blender/draw/intern/draw_cache_impl_volume.c
@@ -62,6 +62,9 @@ typedef struct VolumeBatchCache {
GPUBatch *batch;
} face_wire;
+ /* Surface for selection */
+ GPUBatch *selection_surface;
+
/* settings to determine if cache is invalid */
bool is_dirty;
} VolumeBatchCache;
@@ -132,6 +135,7 @@ static void volume_batch_cache_clear(Volume *volume)
GPU_VERTBUF_DISCARD_SAFE(cache->face_wire.pos_nor_in_order);
GPU_BATCH_DISCARD_SAFE(cache->face_wire.batch);
+ GPU_BATCH_DISCARD_SAFE(cache->selection_surface);
}
void DRW_volume_batch_cache_free(Volume *volume)
@@ -209,6 +213,49 @@ GPUBatch *DRW_volume_batch_cache_get_wireframes_face(Volume *volume)
return cache->face_wire.batch;
}
+static void drw_volume_selection_surface_cb(
+ void *userdata, float (*verts)[3], int (*tris)[3], int totvert, int tottris)
+{
+ Volume *volume = userdata;
+ VolumeBatchCache *cache = volume->batch_cache;
+
+ static GPUVertFormat format = {0};
+ static uint pos_id;
+ if (format.attr_len == 0) {
+ pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ }
+
+ /* Create vertex buffer. */
+ GPUVertBuf *vbo_surface = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo_surface, totvert);
+ GPU_vertbuf_attr_fill(vbo_surface, pos_id, verts);
+
+ /* Create index buffer. */
+ GPUIndexBufBuilder elb;
+ GPU_indexbuf_init(&elb, GPU_PRIM_TRIS, tottris, totvert);
+ for (int i = 0; i < tottris; i++) {
+ GPU_indexbuf_add_tri_verts(&elb, UNPACK3(tris[i]));
+ }
+ GPUIndexBuf *ibo_surface = GPU_indexbuf_build(&elb);
+
+ cache->selection_surface = GPU_batch_create_ex(
+ GPU_PRIM_TRIS, vbo_surface, ibo_surface, GPU_BATCH_OWNS_VBO | GPU_BATCH_OWNS_INDEX);
+}
+
+GPUBatch *DRW_volume_batch_cache_get_selection_surface(Volume *volume)
+{
+ VolumeBatchCache *cache = volume_batch_cache_get(volume);
+ if (cache->selection_surface == NULL) {
+ VolumeGrid *volume_grid = BKE_volume_grid_active_get(volume);
+ if (volume_grid == NULL) {
+ return NULL;
+ }
+ BKE_volume_grid_selection_surface(
+ volume, volume_grid, drw_volume_selection_surface_cb, volume);
+ }
+ return cache->selection_surface;
+}
+
static DRWVolumeGrid *volume_grid_cache_get(Volume *volume,
VolumeGrid *grid,
VolumeBatchCache *cache)