Geometry Nodes: Slightly improve curve to mesh performance
For the single-threaded part of the curve to mesh conversion, avoid writing to two logically separate arrays in the same loop. Instead run the calculation on two separate threads if the output is large. Timing for `calculate_result_offsets` when processing 1 million curves: Before: Average: 10.4 ms, Min: 9.4 ms After: Average: 9.2 ms, Min: 7.7 ms
This commit is contained in:
@@ -236,63 +236,78 @@ static ResultOffsets calculate_result_offsets(const CurvesInfo &info, const bool
|
||||
{
|
||||
ResultOffsets result;
|
||||
result.total = info.main.curves_num() * info.profile.curves_num();
|
||||
result.vert.reinitialize(result.total + 1);
|
||||
result.edge.reinitialize(result.total + 1);
|
||||
result.loop.reinitialize(result.total + 1);
|
||||
result.poly.reinitialize(result.total + 1);
|
||||
|
||||
result.main_indices.reinitialize(result.total);
|
||||
result.profile_indices.reinitialize(result.total);
|
||||
|
||||
const OffsetIndices<int> main_offsets = info.main.evaluated_points_by_curve();
|
||||
const OffsetIndices<int> profile_offsets = info.profile.evaluated_points_by_curve();
|
||||
|
||||
int mesh_index = 0;
|
||||
int vert_offset = 0;
|
||||
int edge_offset = 0;
|
||||
int loop_offset = 0;
|
||||
int poly_offset = 0;
|
||||
for (const int i_main : info.main.curves_range()) {
|
||||
const bool main_cyclic = info.main_cyclic[i_main];
|
||||
const int main_point_num = main_offsets[i_main].size();
|
||||
const int main_segment_num = curves::segments_num(main_point_num, main_cyclic);
|
||||
for (const int i_profile : info.profile.curves_range()) {
|
||||
result.vert[mesh_index] = vert_offset;
|
||||
result.edge[mesh_index] = edge_offset;
|
||||
result.loop[mesh_index] = loop_offset;
|
||||
result.poly[mesh_index] = poly_offset;
|
||||
threading::parallel_invoke(
|
||||
result.total > 1024,
|
||||
[&]() {
|
||||
result.vert.reinitialize(result.total + 1);
|
||||
result.edge.reinitialize(result.total + 1);
|
||||
result.loop.reinitialize(result.total + 1);
|
||||
result.poly.reinitialize(result.total + 1);
|
||||
|
||||
result.main_indices[mesh_index] = i_main;
|
||||
result.profile_indices[mesh_index] = i_profile;
|
||||
int mesh_index = 0;
|
||||
int vert_offset = 0;
|
||||
int edge_offset = 0;
|
||||
int loop_offset = 0;
|
||||
int poly_offset = 0;
|
||||
for (const int i_main : main_offsets.index_range()) {
|
||||
const bool main_cyclic = info.main_cyclic[i_main];
|
||||
const int main_point_num = main_offsets[i_main].size();
|
||||
const int main_segment_num = curves::segments_num(main_point_num, main_cyclic);
|
||||
for (const int i_profile : profile_offsets.index_range()) {
|
||||
result.vert[mesh_index] = vert_offset;
|
||||
result.edge[mesh_index] = edge_offset;
|
||||
result.loop[mesh_index] = loop_offset;
|
||||
result.poly[mesh_index] = poly_offset;
|
||||
|
||||
const bool profile_cyclic = info.profile_cyclic[i_profile];
|
||||
const int profile_point_num = profile_offsets[i_profile].size();
|
||||
const int profile_segment_num = curves::segments_num(profile_point_num, profile_cyclic);
|
||||
const bool profile_cyclic = info.profile_cyclic[i_profile];
|
||||
const int profile_point_num = profile_offsets[i_profile].size();
|
||||
const int profile_segment_num = curves::segments_num(profile_point_num,
|
||||
profile_cyclic);
|
||||
|
||||
const bool has_caps = fill_caps && !main_cyclic && profile_cyclic && profile_point_num > 2;
|
||||
const int tube_face_num = main_segment_num * profile_segment_num;
|
||||
const bool has_caps = fill_caps && !main_cyclic && profile_cyclic &&
|
||||
profile_point_num > 2;
|
||||
const int tube_face_num = main_segment_num * profile_segment_num;
|
||||
|
||||
vert_offset += main_point_num * profile_point_num;
|
||||
vert_offset += main_point_num * profile_point_num;
|
||||
|
||||
/* Add the ring edges, with one ring for every curve vertex, and the edge loops
|
||||
* that run along the length of the curve, starting on the first profile. */
|
||||
edge_offset += main_point_num * profile_segment_num + main_segment_num * profile_point_num;
|
||||
/* Add the ring edges, with one ring for every curve vertex, and the edge loops
|
||||
* that run along the length of the curve, starting on the first profile. */
|
||||
edge_offset += main_point_num * profile_segment_num +
|
||||
main_segment_num * profile_point_num;
|
||||
|
||||
/* Add two cap N-gons for every ending. */
|
||||
poly_offset += tube_face_num + (has_caps ? 2 : 0);
|
||||
/* Add two cap N-gons for every ending. */
|
||||
poly_offset += tube_face_num + (has_caps ? 2 : 0);
|
||||
|
||||
/* All faces on the tube are quads, and all cap faces are N-gons with an edge for each
|
||||
* profile edge. */
|
||||
loop_offset += tube_face_num * 4 + (has_caps ? profile_segment_num * 2 : 0);
|
||||
/* All faces on the tube are quads, and all cap faces are N-gons with an edge for each
|
||||
* profile edge. */
|
||||
loop_offset += tube_face_num * 4 + (has_caps ? profile_segment_num * 2 : 0);
|
||||
|
||||
mesh_index++;
|
||||
}
|
||||
}
|
||||
mesh_index++;
|
||||
}
|
||||
}
|
||||
|
||||
result.vert.last() = vert_offset;
|
||||
result.edge.last() = edge_offset;
|
||||
result.loop.last() = loop_offset;
|
||||
result.poly.last() = poly_offset;
|
||||
result.vert.last() = vert_offset;
|
||||
result.edge.last() = edge_offset;
|
||||
result.loop.last() = loop_offset;
|
||||
result.poly.last() = poly_offset;
|
||||
},
|
||||
[&]() {
|
||||
result.main_indices.reinitialize(result.total);
|
||||
result.profile_indices.reinitialize(result.total);
|
||||
|
||||
int mesh_index = 0;
|
||||
for (const int i_main : main_offsets.index_range()) {
|
||||
for (const int i_profile : profile_offsets.index_range()) {
|
||||
result.main_indices[mesh_index] = i_main;
|
||||
result.profile_indices[mesh_index] = i_profile;
|
||||
mesh_index++;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user