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
|
||||
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
|
||||
|
@ -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");
|
||||
@ -350,7 +359,9 @@ 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("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"))
|
||||
|
@ -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. */
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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) &&
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user