Blender  V3.3
mesh_primitive_cuboid.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #include "BLI_index_range.hh"
4 #include "BLI_math_vector.h"
5 #include "BLI_math_vector.hh"
6 
7 #include "DNA_mesh_types.h"
8 #include "DNA_meshdata_types.h"
9 
10 #include "BKE_geometry_set.hh"
11 #include "BKE_mesh.h"
12 
14 
15 namespace blender::geometry {
16 
17 struct CuboidConfig {
19  int verts_x;
20  int verts_y;
21  int verts_z;
22  int edges_x;
23  int edges_y;
24  int edges_z;
28 
30  : size(size),
34  edges_x(verts_x - 1),
35  edges_y(verts_y - 1),
36  edges_z(verts_z - 1)
37  {
38  BLI_assert(edges_x > 0 && edges_y > 0 && edges_z > 0);
39  this->vertex_count = this->get_vertex_count();
40  this->poly_count = this->get_poly_count();
41  this->loop_count = this->poly_count * 4;
42  }
43 
44  private:
45  int get_vertex_count()
46  {
47  const int inner_position_count = (verts_x - 2) * (verts_y - 2) * (verts_z - 2);
48  return verts_x * verts_y * verts_z - inner_position_count;
49  }
50 
51  int get_poly_count()
52  {
53  return 2 * (edges_x * edges_y + edges_y * edges_z + edges_z * edges_x);
54  }
55 };
56 
58 {
59  const float z_bottom = -config.size.z / 2.0f;
60  const float z_delta = config.size.z / config.edges_z;
61 
62  const float x_left = -config.size.x / 2.0f;
63  const float x_delta = config.size.x / config.edges_x;
64 
65  const float y_front = -config.size.y / 2.0f;
66  const float y_delta = config.size.y / config.edges_y;
67 
68  int vert_index = 0;
69 
70  for (const int z : IndexRange(config.verts_z)) {
71  if (ELEM(z, 0, config.edges_z)) {
72  /* Fill bottom and top. */
73  const float z_pos = z_bottom + z_delta * z;
74  for (const int y : IndexRange(config.verts_y)) {
75  const float y_pos = y_front + y_delta * y;
76  for (const int x : IndexRange(config.verts_x)) {
77  const float x_pos = x_left + x_delta * x;
78  copy_v3_v3(verts[vert_index++].co, float3(x_pos, y_pos, z_pos));
79  }
80  }
81  }
82  else {
83  for (const int y : IndexRange(config.verts_y)) {
84  if (ELEM(y, 0, config.edges_y)) {
85  /* Fill y-sides. */
86  const float y_pos = y_front + y_delta * y;
87  const float z_pos = z_bottom + z_delta * z;
88  for (const int x : IndexRange(config.verts_x)) {
89  const float x_pos = x_left + x_delta * x;
90  copy_v3_v3(verts[vert_index++].co, float3(x_pos, y_pos, z_pos));
91  }
92  }
93  else {
94  /* Fill x-sides. */
95  const float x_pos = x_left;
96  const float y_pos = y_front + y_delta * y;
97  const float z_pos = z_bottom + z_delta * z;
98  copy_v3_v3(verts[vert_index++].co, float3(x_pos, y_pos, z_pos));
99  const float x_pos2 = x_left + x_delta * config.edges_x;
100  copy_v3_v3(verts[vert_index++].co, float3(x_pos2, y_pos, z_pos));
101  }
102  }
103  }
104  }
105 }
106 
107 /* vert_1 = bottom left, vert_2 = bottom right, vert_3 = top right, vert_4 = top left.
108  * Hence they are passed as 1,4,3,2 when calculating polys clockwise, and 1,2,3,4 for
109  * anti-clockwise.
110  */
111 static void define_quad(MutableSpan<MPoly> polys,
112  MutableSpan<MLoop> loops,
113  const int poly_index,
114  const int loop_index,
115  const int vert_1,
116  const int vert_2,
117  const int vert_3,
118  const int vert_4)
119 {
120  MPoly &poly = polys[poly_index];
121  poly.loopstart = loop_index;
122  poly.totloop = 4;
123 
124  MLoop &loop_1 = loops[loop_index];
125  loop_1.v = vert_1;
126  MLoop &loop_2 = loops[loop_index + 1];
127  loop_2.v = vert_2;
128  MLoop &loop_3 = loops[loop_index + 2];
129  loop_3.v = vert_3;
130  MLoop &loop_4 = loops[loop_index + 3];
131  loop_4.v = vert_4;
132 }
133 
134 static void calculate_polys(const CuboidConfig &config,
135  MutableSpan<MPoly> polys,
136  MutableSpan<MLoop> loops)
137 {
138  int loop_index = 0;
139  int poly_index = 0;
140 
141  /* Number of vertices in an XY cross-section of the cube (barring top and bottom faces). */
142  const int xy_cross_section_vert_count = config.verts_x * config.verts_y -
143  (config.verts_x - 2) * (config.verts_y - 2);
144 
145  /* Calculate polys for Bottom faces. */
146  int vert_1_start = 0;
147 
148  for ([[maybe_unused]] const int y : IndexRange(config.edges_y)) {
149  for (const int x : IndexRange(config.edges_x)) {
150  const int vert_1 = vert_1_start + x;
151  const int vert_2 = vert_1_start + config.verts_x + x;
152  const int vert_3 = vert_2 + 1;
153  const int vert_4 = vert_1 + 1;
154 
155  define_quad(polys, loops, poly_index, loop_index, vert_1, vert_2, vert_3, vert_4);
156  loop_index += 4;
157  poly_index++;
158  }
159  vert_1_start += config.verts_x;
160  }
161 
162  /* Calculate polys for Front faces. */
163  vert_1_start = 0;
164  int vert_2_start = config.verts_x * config.verts_y;
165 
166  for ([[maybe_unused]] const int z : IndexRange(config.edges_z)) {
167  for (const int x : IndexRange(config.edges_x)) {
168  define_quad(polys,
169  loops,
170  poly_index,
171  loop_index,
172  vert_1_start + x,
173  vert_1_start + x + 1,
174  vert_2_start + x + 1,
175  vert_2_start + x);
176  loop_index += 4;
177  poly_index++;
178  }
179  vert_1_start = vert_2_start;
180  vert_2_start += config.verts_x * config.verts_y - (config.verts_x - 2) * (config.verts_y - 2);
181  }
182 
183  /* Calculate polys for Top faces. */
184  vert_1_start = config.verts_x * config.verts_y +
185  (config.verts_z - 2) * (config.verts_x * config.verts_y -
186  (config.verts_x - 2) * (config.verts_y - 2));
187  vert_2_start = vert_1_start + config.verts_x;
188 
189  for ([[maybe_unused]] const int y : IndexRange(config.edges_y)) {
190  for (const int x : IndexRange(config.edges_x)) {
191  define_quad(polys,
192  loops,
193  poly_index,
194  loop_index,
195  vert_1_start + x,
196  vert_1_start + x + 1,
197  vert_2_start + x + 1,
198  vert_2_start + x);
199  loop_index += 4;
200  poly_index++;
201  }
202  vert_2_start += config.verts_x;
203  vert_1_start += config.verts_x;
204  }
205 
206  /* Calculate polys for Back faces. */
207  vert_1_start = config.verts_x * config.edges_y;
208  vert_2_start = vert_1_start + xy_cross_section_vert_count;
209 
210  for (const int z : IndexRange(config.edges_z)) {
211  if (z == (config.edges_z - 1)) {
212  vert_2_start += (config.verts_x - 2) * (config.verts_y - 2);
213  }
214  for (const int x : IndexRange(config.edges_x)) {
215  define_quad(polys,
216  loops,
217  poly_index,
218  loop_index,
219  vert_1_start + x,
220  vert_2_start + x,
221  vert_2_start + x + 1,
222  vert_1_start + x + 1);
223  loop_index += 4;
224  poly_index++;
225  }
226  vert_2_start += xy_cross_section_vert_count;
227  vert_1_start += xy_cross_section_vert_count;
228  }
229 
230  /* Calculate polys for Left faces. */
231  vert_1_start = 0;
232  vert_2_start = config.verts_x * config.verts_y;
233 
234  for (const int z : IndexRange(config.edges_z)) {
235  for (const int y : IndexRange(config.edges_y)) {
236  int vert_1;
237  int vert_2;
238  int vert_3;
239  int vert_4;
240 
241  if (z == 0 || y == 0) {
242  vert_1 = vert_1_start + config.verts_x * y;
243  vert_4 = vert_1 + config.verts_x;
244  }
245  else {
246  vert_1 = vert_1_start + 2 * y;
247  vert_1 += config.verts_x - 2;
248  vert_4 = vert_1 + 2;
249  }
250 
251  if (y == 0 || z == (config.edges_z - 1)) {
252  vert_2 = vert_2_start + config.verts_x * y;
253  vert_3 = vert_2 + config.verts_x;
254  }
255  else {
256  vert_2 = vert_2_start + 2 * y;
257  vert_2 += config.verts_x - 2;
258  vert_3 = vert_2 + 2;
259  }
260 
261  define_quad(polys, loops, poly_index, loop_index, vert_1, vert_2, vert_3, vert_4);
262  loop_index += 4;
263  poly_index++;
264  }
265  if (z == 0) {
266  vert_1_start += config.verts_x * config.verts_y;
267  }
268  else {
269  vert_1_start += xy_cross_section_vert_count;
270  }
271  vert_2_start += xy_cross_section_vert_count;
272  }
273 
274  /* Calculate polys for Right faces. */
275  vert_1_start = config.edges_x;
276  vert_2_start = vert_1_start + config.verts_x * config.verts_y;
277 
278  for (const int z : IndexRange(config.edges_z)) {
279  for (const int y : IndexRange(config.edges_y)) {
280  int vert_1 = vert_1_start;
281  int vert_2 = vert_2_start;
282  int vert_3 = vert_2_start + 2;
283  int vert_4 = vert_1 + config.verts_x;
284 
285  if (z == 0) {
286  vert_1 = vert_1_start + config.verts_x * y;
287  vert_4 = vert_1 + config.verts_x;
288  }
289  else {
290  vert_1 = vert_1_start + 2 * y;
291  vert_4 = vert_1 + 2;
292  }
293 
294  if (z == (config.edges_z - 1)) {
295  vert_2 = vert_2_start + config.verts_x * y;
296  vert_3 = vert_2 + config.verts_x;
297  }
298  else {
299  vert_2 = vert_2_start + 2 * y;
300  vert_3 = vert_2 + 2;
301  }
302 
303  if (y == (config.edges_y - 1)) {
304  vert_3 = vert_2 + config.verts_x;
305  vert_4 = vert_1 + config.verts_x;
306  }
307 
308  define_quad(polys, loops, poly_index, loop_index, vert_1, vert_4, vert_3, vert_2);
309  loop_index += 4;
310  poly_index++;
311  }
312  if (z == 0) {
313  vert_1_start += config.verts_x * config.verts_y;
314  }
315  else {
316  vert_1_start += xy_cross_section_vert_count;
317  }
318  vert_2_start += xy_cross_section_vert_count;
319  }
320 }
321 
322 static void calculate_uvs(const CuboidConfig &config, Mesh *mesh, const bke::AttributeIDRef &uv_id)
323 {
325  bke::SpanAttributeWriter<float2> uv_attribute =
327  MutableSpan<float2> uvs = uv_attribute.span;
328 
329  int loop_index = 0;
330 
331  const float x_delta = 0.25f / static_cast<float>(config.edges_x);
332  const float y_delta = 0.25f / static_cast<float>(config.edges_y);
333  const float z_delta = 0.25f / static_cast<float>(config.edges_z);
334 
335  /* Calculate bottom face UVs. */
336  for (const int y : IndexRange(config.edges_y)) {
337  for (const int x : IndexRange(config.edges_x)) {
338  uvs[loop_index++] = float2(0.25f + x * x_delta, 0.375f - y * y_delta);
339  uvs[loop_index++] = float2(0.25f + x * x_delta, 0.375f - (y + 1) * y_delta);
340  uvs[loop_index++] = float2(0.25f + (x + 1) * x_delta, 0.375f - (y + 1) * y_delta);
341  uvs[loop_index++] = float2(0.25f + (x + 1) * x_delta, 0.375f - y * y_delta);
342  }
343  }
344 
345  /* Calculate front face UVs. */
346  for (const int z : IndexRange(config.edges_z)) {
347  for (const int x : IndexRange(config.edges_x)) {
348  uvs[loop_index++] = float2(0.25f + x * x_delta, 0.375f + z * z_delta);
349  uvs[loop_index++] = float2(0.25f + (x + 1) * x_delta, 0.375f + z * z_delta);
350  uvs[loop_index++] = float2(0.25f + (x + 1) * x_delta, 0.375f + (z + 1) * z_delta);
351  uvs[loop_index++] = float2(0.25f + x * x_delta, 0.375f + (z + 1) * z_delta);
352  }
353  }
354 
355  /* Calculate top face UVs. */
356  for (const int y : IndexRange(config.edges_y)) {
357  for (const int x : IndexRange(config.edges_x)) {
358  uvs[loop_index++] = float2(0.25f + x * x_delta, 0.625f + y * y_delta);
359  uvs[loop_index++] = float2(0.25f + (x + 1) * x_delta, 0.625f + y * y_delta);
360  uvs[loop_index++] = float2(0.25f + (x + 1) * x_delta, 0.625f + (y + 1) * y_delta);
361  uvs[loop_index++] = float2(0.25f + x * x_delta, 0.625f + (y + 1) * y_delta);
362  }
363  }
364 
365  /* Calculate back face UVs. */
366  for (const int z : IndexRange(config.edges_z)) {
367  for (const int x : IndexRange(config.edges_x)) {
368  uvs[loop_index++] = float2(1.0f - x * x_delta, 0.375f + z * z_delta);
369  uvs[loop_index++] = float2(1.0f - x * x_delta, 0.375f + (z + 1) * z_delta);
370  uvs[loop_index++] = float2(1.0f - (x + 1) * x_delta, 0.375f + (z + 1) * z_delta);
371  uvs[loop_index++] = float2(1.0f - (x + 1) * x_delta, 0.375f + z * z_delta);
372  }
373  }
374 
375  /* Calculate left face UVs. */
376  for (const int z : IndexRange(config.edges_z)) {
377  for (const int y : IndexRange(config.edges_y)) {
378  uvs[loop_index++] = float2(0.25f - y * y_delta, 0.375f + z * z_delta);
379  uvs[loop_index++] = float2(0.25f - y * y_delta, 0.375f + (z + 1) * z_delta);
380  uvs[loop_index++] = float2(0.25f - (y + 1) * y_delta, 0.375f + (z + 1) * z_delta);
381  uvs[loop_index++] = float2(0.25f - (y + 1) * y_delta, 0.375f + z * z_delta);
382  }
383  }
384 
385  /* Calculate right face UVs. */
386  for (const int z : IndexRange(config.edges_z)) {
387  for (const int y : IndexRange(config.edges_y)) {
388  uvs[loop_index++] = float2(0.50f + y * y_delta, 0.375f + z * z_delta);
389  uvs[loop_index++] = float2(0.50f + (y + 1) * y_delta, 0.375f + z * z_delta);
390  uvs[loop_index++] = float2(0.50f + (y + 1) * y_delta, 0.375f + (z + 1) * z_delta);
391  uvs[loop_index++] = float2(0.50f + y * y_delta, 0.375f + (z + 1) * z_delta);
392  }
393  }
394 
395  uv_attribute.finish();
396 }
397 
399  const int verts_x,
400  const int verts_y,
401  const int verts_z,
402  const bke::AttributeIDRef &uv_id)
403 {
404  const CuboidConfig config(size, verts_x, verts_y, verts_z);
405 
407  config.vertex_count, 0, 0, config.loop_count, config.poly_count);
408 
409  calculate_vertices(config, {mesh->mvert, mesh->totvert});
410 
412  BKE_mesh_calc_edges(mesh, false, false);
413 
414  if (uv_id) {
415  calculate_uvs(config, mesh, uv_id);
416  }
417 
418  return mesh;
419 }
420 
422  const int verts_x,
423  const int verts_y,
424  const int verts_z)
425 {
426  return create_cuboid_mesh(size, verts_x, verts_y, verts_z, {});
427 }
428 
429 } // namespace blender::geometry
@ ATTR_DOMAIN_CORNER
Definition: BKE_attribute.h:30
struct Mesh * BKE_mesh_new_nomain(int verts_len, int edges_len, int tessface_len, int loops_len, int polys_len)
Definition: mesh.cc:991
void BKE_mesh_calc_edges(struct Mesh *mesh, bool keep_existing_edges, bool select_new_edges)
#define BLI_assert(a)
Definition: BLI_assert.h:46
MINLINE void copy_v3_v3(float r[3], const float a[3])
#define ELEM(...)
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble z
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint y
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
GSpanAttributeWriter lookup_or_add_for_write_only_span(const AttributeIDRef &attribute_id, const eAttrDomain domain, const eCustomDataType data_type)
static float verts[][3]
MutableAttributeAccessor mesh_attributes_for_write(Mesh &mesh)
static void calculate_polys(const CuboidConfig &config, MutableSpan< MPoly > polys, MutableSpan< MLoop > loops)
static void calculate_vertices(const CuboidConfig &config, MutableSpan< MVert > verts)
static void define_quad(MutableSpan< MPoly > polys, MutableSpan< MLoop > loops, const int poly_index, const int loop_index, const int vert_1, const int vert_2, const int vert_3, const int vert_4)
static void calculate_uvs(const CuboidConfig &config, Mesh *mesh, const bke::AttributeIDRef &uv_id)
Mesh * create_cuboid_mesh(const float3 &size, int verts_x, int verts_y, int verts_z, const bke::AttributeIDRef &uv_id)
vec_base< float, 3 > float3
vec_base< float, 2 > float2
unsigned int v
struct MVert * mvert
int totvert
struct MLoop * mloop
int totpoly
int totloop
struct MPoly * mpoly
CuboidConfig(float3 size, int verts_x, int verts_y, int verts_z)