@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")