Blender V4.3
mesh_primitive_grid.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "BKE_attribute.hh"
6#include "BKE_mesh.hh"
7
9
10namespace blender::geometry {
11
12static void calculate_uvs(Mesh *mesh,
13 const Span<float3> positions,
14 const Span<int> corner_verts,
15 const float size_x,
16 const float size_y,
17 const StringRef uv_map_id)
18{
19 bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
20 bke::SpanAttributeWriter uv_attribute = attributes.lookup_or_add_for_write_only_span<float2>(
21 uv_map_id, bke::AttrDomain::Corner);
22
23 const float dx = (size_x == 0.0f) ? 0.0f : 1.0f / size_x;
24 const float dy = (size_y == 0.0f) ? 0.0f : 1.0f / size_y;
26 uv_attribute.span.size_in_bytes() + positions.size_in_bytes() + corner_verts.size_in_bytes(),
27 [&]() {
28 threading::parallel_for(corner_verts.index_range(), 1024, [&](IndexRange range) {
29 for (const int i : range) {
30 const float3 &co = positions[corner_verts[i]];
31 uv_attribute.span[i].x = (co.x + size_x * 0.5f) * dx;
32 uv_attribute.span[i].y = (co.y + size_y * 0.5f) * dy;
33 }
34 });
35 });
36
37 uv_attribute.finish();
38}
39
40Mesh *create_grid_mesh(const int verts_x,
41 const int verts_y,
42 const float size_x,
43 const float size_y,
44 const std::optional<StringRef> &uv_map_id)
45{
46 BLI_assert(verts_x > 0 && verts_y > 0);
47 const int edges_x = verts_x - 1;
48 const int edges_y = verts_y - 1;
49 Mesh *mesh = BKE_mesh_new_nomain(verts_x * verts_y,
50 edges_x * verts_y + edges_y * verts_x,
51 edges_x * edges_y,
52 edges_x * edges_y * 4);
53 MutableSpan<float3> positions = mesh->vert_positions_for_write();
54 MutableSpan<int2> edges = mesh->edges_for_write();
55 MutableSpan<int> corner_verts = mesh->corner_verts_for_write();
56 MutableSpan<int> corner_edges = mesh->corner_edges_for_write();
57 bke::mesh_smooth_set(*mesh, false);
58
59 offset_indices::fill_constant_group_size(4, 0, mesh->face_offsets_for_write());
60
61 {
62 const float dx = edges_x == 0 ? 0.0f : size_x / edges_x;
63 const float dy = edges_y == 0 ? 0.0f : size_y / edges_y;
64 const float x_shift = edges_x / 2.0f;
65 const float y_shift = edges_y / 2.0f;
66 threading::memory_bandwidth_bound_task(positions.size_in_bytes(), [&]() {
67 threading::parallel_for(IndexRange(verts_x), 512, [&](IndexRange x_range) {
68 for (const int x : x_range) {
69 const int y_offset = x * verts_y;
70 threading::parallel_for(IndexRange(verts_y), 512, [&](IndexRange y_range) {
71 for (const int y : y_range) {
72 const int vert_index = y_offset + y;
73 positions[vert_index].x = (x - x_shift) * dx;
74 positions[vert_index].y = (y - y_shift) * dy;
75 positions[vert_index].z = 0.0f;
76 }
77 });
78 }
79 });
80 });
81 }
82
83 const int y_edges_start = 0;
84 const int x_edges_start = verts_x * edges_y;
85
86 /* Build the horizontal edges in the X direction. */
87 threading::memory_bandwidth_bound_task(edges.size_in_bytes(), [&]() {
88 threading::parallel_for(IndexRange(verts_x), 512, [&](IndexRange x_range) {
89 for (const int x : x_range) {
90 const int y_vert_offset = x * verts_y;
91 const int y_edge_offset = y_edges_start + x * edges_y;
92 threading::parallel_for(IndexRange(edges_y), 512, [&](IndexRange y_range) {
93 for (const int y : y_range) {
94 const int vert_index = y_vert_offset + y;
95 edges[y_edge_offset + y] = int2(vert_index, vert_index + 1);
96 }
97 });
98 }
99 });
100 });
101
102 /* Build the vertical edges in the Y direction. */
103 threading::memory_bandwidth_bound_task(edges.size_in_bytes(), [&]() {
104 threading::parallel_for(IndexRange(verts_y), 512, [&](IndexRange y_range) {
105 for (const int y : y_range) {
106 const int x_edge_offset = x_edges_start + y * edges_x;
107 threading::parallel_for(IndexRange(edges_x), 512, [&](IndexRange x_range) {
108 for (const int x : x_range) {
109 const int vert_index = x * verts_y + y;
110 edges[x_edge_offset + x] = int2(vert_index, vert_index + verts_y);
111 }
112 });
113 }
114 });
115 });
116
117 threading::memory_bandwidth_bound_task(
118 corner_edges.size_in_bytes() + corner_verts.size_in_bytes(), [&]() {
119 threading::parallel_for(IndexRange(edges_x), 512, [&](IndexRange x_range) {
120 for (const int x : x_range) {
121 const int y_offset = x * edges_y;
122 threading::parallel_for(IndexRange(edges_y), 512, [&](IndexRange y_range) {
123 for (const int y : y_range) {
124 const int face_index = y_offset + y;
125 const int loop_index = face_index * 4;
126 const int vert_index = x * verts_y + y;
127
128 corner_verts[loop_index] = vert_index;
129 corner_edges[loop_index] = x_edges_start + edges_x * y + x;
130
131 corner_verts[loop_index + 1] = vert_index + verts_y;
132 corner_edges[loop_index + 1] = y_edges_start + edges_y * (x + 1) + y;
133
134 corner_verts[loop_index + 2] = vert_index + verts_y + 1;
135 corner_edges[loop_index + 2] = x_edges_start + edges_x * (y + 1) + x;
136
137 corner_verts[loop_index + 3] = vert_index + 1;
138 corner_edges[loop_index + 3] = y_edges_start + edges_y * x + y;
139 }
140 });
141 }
142 });
143 });
144
145 if (uv_map_id && mesh->faces_num != 0) {
146 calculate_uvs(mesh, positions, corner_verts, size_x, size_y, *uv_map_id);
147 }
148
149 if (verts_x > 1 || verts_y > 1) {
150 mesh->tag_loose_verts_none();
151 }
152 if (verts_x > 1 && verts_y > 1) {
153 mesh->tag_loose_edges_none();
154 }
155 mesh->tag_overlapping_none();
156
157 const float3 bounds = float3(size_x * 0.5f, size_y * 0.5f, 0.0f);
158 mesh->bounds_set_eager({-bounds, bounds});
159
160 return mesh;
161}
162
163} // namespace blender::geometry
Mesh * BKE_mesh_new_nomain(int verts_num, int edges_num, int faces_num, int corners_num)
#define BLI_assert(a)
Definition BLI_assert.h:50
static btDbvtVolume bounds(btDbvtNode **leaves, int count)
Definition btDbvt.cpp:299
constexpr int64_t size_in_bytes() const
Definition BLI_span.hh:269
static void calculate_uvs(Mesh *mesh, const Span< float3 > positions, const Span< int > corner_verts, const float size_x, const float size_y, const StringRef uv_map_id)
Mesh * create_grid_mesh(int verts_x, int verts_y, float size_x, float size_y, const std::optional< StringRef > &uv_map_id)
static void calculate_uvs(const CuboidConfig &config, Mesh *mesh, const StringRef uv_id)
void memory_bandwidth_bound_task(const int64_t approximate_bytes_touched, const Function &function)
Definition BLI_task.hh:243