## The SDF-grid family, end to end: mesh -> grid -> fillet -> mesh.
##
## This is MTN_Solidify's chain, which mountain_voronoi1.blend is built from and
## which was skipped at import until these three nodes existed.
extends SceneTree
var _fail := 0
func _ck(n: String, ok: bool, d: String) -> void:
print(" %-34s %s %s" % [n, "PASS" if ok else "FAIL", d])
if not ok: _fail += 1
func _init() -> void:
var g := ProcNodeGraph.new()
var sphere := g.add_node(MeshUVSphereNode.new())
g.get_node(sphere).set_input_default(2, 1.0) # radius
var to_grid := g.add_node(MeshToSDFGridNode.new())
g.get_node(to_grid).set_input_default(1, 0.25) # voxel size (Blender's default is 0.30)
g.connect_sockets(sphere, 0, to_grid, 0)
var fillet := g.add_node(SDFGridFilletNode.new())
g.get_node(fillet).set_input_default(1, 1) # iterations
g.connect_sockets(to_grid, 0, fillet, 0)
var to_mesh := g.add_node(GridToMeshNode.new())
g.connect_sockets(fillet, 0, to_mesh, 0)
var grid_geo = g.evaluate_socket(to_grid, 0)
var vol = grid_geo.get_volume() if grid_geo != null else null
_ck("mesh -> SDF grid", vol != null and vol.get_density_grid().size() > 0,
"%d voxels, res %v" % [vol.get_density_grid().size() if vol != null else 0,
vol.get_grid_resolution() if vol != null else Vector3i.ZERO])
var out = g.evaluate_socket(to_mesh, 0)
var m = out.get_mesh() if out != null else null
_ck("grid -> mesh", m != null and m.get_vertex_count() > 0 and m.get_triangle_count() > 0,
"%d verts, %d tris" % [m.get_vertex_count() if m != null else -1,
m.get_triangle_count() if m != null else -1])
if m != null and m.get_vertex_count() > 0:
# ProcMesh.positions is a C++ member, not a bound property; the only
# way into the vertices from GDScript is the ArrayMesh it builds.
var verts: PackedVector3Array = m.to_array_mesh().surface_get_arrays(0)[Mesh.ARRAY_VERTEX]
var worst := 0.0
for i in range(verts.size()):
worst = max(worst, abs(verts[i].length() - 1.0))
# A filleted unit sphere is still about a unit sphere; the fillet rounds
# creases and a sphere has none, so this also says the fillet did not
# eat the field.
_ck("round trip is still a sphere", worst < 0.25, "worst |r-1| = %.4f" % worst)
else:
_ck("round trip is still a sphere", false, "no mesh")
print("\n%d/%d passed" % [3 - _fail, 3])
quit(1 if _fail > 0 else 0)