Started to add smoothing of errors - atm only for position, not angle.

This commit is contained in:
hiker 2017-12-18 23:13:59 +11:00
parent 51fd0c1e8e
commit 4d02e736f7
10 changed files with 145 additions and 6 deletions

View File

@ -160,8 +160,14 @@
<!-- Networking
state-frequency: how many states the server will send per second.
positional-smoothing: smoothing factor used in exponential smoothing
depending on error.
rotational-smoothing: slerp factor used in exponential smoothing
of rotations depending on error.
-->
<networking state-frequency="10" />
<networking state-frequency="10"
positional-smoothing="0.25:0.95 1.0:0.85"
rotational-smoothing="0.25:0.95 1.0:0.85" />
<!-- The field od views for 1-4 player split screen. fov-3 is
actually not used (since 3 player split screen uses the

View File

@ -117,6 +117,15 @@ void STKConfig::load(const std::string &filename)
Log::fatal("StkConfig", "Wrong number of item switches defined in stk_config");
}
if (m_positional_smoothing.size() == 0)
{
Log::fatal("StkConfig", "No positional smoothing defined in stk_config.");
}
if (m_rotational_smoothing.size() == 0)
{
Log::fatal("StkConfig", "No rotationalsmoothing defined in stk_config.");
}
CHECK_NEG(m_max_karts, "<karts max=..." );
CHECK_NEG(m_item_switch_time, "item-switch-time" );
CHECK_NEG(m_bubblegum_counter, "bubblegum disappear counter");
@ -351,6 +360,8 @@ void STKConfig::getAllData(const XMLNode * root)
if (const XMLNode *networking_node = root->getNode("networking"))
{
networking_node->get("state-frequency", &m_network_state_frequeny);
networking_node->get("positional-smoothing", &m_positional_smoothing );
networking_node->get("rotational-smoothing", &m_rotational_smoothing );
}
if(const XMLNode *replay_node = root->getNode("replay"))

View File

@ -27,6 +27,7 @@
*/
#include "network/remote_kart_info.hpp"
#include "utils/interpolation_array.hpp"
#include "utils/no_copy.hpp"
#include <vector>
@ -85,6 +86,13 @@ public:
/** How many state updates per second the server will send. */
int m_network_state_frequeny;
/** Smoothing of prediction errors for position, defined as an
* InterpolationArray. */
InterpolationArray m_positional_smoothing;
/** Smoothing of prediction errors for rotations, defined as an
* InterpolationArray. */
InterpolationArray m_rotational_smoothing;
/** If the angle between a normal on a vertex and the normal of the
* triangle are more than this value, the physics will use the normal
* of the triangle in smoothing normal. */

View File

@ -51,6 +51,26 @@ void KartRewinder::reset()
Rewinder::reset();
} // reset
// ----------------------------------------------------------------------------
/** This function is called immediately before a rewind is done and saves
* the current transform for the kart. The difference between this saved
* transform and the new transform after rewind is the error that needs
* (smoothly) be applied to the graphical position of the kart.
*/
void KartRewinder::saveTransform()
{
m_saved_transform = getTrans();
} // saveTransform
// ----------------------------------------------------------------------------
void KartRewinder::computeError()
{
//btTransform error = getTrans() - m_saved_transform;
Vec3 pos_error = getTrans().getOrigin() - m_saved_transform.getOrigin();
btQuaternion rot_error(0, 0, 0, 1);
Kart::addError(pos_error, rot_error);
} // computeError
// ----------------------------------------------------------------------------
/** Saves all state information for a kart in a memory buffer. The memory
* is allocated here and the address returned. It will then be managed
@ -114,6 +134,15 @@ void KartRewinder::rewindToState(BareNetworkString *buffer)
t.setRotation(buffer->getQuat());
btRigidBody *body = getBody();
body->setLinearVelocity(buffer->getVec3());
Log::info("KartRewinder", "t %f xyz %f %f %f v %f %f %f",
World::getWorld()->getTime(),
t.getOrigin().getX(),
t.getOrigin().getY(),
t.getOrigin().getZ(),
body->getLinearVelocity().getX(),
body->getLinearVelocity().getY(),
body->getLinearVelocity().getZ());
body->setAngularVelocity(buffer->getVec3());
// This function also reads the velocity, so it must be called
// after the velocities are set

View File

@ -34,6 +34,9 @@ private:
// Flags to indicate the different event types
enum { EVENT_CONTROL = 0x01,
EVENT_ATTACH = 0x02 };
/** The transform of the kart before a rewind starts. */
btTransform m_saved_transform;
public:
KartRewinder(const std::string& ident,
unsigned int world_kart_id,
@ -41,6 +44,8 @@ public:
PerPlayerDifficulty difficulty,
KartRenderType krt = KRT_DEFAULT);
virtual ~KartRewinder() {};
virtual void saveTransform() OVERRIDE;
virtual void computeError() OVERRIDE;
virtual BareNetworkString* saveState() const;
void reset();
virtual void rewindToState(BareNetworkString *p) OVERRIDE;

View File

@ -24,6 +24,9 @@
#include "graphics/irr_driver.hpp"
#include "graphics/material.hpp"
#include "graphics/material_manager.hpp"
#include "modes/world.hpp"
#include "network/network_config.hpp"
#include "network/rewind_manager.hpp"
#include "tracks/track.hpp"
#include "ISceneNode.h"
@ -35,6 +38,8 @@ Moveable::Moveable()
m_mesh = NULL;
m_node = NULL;
m_heading = 0;
m_positional_error = Vec3(0.0f, 0.0f, 0.0f);
m_rotational_error = btQuaternion(0.0f, 0.0f, 0.0f, 1.0f);
} // Moveable
//-----------------------------------------------------------------------------
@ -56,6 +61,24 @@ void Moveable::setNode(scene::ISceneNode *n)
m_node = n;
} // setNode
//-----------------------------------------------------------------------------
/** Adds a new error between graphical and physical position/rotation. Called
* in case of a rewind to allow to for smoothing the visuals in case of
* incorrect client prediction.
* \param pos_error Positional error to add.
* \param rot_Error Rotational error to add.
*/
void Moveable::addError(const Vec3& pos_error,
const btQuaternion &rot_error)
{
m_positional_error += pos_error;
Log::info("VisualError", "time %f addError %f %f %f size %f",
World::getWorld()->getTime(),
m_positional_error.getX(), m_positional_error.getY(), m_positional_error.getZ(),
m_positional_error.length());
m_rotational_error *= rot_error;
} // addError
//-----------------------------------------------------------------------------
/** Updates the graphics model. Mainly set the graphical position to be the
* same as the physics position, but uses offsets to position and rotation
@ -66,8 +89,20 @@ void Moveable::setNode(scene::ISceneNode *n)
void Moveable::updateGraphics(float dt, const Vec3& offset_xyz,
const btQuaternion& rotation)
{
// If this is a client, don't smooth error during rewinds
if (World::getWorld()->isNetworkWorld() &&
NetworkConfig::get()->isClient() &&
!RewindManager::get()->isRewinding())
{
float error = m_positional_error.length();
m_positional_error *= stk_config->m_positional_smoothing.get(error);
Log::info("VisualError", "time %f reduceError %f %f %f size %f",
World::getWorld()->getTime(),
m_positional_error.getX(), m_positional_error.getY(), m_positional_error.getZ(),
m_positional_error.length());
}
#ifndef SERVER_ONLY
Vec3 xyz=getXYZ()+offset_xyz;
Vec3 xyz=getXYZ()+offset_xyz - m_positional_error;
m_node->setPosition(xyz.toIrrVector());
btQuaternion r_all = getRotation()*rotation;
if(btFuzzyZero(r_all.getX()) && btFuzzyZero(r_all.getY()-0.70710677f) &&

View File

@ -40,7 +40,8 @@ class Material;
class Moveable: public NoCopy
{
private:
btVector3 m_velocityLC; /**<Velocity in kart coordinates. */
Vec3 m_velocityLC; /**<Velocity in kart coordinates. */
/** The bullet transform of this rigid body. */
btTransform m_transform;
/** The 'real' heading between -180 to 180 degrees. */
float m_heading;
@ -49,6 +50,14 @@ private:
/** The roll between -180 and 180 degrees. */
float m_roll;
/** Client prediction in networked games might cause the visual
* and physical position to be different. For visual smoothing
* this variable accumulates the error and reduces it over time. */
Vec3 m_positional_error;
/** Similar to m_positional_error for rotation. */
btQuaternion m_rotational_error;
protected:
UserPointer m_user_pointer;
scene::IMesh *m_mesh;
@ -119,7 +128,8 @@ public:
&getTrans() const {return m_transform;}
void setTrans(const btTransform& t);
void updatePosition();
}
; // class Moveable
void addError(const Vec3& pos_error,
const btQuaternion &rot_error);
}; // class Moveable
#endif

View File

@ -277,6 +277,16 @@ void RewindManager::rewindTo(float rewind_time)
assert(!m_is_rewinding);
history->doReplayHistory(History::HISTORY_NONE);
// First save all current transforms so that the error
// can be computed between the transforms before and after
// the rewind.
AllRewinder::iterator rewinder;
for (rewinder = m_all_rewinder.begin();
rewinder != m_all_rewinder.end(); ++rewinder)
{
(*rewinder)->saveTransform();
}
// Then undo the rewind infos going backwards in time
// --------------------------------------------------
m_is_rewinding = true;
@ -335,6 +345,14 @@ void RewindManager::rewindTo(float rewind_time)
world->setTime(current->getTime());
} // while (world->getTime() < current_time)
// Now compute the errors which need to be visually smoothed
for (rewinder = m_all_rewinder.begin();
rewinder != m_all_rewinder.end(); ++rewinder)
{
(*rewinder)->computeError();
}
m_is_rewinding = false;
} // rewindTo

View File

@ -435,6 +435,8 @@ void RewindQueue::unitTesting()
virtual void undoState(BareNetworkString *s) {}
virtual void undo(BareNetworkString *s) {}
virtual void rewind(BareNetworkString *s) {}
virtual void saveTransform() {}
virtual void computeError() {}
DummyRewinder() : Rewinder(true) {}
};
DummyRewinder *dummy_rewinder = new DummyRewinder();

View File

@ -24,11 +24,26 @@ class BareNetworkString;
class Rewinder
{
private:
/** True if this object can be destroyed, i.e. if this object is a 'stand
* alone' (i.e. not used in inheritance). If the object is used in
* inheritance (e.g. KartRewinder, which is a Rewinder and Kart), then
* freeing the kart will free this rewinder instance as well.
*/
bool m_can_be_destroyed;
public:
Rewinder(bool can_be_destroyed);
virtual ~Rewinder();
/** Called before a rewind. Is used to save the previous position of an
* object before a rewind, so that the error due to a rewind can be
* computed. */
virtual void saveTransform() = 0;
/** Called when a rewind is finished, and is used to compute the error
* caused by the rewind (which is then visually smoothed over time). */
virtual void computeError() = 0;
/** Provides a copy of the state of the object in one memory buffer.
* The memory is managed by the RewindManager.
* \param[out] buffer The address of the memory buffer with the state.