Blender V4.3
extract_mesh_vbo_edituv_stretch_angle.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
9#include "BKE_attribute.hh"
10#include "BKE_mesh.hh"
11
12#include "extract_mesh.hh"
13
14#include "draw_subdivision.hh"
15
16namespace blender::draw {
17
19 /* NOTE: To more easily satisfy cross-platform alignment requirements, placing the 4-byte aligned
20 * 2 element array first ensures each attribute block is 4-byte aligned. */
23#if defined(WITH_METAL_BACKEND)
24 /* For apple platforms, vertex data struct must align to minimum per-vertex-stride of 4 bytes.
25 * Hence, this struct needs to align to 8 bytes. */
26 int16_t _pad0;
27#endif
28};
29#if defined(WITH_METAL_BACKEND)
31#endif
32
35 const float2 *uv;
36 float auv[2][2], last_auv[2];
37 float av[2][3], last_av[3];
38 int cd_ofs;
39};
40
41static void compute_normalize_edge_vectors(float auv[2][2],
42 float av[2][3],
43 const float uv[2],
44 const float uv_prev[2],
45 const float co[3],
46 const float co_prev[3])
47{
48 /* Move previous edge. */
49 copy_v2_v2(auv[0], auv[1]);
50 copy_v3_v3(av[0], av[1]);
51 /* 2d edge */
52 sub_v2_v2v2(auv[1], uv_prev, uv);
53 normalize_v2(auv[1]);
54 /* 3d edge */
55 sub_v3_v3v3(av[1], co_prev, co);
56 normalize_v3(av[1]);
57}
58
59static short v2_to_short_angle(const float v[2])
60{
61 return atan2f(v[1], v[0]) * float(M_1_PI) * SHRT_MAX;
62}
63
64static void edituv_get_edituv_stretch_angle(float auv[2][2],
65 const float av[2][3],
66 UVStretchAngle *r_stretch)
67{
68 /* Send UVs to the shader and let it compute the aspect corrected angle. */
69 r_stretch->uv_angles[0] = v2_to_short_angle(auv[0]);
70 r_stretch->uv_angles[1] = v2_to_short_angle(auv[1]);
71 /* Compute 3D angle here. */
72 r_stretch->angle = angle_normalized_v3v3(av[0], av[1]) * float(M_1_PI) * SHRT_MAX;
73
74#if 0 /* here for reference, this is done in shader now. */
75 float uvang = angle_normalized_v2v2(auv0, auv1);
76 float ang = angle_normalized_v3v3(av0, av1);
77 float stretch = fabsf(uvang - ang) / float(M_PI);
78 return 1.0f - pow2f(1.0f - stretch);
79#endif
80}
81
84{
85 const BMesh &bm = *mr.bm;
86 const int uv_offset = CustomData_get_offset(&bm.ldata, CD_PROP_FLOAT2);
87
88 float auv[2][2], last_auv[2];
89 float av[2][3], last_av[3];
90
91 const BMFace *face;
92 BMIter f_iter;
93 BM_ITER_MESH (face, &f_iter, &const_cast<BMesh &>(bm), BM_FACES_OF_MESH) {
94 BMLoop *l_iter, *l_first;
95 l_iter = l_first = BM_FACE_FIRST_LOOP(face);
96 do {
97 const int l_index = BM_elem_index_get(l_iter);
98
99 const float(*luv)[2], (*luv_next)[2];
100 BMLoop *l_next = l_iter->next;
101 if (l_iter == BM_FACE_FIRST_LOOP(face)) {
102 /* First loop in face. */
103 BMLoop *l_tmp = l_iter->prev;
104 BMLoop *l_next_tmp = l_iter;
105 luv = BM_ELEM_CD_GET_FLOAT2_P(l_tmp, uv_offset);
106 luv_next = BM_ELEM_CD_GET_FLOAT2_P(l_next_tmp, uv_offset);
108 av,
109 *luv,
110 *luv_next,
111 bm_vert_co_get(mr, l_tmp->v),
112 bm_vert_co_get(mr, l_next_tmp->v));
113 /* Save last edge. */
114 copy_v2_v2(last_auv, auv[1]);
115 copy_v3_v3(last_av, av[1]);
116 }
117 if (l_next == BM_FACE_FIRST_LOOP(face)) {
118 /* Move previous edge. */
119 copy_v2_v2(auv[0], auv[1]);
120 copy_v3_v3(av[0], av[1]);
121 /* Copy already calculated last edge. */
122 copy_v2_v2(auv[1], last_auv);
123 copy_v3_v3(av[1], last_av);
124 }
125 else {
126 luv = BM_ELEM_CD_GET_FLOAT2_P(l_iter, uv_offset);
127 luv_next = BM_ELEM_CD_GET_FLOAT2_P(l_next, uv_offset);
129 av,
130 *luv,
131 *luv_next,
132 bm_vert_co_get(mr, l_iter->v),
133 bm_vert_co_get(mr, l_next->v));
134 }
135 edituv_get_edituv_stretch_angle(auv, av, &vbo_data[l_index]);
136 } while ((l_iter = l_iter->next) != l_first);
137 }
138}
139
142{
143 const Span<float3> positions = mr.vert_positions;
144 const OffsetIndices faces = mr.faces;
145 const Span<int> corner_verts = mr.corner_verts;
146 const Mesh &mesh = *mr.mesh;
147 const bke::AttributeAccessor attributes = mesh.attributes();
148 const StringRef name = CustomData_get_active_layer_name(&mesh.corner_data, CD_PROP_FLOAT2);
149 const VArraySpan uv_map = *attributes.lookup<float2>(name, bke::AttrDomain::Corner);
150
151 float auv[2][2], last_auv[2];
152 float av[2][3], last_av[3];
153
154 for (const int face_index : faces.index_range()) {
155 const IndexRange face = faces[face_index];
156 const int corner_end = face.start() + face.size();
157 for (int corner = face.start(); corner < corner_end; corner += 1) {
158 int l_next = corner + 1;
159 if (corner == face.start()) {
160 /* First loop in face. */
161 const int corner_last = corner_end - 1;
162 const int l_next_tmp = face.start();
164 av,
165 uv_map[corner_last],
166 uv_map[l_next_tmp],
167 positions[corner_verts[corner_last]],
168 positions[corner_verts[l_next_tmp]]);
169 /* Save last edge. */
170 copy_v2_v2(last_auv, auv[1]);
171 copy_v3_v3(last_av, av[1]);
172 }
173 if (l_next == corner_end) {
174 l_next = face.start();
175 /* Move previous edge. */
176 copy_v2_v2(auv[0], auv[1]);
177 copy_v3_v3(av[0], av[1]);
178 /* Copy already calculated last edge. */
179 copy_v2_v2(auv[1], last_auv);
180 copy_v3_v3(av[1], last_av);
181 }
182 else {
184 av,
185 uv_map[corner],
186 uv_map[l_next],
187 positions[corner_verts[corner]],
188 positions[corner_verts[l_next]]);
189 }
190 edituv_get_edituv_stretch_angle(auv, av, &vbo_data[corner]);
191 }
192 }
193}
194
196{
197 static GPUVertFormat format = {0};
198 if (format.attr_len == 0) {
199 /* Waning: adjust #UVStretchAngle struct accordingly. */
202 }
205 MutableSpan vbo_data = vbo.data<UVStretchAngle>();
206
207 if (mr.extract_type == MR_EXTRACT_BMESH) {
208 extract_uv_stretch_angle_bm(mr, vbo_data);
209 }
210 else {
211 extract_uv_stretch_angle_mesh(mr, vbo_data);
212 }
213}
214
216{
217 static GPUVertFormat format = {0};
218 if (format.attr_len == 0) {
219 /* Waning: adjust #UVStretchAngle struct accordingly. */
222 }
223 return format;
224}
225
227 const DRWSubdivCache &subdiv_cache,
228 const MeshBatchCache &cache,
229 gpu::VertBuf &vbo)
230{
233
234 gpu::VertBuf *pos_nor = cache.final.buff.vbo.pos;
235 gpu::VertBuf *uvs = cache.final.buff.vbo.uv;
236
237 /* It may happen that the data for the UV editor is requested before (as a separate draw update)
238 * the data for the mesh when switching to the `UV Editing` workspace, and therefore the position
239 * buffer might not be created yet. In this case, create a buffer it locally, the subdivision
240 * data should already be evaluated if we are here. This can happen if the subsurf modifier is
241 * only enabled in edit-mode. See #96338. */
242 if (!pos_nor) {
243 pos_nor = GPU_vertbuf_calloc();
245 *pos_nor, draw_subdiv_get_pos_nor_format(), subdiv_full_vbo_size(mr, subdiv_cache));
246
247 draw_subdiv_extract_pos_nor(subdiv_cache, nullptr, pos_nor, nullptr);
248 }
249
250 /* UVs are stored contiguously so we need to compute the offset in the UVs buffer for the active
251 * UV layer. */
252 const CustomData *cd_ldata = (mr.extract_type == MR_EXTRACT_MESH) ? &mr.mesh->corner_data :
253 &mr.bm->ldata;
254
255 uint32_t uv_layers = cache.cd_used.uv;
256 /* HACK to fix #68857 */
257 if (mr.extract_type == MR_EXTRACT_BMESH && cache.cd_used.edit_uv == 1) {
258 int layer = CustomData_get_active_layer(cd_ldata, CD_PROP_FLOAT2);
259 if (layer != -1 && !CustomData_layer_is_anonymous(cd_ldata, CD_PROP_FLOAT2, layer)) {
260 uv_layers |= (1 << layer);
261 }
262 }
263
264 int uvs_offset = 0;
265 for (int i = 0; i < MAX_MTFACE; i++) {
266 if (uv_layers & (1 << i)) {
267 if (i == CustomData_get_active_layer(cd_ldata, CD_PROP_FLOAT2)) {
268 break;
269 }
270
271 uvs_offset += 1;
272 }
273 }
274
275 /* The data is at `offset * num loops`, and we have 2 values per index. */
276 uvs_offset *= subdiv_cache.num_subdiv_loops * 2;
277
278 draw_subdiv_build_edituv_stretch_angle_buffer(subdiv_cache, pos_nor, uvs, uvs_offset, &vbo);
279
280 if (!cache.final.buff.vbo.pos) {
281 GPU_vertbuf_discard(pos_nor);
282 }
283}
284
285} // namespace blender::draw
int CustomData_get_offset(const CustomData *data, eCustomDataType type)
bool CustomData_layer_is_anonymous(const CustomData *data, eCustomDataType type, int n)
int CustomData_get_active_layer(const CustomData *data, eCustomDataType type)
const char * CustomData_get_active_layer_name(const CustomData *data, eCustomDataType type)
#define BLI_STATIC_ASSERT_ALIGN(st, align)
Definition BLI_assert.h:90
#define M_1_PI
MINLINE float pow2f(float x)
#define M_PI
float angle_normalized_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void sub_v2_v2v2(float r[2], const float a[2], const float b[2])
MINLINE float normalize_v2(float n[2])
float angle_normalized_v3v3(const float v1[3], const float v2[3]) ATTR_WARN_UNUSED_RESULT
MINLINE float normalize_v3(float n[3])
@ CD_PROP_FLOAT2
#define MAX_MTFACE
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_I16
#define BM_ELEM_CD_GET_FLOAT2_P(ele, offset)
#define BM_FACE_FIRST_LOOP(p)
#define BM_elem_index_get(ele)
#define BM_ITER_MESH(ele, iter, bm, itype)
@ BM_FACES_OF_MESH
ATTR_WARN_UNUSED_RESULT BMesh * bm
ATTR_WARN_UNUSED_RESULT const BMVert * v
constexpr int64_t start() const
MutableSpan< T > data()
#define atan2f(x, y)
#define fabsf(x)
draw_view in_light_buf[] float
Extraction of Mesh data into VBO to feed to GPU.
format
static void compute_normalize_edge_vectors(float auv[2][2], float av[2][3], const float uv[2], const float uv_prev[2], const float co[3], const float co_prev[3])
void extract_edituv_stretch_angle(const MeshRenderData &mr, gpu::VertBuf &vbo)
static void extract_uv_stretch_angle_bm(const MeshRenderData &mr, MutableSpan< UVStretchAngle > vbo_data)
static const GPUVertFormat & get_edituv_stretch_angle_format_subdiv()
static short v2_to_short_angle(const float v[2])
static void extract_uv_stretch_angle_mesh(const MeshRenderData &mr, MutableSpan< UVStretchAngle > vbo_data)
static void edituv_get_edituv_stretch_angle(float auv[2][2], const float av[2][3], UVStretchAngle *r_stretch)
void draw_subdiv_extract_pos_nor(const DRWSubdivCache &cache, gpu::VertBuf *flags_buffer, gpu::VertBuf *pos_nor, gpu::VertBuf *orco)
int subdiv_full_vbo_size(const MeshRenderData &mr, const DRWSubdivCache &cache)
void extract_edituv_stretch_angle_subdiv(const MeshRenderData &mr, const DRWSubdivCache &subdiv_cache, const MeshBatchCache &cache, gpu::VertBuf &vbo)
BLI_INLINE const float * bm_vert_co_get(const MeshRenderData &mr, const BMVert *eve)
const GPUVertFormat & draw_subdiv_get_pos_nor_format()
void draw_subdiv_build_edituv_stretch_angle_buffer(const DRWSubdivCache &cache, gpu::VertBuf *pos_nor, gpu::VertBuf *uvs, int uvs_offset, gpu::VertBuf *stretch_angles)
signed short int16_t
Definition stdint.h:76
unsigned int uint32_t
Definition stdint.h:80
struct BMVert * v
struct BMLoop * prev
struct BMLoop * next
CustomData ldata
CustomData corner_data
struct blender::draw::MeshBufferList::@247 vbo
OffsetIndices< int > faces