Is 3d physics interpolation bugged, or is there some issue with my camera controls?

Godot Version

4.4.stable

Im currently working on a first person character controller and ive come across an issue. the camera and the rest of the world look and move smoothly with physics interpolation enabled in my project settings, but any meshes attached to my camera (such as a model for a gun) seem to be stuttering. ive build a minimal reproduction of the problem and ive done some experimenting, and if i turn the physics tick rate all the way down to like 3 or 4, the issue becomes obvious. the meshes are being interpolated between physics frames, but it appears to be happening linearly and not spherically. this means that their positions in between frames dont keep their distance from the camera consistent. Ive tried using cubic_interpolate_in_time and spherical_cubic_interpolate_in_time to manually lerp the cameras transform, but the results arent great.

I really would like to keep the physics frame rate low (around 30) but even at 60 this is obvious. is there some known way around this? is there some error in my code? ive attached an image of my scene editor dock, which is the only scene in this project, the only project setting thats been changed is turning on physics interpolation, and here is the on script on the root node :

extends Node

@onready var Character : CharacterBody3D = self.get_node(^"CharacterBody3D")
@onready var Camera : Camera3D = self.get_node(^"CharacterBody3D/Camera3D")

func _ready() -> void:
	Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
	return

func _input(event: InputEvent) -> void:
	if(event is InputEventMouseMotion):
		var T := Transform3D()
		Camera.rotation.y -= (float(event.screen_relative.x) / float(self.get_window().size.x)) * 2.0
		Camera.rotation_degrees.x = clampf(rad_to_deg(Camera.rotation.x + ((float(-event.screen_relative.y) / float(self.get_window().size.y)) * 2.0)), -85.0, 85.0)
	elif(event.is_action(&"quit")) : self.get_tree().quit(0)
	return

any help or solutions would be greatly appreciated!!

nevermind i figured it out. in case anyone comes looking later : the answer is to turn off physics interpolation for the camera and use your own code to properly slerp between the last most recent to the most recent transform.

extends Node

@onready var Character : CharacterBody3D = self.get_node(^"CharacterBody3D")
@onready var Camera : Camera3D = self.get_node(^"CharacterBody3D/Camera3D")

var PrevT : Transform3D
var ThisT : Transform3D

func _ready() -> void:
	Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
	Camera.physics_interpolation_mode = Node.PHYSICS_INTERPOLATION_MODE_OFF
	PrevT = Camera.global_transform
	ThisT = Camera.global_transform
	return

func _input(event: InputEvent) -> void:
	if(event is InputEventMouseMotion):
		var T := Transform3D()
		Camera.rotation.y -= (float(event.screen_relative.x) / float(self.get_window().size.x)) * 2.0
		Camera.rotation_degrees.x = clampf(rad_to_deg(Camera.rotation.x + ((float(-event.screen_relative.y) / float(self.get_window().size.y)) * 2.0)), -85.0, 85.0)
	elif(event.is_action(&"quit")) : self.get_tree().quit(0)
	return

func _process(delta: float) -> void:	
	var Interp := Engine.get_physics_interpolation_fraction()
	Camera.global_transform = Transform3D(
		Basis(
			PrevT.basis.get_rotation_quaternion().normalized().slerp(
				ThisT.basis.get_rotation_quaternion().normalized(),
				Interp
			)
		),
		Vector3(
			PrevT.origin.slerp(
				ThisT.origin,
				Interp
			)
		)
	)
	return


func _physics_process(delta: float) -> void:
	PrevT = ThisT
	ThisT = Camera.global_transform
	return

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.