Изменения значения interpolation_duration на 10.0 не даёт перехода в 10 секунд, по факту переход гораздо быстрее. При переключении с 3rd на 1st нету плавного проезда камеры, переход происходит моментально. Возможно нужно добавить какие-то переменные для хранения параметров камеры (position, yaw, pitch, distance, height) и даже добавить больше уточняющих параметров.

--- Start of main.py ---
import pygame
import math
from pygame.locals import *
from OpenGL.GL import *
from OpenGL.GLU import *
from plane_module import Plane
from game_objects import FBXModel
from interface_module import GameInterface

pygame.init()
screen = pygame.display.set_mode((800, 600), DOUBLEBUF | OPENGL)
pygame.display.set_caption("3D Shooter with OpenGL")

glEnable(GL_DEPTH_TEST)
glEnable(GL_LIGHTING)
glEnable(GL_LIGHT0)
glEnable(GL_COLOR_MATERIAL)
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE)

glLightfv(GL_LIGHT0, GL_POSITION, (0, 100, 0, 1))
glLightfv(GL_LIGHT0, GL_AMBIENT, (0.2, 0.2, 0.2, 1))
glLightfv(GL_LIGHT0, GL_DIFFUSE, (0.8, 0.8, 0.8, 1))

player_x, player_y, player_z = 0, 0, 0
move_speed = 0.8 # Скорость движения в обычном режиме
jump_force = 1.5
gravity = 0.08

camera_distance = 20
camera_height = 15
camera_pitch = 0
camera_yaw = 0
mouse_sensitivity = 0.2
min_pitch, max_pitch = -89, 89

Флаг для режима камеры от третьего лица
third_person_mode = False

plane = Plane(size=20000, grid=50, heightmap="Height_Map.exr", diffusemap="Diffuse_Map.exr", height_scale=20000)
model = FBXModel(model_path="characterMedium.obj", position=[player_x, player_y + 50, player_z], scale=15)
interface = GameInterface(minimap_filename="mini_map.png", minimap_size=200)

noclip_mode = False
third_person_camera_height = 10
first_person_offset_forward = 1 # Смещение вперёд (в метрах)
first_person_offset_up = 2 # Смещение вверх (в метрах)

Добавим новые переменные для хранения начальных и целевых значений параметров камеры
initial_camera_params = {
'position': model.position.copy(),
'yaw': camera_yaw,
'pitch': camera_pitch,
'distance': camera_distance,
'height': camera_height
}

target_camera_params = initial_camera_params.copy()

Переменная для отслеживания прогресса интерполяции
interpolation_progress = 0.0
interpolation_duration = 10.0 # Длительность интерполяции в секундах

def set_camera(player_x, player_y, player_z, yaw, pitch, distance, height, interpolation_factor=1.0):
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluPerspective(60, (800 / 600), 0.1, 10000.0)


glMatrixMode(GL_MODELVIEW)
glLoadIdentity()

if third_person_mode:
    # Режим камеры от третьего лица
    look_x = player_x + math.sin(math.radians(yaw)) * math.cos(math.radians(pitch))
    look_y = player_y + math.sin(math.radians(pitch))
    look_z = player_z - math.cos(math.radians(yaw)) * math.cos(math.radians(pitch))

    # Позиция камеры от третьего лица
    camera_offset_x = player_x - math.sin(math.radians(yaw)) * distance
    camera_offset_z = player_z + math.cos(math.radians(yaw)) * distance
    camera_offset_y = player_y + height

    gluLookAt(
        camera_offset_x, camera_offset_y, camera_offset_z,
        look_x, look_y, look_z,  # Цель камеры смотрит на игрока
        0, 1, 0  # Вектор "вверх" остаётся неизменным
    )
else:
    # Режим камеры от первого лица
    # Расчёт смещения камеры
    camera_offset_x = player_x + math.sin(math.radians(yaw)) * first_person_offset_forward
    camera_offset_z = player_z - math.cos(math.radians(yaw)) * first_person_offset_forward
    camera_offset_y = player_y + first_person_offset_up

    look_x = camera_offset_x + math.sin(math.radians(yaw)) * math.cos(math.radians(pitch))
    look_y = camera_offset_y + math.sin(math.radians(pitch))
    look_z = camera_offset_z - math.cos(math.radians(yaw)) * math.cos(math.radians(pitch))

    gluLookAt(
        camera_offset_x, camera_offset_y, camera_offset_z,
        look_x, look_y, look_z,
        0, 1, 0
    )
clock = pygame.time.Clock()
pygame.mouse.set_visible(False)
pygame.event.set_grab(True)
vertical_momentum = 0
is_grounded = True
running = True

while running:
dt = clock.tick(60) * 0.1


glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glClearColor(0.53, 0.81, 0.98, 1)

# Обработка интерполяции
if interpolation_progress < interpolation_duration:
    interpolation_progress += dt
    factor = interpolation_progress / interpolation_duration

    # Интерполяция параметров камеры
    interpolated_camera_params = {
        'position': [
            initial_camera_params['position'][0] * (1 - factor) + target_camera_params['position'][0] * factor,
            initial_camera_params['position'][1] * (1 - factor) + target_camera_params['position'][1] * factor,
            initial_camera_params['position'][2] * (1 - factor) + target_camera_params['position'][2] * factor
        ],
        'yaw': initial_camera_params['yaw'] * (1 - factor) + target_camera_params['yaw'] * factor,
        'pitch': initial_camera_params['pitch'] * (1 - factor) + target_camera_params['pitch'] * factor,
        'distance': initial_camera_params['distance'] * (1 - factor) + target_camera_params['distance'] * factor,
        'height': initial_camera_params['height'] * (1 - factor) + target_camera_params['height'] * factor
    }

    set_camera(
        interpolated_camera_params['position'][0],
        interpolated_camera_params['position'][1],
        interpolated_camera_params['position'][2],
        interpolated_camera_params['yaw'],
        interpolated_camera_params['pitch'],
        interpolated_camera_params['distance'],
        interpolated_camera_params['height'],
        factor
    )
else:
    # Установка камеры без интерполяции
    set_camera(*model.position, camera_yaw, camera_pitch, camera_distance, camera_height)

glPushMatrix()
plane.render()
model.render()  # Рендерим модель вместо куба
glPopMatrix()

glDisable(GL_DEPTH_TEST)
interface.render_minimap(model.position[0], model.position[2], plane_size=20000)
glEnable(GL_DEPTH_TEST)

for event in pygame.event.get():
    if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE):
        running = False
    elif event.type == pygame.KEYDOWN and event.key == pygame.K_n:  # Переключение режима noclip
        noclip_mode = not noclip_mode
    elif event.type == pygame.KEYDOWN and event.key == pygame.K_f:  # Переключение режима камеры
        third_person_mode = not third_person_mode

        # Сохраняем начальные параметры камеры
        initial_camera_params = {
            'position': model.position.copy(),
            'yaw': camera_yaw,
            'pitch': camera_pitch,
            'distance': camera_distance,
            'height': camera_height
        }

        # Устанавливаем целевые параметры камеры
        if third_person_mode:
            target_camera_params = {
                'position': model.position.copy(),
                'yaw': camera_yaw,
                'pitch': camera_pitch,
                'distance': camera_distance,
                'height': third_person_camera_height
            }
        else:
            target_camera_params = {
                'position': model.position.copy(),
                'yaw': camera_yaw,
                'pitch': camera_pitch,
                'distance': first_person_offset_forward,
                'height': first_person_offset_up
            }

        # Сбрасываем прогресс интерполяции
        interpolation_progress = 0.0

dx, dy = pygame.mouse.get_rel()
camera_yaw += dx * mouse_sensitivity
camera_pitch -= dy * mouse_sensitivity
camera_pitch = max(min_pitch, min(max_pitch, camera_pitch))

keys = pygame.key.get_pressed()
current_move_speed = move_speed * 10 if noclip_mode else move_speed

move_forward = (keys[pygame.K_w] - keys[pygame.K_s]) * current_move_speed * dt
move_strafe = (keys[pygame.K_d] - keys[pygame.K_a]) * current_move_speed * dt

angle = math.radians(camera_yaw)
forward_x = math.sin(angle)
forward_z = -math.cos(angle)
strafe_x = math.cos(angle)
strafe_z = math.sin(angle)

old_model_position = model.position.copy()

if noclip_mode:
    new_x = model.position[0] + forward_x * move_forward + strafe_x * move_strafe
    new_z = model.position[2] + forward_z * move_forward + strafe_z * move_strafe
    vertical_momentum = 0
    new_y = model.position[1] + (keys[pygame.K_SPACE] - keys[pygame.K_LCTRL]) * current_move_speed * dt
    model.update_position([new_x, new_y, new_z])
else:
    new_x = model.position[0] + forward_x * move_forward + strafe_x * move_strafe
    new_z = model.position[2] + forward_z * move_forward + strafe_z * move_strafe

    terrain_height = plane.get_height(new_x, new_z)
    if model.position[1] < terrain_height:
        model.position[1] = terrain_height
        vertical_momentum = 0
        is_grounded = True

    if not is_grounded:
        vertical_momentum -= gravity * dt
        model.position[1] += vertical_momentum
    else:
        vertical_momentum = 0

    if is_grounded and keys[pygame.K_SPACE]:
        vertical_momentum = jump_force
        is_grounded = False

    model.update_position([new_x, model.position[1], new_z])

pygame.display.flip()
pygame.quit()

--- End of main.py ---