OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-tps / scenes / test / gate_winding.gd

71 lines · gd ref:
extends SceneTree
## Does the terrain mesh wind the same way Godot's own meshes do?
##
## Godot's front-face convention is not something to remember: PlaneMesh faces
## +Y, its stored normal is (0,1,0), and cross(b-a, c-a) over its index order is
## (0,-1,0). So the geometric cross of a front-facing triangle points AGAINST
## its shading normal. Getting that backwards renders the terrain inside out,
## which is exactly what the first version did.
##
## This asks PlaneMesh for the convention each run rather than hard-coding it,
## so it stays correct if the engine ever changes, and compares our first
## triangle against it.
##
##   "$HYPER_TPS_GODOT" --headless --path . --script res://scenes/test/gate_winding.gd

var _m: Node = null


func _tri_cross(v: PackedVector3Array, i: PackedInt32Array, t: int) -> Vector3:
	var a := v[i[t * 3]]
	var b := v[i[t * 3 + 1]]
	var c := v[i[t * 3 + 2]]
	return (b - a).cross(c - a).normalized()


func _init() -> void:
	var packed := load("res://scenes/maps/map_heightmap.tscn") as PackedScene
	if packed == null:
		print("FAIL — map_heightmap.tscn did not load"); quit(2); return
	_m = packed.instantiate()
	root.add_child(_m)


func _process(_dt: float) -> bool:
	var pm := PlaneMesh.new()
	pm.size = Vector2(10, 10)
	var pa: Array = pm.get_mesh_arrays()
	var ref_cross := _tri_cross(pa[Mesh.ARRAY_VERTEX], pa[Mesh.ARRAY_INDEX], 0)
	var ref_normal: Vector3 = (pa[Mesh.ARRAY_NORMAL] as PackedVector3Array)[0]
	print("  REFERENCE PlaneMesh (faces +Y): cross %s, stored normal %s"
			% [str(ref_cross), str(ref_normal.round())])

	var mi = _m.get_node_or_null("TerrainMesh")
	if mi == null:
		print("FAIL — no TerrainMesh"); quit(1); return true
	var arrs: Array = mi.mesh.surface_get_arrays(0)
	var our_cross := _tri_cross(arrs[Mesh.ARRAY_VERTEX], arrs[Mesh.ARRAY_INDEX], 0)
	var our_normal: Vector3 = (arrs[Mesh.ARRAY_NORMAL] as PackedVector3Array)[0]
	print("  TERRAIN   tri0:                 cross %s, stored normal %s"
			% [str(our_cross.round()), str(our_normal.round())])

	var fails := 0
	# Both surfaces face up, so both must have the same cross sign.
	if signf(our_cross.y) != signf(ref_cross.y):
		print("  FAIL — winding is flipped relative to PlaneMesh: renders inside out")
		fails += 1
	# And the shading normal must still point up, or lighting is wrong even when
	# the winding is right. These are two different mistakes.
	if our_normal.y <= 0.0:
		print("  FAIL — shading normal points down")
		fails += 1

	print("")
	if fails == 0:
		print("VERDICT: the terrain winds the same way Godot's own meshes do,")
		print("         and its normals point up.")
	else:
		print("VERDICT: ", fails, " check(s) failed.")
	quit(0 if fails == 0 else 1)
	return true