OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-tps / scenes / test / proc_erosion_compare.gd

106 lines · gd ref:
@tool
extends Node3D

## Side-by-side comparison: erosion shader (PlaneMesh) vs DC terrain (proc-nodes).
##
## Left:  PlaneMesh 10x10 with erosion_terrain.gdshader (the known-good reference)
## Right: DCTerrain with GradientNoise → ErosionNoise matching same parameters
##
## Both use identical noise: HEIGHT_TILES=3.0, 3 octaves, gain=0.1,
## erosion_strength=0.16, height_scale=5.0.

@export var voxel_size: float = 0.1  ## Smaller = more detail (0.1 matches ~100 verts across 10m)
@export var spacing: float = 15.0  ## Gap between left and right

var _gen: DCTerrainGeneratorProcNodes

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

func _setup() -> void:
	_setup_shader_mesh()
	_setup_dc_terrain()
	print("[Compare] Left: erosion shader (PlaneMesh), Right: DC terrain (proc-nodes)")

func _setup_shader_mesh() -> void:
	# Reuse the existing erosion shader
	var shader = load("res://shaders/erosion_terrain.gdshader") as Shader
	if not shader:
		push_warning("[Compare] Missing res://shaders/erosion_terrain.gdshader")
		return

	var mat = ShaderMaterial.new()
	mat.shader = shader
	mat.set_shader_parameter("time_offset", 0.0)
	mat.set_shader_parameter("height_scale", 5.0)

	var mesh = PlaneMesh.new()
	mesh.size = Vector2(10, 10)
	mesh.subdivide_width = 255
	mesh.subdivide_depth = 255

	var mi = MeshInstance3D.new()
	mi.name = "ShaderMesh"
	mi.mesh = mesh
	mi.material_override = mat
	mi.position.x = -spacing * 0.5
	add_child(mi)
	mi.owner = get_tree().edited_scene_root if Engine.is_editor_hint() else self

func _setup_dc_terrain() -> void:
	var terrain = get_node_or_null("DCTerrain")
	if terrain == null:
		push_warning("[Compare] Add a DCTerrain child node named 'DCTerrain'")
		return

	terrain.position.x = spacing * 0.5

	# Build graph matching erosion_terrain.gdshader EXACTLY:
	# HEIGHT_TILES=3.0, HEIGHT_OCTAVES=3, HEIGHT_GAIN=0.1
	# EROSION_STRENGTH=0.16, EROSION_SLOPE_POWER=0.6, EROSION_OCTAVES=5, EROSION_GAIN=0.5
	# height_scale=5.0
	var g = ProcNodeGraph.new()

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

	var erosion = g.add_node(ErosionNoiseNode.new())
	g.get_node(erosion).set_input_default(1, 5.0)   # HeightScale = height_scale
	g.get_node(erosion).set_input_default(2, 0.16)   # ErosionStr
	g.get_node(erosion).set_input_default(3, 0.6)    # SlopePower
	g.get_node(erosion).set_input_default(4, 1.0)    # CellScale
	g.get_node(erosion).set_input_default(5, 5)      # Octaves
	g.get_node(erosion).set_input_default(6, 0.5)    # Gain

	g.connect_sockets(noise, 0, erosion, 7)  # Height
	g.connect_sockets(noise, 1, erosion, 8)  # Slope

	_gen = DCTerrainGeneratorProcNodes.new()
	# terrain_height = 10.0: noise UV space [0,1] maps to [0,10] meters (matching 10x10 PlaneMesh)
	_gen.set_terrain_height(10.0)
	_gen.set_graph(g)

	# Match the PlaneMesh dimensions: 10x10m terrain with fine voxels.
	# terrain_size (octree extent) must cover the full height range.
	# HeightScale=5 → surface at y≈2.5, so 12m octree is enough.
	# If you increase HeightScale, increase terrain_size to match.
	terrain.set("terrain_size", 16.0)
	terrain.set("voxel_size", voxel_size)
	terrain.set("use_gpu", true)
	terrain.set("use_noise", true)
	terrain.set("generator", _gen)

	# Apply altitude color shader matching erosion_terrain.gdshader palette
	var shader = load("res://scenes/maps/dc_erosion_color.gdshader") as Shader
	if shader:
		var mat = ShaderMaterial.new()
		mat.shader = shader
		mat.set_shader_parameter("height_scale", 5.0)
		mat.set_shader_parameter("water_height", 0.465)
		mat.set_shader_parameter("terrain_height", 10.0)
		terrain.set("custom_material", mat)

	print("[Compare] DC terrain: size=16m, voxel=", voxel_size, "m, terrain_height=10.0")