feat(render): interpolate entity transforms for rendering

Add RenderTransform component to smooth position/direction updates
and use it in entity and shadow passes.
This commit is contained in:
2026-08-04 10:59:56 +08:00
parent e2bbc2d57f
commit d970988022
4 changed files with 30 additions and 13 deletions

View File

@@ -10,4 +10,5 @@ struct WalkPose {
// for sound play // for sound play
float moving_time = 0.0f; float moving_time = 0.0f;
}; };
} // namespace Cubed } // namespace Cubed

View File

@@ -21,4 +21,10 @@ struct Transform {
Direction direction{}; Direction direction{};
}; };
struct RenderTransform {
Position position{};
Orientation orientation{};
Direction direction{};
};
} // namespace Cubed } // namespace Cubed

View File

@@ -20,7 +20,7 @@ void ClientEntityManager::init() {
BaseClientCreature c; BaseClientCreature c;
c.model = ModelManager::instance().get_model_id("cubed:pig"); c.model = ModelManager::instance().get_model_id("cubed:pig");
create_entity_in_registry(id, Entity{id}, EntityInfo{"cubed:pig", ""}, create_entity_in_registry(id, Entity{id}, EntityInfo{"cubed:pig", ""},
std::move(c), PigTag{}); std::move(c), PigTag{}, RenderTransform{});
}); });
} }
// not thread safe // not thread safe
@@ -34,6 +34,9 @@ void ClientEntityManager::handle_entity_create(EntityID id,
auto* c = m_registry.try_get<BaseClientCreature>(a->second); auto* c = m_registry.try_get<BaseClientCreature>(a->second);
ASSERT(c); ASSERT(c);
c->transform.position.value = pos; c->transform.position.value = pos;
auto* r = m_registry.try_get<RenderTransform>(a->second);
ASSERT(r);
r->position.value = pos;
} }
void ClientEntityManager::handle_entity_update(UpdateInfo& info) { void ClientEntityManager::handle_entity_update(UpdateInfo& info) {
@@ -50,6 +53,13 @@ void ClientEntityManager::handle_entity_update(UpdateInfo& info) {
ASSERT(creature); ASSERT(creature);
creature->transform.position.value = info.pos; creature->transform.position.value = info.pos;
creature->transform.direction.value = info.direction; creature->transform.direction.value = info.direction;
auto r = m_registry.try_get<RenderTransform>(e);
ASSERT(r);
r->direction.value =
glm::mix(r->direction.value, creature->transform.direction.value, 0.15);
r->position.value =
glm::mix(r->position.value, creature->transform.position.value, 0.15);
} }
void ClientEntityManager::receive_entity_create(S2CEntityCreate& s2c) { void ClientEntityManager::receive_entity_create(S2CEntityCreate& s2c) {

View File

@@ -297,15 +297,15 @@ void WorldRenderer::shadow_entity(ClientWorld& world,
shader.set_loc("lightSpaceMatrix", light_matrix); shader.set_loc("lightSpaceMatrix", light_matrix);
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
auto& registry = world.entity_manager().get_registry(); auto& registry = world.entity_manager().get_registry();
auto view = registry.view<BaseClientCreature>(); auto view = registry.view<BaseClientCreature, RenderTransform>();
for (auto entity : view) { for (auto entity : view) {
auto& creature = view.get<BaseClientCreature>(entity); auto& creature = view.get<BaseClientCreature>(entity);
float yaw = std::atan2(creature.transform.direction.value.x, auto& t = view.get<RenderTransform>(entity);
creature.transform.direction.value.z); float yaw = std::atan2(t.direction.value.x, t.direction.value.z);
m_renderer.model_renderer().shadow_pass( m_renderer.model_renderer().shadow_pass(creature.model,
creature.model, creature.transform.position.value, yaw, t.position.value, yaw,
world.world_scene().camera()); world.world_scene().camera());
} }
m_player_renderer.render(shader, world, true); m_player_renderer.render(shader, world, true);
} }
@@ -721,14 +721,14 @@ void WorldRenderer::render_entity(ClientWorld& world) {
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
auto& registry = world.entity_manager().get_registry(); auto& registry = world.entity_manager().get_registry();
auto view = registry.view<BaseClientCreature>(); auto view = registry.view<BaseClientCreature, RenderTransform>();
for (auto entity : view) { for (auto entity : view) {
auto& creature = view.get<BaseClientCreature>(entity); auto& creature = view.get<BaseClientCreature>(entity);
float yaw = std::atan2(creature.transform.direction.value.x, auto& t = view.get<RenderTransform>(entity);
creature.transform.direction.value.z); float yaw = std::atan2(t.direction.value.x, t.direction.value.z);
m_renderer.model_renderer().render_model( m_renderer.model_renderer().render_model(creature.model,
creature.model, creature.transform.position.value, yaw, t.position.value, yaw,
world.world_scene().camera()); world.world_scene().camera());
} }
m_player_renderer.render(shader, world, false); m_player_renderer.render(shader, world, false);