# This script is an addon for HungryProton's Scatter https://github.com/HungryProton/scatter # It provides a `Project on Terrain3D` modifier, which allows Scatter # to detect the terrain height from Terrain3D without using collision. # Copy this file into /addons/proton_scatter/src/modifiers # Then uncomment everything below # In the editor, add this modifier to Scatter, then set your Terrain3D node #@tool #extends "base_modifier.gd" # # #signal projection_completed # # #@export var terrain_node : NodePath #@export var align_with_collision_normal := false # #var _terrain: Terrain3D # # #func _init() -> void: # display_name = "Project On Terrain3D" # category = "Edit" # can_restrict_height = false # global_reference_frame_available = true # local_reference_frame_available = true # individual_instances_reference_frame_available = true # use_global_space_by_default() # # documentation.add_paragraph( # "This is a duplicate of `Project on Colliders` that queries the terrain system # for height and sets the transform height appropriately. # # This modifier must have terrain_node set to a Terrain3D node.") # # var p := documentation.add_parameter("Terrain Node") # p.set_type("NodePath") # p.set_description("Set your Terrain3D node.") # # p = documentation.add_parameter("Align with collision normal") # p.set_type("bool") # p.set_description( # "Rotate the transform to align it with the collision normal in case # the ray cast hit a collider.") # # #func _process_transforms(transforms, domain, _seed) -> void: # if transforms.is_empty(): # return # # if terrain_node: # _terrain = domain.get_root().get_node_or_null(terrain_node) # # if not _terrain: # warning += """No Terrain3D node found""" # return # # if not _terrain.storage: # warning += """Terrain3D storage is not initialized""" # return # # # Get global transform # var gt: Transform3D = domain.get_global_transform() # var gt_inverse: Transform3D = gt.affine_inverse() # for i in transforms.list.size(): # var location: Vector3 = (gt * transforms.list[i]).origin # var height: float = _terrain.storage.get_height(location) # var normal: Vector3 = _terrain.storage.get_normal(location) # # if align_with_collision_normal: # transforms.list[i].basis.y = normal # transforms.list[i].basis.x = -transforms.list[i].basis.z.cross(normal) # transforms.list[i].basis = transforms.list[i].basis.orthonormalized() # # transforms.list[i].origin.y = height - gt.origin.y # # if transforms.is_empty(): # warning += """Every point has been removed. Possible reasons include: \n # + No collider is close enough to the shapes. # + Ray length is too short. # + Ray direction is incorrect. # + Collision mask is not set properly. # + Max slope is too low. # """