Blender  V3.3
extract_mesh_vbo_edituv_stretch_angle.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2021 Blender Foundation. All rights reserved. */
3 
8 #include "MEM_guardedalloc.h"
9 
10 #include "BKE_mesh.h"
11 
12 #include "extract_mesh.hh"
13 
14 #include "draw_subdivision.h"
15 
16 namespace blender::draw {
17 
18 /* ---------------------------------------------------------------------- */
25 };
26 
29  const MLoopUV *luv;
30  float auv[2][2], last_auv[2];
31  float av[2][3], last_av[3];
32  int cd_ofs;
33 };
34 
35 static void compute_normalize_edge_vectors(float auv[2][2],
36  float av[2][3],
37  const float uv[2],
38  const float uv_prev[2],
39  const float co[3],
40  const float co_prev[3])
41 {
42  /* Move previous edge. */
43  copy_v2_v2(auv[0], auv[1]);
44  copy_v3_v3(av[0], av[1]);
45  /* 2d edge */
46  sub_v2_v2v2(auv[1], uv_prev, uv);
47  normalize_v2(auv[1]);
48  /* 3d edge */
49  sub_v3_v3v3(av[1], co_prev, co);
50  normalize_v3(av[1]);
51 }
52 
53 static short v2_to_short_angle(const float v[2])
54 {
55  return atan2f(v[1], v[0]) * (float)M_1_PI * SHRT_MAX;
56 }
57 
58 static void edituv_get_edituv_stretch_angle(float auv[2][2],
59  const float av[2][3],
60  UVStretchAngle *r_stretch)
61 {
62  /* Send UV's to the shader and let it compute the aspect corrected angle. */
63  r_stretch->uv_angles[0] = v2_to_short_angle(auv[0]);
64  r_stretch->uv_angles[1] = v2_to_short_angle(auv[1]);
65  /* Compute 3D angle here. */
66  r_stretch->angle = angle_normalized_v3v3(av[0], av[1]) * (float)M_1_PI * SHRT_MAX;
67 
68 #if 0 /* here for reference, this is done in shader now. */
69  float uvang = angle_normalized_v2v2(auv0, auv1);
70  float ang = angle_normalized_v3v3(av0, av1);
71  float stretch = fabsf(uvang - ang) / (float)M_PI;
72  return 1.0f - pow2f(1.0f - stretch);
73 #endif
74 }
75 
77  MeshBatchCache *UNUSED(cache),
78  void *buf,
79  void *tls_data)
80 {
81  GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
82  static GPUVertFormat format = {0};
83  if (format.attr_len == 0) {
84  /* Waning: adjust #UVStretchAngle struct accordingly. */
87  }
88 
91 
93  data->vbo_data = (UVStretchAngle *)GPU_vertbuf_get_data(vbo);
94 
95  /* Special iterator needed to save about half of the computing cost. */
96  if (mr->extract_type == MR_EXTRACT_BMESH) {
97  data->cd_ofs = CustomData_get_offset(&mr->bm->ldata, CD_MLOOPUV);
98  }
99  else {
101  data->luv = (const MLoopUV *)CustomData_get_layer(&mr->me->ldata, CD_MLOOPUV);
102  }
103 }
104 
106  const BMFace *f,
107  const int UNUSED(f_index),
108  void *_data)
109 {
111  float(*auv)[2] = data->auv, *last_auv = data->last_auv;
112  float(*av)[3] = data->av, *last_av = data->last_av;
113  BMLoop *l_iter, *l_first;
114  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
115  do {
116  const int l_index = BM_elem_index_get(l_iter);
117 
118  const MLoopUV *luv, *luv_next;
119  BMLoop *l_next = l_iter->next;
120  if (l_iter == BM_FACE_FIRST_LOOP(f)) {
121  /* First loop in face. */
122  BMLoop *l_tmp = l_iter->prev;
123  BMLoop *l_next_tmp = l_iter;
124  luv = (const MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_tmp, data->cd_ofs);
125  luv_next = (const MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_next_tmp, data->cd_ofs);
127  av,
128  luv->uv,
129  luv_next->uv,
130  bm_vert_co_get(mr, l_tmp->v),
131  bm_vert_co_get(mr, l_next_tmp->v));
132  /* Save last edge. */
133  copy_v2_v2(last_auv, auv[1]);
134  copy_v3_v3(last_av, av[1]);
135  }
136  if (l_next == BM_FACE_FIRST_LOOP(f)) {
137  /* Move previous edge. */
138  copy_v2_v2(auv[0], auv[1]);
139  copy_v3_v3(av[0], av[1]);
140  /* Copy already calculated last edge. */
141  copy_v2_v2(auv[1], last_auv);
142  copy_v3_v3(av[1], last_av);
143  }
144  else {
145  luv = (const MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_iter, data->cd_ofs);
146  luv_next = (const MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_next, data->cd_ofs);
148  av,
149  luv->uv,
150  luv_next->uv,
151  bm_vert_co_get(mr, l_iter->v),
152  bm_vert_co_get(mr, l_next->v));
153  }
154  edituv_get_edituv_stretch_angle(auv, av, &data->vbo_data[l_index]);
155  } while ((l_iter = l_iter->next) != l_first);
156 }
157 
159  const MPoly *mp,
160  const int UNUSED(mp_index),
161  void *_data)
162 {
164 
165  const int ml_index_end = mp->loopstart + mp->totloop;
166  for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) {
167  float(*auv)[2] = data->auv, *last_auv = data->last_auv;
168  float(*av)[3] = data->av, *last_av = data->last_av;
169  int l_next = ml_index + 1;
170  const MVert *v, *v_next;
171  if (ml_index == mp->loopstart) {
172  /* First loop in face. */
173  const int ml_index_last = ml_index_end - 1;
174  const int l_next_tmp = mp->loopstart;
175  v = &mr->mvert[mr->mloop[ml_index_last].v];
176  v_next = &mr->mvert[mr->mloop[l_next_tmp].v];
178  auv, av, data->luv[ml_index_last].uv, data->luv[l_next_tmp].uv, v->co, v_next->co);
179  /* Save last edge. */
180  copy_v2_v2(last_auv, auv[1]);
181  copy_v3_v3(last_av, av[1]);
182  }
183  if (l_next == ml_index_end) {
184  l_next = mp->loopstart;
185  /* Move previous edge. */
186  copy_v2_v2(auv[0], auv[1]);
187  copy_v3_v3(av[0], av[1]);
188  /* Copy already calculated last edge. */
189  copy_v2_v2(auv[1], last_auv);
190  copy_v3_v3(av[1], last_av);
191  }
192  else {
193  v = &mr->mvert[mr->mloop[ml_index].v];
194  v_next = &mr->mvert[mr->mloop[l_next].v];
196  auv, av, data->luv[ml_index].uv, data->luv[l_next].uv, v->co, v_next->co);
197  }
198  edituv_get_edituv_stretch_angle(auv, av, &data->vbo_data[ml_index]);
199  }
200 }
201 
203 {
204  static GPUVertFormat format = {0};
205  if (format.attr_len == 0) {
206  /* Waning: adjust #UVStretchAngle struct accordingly. */
209  }
210  return &format;
211 }
212 
214  const MeshRenderData *mr,
215  MeshBatchCache *cache,
216  void *buffer,
217  void *UNUSED(tls_data))
218 {
219  GPUVertBuf *refined_vbo = static_cast<GPUVertBuf *>(buffer);
220 
222  refined_vbo, get_edituv_stretch_angle_format_subdiv(), subdiv_cache->num_subdiv_loops);
223 
224  GPUVertBuf *pos_nor = cache->final.buff.vbo.pos_nor;
225  GPUVertBuf *uvs = cache->final.buff.vbo.uv;
226 
227  /* It may happen that the data for the UV editor is requested before (as a separate draw update)
228  * the data for the mesh when switching to the `UV Editing` workspace, and therefore the position
229  * buffer might not be created yet. In this case, create a buffer it locally, the subdivision
230  * data should already be evaluated if we are here. This can happen if the subsurf modifier is
231  * only enabled in edit-mode. See T96338. */
232  if (!pos_nor) {
233  const DRWSubdivLooseGeom &loose_geom = subdiv_cache->loose_geom;
234  pos_nor = GPU_vertbuf_calloc();
237  subdiv_cache->num_subdiv_loops + loose_geom.loop_len);
238 
239  draw_subdiv_extract_pos_nor(subdiv_cache, pos_nor, nullptr);
240  }
241 
242  /* UVs are stored contiguously so we need to compute the offset in the UVs buffer for the active
243  * UV layer. */
244  CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_MESH) ? &mr->me->ldata : &mr->bm->ldata;
245 
246  uint32_t uv_layers = cache->cd_used.uv;
247  /* HACK to fix T68857 */
248  if (mr->extract_type == MR_EXTRACT_BMESH && cache->cd_used.edit_uv == 1) {
249  int layer = CustomData_get_active_layer(cd_ldata, CD_MLOOPUV);
250  if (layer != -1) {
251  uv_layers |= (1 << layer);
252  }
253  }
254 
255  int uvs_offset = 0;
256  for (int i = 0; i < MAX_MTFACE; i++) {
257  if (uv_layers & (1 << i)) {
258  if (i == CustomData_get_active_layer(cd_ldata, CD_MLOOPUV)) {
259  break;
260  }
261 
262  uvs_offset += 1;
263  }
264  }
265 
266  /* The data is at `offset * num loops`, and we have 2 values per index. */
267  uvs_offset *= subdiv_cache->num_subdiv_loops * 2;
268 
270  subdiv_cache, pos_nor, uvs, uvs_offset, refined_vbo);
271 
272  if (!cache->final.buff.vbo.pos_nor) {
273  GPU_vertbuf_discard(pos_nor);
274  }
275 }
276 
278 {
279  MeshExtract extractor = {nullptr};
284  extractor.data_type = MR_DATA_NONE;
285  extractor.data_size = sizeof(MeshExtract_StretchAngle_Data);
286  extractor.use_threading = false;
287  extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.edituv_stretch_angle);
288  return extractor;
289 }
290 
293 } // namespace blender::draw
294 
typedef float(TangentPoint)[2]
int CustomData_get_active_layer(const struct CustomData *data, int type)
void * CustomData_get_layer(const struct CustomData *data, int type)
int CustomData_get_offset(const struct CustomData *data, int type)
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define M_1_PI
Definition: BLI_math_base.h:41
MINLINE float pow2f(float x)
#define M_PI
Definition: BLI_math_base.h:20
float angle_normalized_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
Definition: math_vector.c:461
MINLINE float normalize_v3(float r[3])
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 r[2])
float angle_normalized_v3v3(const float v1[3], const float v2[3]) ATTR_WARN_UNUSED_RESULT
Definition: math_vector.c:445
#define UNUSED(x)
#define ELEM(...)
@ CD_MLOOPUV
#define MAX_MTFACE
void GPU_vertbuf_discard(GPUVertBuf *)
struct GPUVertBuf GPUVertBuf
GPUVertBuf * GPU_vertbuf_calloc(void)
void GPU_vertbuf_data_alloc(GPUVertBuf *, uint v_len)
#define GPU_vertbuf_init_with_format(verts, format)
void * GPU_vertbuf_get_data(const GPUVertBuf *verts)
void GPU_vertbuf_init_build_on_device(GPUVertBuf *verts, GPUVertFormat *format, uint v_len)
@ 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
Read Guarded memory(de)allocation.
#define BM_FACE_FIRST_LOOP(p)
Definition: bmesh_class.h:622
#define BM_ELEM_CD_GET_VOID_P(ele, offset)
Definition: bmesh_class.h:541
#define BM_elem_index_get(ele)
Definition: bmesh_inline.h:110
ATTR_WARN_UNUSED_RESULT const BMVert * v
@ MR_DATA_NONE
void draw_subdiv_build_edituv_stretch_angle_buffer(const DRWSubdivCache *cache, GPUVertBuf *pos_nor, GPUVertBuf *uvs, int uvs_offset, GPUVertBuf *stretch_angles)
GPUVertFormat * draw_subdiv_get_pos_nor_format()
void draw_subdiv_extract_pos_nor(const DRWSubdivCache *cache, GPUVertBuf *pos_nor, GPUVertBuf *orco)
Extraction of Mesh data into VBO to feed to GPU.
BLI_INLINE const float * bm_vert_co_get(const MeshRenderData *mr, const BMVert *eve)
@ MR_EXTRACT_BMESH
Definition: extract_mesh.hh:31
@ MR_EXTRACT_MESH
Definition: extract_mesh.hh:33
@ MR_EXTRACT_MAPPED
Definition: extract_mesh.hh:32
const MeshExtract extract_edituv_stretch_angle
ccl_global float * buffer
format
Definition: logImageCore.h:38
#define atan2f(x, y)
Definition: metal/compat.h:227
#define fabsf(x)
Definition: metal/compat.h:219
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])
static void extract_edituv_stretch_angle_init_subdiv(const DRWSubdivCache *subdiv_cache, const MeshRenderData *mr, MeshBatchCache *cache, void *buffer, void *UNUSED(tls_data))
static short v2_to_short_angle(const float v[2])
static void edituv_get_edituv_stretch_angle(float auv[2][2], const float av[2][3], UVStretchAngle *r_stretch)
constexpr MeshExtract create_extractor_edituv_edituv_stretch_angle()
static GPUVertFormat * get_edituv_stretch_angle_format_subdiv()
static void extract_edituv_stretch_angle_init(const MeshRenderData *mr, MeshBatchCache *UNUSED(cache), void *buf, void *tls_data)
static void extract_edituv_stretch_angle_iter_poly_bm(const MeshRenderData *mr, const BMFace *f, const int UNUSED(f_index), void *_data)
static void extract_edituv_stretch_angle_iter_poly_mesh(const MeshRenderData *mr, const MPoly *mp, const int UNUSED(mp_index), void *_data)
signed short int16_t
Definition: stdint.h:76
unsigned int uint32_t
Definition: stdint.h:80
struct BMVert * v
Definition: bmesh_class.h:153
struct BMLoop * prev
Definition: bmesh_class.h:233
struct BMLoop * next
Definition: bmesh_class.h:233
float co[3]
Definition: bmesh_class.h:87
CustomData ldata
Definition: bmesh_class.h:337
DRWSubdivLooseGeom loose_geom
unsigned int v
float co[3]
DRW_MeshCDMask cd_used
MeshBufferCache final
MeshBufferList buff
GPUVertBuf * pos_nor
struct MeshBufferList::@272 vbo
GPUVertBuf * edituv_stretch_angle
size_t mesh_buffer_offset
eMRDataType data_type
ExtractInitSubdivFn * init_subdiv
size_t data_size
ExtractPolyBMeshFn * iter_poly_bm
ExtractPolyMeshFn * iter_poly_mesh
bool use_threading
ExtractInitFn * init
eMRExtractType extract_type
Definition: extract_mesh.hh:37
const MLoop * mloop
Definition: extract_mesh.hh:76
const MVert * mvert
Definition: extract_mesh.hh:74
CustomData ldata