extends Node3D enum CanopyVariant { GREEN, DARK_GREEN, YELLOW_GREEN, } const COLORS := { CanopyVariant.GREEN: Color(0.40, 0.62, 0.28), CanopyVariant.DARK_GREEN: Color(0.26, 0.51, 0.34), CanopyVariant.YELLOW_GREEN: Color(0.55, 0.67, 0.29), } const TREE_MODEL := preload("res://assets/painterly/painterly_tree.glb") const WIND_SHADER := preload("res://world/jajce/materials/wind.gdshader") const WIND_STRENGTH := 0.07 const WIND_SPEED := 0.55 static var _canopy_mesh: Mesh static var _trunk_mesh: Mesh static var _bark_material: StandardMaterial3D func _ready() -> void: for child in get_children(): child.queue_free() var hash_seed := hash(global_position) var rng := RandomNumberGenerator.new() rng.seed = hash_seed var canopy_variant := rng.randi() % COLORS.size() as CanopyVariant var canopy_radius := 1.25 + rng.randf() * 0.6 var wind_phase := rng.randf_range(0.0, TAU) _ensure_shared_meshes() var trunk := MeshInstance3D.new() trunk.name = "Trunk" trunk.mesh = _trunk_mesh trunk.material_override = _bark_material add_child(trunk) var canopy_color: Color = COLORS[canopy_variant] var crown_height := 3.7 + (canopy_radius - 1.2) * 0.45 _add_canopy( "Canopy", Vector3(0.0, crown_height, 0.0), Vector3(canopy_radius * 1.18, canopy_radius * 0.96, canopy_radius * 1.05), canopy_color, wind_phase ) _add_canopy( "CanopyLeft", Vector3(-0.94, crown_height - 0.27, 0.14), Vector3(canopy_radius * 0.84, canopy_radius * 0.79, canopy_radius * 0.84), canopy_color.lightened(0.05), wind_phase + 0.12 ) _add_canopy( "CanopyRight", Vector3(0.91, crown_height - 0.08, -0.2), Vector3(canopy_radius * 0.82, canopy_radius * 0.73, canopy_radius * 0.79), canopy_color.darkened(0.04), wind_phase - 0.1 ) _add_canopy( "CanopyTop", Vector3(0.13, crown_height + 0.68, -0.08), Vector3(canopy_radius * 0.78, canopy_radius * 0.74, canopy_radius * 0.75), canopy_color.lightened(0.08), wind_phase + 0.05 ) static func _ensure_shared_meshes() -> void: if _canopy_mesh != null: return var source := TREE_MODEL.instantiate() _canopy_mesh = (source.find_child("Canopy", true, false) as MeshInstance3D).mesh _trunk_mesh = (source.find_child("Trunk", true, false) as MeshInstance3D).mesh _bark_material = StandardMaterial3D.new() _bark_material.vertex_color_use_as_albedo = true _bark_material.roughness = 0.95 _bark_material.specular_mode = BaseMaterial3D.SPECULAR_DISABLED source.free() func _add_canopy( canopy_name: String, canopy_position: Vector3, canopy_scale: Vector3, canopy_color: Color, wind_phase: float ) -> void: var material := ShaderMaterial.new() material.shader = WIND_SHADER material.set_shader_parameter("albedo", canopy_color) material.set_shader_parameter("roughness", 0.9) material.set_shader_parameter("wind_strength", WIND_STRENGTH) material.set_shader_parameter("wind_speed", WIND_SPEED) material.set_shader_parameter("wind_phase", wind_phase) material.set_shader_parameter("painted_vertex_weight", 1.0) var canopy := MeshInstance3D.new() canopy.name = canopy_name canopy.mesh = _canopy_mesh canopy.material_override = material canopy.position = canopy_position canopy.scale = canopy_scale canopy.rotation.y = wind_phase * 0.43 + canopy_position.x * 0.31 add_child(canopy)