Skip to content

Instantly share code, notes, and snippets.

@Fenchurchh
Created January 24, 2024 19:58
Show Gist options
  • Save Fenchurchh/6a09519deaf426f929dda77a6d834ef9 to your computer and use it in GitHub Desktop.
Save Fenchurchh/6a09519deaf426f929dda77a6d834ef9 to your computer and use it in GitHub Desktop.
project_on_terrain3d.gd
#This script is an addon for HungryProton's Scatter https://github.com/HungryProton/scatter
#It allows Scatter to detect the terrain height from Terrain3D
#Copy this file into /addons/proton_scatter/src/modifiers
#Then uncomment everything below
#In the editor, add this modifier, then set your Terrain3D node
@tool
extends "base_modifier.gd"
signal projection_completed
@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 Engine.is_editor_hint():
# In editor
_terrain = domain.get_root().get_tree().get_edited_scene_root().find_child( "Terrain3D")
else:
# In game
_terrain = domain.get_root().get_tree().get_current_scene().find_child( "Terrain3D")
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.
"""
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment