OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-tps / scenes / test / erosion_blender_test.gd

100 lines · gd ref:
@tool
extends Node3D

## Test: decomposed erosion terrain synced to Blender.
## Single ProcGeometryNode with UV → GradientNoise → ErosionNoise → AltitudeColor.

@export var generate: bool = false:
	set(v):
		if v: _build()
		generate = false

var _bridge: BlenderBridge

func _ready() -> void:
	call_deferred("_setup")

func _setup() -> void:
	_build()
	_bridge = $BlenderBridge as BlenderBridge
	if _bridge and Engine.is_editor_hint():
		_bridge.start_server("/tmp/blender_bridge.sock")
		set_process(true)
		print("[BlenderTest] Bridge started")

var _exported := false

func _process(_delta: float) -> void:
	if not Engine.is_editor_hint() or not _bridge:
		return
	if _bridge.is_blender_connected() and not _exported:
		var tree := get_tree()
		if tree and tree.edited_scene_root:
			_bridge.export_scene(tree.edited_scene_root)
			_exported = true
			print("[BlenderTest] Exported to Blender")

func _build() -> void:
	var proc := $Terrain as ProcGeometryNode
	if not proc: return

	var g := ProcNodeGraph.new()

	var grid := g.add_node(MeshGridNode.new())
	g.get_node(grid).set_input_default(0, 10.0)
	g.get_node(grid).set_input_default(1, 10.0)
	g.get_node(grid).set_input_default(2, 256)
	g.get_node(grid).set_input_default(3, 256)

	var uv := g.add_node(UVNode.new())

	var noise := g.add_node(GradientNoiseNode.new())
	g.get_node(noise).set_input_default(1, 3.0)  # Scale
	g.get_node(noise).set_input_default(2, 3)    # Detail
	g.get_node(noise).set_input_default(3, 0.1)  # Gain

	var erosion := g.add_node(ErosionNoiseNode.new())

	var color := g.add_node(AltitudeColorNode.new())

	g.connect_sockets(grid, 0, uv, 0)
	g.connect_sockets(uv, 0, noise, 0)
	g.connect_sockets(grid, 0, erosion, 0)
	g.connect_sockets(noise, 0, erosion, 7)  # Height
	g.connect_sockets(noise, 1, erosion, 8)  # Slope
	g.connect_sockets(erosion, 0, color, 0)
	g.connect_sockets(erosion, 1, color, 3)

	g.get_node(grid).set_graph_position(Vector2(-600, 0))
	g.get_node(uv).set_graph_position(Vector2(-400, -80))
	g.get_node(noise).set_graph_position(Vector2(-200, -80))
	g.get_node(erosion).set_graph_position(Vector2(0, 0))
	g.get_node(color).set_graph_position(Vector2(200, 0))

	proc.set_graph(g)

	# Test GLSL compilation of the erosion graph
	var glsl = g.compile_to_glsl_function("terrain_density")
	if glsl.length() > 200 and glsl.contains("terrain_density") and glsl.contains("erosion_filter"):
		print("[BlenderTest] PASS: Erosion graph compiled to GLSL (" + str(glsl.length()) + " chars)")
	else:
		print("[BlenderTest] FAIL: GLSL compilation incomplete")
		print(glsl.substr(0, 500))

	# Apply vertex color material after evaluation
	call_deferred("_apply_mat")
	print("[BlenderTest] Built: UV → GradientNoise → ErosionNoise → AltitudeColor")

func _apply_mat() -> void:
	var proc := $Terrain as ProcGeometryNode
	if not proc or not is_inside_tree(): return
	await get_tree().process_frame
	if not is_inside_tree(): return
	await get_tree().process_frame
	var mo := proc.get_node_or_null(NodePath("MeshOutput")) as MeshInstance3D
	if mo:
		var mat := StandardMaterial3D.new()
		mat.vertex_color_use_as_albedo = true
		mat.roughness = 0.85
		mo.material_override = mat