@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