Blender V4.3
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 "MEM_guardedalloc.h"
10
11#include "BLI_array_utils.hh"
12#include "BLI_string.h"
13
14#include "BKE_attribute.hh"
15#include "BKE_mesh.hh"
16#include "BKE_paint.hh"
17
18#include "draw_subdivision.hh"
19#include "extract_mesh.hh"
20
21namespace blender::draw {
22
24{
25 static GPUVertFormat format = {0};
26 if (format.attr_len == 0) {
29 }
30 return format;
31}
32
34{
37
38 struct gpuSculptData {
39 uchar4 face_set_color;
40 float mask;
41 };
42
43 MutableSpan vbo_data = vbo.data<gpuSculptData>();
44
45 const int default_face_set = mr.mesh->face_sets_color_default;
46 const int face_set_seed = mr.mesh->face_sets_color_seed;
48 const BMesh &bm = *mr.bm;
49 const int mask_offset = CustomData_get_offset_named(
50 &mr.bm->vdata, CD_PROP_FLOAT, ".sculpt_mask");
51 const int face_set_offset = CustomData_get_offset_named(
52 &mr.bm->pdata, CD_PROP_INT32, ".sculpt_face_set");
53 threading::parallel_for(IndexRange(bm.totface), 2048, [&](const IndexRange range) {
54 for (const int face_index : range) {
55 const BMFace &face = *BM_face_at_index(&const_cast<BMesh &>(bm), face_index);
56 const IndexRange face_range(BM_elem_index_get(BM_FACE_FIRST_LOOP(&face)), face.len);
57
58 uchar4 face_set_color(UCHAR_MAX);
59 if (face_set_offset != -1) {
60 const int face_set_id = BM_ELEM_CD_GET_INT(&face, face_set_offset);
61 if (face_set_id != default_face_set) {
62 BKE_paint_face_set_overlay_color_get(face_set_id, face_set_seed, face_set_color);
63 }
64 }
65 vbo_data.slice(face_range).fill(gpuSculptData{face_set_color, 0.0f});
66
67 if (mask_offset != -1) {
68 const BMLoop *loop = BM_FACE_FIRST_LOOP(&face);
69 for ([[maybe_unused]] const int i : IndexRange(face.len)) {
70 const int index = BM_elem_index_get(loop);
71 vbo_data[index].mask = BM_ELEM_CD_GET_FLOAT(loop->v, mask_offset);
72 loop = loop->next;
73 }
74 }
75 }
76 });
77 }
78 else {
79 const OffsetIndices faces = mr.faces;
80 const Span<int> corner_verts = mr.corner_verts;
81 const bke::AttributeAccessor attributes = mr.mesh->attributes();
82 const VArraySpan mask = *attributes.lookup<float>(".sculpt_mask", bke::AttrDomain::Point);
83 const VArraySpan face_set = *attributes.lookup<int>(".sculpt_face_set", bke::AttrDomain::Face);
84 threading::parallel_for(faces.index_range(), 1024, [&](const IndexRange range) {
85 for (const int face_index : range) {
86 const IndexRange face = faces[face_index];
87 uchar4 face_set_color(UCHAR_MAX);
88 if (!face_set.is_empty()) {
89 const int face_set_id = face_set[face_index];
90 if (face_set_id != default_face_set) {
91 BKE_paint_face_set_overlay_color_get(face_set_id, face_set_seed, face_set_color);
92 }
93 }
94 vbo_data.slice(face).fill(gpuSculptData{face_set_color, 0.0f});
95
96 if (!mask.is_empty()) {
97 for (const int corner : face) {
98 vbo_data[corner].mask = mask[corner_verts[corner]];
99 }
100 }
101 }
102 });
103 }
104}
105
107 const DRWSubdivCache &subdiv_cache,
108 gpu::VertBuf &vbo)
109{
110 const Mesh &coarse_mesh = *mr.mesh;
111 const int subdiv_corners_num = subdiv_cache.num_subdiv_loops;
112
113 /* First, interpolate mask if available. */
114 gpu::VertBuf *mask_vbo = nullptr;
115 gpu::VertBuf *subdiv_mask_vbo = nullptr;
116
117 const bke::AttributeAccessor attributes = coarse_mesh.attributes();
118
119 if (const VArray mask = *attributes.lookup<float>(".sculpt_mask", bke::AttrDomain::Point)) {
120 GPUVertFormat mask_format = {0};
121 GPU_vertformat_attr_add(&mask_format, "msk", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
122 const Span<int> corner_verts = coarse_mesh.corner_verts();
123 mask_vbo = GPU_vertbuf_calloc();
124 GPU_vertbuf_init_with_format(*mask_vbo, mask_format);
125 GPU_vertbuf_data_alloc(*mask_vbo, corner_verts.size());
126
127 MutableSpan mask_vbo_data = mask_vbo->data<float>();
128 array_utils::gather(mask, corner_verts, mask_vbo_data);
129
130 subdiv_mask_vbo = GPU_vertbuf_calloc();
131 GPU_vertbuf_init_build_on_device(*subdiv_mask_vbo, mask_format, subdiv_corners_num);
132
133 draw_subdiv_interp_custom_data(subdiv_cache, *mask_vbo, *subdiv_mask_vbo, GPU_COMP_F32, 1, 0);
134 }
135
136 /* Then, gather face sets. */
137 GPUVertFormat face_set_format = {0};
139
140 gpu::VertBuf *face_set_vbo = GPU_vertbuf_calloc();
141 GPU_vertbuf_init_with_format(*face_set_vbo, face_set_format);
142 GPU_vertbuf_data_alloc(*face_set_vbo, subdiv_corners_num);
143
144 struct gpuFaceSet {
146 };
147
148 MutableSpan face_set_vbo_data = face_set_vbo->data<gpuFaceSet>();
149 const VArraySpan face_sets = *attributes.lookup<int>(".sculpt_face_set", bke::AttrDomain::Face);
150 if (face_sets.is_empty()) {
151 face_set_vbo_data.fill({uchar4{UCHAR_MAX}});
152 }
153 else {
154 const Span<int> subdiv_loop_face_index(subdiv_cache.subdiv_loop_face_index,
155 subdiv_corners_num);
156 const int default_face_set = coarse_mesh.face_sets_color_default;
157 const int face_set_seed = coarse_mesh.face_sets_color_seed;
158 threading::parallel_for(IndexRange(subdiv_corners_num), 4096, [&](const IndexRange range) {
159 for (const int i : range) {
160 const int face_index = subdiv_loop_face_index[i];
161
162 uchar4 face_set_color(UCHAR_MAX);
163 const int face_set_id = face_sets[face_index];
164 /* Skip for the default color Face Set to render it white. */
165 if (face_set_id != default_face_set) {
166 BKE_paint_face_set_overlay_color_get(face_set_id, face_set_seed, face_set_color);
167 }
168
169 copy_v3_v3_uchar(face_set_vbo_data[i].color, face_set_color);
170 }
171 });
172 }
173
174 /* Finally, interleave mask and face sets. */
176 draw_subdiv_build_sculpt_data_buffer(subdiv_cache, subdiv_mask_vbo, face_set_vbo, &vbo);
177
178 if (mask_vbo) {
179 GPU_vertbuf_discard(mask_vbo);
180 GPU_vertbuf_discard(subdiv_mask_vbo);
181 }
182 GPU_vertbuf_discard(face_set_vbo);
183}
184
185} // 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:2886
MINLINE void copy_v3_v3_uchar(unsigned char r[3], const unsigned char a[3])
@ CD_PROP_FLOAT
@ CD_PROP_INT32
void GPU_vertbuf_init_build_on_device(blender::gpu::VertBuf &verts, const GPUVertFormat &format, uint v_len)
#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 *)
@ GPU_FETCH_FLOAT
@ GPU_FETCH_INT_TO_FLOAT_UNIT
uint GPU_vertformat_attr_add(GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
@ GPU_COMP_F32
@ GPU_COMP_U8
Read Guarded memory(de)allocation.
ATTR_WARN_UNUSED_RESULT BMesh * bm
AttributeSet attributes
constexpr void fill(const T &value) const
Definition BLI_span.hh:518
constexpr int64_t size() const
Definition BLI_span.hh:253
GAttributeReader lookup(const StringRef attribute_id) const
MutableSpan< T > data()
Extraction of Mesh data into VBO to feed to GPU.
format
ccl_device_inline float4 mask(const int4 mask, const float4 a)
static char faces[256]
void gather(const GVArray &src, const IndexMask &indices, GMutableSpan dst, int64_t grain_size=4096)
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)
void draw_subdiv_interp_custom_data(const DRWSubdivCache &cache, gpu::VertBuf &src_data, gpu::VertBuf &dst_data, int comp_type, int dimensions, int dst_offset)
void extract_sculpt_data(const MeshRenderData &mr, gpu::VertBuf &vbo)
void extract_sculpt_data_subdiv(const MeshRenderData &mr, const DRWSubdivCache &subdiv_cache, gpu::VertBuf &vbo)
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:95
blender::VecBase< uint8_t, 4 > uchar4
CustomData vdata
CustomData pdata
int face_sets_color_seed
int face_sets_color_default