Fix: Avoid floating point error in some mesh primitive nodes
Some mesh primitives created using geometry nodes use loops to create vertices and accumulates positions/angles in FP variables. This allows rounding errors to accumulate and can introduce significant errors. To minimize changes from original implementation, variables allowing errors to accumulate are replaced by: delta * index. Affected Mesh Primitives nodes are Line, Grid, Cylinder, Circle, Cone, and UV-Sphere. Differential Revision: https://developer.blender.org/D12136
This commit is contained in:
parent
263fa406cd
commit
bc0d55e724
Notes:
blender-bot
2024-01-06 18:56:35 +01:00
Referenced by pull request #116729, WIP: Refactoring: Geometry Nodes: Rewrite Ico Sphere mesh primitive
|
@ -126,11 +126,11 @@ static Mesh *create_circle_mesh(const float radius,
|
|||
MutableSpan<MEdge> edges{mesh->medge, mesh->totedge};
|
||||
MutableSpan<MPoly> polys{mesh->mpoly, mesh->totpoly};
|
||||
|
||||
float angle = 0.0f;
|
||||
const float angle_delta = 2.0f * M_PI / static_cast<float>(verts_num);
|
||||
for (MVert &vert : verts) {
|
||||
copy_v3_v3(vert.co, float3(std::cos(angle) * radius, std::sin(angle) * radius, 0.0f));
|
||||
angle += angle_delta;
|
||||
/* Assign vertex coordinates. */
|
||||
const float angle_delta = 2.0f * (M_PI / static_cast<float>(verts_num));
|
||||
for (const int i : IndexRange(verts_num)) {
|
||||
const float angle = i * angle_delta;
|
||||
copy_v3_v3(verts[i].co, float3(std::cos(angle) * radius, std::sin(angle) * radius, 0.0f));
|
||||
}
|
||||
if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
|
||||
copy_v3_v3(verts.last().co, float3(0));
|
||||
|
|
|
@ -318,9 +318,9 @@ Mesh *create_cylinder_or_cone_mesh(const float radius_top,
|
|||
/* Calculate vertex positions. */
|
||||
const int top_verts_start = 0;
|
||||
const int bottom_verts_start = top_verts_start + (!top_is_point ? verts_num : 1);
|
||||
float angle = 0.0f;
|
||||
const float angle_delta = 2.0f * M_PI / static_cast<float>(verts_num);
|
||||
const float angle_delta = 2.0f * (M_PI / static_cast<float>(verts_num));
|
||||
for (const int i : IndexRange(verts_num)) {
|
||||
const float angle = i * angle_delta;
|
||||
const float x = std::cos(angle);
|
||||
const float y = std::sin(angle);
|
||||
if (!top_is_point) {
|
||||
|
@ -330,7 +330,6 @@ Mesh *create_cylinder_or_cone_mesh(const float radius_top,
|
|||
copy_v3_v3(verts[bottom_verts_start + i].co,
|
||||
float3(x * radius_bottom, y * radius_bottom, -height));
|
||||
}
|
||||
angle += angle_delta;
|
||||
}
|
||||
if (top_is_point) {
|
||||
copy_v3_v3(verts[top_verts_start].co, float3(0.0f, 0.0f, height));
|
||||
|
|
|
@ -79,19 +79,17 @@ static Mesh *create_grid_mesh(const int verts_x,
|
|||
MutableSpan<MPoly> polys{mesh->mpoly, mesh->totpoly};
|
||||
|
||||
{
|
||||
const float dx = size_x / edges_x;
|
||||
const float dy = size_y / edges_y;
|
||||
float x = -size_x * 0.5;
|
||||
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 x_shift = edges_x / 2.0f;
|
||||
const float y_shift = edges_y / 2.0f;
|
||||
for (const int x_index : IndexRange(verts_x)) {
|
||||
float y = -size_y * 0.5;
|
||||
for (const int y_index : IndexRange(verts_y)) {
|
||||
const int vert_index = x_index * verts_y + y_index;
|
||||
verts[vert_index].co[0] = x;
|
||||
verts[vert_index].co[1] = y;
|
||||
verts[vert_index].co[0] = (x_index - x_shift) * dx;
|
||||
verts[vert_index].co[1] = (y_index - y_shift) * dy;
|
||||
verts[vert_index].co[2] = 0.0f;
|
||||
y += dy;
|
||||
}
|
||||
x += dx;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -118,11 +118,9 @@ static Mesh *create_line_mesh(const float3 start, const float3 delta, const int
|
|||
short normal[3];
|
||||
normal_float_to_short_v3(normal, delta.normalized());
|
||||
|
||||
float3 co = start;
|
||||
for (const int i : verts.index_range()) {
|
||||
copy_v3_v3(verts[i].co, co);
|
||||
copy_v3_v3(verts[i].co, start + delta * i);
|
||||
copy_v3_v3_short(verts[i].no, normal);
|
||||
co += delta;
|
||||
}
|
||||
|
||||
fill_edge_data(edges);
|
||||
|
|
|
@ -69,26 +69,24 @@ static void calculate_sphere_vertex_data(MutableSpan<MVert> verts,
|
|||
const int rings)
|
||||
{
|
||||
const float delta_theta = M_PI / rings;
|
||||
const float delta_phi = (2 * M_PI) / segments;
|
||||
const float delta_phi = (2.0f * M_PI) / segments;
|
||||
|
||||
copy_v3_v3(verts[0].co, float3(0.0f, 0.0f, radius));
|
||||
normal_float_to_short_v3(verts[0].no, float3(0.0f, 0.0f, 1.0f));
|
||||
|
||||
int vert_index = 1;
|
||||
float theta = delta_theta;
|
||||
for (const int UNUSED(ring) : IndexRange(rings - 1)) {
|
||||
float phi = 0.0f;
|
||||
const float z = cosf(theta);
|
||||
for (const int UNUSED(segment) : IndexRange(segments)) {
|
||||
for (const int ring : IndexRange(1, rings - 1)) {
|
||||
const float theta = ring * delta_theta;
|
||||
const float z = std::cos(theta);
|
||||
for (const int segment : IndexRange(1, segments)) {
|
||||
const float phi = segment * delta_phi;
|
||||
const float sin_theta = std::sin(theta);
|
||||
const float x = sin_theta * std::cos(phi);
|
||||
const float y = sin_theta * std::sin(phi);
|
||||
copy_v3_v3(verts[vert_index].co, float3(x, y, z) * radius);
|
||||
normal_float_to_short_v3(verts[vert_index].no, float3(x, y, z));
|
||||
phi += delta_phi;
|
||||
vert_index++;
|
||||
}
|
||||
theta += delta_theta;
|
||||
}
|
||||
|
||||
copy_v3_v3(verts.last().co, float3(0.0f, 0.0f, -radius));
|
||||
|
|
Loading…
Reference in New Issue