Fixed some camera jittering

This commit is contained in:
2026-06-11 21:51:09 -05:00
parent 432909d65e
commit f1bc43125b
2 changed files with 15 additions and 12 deletions
+14 -12
View File
@@ -8,7 +8,7 @@ const COLLISION_MARGIN:float = 0.3
@export_category("Orbit") @export_category("Orbit")
@export var distance:float = 7.0 @export var distance:float = 7.0
@export var minDistance:float = 5.0 @export var minDistance:float = 2.0
@export var orbitSensitivity:float = 144.0 @export var orbitSensitivity:float = 144.0
@export var orbitAcceleration:float = 600.0 @export var orbitAcceleration:float = 600.0
@export var pitchMin:float = -80.0 @export var pitchMin:float = -80.0
@@ -106,10 +106,15 @@ func _process(delta:float) -> void:
global_transform.origin = finalPos global_transform.origin = finalPos
look_at(pivot, Vector3.UP) look_at(pivot, Vector3.UP)
# Feed actual position back so camera input resumes from where it really is # Lerp _yaw/_pitch toward the actual constrained position so input resumes
# smoothly, and small per-frame raycast variations don't oscillate.
var actualDir:Vector3 = (finalPos - pivot).normalized() var actualDir:Vector3 = (finalPos - pivot).normalized()
_pitch = rad_to_deg(asin(clamp(actualDir.y, -1.0, 1.0))) var targetPitch:float = rad_to_deg(asin(clamp(actualDir.y, -1.0, 1.0)))
_yaw = rad_to_deg(atan2(actualDir.x, actualDir.z)) var targetYaw:float = rad_to_deg(atan2(actualDir.x, actualDir.z))
var feedbackRate:float = minf(20.0 * delta, 1.0)
_pitch = lerpf(_pitch, targetPitch, feedbackRate)
var yawDiff:float = fposmod(targetYaw - _yaw + 180.0, 360.0) - 180.0
_yaw += lerpf(0.0, yawDiff, feedbackRate)
# Returns the camera world position, respecting both minDistance and terrain. # Returns the camera world position, respecting both minDistance and terrain.
func _resolvePosition(pivot:Vector3, dir:Vector3) -> Vector3: func _resolvePosition(pivot:Vector3, dir:Vector3) -> Vector3:
@@ -125,17 +130,14 @@ func _resolvePosition(pivot:Vector3, dir:Vector3) -> Vector3:
var hitNormal:Vector3 = hit["normal"] var hitNormal:Vector3 = hit["normal"]
var hitDist:float = (hit["position"] - pivot).length() - COLLISION_MARGIN var hitDist:float = (hit["position"] - pivot).length() - COLLISION_MARGIN
if hitDist >= minDistance:
# Terrain is beyond minDistance — simple pull-back along the ray
return pivot + dir * hitDist
# Terrain is closer than minDistance.
# Find the closest point on the circle formed by intersecting: # Find the closest point on the circle formed by intersecting:
# • the minDistance sphere centred on pivot # • a sphere of radius max(hitDist, minDistance) centred on pivot
# • the terrain surface plane (inset by COLLISION_MARGIN along its normal) # • the terrain surface plane (inset by COLLISION_MARGIN along its normal)
# That point is exactly minDistance from the pivot and flush with the surface. # Using max() makes both cases meet exactly at hitDist == minDistance,
# eliminating the branch discontinuity that causes jitter at the boundary.
var targetDist:float = maxf(hitDist, minDistance)
var d:float = hitNormal.dot(pivot - hit["position"]) - COLLISION_MARGIN var d:float = hitNormal.dot(pivot - hit["position"]) - COLLISION_MARGIN
var rSq:float = minDistance * minDistance - d * d var rSq:float = targetDist * targetDist - d * d
if rSq <= 0.0: if rSq <= 0.0:
# Pivot is itself nearly on the terrain — sit at the tangent point # Pivot is itself nearly on the terrain — sit at the tangent point
return pivot - hitNormal * d return pivot - hitNormal * d
+1
View File
@@ -26,6 +26,7 @@ size = Vector3(0.689728, 0.52002, 0.796997)
size = Vector3(1.3, 1.3, 1.3) size = Vector3(1.3, 1.3, 1.3)
[node name="Entity" type="CharacterBody3D"] [node name="Entity" type="CharacterBody3D"]
collision_layer = 2
script = ExtResource("1_8e8ef") script = ExtResource("1_8e8ef")
entityId = "35ce980f-3df9-4e09-b365-1a228948cf78" entityId = "35ce980f-3df9-4e09-b365-1a228948cf78"
metadata/_custom_type_script = "uid://c8146flooxeue" metadata/_custom_type_script = "uid://c8146flooxeue"