From 3ef850f14fe7c009d193361131aa6cf3fb6e783d Mon Sep 17 00:00:00 2001 From: FailSpy <9100196+FailSpy@users.noreply.github.com> Date: Fri, 16 Feb 2024 14:52:06 -0500 Subject: [PATCH] Add multiple surface functionality for meshes --- .../Scripts/footstep_surface_detector.gd | 78 ++++++++++++++++++- 1 file changed, 74 insertions(+), 4 deletions(-) diff --git a/COGITO/DynamicFootstepSystem/Scripts/footstep_surface_detector.gd b/COGITO/DynamicFootstepSystem/Scripts/footstep_surface_detector.gd index b21a8a03..c27b631b 100644 --- a/COGITO/DynamicFootstepSystem/Scripts/footstep_surface_detector.gd +++ b/COGITO/DynamicFootstepSystem/Scripts/footstep_surface_detector.gd @@ -4,6 +4,7 @@ class_name FootstepSurfaceDetector @export var generic_fallback_footstep_profile : AudioStreamRandomizer @export var footstep_material_library : FootstepMaterialLibrary +var last_result func _ready(): if not generic_fallback_footstep_profile: @@ -14,6 +15,7 @@ func play_footstep(): var result = get_world_3d().direct_space_state.intersect_ray(query) if result: + last_result = result if _play_by_footstep_surface(result.collider): return elif _play_by_material(result.collider): @@ -59,14 +61,82 @@ func _get_footstep_surface_child(collider : Node3D) -> AudioStreamRandomizer: return null func _get_surface_material(collider : Node3D) -> Material: + var mesh_instance = null + var meshes = [] if collider is CSGShape3D: - return collider.material + if collider is CSGCombiner3D: + #composite mesh + if collider.material_override: + return collider.material_override + meshes = collider.get_meshes() + else: + return collider.material elif collider is StaticBody3D or collider is RigidBody3D: #find all children of the collider static body that are of type "MeshInstance3D" #if there are multiple materials, just default to the first one found - var mesh_instances = collider.find_children("", "MeshInstance3D") - if mesh_instances: - return mesh_instances[0].mesh.material + if collider.get_parent() is MeshInstance3D: + mesh_instance = collider.get_parent() + else: + var mesh_instances = collider.find_children("", "MeshInstance3D") + if mesh_instances: + if len(mesh_instances) == 1: + mesh_instance = mesh_instances[0] + else: + meshes = mesh_instances + + if meshes: + #TODO: Handle multiple meshes + mesh_instance = meshes[0] + + if mesh_instance and 'mesh' in mesh_instance: + var mesh = mesh_instance.mesh + if mesh.get_surface_count() == 0: + return null + elif mesh.get_surface_count() == 1: + return mesh.surface_get_material(0) + else: + var face = null + + var ray = last_result['position'] - global_position + var faces = mesh.get_faces() + + var aabb = mesh.get_aabb() as AABB + var accuracy = round(4*aabb.size.length_squared()) # dynamically calculate a reasonable grid size + var snap = aabb.size/accuracy # this will be the size of our units to snap to + + var coord = null + + for i in range(len(faces) / 3): + # first, figure out what face we're standing on + var face_idx = i * 3 + var a = mesh_instance.to_global(faces[face_idx]) + var b = mesh_instance.to_global(faces[face_idx+1]) + var c = mesh_instance.to_global(faces[face_idx+2]) + var ray_t = Geometry3D.ray_intersects_triangle(global_position,ray,a,b,c) + if ray_t: + face = faces.slice(face_idx,face_idx+3) + # round out vert coordinates to avoid floating point errors + coord = [round(faces[face_idx]/snap),round(faces[face_idx+1]/snap),round(faces[face_idx+2]/snap)] + break + var mat = null + if face: + for surface in range(mesh.get_surface_count()): + var surf = mesh.surface_get_arrays(surface)[0] + var has_vert_a = false + var has_vert_b = false + var has_vert_c = false + for vert in surf: + var vert_coord = round(vert/snap) + has_vert_a = has_vert_a or vert_coord == coord[0] + has_vert_b = has_vert_b or vert_coord == coord[1] + has_vert_c = has_vert_c or vert_coord == coord[2] + if has_vert_a and has_vert_b and has_vert_c: + # we found it! note the material and break free! + mat = mesh.surface_get_material(surface) + break + if has_vert_a and has_vert_b and has_vert_c: + break + return mat return null func _play_footstep(footstep_profile : AudioStreamRandomizer):