class_name ForestEdgeResourceCluster extends TerrainResourceCluster const FERN_OFFSETS := [ Vector3(-5.4, 0.0, 1.8), Vector3(-3.2, 0.0, -1.7), Vector3(-1.3, 0.0, 2.9), Vector3(1.1, 0.0, -2.8), Vector3(2.8, 0.0, 1.4), Vector3(4.8, 0.0, -3.1), Vector3(6.2, 0.0, 2.5), Vector3(8.5, 0.0, -1.2), Vector3(10.6, 0.0, 1.0), Vector3(-7.4, 0.0, -2.9), ] const MUSHROOM_OFFSETS := [ Vector3(-4.4, 0.0, -0.2), Vector3(-2.1, 0.0, 1.2), Vector3(0.3, 0.0, -3.5), Vector3(2.2, 0.0, 3.2), Vector3(5.0, 0.0, 0.2), Vector3(7.1, 0.0, -2.8), Vector3(9.3, 0.0, 2.6), Vector3(-6.5, 0.0, 2.9), ] const STONE_OFFSETS := [ Vector3(-6.8, 0.0, 0.2), Vector3(-2.7, 0.0, -3.4), Vector3(0.7, 0.0, 0.4), Vector3(4.0, 0.0, 3.5), Vector3(7.8, 0.0, 0.8), Vector3(10.8, 0.0, -2.2), ] func _build_understory() -> void: var fern_material := StandardMaterial3D.new() fern_material.albedo_color = Color("#2f5935") fern_material.roughness = 0.95 fern_material.cull_mode = BaseMaterial3D.CULL_DISABLED _assign_multimesh( $DecorativeInstances/Understory/FernClumps, _create_fern_mesh(fern_material), FERN_OFFSETS, Vector3(0.86, 0.86, 0.86), 0.03 ) _assign_multimesh( $DecorativeInstances/Understory/MushroomClumps, _create_mushroom_mesh(), MUSHROOM_OFFSETS, Vector3(1.0, 1.0, 1.0), 0.02 ) var stone_mesh := SphereMesh.new() stone_mesh.radius = 1.0 stone_mesh.height = 2.0 stone_mesh.radial_segments = 8 stone_mesh.rings = 4 var stone_material := StandardMaterial3D.new() stone_material.albedo_color = Color("#68695d") stone_material.roughness = 0.97 stone_mesh.material = stone_material _assign_multimesh( $DecorativeInstances/Understory/ForestStones, stone_mesh, STONE_OFFSETS, Vector3(0.55, 0.22, 0.4), 0.2 ) func _create_mushroom_mesh() -> ArrayMesh: var vertices := PackedVector3Array() var normals := PackedVector3Array() var colors := PackedColorArray() var segment_count := 8 var stem_color := Color("#e8d8ae") var cap_color := Color("#d98142") var cap_under_color := Color("#b85f35") for segment in segment_count: var angle_a := float(segment) / segment_count * TAU var angle_b := float(segment + 1) / segment_count * TAU var normal_a := Vector3(cos(angle_a), 0.0, sin(angle_a)) var normal_b := Vector3(cos(angle_b), 0.0, sin(angle_b)) var stem_bottom_a := normal_a * 0.065 var stem_bottom_b := normal_b * 0.065 var stem_top_a := normal_a * 0.045 + Vector3.UP * 0.3 var stem_top_b := normal_b * 0.045 + Vector3.UP * 0.3 ( vertices . append_array( [ stem_bottom_a, stem_bottom_b, stem_top_b, stem_bottom_a, stem_top_b, stem_top_a, ] ) ) normals.append_array([normal_a, normal_b, normal_b, normal_a, normal_b, normal_a]) for _vertex in 6: colors.append(stem_color) var cap_ring_a := normal_a * 0.24 + Vector3.UP * 0.3 var cap_ring_b := normal_b * 0.24 + Vector3.UP * 0.3 var cap_top := Vector3.UP * 0.48 var cap_normal := ( Vector3( cos((angle_a + angle_b) * 0.5) * 0.55, 0.82, sin((angle_a + angle_b) * 0.5) * 0.55 ) . normalized() ) vertices.append_array([cap_top, cap_ring_b, cap_ring_a]) normals.append_array([cap_normal, cap_normal, cap_normal]) colors.append_array([cap_color, cap_color, cap_color]) vertices.append_array([Vector3.UP * 0.29, cap_ring_a, cap_ring_b]) normals.append_array([Vector3.DOWN, Vector3.DOWN, Vector3.DOWN]) colors.append_array([cap_under_color, cap_under_color, cap_under_color]) var arrays := [] arrays.resize(Mesh.ARRAY_MAX) arrays[Mesh.ARRAY_VERTEX] = vertices arrays[Mesh.ARRAY_NORMAL] = normals arrays[Mesh.ARRAY_COLOR] = colors var material := StandardMaterial3D.new() material.albedo_color = Color.WHITE material.vertex_color_use_as_albedo = true material.roughness = 0.88 var mesh := ArrayMesh.new() mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arrays) mesh.surface_set_material(0, material) return mesh