From: Daniel Karbach Date: Fri, 16 Oct 2015 14:33:52 +0000 (+0200) Subject: use "forces" for entity control and RK4 integrator X-Git-Url: https://git.localhorst.tv/?a=commitdiff_plain;h=d38be21d103052761505d58a6d13e30a896dde01;p=blank.git use "forces" for entity control and RK4 integrator --- diff --git a/src/ai/ai.cpp b/src/ai/ai.cpp index d50aee5..7ada5a3 100644 --- a/src/ai/ai.cpp +++ b/src/ai/ai.cpp @@ -36,7 +36,7 @@ void Chaser::Update(int dt) { glm::vec3 diff(Target().AbsoluteDifference(Controlled())); float dist = length(diff); if (dist < std::numeric_limits::epsilon()) { - Controlled().Velocity(glm::vec3(0.0f)); + Controlled().TargetVelocity(glm::vec3(0.0f)); return; } glm::vec3 norm_diff(diff / dist); @@ -49,13 +49,13 @@ void Chaser::Update(int dt) { } if (!line_of_sight) { - Controlled().Velocity(glm::vec3(0.0f)); + Controlled().TargetVelocity(glm::vec3(0.0f)); } else if (dist > stop_dist) { - Controlled().Velocity(norm_diff * chase_speed); + Controlled().TargetVelocity(norm_diff * chase_speed); } else if (dist < flee_dist) { - Controlled().Velocity(norm_diff * flee_speed); + Controlled().TargetVelocity(norm_diff * flee_speed); } else { - Controlled().Velocity(glm::vec3(0.0f)); + Controlled().TargetVelocity(glm::vec3(0.0f)); } } @@ -97,10 +97,10 @@ void RandomWalk::Update(int dt) { Change(); } else if (lerp_time > 0) { float a = std::min(lerp_time / lerp_max, 1.0f); - Controlled().Velocity(mix(target_vel, start_vel, a)); + Controlled().TargetVelocity(mix(target_vel, start_vel, a)); Controlled().AngularVelocity(mix(target_rot, start_rot, a)); } else { - Controlled().Velocity(target_vel); + Controlled().TargetVelocity(target_vel); Controlled().AngularVelocity(target_rot); } } diff --git a/src/client/NetworkedInput.hpp b/src/client/NetworkedInput.hpp index 462b6a7..36382b9 100644 --- a/src/client/NetworkedInput.hpp +++ b/src/client/NetworkedInput.hpp @@ -36,10 +36,11 @@ private: struct PlayerHistory { EntityState state; + glm::vec3 tgt_vel; int delta_t; std::uint16_t packet; - PlayerHistory(EntityState s, int dt, std::uint16_t p) - : state(s), delta_t(dt), packet(p) { } + PlayerHistory(EntityState s, const glm::vec3 &tv, int dt, std::uint16_t p) + : state(s), tgt_vel(tv), delta_t(dt), packet(p) { } }; std::list player_hist; diff --git a/src/client/net.cpp b/src/client/net.cpp index 5c06bbe..73931f4 100644 --- a/src/client/net.cpp +++ b/src/client/net.cpp @@ -332,10 +332,11 @@ void NetworkedInput::PushPlayerUpdate(int dt) { InventorySlot() ); if (player_hist.size() < 16) { - player_hist.emplace_back(state, dt, packet); + player_hist.emplace_back(state, GetPlayer().GetEntity().TargetVelocity(), dt, packet); } else { auto entry = player_hist.begin(); entry->state = state; + entry->tgt_vel = GetPlayer().GetEntity().TargetVelocity(); entry->delta_t = dt; entry->packet = packet; player_hist.splice(player_hist.end(), player_hist, entry); @@ -378,6 +379,7 @@ void NetworkedInput::MergePlayerCorrection(uint16_t seq, const EntityState &corr vector col; while (entry != end) { replay.Velocity(entry->state.velocity); + replay.TargetVelocity(entry->tgt_vel); replay.Update(entry->delta_t); if (GetWorld().Intersection(replay, col)) { GetWorld().Resolve(replay, col); diff --git a/src/ui/ui.cpp b/src/ui/ui.cpp index 6a48874..9638619 100644 --- a/src/ui/ui.cpp +++ b/src/ui/ui.cpp @@ -86,7 +86,7 @@ void PlayerController::UpdatePlayer() noexcept { constexpr float max_vel = 0.005f; if (dirty) { player.GetEntity().Orientation(glm::quat(glm::vec3(pitch, yaw, 0.0f))); - player.GetEntity().Velocity(glm::rotateY(move_dir * max_vel, yaw)); + player.GetEntity().TargetVelocity(glm::rotateY(move_dir * max_vel, yaw)); Ray aim = player.Aim(); if (!world.Intersection(aim, glm::mat4(1.0f), player.GetEntity().ChunkCoords(), aim_world)) { diff --git a/src/world/Entity.hpp b/src/world/Entity.hpp index eb312ee..bf5fbe9 100644 --- a/src/world/Entity.hpp +++ b/src/world/Entity.hpp @@ -15,6 +15,7 @@ namespace blank { class DirectionalLighting; +struct EntityDerivative; class Shape; class Entity { @@ -37,6 +38,9 @@ public: bool WorldCollidable() const noexcept { return world_collision; } void WorldCollidable(bool b) noexcept { world_collision = b; } + const glm::vec3 &TargetVelocity() const noexcept { return tgt_vel; } + void TargetVelocity(const glm::vec3 &v) noexcept { tgt_vel = v; } + const glm::vec3 &Velocity() const noexcept { return state.velocity; } void Velocity(const glm::vec3 &v) noexcept { state.velocity = v; } @@ -82,6 +86,14 @@ public: if (model) model.Render(M, prog); } +private: + EntityDerivative CalculateStep( + const EntityState &cur, + float dt, + const EntityDerivative &prev + ) const noexcept; + glm::vec3 ControlForce(const EntityState &) const noexcept; + private: Instance model; @@ -90,6 +102,7 @@ private: AABB bounds; EntityState state; + glm::vec3 tgt_vel; int ref_count; diff --git a/src/world/EntityDerivative.hpp b/src/world/EntityDerivative.hpp new file mode 100644 index 0000000..9666b1f --- /dev/null +++ b/src/world/EntityDerivative.hpp @@ -0,0 +1,19 @@ +#ifndef BLANK_WORLD_ENTITYDERIVATIVE_HPP_ +#define BLANK_WORLD_ENTITYDERIVATIVE_HPP_ + +#include + + +namespace blank { + +struct EntityDerivative { + + glm::vec3 position; + glm::vec3 velocity; + glm::vec3 orient; + +}; + +} + +#endif diff --git a/src/world/EntityState.hpp b/src/world/EntityState.hpp index 8f74114..e93fffa 100644 --- a/src/world/EntityState.hpp +++ b/src/world/EntityState.hpp @@ -23,9 +23,6 @@ struct EntityState { /// make sure block_pos is within chunk bounds void AdjustPosition() noexcept; - /// do an integration step of dt milliseconds - void Update(int dt) noexcept; - /// get a position vector relative to the (0,0,0) chunk glm::vec3 AbsolutePosition() const noexcept { return glm::vec3(chunk_pos * Chunk::Extent()) + block_pos; diff --git a/src/world/world.cpp b/src/world/world.cpp index e4fb968..8be2941 100644 --- a/src/world/world.cpp +++ b/src/world/world.cpp @@ -1,4 +1,5 @@ #include "Entity.hpp" +#include "EntityDerivative.hpp" #include "EntityState.hpp" #include "Player.hpp" #include "World.hpp" @@ -12,6 +13,7 @@ #include #include +#include #include #include #include @@ -26,6 +28,7 @@ Entity::Entity() noexcept , name("anonymous") , bounds() , state() +, tgt_vel(0.0f) , ref_count(0) , world_collision(false) , dead(false) { @@ -68,7 +71,56 @@ glm::quat delta_rot(const glm::vec3 &av, float dt) { } void Entity::Update(int dt) noexcept { - state.Update(dt); + float fdt = float(dt); + + // euler + //state.block_pos += state.velocity * fdt; + //state.velocity += ControlForce(state) * fdt; + //state.orient = delta_rot(state.ang_vel, fdt) * state.orient; + //state.AdjustPosition(); + + // RK4 + EntityDerivative a(CalculateStep(state, 0.0f, EntityDerivative())); + EntityDerivative b(CalculateStep(state, fdt * 0.5f, a)); + EntityDerivative c(CalculateStep(state, fdt * 0.5f, b)); + EntityDerivative d(CalculateStep(state, fdt, c)); + + EntityDerivative f; + constexpr float sixth = 1.0f / 6.0f; + f.position = sixth * ((a.position + 2.0f * (b.position + c.position)) + d.position); + f.velocity = sixth * ((a.velocity + 2.0f * (b.velocity + c.velocity)) + d.velocity); + f.orient = sixth * ((a.orient + 2.0f * (b.orient + c.orient)) + d.orient); + + state.block_pos += f.position * fdt; + state.velocity += f.velocity * fdt; + state.orient = delta_rot(f.orient, fdt) * state.orient; + state.AdjustPosition(); +} + +EntityDerivative Entity::CalculateStep( + const EntityState &cur, + float dt, + const EntityDerivative &delta +) const noexcept { + EntityState next(cur); + next.block_pos += delta.position * dt; + next.velocity += delta.velocity * dt; + next.orient = delta_rot(cur.ang_vel, dt) * cur.orient; + next.AdjustPosition(); + + EntityDerivative out; + out.position = next.velocity; + out.velocity = ControlForce(next); // plus other forces and then by mass + return out; +} + +glm::vec3 Entity::ControlForce(const EntityState &cur) const noexcept { + constexpr float k = 1.0f; // spring constant + constexpr float b = 1.0f; // damper constant + constexpr float t = 0.01f; // 1/time constant + const glm::vec3 x(-tgt_vel); // endpoint displacement from equilibrium + const glm::vec3 v(cur.velocity); // relative velocity between endpoints + return (((-k) * x) - (b * v)) * t; // times mass = 1 } @@ -81,13 +133,6 @@ EntityState::EntityState() } -void EntityState::Update(int dt) noexcept { - float fdt = float(dt); - block_pos += velocity * fdt; - orient = delta_rot(ang_vel, fdt) * orient; - AdjustPosition(); -} - void EntityState::AdjustPosition() noexcept { while (block_pos.x >= Chunk::width) { block_pos.x -= Chunk::width;