Changeset View
Changeset View
Standalone View
Standalone View
source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc
| /* | /* | ||||
| * This program is free software; you can redistribute it and/or | * This program is free software; you can redistribute it and/or | ||||
| * modify it under the terms of the GNU General Public License | * modify it under the terms of the GNU General Public License | ||||
| * as published by the Free Software Foundation; either version 2 | * as published by the Free Software Foundation; either version 2 | ||||
| * of the License, or (at your option) any later version. | * of the License, or (at your option) any later version. | ||||
| * | * | ||||
| * This program is distributed in the hope that it will be useful, | * This program is distributed in the hope that it will be useful, | ||||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
| * GNU General Public License for more details. | * GNU General Public License for more details. | ||||
| * | * | ||||
| * You should have received a copy of the GNU General Public License | * You should have received a copy of the GNU General Public License | ||||
| * along with this program; if not, write to the Free Software Foundation, | * along with this program; if not, write to the Free Software Foundation, | ||||
| * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||||
| */ | */ | ||||
| #include "BLI_task.hh" | |||||
| #include "DNA_mesh_types.h" | #include "DNA_mesh_types.h" | ||||
| #include "DNA_meshdata_types.h" | #include "DNA_meshdata_types.h" | ||||
| #include "BKE_material.h" | #include "BKE_material.h" | ||||
| #include "BKE_mesh.h" | #include "BKE_mesh.h" | ||||
| #include "UI_interface.h" | #include "UI_interface.h" | ||||
| #include "UI_resources.h" | #include "UI_resources.h" | ||||
| #include "node_geometry_util.hh" | #include "node_geometry_util.hh" | ||||
| namespace blender::nodes { | namespace blender::nodes { | ||||
| static void calculate_uvs( | static void calculate_uvs( | ||||
| Mesh *mesh, Span<MVert> verts, Span<MLoop> loops, const float size_x, const float size_y) | Mesh *mesh, Span<MVert> verts, Span<MLoop> loops, const float size_x, const float size_y) | ||||
| { | { | ||||
| SCOPED_TIMER("uvs"); | |||||
| MeshComponent mesh_component; | MeshComponent mesh_component; | ||||
| mesh_component.replace(mesh, GeometryOwnershipType::Editable); | mesh_component.replace(mesh, GeometryOwnershipType::Editable); | ||||
| OutputAttribute_Typed<float2> uv_attribute = | OutputAttribute_Typed<float2> uv_attribute = | ||||
| mesh_component.attribute_try_get_for_output_only<float2>("uv_map", ATTR_DOMAIN_CORNER); | mesh_component.attribute_try_get_for_output_only<float2>("uv_map", ATTR_DOMAIN_CORNER); | ||||
| MutableSpan<float2> uvs = uv_attribute.as_span(); | MutableSpan<float2> uvs = uv_attribute.as_span(); | ||||
| const float dx = (size_x == 0.0f) ? 0.0f : 1.0f / size_x; | const float dx = (size_x == 0.0f) ? 0.0f : 1.0f / size_x; | ||||
| const float dy = (size_y == 0.0f) ? 0.0f : 1.0f / size_y; | const float dy = (size_y == 0.0f) ? 0.0f : 1.0f / size_y; | ||||
| for (const int i : loops.index_range()) { | threading::parallel_for(loops.index_range(), 1024, [&](IndexRange range) { | ||||
| for (const int i : range) { | |||||
| const float3 &co = verts[loops[i].v].co; | const float3 &co = verts[loops[i].v].co; | ||||
| uvs[i].x = (co.x + size_x * 0.5f) * dx; | uvs[i].x = (co.x + size_x * 0.5f) * dx; | ||||
| uvs[i].y = (co.y + size_y * 0.5f) * dy; | uvs[i].y = (co.y + size_y * 0.5f) * dy; | ||||
| } | } | ||||
| }); | |||||
| uv_attribute.save(); | uv_attribute.save(); | ||||
| } | } | ||||
| Mesh *create_grid_mesh(const int verts_x, | Mesh *create_grid_mesh(const int verts_x, | ||||
| const int verts_y, | const int verts_y, | ||||
| const float size_x, | const float size_x, | ||||
| const float size_y) | const float size_y) | ||||
| { | { | ||||
| SCOPED_TIMER("TOTAL"); | |||||
| BLI_assert(verts_x > 0 && verts_y > 0); | BLI_assert(verts_x > 0 && verts_y > 0); | ||||
| const int edges_x = verts_x - 1; | const int edges_x = verts_x - 1; | ||||
| const int edges_y = verts_y - 1; | const int edges_y = verts_y - 1; | ||||
| Mesh *mesh = BKE_mesh_new_nomain(verts_x * verts_y, | Mesh *mesh = BKE_mesh_new_nomain(verts_x * verts_y, | ||||
| edges_x * verts_y + edges_y * verts_x, | edges_x * verts_y + edges_y * verts_x, | ||||
| 0, | 0, | ||||
| edges_x * edges_y * 4, | edges_x * edges_y * 4, | ||||
| edges_x * edges_y); | edges_x * edges_y); | ||||
| MutableSpan<MVert> verts{mesh->mvert, mesh->totvert}; | MutableSpan<MVert> verts{mesh->mvert, mesh->totvert}; | ||||
| MutableSpan<MLoop> loops{mesh->mloop, mesh->totloop}; | MutableSpan<MLoop> loops{mesh->mloop, mesh->totloop}; | ||||
| MutableSpan<MEdge> edges{mesh->medge, mesh->totedge}; | MutableSpan<MEdge> edges{mesh->medge, mesh->totedge}; | ||||
| MutableSpan<MPoly> polys{mesh->mpoly, mesh->totpoly}; | MutableSpan<MPoly> polys{mesh->mpoly, mesh->totpoly}; | ||||
| { | { | ||||
| const float dx = edges_x == 0 ? 0.0f : size_x / edges_x; | const float dx = edges_x == 0 ? 0.0f : size_x / edges_x; | ||||
| const float dy = edges_y == 0 ? 0.0f : size_y / edges_y; | const float dy = edges_y == 0 ? 0.0f : size_y / edges_y; | ||||
| const float x_shift = edges_x / 2.0f; | const float x_shift = edges_x / 2.0f; | ||||
| const float y_shift = edges_y / 2.0f; | const float y_shift = edges_y / 2.0f; | ||||
| for (const int x_index : IndexRange(verts_x)) { | threading::parallel_for(IndexRange(verts_x), 512, [&](IndexRange x_range) { | ||||
| for (const int y_index : IndexRange(verts_y)) { | for (const int x : x_range) { | ||||
| const int vert_index = x_index * verts_y + y_index; | const int y_offset = x * verts_y; | ||||
| verts[vert_index].co[0] = (x_index - x_shift) * dx; | threading::parallel_for(IndexRange(verts_y), 512, [&](IndexRange y_range) { | ||||
| verts[vert_index].co[1] = (y_index - y_shift) * dy; | for (const int y : y_range) { | ||||
| const int vert_index = y_offset + y; | |||||
| verts[vert_index].co[0] = (x - x_shift) * dx; | |||||
| verts[vert_index].co[1] = (y - y_shift) * dy; | |||||
| verts[vert_index].co[2] = 0.0f; | verts[vert_index].co[2] = 0.0f; | ||||
| } | } | ||||
| }); | |||||
| } | } | ||||
| }); | |||||
| } | } | ||||
| /* Point all vertex normals in the up direction. */ | /* Point all vertex normals in the up direction. */ | ||||
| { | |||||
| const short up_normal[3] = {0, 0, SHRT_MAX}; | const short up_normal[3] = {0, 0, SHRT_MAX}; | ||||
| for (MVert &vert : verts) { | for (MVert &vert : verts) { | ||||
| copy_v3_v3_short(vert.no, up_normal); | copy_v3_v3_short(vert.no, up_normal); | ||||
| } | } | ||||
| } | |||||
| /* Build the horizontal edges in the X direction. */ | |||||
| const int y_edges_start = 0; | const int y_edges_start = 0; | ||||
| const int x_edges_start = verts_x * edges_y; | |||||
| const short edge_flag = (edges_x == 0 || edges_y == 0) ? ME_LOOSEEDGE : | const short edge_flag = (edges_x == 0 || edges_y == 0) ? ME_LOOSEEDGE : | ||||
| ME_EDGEDRAW | ME_EDGERENDER; | ME_EDGEDRAW | ME_EDGERENDER; | ||||
| int edge_index = 0; | |||||
| for (const int x : IndexRange(verts_x)) { | /* Build the horizontal edges in the X direction. */ | ||||
| for (const int y : IndexRange(edges_y)) { | threading::parallel_for(IndexRange(verts_x), 512, [&](IndexRange x_range) { | ||||
| const int vert_index = x * verts_y + y; | for (const int x : x_range) { | ||||
| MEdge &edge = edges[edge_index++]; | const int y_vert_offset = x * verts_y; | ||||
| const int y_edge_offset = y_edges_start + x * edges_y; | |||||
| threading::parallel_for(IndexRange(edges_y), 512, [&](IndexRange y_range) { | |||||
| for (const int y : y_range) { | |||||
| const int vert_index = y_vert_offset + y; | |||||
| MEdge &edge = edges[y_edge_offset + y]; | |||||
| edge.v1 = vert_index; | edge.v1 = vert_index; | ||||
| edge.v2 = vert_index + 1; | edge.v2 = vert_index + 1; | ||||
| edge.flag = edge_flag; | edge.flag = edge_flag; | ||||
| } | } | ||||
| }); | |||||
| } | } | ||||
| }); | |||||
| /* Build the vertical edges in the Y direction. */ | /* Build the vertical edges in the Y direction. */ | ||||
| const int x_edges_start = edge_index; | threading::parallel_for(IndexRange(verts_y), 512, [&](IndexRange y_range) { | ||||
| for (const int y : IndexRange(verts_y)) { | for (const int y : y_range) { | ||||
| for (const int x : IndexRange(edges_x)) { | const int x_edge_offset = x_edges_start + y * edges_x; | ||||
| threading::parallel_for(IndexRange(edges_x), 512, [&](IndexRange x_range) { | |||||
| for (const int x : x_range) { | |||||
| const int vert_index = x * verts_y + y; | const int vert_index = x * verts_y + y; | ||||
| MEdge &edge = edges[edge_index++]; | MEdge &edge = edges[x_edge_offset + x]; | ||||
| edge.v1 = vert_index; | edge.v1 = vert_index; | ||||
| edge.v2 = vert_index + verts_y; | edge.v2 = vert_index + verts_y; | ||||
| edge.flag = edge_flag; | edge.flag = edge_flag; | ||||
| } | } | ||||
| }); | |||||
| } | } | ||||
| }); | |||||
| int loop_index = 0; | threading::parallel_for(IndexRange(edges_x), 512, [&](IndexRange x_range) { | ||||
| int poly_index = 0; | for (const int x : x_range) { | ||||
| for (const int x : IndexRange(edges_x)) { | const int y_offset = x * edges_y; | ||||
| for (const int y : IndexRange(edges_y)) { | threading::parallel_for(IndexRange(edges_y), 512, [&](IndexRange y_range) { | ||||
| MPoly &poly = polys[poly_index++]; | for (const int y : y_range) { | ||||
| const int poly_index = y_offset + y; | |||||
| const int loop_index = poly_index * 4; | |||||
| MPoly &poly = polys[poly_index]; | |||||
| poly.loopstart = loop_index; | poly.loopstart = loop_index; | ||||
| poly.totloop = 4; | poly.totloop = 4; | ||||
| const int vert_index = x * verts_y + y; | const int vert_index = x * verts_y + y; | ||||
| MLoop &loop_a = loops[loop_index++]; | MLoop &loop_a = loops[loop_index]; | ||||
| loop_a.v = vert_index; | loop_a.v = vert_index; | ||||
| loop_a.e = x_edges_start + edges_x * y + x; | loop_a.e = x_edges_start + edges_x * y + x; | ||||
| MLoop &loop_b = loops[loop_index++]; | MLoop &loop_b = loops[loop_index + 1]; | ||||
| loop_b.v = vert_index + verts_y; | loop_b.v = vert_index + verts_y; | ||||
| loop_b.e = y_edges_start + edges_y * (x + 1) + y; | loop_b.e = y_edges_start + edges_y * (x + 1) + y; | ||||
| MLoop &loop_c = loops[loop_index++]; | MLoop &loop_c = loops[loop_index + 2]; | ||||
| loop_c.v = vert_index + verts_y + 1; | loop_c.v = vert_index + verts_y + 1; | ||||
| loop_c.e = x_edges_start + edges_x * (y + 1) + x; | loop_c.e = x_edges_start + edges_x * (y + 1) + x; | ||||
| MLoop &loop_d = loops[loop_index++]; | MLoop &loop_d = loops[loop_index + 3]; | ||||
| loop_d.v = vert_index + 1; | loop_d.v = vert_index + 1; | ||||
| loop_d.e = y_edges_start + edges_y * x + y; | loop_d.e = y_edges_start + edges_y * x + y; | ||||
| } | } | ||||
| }); | |||||
| } | } | ||||
| }); | |||||
| if (mesh->totpoly != 0) { | if (mesh->totpoly != 0) { | ||||
| calculate_uvs(mesh, verts, loops, size_x, size_y); | calculate_uvs(mesh, verts, loops, size_x, size_y); | ||||
| } | } | ||||
| return mesh; | return mesh; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 60 Lines • Show Last 20 Lines | |||||