Started to add smoothing of errors - atm only for position, not angle.
This commit is contained in:
parent
51fd0c1e8e
commit
4d02e736f7
@ -160,8 +160,14 @@
|
|||||||
|
|
||||||
<!-- Networking
|
<!-- Networking
|
||||||
state-frequency: how many states the server will send per second.
|
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
|
<!-- The field od views for 1-4 player split screen. fov-3 is
|
||||||
actually not used (since 3 player split screen uses the
|
actually not used (since 3 player split screen uses the
|
||||||
|
@ -117,6 +117,15 @@ void STKConfig::load(const std::string &filename)
|
|||||||
Log::fatal("StkConfig", "Wrong number of item switches defined in stk_config");
|
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_max_karts, "<karts max=..." );
|
||||||
CHECK_NEG(m_item_switch_time, "item-switch-time" );
|
CHECK_NEG(m_item_switch_time, "item-switch-time" );
|
||||||
CHECK_NEG(m_bubblegum_counter, "bubblegum disappear counter");
|
CHECK_NEG(m_bubblegum_counter, "bubblegum disappear counter");
|
||||||
@ -350,7 +359,9 @@ void STKConfig::getAllData(const XMLNode * root)
|
|||||||
|
|
||||||
if (const XMLNode *networking_node = root->getNode("networking"))
|
if (const XMLNode *networking_node = root->getNode("networking"))
|
||||||
{
|
{
|
||||||
networking_node->get("state-frequency", &m_network_state_frequeny);
|
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"))
|
if(const XMLNode *replay_node = root->getNode("replay"))
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "network/remote_kart_info.hpp"
|
#include "network/remote_kart_info.hpp"
|
||||||
|
#include "utils/interpolation_array.hpp"
|
||||||
#include "utils/no_copy.hpp"
|
#include "utils/no_copy.hpp"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -85,6 +86,13 @@ public:
|
|||||||
/** How many state updates per second the server will send. */
|
/** How many state updates per second the server will send. */
|
||||||
int m_network_state_frequeny;
|
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
|
/** 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
|
* triangle are more than this value, the physics will use the normal
|
||||||
* of the triangle in smoothing normal. */
|
* of the triangle in smoothing normal. */
|
||||||
|
@ -51,6 +51,26 @@ void KartRewinder::reset()
|
|||||||
Rewinder::reset();
|
Rewinder::reset();
|
||||||
} // 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
|
/** 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
|
* 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());
|
t.setRotation(buffer->getQuat());
|
||||||
btRigidBody *body = getBody();
|
btRigidBody *body = getBody();
|
||||||
body->setLinearVelocity(buffer->getVec3());
|
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());
|
body->setAngularVelocity(buffer->getVec3());
|
||||||
// This function also reads the velocity, so it must be called
|
// This function also reads the velocity, so it must be called
|
||||||
// after the velocities are set
|
// after the velocities are set
|
||||||
|
@ -34,6 +34,9 @@ private:
|
|||||||
// Flags to indicate the different event types
|
// Flags to indicate the different event types
|
||||||
enum { EVENT_CONTROL = 0x01,
|
enum { EVENT_CONTROL = 0x01,
|
||||||
EVENT_ATTACH = 0x02 };
|
EVENT_ATTACH = 0x02 };
|
||||||
|
|
||||||
|
/** The transform of the kart before a rewind starts. */
|
||||||
|
btTransform m_saved_transform;
|
||||||
public:
|
public:
|
||||||
KartRewinder(const std::string& ident,
|
KartRewinder(const std::string& ident,
|
||||||
unsigned int world_kart_id,
|
unsigned int world_kart_id,
|
||||||
@ -41,6 +44,8 @@ public:
|
|||||||
PerPlayerDifficulty difficulty,
|
PerPlayerDifficulty difficulty,
|
||||||
KartRenderType krt = KRT_DEFAULT);
|
KartRenderType krt = KRT_DEFAULT);
|
||||||
virtual ~KartRewinder() {};
|
virtual ~KartRewinder() {};
|
||||||
|
virtual void saveTransform() OVERRIDE;
|
||||||
|
virtual void computeError() OVERRIDE;
|
||||||
virtual BareNetworkString* saveState() const;
|
virtual BareNetworkString* saveState() const;
|
||||||
void reset();
|
void reset();
|
||||||
virtual void rewindToState(BareNetworkString *p) OVERRIDE;
|
virtual void rewindToState(BareNetworkString *p) OVERRIDE;
|
||||||
|
@ -24,6 +24,9 @@
|
|||||||
#include "graphics/irr_driver.hpp"
|
#include "graphics/irr_driver.hpp"
|
||||||
#include "graphics/material.hpp"
|
#include "graphics/material.hpp"
|
||||||
#include "graphics/material_manager.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 "tracks/track.hpp"
|
||||||
|
|
||||||
#include "ISceneNode.h"
|
#include "ISceneNode.h"
|
||||||
@ -35,6 +38,8 @@ Moveable::Moveable()
|
|||||||
m_mesh = NULL;
|
m_mesh = NULL;
|
||||||
m_node = NULL;
|
m_node = NULL;
|
||||||
m_heading = 0;
|
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
|
} // Moveable
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
@ -56,6 +61,24 @@ void Moveable::setNode(scene::ISceneNode *n)
|
|||||||
m_node = n;
|
m_node = n;
|
||||||
} // setNode
|
} // 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
|
/** Updates the graphics model. Mainly set the graphical position to be the
|
||||||
* same as the physics position, but uses offsets to position and rotation
|
* 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,
|
void Moveable::updateGraphics(float dt, const Vec3& offset_xyz,
|
||||||
const btQuaternion& rotation)
|
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
|
#ifndef SERVER_ONLY
|
||||||
Vec3 xyz=getXYZ()+offset_xyz;
|
Vec3 xyz=getXYZ()+offset_xyz - m_positional_error;
|
||||||
m_node->setPosition(xyz.toIrrVector());
|
m_node->setPosition(xyz.toIrrVector());
|
||||||
btQuaternion r_all = getRotation()*rotation;
|
btQuaternion r_all = getRotation()*rotation;
|
||||||
if(btFuzzyZero(r_all.getX()) && btFuzzyZero(r_all.getY()-0.70710677f) &&
|
if(btFuzzyZero(r_all.getX()) && btFuzzyZero(r_all.getY()-0.70710677f) &&
|
||||||
|
@ -40,7 +40,8 @@ class Material;
|
|||||||
class Moveable: public NoCopy
|
class Moveable: public NoCopy
|
||||||
{
|
{
|
||||||
private:
|
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;
|
btTransform m_transform;
|
||||||
/** The 'real' heading between -180 to 180 degrees. */
|
/** The 'real' heading between -180 to 180 degrees. */
|
||||||
float m_heading;
|
float m_heading;
|
||||||
@ -49,6 +50,14 @@ private:
|
|||||||
/** The roll between -180 and 180 degrees. */
|
/** The roll between -180 and 180 degrees. */
|
||||||
float m_roll;
|
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:
|
protected:
|
||||||
UserPointer m_user_pointer;
|
UserPointer m_user_pointer;
|
||||||
scene::IMesh *m_mesh;
|
scene::IMesh *m_mesh;
|
||||||
@ -119,7 +128,8 @@ public:
|
|||||||
&getTrans() const {return m_transform;}
|
&getTrans() const {return m_transform;}
|
||||||
void setTrans(const btTransform& t);
|
void setTrans(const btTransform& t);
|
||||||
void updatePosition();
|
void updatePosition();
|
||||||
}
|
void addError(const Vec3& pos_error,
|
||||||
; // class Moveable
|
const btQuaternion &rot_error);
|
||||||
|
}; // class Moveable
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -277,6 +277,16 @@ void RewindManager::rewindTo(float rewind_time)
|
|||||||
assert(!m_is_rewinding);
|
assert(!m_is_rewinding);
|
||||||
history->doReplayHistory(History::HISTORY_NONE);
|
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
|
// Then undo the rewind infos going backwards in time
|
||||||
// --------------------------------------------------
|
// --------------------------------------------------
|
||||||
m_is_rewinding = true;
|
m_is_rewinding = true;
|
||||||
@ -335,6 +345,14 @@ void RewindManager::rewindTo(float rewind_time)
|
|||||||
world->setTime(current->getTime());
|
world->setTime(current->getTime());
|
||||||
} // while (world->getTime() < current_time)
|
} // 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;
|
m_is_rewinding = false;
|
||||||
} // rewindTo
|
} // rewindTo
|
||||||
|
|
||||||
|
@ -435,6 +435,8 @@ void RewindQueue::unitTesting()
|
|||||||
virtual void undoState(BareNetworkString *s) {}
|
virtual void undoState(BareNetworkString *s) {}
|
||||||
virtual void undo(BareNetworkString *s) {}
|
virtual void undo(BareNetworkString *s) {}
|
||||||
virtual void rewind(BareNetworkString *s) {}
|
virtual void rewind(BareNetworkString *s) {}
|
||||||
|
virtual void saveTransform() {}
|
||||||
|
virtual void computeError() {}
|
||||||
DummyRewinder() : Rewinder(true) {}
|
DummyRewinder() : Rewinder(true) {}
|
||||||
};
|
};
|
||||||
DummyRewinder *dummy_rewinder = new DummyRewinder();
|
DummyRewinder *dummy_rewinder = new DummyRewinder();
|
||||||
|
@ -24,11 +24,26 @@ class BareNetworkString;
|
|||||||
class Rewinder
|
class Rewinder
|
||||||
{
|
{
|
||||||
private:
|
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;
|
bool m_can_be_destroyed;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Rewinder(bool can_be_destroyed);
|
Rewinder(bool can_be_destroyed);
|
||||||
virtual ~Rewinder();
|
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.
|
/** Provides a copy of the state of the object in one memory buffer.
|
||||||
* The memory is managed by the RewindManager.
|
* The memory is managed by the RewindManager.
|
||||||
* \param[out] buffer The address of the memory buffer with the state.
|
* \param[out] buffer The address of the memory buffer with the state.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user