Blender V5.0
extract_mesh_vbo_sculpt_data.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2021 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "BLI_array_utils.hh"
10#include "BLI_math_vector.h"
11
12#include "BKE_attribute.hh"
13#include "BKE_mesh.hh"
14#include "BKE_paint.hh"
15
16#include "draw_subdivision.hh"
17#include "extract_mesh.hh"
18
19namespace blender::draw {
20
22{
23 static const GPUVertFormat format = []() {
25 GPU_vertformat_attr_add(&format, "fset", gpu::VertAttrType::UNORM_8_8_8_8);
26 GPU_vertformat_attr_add(&format, "msk", gpu::VertAttrType::SFLOAT_32);
27 return format;
28 }();
29 return format;
30}
31
33{
36
37 struct gpuSculptData {
38 uchar4 face_set_color;
39 float mask;
40 };
41
42 MutableSpan vbo_data = vbo->data<gpuSculptData>();
43
44 const int default_face_set = mr.mesh->face_sets_color_default;
45 const int face_set_seed = mr.mesh->face_sets_color_seed;
47 const BMesh &bm = *mr.bm;
48 const int mask_offset = CustomData_get_offset_named(
49 &mr.bm->vdata, CD_PROP_FLOAT, ".sculpt_mask");
50 const int face_set_offset = CustomData_get_offset_named(
51 &mr.bm->pdata, CD_PROP_INT32, ".sculpt_face_set");
52 threading::parallel_for(IndexRange(bm.totface), 2048, [&](const IndexRange range) {
53 for (const int face_index : range) {
54 const BMFace &face = *BM_face_at_index(&const_cast<BMesh &>(bm), face_index);
55 const IndexRange face_range(BM_elem_index_get(BM_FACE_FIRST_LOOP(&face)), face.len);
56
57 uchar4 face_set_color(UCHAR_MAX);
58 if (face_set_offset != -1) {
59 const int face_set_id = BM_ELEM_CD_GET_INT(&face, face_set_offset);
60 if (face_set_id != default_face_set) {
61 BKE_paint_face_set_overlay_color_get(face_set_id, face_set_seed, face_set_color);
62 }
63 }
64 vbo_data.slice(face_range).fill(gpuSculptData{face_set_color, 0.0f});
65
66 if (mask_offset != -1) {
67 const BMLoop *loop = BM_FACE_FIRST_LOOP(&face);
68 for ([[maybe_unused]] const int i : IndexRange(face.len)) {
69 const int index = BM_elem_index_get(loop);
70 vbo_data[index].mask = BM_ELEM_CD_GET_FLOAT(loop->v, mask_offset);
71 loop = loop->next;
72 }
73 }
74 }
75 });
76 }
77 else {
78 const OffsetIndices faces = mr.faces;
79 const Span<int> corner_verts = mr.corner_verts;
80 const bke::AttributeAccessor attributes = mr.mesh->attributes();
81 const VArraySpan mask = *attributes.lookup<float>(".sculpt_mask", bke::AttrDomain::Point);
82 const VArraySpan face_set = *attributes.lookup<int>(".sculpt_face_set", bke::AttrDomain::Face);
83 threading::parallel_for(faces.index_range(), 1024, [&](const IndexRange range) {
84 for (const int face_index : range) {
85 const IndexRange face = faces[face_index];
86 uchar4 face_set_color(UCHAR_MAX);
87 if (!face_set.is_empty()) {
88 const int face_set_id = face_set[face_index];
89 if (face_set_id != default_face_set) {
90 BKE_paint_face_set_overlay_color_get(face_set_id, face_set_seed, face_set_color);
91 }
92 }
93 vbo_data.slice(face).fill(gpuSculptData{face_set_color, 0.0f});
94
95 if (!mask.is_empty()) {
96 for (const int corner : face) {
97 vbo_data[corner].mask = mask[corner_verts[corner]];
98 }
99 }
100 }
101 });
102 }
103 return vbo;
104}
105
107 const DRWSubdivCache &subdiv_cache)
108{
109 const Mesh &coarse_mesh = *mr.mesh;
110 const int subdiv_corners_num = subdiv_cache.num_subdiv_loops;
111
112 /* First, interpolate mask if available. */
113 gpu::VertBuf *mask_vbo = nullptr;
114 gpu::VertBuf *subdiv_mask_vbo = nullptr;
115
116 const bke::AttributeAccessor attributes = coarse_mesh.attributes();
117
118 if (const VArray mask = *attributes.lookup<float>(".sculpt_mask", bke::AttrDomain::Point)) {
119 GPUVertFormat mask_format = {0};
120 GPU_vertformat_attr_add(&mask_format, "msk", blender::gpu::VertAttrType::SFLOAT_32);
121 const Span<int> corner_verts = coarse_mesh.corner_verts();
122 mask_vbo = GPU_vertbuf_calloc();
123 GPU_vertbuf_init_with_format(*mask_vbo, mask_format);
124 GPU_vertbuf_data_alloc(*mask_vbo, corner_verts.size());
125
126 MutableSpan mask_vbo_data = mask_vbo->data<float>();
127 array_utils::gather(mask, corner_verts, mask_vbo_data);
128
129 subdiv_mask_vbo = GPU_vertbuf_calloc();
130 GPU_vertbuf_init_build_on_device(*subdiv_mask_vbo, mask_format, subdiv_corners_num);
131
132 draw_subdiv_interp_custom_data(subdiv_cache, *mask_vbo, *subdiv_mask_vbo, GPU_COMP_F32, 1, 0);
133 }
134
135 /* Then, gather face sets. */
136 GPUVertFormat face_set_format = {0};
137 GPU_vertformat_attr_add(&face_set_format, "msk", blender::gpu::VertAttrType::UNORM_8_8_8_8);
138
139 gpu::VertBuf *face_set_vbo = GPU_vertbuf_calloc();
140 GPU_vertbuf_init_with_format(*face_set_vbo, face_set_format);
141 GPU_vertbuf_data_alloc(*face_set_vbo, subdiv_corners_num);
142
143 struct gpuFaceSet {
145 };
146
147 MutableSpan face_set_vbo_data = face_set_vbo->data<gpuFaceSet>();
148 const VArraySpan face_sets = *attributes.lookup<int>(".sculpt_face_set", bke::AttrDomain::Face);
149 if (face_sets.is_empty()) {
150 face_set_vbo_data.fill({uchar4{UCHAR_MAX}});
151 }
152 else {
153 const Span<int> subdiv_loop_face_index(subdiv_cache.subdiv_loop_face_index,
154 subdiv_corners_num);
155 const int default_face_set = coarse_mesh.face_sets_color_default;
156 const int face_set_seed = coarse_mesh.face_sets_color_seed;
157 threading::parallel_for(IndexRange(subdiv_corners_num), 4096, [&](const IndexRange range) {
158 for (const int i : range) {
159 const int face_index = subdiv_loop_face_index[i];
160
161 uchar4 face_set_color(UCHAR_MAX);
162 const int face_set_id = face_sets[face_index];
163 /* Skip for the default color Face Set to render it white. */
164 if (face_set_id != default_face_set) {
165 BKE_paint_face_set_overlay_color_get(face_set_id, face_set_seed, face_set_color);
166 }
167
168 copy_v3_v3_uchar(face_set_vbo_data[i].color, face_set_color);
169 }
170 });
171 }
172
173 /* Finally, interleave mask and face sets. */
176
177 draw_subdiv_build_sculpt_data_buffer(subdiv_cache, subdiv_mask_vbo, face_set_vbo, vbo.get());
178
179 if (mask_vbo) {
180 GPU_vertbuf_discard(mask_vbo);
181 GPU_vertbuf_discard(subdiv_mask_vbo);
182 }
183 GPU_vertbuf_discard(face_set_vbo);
184 return vbo;
185}
186
187} // namespace blender::draw
int CustomData_get_offset_named(const CustomData *data, eCustomDataType type, blender::StringRef name)
void BKE_paint_face_set_overlay_color_get(int face_set, int seed, uchar r_color[4])
Definition paint.cc:3092
MINLINE void copy_v3_v3_uchar(unsigned char r[3], const unsigned char a[3])
@ CD_PROP_FLOAT
@ CD_PROP_INT32
blender::gpu::VertBuf * GPU_vertbuf_create_on_device(const GPUVertFormat &format, uint v_len)
void GPU_vertbuf_init_build_on_device(blender::gpu::VertBuf &verts, const GPUVertFormat &format, uint v_len)
static blender::gpu::VertBuf * GPU_vertbuf_create_with_format(const GPUVertFormat &format)
#define GPU_vertbuf_init_with_format(verts, format)
blender::gpu::VertBuf * GPU_vertbuf_calloc()
void GPU_vertbuf_data_alloc(blender::gpu::VertBuf &verts, uint v_len)
void GPU_vertbuf_discard(blender::gpu::VertBuf *)
uint GPU_vertformat_attr_add(GPUVertFormat *format, blender::StringRef name, blender::gpu::VertAttrType type)
@ GPU_COMP_F32
BMesh * bm
AttributeSet attributes
constexpr T * data() const
Definition BLI_span.hh:539
constexpr void fill(const T &value) const
Definition BLI_span.hh:517
constexpr int64_t size() const
Definition BLI_span.hh:252
GAttributeReader lookup(const StringRef attribute_id) const
MutableSpan< T > data()
Extraction of Mesh data into VBO to feed to GPU.
format
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
static char faces[256]
void gather(const GVArray &src, const IndexMask &indices, GMutableSpan dst, int64_t grain_size=4096)
void draw_subdiv_interp_custom_data(const DRWSubdivCache &cache, gpu::VertBuf &src_data, gpu::VertBuf &dst_data, GPUVertCompType comp_type, int dimensions, int dst_offset)
gpu::VertBufPtr extract_sculpt_data_subdiv(const MeshRenderData &mr, const DRWSubdivCache &subdiv_cache)
static const GPUVertFormat & get_sculpt_data_format()
void draw_subdiv_build_sculpt_data_buffer(const DRWSubdivCache &cache, gpu::VertBuf *mask_vbo, gpu::VertBuf *face_set_vbo, gpu::VertBuf *sculpt_data)
gpu::VertBufPtr extract_sculpt_data(const MeshRenderData &mr)
std::unique_ptr< gpu::VertBuf, gpu::VertBufDeleter > VertBufPtr
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
Definition BLI_task.hh:93
blender::VecBase< uint8_t, 4 > uchar4
CustomData vdata
CustomData pdata
int face_sets_color_seed
int face_sets_color_default
i
Definition text_draw.cc:230