Add curved smoothing for moveable in network

This commit is contained in:
Benau 2018-06-18 00:06:32 +08:00
parent e8c4f74a20
commit 3b4353a2c9
6 changed files with 178 additions and 46 deletions

View File

@ -140,7 +140,7 @@ public:
// ------------------------------------------------------------------------
/** Returns a unique identifier for this kart (name of the directory the
* kart was loaded from). */
const std::string& getIdent() const;
virtual const std::string& getIdent() const;
// ------------------------------------------------------------------------
/** Returns the maximum steering angle for this kart, which depends on the
* speed. */

View File

@ -59,16 +59,13 @@ void KartRewinder::reset()
*/
void KartRewinder::saveTransform()
{
m_saved_transform = getTrans();
Moveable::prepareSmoothing();
} // 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);
Moveable::checkSmoothing();
} // computeError
// ----------------------------------------------------------------------------

View File

@ -34,8 +34,6 @@ private:
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,

View File

@ -38,8 +38,14 @@ 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);
m_smoothed_transform = btTransform(btQuaternion(0.0f, 0.0f, 0.0f, 1.0f));
m_start_smoothing_postion = m_adjust_position =
std::make_pair(Vec3(0.0f, 0.0f, 0.0f),
btQuaternion(0.0f, 0.0f, 0.0f, 1.0f));
m_prev_position_data = std::make_pair(m_smoothed_transform, Vec3());
m_smoothing = SS_NONE;
m_adjust_time = m_adjust_time_dt = 0.0f;
} // Moveable
//-----------------------------------------------------------------------------
@ -61,25 +67,61 @@ void Moveable::setNode(scene::ISceneNode *n)
m_node = n;
} // setNode
//-----------------------------------------------------------------------------
void Moveable::prepareSmoothing()
{
// Continuous smooth enabled
//if (m_smoothing != SS_NONE)
// return;
m_prev_position_data = std::make_pair(m_transform, getVelocity());
} // prepareSmoothing
//-----------------------------------------------------------------------------
/** 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)
void Moveable::checkSmoothing()
{
m_positional_error += pos_error;
#ifdef DEBUG_VISUAL_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());
#endif
m_rotational_error *= rot_error;
} // addError
// Continuous smooth enabled
//if (m_smoothing != SS_NONE)
// return;
float adjust_length = (m_transform.getOrigin() -
m_prev_position_data.first.getOrigin()).length();
if (adjust_length < 0.1f || adjust_length > 4.0f)
return;
float speed = m_prev_position_data.second.length();
speed = std::max(speed, getVelocity().length());
if (speed < 0.3f)
return;
float adjust_time = (adjust_length * 2.0f) / speed;
if (adjust_time > 2.0f)
return;
m_smoothing = SS_TO_ADJUST;
m_adjust_time_dt = 0.0f;
m_adjust_time = adjust_time;
m_start_smoothing_postion.first = m_smoothing == SS_NONE ?
m_prev_position_data.first.getOrigin() :
m_smoothed_transform.getOrigin();
m_start_smoothing_postion.second = m_smoothing == SS_NONE ?
m_prev_position_data.first.getRotation() :
m_smoothed_transform.getRotation();
m_adjust_control_point = m_start_smoothing_postion.first +
m_prev_position_data.second * m_adjust_time;
Vec3 p2 = m_transform.getOrigin() + getVelocity() *
m_adjust_time;
m_adjust_position.first.setInterpolate3(m_adjust_control_point, p2, 0.5f);
m_adjust_position.second = m_transform.getRotation();
m_adjust_position.second.slerp(m_start_smoothing_postion.second, 0.5f);
} // checkSmoothing
//-----------------------------------------------------------------------------
/** Updates the graphics model. Mainly set the graphical position to be the
@ -91,24 +133,84 @@ void Moveable::addError(const Vec3& pos_error,
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);
#ifdef DEBUG_VISUAL_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());
#endif
}
#ifndef SERVER_ONLY
Vec3 xyz=getXYZ()+offset_xyz - m_positional_error;
Vec3 cur_xyz = getXYZ();
btQuaternion cur_rot = getRotation();
float ratio = 0.0f;
if (m_smoothing != SS_NONE)
{
float adjust_time_dt = m_adjust_time_dt + dt;
ratio = adjust_time_dt / m_adjust_time;
if (ratio > 1.0f)
{
ratio -= 1.0f;
m_adjust_time_dt = adjust_time_dt - m_adjust_time;
if (m_smoothing == SS_TO_ADJUST)
{
m_smoothing = SS_TO_REAL;
m_adjust_control_point = m_adjust_position.first +
getVelocity() * m_adjust_time;
}
else
m_smoothing = SS_NONE;
}
else
m_adjust_time_dt = adjust_time_dt;
}
assert(m_adjust_time_dt >= 0.0f);
assert(ratio >= 0.0f);
if (m_smoothing == SS_TO_ADJUST)
{
cur_xyz.setInterpolate3(m_start_smoothing_postion.first,
m_adjust_position.first, ratio);
Vec3 to_control;
to_control.setInterpolate3(m_start_smoothing_postion.first,
m_adjust_control_point, ratio);
cur_xyz.setInterpolate3(cur_xyz, to_control, 1.0f - ratio);
if (smoothRotation())
{
cur_rot = m_start_smoothing_postion.second;
cur_rot.slerp(m_adjust_position.second, ratio);
}
}
else if (m_smoothing == SS_TO_REAL)
{
Vec3 to_control;
to_control.setInterpolate3(m_adjust_position.first,
m_adjust_control_point, ratio);
float ratio_sqrt = sqrtf(ratio);
cur_xyz.setInterpolate3(m_adjust_position.first, cur_xyz, ratio_sqrt);
cur_xyz.setInterpolate3(to_control, cur_xyz, ratio);
if (smoothRotation())
cur_rot.slerp(m_adjust_position.second, 1.0f - ratio);
}
m_smoothed_transform.setOrigin(cur_xyz);
m_smoothed_transform.setRotation(cur_rot);
if (m_smoothing != SS_NONE)
{
Vec3 lc = m_transform.inverse()(cur_xyz);
// Adjust vertical position for up/down-sloping
cur_xyz = m_smoothed_transform(Vec3(0.0f, -lc.y(), 0.0f));
m_smoothed_transform.setOrigin(cur_xyz);
}
#undef DEBUG_SMOOTHING
#ifdef DEBUG_SMOOTHING
// Gnuplot compare command
// plot "stdout.log" u 6:8 w lp lw 2, "stdout.log" u 10:12 w lp lw 2
Log::verbose("Smoothing", "%s smoothed-xyz(6-8) %f %f %f "
"xyz(10-12) %f %f %f", getIdent().c_str(),
cur_xyz.getX(), cur_xyz.getY(), cur_xyz.getZ(),
getXYZ().getX(), getXYZ().getY(), getXYZ().getZ());
#endif
Vec3 xyz = cur_xyz + offset_xyz;
m_node->setPosition(xyz.toIrrVector());
btQuaternion r_all = getRotation()*rotation;
btQuaternion r_all = cur_rot * rotation;
if(btFuzzyZero(r_all.getX()) && btFuzzyZero(r_all.getY()-0.70710677f) &&
btFuzzyZero(r_all.getZ()) && btFuzzyZero(r_all.getW()-0.70710677f) )
r_all.setX(0.000001f);
@ -133,6 +235,7 @@ void Moveable::reset()
m_node->setVisible(true); // In case that the objects was eliminated
#endif
m_smoothed_transform = m_transform;
Vec3 up = getTrans().getBasis().getColumn(1);
m_pitch = atan2(up.getZ(), fabsf(up.getY()));
m_roll = atan2(up.getX(), up.getY());

View File

@ -32,6 +32,8 @@ using namespace irr;
#include "utils/no_copy.hpp"
#include "utils/vec3.hpp"
#include <string>
class Material;
/**
@ -40,6 +42,13 @@ class Material;
class Moveable: public NoCopy
{
private:
enum SmoothingState
{
SS_NONE = 0,
SS_TO_ADJUST,
SS_TO_REAL
};
Vec3 m_velocityLC; /**<Velocity in kart coordinates. */
/** The bullet transform of this rigid body. */
btTransform m_transform;
@ -53,10 +62,18 @@ private:
/** 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;
std::pair<Vec3, btQuaternion> m_start_smoothing_postion,
m_adjust_position;
/** Similar to m_positional_error for rotation. */
btQuaternion m_rotational_error;
Vec3 m_adjust_control_point;
std::pair<btTransform, Vec3> m_prev_position_data;
float m_adjust_time, m_adjust_time_dt;
SmoothingState m_smoothing;
btTransform m_smoothed_transform;
protected:
UserPointer m_user_pointer;
@ -129,14 +146,31 @@ public:
&getTrans() const {return m_transform;}
void setTrans(const btTransform& t);
void updatePosition();
void addError(const Vec3& pos_error,
const btQuaternion &rot_error);
// ------------------------------------------------------------------------
/** Called once per rendered frame. It is used to only update any graphical
* effects.
* \param dt Time step size (since last call).
*/
virtual void updateGraphics(float dt) = 0;
// ------------------------------------------------------------------------
void prepareSmoothing();
// ------------------------------------------------------------------------
void checkSmoothing();
// ------------------------------------------------------------------------
const btTransform &getSmoothedTrans() const
{ return m_smoothed_transform; }
// ------------------------------------------------------------------------
const Vec3& getSmoothedXYZ() const
{ return (Vec3&)m_smoothed_transform.getOrigin(); }
// ------------------------------------------------------------------------
virtual bool smoothRotation() const { return true; }
// ------------------------------------------------------------------------
virtual const std::string& getIdent() const
{
static std::string unused("unused");
return unused;
}
}; // class Moveable
#endif

View File

@ -210,7 +210,6 @@ void RewindQueue::mergeNetworkData(int world_ticks, bool *needs_rewind,
// Only a client ever rewinds. So the rewind time should be the latest
// received state before current world time (if any)
*rewind_ticks = -9999;
bool adjust_next = false;
// FIXME: making m_network_events sorted would prevent the need to
// go through the whole list of events
@ -261,7 +260,8 @@ void RewindQueue::mergeNetworkData(int world_ticks, bool *needs_rewind,
// any server message should be in the client's past - but it can
// happen during debugging) we need to rewind to getTicks (in order
// to get the latest state).
if (NetworkConfig::get()->isClient() && (*i)->getTicks() <= world_ticks)
if (NetworkConfig::get()->isClient() &&
(*i)->getTicks() <= world_ticks && (*i)->isState())
{
// We need rewind if we receive an event in the past. This will
// then trigger a rewind later. Note that we only rewind to the