Aligned foot rotation to ground normal

This commit is contained in:
Eduard Urbach 2024-02-19 23:23:12 +01:00
parent f7209d2164
commit 1e5ab718bf
Signed by: akyoto
GPG Key ID: C874F672B1AF20C0
5 changed files with 73 additions and 6 deletions

View File

@ -140,6 +140,7 @@ scale_max = 1.1
tilt = 0.15 tilt = 0.15
[node name="Enemies" type="Node3D" parent="World"] [node name="Enemies" type="Node3D" parent="World"]
visible = false
script = ExtResource("15_25nmg") script = ExtResource("15_25nmg")
scene = ExtResource("15_hgl78") scene = ExtResource("15_hgl78")
noise = SubResource("FastNoiseLite_yp2fx") noise = SubResource("FastNoiseLite_yp2fx")

View File

@ -90,6 +90,7 @@ bone_idx = 12
[node name="Weapon" type="BoneAttachment3D" parent="Model/Female/Armature/GeneralSkeleton" index="6"] [node name="Weapon" type="BoneAttachment3D" parent="Model/Female/Armature/GeneralSkeleton" index="6"]
transform = Transform3D(0, -1, 0, 0, 0, -1, 1, 0, 0, -0.609469, 1.26691, -0.0234125) transform = Transform3D(0, -1, 0, 0, 0, -1, 1, 0, 0, -0.609469, 1.26691, -0.0234125)
visible = false
bone_name = "RightMiddleProximal" bone_name = "RightMiddleProximal"
bone_idx = 44 bone_idx = 44
@ -124,6 +125,7 @@ libraries = {
skeleton = NodePath("../Model/Female/Armature/GeneralSkeleton") skeleton = NodePath("../Model/Female/Armature/GeneralSkeleton")
movement = NodePath("../Movement") movement = NodePath("../Movement")
footsteps = SubResource("AudioStreamRandomizer_4yj1k") footsteps = SubResource("AudioStreamRandomizer_4yj1k")
step_threshold = 0.1
[node name="Health" parent="." instance=ExtResource("2_np5ag")] [node name="Health" parent="." instance=ExtResource("2_np5ag")]
max_value = 100.0 max_value = 100.0

View File

@ -6,3 +6,5 @@ var audio: AudioStreamPlayer3D
var position: Vector3 var position: Vector3
var velocity: Vector3 var velocity: Vector3
var attachment: BoneAttachment3D var attachment: BoneAttachment3D
var floor_distance: float
var normal: Vector3

View File

@ -1,14 +1,17 @@
class_name FootstepsComponent class_name FootstepsComponent
extends Node extends Node3D
@export var skeleton: Skeleton3D @export var skeleton: Skeleton3D
@export var movement: MovementComponent @export var movement: MovementComponent
@export var footsteps: AudioStreamRandomizer @export var footsteps: AudioStreamRandomizer
@export var step_threshold := 0.1 @export var step_threshold := 0.1
@export var ik_step_threshold := 0.2
@export var ik_speed := 5.0
const feet_names := ["LeftFoot", "RightFoot"] const feet_names := ["LeftFoot", "RightFoot"]
var feet: Array[Foot] = [] var feet: Array[Foot] = []
var ik_time: float
func _ready(): func _ready():
for foot_name in feet_names: for foot_name in feet_names:
@ -17,6 +20,8 @@ func _ready():
foot.bone_id = skeleton.find_bone(foot_name) foot.bone_id = skeleton.find_bone(foot_name)
foot.audio = get_node(foot_name) foot.audio = get_node(foot_name)
foot.position = skeleton.to_global(skeleton.get_bone_global_pose(foot.bone_id).origin) foot.position = skeleton.to_global(skeleton.get_bone_global_pose(foot.bone_id).origin)
foot.floor_distance = INF
foot.normal = Vector3.UP
foot.attachment = BoneAttachment3D.new() foot.attachment = BoneAttachment3D.new()
foot.attachment.bone_name = foot_name foot.attachment.bone_name = foot_name
foot.attachment.bone_idx = foot.bone_id foot.attachment.bone_idx = foot.bone_id
@ -26,13 +31,25 @@ func _ready():
func _process(delta: float): func _process(delta: float):
for foot in feet: for foot in feet:
var global_pose := skeleton.get_bone_global_pose(foot.bone_id)
var old_position := foot.position var old_position := foot.position
foot.position = skeleton.to_global(skeleton.get_bone_global_pose(foot.bone_id).origin) foot.position = skeleton.to_global(global_pose.origin)
foot.velocity = (foot.position - old_position) / delta
if foot.position.y > step_threshold: if foot.floor_distance < ik_step_threshold:
var bone_to_global := skeleton.global_transform * global_pose
var normal_local := bone_to_global.basis.transposed() * foot.normal
var pose := skeleton.get_bone_pose(foot.bone_id)
var rot := get_foot_rotation(pose.basis, normal_local)
ik_time = minf(ik_time + ik_speed * delta, 1.0)
skeleton.set_bone_pose_rotation(foot.bone_id, pose.basis.slerp(rot, ik_time))
else:
ik_time = 0
if foot.floor_distance > step_threshold:
continue continue
foot.velocity = (foot.position - old_position) / delta
if foot.velocity.y > 0: if foot.velocity.y > 0:
continue continue
@ -44,6 +61,51 @@ func _process(delta: float):
play(foot.audio) play(foot.audio)
func _physics_process(_delta):
var space_state = get_world_3d().direct_space_state
for foot in feet:
var from := foot.position
var to := foot.position + Vector3(0, -10, 0)
var query = PhysicsRayQueryParameters3D.create(from, to, 1)
var result = space_state.intersect_ray(query)
if result:
foot.floor_distance = (foot.position - result.position).length()
foot.normal = result.normal
else:
foot.floor_distance = INF
foot.normal = Vector3.UP
func play(audio_player: AudioStreamPlayer3D): func play(audio_player: AudioStreamPlayer3D):
audio_player.stream = footsteps audio_player.stream = footsteps
audio_player.play() audio_player.play()
func get_foot_rotation(base: Basis, normal: Vector3) -> Basis:
var rot := align_with_y(base, normal)
return rot.rotated(Vector3.UP, PI)
func align_with_y(base: Basis, normal: Vector3) -> Basis:
base.x = -base.z.cross(normal)
base.y = normal
return base.orthonormalized()
# func get_foot_rotation2(base: Basis, normal: Vector3) -> Basis:
# normal.x = -normal.x
# normal.z = -normal.z
# return align_up(base, normal)
# func align_up(base: Basis, normal: Vector3) -> Basis:
# var result = Basis()
# var node_scale = base.get_scale().abs()
# result.x = normal.cross(base.z)
# result.y = normal
# result.z = base.x.cross(normal)
# result = result.orthonormalized()
# result.x *= node_scale.x
# result.y *= node_scale.y
# result.z *= node_scale.z
# return result

View File

@ -2,7 +2,7 @@
[ext_resource type="Script" path="res://player/footsteps/FootstepsComponent.gd" id="1_xjrot"] [ext_resource type="Script" path="res://player/footsteps/FootstepsComponent.gd" id="1_xjrot"]
[node name="Footsteps" type="Node"] [node name="Footsteps" type="Node3D"]
script = ExtResource("1_xjrot") script = ExtResource("1_xjrot")
[node name="LeftFoot" type="AudioStreamPlayer3D" parent="."] [node name="LeftFoot" type="AudioStreamPlayer3D" parent="."]