[Bf-blender-cvs] [bc0d55e724a] master: Fix: Avoid floating point error in some mesh primitive nodes

Mattias Fredriksson noreply at git.blender.org
Fri Aug 6 01:34:47 CEST 2021


Commit: bc0d55e724a27fba61a93cc95f2cc48e205e1cd8
Author: Mattias Fredriksson
Date:   Thu Aug 5 18:34:32 2021 -0500
Branches: master
https://developer.blender.org/rBbc0d55e724a27fba61a93cc95f2cc48e205e1cd8

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

===================================================================

M	source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc
M	source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc
M	source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc
M	source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc
M	source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc

===================================================================

diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc
index 96c6f073ab3..131f9548b40 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc
@@ -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));
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc
index 790a518e584..b834f5e2fa0 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc
@@ -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));
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc
index 7a97ae8e318..410290c79ee 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc
@@ -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;
     }
   }
 
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc
index a193c05daa1..2e6d8ca34c8 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc
@@ -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);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc
index fe456dc4564..affba602234 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc
@@ -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));



More information about the Bf-blender-cvs mailing list