Skip to content
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 25 additions & 31 deletions ppsci/geometry/mesh.py
Original file line number Diff line number Diff line change
Expand Up @@ -1360,44 +1360,38 @@ def sample_in_triangle(v0, v1, v2, n, random="pseudo", criteria=None):


def make_sdf(vectors: np.ndarray):
verts = vectors.reshape(-1, 3)
v_min = verts.min(axis=0)
v_max = verts.max(axis=0)
max_dis = np.max(v_max - v_min)
norm_mesh = (verts - v_min) / max_dis

mesh_vertices = [tuple(v) for v in norm_mesh.tolist()]
mesh_indices = np.arange(len(mesh_vertices), dtype=np.int32)

def sdf_func(points: np.ndarray, compute_sdf_derivatives=False):
points = points.copy()
x_min, y_min, z_min = np.min(points, axis=0)
x_max, y_max, z_max = np.max(points, axis=0)
max_dis = max(max((x_max - x_min), (y_max - y_min)), (z_max - z_min))
store_triangles = vectors.copy()
store_triangles[:, :, 0] -= x_min
store_triangles[:, :, 1] -= y_min
store_triangles[:, :, 2] -= z_min
store_triangles *= 1 / max_dis
store_triangles = store_triangles.reshape([-1, 3])
points[:, 0] -= x_min
points[:, 1] -= y_min
points[:, 2] -= z_min
points *= 1 / max_dis
points = points.astype(np.float64).ravel()
pts = (points - v_min) / max_dis

# compute sdf values
sdf = sdf_module.signed_distance_field(
store_triangles,
np.arange((store_triangles.shape[0])),
points,
input_points = [tuple(p) for p in pts.tolist()]

ret = sdf_module.signed_distance_field(
mesh_vertices,
mesh_indices,
input_points,
include_hit_points=compute_sdf_derivatives,
)

if compute_sdf_derivatives:
sdf, sdf_derives = sdf
sdf, grad = ret
else:
sdf = ret
grad = None

sdf = sdf.numpy()
sdf = np.expand_dims(max_dis * sdf, axis=1)
sdf = sdf.numpy().reshape(-1, 1) * max_dis

if compute_sdf_derivatives:
sdf_derives = sdf_derives.numpy().reshape(-1)
sdf_derives = -(sdf_derives - points)
sdf_derives = np.reshape(sdf_derives, (sdf_derives.shape[0] // 3, 3))
sdf_derives = sdf_derives / np.linalg.norm(
sdf_derives, axis=1, keepdims=True
)
return sdf, sdf_derives
if grad is not None:
grad = grad.numpy().reshape(-1, 3)
Copy link

Copilot AI Feb 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The gradient calculation is incorrect. The variable grad is the hit point (closest point on mesh surface) returned from the warp SDF module, not the gradient itself. The gradient of the signed distance field should be the normalized vector from the query point to the closest surface point.

The current code returns the hit point coordinates directly, but it should compute the direction vector and normalize it. The correct implementation should be:

  1. Compute the direction vector: grad_vec = grad.numpy().reshape(-1, 3) - pts
  2. Normalize it: grad = grad_vec / np.linalg.norm(grad_vec, axis=1, keepdims=True)

This matches the implementation in the SDFMesh.sdf_func method (lines 826-828) which correctly computes gradients as normalized vectors from query points to hit points.

Suggested change
grad = grad.numpy().reshape(-1, 3)
# `grad` from the SDF module are hit points in normalized coordinates.
# Convert them into normalized gradient directions from query points
# to the closest surface points.
hit_points = grad.numpy().reshape(-1, 3)
grad_vec = hit_points - pts
norms = np.linalg.norm(grad_vec, axis=1, keepdims=True)
# Avoid division by zero for degenerate cases
norms[norms == 0] = 1.0
grad = grad_vec / norms

Copilot uses AI. Check for mistakes.
return sdf, grad

return sdf

Expand Down
Loading