Blender V5.0
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
8
9#include "BLI_math_vector.h"
10
11#include "BKE_attribute.hh"
12#include "BKE_mesh.hh"
13
14#include "extract_mesh.hh"
15
16#include "draw_subdivision.hh"
17
18namespace blender::draw {
19
21 float angle;
22 int16_t uv_angles[2];
23};
25
28 const float2 *uv;
29 float auv[2][2], last_auv[2];
30 float av[2][3], last_av[3];
31 int cd_ofs;
32};
33
34static void compute_normalize_edge_vectors(float auv[2][2],
35 float av[2][3],
36 const float uv[2],
37 const float uv_prev[2],
38 const float co[3],
39 const float co_prev[3])
40{
41 /* Move previous edge. */
42 copy_v2_v2(auv[0], auv[1]);
43 copy_v3_v3(av[0], av[1]);
44 /* 2d edge */
45 sub_v2_v2v2(auv[1], uv_prev, uv);
46 normalize_v2(auv[1]);
47 /* 3d edge */
48 sub_v3_v3v3(av[1], co_prev, co);
49 normalize_v3(av[1]);
50}
51
52static short v2_to_short_angle(const float v[2])
53{
54 return atan2f(v[1], v[0]) * float(M_1_PI) * SHRT_MAX;
55}
56
57static void edituv_get_edituv_stretch_angle(float auv[2][2],
58 const float av[2][3],
59 UVStretchAngle *r_stretch)
60{
61 /* Send UVs to the shader and let it compute the aspect corrected angle. */
62 r_stretch->uv_angles[0] = v2_to_short_angle(auv[0]);
63 r_stretch->uv_angles[1] = v2_to_short_angle(auv[1]);
64 /* Compute 3D angle here. */
65 r_stretch->angle = angle_normalized_v3v3(av[0], av[1]) * float(M_1_PI);
66
67#if 0 /* here for reference, this is done in shader now. */
68 float uvang = angle_normalized_v2v2(auv0, auv1);
69 float ang = angle_normalized_v3v3(av0, av1);
70 float stretch = fabsf(uvang - ang) / float(M_PI);
71 return 1.0f - pow2f(1.0f - stretch);
72#endif
73}
74
77{
78 const BMesh &bm = *mr.bm;
79 const int uv_offset = CustomData_get_offset(&bm.ldata, CD_PROP_FLOAT2);
80
81 float auv[2][2], last_auv[2];
82 float av[2][3], last_av[3];
83
84 const BMFace *face;
85 BMIter f_iter;
86 BM_ITER_MESH (face, &f_iter, &const_cast<BMesh &>(bm), BM_FACES_OF_MESH) {
87 BMLoop *l_iter, *l_first;
88 l_iter = l_first = BM_FACE_FIRST_LOOP(face);
89 do {
90 const int l_index = BM_elem_index_get(l_iter);
91
92 const float (*luv)[2], (*luv_next)[2];
93 BMLoop *l_next = l_iter->next;
94 if (l_iter == BM_FACE_FIRST_LOOP(face)) {
95 /* First loop in face. */
96 BMLoop *l_tmp = l_iter->prev;
97 BMLoop *l_next_tmp = l_iter;
98 luv = BM_ELEM_CD_GET_FLOAT2_P(l_tmp, uv_offset);
99 luv_next = BM_ELEM_CD_GET_FLOAT2_P(l_next_tmp, uv_offset);
101 av,
102 *luv,
103 *luv_next,
104 bm_vert_co_get(mr, l_tmp->v),
105 bm_vert_co_get(mr, l_next_tmp->v));
106 /* Save last edge. */
107 copy_v2_v2(last_auv, auv[1]);
108 copy_v3_v3(last_av, av[1]);
109 }
110 if (l_next == BM_FACE_FIRST_LOOP(face)) {
111 /* Move previous edge. */
112 copy_v2_v2(auv[0], auv[1]);
113 copy_v3_v3(av[0], av[1]);
114 /* Copy already calculated last edge. */
115 copy_v2_v2(auv[1], last_auv);
116 copy_v3_v3(av[1], last_av);
117 }
118 else {
119 luv = BM_ELEM_CD_GET_FLOAT2_P(l_iter, uv_offset);
120 luv_next = BM_ELEM_CD_GET_FLOAT2_P(l_next, uv_offset);
122 av,
123 *luv,
124 *luv_next,
125 bm_vert_co_get(mr, l_iter->v),
126 bm_vert_co_get(mr, l_next->v));
127 }
128 edituv_get_edituv_stretch_angle(auv, av, &vbo_data[l_index]);
129 } while ((l_iter = l_iter->next) != l_first);
130 }
131}
132
135{
136 const Span<float3> positions = mr.vert_positions;
137 const OffsetIndices faces = mr.faces;
138 const Span<int> corner_verts = mr.corner_verts;
139 const Mesh &mesh = *mr.mesh;
140 const bke::AttributeAccessor attributes = mesh.attributes();
142 const VArraySpan uv_map = *attributes.lookup<float2>(name, bke::AttrDomain::Corner);
143
144 float auv[2][2], last_auv[2];
145 float av[2][3], last_av[3];
146
147 for (const int face_index : faces.index_range()) {
148 const IndexRange face = faces[face_index];
149 const int corner_end = face.start() + face.size();
150 for (int corner = face.start(); corner < corner_end; corner += 1) {
151 int l_next = corner + 1;
152 if (corner == face.start()) {
153 /* First loop in face. */
154 const int corner_last = corner_end - 1;
155 const int l_next_tmp = face.start();
157 av,
158 uv_map[corner_last],
159 uv_map[l_next_tmp],
160 positions[corner_verts[corner_last]],
161 positions[corner_verts[l_next_tmp]]);
162 /* Save last edge. */
163 copy_v2_v2(last_auv, auv[1]);
164 copy_v3_v3(last_av, av[1]);
165 }
166 if (l_next == corner_end) {
167 l_next = face.start();
168 /* Move previous edge. */
169 copy_v2_v2(auv[0], auv[1]);
170 copy_v3_v3(av[0], av[1]);
171 /* Copy already calculated last edge. */
172 copy_v2_v2(auv[1], last_auv);
173 copy_v3_v3(av[1], last_av);
174 }
175 else {
177 av,
178 uv_map[corner],
179 uv_map[l_next],
180 positions[corner_verts[corner]],
181 positions[corner_verts[l_next]]);
182 }
183 edituv_get_edituv_stretch_angle(auv, av, &vbo_data[corner]);
184 }
185 }
186}
187
189{
190 static const GPUVertFormat format = []() {
192 /* Waning: adjust #UVStretchAngle struct accordingly. */
193 GPU_vertformat_attr_add(&format, "angle", gpu::VertAttrType::SFLOAT_32);
194 GPU_vertformat_attr_add(&format, "uv_angles", gpu::VertAttrType::SNORM_16_16);
195 return format;
196 }();
197
200 MutableSpan vbo_data = vbo->data<UVStretchAngle>();
201
203 extract_uv_stretch_angle_bm(mr, vbo_data);
204 }
205 else {
206 extract_uv_stretch_angle_mesh(mr, vbo_data);
207 }
208 return vbo;
209}
210
212{
213 static const GPUVertFormat format = []() {
215 /* Waning: adjust #UVStretchAngle struct accordingly. */
216 GPU_vertformat_attr_add(&format, "angle", gpu::VertAttrType::SFLOAT_32);
217 GPU_vertformat_attr_add(&format, "uv_angles", gpu::VertAttrType::SFLOAT_32_32);
218 return format;
219 }();
220 return format;
221}
222
224 const DRWSubdivCache &subdiv_cache,
225 const MeshBatchCache &cache)
226{
229
230 gpu::VertBuf *pos = cache.final.buff.vbos.lookup(VBOType::Position).get();
231 gpu::VertBuf *uvs = cache.final.buff.vbos.lookup(VBOType::UVs).get();
232
233 /* It may happen that the data for the UV editor is requested before (as a separate draw update)
234 * the data for the mesh when switching to the `UV Editing` workspace, and therefore the position
235 * buffer might not be created yet. In this case, create a buffer it locally, the subdivision
236 * data should already be evaluated if we are here. This can happen if the subsurf modifier is
237 * only enabled in edit-mode. See #96338. */
238 if (!pos) {
240 static const GPUVertFormat pos_format = GPU_vertformat_from_attribute(
241 "pos", gpu::VertAttrType::SFLOAT_32_32_32);
242 GPU_vertbuf_init_build_on_device(*pos, pos_format, subdiv_full_vbo_size(mr, subdiv_cache));
243 draw_subdiv_extract_pos(subdiv_cache, pos, nullptr);
244 }
245
246 /* UVs are stored contiguously so we need to compute the offset in the UVs buffer for the active
247 * UV layer. */
248 const CustomData *cd_ldata = (mr.extract_type == MeshExtractType::Mesh) ? &mr.mesh->corner_data :
249 &mr.bm->ldata;
250
251 uint32_t uv_layers = cache.cd_used.uv;
252 /* HACK to fix #68857 */
253 if (mr.extract_type == MeshExtractType::BMesh && cache.cd_used.edit_uv == 1) {
254 int layer = CustomData_get_active_layer(cd_ldata, CD_PROP_FLOAT2);
255 if (layer != -1 && !CustomData_layer_is_anonymous(cd_ldata, CD_PROP_FLOAT2, layer)) {
256 uv_layers |= (1 << layer);
257 }
258 }
259
260 int uvs_offset = 0;
261 for (int i = 0; i < MAX_MTFACE; i++) {
262 if (uv_layers & (1 << i)) {
263 if (i == CustomData_get_active_layer(cd_ldata, CD_PROP_FLOAT2)) {
264 break;
265 }
266
267 uvs_offset += 1;
268 }
269 }
270
271 /* The data is at `offset * num loops`, and we have 2 values per index. */
272 uvs_offset *= subdiv_cache.num_subdiv_loops * 2;
273
274 draw_subdiv_build_edituv_stretch_angle_buffer(subdiv_cache, pos, uvs, uvs_offset, vbo.get());
275 return vbo;
276}
277
278} // 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:86
MINLINE float pow2f(float x)
#define M_1_PI
#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
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)
blender::gpu::VertBuf * GPU_vertbuf_calloc()
void GPU_vertbuf_data_alloc(blender::gpu::VertBuf &verts, uint v_len)
GPUVertFormat GPU_vertformat_from_attribute(blender::StringRef name, blender::gpu::VertAttrType type)
uint GPU_vertformat_attr_add(GPUVertFormat *format, blender::StringRef name, blender::gpu::VertAttrType type)
#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
BMesh * bm
ATTR_WARN_UNUSED_RESULT const BMVert * v
AttributeSet attributes
constexpr int64_t size() const
constexpr int64_t start() const
constexpr T * data() const
Definition BLI_span.hh:539
GAttributeReader lookup(const StringRef attribute_id) const
nullptr float
Extraction of Mesh data into VBO to feed to GPU.
uint pos
format
static char faces[256]
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])
gpu::VertBufPtr extract_edituv_stretch_angle_subdiv(const MeshRenderData &mr, const DRWSubdivCache &subdiv_cache, const MeshBatchCache &cache)
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)
void draw_subdiv_extract_pos(const DRWSubdivCache &cache, gpu::VertBuf *pos, gpu::VertBuf *orco)
static void edituv_get_edituv_stretch_angle(float auv[2][2], const float av[2][3], UVStretchAngle *r_stretch)
int subdiv_full_vbo_size(const MeshRenderData &mr, const DRWSubdivCache &cache)
void draw_subdiv_build_edituv_stretch_angle_buffer(const DRWSubdivCache &cache, gpu::VertBuf *pos, gpu::VertBuf *uvs, int uvs_offset, gpu::VertBuf *stretch_angles)
gpu::VertBufPtr extract_edituv_stretch_angle(const MeshRenderData &mr)
BLI_INLINE const float * bm_vert_co_get(const MeshRenderData &mr, const BMVert *eve)
std::unique_ptr< gpu::VertBuf, gpu::VertBufDeleter > VertBufPtr
VecBase< float, 2 > float2
const char * name
#define fabsf
#define atan2f
struct BMVert * v
struct BMLoop * prev
struct BMLoop * next
CustomData ldata
CustomData corner_data
Map< VBOType, std::unique_ptr< gpu::VertBuf, gpu::VertBufDeleter > > vbos
OffsetIndices< int > faces
i
Definition text_draw.cc:230