OverviewFilesCommitsIssuesDocsReleasesPeers

dc-terrain commits / 6b678f0

sdf: the sign was already known, so stop computing it twice
compute_pseudonormals was 5554 ms of a 6663 ms load_arrays on this 5.16M triangle mesh -- five times the BVH build. It exists for one thing: to give point_triangle_dist_sq a SIGN by the Baerentzen-Aanaes method, which needs per-vertex AND per-EDGE angle-weighted normals, ~15.5M edge entries here. Mesh to SDF Grid already knows inside from outside. It computes the mesh's signed volume for winding, and floods the outside from the grid boundary -- which IS outside, because the bounds are padded by the band. A caller holding that does not need a pseudonormal per query. set_unsigned_only() skips the pseudonormals and returns unsigned distance; the caller supplies the sign. Gated on the mesh being closed, because the flood is what supplies it and a hole leaks. An open mesh keeps the old path exactly. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
6b678f08ceed252816ed804046c11c38a03a227b
by plankatron <fleeky@gmail.com> · 2026-09-08T17:41:18.000Z

Changed files (2) +22 -2

libdc/include/dc_generator_mesh_sdf.h +13 -0
……@@ -87,7 +87,20 @@ private:
8787 std::vector<float> tri_centroids_;
8888 // Morton code per triangle, and the LBVH build that consumes it.
8989 std::vector<uint32_t> tri_morton_;
90 // Skip the Baerentzen-Aanaes pseudonormals and answer UNSIGNED distance.
91 //
92 // They exist only to give a query point a SIGN, and they cost 5554 ms of a
93 // 6663 ms load_arrays on a 5.16M triangle mesh -- five times the BVH build
94 // -- because they need per-vertex AND per-EDGE angle-weighted normals,
95 // ~15.5M edge entries here. A caller that already knows inside from outside
96 // does not need them. Mesh to SDF Grid does: it floods the outside from the
97 // grid boundary.
98 bool unsigned_only_ = false;
9099 void build_lbvh(int node_idx, int start, int count, int depth);
100
101public:
102 void set_unsigned_only(bool v) { unsigned_only_ = v; }
103private:
91104 float bounds_min_[3] = {};
92105 float bounds_max_[3] = {};
93106 bool loaded_ = false;
libdc/src/generators/dc_generator_mesh_sdf.cpp +9 -2
……@@ -100,7 +100,9 @@ bool DCGeneratorMeshSDF::_build_from_verts_indices(const std::vector<Vec3>& vert
100100 }
101101
102102 // Compute proper pseudonormals for robust sign determination
103 compute_pseudonormals(vertices, face_indices);
103 if (!unsigned_only_) {
104 compute_pseudonormals(vertices, face_indices);
105 }
104106
105107 // Compute bounds
106108 bounds_min_[0] = bounds_min_[1] = bounds_min_[2] = std::numeric_limits<float>::max();
……@@ -584,9 +586,14 @@ float DCGeneratorMeshSDF::evaluate(float x, float y, float z, float /*lod_voxel_
584586 Vec3 closest_normal;
585587 float signed_dist_sq = closest_distance_sq(x, y, z, closest_normal);
586588
587 float sign = (signed_dist_sq >= 0.0f) ? 1.0f : -1.0f;
588589 float dist = std::sqrt(std::fabs(signed_dist_sq));
590 if (unsigned_only_) {
591 // No pseudonormals were built, so the sign carried in signed_dist_sq is
592 // meaningless. The caller supplies it.
593 return dist;
594 }
589595
596 float sign = (signed_dist_sq >= 0.0f) ? 1.0f : -1.0f;
590597 // Convention: positive = solid (inside), negative = air (outside)
591598 return dist * sign;
592599}