OverviewFilesCommitsIssuesDocsReleasesPeers

proc-nodes / demo / sphere_winding_probe.gd

43 lines · gd ref:
## Which way are the primitives wound, and which of their triangles have no area?
##
## Both questions belong to Mesh to SDF Grid: libdc takes a face normal as
## (v1-v0)x(v2-v0), so the enclosed volume under that same cross product says
## whether its pseudonormals point out of the mesh or into it -- and a triangle
## with no thickness has no normal at all, only rounding noise, which is enough
## to flip the field beside it.
extends SceneTree

func _report(label: String, m) -> void:
	var p: PackedVector3Array = m.to_array_mesh().surface_get_arrays(0)[Mesh.ARRAY_VERTEX]
	var idx: PackedInt32Array = m.get_indices()
	var bb := AABB(p[0], Vector3.ZERO)
	for v in p:
		bb = bb.expand(v)
	var min_height := bb.size.length() * 1e-6
	var vol := 0.0
	var slivers := 0
	for t in range(int(idx.size() / 3)):
		var a := p[idx[t*3]]
		var b := p[idx[t*3+1]]
		var c := p[idx[t*3+2]]
		vol += a.dot(b.cross(c)) / 6.0
		var twice_area := (b - a).cross(c - a).length()
		var longest: float = max(max((b-a).length(), (c-b).length()), (a-c).length())
		if longest <= 0.0 or twice_area / longest < min_height:
			slivers += 1
	print("%-11s %5d tris  volume %+9.5f (%s)  %d with no area" %
			[label, int(idx.size()/3), vol,
			 "libdc normals OUTWARD" if vol > 0.0 else "libdc normals INWARD", slivers])

func _init() -> void:
	var g := ProcNodeGraph.new()
	var s := g.add_node(MeshUVSphereNode.new())
	g.get_node(s).set_input_default(2, 1.0)
	_report("uv sphere", g.evaluate_socket(s, 0).get_mesh())
	_report("ico sphere", g.evaluate_socket(g.add_node(MeshIcoSphereNode.new()), 0).get_mesh())
	_report("cube", g.evaluate_socket(g.add_node(MeshCubeNode.new()), 0).get_mesh())
	_report("cylinder", g.evaluate_socket(g.add_node(MeshCylinderNode.new()), 0).get_mesh())
	_report("circle", g.evaluate_socket(g.add_node(MeshCircleNode.new()), 0).get_mesh())
	_report("grid", g.evaluate_socket(g.add_node(MeshGridNode.new()), 0).get_mesh())
	quit(0)