## 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)